|
@@ -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;
|