├── resource ├── ding.mp3 ├── images │ ├── book │ │ ├── 1.jpg │ │ ├── 2.jpg │ │ ├── 3.jpg │ │ ├── 5.jpg │ │ ├── 6.jpg │ │ ├── 7.jpg │ │ ├── 8.jpg │ │ ├── 9.jpg │ │ ├── 10.jpg │ │ ├── 11.jpg │ │ ├── 143.jpg │ │ ├── 144.jpg │ │ ├── 146.jpg │ │ ├── 147.jpg │ │ ├── 148.jpg │ │ ├── 149.jpg │ │ ├── 150.jpg │ │ ├── 151.jpg │ │ ├── 152.jpg │ │ ├── 153.jpg │ │ ├── 154.jpg │ │ ├── 155.jpg │ │ ├── 156.jpg │ │ ├── 157.jpg │ │ ├── 161.jpg │ │ ├── 162.jpg │ │ ├── 163.jpg │ │ ├── 163.png │ │ ├── 164.jpg │ │ ├── 165.jpg │ │ ├── 166.jpg │ │ ├── 167.jpg │ │ ├── 168.jpg │ │ ├── 169.jpg │ │ ├── 170.jpg │ │ ├── 171.jpg │ │ ├── 172.jpg │ │ ├── 173.jpg │ │ ├── 174.jpg │ │ ├── 175.jpg │ │ ├── 177.jpg │ │ ├── 178.jpg │ │ ├── 179.jpg │ │ ├── 18.jpg │ │ ├── 180.jpg │ │ ├── 181.jpg │ │ ├── 20.jpg │ │ └── 33.jpg │ ├── admin │ │ ├── default.jpg │ │ ├── default.png │ │ ├── 15553598117.jpg │ │ └── 15553598117.png │ ├── login │ │ └── login-bg-2.jpg │ ├── user │ │ ├── 15553598112.jpg │ │ └── 15553598112.png │ └── shop │ │ ├── swipe │ │ ├── swipe-1.jpg │ │ ├── swipe-2.jpg │ │ ├── swipe-3.jpg │ │ └── swipe-4.jpg │ │ └── good │ │ ├── good-swipe │ │ ├── good-swipe-1.jpg │ │ ├── good-swipe-2.jpg │ │ ├── good-swipe-3.jpg │ │ └── good-swipe-4.jpg │ │ └── good-detail │ │ └── good-detail-1.jpg └── template │ ├── book │ ├── 分类对照表.xlsx │ └── 批量上传图书.xlsx │ └── delivery │ └── 物流公司上传模板.xlsx ├── views ├── index.jade ├── error.jade └── layout.jade ├── screenshots ├── book.png ├── home.png └── order.png ├── public └── stylesheets │ └── style.css ├── config ├── rsa.js ├── redisConnect.js ├── sessionMiddleware.js ├── dbConnect.js ├── log4j.js ├── uploadConfig.js └── morgan.js ├── .gitignore ├── routes ├── api.js ├── shop.js ├── admin.js ├── user.js ├── index.js ├── book.js └── order.js ├── utils ├── errorMsg.js └── utils.js ├── schema ├── classifySchema.js ├── shopDeliveryCompanySchema.js ├── provinceSchema.js ├── citySchema.js ├── countrySchema.js ├── shopSchema.js ├── shopOptionRecordSchema.js ├── adminUserSchema.js ├── shopStockRecordSchema.js ├── shopRefundRecordSchema.js ├── shopSubOrderListSchema.js ├── shopUserSchema.js ├── shopUserDeliveryAddressSchema.js ├── bookListSchema.js └── shopOrderListSchema.js ├── CONFIG.md ├── modules ├── indexModel.js ├── adminUserModel.js ├── areaModel.js ├── shopStockRecordModel.js ├── shopModel.js ├── bookListModel.js ├── shopUserModel.js └── shopOrderModel.js ├── package.json ├── README.md ├── bin └── www ├── app.js ├── controllers ├── apiController.js ├── shopUserController.js ├── shopController.js ├── adminUserController.js ├── indexController.js ├── shopOrderController.js └── bookListController.js └── autoCreateOrder.js /resource/ding.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/ding.mp3 -------------------------------------------------------------------------------- /views/index.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= title 5 | p Welcome to #{title} 6 | -------------------------------------------------------------------------------- /screenshots/book.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/screenshots/book.png -------------------------------------------------------------------------------- /screenshots/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/screenshots/home.png -------------------------------------------------------------------------------- /screenshots/order.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/screenshots/order.png -------------------------------------------------------------------------------- /resource/images/book/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/1.jpg -------------------------------------------------------------------------------- /resource/images/book/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/2.jpg -------------------------------------------------------------------------------- /resource/images/book/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/3.jpg -------------------------------------------------------------------------------- /resource/images/book/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/5.jpg -------------------------------------------------------------------------------- /resource/images/book/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/6.jpg -------------------------------------------------------------------------------- /resource/images/book/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/7.jpg -------------------------------------------------------------------------------- /resource/images/book/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/8.jpg -------------------------------------------------------------------------------- /resource/images/book/9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/9.jpg -------------------------------------------------------------------------------- /resource/images/book/10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/10.jpg -------------------------------------------------------------------------------- /resource/images/book/11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/11.jpg -------------------------------------------------------------------------------- /resource/images/book/143.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/143.jpg -------------------------------------------------------------------------------- /resource/images/book/144.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/144.jpg -------------------------------------------------------------------------------- /resource/images/book/146.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/146.jpg -------------------------------------------------------------------------------- /resource/images/book/147.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/147.jpg -------------------------------------------------------------------------------- /resource/images/book/148.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/148.jpg -------------------------------------------------------------------------------- /resource/images/book/149.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/149.jpg -------------------------------------------------------------------------------- /resource/images/book/150.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/150.jpg -------------------------------------------------------------------------------- /resource/images/book/151.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/151.jpg -------------------------------------------------------------------------------- /resource/images/book/152.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/152.jpg -------------------------------------------------------------------------------- /resource/images/book/153.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/153.jpg -------------------------------------------------------------------------------- /resource/images/book/154.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/154.jpg -------------------------------------------------------------------------------- /resource/images/book/155.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/155.jpg -------------------------------------------------------------------------------- /resource/images/book/156.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/156.jpg -------------------------------------------------------------------------------- /resource/images/book/157.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/157.jpg -------------------------------------------------------------------------------- /resource/images/book/161.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/161.jpg -------------------------------------------------------------------------------- /resource/images/book/162.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/162.jpg -------------------------------------------------------------------------------- /resource/images/book/163.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/163.jpg -------------------------------------------------------------------------------- /resource/images/book/163.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/163.png -------------------------------------------------------------------------------- /resource/images/book/164.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/164.jpg -------------------------------------------------------------------------------- /resource/images/book/165.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/165.jpg -------------------------------------------------------------------------------- /resource/images/book/166.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/166.jpg -------------------------------------------------------------------------------- /resource/images/book/167.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/167.jpg -------------------------------------------------------------------------------- /resource/images/book/168.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/168.jpg -------------------------------------------------------------------------------- /resource/images/book/169.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/169.jpg -------------------------------------------------------------------------------- /resource/images/book/170.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/170.jpg -------------------------------------------------------------------------------- /resource/images/book/171.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/171.jpg -------------------------------------------------------------------------------- /resource/images/book/172.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/172.jpg -------------------------------------------------------------------------------- /resource/images/book/173.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/173.jpg -------------------------------------------------------------------------------- /resource/images/book/174.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/174.jpg -------------------------------------------------------------------------------- /resource/images/book/175.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/175.jpg -------------------------------------------------------------------------------- /resource/images/book/177.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/177.jpg -------------------------------------------------------------------------------- /resource/images/book/178.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/178.jpg -------------------------------------------------------------------------------- /resource/images/book/179.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/179.jpg -------------------------------------------------------------------------------- /resource/images/book/18.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/18.jpg -------------------------------------------------------------------------------- /resource/images/book/180.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/180.jpg -------------------------------------------------------------------------------- /resource/images/book/181.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/181.jpg -------------------------------------------------------------------------------- /resource/images/book/20.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/20.jpg -------------------------------------------------------------------------------- /resource/images/book/33.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/book/33.jpg -------------------------------------------------------------------------------- /views/error.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= message 5 | h2= error.status 6 | pre #{error.stack} 7 | -------------------------------------------------------------------------------- /resource/images/admin/default.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/admin/default.jpg -------------------------------------------------------------------------------- /resource/images/admin/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/admin/default.png -------------------------------------------------------------------------------- /resource/template/book/分类对照表.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/template/book/分类对照表.xlsx -------------------------------------------------------------------------------- /resource/images/login/login-bg-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/login/login-bg-2.jpg -------------------------------------------------------------------------------- /resource/images/user/15553598112.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/user/15553598112.jpg -------------------------------------------------------------------------------- /resource/images/user/15553598112.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/user/15553598112.png -------------------------------------------------------------------------------- /resource/template/book/批量上传图书.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/template/book/批量上传图书.xlsx -------------------------------------------------------------------------------- /resource/images/admin/15553598117.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/admin/15553598117.jpg -------------------------------------------------------------------------------- /resource/images/admin/15553598117.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/admin/15553598117.png -------------------------------------------------------------------------------- /resource/images/shop/swipe/swipe-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/shop/swipe/swipe-1.jpg -------------------------------------------------------------------------------- /resource/images/shop/swipe/swipe-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/shop/swipe/swipe-2.jpg -------------------------------------------------------------------------------- /resource/images/shop/swipe/swipe-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/shop/swipe/swipe-3.jpg -------------------------------------------------------------------------------- /resource/images/shop/swipe/swipe-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/shop/swipe/swipe-4.jpg -------------------------------------------------------------------------------- /resource/template/delivery/物流公司上传模板.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/template/delivery/物流公司上传模板.xlsx -------------------------------------------------------------------------------- /public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; 4 | } 5 | 6 | a { 7 | color: #00B7FF; 8 | } 9 | -------------------------------------------------------------------------------- /resource/images/shop/good/good-swipe/good-swipe-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/shop/good/good-swipe/good-swipe-1.jpg -------------------------------------------------------------------------------- /resource/images/shop/good/good-swipe/good-swipe-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/shop/good/good-swipe/good-swipe-2.jpg -------------------------------------------------------------------------------- /resource/images/shop/good/good-swipe/good-swipe-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/shop/good/good-swipe/good-swipe-3.jpg -------------------------------------------------------------------------------- /resource/images/shop/good/good-swipe/good-swipe-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/shop/good/good-swipe/good-swipe-4.jpg -------------------------------------------------------------------------------- /resource/images/shop/good/good-detail/good-detail-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pwx123/shop-store-management-server/HEAD/resource/images/shop/good/good-detail/good-detail-1.jpg -------------------------------------------------------------------------------- /views/layout.jade: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title= title 5 | link(rel='stylesheet', href='/stylesheets/style.css') 6 | body 7 | block content 8 | -------------------------------------------------------------------------------- /config/rsa.js: -------------------------------------------------------------------------------- 1 | const nodeRSA = require("node-rsa"); 2 | 3 | let rsaKey = new nodeRSA({b: 512}); 4 | rsaKey.setOptions({encryptionScheme: "pkcs1"}); 5 | 6 | module.exports = rsaKey; 7 | 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | /logs 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | 15 | # Editor directories and files 16 | .idea 17 | .vscode 18 | *.suo 19 | *.ntvs* 20 | *.njsproj 21 | *.sln 22 | *.sw* 23 | -------------------------------------------------------------------------------- /config/redisConnect.js: -------------------------------------------------------------------------------- 1 | var ioRedis = require("ioredis"); 2 | var logger = require("./log4j"); 3 | var redis = new ioRedis(); 4 | redis.connect(function () { 5 | console.log("\x1B[32m redis connection successfully\x1B[0m"); 6 | }); 7 | redis.on("error", function (error) { 8 | logger.error(error); 9 | }); 10 | exports.redis = redis; -------------------------------------------------------------------------------- /routes/api.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | const apiController = require("../controllers/apiController"); 4 | 5 | // 自动生成订单 6 | router.post("/getOrder", apiController.getOrder); 7 | // 订单通知 8 | router.post("/orderNotify", apiController.orderNotify); 9 | 10 | module.exports = router; 11 | -------------------------------------------------------------------------------- /utils/errorMsg.js: -------------------------------------------------------------------------------- 1 | /* 错误提示 */ 2 | const errorMsg = { 3 | 200: "请求成功", 4 | 401: "登陆过期或未登录,请重新登陆", 5 | 404: "请求不存在", 6 | 1001: "用户不存在", 7 | 1002: "密码错误", 8 | 1003: "用户已存在", 9 | 1004: "两次密码不一致", 10 | 1005: "原密码错误", 11 | 2001: "表格中没有数据", 12 | 2002: "更新失败,请尝试刷新后重试", 13 | 9001: "参数错误", 14 | 9999: "系统错误" 15 | }; 16 | 17 | module.exports = errorMsg; -------------------------------------------------------------------------------- /schema/classifySchema.js: -------------------------------------------------------------------------------- 1 | module.exports = function (sequelize, DataTypes) { 2 | return sequelize.define("shop_book_category", { 3 | id: { 4 | type: DataTypes.INTEGER(11), 5 | allowNull: false, 6 | primaryKey: true, 7 | autoIncrement: true 8 | }, 9 | name: { 10 | type: DataTypes.STRING(100), 11 | allowNull: false 12 | } 13 | }, { 14 | timestamps: false, 15 | freezeTableName: true 16 | }); 17 | }; -------------------------------------------------------------------------------- /schema/shopDeliveryCompanySchema.js: -------------------------------------------------------------------------------- 1 | module.exports = function (sequelize, DataTypes) { 2 | return sequelize.define("shop_delivery_company", { 3 | id: { 4 | type: DataTypes.INTEGER(11), 5 | allowNull: false, 6 | primaryKey: true, 7 | autoIncrement: true 8 | }, 9 | name: { 10 | type: DataTypes.STRING(100), 11 | allowNull: false 12 | } 13 | }, { 14 | timestamps: false, 15 | freezeTableName: true 16 | }); 17 | }; -------------------------------------------------------------------------------- /schema/provinceSchema.js: -------------------------------------------------------------------------------- 1 | module.exports = function (sequelize, DataTypes) { 2 | return sequelize.define("shop_delivery_province", { 3 | id: { 4 | type: DataTypes.INTEGER(11), 5 | allowNull: false, 6 | primaryKey: true, 7 | autoIncrement: true 8 | }, 9 | name: { 10 | type: DataTypes.STRING(64), 11 | allowNull: false 12 | }, 13 | provinceId: { 14 | type: DataTypes.STRING(12), 15 | allowNull: false 16 | } 17 | }, { 18 | timestamps: false, 19 | freezeTableName: true 20 | }); 21 | }; -------------------------------------------------------------------------------- /CONFIG.md: -------------------------------------------------------------------------------- 1 | # 项目配置 2 | 3 | ## 开发依赖 4 | 5 | - `Mysql` 数据库 6 | - `Redis` 数据库 7 | - `Apache` 或 `Nginx` 服务器 (存放图片等静态资源) 8 | 9 | ## 配置信息 10 | 11 | - `sql` 文件夹下为数据库库名以及库表结构,包含数据。 12 | - `config/dbConnect.js` 为数据库连接文件 13 | - `config/redisConnect.js` 为 `Redis` 连接文件 14 | - `config/uploadConfig.js` 为文件操作的路径信息,所有上传或下载的文件,都是存储在 `Apache` 服务器路径下的。比如上传图书照片,服务器接受照片,然后存到 `Apache` 的 `/images/book/` 路径下,然后将图片链接 `http://127.0.0.1/image/book/x.jpg` 写入数据库,前端页面就可正常访问。 15 | 16 | ## 资源文件 17 | 18 | 资源文件见 [链接](https://github.com/pwx123/shop-store-management-server/tree/master/resource), 复制到 `Apache` 服务器根目录下即可。 -------------------------------------------------------------------------------- /routes/shop.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | const shopController = require("../controllers/shopController"); 4 | 5 | // 获取店铺信息 6 | router.post("/getShopInfo", shopController.getShopInfo); 7 | // 更改店铺名 8 | router.post("/updateShopName", shopController.updateShopName); 9 | // 更改店铺状态 10 | router.post("/changeShopStatus", shopController.changeShopStatus); 11 | // 更新店铺描述 12 | router.post("/updateShopDescription", shopController.updateShopDescription); 13 | // 分页查询店铺操作日志 14 | router.post("/getOptionRecord", shopController.getOptionRecord); 15 | 16 | module.exports = router; -------------------------------------------------------------------------------- /modules/indexModel.js: -------------------------------------------------------------------------------- 1 | const db = require("../config/dbConnect"); 2 | const sequelize = db.sequelize; 3 | const adminUserSchema = sequelize.import("../schema/adminUserSchema"); 4 | 5 | class indexModel { 6 | /** 7 | * 8 | * 根据用户名查询信息 排除密码 9 | * @static 10 | * @param {*} name 用户名 11 | * @returns {Promise<*>} 12 | * @memberof indexModel 13 | */ 14 | static async getUserInfo(name) { 15 | return await adminUserSchema.findOne({ 16 | attributes: { 17 | exclude: ["pwd", "id"] 18 | }, 19 | where: { 20 | name 21 | } 22 | }); 23 | } 24 | } 25 | 26 | module.exports = indexModel; -------------------------------------------------------------------------------- /config/sessionMiddleware.js: -------------------------------------------------------------------------------- 1 | var session = require("express-session"); 2 | var redis = require("./redisConnect").redis; 3 | var redisStore = require("connect-redis")(session); 4 | 5 | module.exports = session({ 6 | store: new redisStore({ // 存储在Redis服务器中 7 | client: redis, 8 | prefix: "" 9 | }), 10 | secret: "lolHQupaD7pzuuVunipqiK8gyQeZLg+ZAOvgA3jzNgpXPeGmWqhSHbFuiXn8OKqN9ldADkf+38KX9NJfqkG9JA", //签名 11 | name: "SESSION_ID", 12 | resave: true, // 重新写入redis 13 | rolling: true, // 重新计算时间 14 | saveUninitialized: false, 15 | cookie: { 16 | httpOnly: true, 17 | maxAge: 60 * 60 * 1000 // 1小时过期 18 | } 19 | }); 20 | -------------------------------------------------------------------------------- /schema/citySchema.js: -------------------------------------------------------------------------------- 1 | module.exports = function (sequelize, DataTypes) { 2 | return sequelize.define("shop_delivery_city", { 3 | id: { 4 | type: DataTypes.INTEGER(11), 5 | allowNull: false, 6 | primaryKey: true, 7 | autoIncrement: true 8 | }, 9 | name: { 10 | type: DataTypes.STRING(64), 11 | allowNull: false 12 | }, 13 | cityId: { 14 | type: DataTypes.STRING(12), 15 | allowNull: false 16 | }, 17 | provinceId: { 18 | type: DataTypes.STRING(12), 19 | allowNull: false 20 | } 21 | }, { 22 | timestamps: false, 23 | freezeTableName: true 24 | }); 25 | }; -------------------------------------------------------------------------------- /routes/admin.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | const adminUserController = require("../controllers/adminUserController"); 4 | 5 | // 登录 6 | router.post("/login", adminUserController.login); 7 | // 注册 8 | router.post("/register", adminUserController.register); 9 | // 退出登陆 10 | router.post("/logout", adminUserController.logout); 11 | // 更改昵称 12 | router.post("/updateNickname", adminUserController.updateNickname); 13 | // 更改密码 14 | router.post("/updatePassword", adminUserController.updatePassword); 15 | // 更改头像 16 | router.post("/updateAvatar", adminUserController.updateAvatar); 17 | 18 | module.exports = router; -------------------------------------------------------------------------------- /schema/countrySchema.js: -------------------------------------------------------------------------------- 1 | module.exports = function (sequelize, DataTypes) { 2 | return sequelize.define("shop_delivery_country", { 3 | id: { 4 | type: DataTypes.INTEGER(11), 5 | allowNull: false, 6 | primaryKey: true, 7 | autoIncrement: true 8 | }, 9 | name: { 10 | type: DataTypes.STRING(64), 11 | allowNull: false 12 | }, 13 | countryId: { 14 | type: DataTypes.STRING(12), 15 | allowNull: false 16 | }, 17 | cityId: { 18 | type: DataTypes.STRING(12), 19 | allowNull: false 20 | } 21 | }, { 22 | timestamps: false, 23 | freezeTableName: true 24 | }); 25 | }; -------------------------------------------------------------------------------- /routes/user.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | const shopUserController = require("../controllers/shopUserController"); 4 | 5 | // 获取用户信息 6 | router.post("/getShopUserInfo", shopUserController.getShopUserInfo); 7 | // 获取用户收货地址 8 | router.post("/getUserDeliveryAddress", shopUserController.getUserDeliveryAddress); 9 | // 根据id查询收货地址 10 | router.post("/getOrderAddressById", shopUserController.getOrderAddressById); 11 | // 更新用户账号状态 12 | router.post("/changeUserStatus", shopUserController.changeUserStatus); 13 | // 重置用户密码 返回随机生成的密码 14 | router.post("/resetUserPwd", shopUserController.resetUserPwd); 15 | 16 | module.exports = router; -------------------------------------------------------------------------------- /config/dbConnect.js: -------------------------------------------------------------------------------- 1 | const Sequelize = require("sequelize"); 2 | const sequelize = new Sequelize("shop_store_management", "root", "", { 3 | host: "localhost", 4 | dialect: "mysql", 5 | operatorsAliases: false, 6 | dialectOptions: { 7 | charset: "utf8mb4", 8 | supportBigNumbers: true, 9 | bigNumberStrings: true 10 | }, 11 | pool: { 12 | max: 5, 13 | min: 0, 14 | acquire: 30000, 15 | idle: 10000 16 | }, 17 | timezone: "+08:00" 18 | }); 19 | 20 | sequelize 21 | .authenticate() 22 | .then(() => { 23 | console.log("\x1B[32m mysql connection successfully\x1B[0m"); 24 | }) 25 | .catch(err => { 26 | console.error("Unable to connect to the database:", err); 27 | }); 28 | 29 | module.exports = { 30 | sequelize 31 | }; -------------------------------------------------------------------------------- /schema/shopSchema.js: -------------------------------------------------------------------------------- 1 | const moment = require("moment"); 2 | module.exports = function (sequelize, DataTypes) { 3 | return sequelize.define("shop_info", { 4 | id: { 5 | type: DataTypes.INTEGER(11), 6 | allowNull: false, 7 | primaryKey: true, 8 | autoIncrement: true 9 | }, 10 | shopName: { 11 | type: DataTypes.STRING(40), 12 | allowNull: false 13 | }, 14 | status: { 15 | type: DataTypes.INTEGER(1), 16 | allowNull: false 17 | }, 18 | description: { 19 | type: DataTypes.INTEGER(200), 20 | allowNull: true 21 | }, 22 | updatedAt: { 23 | type: DataTypes.DATE, 24 | get() { 25 | return moment(this.getDataValue("updatedAt")).format("YYYY-MM-DD HH:mm:ss"); 26 | } 27 | } 28 | }, { 29 | timestamps: false, 30 | freezeTableName: true 31 | }); 32 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "graduation-project-server", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "set NODE_ENV=development&& node ./bin/www", 7 | "production": "set NODE_ENV=production&& node ./bin/www" 8 | }, 9 | "dependencies": { 10 | "archiver": "^3.0.0", 11 | "axios": "^0.18.0", 12 | "connect-redis": "^3.4.1", 13 | "cookie-parser": "~1.4.3", 14 | "crypto": "^1.0.1", 15 | "debug": "~2.6.9", 16 | "decimal.js": "^10.1.1", 17 | "express": "~4.16.0", 18 | "express-session": "^1.15.6", 19 | "formidable": "^1.2.1", 20 | "http-errors": "~1.6.2", 21 | "ioredis": "^4.6.2", 22 | "jade": "~1.11.0", 23 | "log4js": "^3.0.6", 24 | "morgan": "~1.9.0", 25 | "mysql": "^2.16.0", 26 | "mysql2": "^1.6.5", 27 | "node-rsa": "^1.0.2", 28 | "node-xlsx": "^0.14.1", 29 | "sequelize": "^4.43.0", 30 | "socket.io": "^2.2.0", 31 | "unzip": "^0.1.11" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /config/log4j.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const log4js = require("log4js"); 3 | let fileName = "log"; 4 | 5 | log4js.configure({ 6 | appenders: { 7 | console: { 8 | type: "console", 9 | }, 10 | data_file: { 11 | type: "dateFile", 12 | filename: path.join(__dirname, `/../logs/${fileName}`), 13 | alwaysIncludePattern: true, 14 | daysToKeep: 10, 15 | pattern: "_yyyy-MM-dd-hh.log", 16 | encoding: "utf-8", 17 | }, 18 | }, 19 | categories: { 20 | default: { 21 | appenders: ["console"], 22 | level: "info" 23 | }, 24 | production: { 25 | appenders: ["data_file"], 26 | level: "warn" 27 | }, 28 | console: { 29 | appenders: ["console"], 30 | level: "all" 31 | } 32 | }, 33 | }); 34 | 35 | let logger; 36 | if (process.env.NODE_ENV == "development") { 37 | logger = log4js.getLogger("console"); 38 | } else { 39 | logger = log4js.getLogger("production"); 40 | } 41 | module.exports = logger; -------------------------------------------------------------------------------- /schema/shopOptionRecordSchema.js: -------------------------------------------------------------------------------- 1 | const moment = require("moment"); 2 | module.exports = function (sequelize, DataTypes) { 3 | return sequelize.define("shop_option_record", { 4 | id: { 5 | type: DataTypes.INTEGER(11), 6 | allowNull: false, 7 | primaryKey: true, 8 | autoIncrement: true 9 | }, 10 | optionName: { 11 | type: DataTypes.STRING(40), 12 | allowNull: false 13 | }, 14 | optionNickname: { 15 | type: DataTypes.STRING(20), 16 | allowNull: false 17 | }, 18 | optionType: { 19 | type: DataTypes.INTEGER(11), 20 | allowNull: false, 21 | defaultValue: 0 22 | }, 23 | remark: { 24 | type: DataTypes.STRING(100), 25 | allowNull: false 26 | }, 27 | createdAt: { 28 | type: DataTypes.DATE, 29 | get() { 30 | return moment(this.getDataValue("createdAt")).format("YYYY-MM-DD HH:mm:ss"); 31 | } 32 | } 33 | }, { 34 | timestamps: false, 35 | freezeTableName: true 36 | }); 37 | }; -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | const indexController = require("../controllers/indexController"); 4 | 5 | // 获取公钥 6 | router.post("/getPublicKey", indexController.getPublicKey); 7 | // 获取用户信息 8 | router.post("/getUserInfo", indexController.getUserInfo); 9 | // 获取省份 10 | router.post("/getProvince", indexController.getProvince); 11 | // 根据省份获取市 12 | router.post("/getCityByProvince", indexController.getCityByProvince); 13 | // 根据市获取县 14 | router.post("/getCountryByCity", indexController.getCountryByCity); 15 | // 根据物流单号获取物流信息 16 | router.post("/getDeliveryInfoById", indexController.getDeliveryInfoById); 17 | // 获取订单信息 18 | router.post("/getOrderStatistics", indexController.getOrderStatistics); 19 | // 获取订单统计信息 20 | router.post("/getOrderStatisticsByType", indexController.getOrderStatisticsByType); 21 | // 获取本月Top10信息 22 | router.post("/getTop10Info", indexController.getTop10Info); 23 | // 获取趋势信息 24 | router.post("/getTrendInfo", indexController.getTrendInfo); 25 | 26 | module.exports = router; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 网上书店管理系统-后端 2 | 3 | 基于 `Vue`, `Element` 的网上书店管理后台。 4 | 5 | 6 | ## 项目其他部分 7 | 8 | 网上书店-前端 [链接](https://github.com/pwx123/shop-store-client) 9 | 10 | 网上书店-后端 [链接](https://github.com/pwx123/shop-store-server) 11 | 12 | 网上书店管理系统-前端 [链接](https://github.com/pwx123/shop-store-management-client) 13 | 14 | ## 实现功能 15 | 16 | - 管理员登录/注册 17 | - 首页数据展示 18 | - 订单通知/管理 19 | - 书籍管理 20 | - 用户管理 21 | - 店铺管理 22 | 23 | ## 项目预览 24 | 25 | 访问地址 [链接](http://182.254.192.62/book-store-management) 26 | 27 | ## 项目配置 28 | 29 | 见配置文档 [链接](https://github.com/pwx123/shop-store-management-server/blob/master/CONFIG.md) 30 | 31 | ## 项目运行 32 | 33 | ``` bash 34 | # 安装依赖 35 | npm install 36 | 37 | # 启动 38 | npm start 39 | ``` 40 | 41 | ## 项目截图 42 | ### 首页 43 | ![首页](https://github.com/pwx123/shop-store-management-server/raw/master/screenshots/home.png) 44 | 45 | ### 订单 46 | ![订单](https://github.com/pwx123/shop-store-management-server/raw/master/screenshots/order.png) 47 | 48 | ### 图书 49 | ![图书](https://github.com/pwx123/shop-store-management-server/raw/master/screenshots/book.png) 50 | -------------------------------------------------------------------------------- /config/uploadConfig.js: -------------------------------------------------------------------------------- 1 | // 编码 2 | const ENCODING = "utf-8"; 3 | // 服务器目录 4 | const SERVER_DIR = "D:/wampServer/www"; 5 | // 图书下载模板文件名 6 | const BOOK_NAME = "批量上传图书.xlsx"; 7 | // 图书下载模板位置 8 | const BOOK_TEMPLATE = "/template/book"; 9 | // 物流下载模板位置 10 | const DELIVERY_TEMPLATE = "/template/delivery"; 11 | // temp临时目录 12 | const TEMP = "/temp"; 13 | // 分类对照表excel文件名 14 | const CLASSIFY_EXCEL_NAME = "分类对照表.xlsx"; 15 | // 压缩文件名 16 | const ZIP_NAME = "上传模板.zip"; 17 | // 物流下载模板名称 18 | const DELIVERY_COMPONY_EXCEL = "物流公司上传模板.xlsx"; 19 | // 是否保存拓展 20 | const KEEP_EXTENSIONS = true; 21 | // 最大上传大小 22 | const MAX_FILESIZE = 1024 * 1024 * 20; 23 | // 服务器URL 24 | const SERVER_URL = "http://127.0.0.1"; 25 | // 图书图片地址 26 | const BOOK_IMG_URL = "/images/book/"; 27 | // 管理员头像地址 28 | const ADMIN_AVATAR_URL = "/images/admin/"; 29 | 30 | module.exports = { 31 | ENCODING, 32 | SERVER_DIR, 33 | KEEP_EXTENSIONS, 34 | MAX_FILESIZE, 35 | SERVER_URL, 36 | BOOK_NAME, 37 | BOOK_TEMPLATE, 38 | DELIVERY_TEMPLATE, 39 | CLASSIFY_EXCEL_NAME, 40 | ZIP_NAME, 41 | BOOK_IMG_URL, 42 | TEMP, 43 | ADMIN_AVATAR_URL, 44 | DELIVERY_COMPONY_EXCEL 45 | }; -------------------------------------------------------------------------------- /schema/adminUserSchema.js: -------------------------------------------------------------------------------- 1 | const moment = require("moment"); 2 | module.exports = function (sequelize, DataTypes) { 3 | return sequelize.define("shop_admin_user", { 4 | id: { 5 | type: DataTypes.INTEGER(11), 6 | allowNull: false, 7 | primaryKey: true, 8 | autoIncrement: true 9 | }, 10 | name: { 11 | type: DataTypes.STRING(40), 12 | allowNull: false 13 | }, 14 | pwd: { 15 | type: DataTypes.STRING(255), 16 | allowNull: false 17 | }, 18 | nickname: { 19 | type: DataTypes.STRING(20), 20 | allowNull: false 21 | }, 22 | avatarUrl: { 23 | type: DataTypes.STRING(200), 24 | allowNull: true 25 | }, 26 | createdAt: { 27 | type: DataTypes.DATE, 28 | get() { 29 | return moment(this.getDataValue("createdAt")).format("YYYY-MM-DD HH:mm:ss"); 30 | } 31 | }, 32 | updatedAt: { 33 | type: DataTypes.DATE, 34 | get() { 35 | return moment(this.getDataValue("updatedAt")).format("YYYY-MM-DD HH:mm:ss"); 36 | } 37 | } 38 | }, { 39 | timestamps: false, 40 | freezeTableName: true 41 | }); 42 | }; -------------------------------------------------------------------------------- /schema/shopStockRecordSchema.js: -------------------------------------------------------------------------------- 1 | const moment = require("moment"); 2 | module.exports = function (sequelize, DataTypes) { 3 | return sequelize.define("shop_stock_record", { 4 | id: { 5 | type: DataTypes.INTEGER(11), 6 | allowNull: false, 7 | primaryKey: true, 8 | autoIncrement: true 9 | }, 10 | bookId: { 11 | type: DataTypes.INTEGER(11), 12 | allowNull: false 13 | }, 14 | bookName: { 15 | type: DataTypes.STRING(100), 16 | allowNull: false 17 | }, 18 | stockNum: { 19 | type: DataTypes.INTEGER(11), 20 | allowNull: false 21 | }, 22 | stockPrice: { 23 | type: DataTypes.FLOAT(11, 2), 24 | allowNull: true 25 | }, 26 | type: { 27 | type: DataTypes.INTEGER(11), 28 | allowNull: false, 29 | }, 30 | remark: { 31 | type: DataTypes.STRING(255), 32 | allowNull: true 33 | }, 34 | createdAt: { 35 | type: DataTypes.DATE, 36 | get() { 37 | return moment(this.getDataValue("createdAt")).format("YYYY-MM-DD HH:mm:ss"); 38 | } 39 | } 40 | }, { 41 | timestamps: false, 42 | freezeTableName: true 43 | }); 44 | }; -------------------------------------------------------------------------------- /schema/shopRefundRecordSchema.js: -------------------------------------------------------------------------------- 1 | const moment = require("moment"); 2 | module.exports = function (sequelize, DataTypes) { 3 | return sequelize.define("shop_refund_record", { 4 | id: { 5 | type: DataTypes.INTEGER(11), 6 | allowNull: false, 7 | primaryKey: true, 8 | autoIncrement: true 9 | }, 10 | refundOrderId: { 11 | type: DataTypes.STRING(40), 12 | allowNull: false 13 | }, 14 | orderNumId: { 15 | type: DataTypes.STRING(40), 16 | allowNull: false 17 | }, 18 | userName: { 19 | type: DataTypes.STRING(20), 20 | allowNull: false 21 | }, 22 | status: { 23 | type: DataTypes.INTEGER(11), 24 | allowNull: false 25 | }, 26 | refundMoney: { 27 | type: DataTypes.FLOAT(11, 2), 28 | allowNull: true 29 | }, 30 | remark: { 31 | type: DataTypes.STRING(100), 32 | allowNull: false 33 | }, 34 | createdAt: { 35 | type: DataTypes.DATE, 36 | get() { 37 | return moment(this.getDataValue("createdAt")).format("YYYY-MM-DD HH:mm:ss"); 38 | } 39 | } 40 | }, { 41 | timestamps: false, 42 | freezeTableName: true 43 | }); 44 | }; -------------------------------------------------------------------------------- /routes/book.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | const bookListController = require("../controllers/bookListController"); 4 | 5 | // 获取图书列表 6 | router.post("/getBookList", bookListController.getBookList); 7 | // 删除列表中的图书 8 | router.post("/deleteBooks", bookListController.deleteBooks); 9 | // 获取所有图书分类 10 | router.post("/getAllClassify", bookListController.getAllClassify); 11 | // 新增图书 12 | router.post("/insertBook", bookListController.insertBook); 13 | // 更新图书 14 | router.post("/updateBook", bookListController.updateBook); 15 | // 批量上传图书 16 | router.post("/uploadExcel", bookListController.uploadExcel); 17 | // 下载上传模板 18 | router.post("/downloadBookTemplate", bookListController.downloadBookTemplate); 19 | // 删除分类 20 | router.post("/deleteClassify", bookListController.deleteClassify); 21 | // 新增分类 22 | router.post("/addClassify", bookListController.addClassify); 23 | // 批量上下架 24 | router.post("/changeBookSellStatus", bookListController.changeBookSellStatus); 25 | // 修改库存 26 | router.post("/updateBookStock", bookListController.updateBookStock); 27 | // 分页查询进货记录 28 | router.post("/getStockRecordList", bookListController.getStockRecordList); 29 | module.exports = router; -------------------------------------------------------------------------------- /config/morgan.js: -------------------------------------------------------------------------------- 1 | /* 请求头打印 */ 2 | const morgan = require("morgan"); 3 | 4 | morgan.token("requestParameters", function (req, res) { 5 | return JSON.stringify(req.query) || "-"; 6 | }); 7 | morgan.token("requestBody", function (req, res) { 8 | return JSON.stringify(req.body) || "-"; 9 | }); 10 | 11 | morgan.format("live-api", function developmentFormatLine(tokens, req, res) { 12 | let status = headersSent(res) ? 13 | res.statusCode : 14 | undefined; 15 | 16 | let color = status >= 500 ? 31 // red 17 | : 18 | status >= 400 ? 33 // yellow 19 | : 20 | status >= 300 ? 36 // cyan 21 | : 22 | status >= 200 ? 32 // green 23 | : 24 | 0; // no color 25 | let fn = developmentFormatLine[color]; 26 | 27 | if (!fn) { 28 | fn = developmentFormatLine[color] = morgan.compile("\x1b[0m:method :url \x1b[" + 29 | color + "m:status\x1b[0m :response-time ms - :res[content-length]\x1b[0m :requestParameters :requestBody"); 30 | } 31 | return fn(tokens, req, res); 32 | }); 33 | 34 | function headersSent(res) { 35 | return typeof res.headersSent !== "boolean" ? 36 | Boolean(res._header) : 37 | res.headersSent; 38 | } 39 | 40 | module.exports = morgan; -------------------------------------------------------------------------------- /modules/adminUserModel.js: -------------------------------------------------------------------------------- 1 | const db = require("../config/dbConnect"); 2 | const sequelize = db.sequelize; 3 | const adminUserSchema = sequelize.import("../schema/adminUserSchema"); 4 | 5 | class adminUserModel { 6 | /** 7 | * 8 | * 根据用户名查询信息 9 | * @static 10 | * @param {*} name 用户名 11 | * @returns {Promise<*>} 12 | * @memberof adminUserModel 13 | */ 14 | static async getUserInfo(name) { 15 | return await adminUserSchema.findOne({ 16 | where: { 17 | name 18 | } 19 | }); 20 | } 21 | 22 | /** 23 | * 插入数据 24 | * 25 | * @static 26 | * @param {*} name 27 | * @param {*} pwd 28 | * @returns 29 | * @memberof adminUserModel 30 | */ 31 | static async create(user) { 32 | return await adminUserSchema.create({ 33 | ...user 34 | }); 35 | } 36 | 37 | /** 38 | * 修改数据 39 | * 40 | * @static 41 | * @param {Object} parmas 42 | * @param {*} loginUser 用户手机号 43 | * @returns 44 | * @memberof adminUserModel 45 | */ 46 | static async update(parmas, loginUser) { 47 | return await adminUserSchema.update({ 48 | ...parmas 49 | }, { 50 | where: { 51 | name: loginUser 52 | } 53 | }); 54 | } 55 | } 56 | 57 | module.exports = adminUserModel; -------------------------------------------------------------------------------- /schema/shopSubOrderListSchema.js: -------------------------------------------------------------------------------- 1 | const moment = require("moment"); 2 | module.exports = function (sequelize, DataTypes) { 3 | return sequelize.define("shop_sub_order_list", { 4 | id: { 5 | type: DataTypes.INTEGER(11), 6 | allowNull: false, 7 | primaryKey: true, 8 | autoIncrement: true 9 | }, 10 | mainOrderId: { 11 | type: DataTypes.INTEGER(11), 12 | allowNull: false 13 | }, 14 | bookId: { 15 | type: DataTypes.INTEGER(11), 16 | allowNull: false 17 | }, 18 | bookName: { 19 | type: DataTypes.STRING(100), 20 | allowNull: false 21 | }, 22 | bookTitle: { 23 | type: DataTypes.STRING(200), 24 | allowNull: false 25 | }, 26 | bookNum: { 27 | type: DataTypes.INTEGER(11), 28 | allowNull: false 29 | }, 30 | bookPrice: { 31 | type: DataTypes.FLOAT(11, 2), 32 | allowNull: false 33 | }, 34 | bookSalePrice: { 35 | type: DataTypes.FLOAT(11, 2), 36 | allowNull: false 37 | }, 38 | bookImageUrl: { 39 | type: DataTypes.STRING(200), 40 | allowNull: true 41 | }, 42 | createdAt: { 43 | type: DataTypes.DATE, 44 | get() { 45 | return moment(this.getDataValue("createdAt")).format("YYYY-MM-DD HH:mm:ss"); 46 | } 47 | } 48 | }, { 49 | timestamps: false, 50 | freezeTableName: true 51 | }); 52 | }; -------------------------------------------------------------------------------- /modules/areaModel.js: -------------------------------------------------------------------------------- 1 | const db = require("../config/dbConnect"); 2 | const sequelize = db.sequelize; 3 | const provinceSchema = sequelize.import("../schema/provinceSchema"); 4 | const citySchema = sequelize.import("../schema/citySchema"); 5 | const countrySchema = sequelize.import("../schema/countrySchema"); 6 | 7 | class indexModel { 8 | /** 9 | * 获取省份 10 | * 11 | * @static 12 | * @memberof indexModel 13 | */ 14 | static async getProvince() { 15 | return await provinceSchema.findAll({ 16 | attributes: { 17 | exclude: ["id"] 18 | }, 19 | }); 20 | } 21 | 22 | /** 23 | * 根据省份获取市 24 | * 25 | * @static 26 | * @param {string} provinceId 省份id 27 | * @memberof indexModel 28 | */ 29 | static async getCityByProvince(provinceId) { 30 | return await citySchema.findAll({ 31 | attributes: { 32 | exclude: ["id", "provinceId"] 33 | }, 34 | where: { 35 | provinceId 36 | } 37 | }); 38 | } 39 | 40 | /** 41 | * 根据市获取县 42 | * 43 | * @static 44 | * @param {string} cityId 市id 45 | * @memberof indexModel 46 | */ 47 | static async getCountryByCity(cityId) { 48 | return await countrySchema.findAll({ 49 | attributes: { 50 | exclude: ["id", "cityId"] 51 | }, 52 | where: { 53 | cityId 54 | } 55 | }); 56 | } 57 | } 58 | 59 | module.exports = indexModel; -------------------------------------------------------------------------------- /routes/order.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | const shopOrderController = require("../controllers/shopOrderController"); 4 | 5 | // 分页查询订单列表 6 | router.post("/getOrderList", shopOrderController.getOrderList); 7 | // 根据订单号查询订单 8 | router.post("/getOrderByOrderId", shopOrderController.getOrderByOrderId); 9 | // 确认待处理订单 10 | router.post("/submitOrder", shopOrderController.submitOrder); 11 | // 上传/编辑物流信息 12 | router.post("/submitDeliveryInfo", shopOrderController.submitDeliveryInfo); 13 | // 更改收货地址 14 | router.post("/updateOrderAddress", shopOrderController.updateOrderAddress); 15 | // 新增收货地址 16 | router.post("/submitAddAddress", shopOrderController.submitAddAddress); 17 | // 退款订单处理 18 | router.post("/submitRefundInfo", shopOrderController.submitRefundInfo); 19 | // 分页获取退款订单记录 20 | router.post("/getRefundRecord", shopOrderController.getRefundRecord); 21 | // 查询所有物流公司 22 | router.post("/getAllDeliveryCompany", shopOrderController.getAllDeliveryCompany); 23 | // 添加物流公司 24 | router.post("/addDeliveryCompany", shopOrderController.addDeliveryCompany); 25 | // 删除物流公司 26 | router.post("/deleteDeliveryCompany", shopOrderController.deleteDeliveryCompany); 27 | // 批量上传物流公司 28 | router.post("/uploadDeliveryExcel", shopOrderController.uploadDeliveryExcel); 29 | // 下载物流上传模板 30 | router.post("/downloadDeliveryTemplate", shopOrderController.downloadDeliveryTemplate); 31 | 32 | module.exports = router; -------------------------------------------------------------------------------- /schema/shopUserSchema.js: -------------------------------------------------------------------------------- 1 | const moment = require("moment"); 2 | module.exports = function (sequelize, DataTypes) { 3 | return sequelize.define("shop_user_list", { 4 | id: { 5 | type: DataTypes.INTEGER(11), 6 | allowNull: false, 7 | primaryKey: true, 8 | autoIncrement: true 9 | }, 10 | name: { 11 | type: DataTypes.STRING(40), 12 | allowNull: false 13 | }, 14 | nickname: { 15 | type: DataTypes.STRING(20), 16 | allowNull: false 17 | }, 18 | pwd: { 19 | type: DataTypes.STRING(255), 20 | allowNull: false 21 | }, 22 | payPwd: { 23 | type: DataTypes.STRING(255), 24 | allowNull: true 25 | }, 26 | sex: { 27 | type: DataTypes.INTEGER(11), 28 | allowNull: true 29 | }, 30 | status: { 31 | type: DataTypes.INTEGER(11), 32 | allowNull: false 33 | }, 34 | email: { 35 | type: DataTypes.STRING(40), 36 | allowNull: true 37 | }, 38 | avatarUrl: { 39 | type: DataTypes.STRING(500), 40 | allowNull: true 41 | }, 42 | createdAt: { 43 | type: DataTypes.DATE, 44 | get() { 45 | return moment(this.getDataValue("createdAt")).format("YYYY-MM-DD HH:mm:ss"); 46 | } 47 | }, 48 | updatedAt: { 49 | type: DataTypes.DATE, 50 | get() { 51 | return moment(this.getDataValue("updatedAt")).format("YYYY-MM-DD HH:mm:ss"); 52 | } 53 | } 54 | }, { 55 | timestamps: false, 56 | freezeTableName: true 57 | }); 58 | }; 59 | -------------------------------------------------------------------------------- /modules/shopStockRecordModel.js: -------------------------------------------------------------------------------- 1 | const db = require("../config/dbConnect"); 2 | const sequelize = db.sequelize; 3 | const Op = sequelize.Op; 4 | const shopStockRecordSchema = sequelize.import("../schema/shopStockRecordSchema"); 5 | const getUncertainSqlObj = require("./../utils/utils").getUncertainSqlObj; 6 | const getUncertainLikeSqlObj = require("./../utils/utils").getUncertainLikeSqlObj; 7 | 8 | class shopModel { 9 | 10 | /** 11 | * 查询店铺操作列表 分页 12 | * 13 | * @static 14 | * @memberof shopModel 15 | */ 16 | static async getStockRecordList(parmas) { 17 | let { 18 | pageSize, 19 | pageNumber, 20 | startTime, 21 | endTime, 22 | bookName, 23 | type 24 | } = parmas; 25 | let searchObj = getUncertainSqlObj({ 26 | type 27 | }); 28 | let likeObj = getUncertainLikeSqlObj({ 29 | bookName 30 | }); 31 | let result = await shopStockRecordSchema.findAndCountAll({ 32 | offset: pageSize * (pageNumber - 1), 33 | limit: pageSize, 34 | where: { 35 | createdAt: { 36 | [Op.gt]: startTime, 37 | [Op.lt]: endTime, 38 | }, 39 | ...searchObj, 40 | ...likeObj 41 | }, 42 | order: [ 43 | ["id", "DESC"] 44 | ] 45 | }); 46 | return { 47 | pageSize, 48 | pageNumber, 49 | rows: result.rows, 50 | total: result.count 51 | }; 52 | } 53 | 54 | /** 55 | * 生成进货记录 56 | * 57 | * @static 58 | * @param {*} params 59 | * @memberof shopModel 60 | */ 61 | static async createStockRecord(paramsArr) { 62 | shopStockRecordSchema.bulkCreate(paramsArr); 63 | } 64 | } 65 | 66 | module.exports = shopModel; -------------------------------------------------------------------------------- /schema/shopUserDeliveryAddressSchema.js: -------------------------------------------------------------------------------- 1 | const moment = require("moment"); 2 | module.exports = function (sequelize, DataTypes) { 3 | return sequelize.define("shop_user_delivery", { 4 | id: { 5 | type: DataTypes.INTEGER(11), 6 | allowNull: false, 7 | primaryKey: true, 8 | autoIncrement: true 9 | }, 10 | userId: { 11 | type: DataTypes.INTEGER(11), 12 | allowNull: false, 13 | }, 14 | status: { 15 | type: DataTypes.INTEGER(11), 16 | allowNull: false, 17 | defaultValue: 0 18 | }, 19 | deliveryName: { 20 | type: DataTypes.STRING(20), 21 | allowNull: false 22 | }, 23 | deliveryMobile: { 24 | type: DataTypes.STRING(20), 25 | allowNull: false 26 | }, 27 | provinceId: { 28 | type: DataTypes.STRING(20), 29 | allowNull: false 30 | }, 31 | cityId: { 32 | type: DataTypes.STRING(20), 33 | allowNull: false 34 | }, 35 | countryId: { 36 | type: DataTypes.STRING(20), 37 | allowNull: false 38 | }, 39 | isDefault: { 40 | type: DataTypes.INTEGER(11), 41 | allowNull: false, 42 | defaultValue: 0 43 | }, 44 | detailAddress: { 45 | type: DataTypes.STRING(255), 46 | allowNull: false 47 | }, 48 | createdAt: { 49 | type: DataTypes.DATE, 50 | get() { 51 | return moment(this.getDataValue("createdAt")).format("YYYY-MM-DD HH:mm:ss"); 52 | } 53 | }, 54 | updatedAt: { 55 | type: DataTypes.DATE, 56 | get() { 57 | return moment(this.getDataValue("updatedAt")).format("YYYY-MM-DD HH:mm:ss"); 58 | } 59 | } 60 | }, { 61 | timestamps: false, 62 | freezeTableName: true 63 | }); 64 | }; -------------------------------------------------------------------------------- /bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require("../app"); 8 | var debug = require("debug")("graduation-project-server:server"); 9 | var http = require("http"); 10 | 11 | /** 12 | * Get port from environment and store in Express. 13 | */ 14 | 15 | var port = normalizePort(process.env.PORT || "3000"); 16 | app.set("port", port); 17 | 18 | /** 19 | * Create HTTP server. 20 | */ 21 | 22 | var server = http.createServer(app); 23 | 24 | /** 25 | * Listen on provided port, on all network interfaces. 26 | */ 27 | 28 | server.on("error", onError); 29 | server.on("listening", onListening); 30 | 31 | /** 32 | * Normalize a port into a number, string, or false. 33 | */ 34 | 35 | function normalizePort(val) { 36 | var port = parseInt(val, 10); 37 | 38 | if (isNaN(port)) { 39 | // named pipe 40 | return val; 41 | } 42 | 43 | if (port >= 0) { 44 | // port number 45 | return port; 46 | } 47 | 48 | return false; 49 | } 50 | 51 | /** 52 | * Event listener for HTTP server "error" event. 53 | */ 54 | 55 | function onError(error) { 56 | if (error.syscall !== "listen") { 57 | throw error; 58 | } 59 | 60 | var bind = typeof port === "string" 61 | ? "Pipe " + port 62 | : "Port " + port; 63 | 64 | // handle specific listen errors with friendly messages 65 | switch (error.code) { 66 | case "EACCES": 67 | console.error(bind + " requires elevated privileges"); 68 | process.exit(1); 69 | break; 70 | case "EADDRINUSE": 71 | console.error(bind + " is already in use"); 72 | process.exit(1); 73 | break; 74 | default: 75 | throw error; 76 | } 77 | } 78 | 79 | /** 80 | * Event listener for HTTP server "listening" event. 81 | */ 82 | 83 | function onListening() { 84 | var addr = server.address(); 85 | var bind = typeof addr === "string" 86 | ? "pipe " + addr 87 | : "port " + addr.port; 88 | debug("Listening on " + bind); 89 | } 90 | -------------------------------------------------------------------------------- /schema/bookListSchema.js: -------------------------------------------------------------------------------- 1 | const moment = require("moment"); 2 | module.exports = function (sequelize, DataTypes) { 3 | return sequelize.define("shop_book_list", { 4 | id: { 5 | type: DataTypes.INTEGER(11), 6 | allowNull: false, 7 | primaryKey: true, 8 | autoIncrement: true 9 | }, 10 | status: { 11 | type: DataTypes.INTEGER(11), 12 | allowNull: false, 13 | defaultValue: 0 14 | }, 15 | name: { 16 | type: DataTypes.STRING(100), 17 | allowNull: false 18 | }, 19 | author: { 20 | type: DataTypes.STRING(100), 21 | allowNull: false 22 | }, 23 | press: { 24 | type: DataTypes.STRING(100), 25 | allowNull: false 26 | }, 27 | classify: { 28 | type: DataTypes.STRING(100), 29 | allowNull: true 30 | }, 31 | title: { 32 | type: DataTypes.STRING(200), 33 | allowNull: false 34 | }, 35 | description: { 36 | type: DataTypes.STRING(500), 37 | allowNull: false 38 | }, 39 | stock: { 40 | type: DataTypes.INTEGER(11), 41 | allowNull: false 42 | }, 43 | price: { 44 | type: DataTypes.FLOAT(11, 2), 45 | allowNull: false 46 | }, 47 | stockPrice: { 48 | type: DataTypes.FLOAT(11, 2), 49 | allowNull: false 50 | }, 51 | salePrice: { 52 | type: DataTypes.FLOAT(11, 2), 53 | allowNull: false 54 | }, 55 | isSell: { 56 | type: DataTypes.INTEGER(1), 57 | allowNull: false, 58 | defaultValue: 1 59 | }, 60 | imageUrl: { 61 | type: DataTypes.STRING(200) 62 | }, 63 | description: { 64 | type: DataTypes.STRING(500), 65 | allowNull: false 66 | }, 67 | createdAt: { 68 | type: DataTypes.DATE, 69 | get() { 70 | return moment(this.getDataValue("createdAt")).format("YYYY-MM-DD HH:mm:ss"); 71 | } 72 | }, 73 | updatedAt: { 74 | type: DataTypes.DATE, 75 | get() { 76 | return moment(this.getDataValue("updatedAt")).format("YYYY-MM-DD HH:mm:ss"); 77 | } 78 | } 79 | }, { 80 | timestamps: false, 81 | freezeTableName: true 82 | }); 83 | }; -------------------------------------------------------------------------------- /schema/shopOrderListSchema.js: -------------------------------------------------------------------------------- 1 | const moment = require("moment"); 2 | module.exports = function (sequelize, DataTypes) { 3 | return sequelize.define("shop_order_list", { 4 | id: { 5 | type: DataTypes.INTEGER(11), 6 | allowNull: false, 7 | primaryKey: true, 8 | autoIncrement: true 9 | }, 10 | orderId: { 11 | type: DataTypes.STRING(40), 12 | allowNull: false 13 | }, 14 | userId: { 15 | type: DataTypes.INTEGER(11), 16 | allowNull: false 17 | }, 18 | userName: { 19 | type: DataTypes.STRING(20), 20 | allowNull: false 21 | }, 22 | status: { 23 | type: DataTypes.INTEGER(11), 24 | allowNull: false 25 | }, 26 | orderNum: { 27 | type: DataTypes.INTEGER(11), 28 | allowNull: false 29 | }, 30 | orderMoney: { 31 | type: DataTypes.FLOAT(11, 2), 32 | allowNull: false 33 | }, 34 | deliveryMoney: { 35 | type: DataTypes.FLOAT(11, 2), 36 | allowNull: false 37 | }, 38 | totalMoney: { 39 | type: DataTypes.FLOAT(11, 2), 40 | allowNull: false 41 | }, 42 | deliveryId: { 43 | type: DataTypes.INTEGER(11), 44 | allowNull: true 45 | }, 46 | deliveryOrderId: { 47 | type: DataTypes.STRING(40), 48 | allowNull: true 49 | }, 50 | deliveryAddressId: { 51 | type: DataTypes.INTEGER(11), 52 | allowNull: false 53 | }, 54 | remark: { 55 | type: DataTypes.STRING(255), 56 | allowNull: true 57 | }, 58 | createdAt: { 59 | type: DataTypes.DATE, 60 | get() { 61 | return moment(this.getDataValue("createdAt")).format("YYYY-MM-DD HH:mm:ss"); 62 | } 63 | }, 64 | deliveryAt: { 65 | type: DataTypes.DATE, 66 | allowNull: true, 67 | get() { 68 | return this.getDataValue("deliveryAt") ? moment(this.getDataValue("deliveryAt")).format("YYYY-MM-DD HH:mm:ss") : ""; 69 | } 70 | }, 71 | dealAt: { 72 | type: DataTypes.DATE, 73 | allowNull: true, 74 | get() { 75 | return this.getDataValue("dealAt") ? moment(this.getDataValue("dealAt")).format("YYYY-MM-DD HH:mm:ss") : ""; 76 | } 77 | } 78 | }, { 79 | timestamps: false, 80 | freezeTableName: true 81 | }); 82 | }; 83 | -------------------------------------------------------------------------------- /modules/shopModel.js: -------------------------------------------------------------------------------- 1 | const db = require("../config/dbConnect"); 2 | const sequelize = db.sequelize; 3 | const Op = sequelize.Op; 4 | const shopSchema = sequelize.import("../schema/shopSchema"); 5 | const shopOptionRecordSchema = sequelize.import("../schema/shopOptionRecordSchema"); 6 | const hasEmpty = require("../utils/utils").hasEmpty; 7 | const getUncertainSqlObj = require("./../utils/utils").getUncertainSqlObj; 8 | 9 | class shopModel { 10 | /** 11 | * 12 | * 查询店铺信息 13 | * @static 14 | * @returns {Promise<*>} 15 | * @memberof shopModel 16 | */ 17 | static async getUserInfo() { 18 | return await shopSchema.findOne(); 19 | } 20 | 21 | /** 22 | * 修改数据 23 | * 24 | * @static 25 | * @param {Object} parmas 26 | * @returns 27 | * @memberof shopModel 28 | */ 29 | static async update(parmas) { 30 | return await shopSchema.update({ 31 | ...parmas 32 | }, { 33 | where: {} 34 | }); 35 | } 36 | 37 | /** 38 | * 查询店铺操作列表 分页 39 | * 40 | * @static 41 | * @memberof shopModel 42 | */ 43 | static async getOptionRecord(parmas) { 44 | let { 45 | pageSize, 46 | pageNumber, 47 | startTime, 48 | endTime, 49 | name, 50 | optionType 51 | } = parmas; 52 | let searchObj = getUncertainSqlObj({ 53 | optionType 54 | }); 55 | if (!hasEmpty(name)) { 56 | searchObj[Op.or] = [{ 57 | optionName: name 58 | }, { 59 | optionNickname: name 60 | }]; 61 | } 62 | let result = await shopOptionRecordSchema.findAndCountAll({ 63 | offset: pageSize * (pageNumber - 1), 64 | limit: pageSize, 65 | where: { 66 | createdAt: { 67 | [Op.gt]: startTime, 68 | [Op.lt]: endTime, 69 | }, 70 | ...searchObj 71 | }, 72 | order: [ 73 | ["id", "DESC"] 74 | ] 75 | }); 76 | return { 77 | pageSize, 78 | pageNumber, 79 | rows: result.rows, 80 | total: result.count 81 | }; 82 | } 83 | 84 | /** 85 | * 生成操作记录 86 | * 87 | * @static 88 | * @param {*} params 89 | * @memberof shopModel 90 | */ 91 | static async createOptionRecord(params) { 92 | shopOptionRecordSchema.create({ 93 | ...params 94 | }); 95 | } 96 | } 97 | 98 | module.exports = shopModel; -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | var createError = require("http-errors"); 2 | var express = require("express"); 3 | var path = require("path"); 4 | 5 | var sessionMiddleware = require("./config/sessionMiddleware"); 6 | const morgan = require("./config/morgan"); 7 | const resMsg = require("./utils/utils").resMsg; 8 | const logger = require("./config/log4j"); 9 | 10 | var indexRouter = require("./routes/index"); 11 | var usersRouter = require("./routes/user"); 12 | var bookRouter = require("./routes/book"); 13 | var adminRouter = require("./routes/admin"); 14 | var shopRouter = require("./routes/shop"); 15 | var orderRouter = require("./routes/order"); 16 | var apiRouter = require("./routes/api"); 17 | 18 | const noSessionUrl = ["/admin/login", "/admin/register", "/getPublicKey", "/getUserList", "/api/getOrder", "/api/orderNotify"]; 19 | 20 | var app = express(); 21 | 22 | var io = require("socket.io").listen(app.listen(3000)); 23 | io.sockets.use(function (socket, next) { 24 | sessionMiddleware(socket.request, socket.request.res, next); 25 | }); 26 | io.sockets.on("connection", (socket) => { 27 | console.log("\x1B[32m new socket.io connection successfully\x1B[0m"); 28 | }); 29 | app.io = io; 30 | 31 | app.set("views", path.join(__dirname, "views")); 32 | app.set("view engine", "jade"); 33 | app.use(morgan("live-api")); 34 | 35 | app.use(express.json()); 36 | app.use(express.urlencoded({ 37 | extended: false 38 | })); 39 | app.use(express.static(path.join(__dirname, "public"))); 40 | app.use(sessionMiddleware); 41 | 42 | app.use(function (req, res, next) { 43 | if (req.session.loginUser && typeof req.session.loginUser === "string") { 44 | next(); 45 | } else { 46 | let url = req.originalUrl; 47 | if (noSessionUrl.indexOf(url) !== -1) { 48 | next(); 49 | } else { 50 | res.status(401).json(resMsg(401)); 51 | } 52 | } 53 | }); 54 | app.use("/", indexRouter); 55 | app.use("/user", usersRouter); 56 | app.use("/book", bookRouter); 57 | app.use("/admin", adminRouter); 58 | app.use("/shop", shopRouter); 59 | app.use("/order", orderRouter); 60 | app.use("/api", apiRouter); 61 | 62 | //404 handler 63 | app.use(function (req, res, next) { 64 | res.status(404).json(resMsg(404)); 65 | }); 66 | 67 | // error handler 68 | app.use(function (err, req, res, next) { 69 | // set locals, only providing error in development 70 | res.locals.message = err.message; 71 | res.locals.error = req.app.get("env") === "development" ? err : {}; 72 | 73 | // render the error page 74 | res.status(err.status || 500).json(resMsg()); 75 | }); 76 | 77 | module.exports = app; 78 | -------------------------------------------------------------------------------- /controllers/apiController.js: -------------------------------------------------------------------------------- 1 | const logger = require("../config/log4j"); 2 | const resMsg = require("../utils/utils").resMsg; 3 | const shopOrderModel = require("../modules/shopOrderModel"); 4 | 5 | class apiController { 6 | /** 7 | * 对外获取新订单接口 8 | * 9 | * @static 10 | * @param {*} req 11 | * @param {*} res 12 | * @param {*} next 13 | */ 14 | static async getOrder(req, res, next) { 15 | try { 16 | let { 17 | orders, 18 | ...params 19 | } = req.body; 20 | let result = await shopOrderModel.createOrder(params); 21 | let subOrderArr = JSON.parse(orders); 22 | for (let i = 0, len = subOrderArr.length; i < len; i++) { 23 | subOrderArr[i].mainOrderId = result.id; 24 | } 25 | await shopOrderModel.createSubOrder(subOrderArr); 26 | for (let key of Object.keys(req.app.io.sockets.sockets)) { 27 | let socket = req.app.io.sockets.sockets[key]; 28 | let sessionID = socket.request.sessionID; 29 | socket.request.sessionStore.client.get(sessionID, function (err, result) { 30 | if (err) { 31 | logger.error(err); 32 | } else { 33 | if (result) { 34 | if (params.status === 1) { 35 | socket.emit("hasNewOrder", resMsg(200)); 36 | } else if (params.status === 6) { 37 | socket.emit("hasNewRefundOrder", resMsg(200)); 38 | } 39 | } else { 40 | socket.emit("err", resMsg(401)); 41 | socket.disconnect(true); 42 | } 43 | } 44 | }); 45 | } 46 | res.json(resMsg(200)); 47 | } catch (error) { 48 | logger.error(error); 49 | res.json(resMsg()); 50 | } 51 | } 52 | 53 | /** 54 | * orderNotify 55 | * 56 | * @static 57 | * @param {*} req 58 | * @param {*} res 59 | * @param {*} next 60 | */ 61 | static async orderNotify(req, res, next) { 62 | try { 63 | let {type} = req.body; 64 | for (let key of Object.keys(req.app.io.sockets.sockets)) { 65 | let socket = req.app.io.sockets.sockets[key]; 66 | // let sessionID = socket.request.sessionID; 67 | if (type === 1) { 68 | socket.emit("hasNewOrder", resMsg(200)); 69 | } else if (type === 6) { 70 | socket.emit("hasNewRefundOrder", resMsg(200)); 71 | } 72 | // 取消了 socket 鉴权,代码丢失,忘记怎么改的了 73 | // socket.request.sessionStore.client.get(sessionID, function (err, result) { 74 | // if (err) { 75 | // logger.error(err); 76 | // } else { 77 | // if (result) { 78 | // if (type === 1) { 79 | // socket.emit("hasNewOrder", resMsg(200)); 80 | // } else if (type === 6) { 81 | // socket.emit("hasNewRefundOrder", resMsg(200)); 82 | // } 83 | // } else { 84 | // socket.emit("err", resMsg(401)); 85 | // socket.disconnect(true); 86 | // } 87 | // } 88 | // }); 89 | } 90 | res.json(resMsg(200)); 91 | } catch (error) { 92 | logger.error(error); 93 | res.json(resMsg()); 94 | } 95 | } 96 | } 97 | 98 | module.exports = apiController; 99 | -------------------------------------------------------------------------------- /utils/utils.js: -------------------------------------------------------------------------------- 1 | const db = require("../config/dbConnect"); 2 | const sequelize = db.sequelize; 3 | const Op = sequelize.Op; 4 | const errorMsg = require("./errorMsg"); 5 | 6 | const ALLCHAR = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz"; // 去掉了容易混淆的字符 7 | const ALLNUM = "123456789"; 8 | 9 | // res返回数据 10 | let resMsg = function (errorCode = 9999, data = "") { 11 | return { 12 | errorCode, 13 | errorMsg: errorMsg[errorCode], 14 | data 15 | }; 16 | }; 17 | 18 | /** 19 | * 判断多个数值是否是有效值 20 | * 21 | * @param {*} params 22 | * @returns 23 | */ 24 | let hasEmpty = function (...params) { 25 | for (let i = 0, len = params.length; i < len; i++) { 26 | let val = params[i]; 27 | if (val === "" || val === undefined || val === null || (typeof val === "number") && isNaN(val)) { 28 | return true; 29 | } 30 | } 31 | return false; 32 | }; 33 | 34 | /** 35 | * 获取不为空的数值组成的sequelize WHERE 查询对象 36 | * 37 | * @param {Object} params 要拼接参数 38 | * @returns {Object} 39 | */ 40 | let getUncertainSqlObj = function (params) { 41 | let obj = {}; 42 | for (key in params) { 43 | let val = params[key]; 44 | if (!hasEmpty(val)) { 45 | obj[key] = val; 46 | } 47 | } 48 | return obj; 49 | }; 50 | 51 | /** 52 | * 获取不为空的数值组成的sequelize WHERE LIKE 查询对象 53 | * 54 | * @param {Object} params 需要LIKE的参数 55 | * @returns {Object} 56 | */ 57 | let getUncertainLikeSqlObj = function (params) { 58 | let obj = {}; 59 | for (key in params) { 60 | let val = params[key]; 61 | if (!hasEmpty(val)) { 62 | obj[key] = {}; 63 | obj[key][Op.like] = `%${val}%`; 64 | } 65 | } 66 | return obj; 67 | }; 68 | 69 | let getRandomPwd = function () { 70 | return getRandomStr(6) + getRandomStrNum(4); 71 | }; 72 | 73 | let getRandomStr = function (len) { 74 | let str = ""; 75 | let maxLength = ALLCHAR.length; 76 | for (i = 0; i < len; i++) { 77 | str += ALLCHAR.charAt(Math.floor(Math.random() * maxLength)); 78 | } 79 | return str; 80 | }; 81 | 82 | let getRandomStrNum = function (len) { 83 | let str = ""; 84 | let maxLength = ALLNUM.length; 85 | for (i = 0; i < len; i++) { 86 | str += ALLNUM.charAt(Math.floor(Math.random() * maxLength)); 87 | } 88 | return str; 89 | }; 90 | 91 | /** 92 | * 获取 yyyyMMddHHmmss 时间 93 | * 94 | * @memberof autoCreateOrder 95 | */ 96 | let getDataStr = function () { 97 | let date = new Date(); 98 | let year = date.getFullYear(); 99 | let month = date.getMonth(); 100 | let day = padLeft(2, date.getDate()); 101 | let hour = padLeft(2, date.getHours()); 102 | let minute = padLeft(2, date.getMinutes()); 103 | let second = padLeft(2, date.getSeconds()); 104 | return `${year}${month}${day}${hour}${minute}${second}`; 105 | }; 106 | 107 | /** 108 | * 左补全 109 | * @param len 110 | * @param num 111 | * @returns {string} 112 | */ 113 | let padLeft = function (len, num) { 114 | return new Array(len - (num + "").length + 1).join("0") + num; 115 | }; 116 | 117 | /** 118 | * 获取退款流水号 119 | * @param userId 用户id 120 | * @returns {string} 121 | */ 122 | let getRefundOrderId = function (userId) { 123 | let str = "T"; 124 | str += padLeft(9, userId); 125 | str += getDataStr(); 126 | return str; 127 | }; 128 | 129 | /** 130 | * 生成随机数 131 | * 132 | * @param {Number} lower 最小值 133 | * @param {Number} upper 最大值 134 | * @returns 135 | * @memberof autoCreateOrder 136 | */ 137 | let getRandom = function(lower, upper) { 138 | return Math.floor(Math.random() * (upper - lower)) + lower; 139 | }; 140 | 141 | const mobileReg = /^1[3456789]\d{9}$/; 142 | const pwdReg = /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,16}$/; 143 | const numReg = /^[0-9]+$/; 144 | 145 | module.exports = { 146 | resMsg, 147 | hasEmpty, 148 | getUncertainSqlObj, 149 | getUncertainLikeSqlObj, 150 | mobileReg, 151 | pwdReg, 152 | numReg, 153 | getRandom, 154 | getRandomPwd, 155 | getRefundOrderId 156 | }; -------------------------------------------------------------------------------- /controllers/shopUserController.js: -------------------------------------------------------------------------------- 1 | const logger = require("../config/log4j"); 2 | const resMsg = require("../utils/utils").resMsg; 3 | const hasEmpty = require("../utils/utils").hasEmpty; 4 | const getRandomPwd = require("../utils/utils").getRandomPwd; 5 | const shopUserModel = require("../modules/shopUserModel"); 6 | const crypto = require("crypto"); 7 | 8 | class shopUserController { 9 | /** 10 | * 获取店铺用户信息 11 | * 12 | * @static 13 | * @param {*} req 14 | * @param {*} res 15 | * @param {*} next 16 | * @memberof shopUserController 17 | */ 18 | static async getShopUserInfo(req, res, next) { 19 | try { 20 | if (hasEmpty(req.body.pageSize, req.body.pageNumber)) { 21 | res.json(resMsg(9001)); 22 | return false; 23 | } 24 | let result = await shopUserModel.getShopUserInfo(req.body); 25 | res.json(resMsg(200, result)); 26 | } catch (error) { 27 | logger.error(error); 28 | res.json(resMsg()); 29 | } 30 | } 31 | 32 | /** 33 | * 查询用户收货地址 34 | * 35 | * @static 36 | * @param {*} req 37 | * @param {*} res 38 | * @param {*} next 39 | * @returns 40 | * @memberof shopUserController 41 | */ 42 | static async getUserDeliveryAddress(req, res, next) { 43 | try { 44 | if (hasEmpty(req.body.userId)) { 45 | res.json(resMsg(9001)); 46 | return false; 47 | } 48 | let result = await shopUserModel.getUserDeliveryAddress(req.body.userId); 49 | res.json(resMsg(200, result)); 50 | } catch (error) { 51 | logger.error(error); 52 | res.json(resMsg()); 53 | } 54 | } 55 | 56 | /** 57 | * 根据id获取收货地址信息 58 | * 59 | * @static 60 | * @param {*} req 61 | * @param {*} res 62 | * @param {*} next 63 | * @memberof shopUserController 64 | */ 65 | static async getOrderAddressById(req, res, next) { 66 | try { 67 | if (hasEmpty(req.body.id)) { 68 | res.json(resMsg(9001)); 69 | return false; 70 | } 71 | let result = await shopUserModel.getOrderAddressById(req.body.id); 72 | res.json(resMsg(200, result[0])); 73 | } catch (error) { 74 | logger.error(error); 75 | res.json(resMsg()); 76 | } 77 | } 78 | 79 | /** 80 | * 更新账号状态 81 | * 82 | * @static 83 | * @param {*} req 84 | * @param {*} res 85 | * @param {*} next 86 | * @memberof shopUserController 87 | */ 88 | static async changeUserStatus(req, res, next) { 89 | try { 90 | if (hasEmpty(req.body.id, req.body.status) || (req.body.status != 0 && req.body.status != 1)) { 91 | res.json(resMsg(9001)); 92 | return false; 93 | } 94 | await shopUserModel.update({ 95 | id: req.body.id, 96 | status: req.body.status 97 | }); 98 | res.json(resMsg(200)); 99 | } catch (error) { 100 | logger.error(error); 101 | res.json(resMsg()); 102 | } 103 | } 104 | 105 | /** 106 | * 重置用户密码 返回随机生成的密码 107 | * 108 | * @static 109 | * @param {*} req 110 | * @param {*} res 111 | * @param {*} next 112 | * @memberof shopUserController 113 | */ 114 | static async resetUserPwd(req, res, next) { 115 | try { 116 | if (hasEmpty(req.body.id)) { 117 | res.json(resMsg(9001)); 118 | return false; 119 | } 120 | let ranPwd = getRandomPwd(); 121 | let hash = crypto.createHash("md5"); 122 | hash.update(ranPwd); 123 | let hashPwd = hash.digest("hex"); 124 | await shopUserModel.update({ 125 | id: req.body.id, 126 | pwd: hashPwd 127 | }); 128 | let buffer = new Buffer.from(ranPwd); 129 | res.json(resMsg(200, { 130 | newPwd: buffer.toString("base64") 131 | })); 132 | } catch (error) { 133 | logger.error(error); 134 | res.json(resMsg()); 135 | } 136 | } 137 | } 138 | 139 | module.exports = shopUserController; 140 | -------------------------------------------------------------------------------- /modules/bookListModel.js: -------------------------------------------------------------------------------- 1 | const db = require("../config/dbConnect"); 2 | const sequelize = db.sequelize; 3 | const Op = sequelize.Op; 4 | const bookListSchema = sequelize.import("../schema/bookListSchema"); 5 | const classifySchema = sequelize.import("../schema/classifySchema"); 6 | const getUncertainLikeSqlObj = require("../utils/utils").getUncertainLikeSqlObj; 7 | 8 | class bookListModel { 9 | /** 10 | * 查询图书列表 11 | * 12 | * @static 13 | * @param {*} parmas 14 | * @returns 15 | * @memberof bookListModel 16 | */ 17 | static async getBookList(parmas) { 18 | let { 19 | pageSize, 20 | pageNumber, 21 | startTime, 22 | endTime, 23 | name, 24 | author, 25 | press 26 | } = parmas; 27 | let likeObj = getUncertainLikeSqlObj({ 28 | name, 29 | author, 30 | press 31 | }); 32 | 33 | let result = await bookListSchema.findAndCountAll({ 34 | offset: pageSize * (pageNumber - 1), 35 | limit: pageSize, 36 | where: { 37 | status: 0, 38 | createdAt: { 39 | [Op.gt]: startTime, 40 | [Op.lt]: endTime, 41 | }, 42 | ...likeObj 43 | }, 44 | order: [ 45 | ["id", "DESC"] 46 | ] 47 | }); 48 | return { 49 | pageSize, 50 | pageNumber, 51 | rows: result.rows, 52 | total: result.count 53 | }; 54 | } 55 | 56 | /** 57 | * 删除列表中的图书 58 | * 59 | * @static 60 | * @param {*} ids 图书id 逗号间隔 61 | * @returns 62 | * @memberof bookListModel 63 | */ 64 | static async deleteBooks(ids) { 65 | return await bookListSchema.update({ 66 | status: 1 67 | }, { 68 | where: { 69 | id: { 70 | [Op.in]: ids.split(",") 71 | } 72 | } 73 | }); 74 | } 75 | 76 | /** 77 | * 更新图书 78 | * 79 | * @static 80 | * @param {*} param 81 | * @returns 82 | * @memberof bookListModel 83 | */ 84 | static async updateBook(param) { 85 | let { 86 | id, 87 | stock, 88 | ...updateData 89 | } = param; 90 | let str = ""; 91 | if (stock == undefined) { 92 | str = `+0`; 93 | } else { 94 | str = stock >= 0 ? `+${stock}` : `${stock}`; 95 | } 96 | return await bookListSchema.update({ 97 | stock: sequelize.literal("`stock` " + str), 98 | updatedAt: new Date(), 99 | ...updateData 100 | }, { 101 | where: { 102 | id 103 | } 104 | }); 105 | } 106 | 107 | /** 108 | * 批量插入图书 109 | * 110 | * @static 111 | * @param {Array} bookArr 112 | * @memberof bookListModel 113 | */ 114 | static async insertBook(bookArr) { 115 | return await bookListSchema.bulkCreate(bookArr); 116 | } 117 | 118 | /** 119 | * 120 | * 查询所有图书分类 121 | * @static 122 | * @returns {Promise<*>} 123 | * @memberof bookListModel 124 | */ 125 | static async getAllClassify() { 126 | return await classifySchema.findAll(); 127 | } 128 | 129 | /** 130 | * 131 | * 删除图书分类 132 | * @static 133 | * @param {*} id 分类id 134 | * @returns {Promise<*>} 135 | * @memberof bookListModel 136 | */ 137 | static async deleteClassify(id) { 138 | await classifySchema.destroy({ 139 | where: { 140 | id 141 | } 142 | }); 143 | return await sequelize.query(`UPDATE \`shop_book_list\` SET \`classify\`=TRIM(BOTH ',' FROM replace(concat(',',\`classify\`,','), ',${id},', '')) WHERE FIND_IN_SET('${id}',classify)`); 144 | } 145 | 146 | 147 | /** 148 | * 添加分类 149 | * 150 | * @static 151 | * @param {string} classifyName 分类名 152 | * @returns 153 | * @memberof bookListModel 154 | */ 155 | static async addClassify(classifyName) { 156 | return await classifySchema.create({ 157 | name: classifyName 158 | }); 159 | } 160 | 161 | /** 162 | * 批量修改上下架 163 | * 164 | * @static 165 | * @param {*} isSell 上下架 166 | * @param {*} ids 逗号分隔 ids 167 | * @memberof bookListModel 168 | */ 169 | static async changeBookSellStatus(isSell, ids) { 170 | return await bookListSchema.update({ 171 | isSell 172 | }, { 173 | where: { 174 | id: { 175 | [Op.in]: ids.split(",") 176 | } 177 | } 178 | }); 179 | } 180 | } 181 | 182 | module.exports = bookListModel; -------------------------------------------------------------------------------- /controllers/shopController.js: -------------------------------------------------------------------------------- 1 | const logger = require("../config/log4j"); 2 | const resMsg = require("../utils/utils").resMsg; 3 | const hasEmpty = require("../utils/utils").hasEmpty; 4 | const shopModel = require("../modules/shopModel"); 5 | const adminUserModel = require("../modules/adminUserModel"); 6 | 7 | class shopController { 8 | /** 9 | * 获取店铺信息 10 | * 11 | * @static 12 | * @param {*} req 13 | * @param {*} res 14 | * @param {*} next 15 | * @memberof shopController 16 | */ 17 | static async getShopInfo(req, res, next) { 18 | try { 19 | let result = await shopModel.getUserInfo(); 20 | res.json(resMsg(200, result)); 21 | } catch (error) { 22 | logger.error(error); 23 | res.json(resMsg()); 24 | } 25 | } 26 | 27 | /** 28 | * 更新店铺名 29 | * 30 | * @static 31 | * @param {*} req 32 | * @param {*} res 33 | * @param {*} next 34 | * @memberof shopController 35 | */ 36 | static async updateShopName(req, res, next) { 37 | try { 38 | let shopName = req.body.shopName; 39 | let remark = req.body.remark; 40 | if (hasEmpty(shopName, remark)) { 41 | res.json(resMsg(9001)); 42 | return false; 43 | } 44 | let result = await adminUserModel.getUserInfo(req.session.loginUser); 45 | let { 46 | name, 47 | nickname 48 | } = result; 49 | await shopModel.update({ 50 | shopName 51 | }); 52 | await shopModel.createOptionRecord({ 53 | optionName: name, 54 | optionNickname: nickname, 55 | type: 0, 56 | remark 57 | }); 58 | res.json(resMsg(200)); 59 | } catch (error) { 60 | logger.error(error); 61 | res.json(resMsg()); 62 | } 63 | } 64 | 65 | /** 66 | * 更改店铺状态 67 | * 68 | * @static 69 | * @param {*} req 70 | * @param {*} res 71 | * @param {*} next 72 | * @memberof shopController 73 | */ 74 | static async changeShopStatus(req, res, next) { 75 | try { 76 | let status = req.body.status; 77 | let remark = req.body.remark; 78 | if (hasEmpty(status, remark)) { 79 | res.json(resMsg(9001)); 80 | return false; 81 | } 82 | let result = await adminUserModel.getUserInfo(req.session.loginUser); 83 | let { 84 | name, 85 | nickname 86 | } = result; 87 | await shopModel.update({ 88 | status 89 | }); 90 | await shopModel.createOptionRecord({ 91 | optionName: name, 92 | optionNickname: nickname, 93 | type: 1, 94 | remark 95 | }); 96 | res.json(resMsg(200)); 97 | } catch (error) { 98 | logger.error(error); 99 | res.json(resMsg()); 100 | } 101 | } 102 | 103 | /** 104 | * 更改店铺描述 105 | * 106 | * @static 107 | * @param {*} req 108 | * @param {*} res 109 | * @param {*} next 110 | * @memberof shopController 111 | */ 112 | static async updateShopDescription(req, res, next) { 113 | try { 114 | let description = req.body.description; 115 | let remark = req.body.remark; 116 | if (hasEmpty(description, remark)) { 117 | res.json(resMsg(9001)); 118 | return false; 119 | } 120 | let result = await adminUserModel.getUserInfo(req.session.loginUser); 121 | let { 122 | name, 123 | nickname 124 | } = result; 125 | await shopModel.update({ 126 | description 127 | }); 128 | await shopModel.createOptionRecord({ 129 | optionName: name, 130 | optionNickname: nickname, 131 | type: 2, 132 | remark 133 | }); 134 | res.json(resMsg(200)); 135 | } catch (error) { 136 | logger.error(error); 137 | res.json(resMsg()); 138 | } 139 | } 140 | 141 | /** 142 | * 分页查询店铺操作日志 143 | * 144 | * @static 145 | * @memberof shopController 146 | */ 147 | static async getOptionRecord(req, res, next) { 148 | try { 149 | if (hasEmpty(req.body.pageSize, req.body.pageNumber, req.body.startTime, req.body.endTime)) { 150 | res.json(resMsg(9001)); 151 | return false; 152 | } 153 | let result = await shopModel.getOptionRecord(req.body); 154 | res.json(resMsg(200, result)); 155 | } catch (error) { 156 | logger.error(error); 157 | res.json(resMsg()); 158 | } 159 | } 160 | } 161 | 162 | module.exports = shopController; -------------------------------------------------------------------------------- /modules/shopUserModel.js: -------------------------------------------------------------------------------- 1 | const db = require("../config/dbConnect"); 2 | const sequelize = db.sequelize; 3 | const Op = sequelize.Op; 4 | const shopUserSchema = sequelize.import("../schema/shopUserSchema"); 5 | const provinceSchema = sequelize.import("../schema/provinceSchema"); 6 | const citySchema = sequelize.import("../schema/citySchema"); 7 | const countrySchema = sequelize.import("../schema/countrySchema"); 8 | const shopUserDeliveryAddressSchema = sequelize.import("../schema/shopUserDeliveryAddressSchema"); 9 | const hasEmpty = require("../utils/utils").hasEmpty; 10 | const getUncertainSqlObj = require("./../utils/utils").getUncertainSqlObj; 11 | 12 | class shopModel { 13 | /** 14 | * 15 | * 查询店铺用户信息 16 | * @static 17 | * @returns {Promise<*>} 18 | * @memberof shopModel 19 | */ 20 | static async getShopUserInfo(parmas) { 21 | let { 22 | pageSize, 23 | pageNumber, 24 | startTime, 25 | endTime, 26 | name, 27 | status, 28 | sex 29 | } = parmas; 30 | let searchObj = getUncertainSqlObj({ 31 | status, 32 | sex 33 | }); 34 | if (!hasEmpty(name)) { 35 | searchObj[Op.or] = [{ 36 | name: name 37 | }, { 38 | nickname: name 39 | }]; 40 | } 41 | let createdAt = {}; 42 | if (!hasEmpty(startTime)) { 43 | createdAt[Op.gt] = startTime; 44 | } 45 | if (!hasEmpty(endTime)) { 46 | createdAt[Op.lt] = endTime; 47 | } 48 | // symbols keys 不能判断 49 | if (Object.getOwnPropertySymbols(createdAt).length) { 50 | searchObj.createdAt = createdAt; 51 | } 52 | let result = await shopUserSchema.findAndCountAll({ 53 | offset: pageSize * (pageNumber - 1), 54 | limit: pageSize, 55 | where: { 56 | ...searchObj 57 | }, 58 | order: [ 59 | ["id", "DESC"] 60 | ] 61 | }); 62 | return { 63 | pageSize, 64 | pageNumber, 65 | rows: result.rows, 66 | total: result.count 67 | }; 68 | } 69 | 70 | /** 71 | * 查询用户收货地址 72 | * 73 | * @static 74 | * @param {int} useId 用户id 75 | * @memberof shopModel 76 | */ 77 | static async getUserDeliveryAddress(userId) { 78 | shopUserDeliveryAddressSchema.belongsTo(provinceSchema, { 79 | foreignKey: "provinceId", 80 | targetKey: "provinceId" 81 | }); 82 | shopUserDeliveryAddressSchema.belongsTo(citySchema, { 83 | foreignKey: "cityId", 84 | targetKey: "cityId" 85 | }); 86 | shopUserDeliveryAddressSchema.belongsTo(countrySchema, { 87 | foreignKey: "countryId", 88 | targetKey: "countryId" 89 | }); 90 | return await shopUserDeliveryAddressSchema.findAll({ 91 | attributes: { 92 | include: [ 93 | [sequelize.col("shop_delivery_province.name"), "provinceName"], 94 | [sequelize.col("shop_delivery_city.name"), "cityName"], 95 | [sequelize.col("shop_delivery_country.name"), "countryName"] 96 | ] 97 | }, 98 | include: [{ 99 | model: provinceSchema, 100 | attributes: [] 101 | }, { 102 | model: citySchema, 103 | attributes: [] 104 | }, { 105 | model: countrySchema, 106 | attributes: [] 107 | }], 108 | where: { 109 | userId 110 | } 111 | }); 112 | } 113 | 114 | /** 115 | * 根据id查询收货地址信息 116 | * 117 | * @static 118 | * @param {*} id 119 | * @memberof shopModel 120 | */ 121 | static async getOrderAddressById(id) { 122 | shopUserDeliveryAddressSchema.belongsTo(provinceSchema, { 123 | foreignKey: "provinceId", 124 | targetKey: "provinceId" 125 | }); 126 | shopUserDeliveryAddressSchema.belongsTo(citySchema, { 127 | foreignKey: "cityId", 128 | targetKey: "cityId" 129 | }); 130 | shopUserDeliveryAddressSchema.belongsTo(countrySchema, { 131 | foreignKey: "countryId", 132 | targetKey: "countryId" 133 | }); 134 | return await shopUserDeliveryAddressSchema.findAll({ 135 | attributes: { 136 | include: [ 137 | [sequelize.col("shop_delivery_province.name"), "provinceName"], 138 | [sequelize.col("shop_delivery_city.name"), "cityName"], 139 | [sequelize.col("shop_delivery_country.name"), "countryName"] 140 | ] 141 | }, 142 | include: [{ 143 | model: provinceSchema, 144 | attributes: [] 145 | }, { 146 | model: citySchema, 147 | attributes: [] 148 | }, { 149 | model: countrySchema, 150 | attributes: [] 151 | }], 152 | where: { 153 | id 154 | }, 155 | raw: true 156 | }); 157 | } 158 | 159 | /** 160 | * 更新 161 | * 162 | * @static 163 | * @param {obj} id 用户id 164 | * @returns 165 | * @memberof shopModel 166 | */ 167 | static async update(parmas) { 168 | let { 169 | id, 170 | ...updateData 171 | } = parmas; 172 | return await shopUserSchema.update({ 173 | ...updateData 174 | }, { 175 | where: { 176 | id 177 | } 178 | }); 179 | } 180 | 181 | 182 | } 183 | 184 | module.exports = shopModel; 185 | -------------------------------------------------------------------------------- /autoCreateOrder.js: -------------------------------------------------------------------------------- 1 | var mysql = require("mysql"); 2 | var axios = require("axios"); 3 | var Decimal = require("decimal.js"); 4 | var connection = mysql.createConnection({ 5 | host: "localhost", 6 | user: "root", 7 | password: "", 8 | database: "shop_store_management" 9 | }); 10 | connection.connect(); 11 | 12 | axios.defaults.baseURL = "http://127.0.0.1:3000"; 13 | 14 | class autoCreateOrder { 15 | constructor(option) { 16 | this.orderInfo = { 17 | orderId: "", 18 | userId: "", 19 | userName: "", 20 | status: "", 21 | orderNum: "", 22 | orderMoney: "", 23 | deliveryMoney: "", 24 | totalMoney: "", 25 | deliveryId: null, 26 | deliveryOrderId: null, 27 | deliveryAddressId: "", 28 | orders: "" 29 | }; 30 | setInterval(() => { 31 | this.init(); 32 | }, option.time); 33 | } 34 | 35 | /** 36 | * 初始化 37 | * 38 | * @memberof autoCreateOrder 39 | */ 40 | async init() { 41 | this.orderInfo = { 42 | orderId: "", 43 | userId: "", 44 | userName: "", 45 | status: "", 46 | orderNum: "", 47 | orderMoney: "", 48 | deliveryMoney: "", 49 | totalMoney: "", 50 | deliveryId: null, 51 | deliveryOrderId: null, 52 | deliveryAddressId: "", 53 | orders: "" 54 | }; 55 | await this.getUserInfo(); 56 | this.getStatus(); 57 | await this.getOrderMoney(); 58 | await this.getDeliveryInfo(); 59 | this.sendHttp(); 60 | } 61 | 62 | /** 63 | * 获取 userId userName orderId 64 | * 65 | * @memberof autoCreateOrder 66 | */ 67 | async getUserInfo() { 68 | let sql = "select * from shop_user_list"; 69 | let result = await this.connectionQuery(sql); 70 | let val = result[autoCreateOrder.getRandom(0, result.length - 1)]; 71 | this.orderInfo.userId = val.id; 72 | this.orderInfo.userName = val.name; 73 | let str = "D"; 74 | str += autoCreateOrder.padLeft(9, val.id); 75 | str += autoCreateOrder.getDataStr(); 76 | this.orderInfo.orderId = str; 77 | } 78 | 79 | /** 80 | * 获取 status 81 | * 82 | * @memberof autoCreateOrder 83 | */ 84 | getStatus() { 85 | this.orderInfo.status = autoCreateOrder.getRandom(0, 10) > 8 ? 6 : 1; 86 | } 87 | 88 | /** 89 | * 获取 orderNum orderMoney deliveryMoney totalMoney 90 | * 91 | * @memberof autoCreateOrder 92 | */ 93 | async getOrderMoney() { 94 | this.orderInfo.orderNum = autoCreateOrder.getRandom(1, 5); 95 | let orderMoney = 0; 96 | let orders = []; 97 | let deliveryMoney = autoCreateOrder.getRandom(0, 6); 98 | let sql = "select * from shop_book_list"; 99 | let bookData = await this.connectionQuery(sql); 100 | for (let i = 0; i < this.orderInfo.orderNum; i++) { 101 | let subOrder = {}; 102 | let val = bookData[autoCreateOrder.getRandom(0, bookData.length - 1)]; 103 | subOrder.bookId = val.id; 104 | subOrder.bookName = val.name; 105 | subOrder.bookTitle = val.title; 106 | subOrder.bookNum = autoCreateOrder.getRandom(1, 6); 107 | subOrder.bookPrice = val.price; 108 | subOrder.bookSalePrice = val.salePrice; 109 | subOrder.bookImageUrl = val.imageUrl; 110 | orderMoney = new Decimal(orderMoney).add(new Decimal(val.salePrice).mul(new Decimal(subOrder.bookNum))).toNumber(); 111 | orders.push(subOrder); 112 | } 113 | this.orderInfo.orderMoney = orderMoney; 114 | this.orderInfo.deliveryMoney = deliveryMoney; 115 | this.orderInfo.totalMoney = new Decimal(orderMoney).add(new Decimal(deliveryMoney)).toNumber(); 116 | this.orderInfo.orders = JSON.stringify(orders); 117 | } 118 | 119 | /** 120 | * 获取物流信息 121 | * 122 | * @memberof autoCreateOrder 123 | */ 124 | async getDeliveryInfo() { 125 | if (this.orderInfo.status === 6) { 126 | let sql = "select * from shop_delivery_company"; 127 | let deliveryCompany = await this.connectionQuery(sql); 128 | this.orderInfo.deliveryId = deliveryCompany[autoCreateOrder.getRandom(0, deliveryCompany.length - 1)].id; 129 | this.orderInfo.deliveryOrderId = autoCreateOrder.getRandomNumStr(11); 130 | this.orderInfo.deliveryAt = new Date(); 131 | } 132 | let sql = "select * from shop_user_delivery where userId=?"; 133 | let sqlParams = [this.orderInfo.userId]; 134 | let deliveryAddress = await this.connectionQuery(sql, sqlParams); 135 | this.orderInfo.deliveryAddressId = deliveryAddress[autoCreateOrder.getRandom(0, deliveryAddress.length - 1)].id; 136 | } 137 | 138 | /** 139 | * 生成随机数 140 | * 141 | * @param {Number} lower 最小值 142 | * @param {Number} upper 最大值 143 | * @returns 144 | * @memberof autoCreateOrder 145 | */ 146 | static getRandom(lower, upper) { 147 | return Math.floor(Math.random() * (upper - lower)) + lower; 148 | } 149 | 150 | /** 151 | * 生成随机数字字段 152 | * 153 | * @param {String} len 长度 154 | * @returns 155 | * @memberof autoCreateOrder 156 | */ 157 | static getRandomNumStr(len) { 158 | let str = ""; 159 | for (let i = 0; i < len; i++) { 160 | str += autoCreateOrder.getRandom(0, 9); 161 | } 162 | return str; 163 | } 164 | 165 | /** 166 | * 获取 yyyyMMddHHmmss 时间 167 | * 168 | * @memberof autoCreateOrder 169 | */ 170 | static getDataStr() { 171 | let date = new Date(); 172 | let year = date.getFullYear(); 173 | let month = date.getMonth(); 174 | let day = autoCreateOrder.padLeft(2, date.getDate()); 175 | let hour = autoCreateOrder.padLeft(2, date.getHours()); 176 | let minute = autoCreateOrder.padLeft(2, date.getMinutes()); 177 | let second = autoCreateOrder.padLeft(2, date.getSeconds()); 178 | return `${year}${month}${day}${hour}${minute}${second}`; 179 | } 180 | 181 | /** 182 | * 数字补0 183 | * 184 | * @param {Number} len 补0长度 185 | * @param {Number} num 需要补0的字段 186 | * @returns 187 | * @memberof autoCreateOrder 188 | */ 189 | static padLeft(len, num) { 190 | return new Array(len - (num + "").length + 1).join("0") + num; 191 | } 192 | 193 | sendHttp() { 194 | axios.post("/api/getOrder", this.orderInfo) 195 | .then(res => { 196 | console.log(res.data); 197 | }) 198 | .catch(err => { 199 | console.log(err); 200 | }); 201 | } 202 | 203 | /** 204 | * 数据库 Promise 205 | * 206 | * @param {*} sql 207 | * @param {*} sqlParams 208 | * @returns Promise 209 | * @memberof autoCreateOrder 210 | */ 211 | connectionQuery(sql, sqlParams) { 212 | return new Promise((resolve, reject) => { 213 | connection.query(sql, sqlParams, function (err, result) { 214 | if (err) { 215 | reject(err); 216 | } 217 | resolve(result); 218 | }); 219 | }); 220 | } 221 | } 222 | 223 | let option = { 224 | time: 1000 * 1 225 | }; 226 | 227 | new autoCreateOrder(option); -------------------------------------------------------------------------------- /controllers/adminUserController.js: -------------------------------------------------------------------------------- 1 | const formidable = require("formidable"); 2 | const fs = require("fs"); 3 | const path = require("path"); 4 | const rsaKey = require("../config/rsa"); 5 | const logger = require("../config/log4j"); 6 | const resMsg = require("../utils/utils").resMsg; 7 | const hasEmpty = require("../utils/utils").hasEmpty; 8 | const mobileReg = require("../utils/utils").mobileReg; 9 | const uploadConfig = require("./../config/uploadConfig"); 10 | const adminUserModel = require("../modules/adminUserModel"); 11 | 12 | class adminUserController { 13 | /** 14 | * 管理员登录 15 | * 16 | * @static 17 | * @param {*} req 18 | * @param {*} res 19 | * @param {*} next 20 | * @returns 21 | * @memberof adminUserController 22 | */ 23 | static async login(req, res, next) { 24 | try { 25 | let name = req.body.name; 26 | let pwd = decodeURI(req.body.pwd); 27 | let decryptPwd = rsaKey.decrypt(pwd, "utf8"); // 私钥解密密码 28 | if (hasEmpty(name, decryptPwd)) { 29 | res.json(resMsg(9001)); 30 | return false; 31 | } else { 32 | let result = await adminUserModel.getUserInfo(name); // 更加用户名获取用户信息 33 | if (result === null) { 34 | res.json(resMsg(1001)); // 无此用户 35 | return false; 36 | } 37 | if (decryptPwd === result.pwd) { // 判断密码是否正确 38 | req.session.loginUser = result.name; // 登录成功后设置成功标识 39 | req.session.loginId = result.id; 40 | res.json(resMsg(200)); 41 | } else { 42 | res.json(resMsg(1002)); // 密码错误 43 | } 44 | } 45 | } catch (error) { 46 | logger.error(error); 47 | res.json(resMsg()); 48 | } 49 | } 50 | 51 | /** 52 | * 管理员注册 53 | * 54 | * @static 55 | * @param {*} req 56 | * @param {*} res 57 | * @param {*} next 58 | * @returns 59 | * @memberof adminUserController 60 | */ 61 | static async register(req, res, next) { 62 | try { 63 | let name = req.body.name; 64 | let nickname = req.body.nickname; 65 | let pwd = decodeURI(req.body.pwd); 66 | let repPwd = decodeURI(req.body.repPwd); 67 | let decryptPwd = rsaKey.decrypt(pwd, "utf8"); 68 | let decryptRepPwd = rsaKey.decrypt(repPwd, "utf8"); 69 | if (hasEmpty(name, decryptPwd, decryptRepPwd, nickname) || !mobileReg.test(name) || nickname.length > 20) { 70 | res.json(resMsg(9001)); 71 | return false; 72 | } else { 73 | if (decryptRepPwd !== decryptPwd) { 74 | res.json(resMsg(1004)); 75 | return false; 76 | } 77 | let result = await adminUserModel.getUserInfo(name); 78 | if (result !== null) { 79 | res.json(resMsg(1003)); 80 | return false; 81 | } 82 | await adminUserModel.create({ 83 | nickname: nickname, 84 | name: name, 85 | pwd: decryptPwd 86 | }); 87 | res.json(resMsg(200)); 88 | } 89 | } catch (error) { 90 | logger.error(error); 91 | res.json(resMsg()); 92 | } 93 | } 94 | 95 | /** 96 | * 退出登录 97 | * 98 | * @static 99 | * @param {*} req 100 | * @param {*} res 101 | * @param {*} next 102 | * @memberof adminUserController 103 | */ 104 | static async logout(req, res, next) { 105 | req.session.destroy(); 106 | res.json(resMsg(200)); 107 | } 108 | 109 | /** 110 | * 更新昵称 111 | * 112 | * @static 113 | * @param {*} res 114 | * @param {*} res 115 | * @param {*} next 116 | * @memberof adminUserController 117 | */ 118 | static async updateNickname(req, res, next) { 119 | try { 120 | let { 121 | nickname 122 | } = req.body; 123 | if (hasEmpty(nickname) || nickname.length > 20) { 124 | nickname = ""; 125 | } 126 | await adminUserModel.update({ 127 | nickname 128 | }, req.session.loginUser); 129 | res.json(resMsg(200)); 130 | } catch (error) { 131 | logger.error(error); 132 | res.json(resMsg()); 133 | } 134 | } 135 | 136 | /** 137 | * 更改密码 138 | * 139 | * @static 140 | * @param {*} req 141 | * @param {*} res 142 | * @param {*} next 143 | * @memberof adminUserController 144 | */ 145 | static async updatePassword(req, res, next) { 146 | try { 147 | let pwd = decodeURI(req.body.pwd); 148 | let newPwd = decodeURI(req.body.newPwd); 149 | let repNewPwd = decodeURI(req.body.repNewPwd); 150 | let decryptPwd = rsaKey.decrypt(pwd, "utf8"); 151 | let decryptNewPwd = rsaKey.decrypt(newPwd, "utf8"); 152 | let decryptRepNewPwd = rsaKey.decrypt(repNewPwd, "utf8"); 153 | if (hasEmpty(decryptPwd, decryptNewPwd, decryptRepNewPwd)) { 154 | res.json(resMsg(9001)); 155 | return false; 156 | } 157 | if (decryptNewPwd !== decryptRepNewPwd) { 158 | res.json(resMsg(1004)); 159 | return false; 160 | } 161 | let result = await adminUserModel.getUserInfo(req.session.loginUser); 162 | if (result.pwd === decryptPwd) { 163 | await adminUserModel.update({ 164 | pwd: decryptNewPwd 165 | }, req.session.loginUser); 166 | req.session.destroy(); 167 | res.json(resMsg(200)); 168 | } else { 169 | logger.error("原密码错误"); 170 | res.json(resMsg(1005)); 171 | } 172 | } catch (error) { 173 | logger.error(error); 174 | } 175 | } 176 | 177 | /** 178 | * 更新头像 179 | * 180 | * @static 181 | * @param {*} req 182 | * @param {*} res 183 | * @param {*} next 184 | * @memberof adminUserController 185 | */ 186 | static async updateAvatar(req, res, next) { 187 | let form = new formidable.IncomingForm(); 188 | form.encoding = uploadConfig.ENCODING; 189 | form.uploadDir = uploadConfig.SERVER_DIR + uploadConfig.ADMIN_AVATAR_URL; 190 | form.keepExtensions = uploadConfig.KEEP_EXTENSIONS; 191 | form.maxFileSize = uploadConfig.MAX_FILESIZE; 192 | form.parse(req, async (error, fields, files) => { 193 | if (error) { 194 | logger.error(error); 195 | res.json(resMsg()); 196 | return false; 197 | } 198 | let avatarUrl = ""; 199 | if (files.avatar) { 200 | let extname = path.extname(files.avatar.name); 201 | let newPath = uploadConfig.SERVER_DIR + uploadConfig.ADMIN_AVATAR_URL + req.session.loginUser + extname.toLocaleLowerCase(); 202 | fs.renameSync(files.avatar.path, newPath); 203 | avatarUrl = uploadConfig.SERVER_URL + uploadConfig.ADMIN_AVATAR_URL + req.session.loginUser + extname.toLocaleLowerCase(); 204 | } else { 205 | res.json(resMsg(9001)); 206 | return false; 207 | } 208 | await adminUserModel.update({ 209 | avatarUrl 210 | }, req.session.loginUser); 211 | res.json(resMsg(200)); 212 | }); 213 | form.on("error", function (error) { 214 | logger.error(error); 215 | res.json(resMsg()); 216 | return false; 217 | }); 218 | } 219 | } 220 | 221 | module.exports = adminUserController; 222 | -------------------------------------------------------------------------------- /controllers/indexController.js: -------------------------------------------------------------------------------- 1 | const logger = require("../config/log4j"); 2 | const rsaKey = require("./../config/rsa"); 3 | const resMsg = require("../utils/utils").resMsg; 4 | const hasEmpty = require("../utils/utils").hasEmpty; 5 | const getRandom = require("../utils/utils").getRandom; 6 | const indexModel = require("../modules/indexModel"); 7 | const shopOrderModel = require("../modules/shopOrderModel"); 8 | const areaModel = require("../modules/areaModel"); 9 | 10 | class indexController { 11 | /** 12 | * 获取公钥 13 | * 14 | * @static 15 | * @param {*} req 16 | * @param {*} res 17 | * @param {*} next 18 | * @returns 19 | * @memberof indexController 20 | */ 21 | static async getPublicKey(req, res, next) { 22 | try { 23 | let publicKey = rsaKey.exportKey("public"); 24 | res.json(resMsg(200, publicKey)); 25 | } catch (error) { 26 | logger.error(error); 27 | res.json(resMsg()); 28 | } 29 | } 30 | 31 | /** 32 | * 获取用户信息 排除密码 33 | * 34 | * @static 35 | * @param {*} req 36 | * @param {*} res 37 | * @param {*} next 38 | * @returns 39 | * @memberof indexController 40 | */ 41 | static async getUserInfo(req, res, next) { 42 | try { 43 | let name = req.session.loginUser; 44 | let result = await indexModel.getUserInfo(name); 45 | res.json(resMsg(200, result)); 46 | } catch (error) { 47 | logger.error(error); 48 | res.json(resMsg()); 49 | } 50 | } 51 | 52 | /** 53 | * 获取省份 54 | * 55 | * @static 56 | * @param {*} req 57 | * @param {*} res 58 | * @param {*} next 59 | * @memberof indexController 60 | */ 61 | static async getProvince(req, res, next) { 62 | try { 63 | let result = await areaModel.getProvince(); 64 | res.json(resMsg(200, result)); 65 | } catch (error) { 66 | logger.error(error); 67 | res.json(resMsg()); 68 | } 69 | } 70 | 71 | /** 72 | * 根据省份获取市 73 | * 74 | * @static 75 | * @param {*} req 76 | * @param {*} res 77 | * @param {*} next 78 | * @memberof indexController 79 | */ 80 | static async getCityByProvince(req, res, next) { 81 | try { 82 | if (hasEmpty(req.body.provinceId)) { 83 | res.json(resMsg(9001)); 84 | return false; 85 | } 86 | let result = await areaModel.getCityByProvince(req.body.provinceId); 87 | res.json(resMsg(200, result)); 88 | } catch (error) { 89 | logger.error(error); 90 | res.json(resMsg()); 91 | } 92 | } 93 | 94 | /** 95 | * 根据市获取县 96 | * 97 | * @static 98 | * @param {*} req 99 | * @param {*} res 100 | * @param {*} next 101 | * @memberof indexController 102 | */ 103 | static async getCountryByCity(req, res, next) { 104 | try { 105 | if (hasEmpty(req.body.cityId)) { 106 | res.json(resMsg(9001)); 107 | return false; 108 | } 109 | let result = await areaModel.getCountryByCity(req.body.cityId); 110 | res.json(resMsg(200, result)); 111 | } catch (error) { 112 | logger.error(error); 113 | res.json(resMsg()); 114 | } 115 | } 116 | 117 | /** 118 | * 根据物流id获取物流信息 119 | * @param req 120 | * @param res 121 | * @param next 122 | * @returns {Promise} 123 | */ 124 | static async getDeliveryInfoById(req, res, next) { 125 | try { 126 | if (hasEmpty(req.body.id)) { 127 | res.json(resMsg(9001)); 128 | return false; 129 | } 130 | let deliveryInfo = [ 131 | { 132 | time: "2019-10-12 18:41:53", 133 | info: "仓库已接单" 134 | }, 135 | { 136 | time: "2019-10-12 20:31:14", 137 | info: "快递已从烟台转运发出" 138 | }, 139 | { 140 | time: "2019-10-13 12:32:54", 141 | info: "快件到达 上海市奉贤区南桥 公司,已揽收" 142 | }, 143 | { 144 | time: "2019-10-13 20:27:36", 145 | info: "浦东转运中心公司 已打包" 146 | }, 147 | { 148 | time: "2019-10-13 21:19:24", 149 | info: "浦东转运中心公司 已发出,下一站 上海转运中心" 150 | }, 151 | { 152 | time: "2019-10-14 08:57:08", 153 | info: "亲,您的快递已送达,请及时取件,如有疑问请电联,亲,您的快递已送达,请及时取件,如有疑问请电联,亲,您的快递已送达,请及时取件,如有疑问请电联" 154 | }, 155 | { 156 | time: "2019-10-14 12:32:54", 157 | info: "【烟台市】山东省烟台市派件员 正在为您派件" 158 | } 159 | ]; 160 | let len = getRandom(2, deliveryInfo.length); 161 | let resObj = { 162 | infoArr: [], 163 | status: getRandom(0, 2) 164 | }; 165 | for (let i = 0; i < len; i++) { 166 | resObj.infoArr.push(deliveryInfo[getRandom(0, len)]); 167 | } 168 | res.json(resMsg(200, resObj)); 169 | } catch (error) { 170 | logger.error(error); 171 | res.json(resMsg()); 172 | } 173 | } 174 | 175 | /** 176 | * 获取订单信息 177 | * @param req 178 | * @param res 179 | * @param next 180 | * @returns {Promise} 181 | */ 182 | static async getOrderStatistics(req, res, next) { 183 | try { 184 | let promiseArr = [shopOrderModel.getTodayOrder(), shopOrderModel.getAllDealWithOrder(), shopOrderModel.getAllRefundOrder()]; 185 | let resultArr = await Promise.all(promiseArr); 186 | res.json(resMsg(200, { 187 | todayOrderNum: resultArr[0][0].get("todayOrderNum"), 188 | dealWithOrderNum: resultArr[1][0].get("dealWithOrderNum"), 189 | refundOrderNum: resultArr[2][0].get("refundOrderNum"), 190 | })); 191 | } catch (error) { 192 | logger.error(error); 193 | res.json(resMsg()); 194 | } 195 | } 196 | 197 | /** 198 | * 199 | * @param req 200 | * @param res 201 | * @param next 202 | * @returns {Promise} 203 | */ 204 | static async getOrderStatisticsByType(req, res, next) { 205 | try { 206 | if (hasEmpty(req.body.type)) { 207 | res.json(resMsg(9001)); 208 | return false; 209 | } 210 | if (req.body.type === 0) { 211 | let promiseArr = [shopOrderModel.getTodaySubOrder(), shopOrderModel.getWeekSubOrder(), shopOrderModel.getMonthSubOrder()]; 212 | let resultArr = await Promise.all(promiseArr); 213 | res.json(resMsg(200, { 214 | today: resultArr[0][0].get("today"), 215 | week: resultArr[1][0].get("week"), 216 | month: resultArr[2][0].get("month"), 217 | })); 218 | } else { 219 | let promiseArr = [shopOrderModel.getTodayMoney(), shopOrderModel.getWeekMoney(), shopOrderModel.getMonthMoney()]; 220 | let resultArr = await Promise.all(promiseArr); 221 | res.json(resMsg(200, { 222 | today: resultArr[0][0].get("today") && resultArr[0][0].get("today").toFixed(2), 223 | week: resultArr[1][0].get("week") && resultArr[1][0].get("week").toFixed(2), 224 | month: resultArr[2][0].get("month") && resultArr[2][0].get("month").toFixed(2), 225 | })); 226 | } 227 | } catch (error) { 228 | logger.error(error); 229 | res.json(resMsg()); 230 | } 231 | } 232 | 233 | /** 234 | * 获取本月Top10信息 235 | * @param req 236 | * @param res 237 | * @param next 238 | * @returns {Promise} 239 | */ 240 | static async getTop10Info(req, res, next){ 241 | try { 242 | let promiseArr = [shopOrderModel.getBookTop10(), shopOrderModel.getStockTop10(), shopOrderModel.getUserTop10()]; 243 | let resultArr = await Promise.all(promiseArr); 244 | res.json(resMsg(200, { 245 | book: resultArr[0], 246 | stock: resultArr[1], 247 | user: resultArr[2], 248 | })); 249 | } catch (error) { 250 | logger.error(error); 251 | res.json(resMsg()); 252 | } 253 | } 254 | 255 | /** 256 | * 获取趋势变化信息 257 | * @param req 258 | * @param res 259 | * @param next 260 | * @returns {Promise} 261 | */ 262 | static async getTrendInfo(req, res, next) { 263 | try { 264 | if (hasEmpty(req.body.type)) { 265 | res.json(resMsg(9001)); 266 | return false; 267 | } 268 | if (req.body.type === 0) { 269 | let result = await shopOrderModel.getTrendCountInfo(); 270 | res.json(resMsg(200, result[0] || [])); 271 | } else { 272 | let result = await shopOrderModel.getTrendMoneyInfo(); 273 | res.json(resMsg(200, result[0] || [])); 274 | } 275 | } catch (error) { 276 | logger.error(error); 277 | res.json(resMsg()); 278 | } 279 | } 280 | } 281 | 282 | module.exports = indexController; -------------------------------------------------------------------------------- /controllers/shopOrderController.js: -------------------------------------------------------------------------------- 1 | const formidable = require("formidable"); 2 | const fs = require("fs"); 3 | const nodeXlsx = require("node-xlsx"); 4 | const logger = require("../config/log4j"); 5 | const resMsg = require("../utils/utils").resMsg; 6 | const hasEmpty = require("../utils/utils").hasEmpty; 7 | const numReg = require("../utils/utils").numReg; 8 | const getRefundOrderId = require("../utils/utils").getRefundOrderId; 9 | const shopOrderModel = require("../modules/shopOrderModel"); 10 | const uploadConfig = require("./../config/uploadConfig"); 11 | 12 | class shopOrderController { 13 | /** 14 | * 分页获取订单记录 15 | * 16 | * @static 17 | * @param {*} req 18 | * @param {*} res 19 | * @param {*} next 20 | * @memberof shopOrderController 21 | */ 22 | static async getOrderList(req, res, next) { 23 | try { 24 | if (hasEmpty(req.body.pageSize, req.body.pageNumber, req.body.startTime, req.body.endTime)) { 25 | res.json(resMsg(9001)); 26 | return false; 27 | } 28 | let result = await shopOrderModel.getOrderList(req.body); 29 | res.json(resMsg(200, result)); 30 | } catch (error) { 31 | logger.error(error); 32 | res.json(resMsg()); 33 | } 34 | } 35 | 36 | /** 37 | * 根据订单号查询订单 38 | * @param req 39 | * @param res 40 | * @param next 41 | * @returns {Promise} 42 | */ 43 | static async getOrderByOrderId(req, res, next){ 44 | try { 45 | if (hasEmpty(req.body.orderId)) { 46 | res.json(resMsg(9001)); 47 | return false; 48 | } 49 | let result = await shopOrderModel.getOrderByOrderId(req.body.orderId); 50 | res.json(resMsg(200, result)); 51 | } catch (error) { 52 | logger.error(error); 53 | res.json(resMsg()); 54 | } 55 | } 56 | 57 | /** 58 | * 确认待处理订单 59 | * 60 | * @static 61 | * @param {*} req 62 | * @param {*} res 63 | * @param {*} next 64 | * @returns 65 | * @memberof shopOrderController 66 | */ 67 | static async submitOrder(req, res, next) { 68 | try { 69 | if (hasEmpty(req.body.ids)) { 70 | res.json(resMsg(9001)); 71 | return false; 72 | } 73 | let result = await shopOrderModel.submitOrder(req.body.ids); 74 | if (!result || result[0] === 0) { 75 | res.json(resMsg(2002)); 76 | } else { 77 | res.json(resMsg(200)); 78 | } 79 | } catch (error) { 80 | logger.error(error); 81 | res.json(resMsg()); 82 | } 83 | } 84 | 85 | /** 86 | * 上传/编辑物流信息 87 | * 88 | * @static 89 | * @param {*} req 90 | * @param {*} res 91 | * @param {*} next 92 | * @memberof shopOrderController 93 | */ 94 | static async submitDeliveryInfo(req, res, next) { 95 | try { 96 | let { 97 | id, 98 | deliveryId, 99 | deliveryOrderId 100 | } = req.body; 101 | if (hasEmpty(id, deliveryId, deliveryOrderId) || !/^[A-Za-z0-9]+$/.test(deliveryOrderId) || !numReg.test(deliveryId)) { 102 | res.json(resMsg(9001)); 103 | return false; 104 | } 105 | let params = { 106 | id, 107 | deliveryId, 108 | deliveryOrderId, 109 | deliveryAt: new Date() 110 | }; 111 | let result = await shopOrderModel.getSubmitDeliveryInfo(params); 112 | if (!result || result.length === 0) { 113 | res.json(resMsg(2002)); 114 | } else { 115 | await shopOrderModel.submitDeliveryInfo(params); 116 | res.json(resMsg(200)); 117 | } 118 | } catch (error) { 119 | logger.error(error); 120 | res.json(resMsg()); 121 | } 122 | } 123 | 124 | /** 125 | * 更改订单物流信息 126 | * 127 | * @static 128 | * @param {*} req 129 | * @param {*} res 130 | * @param {*} next 131 | * @memberof shopOrderController 132 | */ 133 | static async updateOrderAddress(req, res, next) { 134 | try { 135 | let { 136 | id, 137 | deliveryAddressId 138 | } = req.body; 139 | if (hasEmpty(id, deliveryAddressId)) { 140 | res.json(resMsg(9001)); 141 | return false; 142 | } 143 | let params = { 144 | id, 145 | deliveryAddressId 146 | }; 147 | let result = await shopOrderModel.getUpdateAddressInfo(params); 148 | if (!result || result.length === 0) { 149 | res.json(resMsg(2002)); 150 | } else { 151 | await shopOrderModel.updateAddressInfo(params); 152 | res.json(resMsg(200)); 153 | } 154 | } catch (error) { 155 | logger.error(error); 156 | res.json(resMsg()); 157 | } 158 | } 159 | 160 | /** 161 | * 获取所有物流公司 162 | * 163 | * @static 164 | * @param {*} req 165 | * @param {*} res 166 | * @param {*} next 167 | * @returns 168 | * @memberof shopOrderController 169 | */ 170 | static async getAllDeliveryCompany(req, res, next) { 171 | try { 172 | let result = await shopOrderModel.getAllDeliveryCompany(); 173 | res.json(resMsg(200, result)); 174 | } catch (error) { 175 | logger.error(error); 176 | res.json(resMsg()); 177 | } 178 | } 179 | 180 | /** 181 | * 新增收货地址 182 | * 183 | * @static 184 | * @param {*} req 185 | * @param {*} res 186 | * @param {*} next 187 | * @memberof shopOrderController 188 | */ 189 | static async submitAddAddress(req, res, next) { 190 | try { 191 | let { 192 | userId, 193 | deliveryName, 194 | deliveryMobile, 195 | provinceId, 196 | cityId, 197 | countryId, 198 | detailAddress 199 | } = req.body; 200 | if (hasEmpty(userId, deliveryName, deliveryMobile, provinceId, cityId, countryId, detailAddress)) { 201 | res.json(resMsg(9001)); 202 | return false; 203 | } 204 | await shopOrderModel.submitAddAddress({ 205 | userId, 206 | deliveryName, 207 | deliveryMobile, 208 | provinceId, 209 | cityId, 210 | countryId, 211 | detailAddress 212 | }); 213 | res.json(resMsg(200)); 214 | } catch (error) { 215 | logger.error(error); 216 | res.json(resMsg()); 217 | } 218 | } 219 | 220 | /** 221 | * 处理退款订单 222 | * @param req 223 | * @param res 224 | * @param next 225 | */ 226 | static async submitRefundInfo(req, res, next) { 227 | try { 228 | let { 229 | ids, 230 | refundRemark, 231 | refundStatus 232 | } = req.body; 233 | if (hasEmpty(ids, refundRemark, refundStatus) || (refundStatus !== 0 && refundStatus !== 1)) { 234 | res.json(resMsg(9001)); 235 | return false; 236 | } 237 | let idsArr = ids.split(","); 238 | let result = await shopOrderModel.getUpdateRefundInfo(idsArr); 239 | if (!result || result.length !== idsArr.length) { 240 | res.json(resMsg(2002)); 241 | } else { 242 | let status = refundStatus === 0 ? 8 : 7; 243 | await shopOrderModel.submitRefundInfo({ 244 | idsArr, 245 | status 246 | }); 247 | let refundRecordData = []; 248 | for (let i = 0, len = result.length; i < len; i++) { 249 | let obj = { 250 | remark: refundRemark, 251 | status 252 | }; 253 | obj.refundOrderId = getRefundOrderId(result[i].userId); 254 | obj.orderNumId = result[i].orderId; 255 | obj.userName = result[i].userName; 256 | obj.refundMoney = status === 7 ? result[i].totalMoney : null; 257 | refundRecordData.push(obj); 258 | } 259 | await shopOrderModel.createRefundRecord(refundRecordData); 260 | res.json(resMsg(200)); 261 | } 262 | } catch (error) { 263 | logger.error(error); 264 | res.json(resMsg()); 265 | } 266 | } 267 | 268 | /** 269 | * 分页获取退款订单记录 270 | * @param req 271 | * @param res 272 | * @param next 273 | * @returns {Promise} 274 | */ 275 | static async getRefundRecord(req, res, next){ 276 | try { 277 | if (hasEmpty(req.body.pageSize, req.body.pageNumber, req.body.startTime, req.body.endTime)) { 278 | res.json(resMsg(9001)); 279 | return false; 280 | } 281 | let result = await shopOrderModel.getRefundRecord(req.body); 282 | res.json(resMsg(200, result)); 283 | } catch (error) { 284 | logger.error(error); 285 | res.json(resMsg()); 286 | } 287 | } 288 | 289 | /** 290 | * 删除物流公司 291 | * 292 | * @static 293 | * @param {*} req 294 | * @param {*} res 295 | * @param {*} next 296 | * @returns 297 | * @memberof shopOrderController 298 | */ 299 | static async deleteDeliveryCompany(req, res, next) { 300 | try { 301 | if (hasEmpty(req.body.id)) { 302 | res.json(resMsg(9001)); 303 | return false; 304 | } 305 | await shopOrderModel.deleteDeliveryCompany(req.body.id); 306 | res.json(resMsg(200)); 307 | } catch (error) { 308 | logger.error(error); 309 | res.json(resMsg()); 310 | } 311 | } 312 | 313 | /** 314 | * 新增物流公司 315 | * 316 | * @static 317 | * @param {*} req 318 | * @param {*} res 319 | * @param {*} next 320 | * @returns 321 | * @memberof shopOrderController 322 | */ 323 | static async addDeliveryCompany(req, res, next) { 324 | try { 325 | if (hasEmpty(req.body.deliveryCompanyName)) { 326 | res.json(resMsg(9001)); 327 | return false; 328 | } 329 | await shopOrderModel.addDeliveryCompany([{ 330 | name: req.body.deliveryCompanyName 331 | }]); 332 | res.json(resMsg(200)); 333 | } catch (error) { 334 | logger.error(error); 335 | res.json(resMsg()); 336 | } 337 | } 338 | 339 | /** 340 | * 批量上传物流公司 341 | * 342 | * @static 343 | * @param {*} req 344 | * @param {*} res 345 | * @param {*} next 346 | * @memberof shopOrderController 347 | */ 348 | static async uploadDeliveryExcel(req, res, next) { 349 | let excelUrl = uploadConfig.TEMP; 350 | let form = new formidable.IncomingForm(); 351 | let map = { 352 | 1: "A" 353 | }; 354 | let dataMap = { 355 | 0: "name" 356 | }; 357 | const DATA_LENGTH = Object.keys(dataMap).length; 358 | form.encoding = uploadConfig.ENCODING; 359 | form.uploadDir = uploadConfig.SERVER_DIR + excelUrl; 360 | form.keepExtensions = uploadConfig.KEEP_EXTENSIONS; 361 | form.maxFileSize = uploadConfig.MAX_FILESIZE; 362 | let errorMsg = ""; 363 | form.parse(req, async (error, fields, files) => { 364 | if (error) { 365 | logger.error(error); 366 | res.json(resMsg()); 367 | return false; 368 | } 369 | // 读取文件 370 | const excelData = nodeXlsx.parse(files.excel.path); 371 | // 删除文件 372 | fs.unlink(files.excel.path, (error) => { 373 | if (error) { 374 | logger.error(error); 375 | } 376 | }); 377 | let optionData = excelData[0].data; 378 | let saveData = []; 379 | if (optionData.length > 1) { 380 | for (let i = 1, len = optionData.length; i < len; i++) { 381 | let data = optionData[i]; 382 | let saveDataObj = {}; 383 | for (let j = 0; j < DATA_LENGTH; j++) { 384 | let val = data[j]; 385 | if (hasEmpty(val)) { 386 | errorMsg = `第 ${i + 1} 行第 ${map[j + 1]} 列数据不能为空`; 387 | break; 388 | } 389 | saveDataObj[dataMap[j]] = val; 390 | } 391 | if (errorMsg) { 392 | break; 393 | } 394 | saveData.push(saveDataObj); 395 | } 396 | if (errorMsg) { 397 | logger.error(errorMsg); 398 | res.json({ 399 | errorCode: 9999, 400 | errorMsg: errorMsg, 401 | data: "" 402 | }); 403 | return false; 404 | } else { 405 | await shopOrderModel.addDeliveryCompany(saveData); 406 | res.json(resMsg(200)); 407 | } 408 | } else { 409 | logger.error("上传文件内容为空"); 410 | res.json(resMsg(2001)); 411 | return false; 412 | } 413 | }); 414 | form.on("error", function (error) { 415 | logger.error(error); 416 | res.json(resMsg()); 417 | return false; 418 | }); 419 | } 420 | 421 | /** 422 | * 下载物流上传模板 423 | * 424 | * @static 425 | * @param {*} req 426 | * @param {*} res 427 | * @param {*} next 428 | * @memberof shopOrderController 429 | */ 430 | static async downloadDeliveryTemplate(req, res, next) { 431 | try { 432 | let filePath = uploadConfig.SERVER_DIR + uploadConfig.DELIVERY_TEMPLATE + "/" + uploadConfig.DELIVERY_COMPONY_EXCEL; 433 | res.download(filePath); 434 | } catch (error) { 435 | logger.error(error); 436 | res.json(resMsg()); 437 | } 438 | } 439 | } 440 | 441 | module.exports = shopOrderController; -------------------------------------------------------------------------------- /modules/shopOrderModel.js: -------------------------------------------------------------------------------- 1 | const db = require("../config/dbConnect"); 2 | const sequelize = db.sequelize; 3 | const Op = sequelize.Op; 4 | const moment = require("moment"); 5 | const shopOrderListSchema = sequelize.import("../schema/shopOrderListSchema"); 6 | const shopSubOrderListSchema = sequelize.import("../schema/shopSubOrderListSchema"); 7 | const shopDeliveryCompanySchema = sequelize.import("../schema/shopDeliveryCompanySchema"); 8 | const shopUserDeliveryAddressSchema = sequelize.import("../schema/shopUserDeliveryAddressSchema"); 9 | const shopRefundRecordSchema = sequelize.import("../schema/shopRefundRecordSchema"); 10 | const shopStockRecordSchema = sequelize.import("../schema/shopStockRecordSchema"); 11 | const getUncertainSqlObj = require("./../utils/utils").getUncertainSqlObj; 12 | 13 | class shopOrderModel { 14 | /** 15 | * 分页查询订单列表 16 | * 17 | * @static 18 | * @memberof shopOrderModel 19 | */ 20 | static async getOrderList(parmas) { 21 | let { 22 | pageSize, 23 | pageNumber, 24 | startTime, 25 | endTime, 26 | status, 27 | orderId, 28 | userName 29 | } = parmas; 30 | let searchObj = getUncertainSqlObj({ 31 | status, 32 | orderId, 33 | userName 34 | }); 35 | shopOrderListSchema.hasMany(shopSubOrderListSchema, { 36 | foreignKey: "mainOrderId", 37 | sourceKey: "id", 38 | as: { 39 | singular: "orders", 40 | plural: "orders" 41 | } 42 | }); 43 | let result = await shopOrderListSchema.findAndCountAll({ 44 | offset: pageSize * (pageNumber - 1), 45 | limit: pageSize, 46 | where: { 47 | createdAt: { 48 | [Op.gt]: startTime, 49 | [Op.lt]: endTime, 50 | }, 51 | ...searchObj 52 | }, 53 | include: [{ 54 | model: shopSubOrderListSchema, 55 | as: "orders" 56 | }], 57 | order: [ 58 | ["id", "DESC"] 59 | ], 60 | distinct: true 61 | }); 62 | return { 63 | pageSize, 64 | pageNumber, 65 | rows: result.rows, 66 | total: result.count 67 | }; 68 | } 69 | 70 | /** 71 | * 根据订单号查询订单 72 | * @param orderId 73 | * @returns {Promise<*>} 74 | */ 75 | static async getOrderByOrderId(orderId) { 76 | shopOrderListSchema.hasMany(shopSubOrderListSchema, { 77 | foreignKey: "mainOrderId", 78 | sourceKey: "id", 79 | as: { 80 | singular: "orders", 81 | plural: "orders" 82 | } 83 | }); 84 | return await shopOrderListSchema.findOne({ 85 | where: { 86 | orderId 87 | }, 88 | include: [{ 89 | model: shopSubOrderListSchema, 90 | as: "orders" 91 | }], 92 | distinct: true 93 | }); 94 | } 95 | 96 | /** 97 | * 确认待处理订单 98 | * 99 | * @static 100 | * @param {string} ids 逗号间隔订单id 101 | * @returns 102 | * @memberof shopOrderModel 103 | */ 104 | static async submitOrder(ids) { 105 | return await shopOrderListSchema.update({ 106 | status: 2 107 | }, { 108 | where: { 109 | status: 1, 110 | id: { 111 | [Op.in]: ids.split(",") 112 | } 113 | } 114 | }); 115 | } 116 | 117 | /** 118 | * 查询符合更新条件的 119 | * 120 | * @static 121 | * @param {*} parmas 122 | * @memberof shopOrderModel 123 | */ 124 | static async getSubmitDeliveryInfo(parmas) { 125 | let { 126 | id 127 | } = parmas; 128 | return await shopOrderListSchema.findAll({ 129 | where: { 130 | status: { 131 | [Op.or]: [2, 3] 132 | }, 133 | id 134 | } 135 | }); 136 | } 137 | 138 | /** 139 | * 查询符合收货地址符合条件的 140 | * 141 | * @static 142 | * @param {*} parmas 143 | * @memberof shopOrderModel 144 | */ 145 | static async getUpdateAddressInfo(parmas) { 146 | let { 147 | id 148 | } = parmas; 149 | return await shopOrderListSchema.findAll({ 150 | where: { 151 | status: { 152 | [Op.or]: [1, 2, 3] 153 | }, 154 | id 155 | } 156 | }); 157 | } 158 | 159 | /** 160 | * 查询符合退款条件的 161 | * 162 | * @static 163 | * @memberof shopOrderModel 164 | * @param idsArr 165 | */ 166 | static async getUpdateRefundInfo(idsArr) { 167 | return await shopOrderListSchema.findAll({ 168 | where: { 169 | status: 6, 170 | id: { 171 | [Op.in]: idsArr 172 | } 173 | } 174 | }); 175 | } 176 | 177 | /** 178 | * 更新待退款状态 179 | * 180 | * @static 181 | * @param param 182 | * @memberof shopOrderModel 183 | */ 184 | static async submitRefundInfo(param) { 185 | return await shopOrderListSchema.update({ 186 | status: param.status, 187 | dealAt: new Date() 188 | }, { 189 | where: { 190 | status: 6, 191 | id: { 192 | [Op.in]: param.idsArr 193 | } 194 | } 195 | }); 196 | } 197 | 198 | /** 199 | * 生成退款订单记录 200 | * @param refundArr 退款订单数据 201 | * @returns {Promise<*>} 202 | */ 203 | static async createRefundRecord(refundArr) { 204 | return await shopRefundRecordSchema.bulkCreate(refundArr); 205 | } 206 | 207 | /** 208 | * 分页获取退款订单记录 209 | * @param params 210 | * @returns {Promise<{total: *, pageNumber: *, pageSize: *, rows: *}>} 211 | */ 212 | static async getRefundRecord(params) { 213 | let { 214 | pageSize, 215 | pageNumber, 216 | startTime, 217 | endTime, 218 | refundOrderId, 219 | orderNumId, 220 | userName, 221 | status 222 | } = params; 223 | let queryObj = getUncertainSqlObj({ 224 | refundOrderId, 225 | orderNumId, 226 | userName, 227 | status 228 | }); 229 | let result = await shopRefundRecordSchema.findAndCountAll({ 230 | offset: pageSize * (pageNumber - 1), 231 | limit: pageSize, 232 | where: { 233 | createdAt: { 234 | [Op.gt]: startTime, 235 | [Op.lt]: endTime, 236 | }, 237 | ...queryObj 238 | }, 239 | order: [ 240 | ["id", "DESC"] 241 | ] 242 | }); 243 | return { 244 | pageSize, 245 | pageNumber, 246 | rows: result.rows, 247 | total: result.count 248 | }; 249 | } 250 | 251 | /** 252 | * 上传/编辑物流信息 253 | * 254 | * @static 255 | * @param {Object} parmas 256 | * @memberof shopOrderModel 257 | */ 258 | static async submitDeliveryInfo(parmas) { 259 | let { 260 | id, 261 | ...updateObj 262 | } = parmas; 263 | return await shopOrderListSchema.update({ 264 | status: 3, 265 | ...updateObj 266 | }, { 267 | where: { 268 | status: { 269 | [Op.or]: [2, 3] 270 | }, 271 | id 272 | } 273 | }); 274 | } 275 | 276 | 277 | /** 278 | * 更改订单物流信息 279 | * 280 | * @static 281 | * @param {Object} parmas 282 | * @memberof shopOrderModel 283 | */ 284 | static async updateAddressInfo(parmas) { 285 | let { 286 | id, 287 | ...updateObj 288 | } = parmas; 289 | return await shopOrderListSchema.update({ 290 | ...updateObj 291 | }, { 292 | where: { 293 | status: { 294 | [Op.or]: [1, 2, 3] 295 | }, 296 | id 297 | } 298 | }); 299 | } 300 | 301 | /** 302 | * 新增收货地址 303 | * 304 | * @static 305 | * @param {Object} param 新增的字段 306 | * @memberof shopOrderModel 307 | */ 308 | static async submitAddAddress(param) { 309 | return await shopUserDeliveryAddressSchema.create({ 310 | ...param 311 | }); 312 | } 313 | 314 | /** 315 | * 316 | * 查询所有物流公司 317 | * @static 318 | * @returns {Promise<*>} 319 | * @memberof shopOrderModel 320 | */ 321 | static async getAllDeliveryCompany() { 322 | return await shopDeliveryCompanySchema.findAll(); 323 | } 324 | 325 | /** 326 | * 327 | * 删除物流公司 328 | * @static 329 | * @param {*} id 物流公司id 330 | * @returns {Promise<*>} 331 | * @memberof shopOrderModel 332 | */ 333 | static async deleteDeliveryCompany(id) { 334 | await shopDeliveryCompanySchema.destroy({ 335 | where: { 336 | id 337 | } 338 | }); 339 | } 340 | 341 | 342 | /** 343 | * 添加物流公司 344 | * 345 | * @static 346 | * @param {Array} deliveryCompanyArr 物流公司数组 347 | * @returns 348 | * @memberof shopOrderModel 349 | */ 350 | static async addDeliveryCompany(deliveryCompanyArr) { 351 | return await shopDeliveryCompanySchema.bulkCreate(deliveryCompanyArr); 352 | } 353 | 354 | /** 355 | * 生成订单 356 | * 357 | * @static 358 | * @param {*} param 359 | * @returns 360 | * @memberof shopOrderModel 361 | */ 362 | static async createOrder(param) { 363 | return await shopOrderListSchema.create(param); 364 | } 365 | 366 | /** 367 | * 生成子订单 368 | * 369 | * @static 370 | * @param {*} paramsArr 371 | * @returns 372 | * @memberof shopOrderModel 373 | */ 374 | static async createSubOrder(paramsArr) { 375 | return await shopSubOrderListSchema.bulkCreate(paramsArr); 376 | } 377 | 378 | /** 379 | * 获取今日订单 380 | * @returns {Promise} 381 | */ 382 | static getTodayOrder() { 383 | let todayStartTime = new Date(new Date(new Date().toLocaleDateString()).getTime()); 384 | return shopOrderListSchema.findAll({ 385 | attributes: [[sequelize.fn("COUNT", sequelize.col("id")), "todayOrderNum"]], 386 | where: { 387 | createdAt: { 388 | [Op.gt]: todayStartTime, 389 | } 390 | } 391 | }); 392 | } 393 | 394 | /** 395 | * 获取待处理订单 396 | * @returns {Promise} 397 | */ 398 | static getAllDealWithOrder() { 399 | return shopOrderListSchema.findAll({ 400 | attributes: [[sequelize.fn("COUNT", sequelize.col("id")), "dealWithOrderNum"]], 401 | where: { 402 | status: 1 403 | } 404 | }); 405 | } 406 | 407 | /** 408 | * 获取退款订单 409 | * @returns {Promise} 410 | */ 411 | static getAllRefundOrder() { 412 | return shopOrderListSchema.findAll({ 413 | attributes: [[sequelize.fn("COUNT", sequelize.col("id")), "refundOrderNum"]], 414 | where: { 415 | status: 6 416 | } 417 | }); 418 | } 419 | 420 | /** 421 | * 获取今日销量 422 | * @returns {Promise} 423 | */ 424 | static getTodaySubOrder() { 425 | let time = new Date(new Date(new Date().toLocaleDateString()).getTime()); 426 | return shopSubOrderListSchema.findAll({ 427 | attributes: [[sequelize.fn("COUNT", sequelize.col("id")), "today"]], 428 | where: { 429 | createdAt: { 430 | [Op.gt]: time, 431 | } 432 | } 433 | }); 434 | } 435 | 436 | /** 437 | * 获取本周销量 438 | * @returns {Promise} 439 | */ 440 | static getWeekSubOrder() { 441 | let time = new Date(new Date(new Date().toLocaleDateString()).getTime()); 442 | let day = time.getDay(); 443 | day = day === 0 ? 7 : day; 444 | time.setDate(time.getDate() - day + 1); 445 | return shopSubOrderListSchema.findAll({ 446 | attributes: [[sequelize.fn("COUNT", sequelize.col("id")), "week"]], 447 | where: { 448 | createdAt: { 449 | [Op.gt]: time, 450 | } 451 | } 452 | }); 453 | } 454 | 455 | /** 456 | * 获取本月销量 457 | * @returns {Promise} 458 | */ 459 | static getMonthSubOrder() { 460 | let time = new Date(new Date(new Date().toLocaleDateString()).getTime()); 461 | time.setDate(1); 462 | return shopSubOrderListSchema.findAll({ 463 | attributes: [[sequelize.fn("COUNT", sequelize.col("id")), "month"]], 464 | where: { 465 | createdAt: { 466 | [Op.gt]: time, 467 | } 468 | } 469 | }); 470 | } 471 | 472 | 473 | /** 474 | * 获取今日销售额 475 | * @returns {Promise} 476 | */ 477 | static getTodayMoney() { 478 | let time = new Date(new Date(new Date().toLocaleDateString()).getTime()); 479 | return shopSubOrderListSchema.findAll({ 480 | attributes: [[sequelize.literal("SUM(bookSalePrice * bookNum)"), "today"]], 481 | where: { 482 | createdAt: { 483 | [Op.gt]: time, 484 | } 485 | } 486 | }); 487 | } 488 | 489 | /** 490 | * 获取本周销售额 491 | * @returns {Promise} 492 | */ 493 | static getWeekMoney() { 494 | let time = new Date(new Date(new Date().toLocaleDateString()).getTime()); 495 | let day = time.getDay(); 496 | day = day === 0 ? 7 : day; 497 | time.setDate(time.getDate() - day + 1); 498 | return shopSubOrderListSchema.findAll({ 499 | attributes: [[sequelize.literal("SUM(bookSalePrice * bookNum)"), "week"]], 500 | where: { 501 | createdAt: { 502 | [Op.gt]: time, 503 | } 504 | } 505 | }); 506 | } 507 | 508 | /** 509 | * 获取本月销售额 510 | * @returns {Promise} 511 | */ 512 | static getMonthMoney() { 513 | let time = new Date(new Date(new Date().toLocaleDateString()).getTime()); 514 | time.setDate(1); 515 | return shopSubOrderListSchema.findAll({ 516 | attributes: [[sequelize.literal("SUM(bookSalePrice * bookNum)"), "month"]], 517 | where: { 518 | createdAt: { 519 | [Op.gt]: time, 520 | } 521 | } 522 | }); 523 | } 524 | 525 | /** 526 | * 获取书籍销量Top10 527 | * @returns {Promise<*>} 528 | */ 529 | static async getBookTop10() { 530 | let time = new Date(new Date(new Date().toLocaleDateString()).getTime()); 531 | time.setDate(1); 532 | return shopSubOrderListSchema.findAll({ 533 | attributes: [[sequelize.fn("COUNT", sequelize.col("id")), "bookCount"], "bookName"], 534 | where: { 535 | createdAt: { 536 | [Op.gt]: time, 537 | } 538 | }, 539 | group: "bookId", 540 | order: [ 541 | [[sequelize.literal("bookCount"), "DESC"]] 542 | ], 543 | limit: 10 544 | }); 545 | } 546 | 547 | /** 548 | * 获取进货量Top10 549 | * @returns {Promise<*>} 550 | */ 551 | static async getStockTop10() { 552 | let time = new Date(new Date(new Date().toLocaleDateString()).getTime()); 553 | time.setDate(1); 554 | return shopStockRecordSchema.findAll({ 555 | attributes: ["stockNum", "bookName"], 556 | where: { 557 | createdAt: { 558 | [Op.gt]: time, 559 | } 560 | }, 561 | order: [ 562 | ["stockNum", "DESC"] 563 | ], 564 | limit: 10 565 | }); 566 | } 567 | 568 | /** 569 | * 获取用户消费Top10 570 | * @returns {Promise<*>} 571 | */ 572 | static async getUserTop10() { 573 | let time = new Date(new Date(new Date().toLocaleDateString()).getTime()); 574 | time.setDate(1); 575 | return shopOrderListSchema.findAll({ 576 | attributes: [[sequelize.literal("SUM(totalMoney)"), "userMoney"], "userName"], 577 | where: { 578 | createdAt: { 579 | [Op.gt]: time, 580 | } 581 | }, 582 | group: "userId", 583 | order: [ 584 | [[sequelize.literal("userMoney"), "DESC"]] 585 | ], 586 | limit: 10 587 | }); 588 | } 589 | 590 | /** 591 | * 统计七个月销售量 592 | * @returns {Promise} 593 | */ 594 | static async getTrendCountInfo() { 595 | let time = new Date(new Date(new Date().toLocaleDateString()).getTime()); 596 | time.setMonth(time.getMonth() - 10); 597 | time.setDate(1); 598 | return await sequelize.query(` 599 | SELECT 600 | DATE_FORMAT(createdAt, '%Y-%m') day, 601 | COUNT(id) count 602 | FROM 603 | \`shop_sub_order_list\` 604 | WHERE 605 | createdAt BETWEEN '${moment(time).format("YYYY-MM-DD HH:mm:ss")}' AND '${moment(new Date()).format("YYYY-MM-DD HH:mm:ss")}' 606 | GROUP BY day 607 | ORDER BY createdAt;`); 608 | } 609 | 610 | /** 611 | * 统计七个月销售额 612 | * @returns {Promise} 613 | */ 614 | static async getTrendMoneyInfo() { 615 | let time = new Date(new Date(new Date().toLocaleDateString()).getTime()); 616 | time.setMonth(time.getMonth() - 10); 617 | time.setDate(1); 618 | return await sequelize.query(` 619 | SELECT 620 | DATE_FORMAT(createdAt, '%Y-%m') day, 621 | SUM(bookNum*bookPrice) count 622 | FROM 623 | \`shop_sub_order_list\` 624 | WHERE 625 | createdAt BETWEEN '${moment(time).format("YYYY-MM-DD HH:mm:ss")}' AND '${moment(new Date()).format("YYYY-MM-DD HH:mm:ss")}' 626 | GROUP BY day 627 | ORDER BY createdAt;`); 628 | } 629 | } 630 | 631 | module.exports = shopOrderModel; 632 | -------------------------------------------------------------------------------- /controllers/bookListController.js: -------------------------------------------------------------------------------- 1 | const formidable = require("formidable"); 2 | const fs = require("fs"); 3 | const path = require("path"); 4 | const nodeXlsx = require("node-xlsx"); 5 | const nodeZip = require("archiver"); 6 | const logger = require("../config/log4j"); 7 | const resMsg = require("../utils/utils").resMsg; 8 | const hasEmpty = require("../utils/utils").hasEmpty; 9 | const bookListModel = require("../modules/bookListModel"); 10 | const shopStockRecordModel = require("../modules/shopStockRecordModel"); 11 | const uploadConfig = require("./../config/uploadConfig"); 12 | 13 | class bookListController { 14 | /** 15 | * 获取图书列表 16 | * 17 | * @static 18 | * @param {*} req 19 | * @param {*} res 20 | * @param {*} next 21 | * @returns 22 | * @memberof bookListController 23 | */ 24 | static async getBookList(req, res, next) { 25 | try { 26 | if (hasEmpty(req.body.pageSize, req.body.pageNumber, req.body.startTime, req.body.endTime)) { 27 | res.json(resMsg(9001)); 28 | return false; 29 | } 30 | let result = await bookListModel.getBookList(req.body); 31 | res.json(resMsg(200, result)); 32 | } catch (error) { 33 | logger.error(error); 34 | res.json(resMsg()); 35 | } 36 | } 37 | 38 | /** 39 | * 删除图书 40 | * 41 | * @static 42 | * @param {*} req 43 | * @param {*} res 44 | * @param {*} next 45 | * @returns 46 | * @memberof bookListController 47 | */ 48 | static async deleteBooks(req, res, next) { 49 | try { 50 | let { 51 | ids 52 | } = req.body; 53 | if (hasEmpty(ids)) { 54 | res.json(resMsg(9001)); 55 | return false; 56 | } 57 | await bookListModel.deleteBooks(ids); 58 | res.json(resMsg(200)); 59 | } catch (error) { 60 | logger.error(error); 61 | res.json(resMsg()); 62 | } 63 | } 64 | 65 | /** 66 | * 更新图书 67 | * 68 | * @static 69 | * @param {*} req 70 | * @param {*} res 71 | * @param {*} next 72 | * @memberof bookListController 73 | */ 74 | static async updateBook(req, res, next) { 75 | let form = new formidable.IncomingForm(); 76 | form.encoding = uploadConfig.ENCODING; 77 | form.uploadDir = uploadConfig.SERVER_DIR + uploadConfig.BOOK_IMG_URL; 78 | form.keepExtensions = uploadConfig.KEEP_EXTENSIONS; 79 | form.maxFileSize = uploadConfig.MAX_FILESIZE; 80 | form.parse(req, async (error, fields, files) => { 81 | if (error) { 82 | logger.error(error); 83 | res.json(resMsg()); 84 | return false; 85 | } 86 | let data = fields; 87 | let { 88 | id, 89 | name, 90 | author, 91 | press, 92 | title, 93 | description, 94 | price, 95 | salePrice, 96 | isSell 97 | } = data; 98 | if (hasEmpty(id, name, author, press, title, description, price, salePrice, isSell)) { 99 | res.json(resMsg(9001)); 100 | return false; 101 | } 102 | if (files.imageUrl) { 103 | let extname = path.extname(files.imageUrl.name); 104 | let newPath = uploadConfig.SERVER_DIR + uploadConfig.BOOK_IMG_URL + data.id + extname.toLocaleLowerCase(); 105 | fs.renameSync(files.imageUrl.path, newPath); 106 | data.imageUrl = uploadConfig.SERVER_URL + uploadConfig.BOOK_IMG_URL + data.id + extname.toLocaleLowerCase(); 107 | } else { 108 | delete data.imageUrl; 109 | } 110 | await bookListModel.updateBook(data); 111 | res.json(resMsg(200)); 112 | }); 113 | form.on("error", function (error) { 114 | logger.error(error); 115 | res.json(resMsg()); 116 | return false; 117 | }); 118 | } 119 | 120 | /** 121 | * 新增图书 122 | * 123 | * @static 124 | * @param {*} req 125 | * @param {*} res 126 | * @param {*} next 127 | * @memberof bookListController 128 | */ 129 | static async insertBook(req, res, next) { 130 | let form = new formidable.IncomingForm(); 131 | form.encoding = uploadConfig.ENCODING; 132 | form.uploadDir = uploadConfig.SERVER_DIR + uploadConfig.BOOK_IMG_URL; 133 | form.keepExtensions = uploadConfig.KEEP_EXTENSIONS; 134 | form.maxFileSize = uploadConfig.MAX_FILESIZE; 135 | form.parse(req, async (error, fields, files) => { 136 | if (error) { 137 | logger.error(error); 138 | res.json(resMsg()); 139 | return false; 140 | } 141 | let data = fields; 142 | let { 143 | name, 144 | author, 145 | press, 146 | title, 147 | description, 148 | stock, 149 | stockPrice, 150 | price, 151 | salePrice, 152 | isSell 153 | } = data; 154 | if (hasEmpty(name, author, press, title, description, stock, stockPrice, price, salePrice, isSell)) { 155 | res.json(resMsg(9001)); 156 | return false; 157 | } 158 | delete data.imageUrl; 159 | let result = await bookListModel.insertBook([data]); 160 | let imageUrl = ""; 161 | if (files.imageUrl) { 162 | let extname = path.extname(files.imageUrl.name); 163 | let newPath = uploadConfig.SERVER_DIR + uploadConfig.BOOK_IMG_URL + result[0].id + extname.toLocaleLowerCase(); 164 | fs.renameSync(files.imageUrl.path, newPath); 165 | imageUrl = uploadConfig.SERVER_URL + uploadConfig.BOOK_IMG_URL + result[0].id + extname.toLocaleLowerCase(); 166 | let updateObj = { 167 | id: result[0].id, 168 | imageUrl 169 | }; 170 | await bookListModel.updateBook(updateObj); 171 | } 172 | let stockObj = { 173 | bookId: result[0].id, 174 | bookName: result[0].name, 175 | stockNum: stock, 176 | stockPrice, 177 | type: 0, 178 | remark: "新进图书:新进图书" 179 | }; 180 | await shopStockRecordModel.createStockRecord([stockObj]); 181 | res.json(resMsg(200)); 182 | }); 183 | form.on("error", function (error) { 184 | logger.error(error); 185 | res.json(resMsg()); 186 | return false; 187 | }); 188 | } 189 | 190 | /** 191 | * 修改库存 192 | * 193 | * @static 194 | * @param {*} req 195 | * @param {*} res 196 | * @param {*} next 197 | * @memberof bookListController 198 | */ 199 | static async updateBookStock(req, res, next) { 200 | try { 201 | if (hasEmpty(req.body.id, req.body.changeStock)) { 202 | res.json(resMsg(9001)); 203 | return false; 204 | } 205 | await bookListModel.updateBook({ 206 | id: req.body.id, 207 | stock: req.body.changeStock 208 | }); 209 | let stockObj = { 210 | bookId: req.body.id, 211 | bookName: req.body.name, 212 | stockNum: req.body.changeStock 213 | }; 214 | if (req.body.type === 0) { 215 | stockObj.stockPrice = req.body.stockPrice; 216 | stockObj.type = 1; 217 | stockObj.remark = "新进图书:增加库存"; 218 | } else { 219 | stockObj.type = 2; 220 | stockObj.remark = "删除库存:" + req.body.remark; 221 | } 222 | await shopStockRecordModel.createStockRecord([stockObj]); 223 | res.json(resMsg(200)); 224 | } catch (error) { 225 | logger.error(error); 226 | res.json(resMsg()); 227 | } 228 | } 229 | 230 | /** 231 | * 上传excel 232 | * 233 | * @static 234 | * @param {*} req 235 | * @param {*} res 236 | * @param {*} next 237 | * @memberof bookListController 238 | */ 239 | static async uploadExcel(req, res, next) { 240 | let excelUrl = uploadConfig.TEMP; 241 | let form = new formidable.IncomingForm(); 242 | let map = { 243 | 1: "A", 244 | 2: "B", 245 | 3: "C", 246 | 4: "D", 247 | 5: "E", 248 | 6: "F", 249 | 7: "G", 250 | 8: "H", 251 | 9: "I", 252 | 10: "J", 253 | 11: "K" 254 | }; 255 | let dataMap = { 256 | 0: "name", 257 | 1: "author", 258 | 2: "press", 259 | 3: "isSell", 260 | 4: "classify", 261 | 5: "title", 262 | 6: "description", 263 | 7: "stock", 264 | 8: "stockPrice", 265 | 9: "price", 266 | 10: "salePrice" 267 | }; 268 | const DATA_LENGTH = Object.keys(dataMap).length; 269 | form.encoding = uploadConfig.ENCODING; 270 | form.uploadDir = uploadConfig.SERVER_DIR + excelUrl; 271 | form.keepExtensions = uploadConfig.KEEP_EXTENSIONS; 272 | form.maxFileSize = uploadConfig.MAX_FILESIZE; 273 | let errorMsg = ""; 274 | form.parse(req, async (error, fields, files) => { 275 | if (error) { 276 | logger.error(error); 277 | res.json(resMsg()); 278 | return false; 279 | } 280 | // 读取文件 281 | const excelData = nodeXlsx.parse(files.excel.path); 282 | // 删除文件 283 | fs.unlink(files.excel.path, (error) => { 284 | if (error) { 285 | logger.error(error); 286 | } 287 | }); 288 | let optionData = excelData[0].data; 289 | let saveData = []; 290 | if (optionData.length > 1) { 291 | for (let i = 1, len = optionData.length; i < len; i++) { 292 | let data = optionData[i]; 293 | let saveDataObj = {}; 294 | for (let j = 0; j < DATA_LENGTH; j++) { 295 | let val = data[j]; 296 | if (j === 3) { 297 | if (hasEmpty(val)) { 298 | errorMsg = `第 ${i + 1} 行第 ${map[j + 1]} 列数据不能为空`; 299 | break; 300 | } 301 | if (val !== 1 && val !== 0) { 302 | errorMsg = `第 ${i + 1} 行第 ${map[j + 1]} 列数据格式不正确,只能为 0 或 1`; 303 | break; 304 | } 305 | } else if (j === 4) { 306 | if (!hasEmpty(val) && !/^\d(,\d)*$/.test(val)) { 307 | errorMsg = `第 ${i + 1} 行第 ${map[j + 1]} 列数据格式不正确,示例:'1' 或 '1,2,3'`; 308 | break; 309 | } 310 | } else if (j === 7) { 311 | if (hasEmpty(val)) { 312 | errorMsg = `第 ${i + 1} 行第 ${map[j + 1]} 列数据不能为空`; 313 | break; 314 | } 315 | if (!/^\d+$/.test(val)) { 316 | errorMsg = `第 ${i + 1} 行第 ${map[j + 1]} 列数据格式不正确,必须为大于0的数字`; 317 | break; 318 | } 319 | } else if (j === 8 || j === 9 || j === 10) { 320 | if (hasEmpty(val)) { 321 | errorMsg = `第 ${i + 1} 行第 ${map[j + 1]} 列数据不能为空`; 322 | break; 323 | } 324 | if (!/^\d+(\.\d{0,2})?$/.test(val)) { 325 | errorMsg = `第 ${i + 1} 行第 ${map[j + 1]} 列数据格式不正确,必须为大于0的数字,最多保留两位小数`; 326 | break; 327 | } 328 | } else if (hasEmpty(val)) { 329 | errorMsg = `第 ${i + 1} 行第 ${map[j + 1]} 列数据不能为空`; 330 | break; 331 | } 332 | saveDataObj[dataMap[j]] = val; 333 | } 334 | if (errorMsg) { 335 | break; 336 | } 337 | saveData.push(saveDataObj); 338 | } 339 | if (errorMsg) { 340 | logger.error(errorMsg); 341 | res.json({ 342 | errorCode: 9999, 343 | errorMsg: errorMsg, 344 | data: "" 345 | }); 346 | return false; 347 | } else { 348 | let result = await bookListModel.insertBook(saveData); 349 | let saveStockData = []; 350 | for (let i = 0, len = result.length; i < len; i++) { 351 | let item = result[i]; 352 | let saveStockObj = { 353 | bookId: item.id, 354 | bookName: item.name, 355 | stockNum: item.stock, 356 | stockPrice: item.stockPrice, 357 | type: 0, 358 | remark: "新进图书:新进图书" 359 | }; 360 | saveStockData.push(saveStockObj); 361 | } 362 | await shopStockRecordModel.createStockRecord(saveStockData); 363 | res.json(resMsg(200)); 364 | } 365 | } else { 366 | logger.error("上传文件内容为空"); 367 | res.json(resMsg(2001)); 368 | return false; 369 | } 370 | }); 371 | form.on("error", function (error) { 372 | logger.error(error); 373 | res.json(resMsg()); 374 | return false; 375 | }); 376 | } 377 | 378 | /** 379 | * 下载上传模板 380 | * 381 | * @static 382 | * @param {*} req 383 | * @param {*} res 384 | * @param {*} next 385 | * @memberof bookListController 386 | */ 387 | static async downloadBookTemplate(req, res, next) { 388 | let filePath = uploadConfig.SERVER_DIR + "/" + uploadConfig.ZIP_NAME; 389 | let classifyData = await bookListModel.getAllClassify(); 390 | let name = uploadConfig.CLASSIFY_EXCEL_NAME; 391 | let zipName = uploadConfig.ZIP_NAME; 392 | let data = [ 393 | ["id", "分类名"] 394 | ]; 395 | for (var i = 0, len = classifyData.length; i < len; i++) { 396 | let temp = []; 397 | temp[0] = classifyData[i].id; 398 | temp[1] = classifyData[i].name; 399 | data.push(temp); 400 | } 401 | var buffer = nodeXlsx.build([{ 402 | name, 403 | data 404 | }]); 405 | // 生成类别对照表excel 406 | fs.writeFile(uploadConfig.SERVER_DIR + uploadConfig.BOOK_TEMPLATE + "/" + name, buffer, (err) => { 407 | if (err) { 408 | logger.error(err); 409 | res.json(resMsg()); 410 | return false; 411 | } 412 | // 压缩为zip 413 | let output = fs.createWriteStream(uploadConfig.SERVER_DIR + "/" + zipName); 414 | let archive = nodeZip("zip"); 415 | archive.on("error", (err) => { 416 | logger.error(err); 417 | res.json(resMsg()); 418 | return false; 419 | }); 420 | archive.pipe(output); 421 | archive.directory(uploadConfig.SERVER_DIR + uploadConfig.BOOK_TEMPLATE, false); 422 | archive.finalize(); 423 | output.on("close", () => { 424 | res.download(filePath); 425 | }); 426 | }); 427 | } 428 | 429 | /** 430 | * 获取所有分类信息 431 | * 432 | * @static 433 | * @param {*} req 434 | * @param {*} res 435 | * @param {*} next 436 | * @returns 437 | * @memberof bookListController 438 | */ 439 | static async getAllClassify(req, res, next) { 440 | try { 441 | let result = await bookListModel.getAllClassify(); 442 | res.json(resMsg(200, result)); 443 | } catch (error) { 444 | logger.error(error); 445 | res.json(resMsg()); 446 | } 447 | } 448 | 449 | /** 450 | * 删除分类信息 451 | * 452 | * @static 453 | * @param {*} req 454 | * @param {*} res 455 | * @param {*} next 456 | * @returns 457 | * @memberof bookListController 458 | */ 459 | static async deleteClassify(req, res, next) { 460 | try { 461 | if (hasEmpty(req.body.id)) { 462 | res.json(resMsg(9001)); 463 | return false; 464 | } 465 | await bookListModel.deleteClassify(req.body.id); 466 | res.json(resMsg(200)); 467 | } catch (error) { 468 | logger.error(error); 469 | res.json(resMsg()); 470 | } 471 | } 472 | 473 | /** 474 | * 新增分类 475 | * 476 | * @static 477 | * @param {*} req 478 | * @param {*} res 479 | * @param {*} next 480 | * @returns 481 | * @memberof bookListController 482 | */ 483 | static async addClassify(req, res, next) { 484 | try { 485 | if (hasEmpty(req.body.classifyName)) { 486 | res.json(resMsg(9001)); 487 | return false; 488 | } 489 | await bookListModel.addClassify(req.body.classifyName); 490 | res.json(resMsg(200)); 491 | } catch (error) { 492 | logger.error(error); 493 | res.json(resMsg()); 494 | } 495 | } 496 | 497 | /** 498 | * 批量修改图书上下架 499 | * 500 | * @static 501 | * @param {*} req 502 | * @param {*} res 503 | * @param {*} next 504 | * @returns 505 | * @memberof bookListController 506 | */ 507 | static async changeBookSellStatus(req, res, next) { 508 | try { 509 | if (hasEmpty(req.body.isSell, req.body.ids)) { 510 | res.json(resMsg(9001)); 511 | return false; 512 | } 513 | await bookListModel.changeBookSellStatus(req.body.isSell, req.body.ids); 514 | res.json(resMsg(200)); 515 | } catch (error) { 516 | logger.error(error); 517 | res.json(resMsg()); 518 | } 519 | } 520 | 521 | /** 522 | * 分页获取进货记录 523 | * 524 | * @static 525 | * @param {*} req 526 | * @param {*} res 527 | * @param {*} next 528 | * @memberof bookListController 529 | */ 530 | static async getStockRecordList(req, res, next) { 531 | try { 532 | if (hasEmpty(req.body.pageSize, req.body.pageNumber, req.body.startTime, req.body.endTime)) { 533 | res.json(resMsg(9001)); 534 | return false; 535 | } 536 | let result = await shopStockRecordModel.getStockRecordList(req.body); 537 | res.json(resMsg(200, result)); 538 | } catch (error) { 539 | logger.error(error); 540 | res.json(resMsg()); 541 | } 542 | } 543 | } 544 | 545 | module.exports = bookListController; --------------------------------------------------------------------------------