lrf 2 年之前
當前提交
bb66d2642a

+ 1 - 0
.eslintignore

@@ -0,0 +1 @@
+coverage

+ 4 - 0
.eslintrc

@@ -0,0 +1,4 @@
+{
+  "extends": "eslint-config-egg",
+  "root": true
+}

+ 46 - 0
.github/workflows/nodejs.yml

@@ -0,0 +1,46 @@
+# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
+# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
+
+name: Node.js CI
+
+on:
+  push:
+    branches:
+      - main
+      - master
+  pull_request:
+    branches:
+      - main
+      - master
+  schedule:
+    - cron: '0 2 * * *'
+
+jobs:
+  build:
+    runs-on: ${{ matrix.os }}
+
+    strategy:
+      fail-fast: false
+      matrix:
+        node-version: [16]
+        os: [ubuntu-latest, windows-latest, macos-latest]
+
+    steps:
+    - name: Checkout Git Source
+      uses: actions/checkout@v2
+
+    - name: Use Node.js ${{ matrix.node-version }}
+      uses: actions/setup-node@v1
+      with:
+        node-version: ${{ matrix.node-version }}
+
+    - name: Install Dependencies
+      run: npm i
+
+    - name: Continuous Integration
+      run: npm run ci
+
+    - name: Code Coverage
+      uses: codecov/codecov-action@v1
+      with:
+        token: ${{ secrets.CODECOV_TOKEN }}

+ 14 - 0
.gitignore

@@ -0,0 +1,14 @@
+logs/
+npm-debug.log
+yarn-error.log
+node_modules/
+*-lock.yaml
+yarn.lock
+coverage/
+.idea/
+run/
+.DS_Store
+*.sw*
+*.un~
+typings/
+.nyc_output/

+ 33 - 0
README.md

