lrf402788946 4 years ago
parent
commit
214b830502
4 changed files with 276 additions and 10 deletions
  1. 2 0
      app/controller/.card.js
  2. 2 0
      app/model/card.js
  3. 21 0
      app/schedule/carshow.js
  4. 251 10
      app/service/card.js

+ 2 - 0
app/controller/.card.js

@@ -58,6 +58,8 @@ module.exports = {
         level: "level",
         level: "level",
         recommend: "%recommend%",
         recommend: "%recommend%",
         r_mobile: "r_mobile",
         r_mobile: "r_mobile",
+        car_show: "car_show",
+        stockholder: "stockholder",
         "create_time@start": "create_time@start",
         "create_time@start": "create_time@start",
         "create_time@end": "create_time@end",
         "create_time@end": "create_time@end",
       },
       },

+ 2 - 0
app/model/card.js

@@ -25,6 +25,8 @@ const card = {
   recommend: { type: String }, // 推荐人
   recommend: { type: String }, // 推荐人
   r_mobile: { type: String }, // 推荐人电话
   r_mobile: { type: String }, // 推荐人电话
   zf: { type: zf }, // 支付设置
   zf: { type: zf }, // 支付设置
+  car_show: { type: Boolean, default: false }, // 车奖
+  stockholder: { type: Boolean, default: false }, // 股东
   create_time: {
   create_time: {
     type: String,
     type: String,
     default: moment().format('YYYY-MM-DD HH:mm:ss'),
     default: moment().format('YYYY-MM-DD HH:mm:ss'),

+ 21 - 0
app/schedule/carshow.js

@@ -0,0 +1,21 @@
+'use strict';
+
+const Subscription = require('egg').Subscription;
+
+class CheckCheck extends Subscription {
+  // 通过 schedule 属性来设置定时任务的执行间隔等配置
+  // 更改执行时间
+  static get schedule() {
+    return {
+      cron: '0 0 0 * * *',
+      // interval: '1d',
+      type: 'worker', // 指定所有的 worker 都需要执行
+    };
+  }
+
+  // subscribe 是真正定时任务执行时被运行的函数
+  async subscribe() {
+    // await this.ctx.service.system.schedule.check();
+  }
+}
+module.exports = CheckCheck;

+ 251 - 10
app/service/card.js

@@ -2,26 +2,267 @@
 const { CrudService } = require('naf-framework-mongoose/lib/service');
 const { CrudService } = require('naf-framework-mongoose/lib/service');
 const { BusinessError, ErrorCode } = require('naf-core').Error;
 const { BusinessError, ErrorCode } = require('naf-core').Error;
 const { ObjectId } = require('mongoose').Types;
 const { ObjectId } = require('mongoose').Types;
-
+const _ = require('lodash');
+const moment = require('moment');
+/**
+ * 核心逻辑
+ *            .         A
+ *           /_\        B
+ *          /_ _\       C crime
+ *         /_ _ _\      D crime
+ *        /_ _ _ _\     E crime
+ */
 class CardService extends CrudService {
 class CardService extends CrudService {
   constructor(ctx) {
   constructor(ctx) {
     super(ctx, 'card');
     super(ctx, 'card');
     this.model = this.ctx.model.Card;
     this.model = this.ctx.model.Card;
+    /**
+     * @constant Number 车奖的积分
+     */
+    this.car_point = 131400;
+    /**
+     * @constant Number 股东的积分
+     */
+    this.stockholder_point = 10;
+    /**
+     * @constant Number 股东的单数界限,前xxxx单不是股东
+     */
+    this.stockholder_limit = 9999;
   }
   }
-  async create(data) {
-    const { password, mobile } = data;
-    const is_exists = await this.model.count({ mobile });
-    if (is_exists) throw new BusinessError(ErrorCode.DATA_EXISTED, '手机号已存在');
-    data.password = { secret: password };
-    const res = await this.model.create(data);
-    return res;
-  }
-
+  /**
+   * 修改密码
+   * @param {Object} param 参数
+   */
   async passwd({ id, password }) {
   async passwd({ id, password }) {
     password = { secret: password };
     password = { secret: password };
     const res = await this.model.update({ _id: ObjectId(id) }, { password });
     const res = await this.model.update({ _id: ObjectId(id) }, { password });
     return res;
     return res;
   }
   }
+
+  /**
+   * 1创建卡用户;2检查推荐人
+   * @param {Object} data 参数
+   */
+  async create(data) {
+    // 先创建用户
+    // 1,检查手机号是否存在
+    const { password, mobile, set, r_mobile } = data;
+    const is_exists = await this.model.count({ mobile });
+    if (is_exists) { throw new BusinessError(ErrorCode.DATA_EXISTED, '手机号已存在'); }
+    // 2,创建用户
+    let user;
+    try {
+      data.password = { secret: password };
+      user = await this.model.create(data);
+    } catch (e) {
+      throw new BusinessError(
+        ErrorCode.SERVICE_FAULT,
+        '输入信息有误,用户创建失败!'
+      );
+    }
+    // 3,检查有没有推荐人,如果没有推荐人,那就完事了,有推荐人,还需要检查给推荐人加多少分
+    if (!r_mobile) return user;
+    const recommender = await this.model.findOne({ mobile: r_mobile });
+    if (!recommender) {
+      await this.model.deleteOne({ _id: user._id });
+      throw new BusinessError(
+        ErrorCode.SERVICE_FAULT,
+        '推荐人信息错误,用户创建失败!'
+      );
+    }
+    // 4,判断是129套餐,还是169套餐,如果是129套餐,那就不需要继续了
+    if (set === '129') return user;
+    // 5,接下来,查看推荐人下已经有了多少人
+    const a_recer = await this.model.count(r_mobile);
+    // 根据等级,找下推荐人应该加多少分
+    const { level, car_show, stockholder } = a_recer;
+    const rank = this.getRank().find(f => `${f.rank}` === `${level}`);
+    if (!rank) {
+      // TODO 告知推荐人,等级信息有错误,中断,返回用户添加成功
+      return user;
+    }
+    let { score } = rank;
+    // TODO,需要检查股东奖,是否需要+10
+    if (stockholder) score = score + this.stockholder_point;
+    else {
+      // TODO 去写检查是不是股东的问题
+      const result = await this.checkStockholder(a_recer);
+      if (result === undefined) {
+        // TODO 告知推荐人,股东检测有错误,中断,返回用户添加成功
+        return user;
+      }
+      // 这次加上这个用户就是股东了
+      if (result) {
+        // 此情况主要讨论的是 9999 单时,是否加=>9999单时,不加
+        a_recer.stockholder = true;
+        score = score + 10;
+      }
+    }
+    // 加积分
+    a_recer.points = a_recer.points + score;
+    // 重新计算推荐人用户等级
+    const nlevel = await this.reComputedLevel(a_recer);
+    a_recer.level = nlevel;
+    await a_recer.save();
+    // TODO 添加分数记录,这次推荐人加了多少分
+    // // 检测车奖 这个应该做定时任务,1天/小时 检查1/2次,不应该放在这里,和股东的性质不一样,只要给了就行
+    // // 1,先看看车奖得没得,得了就可以返回了,都处理完了
+    // if (!car_show) {
+    //   const result = await this.checkCarshow(a_recer);
+    //   if (result === undefined) {
+    //     // TODO 告知推荐人,车奖检测有错误,中断,返回用户添加成功
+    //     return user;
+    //   }
+    //   // 这次满足车奖了
+    //   if (result) {
+    //     a_recer.car_show = true;
+    //     a_recer.points = a_recer.points + this.car_point;
+    //   }
+    // }
+    return user;
+  }
+  /**
+   * 计算推荐人信息的等级;找到@property的2个变量
+   * @param {Object} user 推荐人信息
+   * @property r_number A推出去的人数 B级总数
+   * @property b_r_number B级推出去的人数 C级总数
+   * @property group_number 团队完成单数: r_number + b_r_number
+   * @return {String} level 等级
+   */
+  async reComputedLevel(user) {
+    const result = await this.getEchelon(user);
+    if (!result) return;
+    const { b = [], c = 0 } = result;
+    /**
+     * @constant Number group_number 团队完成单数
+     * @type Number
+     */
+    const group_number = b.length + c;
+    // 先用1阶条件过滤,是否满足推荐人数要求 + 是否满足团队单数要求
+    let ranks = this.getRank().filter(f => b.length >= f.person && group_number >= f.group);
+    // 按rank 倒序
+    ranks = _.orderBy(ranks, [ 'rank' ], [ 'desc' ]);
+    // 使用find查找,因为倒序排列,所以按照条件挨个比,取的就是结果
+    const rank = ranks.find(f => {
+      const { n_rank, n_r_person } = f;
+      // 查找B梯队里,满足当前阶级要求的 B梯队职位 的人数
+      const list = b.filter(bl => `${bl.level}` === `${n_rank}`);
+      // 如果人数也满足要求,推荐人就应该是这个阶级了,反之继续找
+      return list >= n_r_person;
+    });
+    if (rank) return `${rank.rank}`;
+    return `${user.level}`;
+  }
+
+  /**
+   * 检查该用户是否满足股东身份
+   * @param {Object} user 用户
+   */
+  async checkStockholder(user) {
+    try {
+      const level = _.get(user, 'level', 1) * 1;
+      if (level < 6) return false;
+      const result = await this.getEchelon(user);
+      if (!result) return;
+      const { b = [], c = 0 } = result;
+      const group_number = b.length + c;
+      return group_number > this.stockholder_limit;
+    } catch (error) {
+      this.ctx.logger.error(`${moment().format('YYYY-MM-DD HH:mm:ss')}-${user.name}-${user.mobile}:股东检查出错`);
+      return undefined;
+    }
+  }
+
+  /**
+   * 检查该用户是否满足车奖
+   * @param {Object} user 用户
+   */
+  async checkCarshow(user) {
+    try {
+      const level = _.get(user, 'level', 1) * 1;
+      if (level < 4) return false;
+      const b = await this.model.count({ r_mobile: user.mobile, level: 4 });
+      return b >= 5;
+    } catch (error) {
+      this.ctx.logger.error(`${moment().format('YYYY-MM-DD HH:mm:ss')}-${user.name}-${user.mobile}:车奖检查出错`);
+      return undefined;
+    }
+
+  }
+
+  /**
+   * 查找用户的梯队
+   * @param {Object} user 用户(其实指的就是推荐人)
+   * @return {Object} {b:b梯队列表,c:c梯队数据}
+   */
+  async getEchelon(user) {
+    // 推荐的人 B梯队
+    const b_echelon = await this.model.find({ r_mobile: user.mobile });
+    // c梯队的总人数
+    const c_echelon_number = await this.model.count({ r_mobile: b_echelon.map(i => i.mobile) });
+    return { b: b_echelon, c: c_echelon_number };
+  }
+
+  /**
+   *  等级设置
+   * @property rank 等级:1,业务员;2,经理;3一星经理;4,二星经理;5,三星经理;6,四星经理;
+   * @property person 该等级人数底线要求
+   * @property group 该等级团队单数底线要求
+   * @property n_rank 该团队中,要求B梯队中的等级
+   * @property n_r_person 该团队中,要求B梯队指定等级的人数
+   */
+  getRank() {
+    return [
+      {
+        rank: 1,
+        person: 1,
+        group: 0,
+        score: 600,
+        n_rank: undefined,
+        n_r_person: 0,
+      },
+      {
+        rank: 2,
+        person: 3,
+        group: 11,
+        score: 600 + 100,
+        n_rank: undefined,
+        n_r_person: 0,
+      },
+      {
+        rank: 3,
+        person: 10,
+        group: 111,
+        score: 600 + 150,
+        n_rank: 2,
+        n_r_person: 1,
+      },
+      {
+        rank: 4,
+        person: 20,
+        group: 555,
+        score: 600 + 200,
+        n_rank: 3,
+        n_r_person: 2,
+      },
+      {
+        rank: 5,
+        person: 25,
+        group: 1111,
+        score: 600 + 250,
+        n_rank: 4,
+        n_r_person: 2,
+      },
+      {
+        rank: 6,
+        person: 30,
+        group: 5555,
+        score: 600 + 300,
+        n_rank: 5,
+        n_r_person: 3,
+      },
+    ];
+  }
 }
 }
 
 
 module.exports = CardService;
 module.exports = CardService;