├── .env ├── .gitignore ├── ReadMe.md ├── package-lock.json ├── package.json ├── src ├── app │ ├── errHandler.js │ └── index.js ├── config │ └── config.default.js ├── constant │ └── err.type.js ├── controller │ ├── addr.controller.js │ ├── cart.controller.js │ ├── goods.controller.js │ ├── order.controller.js │ └── user.controller.js ├── db │ └── seq.js ├── main.js ├── middleware │ ├── addr.middleware.js │ ├── auth.middleware.js │ ├── cart.middleware.js │ ├── goods.middleware.js │ ├── order.middleware.js │ └── user.middleware.js ├── model │ ├── addr.model.js │ ├── cart.model.js │ ├── goods.model.js │ ├── order.model.js │ └── use.model.js ├── router │ ├── addr.route.js │ ├── cart.route.js │ ├── goods.route.js │ ├── index.js │ ├── order.route.js │ └── user.route.js └── service │ ├── addr.service.js │ ├── cart.service.js │ ├── goods.service.js │ ├── order.service.js │ └── user.service.js └── test └── file_text.html /.env: -------------------------------------------------------------------------------- 1 | APP_PORT = 8000 2 | 3 | MYSQL_HOST = localhost 4 | MYSQL_PORT = 3306 5 | MYSQL_USER = root 6 | MYSQL_PWD = 123456 7 | MYSQL_DB = zdsc 8 | 9 | JWT_SECRET = xzd -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | src/upload -------------------------------------------------------------------------------- /ReadMe.md: -------------------------------------------------------------------------------- 1 | # 一. 项目的初始化 2 | 3 | ## 1 npm 初始化 4 | 5 | ``` 6 | npm init -y 7 | ``` 8 | 9 | 生成`package.json`文件: 10 | 11 | - 记录项目的依赖 12 | 13 | ## 2 git 初始化 14 | 15 | ``` 16 | git init 17 | ``` 18 | 19 | 生成'.git'隐藏文件夹, git 的本地仓库 20 | 21 | ## 3 创建 ReadMe 文件 22 | 23 | # 二. 搭建项目 24 | 25 | ## 1 安装 Koa 框架 26 | 27 | ``` 28 | npm install koa 29 | ``` 30 | 31 | ## 2 编写最基本的 app 32 | 33 | 创建`src/main.js` 34 | 35 | ```js 36 | const Koa = require('koa') 37 | 38 | const app = new Koa() 39 | 40 | app.use((ctx, next) => { 41 | ctx.body = 'hello world' 42 | }) 43 | 44 | app.listen(3000, () => { 45 | console.log('server is running on http://localhost:3000') 46 | }) 47 | ``` 48 | 49 | ## 3 测试 50 | 51 | 在终端, 使用`node src/main.js` 52 | 53 |  54 | 55 | # 三. 项目的基本优化 56 | 57 | ## 1 自动重启服务 58 | 59 | 安装 nodemon 工具 60 | 61 | ``` 62 | npm i nodemon -D 63 | ``` 64 | 65 | 编写`package.json`脚本 66 | 67 | ```json 68 | "scripts": { 69 | "dev": "nodemon ./src/main.js", 70 | "test": "echo \"Error: no test specified\" && exit 1" 71 | }, 72 | ``` 73 | 74 | 执行`npm run dev`启动服务 75 | 76 |  77 | 78 | ## 2 读取配置文件 79 | 80 | 安装`dotenv`, 读取根目录中的`.env`文件, 将配置写到`process.env`中 81 | 82 | ``` 83 | npm i dotenv 84 | ``` 85 | 86 | 创建`.env`文件 87 | 88 | ``` 89 | APP_PORT=8000 90 | ``` 91 | 92 | 创建`src/config/config.default.js` 93 | 94 | ```js 95 | const dotenv = require('dotenv') 96 | 97 | dotenv.config() 98 | 99 | // console.log(process.env.APP_PORT) 100 | 101 | module.exports = process.env 102 | ``` 103 | 104 | 改写`main.js` 105 | 106 | ```js 107 | const Koa = require('koa') 108 | 109 | const { APP_PORT } = require('./config/config.default') 110 | 111 | const app = new Koa() 112 | 113 | app.use((ctx, next) => { 114 | ctx.body = 'hello api' 115 | }) 116 | 117 | app.listen(APP_PORT, () => { 118 | console.log(`server is running on http://localhost:${APP_PORT}`) 119 | }) 120 | ``` 121 | 122 | # 四. 添加路由 123 | 124 | 路由: 根据不同的 URL, 调用对应处理函数 125 | 126 | ## 1 安装 koa-router 127 | 128 | ``` 129 | npm i koa-router 130 | ``` 131 | 132 | 步骤: 133 | 134 | 1. 导入包 135 | 2. 实例化对象 136 | 3. 编写路由 137 | 4. 注册中间件 138 | 139 | ## 2 编写路由 140 | 141 | 创建`src/router`目录, 编写`user.route.js` 142 | 143 | ```js 144 | const Router = require('koa-router') 145 | 146 | const router = new Router({ prefix: '/users' }) 147 | 148 | // GET /users/ 149 | router.get('/', (ctx, next) => { 150 | ctx.body = 'hello users' 151 | }) 152 | 153 | module.exports = router 154 | ``` 155 | 156 | ## 3 改写 main.js 157 | 158 | ```js 159 | const Koa = require('koa') 160 | 161 | const { APP_PORT } = require('./config/config.default') 162 | 163 | const userRouter = require('./router/user.route') 164 | 165 | const app = new Koa() 166 | 167 | app.use(userRouter.routes()) 168 | 169 | app.listen(APP_PORT, () => { 170 | console.log(`server is running on http://localhost:${APP_PORT}`) 171 | }) 172 | ``` 173 | 174 | # 五. 目录结构优化 175 | 176 | ## 1 将 http 服务和 app 业务拆分 177 | 178 | 创建`src/app/index.js` 179 | 180 | ```js 181 | const Koa = require('koa') 182 | 183 | const userRouter = require('../router/user.route') 184 | 185 | const app = new Koa() 186 | 187 | app.use(userRouter.routes()) 188 | 189 | module.exports = app 190 | ``` 191 | 192 | 改写`main.js` 193 | 194 | ```js 195 | const { APP_PORT } = require('./config/config.default') 196 | 197 | const app = require('./app') 198 | 199 | app.listen(APP_PORT, () => { 200 | console.log(`server is running on http://localhost:${APP_PORT}`) 201 | }) 202 | ``` 203 | 204 | ## 2 将路由和控制器拆分 205 | 206 | 路由: 解析 URL, 分布给控制器对应的方法 207 | 208 | 控制器: 处理不同的业务 209 | 210 | 改写`user.route.js` 211 | 212 | ```js 213 | const Router = require('koa-router') 214 | 215 | const { register, login } = require('../controller/user.controller') 216 | 217 | const router = new Router({ prefix: '/users' }) 218 | 219 | // 注册接口 220 | router.post('/register', register) 221 | 222 | // 登录接口 223 | router.post('/login', login) 224 | 225 | module.exports = router 226 | ``` 227 | 228 | 创建`controller/user.controller.js` 229 | 230 | ```js 231 | class UserController { 232 | async register(ctx, next) { 233 | ctx.body = '用户注册成功' 234 | } 235 | 236 | async login(ctx, next) { 237 | ctx.body = '登录成功' 238 | } 239 | } 240 | 241 | module.exports = new UserController() 242 | ``` 243 | 244 | # 六. 解析 body 245 | 246 | ## 1 安装 koa-body 247 | 248 | ``` 249 | npm i koa-body 250 | ``` 251 | 252 | ## 2 注册中间件 253 | 254 | 改写`app/index.js` 255 | 256 |  257 | 258 | ## 3 解析请求数据 259 | 260 | 改写`user.controller.js`文件 261 | 262 | ```js 263 | const { createUser } = require('../service/user.service') 264 | 265 | class UserController { 266 | async register(ctx, next) { 267 | // 1. 获取数据 268 | // console.log(ctx.request.body) 269 | const { user_name, password } = ctx.request.body 270 | // 2. 操作数据库 271 | const res = await createUser(user_name, password) 272 | // console.log(res) 273 | // 3. 返回结果 274 | ctx.body = ctx.request.body 275 | } 276 | 277 | async login(ctx, next) { 278 | ctx.body = '登录成功' 279 | } 280 | } 281 | 282 | module.exports = new UserController() 283 | ``` 284 | 285 | ## 4 拆分 service 层 286 | 287 | service 层主要是做数据库处理 288 | 289 | 创建`src/service/user.service.js` 290 | 291 | ```js 292 | class UserService { 293 | async createUser(user_name, password) { 294 | // todo: 写入数据库 295 | return '写入数据库成功' 296 | } 297 | } 298 | 299 | module.exports = new UserService() 300 | ``` 301 | 302 | # 七. 集成 sequlize 303 | 304 | sequelize ORM 数据库工具 305 | 306 | ORM: 对象关系映射 307 | 308 | - 数据表映射(对应)一个类 309 | - 数据表中的数据行(记录)对应一个对象 310 | - 数据表字段对应对象的属性 311 | - 数据表的操作对应对象的方法 312 | 313 | ## 1 安装 sequelize 314 | 315 | ``` 316 | npm i mysql2 sequelize 317 | ``` 318 | 319 | ## 2 连接数据库 320 | 321 | `src/db/seq.js` 322 | 323 | ```js 324 | const { Sequelize } = require('sequelize') 325 | 326 | const { 327 | MYSQL_HOST, 328 | MYSQL_PORT, 329 | MYSQL_USER, 330 | MYSQL_PWD, 331 | MYSQL_DB, 332 | } = require('../config/config.default') 333 | 334 | const seq = new Sequelize(MYSQL_DB, MYSQL_USER, MYSQL_PWD, { 335 | host: MYSQL_HOST, 336 | dialect: 'mysql', 337 | }) 338 | 339 | seq 340 | .authenticate() 341 | .then(() => { 342 | console.log('数据库连接成功') 343 | }) 344 | .catch((err) => { 345 | console.log('数据库连接失败', err) 346 | }) 347 | 348 | module.exports = seq 349 | ``` 350 | 351 | ## 3 编写配置文件 352 | 353 | ``` 354 | APP_PORT = 8000 355 | 356 | MYSQL_HOST = localhost 357 | MYSQL_PORT = 3306 358 | MYSQL_USER = root 359 | MYSQL_PWD = 123456 360 | MYSQL_DB = zdsc 361 | ``` 362 | 363 | # 八. 创建 User 模型 364 | 365 | ## 1 拆分 Model 层 366 | 367 | sequelize 主要通过 Model 对应数据表 368 | 369 | 创建`src/model/user.model.js` 370 | 371 | ```js 372 | const { DataTypes } = require('sequelize') 373 | 374 | const seq = require('../db/seq') 375 | 376 | // 创建模型(Model zd_user -> 表 zd_users) 377 | const User = seq.define('zd_user', { 378 | // id 会被sequelize自动创建, 管理 379 | user_name: { 380 | type: DataTypes.STRING, 381 | allowNull: false, 382 | unique: true, 383 | comment: '用户名, 唯一', 384 | }, 385 | password: { 386 | type: DataTypes.CHAR(64), 387 | allowNull: false, 388 | comment: '密码', 389 | }, 390 | is_admin: { 391 | type: DataTypes.BOOLEAN, 392 | allowNull: false, 393 | defaultValue: 0, 394 | comment: '是否为管理员, 0: 不是管理员(默认); 1: 是管理员', 395 | }, 396 | }) 397 | 398 | // 强制同步数据库(创建数据表) 399 | // User.sync({ force: true }) 400 | 401 | module.exports = User 402 | ``` 403 | 404 | # 九. 添加用户入库 405 | 406 | 所有数据库的操作都在 Service 层完成, Service 调用 Model 完成数据库操作 407 | 408 | 改写`src/service/user.service.js` 409 | 410 | ```js 411 | const User = require('../model/use.model') 412 | 413 | class UserService { 414 | async createUser(user_name, password) { 415 | // 插入数据 416 | // User.create({ 417 | // // 表的字段 418 | // user_name: user_name, 419 | // password: password 420 | // }) 421 | 422 | // await表达式: promise对象的值 423 | const res = await User.create({ user_name, password }) 424 | // console.log(res) 425 | 426 | return res.dataValues 427 | } 428 | } 429 | 430 | module.exports = new UserService() 431 | ``` 432 | 433 | 同时, 改写`user.controller.js` 434 | 435 | ```js 436 | const { createUser } = require('../service/user.service') 437 | 438 | class UserController { 439 | async register(ctx, next) { 440 | // 1. 获取数据 441 | // console.log(ctx.request.body) 442 | const { user_name, password } = ctx.request.body 443 | // 2. 操作数据库 444 | const res = await createUser(user_name, password) 445 | // console.log(res) 446 | // 3. 返回结果 447 | ctx.body = { 448 | code: 0, 449 | message: '用户注册成功', 450 | result: { 451 | id: res.id, 452 | user_name: res.user_name, 453 | }, 454 | } 455 | } 456 | 457 | async login(ctx, next) { 458 | ctx.body = '登录成功' 459 | } 460 | } 461 | 462 | module.exports = new UserController() 463 | ``` 464 | 465 | # 十. 错误处理 466 | 467 | 在控制器中, 对不同的错误进行处理, 返回不同的提示错误提示, 提高代码质量 468 | 469 | ```js 470 | const { createUser, getUerInfo } = require('../service/user.service') 471 | 472 | class UserController { 473 | async register(ctx, next) { 474 | // 1. 获取数据 475 | // console.log(ctx.request.body) 476 | const { user_name, password } = ctx.request.body 477 | 478 | // 合法性 479 | if (!user_name || !password) { 480 | console.error('用户名或密码为空', ctx.request.body) 481 | ctx.status = 400 482 | ctx.body = { 483 | code: '10001', 484 | message: '用户名或密码为空', 485 | result: '', 486 | } 487 | return 488 | } 489 | // 合理性 490 | if (getUerInfo({ user_name })) { 491 | ctx.status = 409 492 | ctx.body = { 493 | code: '10002', 494 | message: '用户已经存在', 495 | result: '', 496 | } 497 | return 498 | } 499 | // 2. 操作数据库 500 | const res = await createUser(user_name, password) 501 | // console.log(res) 502 | // 3. 返回结果 503 | ctx.body = { 504 | code: 0, 505 | message: '用户注册成功', 506 | result: { 507 | id: res.id, 508 | user_name: res.user_name, 509 | }, 510 | } 511 | } 512 | 513 | async login(ctx, next) { 514 | ctx.body = '登录成功' 515 | } 516 | } 517 | 518 | module.exports = new UserController() 519 | ``` 520 | 521 | 在 service 中封装函数 522 | 523 | ```js 524 | const User = require('../model/use.model') 525 | 526 | class UserService { 527 | async createUser(user_name, password) { 528 | // 插入数据 529 | // await表达式: promise对象的值 530 | const res = await User.create({ user_name, password }) 531 | // console.log(res) 532 | 533 | return res.dataValues 534 | } 535 | 536 | async getUerInfo({ id, user_name, password, is_admin }) { 537 | const whereOpt = {} 538 | 539 | id && Object.assign(whereOpt, { id }) 540 | user_name && Object.assign(whereOpt, { user_name }) 541 | password && Object.assign(whereOpt, { password }) 542 | is_admin && Object.assign(whereOpt, { is_admin }) 543 | 544 | const res = await User.findOne({ 545 | attributes: ['id', 'user_name', 'password', 'is_admin'], 546 | where: whereOpt, 547 | }) 548 | 549 | return res ? res.dataValues : null 550 | } 551 | } 552 | 553 | module.exports = new UserService() 554 | ``` 555 | 556 | # 十一. 拆分中间件 557 | 558 | 为了使代码的逻辑更加清晰, 我们可以拆分一个中间件层, 封装多个中间件函数 559 | 560 |  561 | 562 | ## 1 拆分中间件 563 | 564 | 添加`src/middleware/user.middleware.js` 565 | 566 | ```js 567 | const { getUerInfo } = require('../service/user.service') 568 | const { userFormateError, userAlreadyExited } = require('../constant/err.type') 569 | 570 | const userValidator = async (ctx, next) => { 571 | const { user_name, password } = ctx.request.body 572 | // 合法性 573 | if (!user_name || !password) { 574 | console.error('用户名或密码为空', ctx.request.body) 575 | ctx.app.emit('error', userFormateError, ctx) 576 | return 577 | } 578 | 579 | await next() 580 | } 581 | 582 | const verifyUser = async (ctx, next) => { 583 | const { user_name } = ctx.request.body 584 | 585 | if (getUerInfo({ user_name })) { 586 | ctx.app.emit('error', userAlreadyExited, ctx) 587 | return 588 | } 589 | 590 | await next() 591 | } 592 | 593 | module.exports = { 594 | userValidator, 595 | verifyUser, 596 | } 597 | ``` 598 | 599 | ## 2 统一错误处理 600 | 601 | - 在出错的地方使用`ctx.app.emit`提交错误 602 | - 在 app 中通过`app.on`监听 603 | 604 | 编写统一的错误定义文件 605 | 606 | ```js 607 | module.exports = { 608 | userFormateError: { 609 | code: '10001', 610 | message: '用户名或密码为空', 611 | result: '', 612 | }, 613 | userAlreadyExited: { 614 | code: '10002', 615 | message: '用户已经存在', 616 | result: '', 617 | }, 618 | } 619 | ``` 620 | 621 | ## 3 错误处理函数 622 | 623 | ```js 624 | module.exports = (err, ctx) => { 625 | let status = 500 626 | switch (err.code) { 627 | case '10001': 628 | status = 400 629 | break 630 | case '10002': 631 | status = 409 632 | break 633 | default: 634 | status = 500 635 | } 636 | ctx.status = status 637 | ctx.body = err 638 | } 639 | ``` 640 | 641 | 改写`app/index.js` 642 | 643 | ```js 644 | const errHandler = require('./errHandler') 645 | // 统一的错误处理 646 | app.on('error', errHandler) 647 | ``` 648 | 649 | # 十二. 加密 650 | 651 | 在将密码保存到数据库之前, 要对密码进行加密处理 652 | 653 | 123123abc (加盐) 加盐加密 654 | 655 | ## 1 安装 bcryptjs 656 | 657 | ``` 658 | npm i bcryptjs 659 | ``` 660 | 661 | ## 2 编写加密中间件 662 | 663 | ```js 664 | const crpytPassword = async (ctx, next) => { 665 | const { password } = ctx.request.body 666 | 667 | const salt = bcrypt.genSaltSync(10) 668 | // hash保存的是 密文 669 | const hash = bcrypt.hashSync(password, salt) 670 | 671 | ctx.request.body.password = hash 672 | 673 | await next() 674 | } 675 | ``` 676 | 677 | ## 3 在 router 中使用 678 | 679 | 改写`user.router.js` 680 | 681 | ```js 682 | const Router = require('koa-router') 683 | 684 | const { 685 | userValidator, 686 | verifyUser, 687 | crpytPassword, 688 | } = require('../middleware/user.middleware') 689 | const { register, login } = require('../controller/user.controller') 690 | 691 | const router = new Router({ prefix: '/users' }) 692 | 693 | // 注册接口 694 | router.post('/register', userValidator, verifyUser, crpytPassword, register) 695 | 696 | // 登录接口 697 | router.post('/login', login) 698 | 699 | module.exports = router 700 | ``` 701 | 702 | # 十三. 登录验证 703 | 704 | 流程: 705 | 706 | - 验证格式 707 | - 验证用户是否存在 708 | - 验证密码是否匹配 709 | 710 | 改写`src/middleware/user.middleware.js` 711 | 712 | ```js 713 | const bcrypt = require('bcryptjs') 714 | 715 | const { getUerInfo } = require('../service/user.service') 716 | const { 717 | userFormateError, 718 | userAlreadyExited, 719 | userRegisterError, 720 | userDoesNotExist, 721 | userLoginError, 722 | invalidPassword, 723 | } = require('../constant/err.type') 724 | 725 | const userValidator = async (ctx, next) => { 726 | const { user_name, password } = ctx.request.body 727 | // 合法性 728 | if (!user_name || !password) { 729 | console.error('用户名或密码为空', ctx.request.body) 730 | ctx.app.emit('error', userFormateError, ctx) 731 | return 732 | } 733 | 734 | await next() 735 | } 736 | 737 | const verifyUser = async (ctx, next) => { 738 | const { user_name } = ctx.request.body 739 | 740 | // if (await getUerInfo({ user_name })) { 741 | // ctx.app.emit('error', userAlreadyExited, ctx) 742 | // return 743 | // } 744 | try { 745 | const res = await getUerInfo({ user_name }) 746 | 747 | if (res) { 748 | console.error('用户名已经存在', { user_name }) 749 | ctx.app.emit('error', userAlreadyExited, ctx) 750 | return 751 | } 752 | } catch (err) { 753 | console.error('获取用户信息错误', err) 754 | ctx.app.emit('error', userRegisterError, ctx) 755 | return 756 | } 757 | 758 | await next() 759 | } 760 | 761 | const crpytPassword = async (ctx, next) => { 762 | const { password } = ctx.request.body 763 | 764 | const salt = bcrypt.genSaltSync(10) 765 | // hash保存的是 密文 766 | const hash = bcrypt.hashSync(password, salt) 767 | 768 | ctx.request.body.password = hash 769 | 770 | await next() 771 | } 772 | 773 | const verifyLogin = async (ctx, next) => { 774 | // 1. 判断用户是否存在(不存在:报错) 775 | const { user_name, password } = ctx.request.body 776 | 777 | try { 778 | const res = await getUerInfo({ user_name }) 779 | 780 | if (!res) { 781 | console.error('用户名不存在', { user_name }) 782 | ctx.app.emit('error', userDoesNotExist, ctx) 783 | return 784 | } 785 | 786 | // 2. 密码是否匹配(不匹配: 报错) 787 | if (!bcrypt.compareSync(password, res.password)) { 788 | ctx.app.emit('error', invalidPassword, ctx) 789 | return 790 | } 791 | } catch (err) { 792 | console.error(err) 793 | return ctx.app.emit('error', userLoginError, ctx) 794 | } 795 | 796 | await next() 797 | } 798 | 799 | module.exports = { 800 | userValidator, 801 | verifyUser, 802 | crpytPassword, 803 | verifyLogin, 804 | } 805 | ``` 806 | 807 | 定义错误类型 808 | 809 | ```js 810 | module.exports = { 811 | userFormateError: { 812 | code: '10001', 813 | message: '用户名或密码为空', 814 | result: '', 815 | }, 816 | userAlreadyExited: { 817 | code: '10002', 818 | message: '用户已经存在', 819 | result: '', 820 | }, 821 | userRegisterError: { 822 | code: '10003', 823 | message: '用户注册错误', 824 | result: '', 825 | }, 826 | userDoesNotExist: { 827 | code: '10004', 828 | message: '用户不存在', 829 | result: '', 830 | }, 831 | userLoginError: { 832 | code: '10005', 833 | message: '用户登录失败', 834 | result: '', 835 | }, 836 | invalidPassword: { 837 | code: '10006', 838 | message: '密码不匹配', 839 | result: '', 840 | }, 841 | } 842 | ``` 843 | 844 | 改写路由 845 | 846 | ```js 847 | // 登录接口 848 | router.post('/login', userValidator, verifyLogin, login) 849 | ``` 850 | 851 | # 十四. 用户的认证 852 | 853 | 登录成功后, 给用户颁发一个令牌 token, 用户在以后的每一次请求中携带这个令牌. 854 | 855 | jwt: jsonwebtoken 856 | 857 | - header: 头部 858 | - payload: 载荷 859 | - signature: 签名 860 | 861 | ## 1 颁发 token 862 | 863 | ### 1) 安装 jsonwebtoken 864 | 865 | ``` 866 | npm i jsonwebtoken 867 | ``` 868 | 869 | ### 2) 在控制器中改写 login 方法 870 | 871 | ```js 872 | async login(ctx, next) { 873 | const { user_name } = ctx.request.body 874 | 875 | // 1. 获取用户信息(在token的payload中, 记录id, user_name, is_admin) 876 | try { 877 | // 从返回结果对象中剔除password属性, 将剩下的属性放到res对象 878 | const { password, ...res } = await getUerInfo({ user_name }) 879 | 880 | ctx.body = { 881 | code: 0, 882 | message: '用户登录成功', 883 | result: { 884 | token: jwt.sign(res, JWT_SECRET, { expiresIn: '1d' }), 885 | }, 886 | } 887 | } catch (err) { 888 | console.error('用户登录失败', err) 889 | } 890 | } 891 | ``` 892 | 893 | ### 3) 定义私钥 894 | 895 | 在`.env`定义 896 | 897 | ``` 898 | JWT_SECRET = xzd 899 | ``` 900 | 901 | ## 2 用户认证 902 | 903 | ### 1) 创建 auth 中间件 904 | 905 | ```js 906 | const jwt = require('jsonwebtoken') 907 | 908 | const { JWT_SECRET } = require('../config/config.default') 909 | 910 | const { tokenExpiredError, invalidToken } = require('../constant/err.type') 911 | 912 | const auth = async (ctx, next) => { 913 | const { authorization } = ctx.request.header 914 | const token = authorization.replace('Bearer ', '') 915 | console.log(token) 916 | 917 | try { 918 | // user中包含了payload的信息(id, user_name, is_admin) 919 | const user = jwt.verify(token, JWT_SECRET) 920 | ctx.state.user = user 921 | } catch (err) { 922 | switch (err.name) { 923 | case 'TokenExpiredError': 924 | console.error('token已过期', err) 925 | return ctx.app.emit('error', tokenExpiredError, ctx) 926 | case 'JsonWebTokenError': 927 | console.error('无效的token', err) 928 | return ctx.app.emit('error', invalidToken, ctx) 929 | } 930 | } 931 | 932 | await next() 933 | } 934 | 935 | module.exports = { 936 | auth, 937 | } 938 | ``` 939 | 940 | ### 2) 改写 router 941 | 942 | ```js 943 | // 修改密码接口 944 | router.patch('/', auth, (ctx, next) => { 945 | console.log(ctx.state.user) 946 | ctx.body = '修改密码成功' 947 | }) 948 | ``` 949 | 950 | 新的内容 951 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "api", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@sindresorhus/is": { 8 | "version": "0.14.0", 9 | "resolved": "https://registry.nlark.com/@sindresorhus/is/download/@sindresorhus/is-0.14.0.tgz", 10 | "integrity": "sha1-n7OjzzEyMoFR81PeRjLgHlIQK+o=", 11 | "dev": true 12 | }, 13 | "@szmarczak/http-timer": { 14 | "version": "1.1.2", 15 | "resolved": "https://registry.npm.taobao.org/@szmarczak/http-timer/download/@szmarczak/http-timer-1.1.2.tgz", 16 | "integrity": "sha1-sWZeLEYaLNkvTBu/UNVFTeDUtCE=", 17 | "dev": true, 18 | "requires": { 19 | "defer-to-connect": "^1.0.1" 20 | } 21 | }, 22 | "@types/formidable": { 23 | "version": "1.2.2", 24 | "resolved": "https://registry.nlark.com/@types/formidable/download/@types/formidable-1.2.2.tgz?cache=0&sync_timestamp=1620993060172&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fformidable%2Fdownload%2F%40types%2Fformidable-1.2.2.tgz", 25 | "integrity": "sha1-5pDWBzLunT8KRBvFcsF0CXhbKDw=", 26 | "requires": { 27 | "@types/node": "*" 28 | } 29 | }, 30 | "@types/node": { 31 | "version": "15.3.1", 32 | "resolved": "https://registry.nlark.com/@types/node/download/@types/node-15.3.1.tgz?cache=0&sync_timestamp=1621463621315&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fnode%2Fdownload%2F%40types%2Fnode-15.3.1.tgz", 33 | "integrity": "sha1-I6Brh+7bUkAWYW6IaxFrj9yxgK8=" 34 | }, 35 | "abbrev": { 36 | "version": "1.1.1", 37 | "resolved": "https://registry.npm.taobao.org/abbrev/download/abbrev-1.1.1.tgz", 38 | "integrity": "sha1-+PLIh60Qv2f2NPAFtph/7TF5qsg=", 39 | "dev": true 40 | }, 41 | "accepts": { 42 | "version": "1.3.7", 43 | "resolved": "https://registry.npm.taobao.org/accepts/download/accepts-1.3.7.tgz", 44 | "integrity": "sha1-UxvHJlF6OytB+FACHGzBXqq1B80=", 45 | "requires": { 46 | "mime-types": "~2.1.24", 47 | "negotiator": "0.6.2" 48 | } 49 | }, 50 | "ansi-align": { 51 | "version": "3.0.0", 52 | "resolved": "https://registry.npm.taobao.org/ansi-align/download/ansi-align-3.0.0.tgz", 53 | "integrity": "sha1-tTazcc9ofKrvI2wY0+If43l0Z8s=", 54 | "dev": true, 55 | "requires": { 56 | "string-width": "^3.0.0" 57 | }, 58 | "dependencies": { 59 | "string-width": { 60 | "version": "3.1.0", 61 | "resolved": "https://registry.npm.taobao.org/string-width/download/string-width-3.1.0.tgz", 62 | "integrity": "sha1-InZ74htirxCBV0MG9prFG2IgOWE=", 63 | "dev": true, 64 | "requires": { 65 | "emoji-regex": "^7.0.1", 66 | "is-fullwidth-code-point": "^2.0.0", 67 | "strip-ansi": "^5.1.0" 68 | } 69 | } 70 | } 71 | }, 72 | "ansi-regex": { 73 | "version": "4.1.0", 74 | "resolved": "https://registry.nlark.com/ansi-regex/download/ansi-regex-4.1.0.tgz", 75 | "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=", 76 | "dev": true 77 | }, 78 | "ansi-styles": { 79 | "version": "4.3.0", 80 | "resolved": "https://registry.nlark.com/ansi-styles/download/ansi-styles-4.3.0.tgz?cache=0&sync_timestamp=1618995625950&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fansi-styles%2Fdownload%2Fansi-styles-4.3.0.tgz", 81 | "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=", 82 | "dev": true, 83 | "requires": { 84 | "color-convert": "^2.0.1" 85 | } 86 | }, 87 | "any-promise": { 88 | "version": "1.3.0", 89 | "resolved": "https://registry.npm.taobao.org/any-promise/download/any-promise-1.3.0.tgz", 90 | "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" 91 | }, 92 | "anymatch": { 93 | "version": "3.1.2", 94 | "resolved": "https://registry.npm.taobao.org/anymatch/download/anymatch-3.1.2.tgz", 95 | "integrity": "sha1-wFV8CWrzLxBhmPT04qODU343hxY=", 96 | "dev": true, 97 | "requires": { 98 | "normalize-path": "^3.0.0", 99 | "picomatch": "^2.0.4" 100 | } 101 | }, 102 | "balanced-match": { 103 | "version": "1.0.2", 104 | "resolved": "https://registry.npm.taobao.org/balanced-match/download/balanced-match-1.0.2.tgz", 105 | "integrity": "sha1-6D46fj8wCzTLnYf2FfoMvzV2kO4=", 106 | "dev": true 107 | }, 108 | "bcryptjs": { 109 | "version": "2.4.3", 110 | "resolved": "https://registry.nlark.com/bcryptjs/download/bcryptjs-2.4.3.tgz", 111 | "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=" 112 | }, 113 | "binary-extensions": { 114 | "version": "2.2.0", 115 | "resolved": "https://registry.npm.taobao.org/binary-extensions/download/binary-extensions-2.2.0.tgz?cache=0&sync_timestamp=1610299268308&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbinary-extensions%2Fdownload%2Fbinary-extensions-2.2.0.tgz", 116 | "integrity": "sha1-dfUC7q+f/eQvyYgpZFvk6na9ni0=", 117 | "dev": true 118 | }, 119 | "boxen": { 120 | "version": "4.2.0", 121 | "resolved": "https://registry.npm.taobao.org/boxen/download/boxen-4.2.0.tgz", 122 | "integrity": "sha1-5BG2I1fW1tNlh8isPV2XTaoHDmQ=", 123 | "dev": true, 124 | "requires": { 125 | "ansi-align": "^3.0.0", 126 | "camelcase": "^5.3.1", 127 | "chalk": "^3.0.0", 128 | "cli-boxes": "^2.2.0", 129 | "string-width": "^4.1.0", 130 | "term-size": "^2.1.0", 131 | "type-fest": "^0.8.1", 132 | "widest-line": "^3.1.0" 133 | } 134 | }, 135 | "brace-expansion": { 136 | "version": "1.1.11", 137 | "resolved": "https://registry.npm.taobao.org/brace-expansion/download/brace-expansion-1.1.11.tgz", 138 | "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", 139 | "dev": true, 140 | "requires": { 141 | "balanced-match": "^1.0.0", 142 | "concat-map": "0.0.1" 143 | } 144 | }, 145 | "braces": { 146 | "version": "3.0.2", 147 | "resolved": "https://registry.npm.taobao.org/braces/download/braces-3.0.2.tgz", 148 | "integrity": "sha1-NFThpGLujVmeI23zNs2epPiv4Qc=", 149 | "dev": true, 150 | "requires": { 151 | "fill-range": "^7.0.1" 152 | } 153 | }, 154 | "buffer-equal-constant-time": { 155 | "version": "1.0.1", 156 | "resolved": "https://registry.npm.taobao.org/buffer-equal-constant-time/download/buffer-equal-constant-time-1.0.1.tgz", 157 | "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" 158 | }, 159 | "bytes": { 160 | "version": "3.1.0", 161 | "resolved": "https://registry.npm.taobao.org/bytes/download/bytes-3.1.0.tgz", 162 | "integrity": "sha1-9s95M6Ng4FiPqf3oVlHNx/gF0fY=" 163 | }, 164 | "cache-content-type": { 165 | "version": "1.0.1", 166 | "resolved": "https://registry.npm.taobao.org/cache-content-type/download/cache-content-type-1.0.1.tgz", 167 | "integrity": "sha1-A1zeKwjuISn0qDFeqPAKANuhRTw=", 168 | "requires": { 169 | "mime-types": "^2.1.18", 170 | "ylru": "^1.2.0" 171 | } 172 | }, 173 | "cacheable-request": { 174 | "version": "6.1.0", 175 | "resolved": "https://registry.npm.taobao.org/cacheable-request/download/cacheable-request-6.1.0.tgz", 176 | "integrity": "sha1-IP+4vRYrpL4R6VZ9gj22UQUsqRI=", 177 | "dev": true, 178 | "requires": { 179 | "clone-response": "^1.0.2", 180 | "get-stream": "^5.1.0", 181 | "http-cache-semantics": "^4.0.0", 182 | "keyv": "^3.0.0", 183 | "lowercase-keys": "^2.0.0", 184 | "normalize-url": "^4.1.0", 185 | "responselike": "^1.0.2" 186 | }, 187 | "dependencies": { 188 | "get-stream": { 189 | "version": "5.2.0", 190 | "resolved": "https://registry.nlark.com/get-stream/download/get-stream-5.2.0.tgz?cache=0&sync_timestamp=1618847023057&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fget-stream%2Fdownload%2Fget-stream-5.2.0.tgz", 191 | "integrity": "sha1-SWaheV7lrOZecGxLe+txJX1uItM=", 192 | "dev": true, 193 | "requires": { 194 | "pump": "^3.0.0" 195 | } 196 | }, 197 | "lowercase-keys": { 198 | "version": "2.0.0", 199 | "resolved": "https://registry.npm.taobao.org/lowercase-keys/download/lowercase-keys-2.0.0.tgz", 200 | "integrity": "sha1-JgPni3tLAAbLyi+8yKMgJVislHk=", 201 | "dev": true 202 | } 203 | } 204 | }, 205 | "call-bind": { 206 | "version": "1.0.2", 207 | "resolved": "https://registry.npm.taobao.org/call-bind/download/call-bind-1.0.2.tgz?cache=0&sync_timestamp=1610405478355&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcall-bind%2Fdownload%2Fcall-bind-1.0.2.tgz", 208 | "integrity": "sha1-sdTonmiBGcPJqQOtMKuy9qkZvjw=", 209 | "requires": { 210 | "function-bind": "^1.1.1", 211 | "get-intrinsic": "^1.0.2" 212 | } 213 | }, 214 | "camelcase": { 215 | "version": "5.3.1", 216 | "resolved": "https://registry.npm.taobao.org/camelcase/download/camelcase-5.3.1.tgz?cache=0&sync_timestamp=1603921884289&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcamelcase%2Fdownload%2Fcamelcase-5.3.1.tgz", 217 | "integrity": "sha1-48mzFWnhBoEd8kL3FXJaH0xJQyA=", 218 | "dev": true 219 | }, 220 | "chalk": { 221 | "version": "3.0.0", 222 | "resolved": "https://registry.nlark.com/chalk/download/chalk-3.0.0.tgz?cache=0&sync_timestamp=1618995297666&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fchalk%2Fdownload%2Fchalk-3.0.0.tgz", 223 | "integrity": "sha1-P3PCv1JlkfV0zEksUeJFY0n4ROQ=", 224 | "dev": true, 225 | "requires": { 226 | "ansi-styles": "^4.1.0", 227 | "supports-color": "^7.1.0" 228 | }, 229 | "dependencies": { 230 | "has-flag": { 231 | "version": "4.0.0", 232 | "resolved": "https://registry.nlark.com/has-flag/download/has-flag-4.0.0.tgz?cache=0&sync_timestamp=1618847009337&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fhas-flag%2Fdownload%2Fhas-flag-4.0.0.tgz", 233 | "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=", 234 | "dev": true 235 | }, 236 | "supports-color": { 237 | "version": "7.2.0", 238 | "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-7.2.0.tgz?cache=0&sync_timestamp=1618560998281&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-7.2.0.tgz", 239 | "integrity": "sha1-G33NyzK4E4gBs+R4umpRyqiWSNo=", 240 | "dev": true, 241 | "requires": { 242 | "has-flag": "^4.0.0" 243 | } 244 | } 245 | } 246 | }, 247 | "chokidar": { 248 | "version": "3.5.1", 249 | "resolved": "https://registry.npm.taobao.org/chokidar/download/chokidar-3.5.1.tgz?cache=0&sync_timestamp=1610719499558&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fchokidar%2Fdownload%2Fchokidar-3.5.1.tgz", 250 | "integrity": "sha1-7pznu+vSt59J8wR5nVRo4x4U5oo=", 251 | "dev": true, 252 | "requires": { 253 | "anymatch": "~3.1.1", 254 | "braces": "~3.0.2", 255 | "fsevents": "~2.3.1", 256 | "glob-parent": "~5.1.0", 257 | "is-binary-path": "~2.1.0", 258 | "is-glob": "~4.0.1", 259 | "normalize-path": "~3.0.0", 260 | "readdirp": "~3.5.0" 261 | } 262 | }, 263 | "ci-info": { 264 | "version": "2.0.0", 265 | "resolved": "https://registry.npm.taobao.org/ci-info/download/ci-info-2.0.0.tgz?cache=0&sync_timestamp=1613628860338&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fci-info%2Fdownload%2Fci-info-2.0.0.tgz", 266 | "integrity": "sha1-Z6npZL4xpR4V5QENWObxKDQAL0Y=", 267 | "dev": true 268 | }, 269 | "cli-boxes": { 270 | "version": "2.2.1", 271 | "resolved": "https://registry.npm.taobao.org/cli-boxes/download/cli-boxes-2.2.1.tgz?cache=0&sync_timestamp=1610824917487&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcli-boxes%2Fdownload%2Fcli-boxes-2.2.1.tgz", 272 | "integrity": "sha1-3dUDXSUJT84iDpyrQKRYQKRAMY8=", 273 | "dev": true 274 | }, 275 | "clone-response": { 276 | "version": "1.0.2", 277 | "resolved": "https://registry.npm.taobao.org/clone-response/download/clone-response-1.0.2.tgz", 278 | "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", 279 | "dev": true, 280 | "requires": { 281 | "mimic-response": "^1.0.0" 282 | } 283 | }, 284 | "co": { 285 | "version": "4.6.0", 286 | "resolved": "https://registry.npm.taobao.org/co/download/co-4.6.0.tgz", 287 | "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" 288 | }, 289 | "co-body": { 290 | "version": "5.2.0", 291 | "resolved": "https://registry.npm.taobao.org/co-body/download/co-body-5.2.0.tgz", 292 | "integrity": "sha1-WgpljEYCkTHg46MG9nZHMC9xwSQ=", 293 | "requires": { 294 | "inflation": "^2.0.0", 295 | "qs": "^6.4.0", 296 | "raw-body": "^2.2.0", 297 | "type-is": "^1.6.14" 298 | } 299 | }, 300 | "color-convert": { 301 | "version": "2.0.1", 302 | "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz", 303 | "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=", 304 | "dev": true, 305 | "requires": { 306 | "color-name": "~1.1.4" 307 | } 308 | }, 309 | "color-name": { 310 | "version": "1.1.4", 311 | "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz", 312 | "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=", 313 | "dev": true 314 | }, 315 | "concat-map": { 316 | "version": "0.0.1", 317 | "resolved": "https://registry.npm.taobao.org/concat-map/download/concat-map-0.0.1.tgz", 318 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 319 | "dev": true 320 | }, 321 | "configstore": { 322 | "version": "5.0.1", 323 | "resolved": "https://registry.nlark.com/configstore/download/configstore-5.0.1.tgz", 324 | "integrity": "sha1-02UCG130uYzdGH1qOw4/anzF7ZY=", 325 | "dev": true, 326 | "requires": { 327 | "dot-prop": "^5.2.0", 328 | "graceful-fs": "^4.1.2", 329 | "make-dir": "^3.0.0", 330 | "unique-string": "^2.0.0", 331 | "write-file-atomic": "^3.0.0", 332 | "xdg-basedir": "^4.0.0" 333 | } 334 | }, 335 | "content-disposition": { 336 | "version": "0.5.3", 337 | "resolved": "https://registry.npm.taobao.org/content-disposition/download/content-disposition-0.5.3.tgz", 338 | "integrity": "sha1-4TDK9+cnkIfFYWwgB9BIVpiYT70=", 339 | "requires": { 340 | "safe-buffer": "5.1.2" 341 | } 342 | }, 343 | "content-type": { 344 | "version": "1.0.4", 345 | "resolved": "https://registry.npm.taobao.org/content-type/download/content-type-1.0.4.tgz", 346 | "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=" 347 | }, 348 | "cookies": { 349 | "version": "0.8.0", 350 | "resolved": "https://registry.npm.taobao.org/cookies/download/cookies-0.8.0.tgz", 351 | "integrity": "sha1-EpPOSzkXQKhAbjyYcOgoxLVPP5A=", 352 | "requires": { 353 | "depd": "~2.0.0", 354 | "keygrip": "~1.1.0" 355 | } 356 | }, 357 | "crypto-random-string": { 358 | "version": "2.0.0", 359 | "resolved": "https://registry.npm.taobao.org/crypto-random-string/download/crypto-random-string-2.0.0.tgz?cache=0&sync_timestamp=1617610467993&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcrypto-random-string%2Fdownload%2Fcrypto-random-string-2.0.0.tgz", 360 | "integrity": "sha1-7yp6lm7BEIM4g2m6oC6+rSKbMNU=", 361 | "dev": true 362 | }, 363 | "debug": { 364 | "version": "3.1.0", 365 | "resolved": "https://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz?cache=0&sync_timestamp=1607566571506&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-3.1.0.tgz", 366 | "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", 367 | "requires": { 368 | "ms": "2.0.0" 369 | } 370 | }, 371 | "decompress-response": { 372 | "version": "3.3.0", 373 | "resolved": "https://registry.npm.taobao.org/decompress-response/download/decompress-response-3.3.0.tgz?cache=0&sync_timestamp=1613125479486&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdecompress-response%2Fdownload%2Fdecompress-response-3.3.0.tgz", 374 | "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", 375 | "dev": true, 376 | "requires": { 377 | "mimic-response": "^1.0.0" 378 | } 379 | }, 380 | "deep-equal": { 381 | "version": "1.0.1", 382 | "resolved": "https://registry.npm.taobao.org/deep-equal/download/deep-equal-1.0.1.tgz", 383 | "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=" 384 | }, 385 | "deep-extend": { 386 | "version": "0.6.0", 387 | "resolved": "https://registry.npm.taobao.org/deep-extend/download/deep-extend-0.6.0.tgz", 388 | "integrity": "sha1-xPp8lUBKF6nD6Mp+FTcxK3NjMKw=", 389 | "dev": true 390 | }, 391 | "defer-to-connect": { 392 | "version": "1.1.3", 393 | "resolved": "https://registry.npm.taobao.org/defer-to-connect/download/defer-to-connect-1.1.3.tgz?cache=0&sync_timestamp=1614211138920&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdefer-to-connect%2Fdownload%2Fdefer-to-connect-1.1.3.tgz", 394 | "integrity": "sha1-MxrgUMCNz3ifjIOnuB8O2U9KxZE=", 395 | "dev": true 396 | }, 397 | "delegates": { 398 | "version": "1.0.0", 399 | "resolved": "https://registry.npm.taobao.org/delegates/download/delegates-1.0.0.tgz", 400 | "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" 401 | }, 402 | "denque": { 403 | "version": "1.5.0", 404 | "resolved": "https://registry.npm.taobao.org/denque/download/denque-1.5.0.tgz", 405 | "integrity": "sha1-dz3gaG/y2Owv+SkUMWpHtzscc94=" 406 | }, 407 | "depd": { 408 | "version": "2.0.0", 409 | "resolved": "https://registry.npm.taobao.org/depd/download/depd-2.0.0.tgz", 410 | "integrity": "sha1-tpYWPMdXVg0JzyLMj60Vcbeedt8=" 411 | }, 412 | "destroy": { 413 | "version": "1.0.4", 414 | "resolved": "https://registry.npm.taobao.org/destroy/download/destroy-1.0.4.tgz", 415 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 416 | }, 417 | "dot-prop": { 418 | "version": "5.3.0", 419 | "resolved": "https://registry.npm.taobao.org/dot-prop/download/dot-prop-5.3.0.tgz?cache=0&sync_timestamp=1605778171073&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdot-prop%2Fdownload%2Fdot-prop-5.3.0.tgz", 420 | "integrity": "sha1-kMzOcIzZzYLMTcjD3dmr3VWyDog=", 421 | "dev": true, 422 | "requires": { 423 | "is-obj": "^2.0.0" 424 | } 425 | }, 426 | "dotenv": { 427 | "version": "9.0.2", 428 | "resolved": "https://registry.nlark.com/dotenv/download/dotenv-9.0.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdotenv%2Fdownload%2Fdotenv-9.0.2.tgz", 429 | "integrity": "sha1-2swgFgk1o33qY2SqG++Bn7m2qwU=" 430 | }, 431 | "dottie": { 432 | "version": "2.0.2", 433 | "resolved": "https://registry.npm.taobao.org/dottie/download/dottie-2.0.2.tgz", 434 | "integrity": "sha1-zJHAcmzjoFTr8RxV+8kqfyZt0VQ=" 435 | }, 436 | "duplexer3": { 437 | "version": "0.1.4", 438 | "resolved": "https://registry.npm.taobao.org/duplexer3/download/duplexer3-0.1.4.tgz", 439 | "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", 440 | "dev": true 441 | }, 442 | "ecdsa-sig-formatter": { 443 | "version": "1.0.11", 444 | "resolved": "https://registry.npm.taobao.org/ecdsa-sig-formatter/download/ecdsa-sig-formatter-1.0.11.tgz", 445 | "integrity": "sha1-rg8PothQRe8UqBfao86azQSJ5b8=", 446 | "requires": { 447 | "safe-buffer": "^5.0.1" 448 | } 449 | }, 450 | "ee-first": { 451 | "version": "1.1.1", 452 | "resolved": "https://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz", 453 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 454 | }, 455 | "emoji-regex": { 456 | "version": "7.0.3", 457 | "resolved": "https://registry.npm.taobao.org/emoji-regex/download/emoji-regex-7.0.3.tgz?cache=0&sync_timestamp=1614682818988&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Femoji-regex%2Fdownload%2Femoji-regex-7.0.3.tgz", 458 | "integrity": "sha1-kzoEBShgyF6DwSJHnEdIqOTHIVY=", 459 | "dev": true 460 | }, 461 | "encodeurl": { 462 | "version": "1.0.2", 463 | "resolved": "https://registry.npm.taobao.org/encodeurl/download/encodeurl-1.0.2.tgz", 464 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 465 | }, 466 | "end-of-stream": { 467 | "version": "1.4.4", 468 | "resolved": "https://registry.npm.taobao.org/end-of-stream/download/end-of-stream-1.4.4.tgz", 469 | "integrity": "sha1-WuZKX0UFe682JuwU2gyl5LJDHrA=", 470 | "dev": true, 471 | "requires": { 472 | "once": "^1.4.0" 473 | } 474 | }, 475 | "escape-goat": { 476 | "version": "2.1.1", 477 | "resolved": "https://registry.npm.taobao.org/escape-goat/download/escape-goat-2.1.1.tgz", 478 | "integrity": "sha1-Gy3HcANnbEV+x2Cy3GjttkgYhnU=", 479 | "dev": true 480 | }, 481 | "escape-html": { 482 | "version": "1.0.3", 483 | "resolved": "https://registry.npm.taobao.org/escape-html/download/escape-html-1.0.3.tgz", 484 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 485 | }, 486 | "fill-range": { 487 | "version": "7.0.1", 488 | "resolved": "https://registry.npm.taobao.org/fill-range/download/fill-range-7.0.1.tgz", 489 | "integrity": "sha1-GRmmp8df44ssfHflGYU12prN2kA=", 490 | "dev": true, 491 | "requires": { 492 | "to-regex-range": "^5.0.1" 493 | } 494 | }, 495 | "formidable": { 496 | "version": "1.2.2", 497 | "resolved": "https://registry.npm.taobao.org/formidable/download/formidable-1.2.2.tgz", 498 | "integrity": "sha1-v2muopcpgmdfAIZTQrmCmG9rjdk=" 499 | }, 500 | "fresh": { 501 | "version": "0.5.2", 502 | "resolved": "https://registry.npm.taobao.org/fresh/download/fresh-0.5.2.tgz", 503 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 504 | }, 505 | "fsevents": { 506 | "version": "2.3.2", 507 | "resolved": "https://registry.npm.taobao.org/fsevents/download/fsevents-2.3.2.tgz?cache=0&sync_timestamp=1612536512306&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffsevents%2Fdownload%2Ffsevents-2.3.2.tgz", 508 | "integrity": "sha1-ilJveLj99GI7cJ4Ll1xSwkwC/Ro=", 509 | "dev": true, 510 | "optional": true 511 | }, 512 | "function-bind": { 513 | "version": "1.1.1", 514 | "resolved": "https://registry.npm.taobao.org/function-bind/download/function-bind-1.1.1.tgz", 515 | "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=" 516 | }, 517 | "generate-function": { 518 | "version": "2.3.1", 519 | "resolved": "https://registry.npm.taobao.org/generate-function/download/generate-function-2.3.1.tgz", 520 | "integrity": "sha1-8GlhdpDBDIaOc7hGV0Z2T5fDR58=", 521 | "requires": { 522 | "is-property": "^1.0.2" 523 | } 524 | }, 525 | "get-intrinsic": { 526 | "version": "1.1.1", 527 | "resolved": "https://registry.npm.taobao.org/get-intrinsic/download/get-intrinsic-1.1.1.tgz?cache=0&sync_timestamp=1612364352840&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fget-intrinsic%2Fdownload%2Fget-intrinsic-1.1.1.tgz", 528 | "integrity": "sha1-FfWfN2+FXERpY5SPDSTNNje0q8Y=", 529 | "requires": { 530 | "function-bind": "^1.1.1", 531 | "has": "^1.0.3", 532 | "has-symbols": "^1.0.1" 533 | } 534 | }, 535 | "get-stream": { 536 | "version": "4.1.0", 537 | "resolved": "https://registry.nlark.com/get-stream/download/get-stream-4.1.0.tgz?cache=0&sync_timestamp=1618847023057&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fget-stream%2Fdownload%2Fget-stream-4.1.0.tgz", 538 | "integrity": "sha1-wbJVV189wh1Zv8ec09K0axw6VLU=", 539 | "dev": true, 540 | "requires": { 541 | "pump": "^3.0.0" 542 | } 543 | }, 544 | "glob-parent": { 545 | "version": "5.1.2", 546 | "resolved": "https://registry.nlark.com/glob-parent/download/glob-parent-5.1.2.tgz?cache=0&sync_timestamp=1620073671816&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fglob-parent%2Fdownload%2Fglob-parent-5.1.2.tgz", 547 | "integrity": "sha1-hpgyxYA0/mikCTwX3BXoNA2EAcQ=", 548 | "dev": true, 549 | "requires": { 550 | "is-glob": "^4.0.1" 551 | } 552 | }, 553 | "global-dirs": { 554 | "version": "2.1.0", 555 | "resolved": "https://registry.npm.taobao.org/global-dirs/download/global-dirs-2.1.0.tgz?cache=0&sync_timestamp=1610454716901&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fglobal-dirs%2Fdownload%2Fglobal-dirs-2.1.0.tgz", 556 | "integrity": "sha1-6QRqScgG/wTWwYJeGWyPAJHo300=", 557 | "dev": true, 558 | "requires": { 559 | "ini": "1.3.7" 560 | } 561 | }, 562 | "got": { 563 | "version": "9.6.0", 564 | "resolved": "https://registry.npm.taobao.org/got/download/got-9.6.0.tgz?cache=0&sync_timestamp=1614332558999&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fgot%2Fdownload%2Fgot-9.6.0.tgz", 565 | "integrity": "sha1-7fRefWf5lUVwXeH3u+7rEhdl7YU=", 566 | "dev": true, 567 | "requires": { 568 | "@sindresorhus/is": "^0.14.0", 569 | "@szmarczak/http-timer": "^1.1.2", 570 | "cacheable-request": "^6.0.0", 571 | "decompress-response": "^3.3.0", 572 | "duplexer3": "^0.1.4", 573 | "get-stream": "^4.1.0", 574 | "lowercase-keys": "^1.0.1", 575 | "mimic-response": "^1.0.1", 576 | "p-cancelable": "^1.0.0", 577 | "to-readable-stream": "^1.0.0", 578 | "url-parse-lax": "^3.0.0" 579 | } 580 | }, 581 | "graceful-fs": { 582 | "version": "4.2.6", 583 | "resolved": "https://registry.npm.taobao.org/graceful-fs/download/graceful-fs-4.2.6.tgz", 584 | "integrity": "sha1-/wQLKwhTsjw9MQJ1I3BvGIXXa+4=", 585 | "dev": true 586 | }, 587 | "has": { 588 | "version": "1.0.3", 589 | "resolved": "https://registry.npm.taobao.org/has/download/has-1.0.3.tgz", 590 | "integrity": "sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y=", 591 | "requires": { 592 | "function-bind": "^1.1.1" 593 | } 594 | }, 595 | "has-flag": { 596 | "version": "3.0.0", 597 | "resolved": "https://registry.nlark.com/has-flag/download/has-flag-3.0.0.tgz?cache=0&sync_timestamp=1618847009337&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fhas-flag%2Fdownload%2Fhas-flag-3.0.0.tgz", 598 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 599 | "dev": true 600 | }, 601 | "has-symbols": { 602 | "version": "1.0.2", 603 | "resolved": "https://registry.npm.taobao.org/has-symbols/download/has-symbols-1.0.2.tgz?cache=0&sync_timestamp=1614443681706&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhas-symbols%2Fdownload%2Fhas-symbols-1.0.2.tgz", 604 | "integrity": "sha1-Fl0wcMADCXUqEjakeTMeOsVvFCM=" 605 | }, 606 | "has-yarn": { 607 | "version": "2.1.0", 608 | "resolved": "https://registry.npm.taobao.org/has-yarn/download/has-yarn-2.1.0.tgz", 609 | "integrity": "sha1-E34RNUp7W/EapctknPDG8/8rLnc=", 610 | "dev": true 611 | }, 612 | "http-assert": { 613 | "version": "1.4.1", 614 | "resolved": "https://registry.npm.taobao.org/http-assert/download/http-assert-1.4.1.tgz", 615 | "integrity": "sha1-xfcl1neqfoc+9zYZm4lobM6zeHg=", 616 | "requires": { 617 | "deep-equal": "~1.0.1", 618 | "http-errors": "~1.7.2" 619 | }, 620 | "dependencies": { 621 | "depd": { 622 | "version": "1.1.2", 623 | "resolved": "https://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz", 624 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 625 | }, 626 | "http-errors": { 627 | "version": "1.7.3", 628 | "resolved": "https://registry.npm.taobao.org/http-errors/download/http-errors-1.7.3.tgz", 629 | "integrity": "sha1-bGGeT5xgMIw4UZSYwU+7EKrOuwY=", 630 | "requires": { 631 | "depd": "~1.1.2", 632 | "inherits": "2.0.4", 633 | "setprototypeof": "1.1.1", 634 | "statuses": ">= 1.5.0 < 2", 635 | "toidentifier": "1.0.0" 636 | } 637 | } 638 | } 639 | }, 640 | "http-cache-semantics": { 641 | "version": "4.1.0", 642 | "resolved": "https://registry.npm.taobao.org/http-cache-semantics/download/http-cache-semantics-4.1.0.tgz", 643 | "integrity": "sha1-SekcXL82yblLz81xwj1SSex045A=", 644 | "dev": true 645 | }, 646 | "http-errors": { 647 | "version": "1.8.0", 648 | "resolved": "https://registry.npm.taobao.org/http-errors/download/http-errors-1.8.0.tgz", 649 | "integrity": "sha1-ddG75JfhBE9R5O6ecEpi8o0zZQc=", 650 | "requires": { 651 | "depd": "~1.1.2", 652 | "inherits": "2.0.4", 653 | "setprototypeof": "1.2.0", 654 | "statuses": ">= 1.5.0 < 2", 655 | "toidentifier": "1.0.0" 656 | }, 657 | "dependencies": { 658 | "depd": { 659 | "version": "1.1.2", 660 | "resolved": "https://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz", 661 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 662 | }, 663 | "setprototypeof": { 664 | "version": "1.2.0", 665 | "resolved": "https://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.2.0.tgz", 666 | "integrity": "sha1-ZsmiSnP5/CjL5msJ/tPTPcrxtCQ=" 667 | } 668 | } 669 | }, 670 | "iconv-lite": { 671 | "version": "0.4.24", 672 | "resolved": "https://registry.npm.taobao.org/iconv-lite/download/iconv-lite-0.4.24.tgz?cache=0&sync_timestamp=1594184264130&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ficonv-lite%2Fdownload%2Ficonv-lite-0.4.24.tgz", 673 | "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=", 674 | "requires": { 675 | "safer-buffer": ">= 2.1.2 < 3" 676 | } 677 | }, 678 | "ignore-by-default": { 679 | "version": "1.0.1", 680 | "resolved": "https://registry.npm.taobao.org/ignore-by-default/download/ignore-by-default-1.0.1.tgz", 681 | "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", 682 | "dev": true 683 | }, 684 | "import-lazy": { 685 | "version": "2.1.0", 686 | "resolved": "https://registry.npm.taobao.org/import-lazy/download/import-lazy-2.1.0.tgz", 687 | "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", 688 | "dev": true 689 | }, 690 | "imurmurhash": { 691 | "version": "0.1.4", 692 | "resolved": "https://registry.npm.taobao.org/imurmurhash/download/imurmurhash-0.1.4.tgz", 693 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", 694 | "dev": true 695 | }, 696 | "inflation": { 697 | "version": "2.0.0", 698 | "resolved": "https://registry.npm.taobao.org/inflation/download/inflation-2.0.0.tgz", 699 | "integrity": "sha1-i0F+R8KPklpFEz2RTKH9OJEH8w8=" 700 | }, 701 | "inflection": { 702 | "version": "1.12.0", 703 | "resolved": "https://registry.nlark.com/inflection/download/inflection-1.12.0.tgz", 704 | "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=" 705 | }, 706 | "inherits": { 707 | "version": "2.0.4", 708 | "resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.4.tgz", 709 | "integrity": "sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w=" 710 | }, 711 | "ini": { 712 | "version": "1.3.7", 713 | "resolved": "https://registry.npm.taobao.org/ini/download/ini-1.3.7.tgz?cache=0&sync_timestamp=1607907801722&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fini%2Fdownload%2Fini-1.3.7.tgz", 714 | "integrity": "sha1-oJNj4ZEZcuoW16iFEAXYTPCamoQ=", 715 | "dev": true 716 | }, 717 | "is-binary-path": { 718 | "version": "2.1.0", 719 | "resolved": "https://registry.npm.taobao.org/is-binary-path/download/is-binary-path-2.1.0.tgz", 720 | "integrity": "sha1-6h9/O4DwZCNug0cPhsCcJU+0Wwk=", 721 | "dev": true, 722 | "requires": { 723 | "binary-extensions": "^2.0.0" 724 | } 725 | }, 726 | "is-ci": { 727 | "version": "2.0.0", 728 | "resolved": "https://registry.npm.taobao.org/is-ci/download/is-ci-2.0.0.tgz?cache=0&sync_timestamp=1613631987391&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-ci%2Fdownload%2Fis-ci-2.0.0.tgz", 729 | "integrity": "sha1-a8YzQYGBDgS1wis9WJ/cpVAmQEw=", 730 | "dev": true, 731 | "requires": { 732 | "ci-info": "^2.0.0" 733 | } 734 | }, 735 | "is-extglob": { 736 | "version": "2.1.1", 737 | "resolved": "https://registry.npm.taobao.org/is-extglob/download/is-extglob-2.1.1.tgz", 738 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", 739 | "dev": true 740 | }, 741 | "is-fullwidth-code-point": { 742 | "version": "2.0.0", 743 | "resolved": "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-2.0.0.tgz?cache=0&sync_timestamp=1618552489864&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-fullwidth-code-point%2Fdownload%2Fis-fullwidth-code-point-2.0.0.tgz", 744 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 745 | "dev": true 746 | }, 747 | "is-generator-function": { 748 | "version": "1.0.9", 749 | "resolved": "https://registry.nlark.com/is-generator-function/download/is-generator-function-1.0.9.tgz", 750 | "integrity": "sha1-5fgsIyNnPn/K09EoWMg8QDn2OZw=" 751 | }, 752 | "is-glob": { 753 | "version": "4.0.1", 754 | "resolved": "https://registry.npm.taobao.org/is-glob/download/is-glob-4.0.1.tgz", 755 | "integrity": "sha1-dWfb6fL14kZ7x3q4PEopSCQHpdw=", 756 | "dev": true, 757 | "requires": { 758 | "is-extglob": "^2.1.1" 759 | } 760 | }, 761 | "is-installed-globally": { 762 | "version": "0.3.2", 763 | "resolved": "https://registry.npm.taobao.org/is-installed-globally/download/is-installed-globally-0.3.2.tgz?cache=0&sync_timestamp=1610875192100&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-installed-globally%2Fdownload%2Fis-installed-globally-0.3.2.tgz", 764 | "integrity": "sha1-/T76ee5nDRGHIzGC1bCh3QAxMUE=", 765 | "dev": true, 766 | "requires": { 767 | "global-dirs": "^2.0.1", 768 | "is-path-inside": "^3.0.1" 769 | } 770 | }, 771 | "is-npm": { 772 | "version": "4.0.0", 773 | "resolved": "https://registry.npm.taobao.org/is-npm/download/is-npm-4.0.0.tgz?cache=0&sync_timestamp=1589565368496&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-npm%2Fdownload%2Fis-npm-4.0.0.tgz", 774 | "integrity": "sha1-yQ3YOAaW34enptgjwg0LErvjyE0=", 775 | "dev": true 776 | }, 777 | "is-number": { 778 | "version": "7.0.0", 779 | "resolved": "https://registry.npm.taobao.org/is-number/download/is-number-7.0.0.tgz", 780 | "integrity": "sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss=", 781 | "dev": true 782 | }, 783 | "is-obj": { 784 | "version": "2.0.0", 785 | "resolved": "https://registry.npm.taobao.org/is-obj/download/is-obj-2.0.0.tgz?cache=0&sync_timestamp=1618600242427&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-obj%2Fdownload%2Fis-obj-2.0.0.tgz", 786 | "integrity": "sha1-Rz+wXZc3BeP9liBUUBjKjiLvSYI=", 787 | "dev": true 788 | }, 789 | "is-path-inside": { 790 | "version": "3.0.3", 791 | "resolved": "https://registry.nlark.com/is-path-inside/download/is-path-inside-3.0.3.tgz?cache=0&sync_timestamp=1620046845369&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fis-path-inside%2Fdownload%2Fis-path-inside-3.0.3.tgz", 792 | "integrity": "sha1-0jE2LlOgf/Kw4Op/7QSRYf/RYoM=", 793 | "dev": true 794 | }, 795 | "is-property": { 796 | "version": "1.0.2", 797 | "resolved": "https://registry.npm.taobao.org/is-property/download/is-property-1.0.2.tgz", 798 | "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" 799 | }, 800 | "is-typedarray": { 801 | "version": "1.0.0", 802 | "resolved": "https://registry.npm.taobao.org/is-typedarray/download/is-typedarray-1.0.0.tgz", 803 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", 804 | "dev": true 805 | }, 806 | "is-yarn-global": { 807 | "version": "0.3.0", 808 | "resolved": "https://registry.nlark.com/is-yarn-global/download/is-yarn-global-0.3.0.tgz?cache=0&sync_timestamp=1619356719315&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fis-yarn-global%2Fdownload%2Fis-yarn-global-0.3.0.tgz", 809 | "integrity": "sha1-1QLTOCWQ6jAEiTdGdUyJE5lz4jI=", 810 | "dev": true 811 | }, 812 | "json-buffer": { 813 | "version": "3.0.0", 814 | "resolved": "https://registry.npm.taobao.org/json-buffer/download/json-buffer-3.0.0.tgz", 815 | "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", 816 | "dev": true 817 | }, 818 | "jsonwebtoken": { 819 | "version": "8.5.1", 820 | "resolved": "https://registry.npm.taobao.org/jsonwebtoken/download/jsonwebtoken-8.5.1.tgz", 821 | "integrity": "sha1-AOceC431TCEhofJhN98igGc7zA0=", 822 | "requires": { 823 | "jws": "^3.2.2", 824 | "lodash.includes": "^4.3.0", 825 | "lodash.isboolean": "^3.0.3", 826 | "lodash.isinteger": "^4.0.4", 827 | "lodash.isnumber": "^3.0.3", 828 | "lodash.isplainobject": "^4.0.6", 829 | "lodash.isstring": "^4.0.1", 830 | "lodash.once": "^4.0.0", 831 | "ms": "^2.1.1", 832 | "semver": "^5.6.0" 833 | }, 834 | "dependencies": { 835 | "ms": { 836 | "version": "2.1.3", 837 | "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.3.tgz?cache=0&sync_timestamp=1607433926553&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.1.3.tgz", 838 | "integrity": "sha1-V0yBOM4dK1hh8LRFedut1gxmFbI=" 839 | } 840 | } 841 | }, 842 | "jwa": { 843 | "version": "1.4.1", 844 | "resolved": "https://registry.npm.taobao.org/jwa/download/jwa-1.4.1.tgz", 845 | "integrity": "sha1-dDwymFy56YZVUw1TZBtmyGRbA5o=", 846 | "requires": { 847 | "buffer-equal-constant-time": "1.0.1", 848 | "ecdsa-sig-formatter": "1.0.11", 849 | "safe-buffer": "^5.0.1" 850 | } 851 | }, 852 | "jws": { 853 | "version": "3.2.2", 854 | "resolved": "https://registry.npm.taobao.org/jws/download/jws-3.2.2.tgz", 855 | "integrity": "sha1-ABCZ82OUaMlBQADpmZX6UvtHgwQ=", 856 | "requires": { 857 | "jwa": "^1.4.1", 858 | "safe-buffer": "^5.0.1" 859 | } 860 | }, 861 | "keygrip": { 862 | "version": "1.1.0", 863 | "resolved": "https://registry.npm.taobao.org/keygrip/download/keygrip-1.1.0.tgz", 864 | "integrity": "sha1-hxsWgdXhWcYqRFsMdLYV4JF+ciY=", 865 | "requires": { 866 | "tsscmp": "1.0.6" 867 | } 868 | }, 869 | "keyv": { 870 | "version": "3.1.0", 871 | "resolved": "https://registry.npm.taobao.org/keyv/download/keyv-3.1.0.tgz?cache=0&sync_timestamp=1600337541422&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fkeyv%2Fdownload%2Fkeyv-3.1.0.tgz", 872 | "integrity": "sha1-7MIoSG9pmR5J6UdkhaW+Ho/FxNk=", 873 | "dev": true, 874 | "requires": { 875 | "json-buffer": "3.0.0" 876 | } 877 | }, 878 | "koa": { 879 | "version": "2.13.1", 880 | "resolved": "https://registry.nlark.com/koa/download/koa-2.13.1.tgz", 881 | "integrity": "sha1-YnUXKHWye8/h1FQ1altrn1qbEFE=", 882 | "requires": { 883 | "accepts": "^1.3.5", 884 | "cache-content-type": "^1.0.0", 885 | "content-disposition": "~0.5.2", 886 | "content-type": "^1.0.4", 887 | "cookies": "~0.8.0", 888 | "debug": "~3.1.0", 889 | "delegates": "^1.0.0", 890 | "depd": "^2.0.0", 891 | "destroy": "^1.0.4", 892 | "encodeurl": "^1.0.2", 893 | "escape-html": "^1.0.3", 894 | "fresh": "~0.5.2", 895 | "http-assert": "^1.3.0", 896 | "http-errors": "^1.6.3", 897 | "is-generator-function": "^1.0.7", 898 | "koa-compose": "^4.1.0", 899 | "koa-convert": "^1.2.0", 900 | "on-finished": "^2.3.0", 901 | "only": "~0.0.2", 902 | "parseurl": "^1.3.2", 903 | "statuses": "^1.5.0", 904 | "type-is": "^1.6.16", 905 | "vary": "^1.1.2" 906 | } 907 | }, 908 | "koa-body": { 909 | "version": "4.2.0", 910 | "resolved": "https://registry.npm.taobao.org/koa-body/download/koa-body-4.2.0.tgz", 911 | "integrity": "sha1-NyKSCLggdhrKWCLRTF/FXO4xsm8=", 912 | "requires": { 913 | "@types/formidable": "^1.0.31", 914 | "co-body": "^5.1.1", 915 | "formidable": "^1.1.1" 916 | } 917 | }, 918 | "koa-compose": { 919 | "version": "4.1.0", 920 | "resolved": "https://registry.npm.taobao.org/koa-compose/download/koa-compose-4.1.0.tgz", 921 | "integrity": "sha1-UHMGuTcZAdtBEhyBLpI9DWfT6Hc=" 922 | }, 923 | "koa-convert": { 924 | "version": "1.2.0", 925 | "resolved": "https://registry.npm.taobao.org/koa-convert/download/koa-convert-1.2.0.tgz", 926 | "integrity": "sha1-2kCHXfSd4FOQmNFwC1CCDOvNIdA=", 927 | "requires": { 928 | "co": "^4.6.0", 929 | "koa-compose": "^3.0.0" 930 | }, 931 | "dependencies": { 932 | "koa-compose": { 933 | "version": "3.2.1", 934 | "resolved": "https://registry.npm.taobao.org/koa-compose/download/koa-compose-3.2.1.tgz", 935 | "integrity": "sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec=", 936 | "requires": { 937 | "any-promise": "^1.1.0" 938 | } 939 | } 940 | } 941 | }, 942 | "koa-parameter": { 943 | "version": "3.0.1", 944 | "resolved": "https://registry.npm.taobao.org/koa-parameter/download/koa-parameter-3.0.1.tgz", 945 | "integrity": "sha1-sGRfJBLq23nToYCNF+0wgkpUyIc=", 946 | "requires": { 947 | "parameter": "^2.2.0" 948 | } 949 | }, 950 | "koa-router": { 951 | "version": "10.0.0", 952 | "resolved": "https://registry.nlark.com/koa-router/download/koa-router-10.0.0.tgz", 953 | "integrity": "sha1-e8dqAxCFcx5h/JLBaDaHsvRN5qQ=", 954 | "requires": { 955 | "debug": "^4.1.1", 956 | "http-errors": "^1.7.3", 957 | "koa-compose": "^4.1.0", 958 | "methods": "^1.1.2", 959 | "path-to-regexp": "^6.1.0" 960 | }, 961 | "dependencies": { 962 | "debug": { 963 | "version": "4.3.1", 964 | "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.3.1.tgz?cache=0&sync_timestamp=1607566571506&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-4.3.1.tgz", 965 | "integrity": "sha1-8NIpxQXgxtjEmsVT0bE9wYP2su4=", 966 | "requires": { 967 | "ms": "2.1.2" 968 | } 969 | }, 970 | "ms": { 971 | "version": "2.1.2", 972 | "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz?cache=0&sync_timestamp=1607433926553&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.1.2.tgz", 973 | "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk=" 974 | } 975 | } 976 | }, 977 | "koa-send": { 978 | "version": "5.0.1", 979 | "resolved": "https://registry.npm.taobao.org/koa-send/download/koa-send-5.0.1.tgz", 980 | "integrity": "sha1-Odzuv6+zldDWC+r/ujpwtPVD/nk=", 981 | "requires": { 982 | "debug": "^4.1.1", 983 | "http-errors": "^1.7.3", 984 | "resolve-path": "^1.4.0" 985 | }, 986 | "dependencies": { 987 | "debug": { 988 | "version": "4.3.1", 989 | "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.3.1.tgz?cache=0&sync_timestamp=1607566571506&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-4.3.1.tgz", 990 | "integrity": "sha1-8NIpxQXgxtjEmsVT0bE9wYP2su4=", 991 | "requires": { 992 | "ms": "2.1.2" 993 | } 994 | }, 995 | "ms": { 996 | "version": "2.1.2", 997 | "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz?cache=0&sync_timestamp=1607433926553&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.1.2.tgz", 998 | "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk=" 999 | } 1000 | } 1001 | }, 1002 | "koa-static": { 1003 | "version": "5.0.0", 1004 | "resolved": "https://registry.npm.taobao.org/koa-static/download/koa-static-5.0.0.tgz", 1005 | "integrity": "sha1-XpL8lrU3rVIZ9CUxnJW2R3J3aUM=", 1006 | "requires": { 1007 | "debug": "^3.1.0", 1008 | "koa-send": "^5.0.0" 1009 | } 1010 | }, 1011 | "latest-version": { 1012 | "version": "5.1.0", 1013 | "resolved": "https://registry.npm.taobao.org/latest-version/download/latest-version-5.1.0.tgz", 1014 | "integrity": "sha1-EZ3+kI/jjRXfpD7NE/oS7Igy+s4=", 1015 | "dev": true, 1016 | "requires": { 1017 | "package-json": "^6.3.0" 1018 | } 1019 | }, 1020 | "lodash": { 1021 | "version": "4.17.21", 1022 | "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.21.tgz?cache=0&sync_timestamp=1613835817439&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.21.tgz", 1023 | "integrity": "sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw=" 1024 | }, 1025 | "lodash.includes": { 1026 | "version": "4.3.0", 1027 | "resolved": "https://registry.npm.taobao.org/lodash.includes/download/lodash.includes-4.3.0.tgz", 1028 | "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" 1029 | }, 1030 | "lodash.isboolean": { 1031 | "version": "3.0.3", 1032 | "resolved": "https://registry.npm.taobao.org/lodash.isboolean/download/lodash.isboolean-3.0.3.tgz", 1033 | "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" 1034 | }, 1035 | "lodash.isinteger": { 1036 | "version": "4.0.4", 1037 | "resolved": "https://registry.npm.taobao.org/lodash.isinteger/download/lodash.isinteger-4.0.4.tgz", 1038 | "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" 1039 | }, 1040 | "lodash.isnumber": { 1041 | "version": "3.0.3", 1042 | "resolved": "https://registry.npm.taobao.org/lodash.isnumber/download/lodash.isnumber-3.0.3.tgz", 1043 | "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" 1044 | }, 1045 | "lodash.isplainobject": { 1046 | "version": "4.0.6", 1047 | "resolved": "https://registry.npm.taobao.org/lodash.isplainobject/download/lodash.isplainobject-4.0.6.tgz", 1048 | "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" 1049 | }, 1050 | "lodash.isstring": { 1051 | "version": "4.0.1", 1052 | "resolved": "https://registry.npm.taobao.org/lodash.isstring/download/lodash.isstring-4.0.1.tgz", 1053 | "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" 1054 | }, 1055 | "lodash.once": { 1056 | "version": "4.1.1", 1057 | "resolved": "https://registry.npm.taobao.org/lodash.once/download/lodash.once-4.1.1.tgz", 1058 | "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" 1059 | }, 1060 | "long": { 1061 | "version": "4.0.0", 1062 | "resolved": "https://registry.npm.taobao.org/long/download/long-4.0.0.tgz", 1063 | "integrity": "sha1-mntxz7fTYaGU6lVSQckvdGjVvyg=" 1064 | }, 1065 | "lowercase-keys": { 1066 | "version": "1.0.1", 1067 | "resolved": "https://registry.npm.taobao.org/lowercase-keys/download/lowercase-keys-1.0.1.tgz", 1068 | "integrity": "sha1-b54wtHCE2XGnyCD/FabFFnt0wm8=", 1069 | "dev": true 1070 | }, 1071 | "lru-cache": { 1072 | "version": "6.0.0", 1073 | "resolved": "https://registry.npm.taobao.org/lru-cache/download/lru-cache-6.0.0.tgz?cache=0&sync_timestamp=1594427567713&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-6.0.0.tgz", 1074 | "integrity": "sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ=", 1075 | "requires": { 1076 | "yallist": "^4.0.0" 1077 | } 1078 | }, 1079 | "make-dir": { 1080 | "version": "3.1.0", 1081 | "resolved": "https://registry.npm.taobao.org/make-dir/download/make-dir-3.1.0.tgz?cache=0&sync_timestamp=1587567875186&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmake-dir%2Fdownload%2Fmake-dir-3.1.0.tgz", 1082 | "integrity": "sha1-QV6WcEazp/HRhSd9hKpYIDcmoT8=", 1083 | "dev": true, 1084 | "requires": { 1085 | "semver": "^6.0.0" 1086 | }, 1087 | "dependencies": { 1088 | "semver": { 1089 | "version": "6.3.0", 1090 | "resolved": "https://registry.npm.taobao.org/semver/download/semver-6.3.0.tgz?cache=0&sync_timestamp=1616463550093&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-6.3.0.tgz", 1091 | "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", 1092 | "dev": true 1093 | } 1094 | } 1095 | }, 1096 | "media-typer": { 1097 | "version": "0.3.0", 1098 | "resolved": "https://registry.npm.taobao.org/media-typer/download/media-typer-0.3.0.tgz", 1099 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 1100 | }, 1101 | "methods": { 1102 | "version": "1.1.2", 1103 | "resolved": "https://registry.npm.taobao.org/methods/download/methods-1.1.2.tgz", 1104 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 1105 | }, 1106 | "mime-db": { 1107 | "version": "1.47.0", 1108 | "resolved": "https://registry.npm.taobao.org/mime-db/download/mime-db-1.47.0.tgz?cache=0&sync_timestamp=1617306025156&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmime-db%2Fdownload%2Fmime-db-1.47.0.tgz", 1109 | "integrity": "sha1-jLMT5Zll08Bc+/iYkVomevRqM1w=" 1110 | }, 1111 | "mime-types": { 1112 | "version": "2.1.30", 1113 | "resolved": "https://registry.npm.taobao.org/mime-types/download/mime-types-2.1.30.tgz", 1114 | "integrity": "sha1-bnvotMR5gl+F7WMmaV23P5MF1i0=", 1115 | "requires": { 1116 | "mime-db": "1.47.0" 1117 | } 1118 | }, 1119 | "mimic-response": { 1120 | "version": "1.0.1", 1121 | "resolved": "https://registry.npm.taobao.org/mimic-response/download/mimic-response-1.0.1.tgz?cache=0&sync_timestamp=1589481080007&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmimic-response%2Fdownload%2Fmimic-response-1.0.1.tgz", 1122 | "integrity": "sha1-SSNTiHju9CBjy4o+OweYeBSHqxs=", 1123 | "dev": true 1124 | }, 1125 | "minimatch": { 1126 | "version": "3.0.4", 1127 | "resolved": "https://registry.npm.taobao.org/minimatch/download/minimatch-3.0.4.tgz", 1128 | "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", 1129 | "dev": true, 1130 | "requires": { 1131 | "brace-expansion": "^1.1.7" 1132 | } 1133 | }, 1134 | "minimist": { 1135 | "version": "1.2.5", 1136 | "resolved": "https://registry.npm.taobao.org/minimist/download/minimist-1.2.5.tgz", 1137 | "integrity": "sha1-Z9ZgFLZqaoqqDAg8X9WN9OTpdgI=", 1138 | "dev": true 1139 | }, 1140 | "moment": { 1141 | "version": "2.29.1", 1142 | "resolved": "https://registry.npm.taobao.org/moment/download/moment-2.29.1.tgz?cache=0&sync_timestamp=1601983320283&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmoment%2Fdownload%2Fmoment-2.29.1.tgz", 1143 | "integrity": "sha1-sr52n6MZQL6e7qZGnAdeNQBvo9M=" 1144 | }, 1145 | "moment-timezone": { 1146 | "version": "0.5.33", 1147 | "resolved": "https://registry.npm.taobao.org/moment-timezone/download/moment-timezone-0.5.33.tgz", 1148 | "integrity": "sha1-slL9a7V/NBybWaWrYajlGnO70iw=", 1149 | "requires": { 1150 | "moment": ">= 2.9.0" 1151 | } 1152 | }, 1153 | "ms": { 1154 | "version": "2.0.0", 1155 | "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz?cache=0&sync_timestamp=1607433926553&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.0.0.tgz", 1156 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 1157 | }, 1158 | "mysql2": { 1159 | "version": "2.2.5", 1160 | "resolved": "https://registry.npm.taobao.org/mysql2/download/mysql2-2.2.5.tgz", 1161 | "integrity": "sha1-cmJP+0gW+A+Wucl/7djACTX580A=", 1162 | "requires": { 1163 | "denque": "^1.4.1", 1164 | "generate-function": "^2.3.1", 1165 | "iconv-lite": "^0.6.2", 1166 | "long": "^4.0.0", 1167 | "lru-cache": "^6.0.0", 1168 | "named-placeholders": "^1.1.2", 1169 | "seq-queue": "^0.0.5", 1170 | "sqlstring": "^2.3.2" 1171 | }, 1172 | "dependencies": { 1173 | "iconv-lite": { 1174 | "version": "0.6.2", 1175 | "resolved": "https://registry.npm.taobao.org/iconv-lite/download/iconv-lite-0.6.2.tgz?cache=0&sync_timestamp=1594184264130&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ficonv-lite%2Fdownload%2Ficonv-lite-0.6.2.tgz", 1176 | "integrity": "sha1-zhPRh1sMOmdL1qBLf3awGxtt7QE=", 1177 | "requires": { 1178 | "safer-buffer": ">= 2.1.2 < 3.0.0" 1179 | } 1180 | } 1181 | } 1182 | }, 1183 | "named-placeholders": { 1184 | "version": "1.1.2", 1185 | "resolved": "https://registry.npm.taobao.org/named-placeholders/download/named-placeholders-1.1.2.tgz", 1186 | "integrity": "sha1-zrH7/1C2szSStc8hTM9eOc7z0Og=", 1187 | "requires": { 1188 | "lru-cache": "^4.1.3" 1189 | }, 1190 | "dependencies": { 1191 | "lru-cache": { 1192 | "version": "4.1.5", 1193 | "resolved": "https://registry.npm.taobao.org/lru-cache/download/lru-cache-4.1.5.tgz?cache=0&sync_timestamp=1594427567713&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-4.1.5.tgz", 1194 | "integrity": "sha1-i75Q6oW+1ZvJ4z3KuCNe6bz0Q80=", 1195 | "requires": { 1196 | "pseudomap": "^1.0.2", 1197 | "yallist": "^2.1.2" 1198 | } 1199 | }, 1200 | "yallist": { 1201 | "version": "2.1.2", 1202 | "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-2.1.2.tgz", 1203 | "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" 1204 | } 1205 | } 1206 | }, 1207 | "negotiator": { 1208 | "version": "0.6.2", 1209 | "resolved": "https://registry.npm.taobao.org/negotiator/download/negotiator-0.6.2.tgz", 1210 | "integrity": "sha1-/qz3zPUlp3rpY0Q2pkiD/+yjRvs=" 1211 | }, 1212 | "nodemon": { 1213 | "version": "2.0.7", 1214 | "resolved": "https://registry.nlark.com/nodemon/download/nodemon-2.0.7.tgz", 1215 | "integrity": "sha1-bwMKCg6+PqG6Kjj3G/m6tIQc7TI=", 1216 | "dev": true, 1217 | "requires": { 1218 | "chokidar": "^3.2.2", 1219 | "debug": "^3.2.6", 1220 | "ignore-by-default": "^1.0.1", 1221 | "minimatch": "^3.0.4", 1222 | "pstree.remy": "^1.1.7", 1223 | "semver": "^5.7.1", 1224 | "supports-color": "^5.5.0", 1225 | "touch": "^3.1.0", 1226 | "undefsafe": "^2.0.3", 1227 | "update-notifier": "^4.1.0" 1228 | }, 1229 | "dependencies": { 1230 | "debug": { 1231 | "version": "3.2.7", 1232 | "resolved": "https://registry.npm.taobao.org/debug/download/debug-3.2.7.tgz?cache=0&sync_timestamp=1607566571506&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-3.2.7.tgz", 1233 | "integrity": "sha1-clgLfpFF+zm2Z2+cXl+xALk0F5o=", 1234 | "dev": true, 1235 | "requires": { 1236 | "ms": "^2.1.1" 1237 | } 1238 | }, 1239 | "ms": { 1240 | "version": "2.1.3", 1241 | "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.3.tgz?cache=0&sync_timestamp=1607433926553&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.1.3.tgz", 1242 | "integrity": "sha1-V0yBOM4dK1hh8LRFedut1gxmFbI=", 1243 | "dev": true 1244 | } 1245 | } 1246 | }, 1247 | "nopt": { 1248 | "version": "1.0.10", 1249 | "resolved": "https://registry.npm.taobao.org/nopt/download/nopt-1.0.10.tgz?cache=0&sync_timestamp=1597649920098&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnopt%2Fdownload%2Fnopt-1.0.10.tgz", 1250 | "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", 1251 | "dev": true, 1252 | "requires": { 1253 | "abbrev": "1" 1254 | } 1255 | }, 1256 | "normalize-path": { 1257 | "version": "3.0.0", 1258 | "resolved": "https://registry.npm.taobao.org/normalize-path/download/normalize-path-3.0.0.tgz", 1259 | "integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU=", 1260 | "dev": true 1261 | }, 1262 | "normalize-url": { 1263 | "version": "4.5.0", 1264 | "resolved": "https://registry.npm.taobao.org/normalize-url/download/normalize-url-4.5.0.tgz?cache=0&sync_timestamp=1617786343734&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnormalize-url%2Fdownload%2Fnormalize-url-4.5.0.tgz", 1265 | "integrity": "sha1-RTNUCH5sqWlXvY9br3U/WYIUISk=", 1266 | "dev": true 1267 | }, 1268 | "object-inspect": { 1269 | "version": "1.10.3", 1270 | "resolved": "https://registry.nlark.com/object-inspect/download/object-inspect-1.10.3.tgz?cache=0&sync_timestamp=1620446097930&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fobject-inspect%2Fdownload%2Fobject-inspect-1.10.3.tgz", 1271 | "integrity": "sha1-wqp9LQn1DJk3VwT3oK3yTFeC02k=" 1272 | }, 1273 | "on-finished": { 1274 | "version": "2.3.0", 1275 | "resolved": "https://registry.npm.taobao.org/on-finished/download/on-finished-2.3.0.tgz", 1276 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 1277 | "requires": { 1278 | "ee-first": "1.1.1" 1279 | } 1280 | }, 1281 | "once": { 1282 | "version": "1.4.0", 1283 | "resolved": "https://registry.npm.taobao.org/once/download/once-1.4.0.tgz", 1284 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1285 | "dev": true, 1286 | "requires": { 1287 | "wrappy": "1" 1288 | } 1289 | }, 1290 | "only": { 1291 | "version": "0.0.2", 1292 | "resolved": "https://registry.npm.taobao.org/only/download/only-0.0.2.tgz", 1293 | "integrity": "sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q=" 1294 | }, 1295 | "p-cancelable": { 1296 | "version": "1.1.0", 1297 | "resolved": "https://registry.nlark.com/p-cancelable/download/p-cancelable-1.1.0.tgz?cache=0&sync_timestamp=1619950979130&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fp-cancelable%2Fdownload%2Fp-cancelable-1.1.0.tgz", 1298 | "integrity": "sha1-0HjRWjr0CSIMiG8dmgyi5EGrJsw=", 1299 | "dev": true 1300 | }, 1301 | "package-json": { 1302 | "version": "6.5.0", 1303 | "resolved": "https://registry.npm.taobao.org/package-json/download/package-json-6.5.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpackage-json%2Fdownload%2Fpackage-json-6.5.0.tgz", 1304 | "integrity": "sha1-b+7ayjXnVyWHbQsOZJdGl/7RRbA=", 1305 | "dev": true, 1306 | "requires": { 1307 | "got": "^9.6.0", 1308 | "registry-auth-token": "^4.0.0", 1309 | "registry-url": "^5.0.0", 1310 | "semver": "^6.2.0" 1311 | }, 1312 | "dependencies": { 1313 | "semver": { 1314 | "version": "6.3.0", 1315 | "resolved": "https://registry.npm.taobao.org/semver/download/semver-6.3.0.tgz?cache=0&sync_timestamp=1616463550093&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-6.3.0.tgz", 1316 | "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", 1317 | "dev": true 1318 | } 1319 | } 1320 | }, 1321 | "parameter": { 1322 | "version": "2.4.0", 1323 | "resolved": "https://registry.npm.taobao.org/parameter/download/parameter-2.4.0.tgz", 1324 | "integrity": "sha1-hepS6d/ugCZaB7CG7bw1LmizlzM=" 1325 | }, 1326 | "parseurl": { 1327 | "version": "1.3.3", 1328 | "resolved": "https://registry.npm.taobao.org/parseurl/download/parseurl-1.3.3.tgz", 1329 | "integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ=" 1330 | }, 1331 | "path-is-absolute": { 1332 | "version": "1.0.1", 1333 | "resolved": "https://registry.npm.taobao.org/path-is-absolute/download/path-is-absolute-1.0.1.tgz", 1334 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 1335 | }, 1336 | "path-to-regexp": { 1337 | "version": "6.2.0", 1338 | "resolved": "https://registry.npm.taobao.org/path-to-regexp/download/path-to-regexp-6.2.0.tgz?cache=0&sync_timestamp=1601400247487&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpath-to-regexp%2Fdownload%2Fpath-to-regexp-6.2.0.tgz", 1339 | "integrity": "sha1-97OAMzYQTDRoia3s5hRmkjBkXzg=" 1340 | }, 1341 | "picomatch": { 1342 | "version": "2.2.3", 1343 | "resolved": "https://registry.npm.taobao.org/picomatch/download/picomatch-2.2.3.tgz?cache=0&sync_timestamp=1618049925917&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpicomatch%2Fdownload%2Fpicomatch-2.2.3.tgz", 1344 | "integrity": "sha1-RlVH81nMwgbTxI5Goby4m/fuYZ0=", 1345 | "dev": true 1346 | }, 1347 | "prepend-http": { 1348 | "version": "2.0.0", 1349 | "resolved": "https://registry.npm.taobao.org/prepend-http/download/prepend-http-2.0.0.tgz", 1350 | "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", 1351 | "dev": true 1352 | }, 1353 | "pseudomap": { 1354 | "version": "1.0.2", 1355 | "resolved": "https://registry.npm.taobao.org/pseudomap/download/pseudomap-1.0.2.tgz", 1356 | "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" 1357 | }, 1358 | "pstree.remy": { 1359 | "version": "1.1.8", 1360 | "resolved": "https://registry.npm.taobao.org/pstree.remy/download/pstree.remy-1.1.8.tgz", 1361 | "integrity": "sha1-wkIiT0pnwh9oaDm720rCgrg3PTo=", 1362 | "dev": true 1363 | }, 1364 | "pump": { 1365 | "version": "3.0.0", 1366 | "resolved": "https://registry.npm.taobao.org/pump/download/pump-3.0.0.tgz", 1367 | "integrity": "sha1-tKIRaBW94vTh6mAjVOjHVWUQemQ=", 1368 | "dev": true, 1369 | "requires": { 1370 | "end-of-stream": "^1.1.0", 1371 | "once": "^1.3.1" 1372 | } 1373 | }, 1374 | "pupa": { 1375 | "version": "2.1.1", 1376 | "resolved": "https://registry.npm.taobao.org/pupa/download/pupa-2.1.1.tgz", 1377 | "integrity": "sha1-9ej9SvwsXZeCj6pSNUnth0SiDWI=", 1378 | "dev": true, 1379 | "requires": { 1380 | "escape-goat": "^2.0.0" 1381 | } 1382 | }, 1383 | "qs": { 1384 | "version": "6.10.1", 1385 | "resolved": "https://registry.npm.taobao.org/qs/download/qs-6.10.1.tgz?cache=0&sync_timestamp=1616385248556&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fqs%2Fdownload%2Fqs-6.10.1.tgz", 1386 | "integrity": "sha1-STFIL6jWR6Wqt5nFJx0hM7mB+2o=", 1387 | "requires": { 1388 | "side-channel": "^1.0.4" 1389 | } 1390 | }, 1391 | "raw-body": { 1392 | "version": "2.4.1", 1393 | "resolved": "https://registry.npm.taobao.org/raw-body/download/raw-body-2.4.1.tgz", 1394 | "integrity": "sha1-MKyC+Yu1rowVLmcUnayNVRU7Fow=", 1395 | "requires": { 1396 | "bytes": "3.1.0", 1397 | "http-errors": "1.7.3", 1398 | "iconv-lite": "0.4.24", 1399 | "unpipe": "1.0.0" 1400 | }, 1401 | "dependencies": { 1402 | "depd": { 1403 | "version": "1.1.2", 1404 | "resolved": "https://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz", 1405 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 1406 | }, 1407 | "http-errors": { 1408 | "version": "1.7.3", 1409 | "resolved": "https://registry.npm.taobao.org/http-errors/download/http-errors-1.7.3.tgz", 1410 | "integrity": "sha1-bGGeT5xgMIw4UZSYwU+7EKrOuwY=", 1411 | "requires": { 1412 | "depd": "~1.1.2", 1413 | "inherits": "2.0.4", 1414 | "setprototypeof": "1.1.1", 1415 | "statuses": ">= 1.5.0 < 2", 1416 | "toidentifier": "1.0.0" 1417 | } 1418 | } 1419 | } 1420 | }, 1421 | "rc": { 1422 | "version": "1.2.8", 1423 | "resolved": "https://registry.npm.taobao.org/rc/download/rc-1.2.8.tgz", 1424 | "integrity": "sha1-zZJL9SAKB1uDwYjNa54hG3/A0+0=", 1425 | "dev": true, 1426 | "requires": { 1427 | "deep-extend": "^0.6.0", 1428 | "ini": "~1.3.0", 1429 | "minimist": "^1.2.0", 1430 | "strip-json-comments": "~2.0.1" 1431 | } 1432 | }, 1433 | "readdirp": { 1434 | "version": "3.5.0", 1435 | "resolved": "https://registry.npm.taobao.org/readdirp/download/readdirp-3.5.0.tgz", 1436 | "integrity": "sha1-m6dMAZsV02UnjS6Ru4xI17TULJ4=", 1437 | "dev": true, 1438 | "requires": { 1439 | "picomatch": "^2.2.1" 1440 | } 1441 | }, 1442 | "registry-auth-token": { 1443 | "version": "4.2.1", 1444 | "resolved": "https://registry.npm.taobao.org/registry-auth-token/download/registry-auth-token-4.2.1.tgz", 1445 | "integrity": "sha1-bXtABkQZGJcszV/tzUHcMix5slA=", 1446 | "dev": true, 1447 | "requires": { 1448 | "rc": "^1.2.8" 1449 | } 1450 | }, 1451 | "registry-url": { 1452 | "version": "5.1.0", 1453 | "resolved": "https://registry.nlark.com/registry-url/download/registry-url-5.1.0.tgz", 1454 | "integrity": "sha1-6YM0tQ1UNLgRNrROxjjZwgCcUAk=", 1455 | "dev": true, 1456 | "requires": { 1457 | "rc": "^1.2.8" 1458 | } 1459 | }, 1460 | "resolve-path": { 1461 | "version": "1.4.0", 1462 | "resolved": "https://registry.npm.taobao.org/resolve-path/download/resolve-path-1.4.0.tgz", 1463 | "integrity": "sha1-xL2p9e+y/OZSR4c6s2u02DT+Fvc=", 1464 | "requires": { 1465 | "http-errors": "~1.6.2", 1466 | "path-is-absolute": "1.0.1" 1467 | }, 1468 | "dependencies": { 1469 | "depd": { 1470 | "version": "1.1.2", 1471 | "resolved": "https://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz", 1472 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 1473 | }, 1474 | "http-errors": { 1475 | "version": "1.6.3", 1476 | "resolved": "https://registry.npm.taobao.org/http-errors/download/http-errors-1.6.3.tgz", 1477 | "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", 1478 | "requires": { 1479 | "depd": "~1.1.2", 1480 | "inherits": "2.0.3", 1481 | "setprototypeof": "1.1.0", 1482 | "statuses": ">= 1.4.0 < 2" 1483 | } 1484 | }, 1485 | "inherits": { 1486 | "version": "2.0.3", 1487 | "resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.3.tgz", 1488 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 1489 | }, 1490 | "setprototypeof": { 1491 | "version": "1.1.0", 1492 | "resolved": "https://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.1.0.tgz", 1493 | "integrity": "sha1-0L2FU2iHtv58DYGMuWLZ2RxU5lY=" 1494 | } 1495 | } 1496 | }, 1497 | "responselike": { 1498 | "version": "1.0.2", 1499 | "resolved": "https://registry.npm.taobao.org/responselike/download/responselike-1.0.2.tgz", 1500 | "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", 1501 | "dev": true, 1502 | "requires": { 1503 | "lowercase-keys": "^1.0.0" 1504 | } 1505 | }, 1506 | "retry-as-promised": { 1507 | "version": "3.2.0", 1508 | "resolved": "https://registry.npm.taobao.org/retry-as-promised/download/retry-as-promised-3.2.0.tgz", 1509 | "integrity": "sha1-dp9j1Ta+xHg1SdsHd8tW2t2dhUM=", 1510 | "requires": { 1511 | "any-promise": "^1.3.0" 1512 | } 1513 | }, 1514 | "safe-buffer": { 1515 | "version": "5.1.2", 1516 | "resolved": "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.2.tgz", 1517 | "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" 1518 | }, 1519 | "safer-buffer": { 1520 | "version": "2.1.2", 1521 | "resolved": "https://registry.npm.taobao.org/safer-buffer/download/safer-buffer-2.1.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsafer-buffer%2Fdownload%2Fsafer-buffer-2.1.2.tgz", 1522 | "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=" 1523 | }, 1524 | "semver": { 1525 | "version": "5.7.1", 1526 | "resolved": "https://registry.npm.taobao.org/semver/download/semver-5.7.1.tgz?cache=0&sync_timestamp=1616463550093&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-5.7.1.tgz", 1527 | "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=" 1528 | }, 1529 | "semver-diff": { 1530 | "version": "3.1.1", 1531 | "resolved": "https://registry.nlark.com/semver-diff/download/semver-diff-3.1.1.tgz", 1532 | "integrity": "sha1-Bfd85Z8yXgDicGr9Z7tQbdscoys=", 1533 | "dev": true, 1534 | "requires": { 1535 | "semver": "^6.3.0" 1536 | }, 1537 | "dependencies": { 1538 | "semver": { 1539 | "version": "6.3.0", 1540 | "resolved": "https://registry.npm.taobao.org/semver/download/semver-6.3.0.tgz?cache=0&sync_timestamp=1616463550093&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-6.3.0.tgz", 1541 | "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", 1542 | "dev": true 1543 | } 1544 | } 1545 | }, 1546 | "seq-queue": { 1547 | "version": "0.0.5", 1548 | "resolved": "https://registry.npm.taobao.org/seq-queue/download/seq-queue-0.0.5.tgz", 1549 | "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" 1550 | }, 1551 | "sequelize": { 1552 | "version": "6.6.2", 1553 | "resolved": "https://registry.npm.taobao.org/sequelize/download/sequelize-6.6.2.tgz", 1554 | "integrity": "sha1-NoGwpK6xBuMQedOlN9iFQgUdqy4=", 1555 | "requires": { 1556 | "debug": "^4.1.1", 1557 | "dottie": "^2.0.0", 1558 | "inflection": "1.12.0", 1559 | "lodash": "^4.17.20", 1560 | "moment": "^2.26.0", 1561 | "moment-timezone": "^0.5.31", 1562 | "retry-as-promised": "^3.2.0", 1563 | "semver": "^7.3.2", 1564 | "sequelize-pool": "^6.0.0", 1565 | "toposort-class": "^1.0.1", 1566 | "uuid": "^8.1.0", 1567 | "validator": "^10.11.0", 1568 | "wkx": "^0.5.0" 1569 | }, 1570 | "dependencies": { 1571 | "debug": { 1572 | "version": "4.3.1", 1573 | "resolved": "https://registry.npm.taobao.org/debug/download/debug-4.3.1.tgz?cache=0&sync_timestamp=1607566571506&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-4.3.1.tgz", 1574 | "integrity": "sha1-8NIpxQXgxtjEmsVT0bE9wYP2su4=", 1575 | "requires": { 1576 | "ms": "2.1.2" 1577 | } 1578 | }, 1579 | "ms": { 1580 | "version": "2.1.2", 1581 | "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz?cache=0&sync_timestamp=1607433926553&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.1.2.tgz", 1582 | "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk=" 1583 | }, 1584 | "semver": { 1585 | "version": "7.3.5", 1586 | "resolved": "https://registry.npm.taobao.org/semver/download/semver-7.3.5.tgz?cache=0&sync_timestamp=1616463550093&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-7.3.5.tgz", 1587 | "integrity": "sha1-C2Ich5NI2JmOSw5L6Us/EuYBjvc=", 1588 | "requires": { 1589 | "lru-cache": "^6.0.0" 1590 | } 1591 | } 1592 | } 1593 | }, 1594 | "sequelize-pool": { 1595 | "version": "6.1.0", 1596 | "resolved": "https://registry.npm.taobao.org/sequelize-pool/download/sequelize-pool-6.1.0.tgz", 1597 | "integrity": "sha1-yqoMHjJNPCw6OZ/tLHmYlwkl1mg=" 1598 | }, 1599 | "setprototypeof": { 1600 | "version": "1.1.1", 1601 | "resolved": "https://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.1.1.tgz", 1602 | "integrity": "sha1-fpWsskqpL1iF4KvvW6ExMw1K5oM=" 1603 | }, 1604 | "side-channel": { 1605 | "version": "1.0.4", 1606 | "resolved": "https://registry.npm.taobao.org/side-channel/download/side-channel-1.0.4.tgz", 1607 | "integrity": "sha1-785cj9wQTudRslxY1CkAEfpeos8=", 1608 | "requires": { 1609 | "call-bind": "^1.0.0", 1610 | "get-intrinsic": "^1.0.2", 1611 | "object-inspect": "^1.9.0" 1612 | } 1613 | }, 1614 | "signal-exit": { 1615 | "version": "3.0.3", 1616 | "resolved": "https://registry.npm.taobao.org/signal-exit/download/signal-exit-3.0.3.tgz", 1617 | "integrity": "sha1-oUEMLt2PB3sItOJTyOrPyvBXRhw=", 1618 | "dev": true 1619 | }, 1620 | "sqlstring": { 1621 | "version": "2.3.2", 1622 | "resolved": "https://registry.npm.taobao.org/sqlstring/download/sqlstring-2.3.2.tgz", 1623 | "integrity": "sha1-za5xaTiaE3WxjohfLmCz5GCAlRQ=" 1624 | }, 1625 | "statuses": { 1626 | "version": "1.5.0", 1627 | "resolved": "https://registry.npm.taobao.org/statuses/download/statuses-1.5.0.tgz?cache=0&sync_timestamp=1609654065358&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstatuses%2Fdownload%2Fstatuses-1.5.0.tgz", 1628 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 1629 | }, 1630 | "string-width": { 1631 | "version": "4.2.2", 1632 | "resolved": "https://registry.npm.taobao.org/string-width/download/string-width-4.2.2.tgz", 1633 | "integrity": "sha1-2v1PlVmnWFz7pSnGoKT3NIjr1MU=", 1634 | "dev": true, 1635 | "requires": { 1636 | "emoji-regex": "^8.0.0", 1637 | "is-fullwidth-code-point": "^3.0.0", 1638 | "strip-ansi": "^6.0.0" 1639 | }, 1640 | "dependencies": { 1641 | "ansi-regex": { 1642 | "version": "5.0.0", 1643 | "resolved": "https://registry.nlark.com/ansi-regex/download/ansi-regex-5.0.0.tgz", 1644 | "integrity": "sha1-OIU59VF5vzkznIGvMKZU1p+Hy3U=", 1645 | "dev": true 1646 | }, 1647 | "emoji-regex": { 1648 | "version": "8.0.0", 1649 | "resolved": "https://registry.npm.taobao.org/emoji-regex/download/emoji-regex-8.0.0.tgz?cache=0&sync_timestamp=1614682818988&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Femoji-regex%2Fdownload%2Femoji-regex-8.0.0.tgz", 1650 | "integrity": "sha1-6Bj9ac5cz8tARZT4QpY79TFkzDc=", 1651 | "dev": true 1652 | }, 1653 | "is-fullwidth-code-point": { 1654 | "version": "3.0.0", 1655 | "resolved": "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-3.0.0.tgz?cache=0&sync_timestamp=1618552489864&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-fullwidth-code-point%2Fdownload%2Fis-fullwidth-code-point-3.0.0.tgz", 1656 | "integrity": "sha1-8Rb4Bk/pCz94RKOJl8C3UFEmnx0=", 1657 | "dev": true 1658 | }, 1659 | "strip-ansi": { 1660 | "version": "6.0.0", 1661 | "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-6.0.0.tgz?cache=0&sync_timestamp=1618553299612&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-6.0.0.tgz", 1662 | "integrity": "sha1-CxVx3XZpzNTz4G4U7x7tJiJa5TI=", 1663 | "dev": true, 1664 | "requires": { 1665 | "ansi-regex": "^5.0.0" 1666 | } 1667 | } 1668 | } 1669 | }, 1670 | "strip-ansi": { 1671 | "version": "5.2.0", 1672 | "resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-5.2.0.tgz?cache=0&sync_timestamp=1618553299612&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-5.2.0.tgz", 1673 | "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", 1674 | "dev": true, 1675 | "requires": { 1676 | "ansi-regex": "^4.1.0" 1677 | } 1678 | }, 1679 | "strip-json-comments": { 1680 | "version": "2.0.1", 1681 | "resolved": "https://registry.npm.taobao.org/strip-json-comments/download/strip-json-comments-2.0.1.tgz?cache=0&sync_timestamp=1594567580605&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-json-comments%2Fdownload%2Fstrip-json-comments-2.0.1.tgz", 1682 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", 1683 | "dev": true 1684 | }, 1685 | "supports-color": { 1686 | "version": "5.5.0", 1687 | "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-5.5.0.tgz?cache=0&sync_timestamp=1618560998281&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-5.5.0.tgz", 1688 | "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=", 1689 | "dev": true, 1690 | "requires": { 1691 | "has-flag": "^3.0.0" 1692 | } 1693 | }, 1694 | "term-size": { 1695 | "version": "2.2.1", 1696 | "resolved": "https://registry.npm.taobao.org/term-size/download/term-size-2.2.1.tgz", 1697 | "integrity": "sha1-KmpUhAQywvtjIP6g9BVTHpAYn1Q=", 1698 | "dev": true 1699 | }, 1700 | "to-readable-stream": { 1701 | "version": "1.0.0", 1702 | "resolved": "https://registry.nlark.com/to-readable-stream/download/to-readable-stream-1.0.0.tgz", 1703 | "integrity": "sha1-zgqgwvPfat+FLvtASng+d8BHV3E=", 1704 | "dev": true 1705 | }, 1706 | "to-regex-range": { 1707 | "version": "5.0.1", 1708 | "resolved": "https://registry.npm.taobao.org/to-regex-range/download/to-regex-range-5.0.1.tgz", 1709 | "integrity": "sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ=", 1710 | "dev": true, 1711 | "requires": { 1712 | "is-number": "^7.0.0" 1713 | } 1714 | }, 1715 | "toidentifier": { 1716 | "version": "1.0.0", 1717 | "resolved": "https://registry.npm.taobao.org/toidentifier/download/toidentifier-1.0.0.tgz", 1718 | "integrity": "sha1-fhvjRw8ed5SLxD2Uo8j013UrpVM=" 1719 | }, 1720 | "toposort-class": { 1721 | "version": "1.0.1", 1722 | "resolved": "https://registry.npm.taobao.org/toposort-class/download/toposort-class-1.0.1.tgz", 1723 | "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" 1724 | }, 1725 | "touch": { 1726 | "version": "3.1.0", 1727 | "resolved": "https://registry.npm.taobao.org/touch/download/touch-3.1.0.tgz", 1728 | "integrity": "sha1-/jZfX3XsntTlaCXgu3bSSrdK+Ds=", 1729 | "dev": true, 1730 | "requires": { 1731 | "nopt": "~1.0.10" 1732 | } 1733 | }, 1734 | "tsscmp": { 1735 | "version": "1.0.6", 1736 | "resolved": "https://registry.npm.taobao.org/tsscmp/download/tsscmp-1.0.6.tgz", 1737 | "integrity": "sha1-hbmVg6w1iexL/vgltQAKqRHWBes=" 1738 | }, 1739 | "type-fest": { 1740 | "version": "0.8.1", 1741 | "resolved": "https://registry.nlark.com/type-fest/download/type-fest-0.8.1.tgz?cache=0&sync_timestamp=1621402383646&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ftype-fest%2Fdownload%2Ftype-fest-0.8.1.tgz", 1742 | "integrity": "sha1-CeJJ696FHTseSNJ8EFREZn8XuD0=", 1743 | "dev": true 1744 | }, 1745 | "type-is": { 1746 | "version": "1.6.18", 1747 | "resolved": "https://registry.npm.taobao.org/type-is/download/type-is-1.6.18.tgz", 1748 | "integrity": "sha1-TlUs0F3wlGfcvE73Od6J8s83wTE=", 1749 | "requires": { 1750 | "media-typer": "0.3.0", 1751 | "mime-types": "~2.1.24" 1752 | } 1753 | }, 1754 | "typedarray-to-buffer": { 1755 | "version": "3.1.5", 1756 | "resolved": "https://registry.npm.taobao.org/typedarray-to-buffer/download/typedarray-to-buffer-3.1.5.tgz", 1757 | "integrity": "sha1-qX7nqf9CaRufeD/xvFES/j/KkIA=", 1758 | "dev": true, 1759 | "requires": { 1760 | "is-typedarray": "^1.0.0" 1761 | } 1762 | }, 1763 | "undefsafe": { 1764 | "version": "2.0.3", 1765 | "resolved": "https://registry.npm.taobao.org/undefsafe/download/undefsafe-2.0.3.tgz", 1766 | "integrity": "sha1-axZucJStRjE7IgLafsws18xueq4=", 1767 | "dev": true, 1768 | "requires": { 1769 | "debug": "^2.2.0" 1770 | }, 1771 | "dependencies": { 1772 | "debug": { 1773 | "version": "2.6.9", 1774 | "resolved": "https://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1607566571506&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz", 1775 | "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", 1776 | "dev": true, 1777 | "requires": { 1778 | "ms": "2.0.0" 1779 | } 1780 | } 1781 | } 1782 | }, 1783 | "unique-string": { 1784 | "version": "2.0.0", 1785 | "resolved": "https://registry.npm.taobao.org/unique-string/download/unique-string-2.0.0.tgz", 1786 | "integrity": "sha1-OcZFH4GvsnSd4rIz4/fF6IQ72J0=", 1787 | "dev": true, 1788 | "requires": { 1789 | "crypto-random-string": "^2.0.0" 1790 | } 1791 | }, 1792 | "unpipe": { 1793 | "version": "1.0.0", 1794 | "resolved": "https://registry.npm.taobao.org/unpipe/download/unpipe-1.0.0.tgz", 1795 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 1796 | }, 1797 | "update-notifier": { 1798 | "version": "4.1.3", 1799 | "resolved": "https://registry.npm.taobao.org/update-notifier/download/update-notifier-4.1.3.tgz", 1800 | "integrity": "sha1-vobuE+jOSPtQBD/3IFe1vVmOHqM=", 1801 | "dev": true, 1802 | "requires": { 1803 | "boxen": "^4.2.0", 1804 | "chalk": "^3.0.0", 1805 | "configstore": "^5.0.1", 1806 | "has-yarn": "^2.1.0", 1807 | "import-lazy": "^2.1.0", 1808 | "is-ci": "^2.0.0", 1809 | "is-installed-globally": "^0.3.1", 1810 | "is-npm": "^4.0.0", 1811 | "is-yarn-global": "^0.3.0", 1812 | "latest-version": "^5.0.0", 1813 | "pupa": "^2.0.1", 1814 | "semver-diff": "^3.1.1", 1815 | "xdg-basedir": "^4.0.0" 1816 | } 1817 | }, 1818 | "url-parse-lax": { 1819 | "version": "3.0.0", 1820 | "resolved": "https://registry.npm.taobao.org/url-parse-lax/download/url-parse-lax-3.0.0.tgz", 1821 | "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", 1822 | "dev": true, 1823 | "requires": { 1824 | "prepend-http": "^2.0.0" 1825 | } 1826 | }, 1827 | "uuid": { 1828 | "version": "8.3.2", 1829 | "resolved": "https://registry.npm.taobao.org/uuid/download/uuid-8.3.2.tgz?cache=0&sync_timestamp=1607458532020&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fuuid%2Fdownload%2Fuuid-8.3.2.tgz", 1830 | "integrity": "sha1-gNW1ztJxu5r2xEXyGhoExgbO++I=" 1831 | }, 1832 | "validator": { 1833 | "version": "10.11.0", 1834 | "resolved": "https://registry.nlark.com/validator/download/validator-10.11.0.tgz", 1835 | "integrity": "sha1-ADEI6m6amHTTHMyeUAaFbM12sig=" 1836 | }, 1837 | "vary": { 1838 | "version": "1.1.2", 1839 | "resolved": "https://registry.npm.taobao.org/vary/download/vary-1.1.2.tgz", 1840 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 1841 | }, 1842 | "widest-line": { 1843 | "version": "3.1.0", 1844 | "resolved": "https://registry.nlark.com/widest-line/download/widest-line-3.1.0.tgz?cache=0&sync_timestamp=1619001870221&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fwidest-line%2Fdownload%2Fwidest-line-3.1.0.tgz", 1845 | "integrity": "sha1-gpIzO79my0X/DeFgOxNreuFJbso=", 1846 | "dev": true, 1847 | "requires": { 1848 | "string-width": "^4.0.0" 1849 | } 1850 | }, 1851 | "wkx": { 1852 | "version": "0.5.0", 1853 | "resolved": "https://registry.npm.taobao.org/wkx/download/wkx-0.5.0.tgz", 1854 | "integrity": "sha1-xsNwGaz0DlF8xrlGV6JaPUqjPow=", 1855 | "requires": { 1856 | "@types/node": "*" 1857 | } 1858 | }, 1859 | "wrappy": { 1860 | "version": "1.0.2", 1861 | "resolved": "https://registry.nlark.com/wrappy/download/wrappy-1.0.2.tgz?cache=0&sync_timestamp=1619133505879&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fwrappy%2Fdownload%2Fwrappy-1.0.2.tgz", 1862 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1863 | "dev": true 1864 | }, 1865 | "write-file-atomic": { 1866 | "version": "3.0.3", 1867 | "resolved": "https://registry.npm.taobao.org/write-file-atomic/download/write-file-atomic-3.0.3.tgz", 1868 | "integrity": "sha1-Vr1cWlxwSBzRnFcb05q5ZaXeVug=", 1869 | "dev": true, 1870 | "requires": { 1871 | "imurmurhash": "^0.1.4", 1872 | "is-typedarray": "^1.0.0", 1873 | "signal-exit": "^3.0.2", 1874 | "typedarray-to-buffer": "^3.1.5" 1875 | } 1876 | }, 1877 | "xdg-basedir": { 1878 | "version": "4.0.0", 1879 | "resolved": "https://registry.npm.taobao.org/xdg-basedir/download/xdg-basedir-4.0.0.tgz?cache=0&sync_timestamp=1617611782885&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fxdg-basedir%2Fdownload%2Fxdg-basedir-4.0.0.tgz", 1880 | "integrity": "sha1-S8jZmEQDaWIl74OhVzy7y0552xM=", 1881 | "dev": true 1882 | }, 1883 | "yallist": { 1884 | "version": "4.0.0", 1885 | "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-4.0.0.tgz", 1886 | "integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=" 1887 | }, 1888 | "ylru": { 1889 | "version": "1.2.1", 1890 | "resolved": "https://registry.npm.taobao.org/ylru/download/ylru-1.2.1.tgz", 1891 | "integrity": "sha1-9Xa2M0FUeYnB3nuiiHYJI7J/6E8=" 1892 | } 1893 | } 1894 | } 1895 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "api", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "nodemon ./src/main.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "bcryptjs": "^2.4.3", 15 | "dotenv": "^9.0.2", 16 | "jsonwebtoken": "^8.5.1", 17 | "koa": "^2.13.1", 18 | "koa-body": "^4.2.0", 19 | "koa-parameter": "^3.0.1", 20 | "koa-router": "^10.0.0", 21 | "koa-static": "^5.0.0", 22 | "mysql2": "^2.2.5", 23 | "sequelize": "^6.6.2" 24 | }, 25 | "devDependencies": { 26 | "nodemon": "^2.0.7" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/app/errHandler.js: -------------------------------------------------------------------------------- 1 | module.exports = (err, ctx) => { 2 | let status = 500 3 | switch (err.code) { 4 | case '10001': 5 | status = 400 6 | break 7 | case '10002': 8 | status = 409 9 | break 10 | default: 11 | status = 500 12 | } 13 | ctx.status = status 14 | ctx.body = err 15 | console.log(err) 16 | } 17 | -------------------------------------------------------------------------------- /src/app/index.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | const Koa = require('koa') 4 | const KoaBody = require('koa-body') 5 | const KoaStatic = require('koa-static') 6 | const parameter = require('koa-parameter') 7 | 8 | const errHandler = require('./errHandler') 9 | const router = require('../router') 10 | 11 | const app = new Koa() 12 | 13 | app.use( 14 | KoaBody({ 15 | multipart: true, 16 | formidable: { 17 | // 在配制选项option里, 不推荐使用相对路径 18 | // 在option里的相对路径, 不是相对的当前文件. 相对process.cwd() 19 | uploadDir: path.join(__dirname, '../upload'), 20 | keepExtensions: true, 21 | }, 22 | parsedMethods: ['POST', 'PUT', 'PATCH', 'DELETE'], 23 | }) 24 | ) 25 | app.use(KoaStatic(path.join(__dirname, '../upload'))) 26 | app.use(parameter(app)) 27 | 28 | app.use(router.routes()).use(router.allowedMethods()) 29 | 30 | // 统一的错误处理 31 | app.on('error', errHandler) 32 | 33 | module.exports = app 34 | -------------------------------------------------------------------------------- /src/config/config.default.js: -------------------------------------------------------------------------------- 1 | const dotenv = require('dotenv') 2 | 3 | dotenv.config() 4 | 5 | // console.log(process.env.APP_PORT) 6 | 7 | module.exports = process.env 8 | -------------------------------------------------------------------------------- /src/constant/err.type.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | userFormateError: { 3 | code: '10001', 4 | message: '用户名或密码为空', 5 | result: '', 6 | }, 7 | userAlreadyExited: { 8 | code: '10002', 9 | message: '用户已经存在', 10 | result: '', 11 | }, 12 | userRegisterError: { 13 | code: '10003', 14 | message: '用户注册错误', 15 | result: '', 16 | }, 17 | userDoesNotExist: { 18 | code: '10004', 19 | message: '用户不存在', 20 | result: '', 21 | }, 22 | userLoginError: { 23 | code: '10005', 24 | message: '用户登录失败', 25 | result: '', 26 | }, 27 | invalidPassword: { 28 | code: '10006', 29 | message: '密码不匹配', 30 | result: '', 31 | }, 32 | tokenExpiredError: { 33 | code: '10101', 34 | message: 'token已过期', 35 | result: '', 36 | }, 37 | invalidToken: { 38 | code: '10102', 39 | message: '无效的token', 40 | result: '', 41 | }, 42 | hasNotAdminPermission: { 43 | code: '10103', 44 | message: '没有管理员权限', 45 | result: '', 46 | }, 47 | fileUploadError: { 48 | code: '10201', 49 | message: '商品图片上传失败', 50 | result: '', 51 | }, 52 | unSupportedFileType: { 53 | code: '10202', 54 | message: '不支持的文件格式', 55 | result: '', 56 | }, 57 | goodsFormatError: { 58 | code: '10203', 59 | message: '商品参数格式错误', 60 | result: '', 61 | }, 62 | publishGoodsError: { 63 | code: '10204', 64 | message: '发布商品失败', 65 | result: '', 66 | }, 67 | invalidGoodsID: { 68 | code: '10205', 69 | message: '无效的商品id', 70 | result: '', 71 | }, 72 | cartFormatError: { 73 | code: '10301', 74 | message: '购物车数据格式错误', 75 | result: '', 76 | }, 77 | addrFormatError: { 78 | code: '10401', 79 | message: '地址数据格式错误', 80 | result: '', 81 | }, 82 | orderFormatError: { 83 | code: '10501', 84 | message: '订单数据格式错误', 85 | result: '', 86 | }, 87 | } 88 | -------------------------------------------------------------------------------- /src/controller/addr.controller.js: -------------------------------------------------------------------------------- 1 | const { 2 | createAddr, 3 | findAllAddr, 4 | updateAddr, 5 | removeAddr, 6 | setDefaultAddr, 7 | } = require('../service/addr.service') 8 | 9 | class AddrController { 10 | async create(ctx) { 11 | // 解析user_id, consignee, phone, address 12 | const user_id = ctx.state.user.id 13 | const { consignee, phone, address } = ctx.request.body 14 | 15 | const res = await createAddr({ user_id, consignee, phone, address }) 16 | 17 | ctx.body = { 18 | code: 0, 19 | message: '添加地址成功', 20 | result: res, 21 | } 22 | } 23 | 24 | async findAll(ctx) { 25 | const user_id = ctx.state.user.id 26 | 27 | const res = await findAllAddr(user_id) 28 | 29 | ctx.body = { 30 | code: 0, 31 | message: '获取列表成功', 32 | result: res, 33 | } 34 | } 35 | 36 | async update(ctx) { 37 | const id = ctx.request.params.id 38 | 39 | const res = await updateAddr(id, ctx.request.body) 40 | 41 | ctx.body = { 42 | code: 0, 43 | message: '更新地址成功', 44 | result: res, 45 | } 46 | } 47 | 48 | async remove(ctx) { 49 | const id = ctx.request.params.id 50 | 51 | const res = await removeAddr(id) 52 | 53 | ctx.body = { 54 | code: 0, 55 | message: '删除地址成功', 56 | result: res, 57 | } 58 | } 59 | 60 | async setDefault(ctx) { 61 | const user_id = ctx.state.user.id 62 | const id = ctx.request.params.id 63 | 64 | const res = await setDefaultAddr(user_id, id) 65 | 66 | ctx.body = { 67 | code: 0, 68 | message: '设置默认成功', 69 | result: res, 70 | } 71 | } 72 | } 73 | 74 | module.exports = new AddrController() 75 | -------------------------------------------------------------------------------- /src/controller/cart.controller.js: -------------------------------------------------------------------------------- 1 | const { 2 | createOrUpdate, 3 | findCarts, 4 | updateCarts, 5 | removeCarts, 6 | selectAllCarts, 7 | unselectAllCarts, 8 | } = require('../service/cart.service') 9 | const { cartFormatError } = require('../constant/err.type') 10 | 11 | class CartController { 12 | async add(ctx) { 13 | // 将商品添加到购物车 14 | // 1. 解析user_id, goods_id 15 | const user_id = ctx.state.user.id 16 | const goods_id = ctx.request.body.goods_id 17 | // console.log(user_id, goods_id) 18 | // 2. 操作数据库 19 | const res = await createOrUpdate(user_id, goods_id) 20 | // 3. 返回结果 21 | ctx.body = { 22 | code: 0, 23 | message: '添加到购物车成功', 24 | result: res, 25 | } 26 | } 27 | 28 | async findAll(ctx) { 29 | // 1. 解析请求参数 30 | const { pageNum = 1, pageSize = 10 } = ctx.request.query 31 | // 2. 操作数据库 32 | const res = await findCarts(pageNum, pageSize) 33 | // 3. 返回结果 34 | ctx.body = { 35 | code: 0, 36 | message: '获取购物车列表成功', 37 | result: res, 38 | } 39 | } 40 | 41 | async update(ctx) { 42 | // 1. 解析参数 43 | const { id } = ctx.request.params 44 | const { number, selected } = ctx.request.body 45 | if (number === undefined && selected === undefined) { 46 | cartFormatError.message = 'number和selected不能同时为空' 47 | return ctx.app.emit('error', cartFormatError, ctx) 48 | } 49 | // 2. 操作数据库 50 | const res = await updateCarts({ id, number, selected }) 51 | // 3. 返回数据 52 | ctx.body = { 53 | code: 0, 54 | message: '更新购物车成功', 55 | result: res, 56 | } 57 | } 58 | 59 | async remove(ctx) { 60 | const { ids } = ctx.request.body 61 | 62 | const res = await removeCarts(ids) 63 | 64 | ctx.body = { 65 | code: 0, 66 | message: '删除购物车成功', 67 | result: res, 68 | } 69 | } 70 | 71 | async selectAll(ctx) { 72 | const user_id = ctx.state.user.id 73 | 74 | const res = await selectAllCarts(user_id) 75 | 76 | ctx.body = { 77 | code: 0, 78 | message: '全部选中', 79 | result: res, 80 | } 81 | } 82 | 83 | async unselectAll(ctx) { 84 | const user_id = ctx.state.user.id 85 | 86 | const res = await unselectAllCarts(user_id) 87 | 88 | ctx.body = { 89 | code: 0, 90 | message: '全部不选中', 91 | result: res, 92 | } 93 | } 94 | } 95 | 96 | module.exports = new CartController() 97 | -------------------------------------------------------------------------------- /src/controller/goods.controller.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | const { 4 | fileUploadError, 5 | unSupportedFileType, 6 | publishGoodsError, 7 | invalidGoodsID, 8 | } = require('../constant/err.type') 9 | 10 | const { 11 | createGoods, 12 | updateGoods, 13 | removeGoods, 14 | restoreGoods, 15 | findGoods, 16 | } = require('../service/goods.service') 17 | 18 | class GoodsController { 19 | async upload(ctx, next) { 20 | // console.log(ctx.request.files) 21 | const { file } = ctx.request.files 22 | // console.log(file) 23 | const fileTypes = ['image/jpeg', 'image/png'] 24 | if (file) { 25 | if (!fileTypes.includes(file.type)) { 26 | return ctx.app.emit('error', unSupportedFileType, ctx) 27 | } 28 | ctx.body = { 29 | code: 0, 30 | message: '商品图片上传成功', 31 | result: { 32 | goods_img: path.basename(file.path), 33 | }, 34 | } 35 | } else { 36 | return ctx.app.emit('error', fileUploadError, ctx) 37 | } 38 | } 39 | async create(ctx) { 40 | // 直接调用service的createGoods方法 41 | try { 42 | const { createdAt, updatedAt, ...res } = await createGoods( 43 | ctx.request.body 44 | ) 45 | ctx.body = { 46 | code: 0, 47 | message: '发布商品成功', 48 | result: res, 49 | } 50 | } catch (err) { 51 | console.error(err) 52 | return ctx.app.emit('error', publishGoodsError, ctx) 53 | } 54 | } 55 | async update(ctx) { 56 | try { 57 | const res = await updateGoods(ctx.params.id, ctx.request.body) 58 | 59 | if (res) { 60 | ctx.body = { 61 | code: 0, 62 | message: '修改商品成功', 63 | result: '', 64 | } 65 | } else { 66 | return ctx.app.emit('error', invalidGoodsID, ctx) 67 | } 68 | } catch (err) { 69 | console.error(err) 70 | } 71 | } 72 | async remove(ctx) { 73 | const res = await removeGoods(ctx.params.id) 74 | 75 | if (res) { 76 | ctx.body = { 77 | code: 0, 78 | message: '下架商品成功', 79 | result: '', 80 | } 81 | } else { 82 | return ctx.app.emit('error', invalidGoodsID, ctx) 83 | } 84 | } 85 | async restore(ctx) { 86 | const res = await restoreGoods(ctx.params.id) 87 | if (res) { 88 | ctx.body = { 89 | code: 0, 90 | message: '上架商品成功', 91 | result: '', 92 | } 93 | } else { 94 | return ctx.app.emit('error', invalidGoodsID, ctx) 95 | } 96 | } 97 | async findAll(ctx) { 98 | // 1. 解析pageNum和pageSize 99 | const { pageNum = 1, pageSize = 10 } = ctx.request.query 100 | // 2. 调用数据处理的相关方法 101 | const res = await findGoods(pageNum, pageSize) 102 | // 3. 返回结果 103 | ctx.body = { 104 | code: 0, 105 | message: '获取商品列表成功', 106 | result: res, 107 | } 108 | } 109 | } 110 | 111 | module.exports = new GoodsController() 112 | -------------------------------------------------------------------------------- /src/controller/order.controller.js: -------------------------------------------------------------------------------- 1 | const { 2 | createOrder, 3 | findAllOrder, 4 | updateOrder, 5 | } = require('../service/order.service') 6 | 7 | class OrderController { 8 | async create(ctx) { 9 | // 准备数据 10 | const user_id = ctx.state.user.id 11 | const { address_id, goods_info, total } = ctx.request.body 12 | 13 | const order_number = 'XZD' + Date.now() 14 | 15 | const res = await createOrder({ 16 | user_id, 17 | address_id, 18 | goods_info, 19 | total, 20 | order_number, 21 | }) 22 | 23 | ctx.body = { 24 | code: 0, 25 | message: '生成订单成功', 26 | result: res, 27 | } 28 | } 29 | 30 | async findAll(ctx) { 31 | const { pageNum = 1, pageSize = 10, status = 0 } = ctx.request.query 32 | 33 | const res = await findAllOrder(pageNum, pageSize, status) 34 | 35 | ctx.body = { 36 | code: 0, 37 | message: '获取订单列表成功', 38 | result: res, 39 | } 40 | } 41 | 42 | async update(ctx) { 43 | const id = ctx.request.params.id 44 | const { status } = ctx.request.body 45 | 46 | const res = await updateOrder(id, status) 47 | 48 | ctx.body = { 49 | code: 0, 50 | message: '更新订单状态成功', 51 | result: res, 52 | } 53 | } 54 | } 55 | 56 | module.exports = new OrderController() 57 | -------------------------------------------------------------------------------- /src/controller/user.controller.js: -------------------------------------------------------------------------------- 1 | const jwt = require('jsonwebtoken') 2 | 3 | const { 4 | createUser, 5 | getUerInfo, 6 | updateById, 7 | } = require('../service/user.service') 8 | 9 | const { userRegisterError } = require('../constant/err.type') 10 | 11 | const { JWT_SECRET } = require('../config/config.default') 12 | 13 | class UserController { 14 | async register(ctx, next) { 15 | // 1. 获取数据 16 | // console.log(ctx.request.body) 17 | const { user_name, password } = ctx.request.body 18 | 19 | // 2. 操作数据库 20 | try { 21 | const res = await createUser(user_name, password) 22 | // console.log(res) 23 | // 3. 返回结果 24 | ctx.body = { 25 | code: 0, 26 | message: '用户注册成功', 27 | result: { 28 | id: res.id, 29 | user_name: res.user_name, 30 | }, 31 | } 32 | } catch (err) { 33 | console.log(err) 34 | ctx.app.emit('error', userRegisterError, ctx) 35 | } 36 | } 37 | 38 | async login(ctx, next) { 39 | const { user_name } = ctx.request.body 40 | 41 | // 1. 获取用户信息(在token的payload中, 记录id, user_name, is_admin) 42 | try { 43 | // 从返回结果对象中剔除password属性, 将剩下的属性放到res对象 44 | const { password, ...res } = await getUerInfo({ user_name }) 45 | 46 | ctx.body = { 47 | code: 0, 48 | message: '用户登录成功', 49 | result: { 50 | token: jwt.sign(res, JWT_SECRET, { expiresIn: '1d' }), 51 | }, 52 | } 53 | } catch (err) { 54 | console.error('用户登录失败', err) 55 | } 56 | } 57 | 58 | async changePassword(ctx, next) { 59 | // 1. 获取数据 60 | const id = ctx.state.user.id 61 | const password = ctx.request.body.password 62 | 63 | // 2. 操作数据库 64 | if (await updateById({ id, password })) { 65 | ctx.body = { 66 | code: 0, 67 | message: '修改密码成功', 68 | result: '', 69 | } 70 | } else { 71 | ctx.body = { 72 | code: '10007', 73 | message: '修改密码失败', 74 | result: '', 75 | } 76 | } 77 | // 3. 返回结果 78 | } 79 | } 80 | 81 | module.exports = new UserController() 82 | -------------------------------------------------------------------------------- /src/db/seq.js: -------------------------------------------------------------------------------- 1 | const { Sequelize } = require('sequelize') 2 | 3 | const { 4 | MYSQL_HOST, 5 | MYSQL_PORT, 6 | MYSQL_USER, 7 | MYSQL_PWD, 8 | MYSQL_DB, 9 | } = require('../config/config.default') 10 | 11 | const seq = new Sequelize(MYSQL_DB, MYSQL_USER, MYSQL_PWD, { 12 | host: MYSQL_HOST, 13 | dialect: 'mysql', 14 | }) 15 | 16 | // seq 17 | // .authenticate() 18 | // .then(() => { 19 | // console.log('数据库连接成功') 20 | // }) 21 | // .catch(err => { 22 | // console.log('数据库连接失败', err) 23 | // }) 24 | 25 | module.exports = seq 26 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | const { APP_PORT } = require('./config/config.default') 2 | 3 | const app = require('./app') 4 | 5 | app.listen(APP_PORT, () => { 6 | console.log(`server is running on http://localhost:${APP_PORT}`) 7 | }) 8 | -------------------------------------------------------------------------------- /src/middleware/addr.middleware.js: -------------------------------------------------------------------------------- 1 | const { addrFormatError } = require('../constant/err.type') 2 | 3 | const validator = (rules) => { 4 | return async (ctx, next) => { 5 | try { 6 | ctx.verifyParams(rules) 7 | } catch (err) { 8 | console.error(err) 9 | addrFormatError.result = err 10 | return ctx.app.emit('error', addrFormatError, ctx) 11 | } 12 | 13 | await next() 14 | } 15 | } 16 | 17 | module.exports = { 18 | validator, 19 | } 20 | -------------------------------------------------------------------------------- /src/middleware/auth.middleware.js: -------------------------------------------------------------------------------- 1 | const jwt = require('jsonwebtoken') 2 | 3 | const { JWT_SECRET } = require('../config/config.default') 4 | 5 | const { 6 | tokenExpiredError, 7 | invalidToken, 8 | hasNotAdminPermission, 9 | } = require('../constant/err.type') 10 | 11 | const auth = async (ctx, next) => { 12 | const { authorization = '' } = ctx.request.header 13 | const token = authorization.replace('Bearer ', '') 14 | // console.log(token) 15 | 16 | try { 17 | // user中包含了payload的信息(id, user_name, is_admin) 18 | const user = jwt.verify(token, JWT_SECRET) 19 | ctx.state.user = user 20 | } catch (err) { 21 | switch (err.name) { 22 | case 'TokenExpiredError': 23 | console.error('token已过期', err) 24 | return ctx.app.emit('error', tokenExpiredError, ctx) 25 | case 'JsonWebTokenError': 26 | console.error('无效的token', err) 27 | return ctx.app.emit('error', invalidToken, ctx) 28 | } 29 | } 30 | 31 | await next() 32 | } 33 | 34 | const hadAdminPermission = async (ctx, next) => { 35 | const { is_admin } = ctx.state.user 36 | 37 | if (!is_admin) { 38 | console.error('该用户没有管理员的权限', ctx.state.user) 39 | return ctx.app.emit('error', hasNotAdminPermission, ctx) 40 | } 41 | 42 | await next() 43 | } 44 | 45 | module.exports = { 46 | auth, 47 | hadAdminPermission, 48 | } 49 | -------------------------------------------------------------------------------- /src/middleware/cart.middleware.js: -------------------------------------------------------------------------------- 1 | const { cartFormatError } = require('../constant/err.type') 2 | 3 | const validator = (rules) => { 4 | return async (ctx, next) => { 5 | try { 6 | ctx.verifyParams(rules) 7 | } catch (err) { 8 | console.error(err) 9 | cartFormatError.result = err 10 | return ctx.app.emit('error', cartFormatError, ctx) 11 | } 12 | 13 | await next() 14 | } 15 | } 16 | module.exports = { 17 | validator, 18 | } 19 | -------------------------------------------------------------------------------- /src/middleware/goods.middleware.js: -------------------------------------------------------------------------------- 1 | const { goodsFormatError } = require('../constant/err.type') 2 | 3 | const validator = async (ctx, next) => { 4 | try { 5 | ctx.verifyParams({ 6 | goods_name: { type: 'string', required: true }, 7 | goods_price: { type: 'number', required: true }, 8 | goods_num: { type: 'number', required: true }, 9 | goods_img: { type: 'string', required: true }, 10 | }) 11 | } catch (err) { 12 | console.error(err) 13 | goodsFormatError.result = err 14 | return ctx.app.emit('error', goodsFormatError, ctx) 15 | } 16 | 17 | await next() 18 | } 19 | 20 | module.exports = { 21 | validator, 22 | } 23 | -------------------------------------------------------------------------------- /src/middleware/order.middleware.js: -------------------------------------------------------------------------------- 1 | const { orderFormatError } = require('../constant/err.type') 2 | 3 | const validator = (rules) => { 4 | return async (ctx, next) => { 5 | try { 6 | ctx.verifyParams(rules) 7 | } catch (err) { 8 | console.error(err) 9 | orderFormatError.result = err 10 | return ctx.app.emit('error', orderFormatError, ctx) 11 | } 12 | await next() 13 | } 14 | } 15 | 16 | module.exports = { 17 | validator, 18 | } 19 | -------------------------------------------------------------------------------- /src/middleware/user.middleware.js: -------------------------------------------------------------------------------- 1 | const bcrypt = require('bcryptjs') 2 | 3 | const { getUerInfo } = require('../service/user.service') 4 | const { 5 | userFormateError, 6 | userAlreadyExited, 7 | userRegisterError, 8 | userDoesNotExist, 9 | userLoginError, 10 | invalidPassword, 11 | } = require('../constant/err.type') 12 | 13 | const userValidator = async (ctx, next) => { 14 | const { user_name, password } = ctx.request.body 15 | // 合法性 16 | if (!user_name || !password) { 17 | console.error('用户名或密码为空', ctx.request.body) 18 | ctx.app.emit('error', userFormateError, ctx) 19 | return 20 | } 21 | 22 | await next() 23 | } 24 | 25 | const verifyUser = async (ctx, next) => { 26 | const { user_name } = ctx.request.body 27 | 28 | // if (await getUerInfo({ user_name })) { 29 | // ctx.app.emit('error', userAlreadyExited, ctx) 30 | // return 31 | // } 32 | try { 33 | const res = await getUerInfo({ user_name }) 34 | 35 | if (res) { 36 | console.error('用户名已经存在', { user_name }) 37 | ctx.app.emit('error', userAlreadyExited, ctx) 38 | return 39 | } 40 | } catch (err) { 41 | console.error('获取用户信息错误', err) 42 | ctx.app.emit('error', userRegisterError, ctx) 43 | return 44 | } 45 | 46 | await next() 47 | } 48 | 49 | const crpytPassword = async (ctx, next) => { 50 | const { password } = ctx.request.body 51 | 52 | const salt = bcrypt.genSaltSync(10) 53 | // hash保存的是 密文 54 | const hash = bcrypt.hashSync(password, salt) 55 | 56 | ctx.request.body.password = hash 57 | 58 | await next() 59 | } 60 | 61 | const verifyLogin = async (ctx, next) => { 62 | // 1. 判断用户是否存在(不存在:报错) 63 | const { user_name, password } = ctx.request.body 64 | 65 | try { 66 | const res = await getUerInfo({ user_name }) 67 | 68 | if (!res) { 69 | console.error('用户名不存在', { user_name }) 70 | ctx.app.emit('error', userDoesNotExist, ctx) 71 | return 72 | } 73 | 74 | // 2. 密码是否匹配(不匹配: 报错) 75 | if (!bcrypt.compareSync(password, res.password)) { 76 | ctx.app.emit('error', invalidPassword, ctx) 77 | return 78 | } 79 | } catch (err) { 80 | console.error(err) 81 | return ctx.app.emit('error', userLoginError, ctx) 82 | } 83 | 84 | await next() 85 | } 86 | 87 | module.exports = { 88 | userValidator, 89 | verifyUser, 90 | crpytPassword, 91 | verifyLogin, 92 | } 93 | -------------------------------------------------------------------------------- /src/model/addr.model.js: -------------------------------------------------------------------------------- 1 | // 1. 导入seq的连接 2 | const { DataTypes } = require('sequelize') 3 | const seq = require('../db/seq') 4 | 5 | // 2. 定义字段(模型) 6 | const Address = seq.define('zd_addresses', { 7 | user_id: { 8 | type: DataTypes.INTEGER, 9 | allowNull: false, 10 | comment: '用户id', 11 | }, 12 | consignee: { 13 | type: DataTypes.STRING, 14 | allowNull: false, 15 | comment: '收货人姓名', 16 | }, 17 | phone: { 18 | type: DataTypes.CHAR(11), 19 | allowNull: false, 20 | comment: '收货人的手机号', 21 | }, 22 | address: { 23 | type: DataTypes.STRING, 24 | allowNull: false, 25 | comment: '收货人的地址', 26 | }, 27 | is_default: { 28 | type: DataTypes.BOOLEAN, 29 | allowNull: false, 30 | defaultValue: false, 31 | comment: '是否为默认地址, 0:不是(默认值) 1: 是', 32 | }, 33 | }) 34 | 35 | // 3. 同步, sync 36 | // Address.sync({ force: true }) 37 | 38 | // 4. 导出模型对象 39 | module.exports = Address 40 | -------------------------------------------------------------------------------- /src/model/cart.model.js: -------------------------------------------------------------------------------- 1 | // 1. 导入sequelize的连接 2 | const { DataTypes } = require('sequelize') 3 | const seq = require('../db/seq') 4 | const Goods = require('./goods.model') 5 | 6 | // 2. 定义Cart模型 7 | const Cart = seq.define('zd_carts', { 8 | goods_id: { 9 | type: DataTypes.INTEGER, 10 | allowNull: false, 11 | comment: '商品的id', 12 | }, 13 | user_id: { 14 | type: DataTypes.INTEGER, 15 | allowNull: false, 16 | comment: '用户的id', 17 | }, 18 | number: { 19 | type: DataTypes.INTEGER, 20 | allowNull: false, 21 | defaultValue: 1, 22 | comment: '商品的数量', 23 | }, 24 | selected: { 25 | type: DataTypes.BOOLEAN, 26 | allowNull: false, 27 | defaultValue: true, 28 | comment: '是否选中', 29 | }, 30 | }) 31 | 32 | // 3. 同步数据(建表) 33 | // Cart.sync({ force: true }) 34 | Cart.belongsTo(Goods, { 35 | foreignKey: 'goods_id', 36 | as: 'goods_info', 37 | }) 38 | // 4. 导出Cart模型 39 | module.exports = Cart 40 | -------------------------------------------------------------------------------- /src/model/goods.model.js: -------------------------------------------------------------------------------- 1 | const { DataTypes } = require('sequelize') 2 | 3 | const seq = require('../db/seq') 4 | 5 | const Goods = seq.define( 6 | 'zd_goods', 7 | { 8 | goods_name: { 9 | type: DataTypes.STRING, 10 | allowNull: false, 11 | comment: '商品名称', 12 | }, 13 | goods_price: { 14 | type: DataTypes.DECIMAL(10, 2), 15 | allowNull: false, 16 | comment: '商品价格', 17 | }, 18 | goods_num: { 19 | type: DataTypes.INTEGER, 20 | allowNull: false, 21 | comment: '商品库存', 22 | }, 23 | goods_img: { 24 | type: DataTypes.STRING, 25 | allowNull: false, 26 | comment: '商品图片的url', 27 | }, 28 | }, 29 | { 30 | paranoid: true, 31 | } 32 | ) 33 | 34 | // Goods.sync({ force: true }) 35 | 36 | module.exports = Goods 37 | -------------------------------------------------------------------------------- /src/model/order.model.js: -------------------------------------------------------------------------------- 1 | const { DataTypes } = require('sequelize') 2 | const seq = require('../db/seq') 3 | 4 | const Order = seq.define('zd_orders', { 5 | user_id: { 6 | type: DataTypes.INTEGER, 7 | allowNull: false, 8 | comment: '用户id', 9 | }, 10 | address_id: { 11 | type: DataTypes.INTEGER, 12 | allowNull: false, 13 | comment: '地址id', 14 | }, 15 | goods_info: { 16 | type: DataTypes.TEXT, 17 | allowNull: false, 18 | comment: '商品信息', 19 | }, 20 | total: { 21 | type: DataTypes.DECIMAL(10, 2), 22 | allowNull: false, 23 | comment: '订单总金额', 24 | }, 25 | order_number: { 26 | type: DataTypes.CHAR(16), 27 | allowNull: false, 28 | comment: '订单号', 29 | }, 30 | status: { 31 | type: DataTypes.TINYINT, 32 | allowNull: false, 33 | defaultValue: 0, 34 | comment: '订单状态(0: 未支付,1: 已支付, 2: 已发货, 3: 已签收, 4: 取消)', 35 | }, 36 | }) 37 | 38 | // Order.sync({ force: true }) 39 | 40 | module.exports = Order 41 | -------------------------------------------------------------------------------- /src/model/use.model.js: -------------------------------------------------------------------------------- 1 | const { DataTypes } = require('sequelize') 2 | 3 | const seq = require('../db/seq') 4 | 5 | // 创建模型(Model zd_user -> 表 zd_users) 6 | const User = seq.define('zd_user', { 7 | // id 会被sequelize自动创建, 管理 8 | user_name: { 9 | type: DataTypes.STRING, 10 | allowNull: false, 11 | unique: true, 12 | comment: '用户名, 唯一', 13 | }, 14 | password: { 15 | type: DataTypes.CHAR(64), 16 | allowNull: false, 17 | comment: '密码', 18 | }, 19 | is_admin: { 20 | type: DataTypes.BOOLEAN, 21 | allowNull: false, 22 | defaultValue: 0, 23 | comment: '是否为管理员, 0: 不是管理员(默认); 1: 是管理员', 24 | }, 25 | }) 26 | 27 | // 强制同步数据库(创建数据表) 28 | // User.sync({ force: true }) 29 | 30 | module.exports = User 31 | -------------------------------------------------------------------------------- /src/router/addr.route.js: -------------------------------------------------------------------------------- 1 | // 一. 导入koa-router包 2 | const Router = require('koa-router') 3 | 4 | // 二. 实例化对象 5 | const router = new Router({ prefix: '/address' }) 6 | 7 | // 中间件/控制器 8 | const { auth } = require('../middleware/auth.middleware') 9 | const { validator } = require('../middleware/addr.middleware') 10 | 11 | const { 12 | create, 13 | findAll, 14 | update, 15 | remove, 16 | setDefault, 17 | } = require('../controller/addr.controller') 18 | 19 | // 三. 编写路由规则 20 | // 3.1 添加接口: 登录, 格式 21 | router.post( 22 | '/', 23 | auth, 24 | validator({ 25 | consignee: 'string', 26 | phone: { type: 'string', format: /^1\d{10}$/ }, 27 | address: 'string', 28 | }), 29 | create 30 | ) 31 | 32 | // 3.2 获取地址列表 33 | router.get('/', auth, findAll) 34 | 35 | // 3.3 更新地址 36 | router.put( 37 | '/:id', 38 | auth, 39 | validator({ 40 | consignee: 'string', 41 | phone: { type: 'string', format: /^1\d{10}$/ }, 42 | address: 'string', 43 | }), 44 | update 45 | ) 46 | 47 | // 3.4 删除地址 48 | router.delete('/:id', auth, remove) 49 | 50 | // 3.5 设置默认 51 | router.patch('/:id', auth, setDefault) 52 | 53 | // 四. 导出router对象 54 | module.exports = router 55 | -------------------------------------------------------------------------------- /src/router/cart.route.js: -------------------------------------------------------------------------------- 1 | // 1. 导入koa-router 2 | const Router = require('koa-router') 3 | 4 | // 中间件 5 | const { auth } = require('../middleware/auth.middleware') 6 | const { validator } = require('../middleware/cart.middleware') 7 | 8 | // 控件器 9 | const { 10 | add, 11 | findAll, 12 | update, 13 | remove, 14 | selectAll, 15 | unselectAll, 16 | } = require('../controller/cart.controller') 17 | 18 | // 2. 实例化router对象 19 | const router = new Router({ prefix: '/carts' }) 20 | 21 | // 3. 编写路由规则 22 | 23 | // 3.1 添加到购物车接口: 登录, 格式 24 | router.post('/', auth, validator({ goods_id: 'number' }), add) 25 | 26 | // 3.2 获取购物车列表 27 | router.get('/', auth, findAll) 28 | 29 | // 3.3 更新购物车 30 | router.patch( 31 | '/:id', 32 | auth, 33 | validator({ 34 | number: { type: 'number', required: false }, 35 | selected: { type: 'bool', required: false }, 36 | }), 37 | update 38 | ) 39 | 40 | // 3.4 删除购物车 41 | router.delete('/', auth, validator({ ids: 'array' }), remove) 42 | 43 | // 3.5 全选与全不选 44 | router.post('/selectAll', auth, selectAll) 45 | router.post('/unselectAll', auth, unselectAll) 46 | 47 | // 4. 导出router对象 48 | module.exports = router 49 | -------------------------------------------------------------------------------- /src/router/goods.route.js: -------------------------------------------------------------------------------- 1 | const Router = require('koa-router') 2 | 3 | const { auth, hadAdminPermission } = require('../middleware/auth.middleware') 4 | const { validator } = require('../middleware/goods.middleware') 5 | 6 | const { 7 | upload, 8 | create, 9 | update, 10 | remove, 11 | restore, 12 | findAll, 13 | } = require('../controller/goods.controller') 14 | 15 | const router = new Router({ prefix: '/goods' }) 16 | 17 | // 商品图片上传接口 18 | router.post('/upload', auth, hadAdminPermission, upload) 19 | 20 | // 发布商品接口 21 | router.post('/', auth, hadAdminPermission, validator, create) 22 | 23 | // 修改商品接口 24 | router.put('/:id', auth, hadAdminPermission, validator, update) 25 | 26 | // 硬删除接口 27 | // router.delete('/:id', auth, hadAdminPermission, remove) 28 | 29 | router.post('/:id/off', auth, hadAdminPermission, remove) 30 | router.post('/:id/on', auth, hadAdminPermission, restore) 31 | 32 | // 获取商品列表 33 | router.get('/', findAll) 34 | 35 | module.exports = router 36 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | 3 | const Router = require('koa-router') 4 | const router = new Router() 5 | 6 | fs.readdirSync(__dirname).forEach(file => { 7 | // console.log(file) 8 | if (file !== 'index.js') { 9 | let r = require('./' + file) 10 | router.use(r.routes()) 11 | } 12 | }) 13 | 14 | module.exports = router 15 | -------------------------------------------------------------------------------- /src/router/order.route.js: -------------------------------------------------------------------------------- 1 | const Router = require('koa-router') 2 | const router = new Router({ prefix: '/orders' }) 3 | 4 | const { auth } = require('../middleware/auth.middleware') 5 | const { validator } = require('../middleware/order.middleware') 6 | 7 | const { create, findAll, update } = require('../controller/order.controller') 8 | 9 | // 提交订单 10 | router.post( 11 | '/', 12 | auth, 13 | validator({ 14 | address_id: 'int', 15 | goods_info: 'string', 16 | total: 'string', 17 | }), 18 | create 19 | ) 20 | 21 | // 获取订单列表 22 | router.get('/', auth, findAll) 23 | 24 | // 更新订单状态 25 | router.patch( 26 | '/:id', 27 | auth, 28 | validator({ 29 | status: 'number', 30 | }), 31 | update 32 | ) 33 | 34 | module.exports = router 35 | -------------------------------------------------------------------------------- /src/router/user.route.js: -------------------------------------------------------------------------------- 1 | const Router = require('koa-router') 2 | 3 | const { 4 | userValidator, 5 | verifyUser, 6 | crpytPassword, 7 | verifyLogin, 8 | } = require('../middleware/user.middleware') 9 | 10 | const { auth } = require('../middleware/auth.middleware') 11 | const { 12 | register, 13 | login, 14 | changePassword, 15 | } = require('../controller/user.controller') 16 | 17 | const router = new Router({ prefix: '/users' }) 18 | 19 | // 注册接口 20 | router.post('/register', userValidator, verifyUser, crpytPassword, register) 21 | 22 | // 登录接口 23 | router.post('/login', userValidator, verifyLogin, login) 24 | 25 | // 修改密码接口 26 | router.patch('/', auth, crpytPassword, changePassword) 27 | 28 | module.exports = router 29 | -------------------------------------------------------------------------------- /src/service/addr.service.js: -------------------------------------------------------------------------------- 1 | const Address = require('../model/addr.model') 2 | 3 | class AddrService { 4 | async createAddr(addr) { 5 | return await Address.create(addr) 6 | } 7 | 8 | async findAllAddr(user_id) { 9 | return await Address.findAll({ 10 | attributes: ['id', 'consignee', 'phone', 'address', 'is_default'], 11 | where: { user_id }, 12 | }) 13 | } 14 | 15 | async updateAddr(id, addr) { 16 | return await Address.update(addr, { where: { id } }) 17 | } 18 | 19 | async removeAddr(id) { 20 | return await Address.destroy({ where: { id } }) 21 | } 22 | 23 | async setDefaultAddr(user_id, id) { 24 | await Address.update( 25 | { is_default: false }, 26 | { 27 | where: { 28 | user_id, 29 | }, 30 | } 31 | ) 32 | 33 | return await Address.update( 34 | { is_default: true }, 35 | { 36 | where: { 37 | id, 38 | }, 39 | } 40 | ) 41 | } 42 | } 43 | 44 | module.exports = new AddrService() 45 | -------------------------------------------------------------------------------- /src/service/cart.service.js: -------------------------------------------------------------------------------- 1 | const { Op } = require('sequelize') 2 | const Cart = require('../model/cart.model') 3 | const Goods = require('../model/goods.model') 4 | 5 | class CartService { 6 | async createOrUpdate(user_id, goods_id) { 7 | // 根据user_id和goods_id同时查找, 有没有记录 8 | let res = await Cart.findOne({ 9 | where: { 10 | [Op.and]: { 11 | user_id, 12 | goods_id, 13 | }, 14 | }, 15 | }) 16 | 17 | if (res) { 18 | // 已经存在一条记录, 将number + 1 19 | await res.increment('number') 20 | return await res.reload() 21 | } else { 22 | return await Cart.create({ 23 | user_id, 24 | goods_id, 25 | }) 26 | } 27 | } 28 | 29 | async findCarts(pageNum, pageSize) { 30 | const offset = (pageNum - 1) * pageSize 31 | const { count, rows } = await Cart.findAndCountAll({ 32 | attributes: ['id', 'number', 'selected'], 33 | offset: offset, 34 | limit: pageSize * 1, 35 | include: { 36 | model: Goods, 37 | as: 'goods_info', 38 | attributes: ['id', 'goods_name', 'goods_price', 'goods_img'], 39 | }, 40 | }) 41 | return { 42 | pageNum, 43 | pageSize, 44 | total: count, 45 | list: rows, 46 | } 47 | } 48 | 49 | async updateCarts(params) { 50 | const { id, number, selected } = params 51 | 52 | const res = await Cart.findByPk(id) 53 | if (!res) return '' 54 | 55 | number !== undefined ? (res.number = number) : '' 56 | if (selected !== undefined) { 57 | res.selected = selected 58 | } 59 | 60 | return await res.save() 61 | } 62 | 63 | async removeCarts(ids) { 64 | return await Cart.destroy({ 65 | where: { 66 | id: { 67 | [Op.in]: ids, 68 | }, 69 | }, 70 | }) 71 | } 72 | 73 | async selectAllCarts(user_id) { 74 | return await Cart.update( 75 | { selected: true }, 76 | { 77 | where: { 78 | user_id, 79 | }, 80 | } 81 | ) 82 | } 83 | 84 | async unselectAllCarts(user_id) { 85 | return await Cart.update( 86 | { selected: false }, 87 | { 88 | where: { 89 | user_id, 90 | }, 91 | } 92 | ) 93 | } 94 | } 95 | 96 | module.exports = new CartService() 97 | -------------------------------------------------------------------------------- /src/service/goods.service.js: -------------------------------------------------------------------------------- 1 | const Goods = require('../model/goods.model') 2 | 3 | class GoodsService { 4 | async createGoods(goods) { 5 | const res = await Goods.create(goods) 6 | return res.dataValues 7 | } 8 | 9 | async updateGoods(id, goods) { 10 | const res = await Goods.update(goods, { where: { id } }) 11 | 12 | return res[0] > 0 ? true : false 13 | } 14 | 15 | async removeGoods(id) { 16 | const res = await Goods.destroy({ where: { id } }) 17 | 18 | return res > 0 ? true : false 19 | } 20 | 21 | async restoreGoods(id) { 22 | const res = await Goods.restore({ where: { id } }) 23 | 24 | return res > 0 ? true : false 25 | } 26 | 27 | async findGoods(pageNum, pageSize) { 28 | // // 1. 获取总数 29 | // const count = await Goods.count() 30 | // // console.log(count) 31 | // // 2. 获取分页的具体数据 32 | // const offset = (pageNum - 1) * pageSize 33 | // const rows = await Goods.findAll({ offset: offset, limit: pageSize * 1 }) 34 | 35 | const offset = (pageNum - 1) * pageSize 36 | const { count, rows } = await Goods.findAndCountAll({ 37 | offset: offset, 38 | limit: pageSize * 1, 39 | }) 40 | return { 41 | pageNum, 42 | pageSize, 43 | total: count, 44 | list: rows, 45 | } 46 | } 47 | } 48 | 49 | module.exports = new GoodsService() 50 | -------------------------------------------------------------------------------- /src/service/order.service.js: -------------------------------------------------------------------------------- 1 | const Order = require('../model/order.model') 2 | 3 | class OrderService { 4 | async createOrder(order) { 5 | return await Order.create(order) 6 | } 7 | 8 | async findAllOrder(pageNum, pageSize, status) { 9 | const { count, rows } = await Order.findAndCountAll({ 10 | attributes: ['goods_info', 'total', 'order_number', 'status'], 11 | where: { 12 | status, 13 | }, 14 | offset: (pageNum - 1) * pageSize, 15 | limit: pageSize * 1, 16 | }) 17 | 18 | return { 19 | pageNum, 20 | pageSize, 21 | total: count, 22 | list: rows, 23 | } 24 | } 25 | 26 | async updateOrder(id, status) { 27 | return await Order.update({ status }, { where: { id } }) 28 | } 29 | } 30 | 31 | module.exports = new OrderService() 32 | -------------------------------------------------------------------------------- /src/service/user.service.js: -------------------------------------------------------------------------------- 1 | const User = require('../model/use.model') 2 | 3 | class UserService { 4 | async createUser(user_name, password) { 5 | // 插入数据 6 | // await表达式: promise对象的值 7 | const res = await User.create({ user_name, password }) 8 | // console.log(res) 9 | return res.dataValues 10 | } 11 | 12 | async getUerInfo({ id, user_name, password, is_admin }) { 13 | const whereOpt = {} 14 | 15 | id && Object.assign(whereOpt, { id }) 16 | user_name && Object.assign(whereOpt, { user_name }) 17 | password && Object.assign(whereOpt, { password }) 18 | is_admin && Object.assign(whereOpt, { is_admin }) 19 | 20 | const res = await User.findOne({ 21 | attributes: ['id', 'user_name', 'password', 'is_admin'], 22 | where: whereOpt, 23 | }) 24 | 25 | return res ? res.dataValues : null 26 | } 27 | 28 | async updateById({ id, user_name, password, is_admin }) { 29 | const whereOpt = { id } 30 | const newUser = {} 31 | 32 | user_name && Object.assign(newUser, { user_name }) 33 | password && Object.assign(newUser, { password }) 34 | is_admin && Object.assign(newUser, { is_admin }) 35 | 36 | const res = await User.update(newUser, { where: whereOpt }) 37 | // console.log(res) 38 | return res[0] > 0 ? true : false 39 | } 40 | } 41 | 42 | module.exports = new UserService() 43 | -------------------------------------------------------------------------------- /test/file_text.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 |