@@ -0,0 +1,33 @@
+# service-point_shop
+
+
+
+## QuickStart
+
+<!-- add docs here for user -->
+
+see [egg docs][egg] for more detail.
+
+### Development
+
+```bash
+$ npm i
+$ npm run dev
+$ open http://localhost:7001/
+```
+
+### Deploy
+
+```bash
+$ npm start
+$ npm stop
+```
+
+### npm scripts
+
+- Use `npm run lint` to check code style.
+- Use `npm test` to run unit test.
+- Use `npm run autod` to auto detect dependencies upgrade, see [autod](https://www.npmjs.com/package/autod) for more detail.
+
+
+[egg]: https://eggjs.org

+ 43 - 0
app/controller/config/.zrGoods.js

@@ -0,0 +1,43 @@
+module.exports = {
+  create: {
+    requestBody: ['cost', 'shop', 'name', 'shot_brief', 'send_time', 'brief', 'file', 'view_num', 'sell_num', 'status', 'sort'],
+  },
+  destroy: {
+    params: ['!id'],
+    service: 'delete',
+  },
+  update: {
+    params: ['!id'],
+    requestBody: ['cost', 'shop', 'name', 'shot_brief', 'send_time', 'brief', 'file', 'view_num', 'sell_num', 'status', 'sort'],
+  },
+  show: {
+    parameters: {
+      params: ['!id'],
+    },
+    service: 'fetch',
+  },
+  index: {
+    parameters: {
+      query: {
+        'meta.createdAt@start': 'meta.createdAt@start',
+        'meta.createdAt@end': 'meta.createdAt@end',
+        shop: 'shop',
+        name: 'name',
+        view_num: 'view_num',
+        sell_num: 'sell_num',
+        status: 'status',
+        sort: 'sort',
+      },
+      // options: {
+      //   "meta.state": 0 // 默认条件
+      // },
+    },
+    service: 'query',
+    options: {
+      query: ['skip', 'limit'],
+      sort: ['meta.createdAt'],
+      desc: true,
+      count: true,
+    },
+  },
+};

+ 42 - 0
app/controller/config/.zrOrder.js

@@ -0,0 +1,42 @@
+module.exports = {
+  create: {
+    requestBody: ['customer', 'shop', 'goods', 'buy_num', 'buy_time', 'no', 'address', 'transport', 'remarks', 'status'],
+  },
+  destroy: {
+    params: ['!id'],
+    service: 'delete',
+  },
+  update: {
+    params: ['!id'],
+    requestBody: ['customer', 'shop', 'goods', 'buy_num', 'buy_time', 'no', 'address', 'transport', 'remarks', 'status'],
+  },
+  show: {
+    parameters: {
+      params: ['!id'],
+    },
+    service: 'fetch',
+  },
+  index: {
+    parameters: {
+      query: {
+        'meta.createdAt@start': 'meta.createdAt@start',
+        'meta.createdAt@end': 'meta.createdAt@end',
+        customer: 'customer',
+        shop: 'shop',
+        goods: 'goods',
+        no: 'no',
+        status: 'status',
+      },
+      // options: {
+      //   "meta.state": 0 // 默认条件
+      // },
+    },
+    service: 'query',
+    options: {
+      query: ['skip', 'limit'],
+      sort: ['meta.createdAt'],
+      desc: true,
+      count: true,
+    },
+  },
+};

+ 12 - 0
app/controller/home.js

@@ -0,0 +1,12 @@
+'use strict';
+
+const { Controller } = require('egg');
+
+class HomeController extends Controller {
+  async index() {
+    const { ctx } = this;
+    ctx.body = 'hi, egg';
+  }
+}
+
+module.exports = HomeController;

+ 13 - 0
app/controller/zrGoods.js

@@ -0,0 +1,13 @@
+'use strict';
+const meta = require('./config/.zrGoods.js');
+const Controller = require('egg').Controller;
+const { CrudController } = require('naf-framework-mongoose-free/lib/controller');
+
+//
+class ZrGoodsController extends Controller {
+  constructor(ctx) {
+    super(ctx);
+    this.service = this.ctx.service.zrGoods;
+  }
+}
+module.exports = CrudController(ZrGoodsController, meta);

+ 13 - 0
app/controller/zrOrder.js

@@ -0,0 +1,13 @@
+'use strict';
+const meta = require('./config/.zrOrder.js');
+const Controller = require('egg').Controller;
+const { CrudController } = require('naf-framework-mongoose-free/lib/controller');
+
+// 
+class ZrOrderController extends Controller {
+  constructor(ctx) {
+    super(ctx);
+    this.service = this.ctx.service.zrOrder;
+  }
+}
+module.exports = CrudController(ZrOrderController, meta);

+ 37 - 0
app/extend/context.js

@@ -0,0 +1,37 @@
+'use strict';
+const Decimal = require('decimal.js');
+// Decimal.set({ precision: 2 });
+module.exports = {
+  // 加法
+  plus(n1 = 0, n2 = 0) {
+    const number1 = new Decimal(n1);
+    const number2 = new Decimal(n2);
+    const result = number1.add(number2).toFixed(2, Decimal.ROUND_DOWN);
+    return this.toNumber(result);
+  },
+  // 减法
+  minus(n1 = 0, n2 = 0) {
+    const number1 = new Decimal(n1);
+    const number2 = new Decimal(n2);
+    const result = number1.minus(number2).toFixed(2, Decimal.ROUND_DOWN);
+    return this.toNumber(result);
+  },
+  // 乘法
+  multiply(n1 = 0, n2 = 0) {
+    const number1 = new Decimal(n1);
+    const number2 = new Decimal(n2);
+    const result = number1.mul(number2).toFixed(2, Decimal.ROUND_DOWN);
+    return this.toNumber(result);
+  },
+  // 除法
+  divide(n1 = 0, n2 = 0) {
+    const number1 = new Decimal(n1);
+    const number2 = new Decimal(n2);
+    const result = number1.div(number2).toFixed(2, Decimal.ROUND_DOWN);
+    return this.toNumber(result);
+  },
+
+  toNumber(num) {
+    return new Decimal(num).toNumber();
+  },
+};

+ 34 - 0
app/model/base/shop.js

@@ -0,0 +1,34 @@
+'use strict';
+const Schema = require('mongoose').Schema;
+const metaPlugin = require('naf-framework-mongoose-free/lib/model/meta-plugin');
+
+// 商店信息
+const shop = {
+  logo: { type: Array, required: false, zh: '店铺logo' }, //
+  name: { type: String, required: false, zh: '商店名称' }, //
+  code: { type: String, required: false, zh: '店铺编号' }, // 自增,中间件处理
+  person: { type: String, required: false, zh: '店主' }, //
+  phone: { type: String, required: false, zh: '联系电话' }, //
+  address: { type: String, required: false, zh: '地址' }, //
+  file: { type: Array, required: false, zh: '证件照片' }, //
+  status: { type: String, required: false, zh: '店铺状态' }, // 字典:shop_status
+  goods_score: { type: Number, required: false, default: 5, zh: '商品评分' }, //
+  send_score: { type: Number, required: false, default: 5, zh: '发货评分' }, //
+  service_score: { type: Number, required: false, default: 5, zh: '服务评分' }, //
+  qrcode: { type: Array, required: false, zh: '二维码' }, //
+};
+const schema = new Schema(shop, { toJSON: { getters: true, virtuals: true } });
+schema.index({ id: 1 });
+schema.index({ 'meta.createdAt': 1 });
+schema.index({ name: 1 });
+schema.index({ code: 1 });
+schema.index({ person: 1 });
+schema.index({ phone: 1 });
+schema.index({ status: 1 });
+
+schema.plugin(metaPlugin);
+module.exports = app => {
+  const { mongoose } = app;
+  return mongoose.model('Shop', schema, 'shop');
+};
+

+ 36 - 0
app/model/zrGoods.js

@@ -0,0 +1,36 @@
+'use strict';
+const Schema = require('mongoose').Schema;
+const metaPlugin = require('naf-framework-mongoose-free/lib/model/meta-plugin');
+
+const MoneyPlugin = require('naf-framework-mongoose-free/lib/model/type-money-plugin');
+
+// 尊荣商品
+const zrGoods = {
+  shop: { type: String, required: false, zh: '店铺', ref: 'Base.Shop' }, //
+  name: { type: String, required: false, zh: '商品名称' }, //
+  shot_brief: { type: String, required: false, zh: '简短简介' }, //
+  send_time: { type: String, required: false, zh: '发货时间' }, //
+  brief: { type: String, required: false, zh: '商品介绍' }, //
+  file: { type: String, required: false, zh: '商品图片' }, //
+  view_num: { type: String, required: false, zh: '浏览量' }, //
+  sell_num: { type: String, required: false, zh: '销量' }, //
+  status: { type: String, required: false, zh: '商品状态' }, //
+  sort: { type: Number, required: false, zh: '排序' }, //
+};
+const schema = new Schema(zrGoods, { toJSON: { getters: true, virtuals: true } });
+schema.index({ id: 1 });
+schema.index({ 'meta.createdAt': 1 });
+schema.index({ shop: 1 });
+schema.index({ name: 1 });
+schema.index({ view_num: 1 });
+schema.index({ sell_num: 1 });
+schema.index({ status: 1 });
+schema.index({ sort: 1 });
+
+schema.plugin(metaPlugin);
+schema.plugin(MoneyPlugin({ zh: '消耗尊荣', required: false, key: 'cost' }));
+
+module.exports = app => {
+  const { mongoose } = app;
+  return mongoose.model('ZrGoods', schema, 'zrGoods');
+};

+ 32 - 0
app/model/zrOrder.js

@@ -0,0 +1,32 @@
+'use strict';
+const Schema = require('mongoose').Schema;
+const metaPlugin = require('naf-framework-mongoose-free/lib/model/meta-plugin');
+
+// 订单
+const zrOrder = {
+  customer: { type: String, required: false, zh: '顾客', ref: 'Base.User' }, //
+  shop: { type: String, required: false, zh: '店铺', ref: 'Base.Shop' }, //
+  goods: { type: String, required: false, zh: '商品', ref: 'ZrGoods' }, // 快照
+  buy_num: { type: Number, required: false, zh: '购买数量' }, //
+  buy_time: { type: String, required: false, zh: '购买时间' }, //
+  no: { type: String, required: false, zh: '订单号' }, //
+  address: { type: Object, required: false, zh: '地址' }, // 快照
+  transport: { type: Object, required: false, zh: '快递信息' }, //
+  remarks: { type: String, required: false, zh: '备注' }, //
+  status: { type: String, required: false, zh: '订单状态' }, //
+};
+const schema = new Schema(zrOrder, { toJSON: { getters: true, virtuals: true } });
+schema.index({ id: 1 });
+schema.index({ 'meta.createdAt': 1 });
+schema.index({ customer: 1 });
+schema.index({ shop: 1 });
+schema.index({ goods: 1 });
+schema.index({ no: 1 });
+schema.index({ status: 1 });
+
+schema.plugin(metaPlugin);
+
+module.exports = app => {
+  const { mongoose } = app;
+  return mongoose.model('ZrOrder', schema, 'zrOrder');
+};

+ 27 - 0
app/public/routerRegister.js

@@ -0,0 +1,27 @@
+'use strict';
+/**
+ * 注册路由
+ * @param {App} app 全局变量
+ * @param {Array} routes 路由数组
+ * @param {String} keyZh 路由主题
+ * @param {String} rkey 路由主位置的标识
+ * @param {String} ckey 路由对应的controller的标识
+ */
+const _ = require('lodash');
+module.exports = (app, routes, keyZh, rkey, ckey) => {
+  const { router, config } = app;
+  const mwares = app.middleware;
+  if (process.env.NODE_ENV === 'development') console.log(`${keyZh}:  ${rkey}`);
+  for (const route of routes) {
+    const { method, path, controller: ctl, zh } = route;
+    let { middleware = [] } = route;
+    if (!method || !path || !ctl) continue;
+    // 拼全路径
+    const allPath = `${config.routePrefix}/${path}`;
+    if (process.env.NODE_ENV === 'development') console.log(`     ${zh}: ${allPath}`);
+    // 处理中间件
+    if (middleware.length > 0) middleware = middleware.map(i => _.get(mwares, i)({ enable: true, model: ckey || rkey }));
+    // 注册路由
+    router[method](zh, allPath, ...middleware, ctl);
+  }
+};

+ 11 - 0
app/router.js

@@ -0,0 +1,11 @@
+'use strict';
+
+/**
+ * @param {Egg.Application} app - egg application
+ */
+module.exports = app => {
+  const { router, controller } = app;
+  router.get('/', controller.home.index);
+  require('./z_router/zrOrder')(app); // 尊荣订单
+  require('./z_router/zrGoods')(app); // 尊荣商品
+};

+ 15 - 0
app/service/zrGoods.js

@@ -0,0 +1,15 @@
+'use strict';
+const { CrudService } = require('naf-framework-mongoose-free/lib/service');
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+const _ = require('lodash');
+const assert = require('assert');
+
+//
+class ZrGoodsService extends CrudService {
+  constructor(ctx) {
+    super(ctx, 'zrgoods');
+    this.model = this.ctx.model.Business.ZrGoods;
+  }
+}
+
+module.exports = ZrGoodsService;

+ 14 - 0
app/service/zrOrder.js

@@ -0,0 +1,14 @@
+'use strict';
+const { CrudService } = require('naf-framework-mongoose-free/lib/service');
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+const _ = require('lodash');
+const assert = require('assert');
+//
+class ZrOrderService extends CrudService {
+  constructor(ctx) {
+    super(ctx, 'zrorder');
+    this.model = this.ctx.model.ZrOrder;
+  }
+}
+
+module.exports = ZrOrderService;

+ 19 - 0
app/z_router/zrGoods.js

@@ -0,0 +1,19 @@
+'use strict';
+// 路由配置
+const path = require('path');
+const regPath = path.resolve('app', 'public', 'routerRegister');
+const routerRegister = require(regPath);
+const rkey = 'zrGoods';
+const ckey = 'zrGoods';
+const keyZh = '尊荣商品';
+const routes = [
+  { method: 'get', path: `${rkey}`, controller: `${ckey}.index`, name: `${ckey}Query`, zh: `${keyZh}列表查询` },
+  { method: 'get', path: `${rkey}/:id`, controller: `${ckey}.show`, name: `${ckey}Show`, zh: `${keyZh}查询` },
+  { method: 'post', path: `${rkey}`, controller: `${ckey}.create`, name: `${ckey}Create`, zh: `创建${keyZh}` },
+  { method: 'post', path: `${rkey}/:id`, controller: `${ckey}.update`, name: `${ckey}Update`, zh: `修改${keyZh}` },
+  { method: 'delete', path: `${rkey}/:id`, controller: `${ckey}.destroy`, name: `${ckey}Delete`, zh: `删除${keyZh}` },
+];
+
+module.exports = app => {
+  routerRegister(app, routes, keyZh, rkey, ckey);
+};

+ 19 - 0
app/z_router/zrOrder.js

@@ -0,0 +1,19 @@
+'use strict';
+// 路由配置
+const path = require('path');
+const regPath = path.resolve('app', 'public', 'routerRegister');
+const routerRegister = require(regPath);
+const rkey = 'zrOrder';
+const ckey = 'zrOrder';
+const keyZh = '尊荣订单';
+const routes = [
+  { method: 'get', path: `${rkey}`, controller: `${ckey}.index`, name: `${ckey}Query`, zh: `${keyZh}列表查询` },
+  { method: 'get', path: `${rkey}/:id`, controller: `${ckey}.show`, name: `${ckey}Show`, zh: `${keyZh}查询` },
+  { method: 'post', path: `${rkey}`, controller: `${ckey}.create`, name: `${ckey}Create`, zh: `创建${keyZh}` },
+  { method: 'post', path: `${rkey}/:id`, controller: `${ckey}.update`, name: `${ckey}Update`, zh: `修改${keyZh}` },
+  { method: 'delete', path: `${rkey}/:id`, controller: `${ckey}.destroy`, name: `${ckey}Delete`, zh: `删除${keyZh}` },
+];
+
+module.exports = app => {
+  routerRegister(app, routes, keyZh, rkey, ckey);
+};

+ 78 - 0
config/config.default.js

@@ -0,0 +1,78 @@
+/* eslint valid-jsdoc: "off" */
+
+'use strict';
+
+/**
+ * @param {Egg.EggAppInfo} appInfo app info
+ */
+const { jwt } = require('./config.secret');
+module.exports = appInfo => {
+  /**
+   * built-in config
+   * @type {Egg.EggAppConfig}
+   **/
+  const config = (exports = {});
+
+  // use for cookie sign key, should change to your own and keep security
+  config.keys = appInfo.name + '_1666686710616_3993';
+  config.appName = '天恩活泉商城-服务';
+
+  // add your middleware config here
+  config.middleware = [];
+  config.checkToken = {
+    enable: false,
+  };
+  // 进程设置
+  config.cluster = {
+    listen: {
+      port: 12112,
+    },
+  };
+  // 数据库设置
+  config.dbName = 'point_shopping';
+  config.mongoose = {
+    url: `mongodb://120.48.146.1:27017/${config.dbName}`, // 120.48.146.1 127.0.0.1
+    options: {
+      user: 'admin',
+      pass: 'admin',
+      authSource: 'admin',
+      useNewUrlParser: true,
+      useCreateIndex: true,
+      useFindAndModify: true,
+      allowDiskUse: true,
+    },
+  };
+  // jwt设置
+  config.jwt = {
+    ...jwt,
+    expiresIn: '1d',
+    issuer: 'shopping',
+  };
+  // 路由设置
+  config.routePrefix = '/point/zr/v1/api';
+  config.emailConfig = {
+    config: 'free',
+  };
+  config.smsConfig = {
+    config: 'free',
+  };
+  // 中间件
+  config.requestLog = {
+    toMongoDB: true,
+  };
+
+  config.redisKey = {
+    orderKeyPrefix: 'orderKey:',
+  };
+  config.redisTimeout = 3600;
+  config.wxPayConfig = 'pointApp';
+  // add your user config here
+  const userConfig = {
+    // myAppName: 'egg',
+  };
+
+  return {
+    ...config,
+    ...userConfig,
+  };
+};

+ 47 - 0
config/config.prod.js

@@ -0,0 +1,47 @@
+'use strict';
+module.exports = appInfo => {
+  const config = (exports = {});
+  // 数据库设置
+  config.dbName = 'point_shopping';
+  config.mongoose = {
+    url: `mongodb://127.0.0.1:27017/${config.dbName}`, // 120.48.146.1 127.0.0.1
+    options: {
+      user: 'admin',
+      pass: 'admin',
+      authSource: 'admin',
+      useNewUrlParser: true,
+      useCreateIndex: true,
+      useFindAndModify: true,
+    },
+  };
+  // mq设置
+  config.amqp = {
+    client: {
+      hostname: '127.0.0.1',
+      username: 'tehq',
+      password: 'tehq',
+      vhost: 'tehq',
+    },
+    app: true,
+    agent: true,
+  };
+  // redis设置
+  config.redis = {
+    client: {
+      port: 6379, // Redis port
+      host: '127.0.0.1', // Redis host
+      password: '123456',
+      db: 1,
+    },
+  };
+  config.emailConfig = {
+    config: 'tehq',
+  };
+  config.smsConfig = {
+    config: 'tehq',
+  };
+  config.wxPayConfig = 'tnhqApp';
+  return {
+    ...config,
+  };
+};

+ 7 - 0
config/config.secret.js

@@ -0,0 +1,7 @@
+'use strict';
+
+module.exports = {
+  jwt: {
+    secret: 'Ziyouyanfa!@#',
+  },
+};

+ 10 - 0
config/plugin.js

@@ -0,0 +1,10 @@
+'use strict';
+exports.redis = {
+  enable: true,
+  package: 'egg-redis',
+};
+
+exports.amqp = {
+  enable: true,
+  package: 'egg-naf-amqp',
+};

File diff suppressed because it is too large
+ 30491 - 0
package-lock.json


+ 55 - 0
package.json

@@ -0,0 +1,55 @@
+{
+  "name": "service-point_shop",
+  "version": "1.0.0",
+  "description": "",
+  "private": true,
+  "egg": {
+    "framework": "naf-framework-mongoose-free"
+  },
+  "dependencies": {
+    "decimal.js": "^10.4.1",
+    "egg": "^2",
+    "egg-naf-amqp": "^0.0.13",
+    "egg-redis": "^2.4.0",
+    "egg-scripts": "^2",
+    "jsonwebtoken": "^8.5.1",
+    "lodash": "^4.17.21",
+    "moment": "^2.29.4",
+    "mongoose-transactions": "^1.1.4",
+    "naf-framework-mongoose-free": "^0.0.37"
+  },
+  "devDependencies": {
+    "autod": "^3",
+    "autod-egg": "^1",
+    "egg-bin": "^4",
+    "egg-ci": "^2",
+    "egg-mock": "^4",
+    "eslint": "^8",
+    "eslint-config-egg": "^12"
+  },
+  "engines": {
+    "node": ">=16.0.0"
+  },
+  "scripts": {
+    "start": "egg-scripts start --daemon --title=egg-server-server",
+    "stop": "egg-scripts stop --title=egg-server-server",
+    "dev": "egg-bin dev",
+    "debug": "egg-bin debug",
+    "test": "npm run lint -- --fix && npm run test-local",
+    "test-local": "egg-bin test",
+    "cov": "egg-bin cov",
+    "lint": "eslint .",
+    "ci": "npm run lint && npm run cov",
+    "autod": "autod"
+  },
+  "ci": {
+    "version": "16",
+    "type": "github"
+  },
+  "repository": {
+    "type": "git",
+    "url": ""
+  },
+  "author": "",
+  "license": "MIT"
+}

+ 20 - 0
test/app/controller/home.test.js

@@ -0,0 +1,20 @@
+'use strict';
+
+const { app, assert } = require('egg-mock/bootstrap');
+
+describe('test/app/controller/home.test.js', () => {
+  it('should assert', async () => {
+    const pkg = require('../../../package.json');
+    assert(app.config.keys.startsWith(pkg.name));
+
+    // const ctx = app.mockContext({});
+    // yield ctx.service.xx();
+  });
+
+  it('should GET /', async () => {
+    return app.httpRequest()
+      .get('/')
+      .expect('hi, egg')
+      .expect(200);
+  });
+});