wheel-surf-redis.js 10.4 KB
const {Activity} = require('../../../db');
const _ = require('lodash');
const logger = global.yoho.logger;
const _sender = global.yoho.sender;

/**
 * 上报
 * @param type 0: packrain 1: turntable
 * @param tags 一些基础参数
 * @param fields 红包的金额
 * @param isFail 接口是否失败
 */
const sendMessage = (type, tags, fields, isFail) => {
  if (!_sender) {
    return;
  }
  const hostname = (require('os').hostname());
  let typeName = ['turntable-red', 'turntable-coupon'][type];
  let initTags = {
    hostname,
    pid: process.pid || 0,
    app: global.yoho.config.appName,
    type: typeName
  };

  tags = Object.assign({}, initTags, tags);
  isFail = isFail ? 1 : 0;
  fields = Object.assign({}, fields);

  let mesurement = ['monitor_success_report', 'monitor_error_report'][isFail];

  try {
    _sender.addMessage({
      measurement: mesurement,
      tags,
      fields
    });
  } catch (e) {
    logger.error(e);
  }
};

class ActWheelSurfModelRedis extends global.yoho.BaseModel {
  constructor(ctx) {
    super(ctx);
    this.redis = global.yoho.redis;
    this.client = this.redis.client;
  }

  async getNowConf(obj) {
    try {
      let data = {};

      data.conf = await this.client.hgetallAsync(`turntable:${obj.act_id}`)
        .then(conf => {
          Object.keys(conf).forEach(key => {
            if (conf[key] && !_.isNaN(Number(conf[key]))) {
              conf[key] = Number(conf[key])
            }
          });
          return conf;
        });

      // 获取当前活动奖品
      let prize = await this.client.lrangeAsync(`turntable:${obj.act_id}:prize`, 0, 7)
        .then(prizes => {
          return prizes.map(prize => {
            return JSON.parse(prize);
          })
        });

      data.prize = prize.length;
      data.emptyPrize = {};

      for (let value of prize) {
        if (value.type === 1) {
          data.emptyPrize = value;
          break;
        }
      }

      let act = await Activity.findOne({where: {id: obj.act_id}});
      let nowDate = new Date();

      nowDate = parseInt(nowDate.getTime() / 1000);
      if (act.startTime > nowDate) {
        data.startType = false;
        data.errorType = 0;
        data.errorMsg = '活动未开始';
      }
      if (act.endTime < nowDate) {
        data.startType = false;
        data.errorType = 1;
        data.errorMsg = '活动已过期';
      }

      // 获取当去用户剩余次数
      let residueCount;

      // 判断用户是否登录 如果没登录就取当前活动最大次数
      if (obj.uid) {
        // 每日最大次数
        if (data.conf.times_type === 1) {
          // 获取当天0点和23:59:59
          let startTime = new Date(new Date().toLocaleDateString()).getTime();
          let endTime = new Date(new Date(new Date().toLocaleDateString()).getTime()+24*60*60*1000-1).getTime();
          let usedArr = await this.client.zrangebyscoreAsync(`turntable:${obj.act_id}:user:${obj.uid}:prize`, startTime, endTime);

          residueCount = data.conf.day_limit_times - usedArr.length;
        }
      } else {
        residueCount = 0;
      }
      data.residueCount = residueCount;
      return Promise.resolve(data);
    } catch (e) {
      logger.error(e);
      return Promise.reject({code: 305, result: false, msg: '服务错误,请稍等'});
    }
  }

  // noinspection JSAnnotator
  async goPrize(obj) {
    try {
      // 校验有效活动时间
      let act = await Activity.findOne({where: {id: obj.act_id}});
      let nowDate = new Date();

      nowDate = parseInt(nowDate.getTime() / 1000);
      if (act.startTime > nowDate) {
        return Promise.reject({code: 301, result: false, msg: '活动未开始'});
      }
      if (act.endTime < nowDate) {
        return Promise.reject({code: 302, result: false, msg: '活动已过期'});
      }

      // 获取活动信息
      let conf = await this.client.hgetallAsync(`turntable:${obj.act_id}`)
        .then(conf => {
          Object.keys(conf).forEach(key => {
            if (conf[key] && !_.isNaN(Number(conf[key]))) {
              conf[key] = Number(conf[key])
            }
          });
          return conf;
        });

      let residueCount;
      let uid = {
        toString: () => {
          return _.parseInt(obj.uid);
        },
        sessionKey: obj.sessionKey,
        appVersion: obj.appVersion,
        appSessionType: obj.sessionType
      };

      delete obj.sessionKey;
      delete obj.appVersion;
      delete obj.sessionType;

      // 计算用户剩余次数校验
      if (conf.times_type === 1) {
        // 获取当天0点和23:59:59
        let startTime = new Date(new Date().toLocaleDateString()).getTime();
        let endTime = new Date(new Date(new Date().toLocaleDateString()).getTime()+24*60*60*1000-1).getTime();
        let usedArr = await this.client.zrangebyscoreAsync(`turntable:${obj.act_id}:user:${obj.uid}:prize`, startTime, endTime);

        residueCount = conf.day_limit_times - usedArr.length;
      }

      if (residueCount > 0) {
        // 获取抽取到奖品
        // 获取奖品信息
        let prize = await this.client.lrangeAsync(`turntable:${obj.act_id}:prize`, 0, 7)
          .then(prizes => {
            return prizes.map(prize => {
              return JSON.parse(prize);
            })
          });

        // 获取每个奖品获取它们的中奖范围
        let arr = {}, oldValue;

        prize.map(function (value, index) {
          if (value.chance) {
            if (typeof(oldValue) === 'undefined') {
              arr[index] = {maxValue: value.chance, leastValue: 0};
            } else {
              let maxValue = value.chance + oldValue;
              let leastValue = oldValue;

              arr[index] = {maxValue, leastValue};
            }
            oldValue = arr[index].maxValue;
          }
        });

        // 比较概率获取中奖奖品
        // 随机生成0-100的随机数
        let random = Math.random() * 100;

        // 判定随机数在奖品池子取件 选定中奖奖品
        let getPrize, sendResult = {}, result, reduce;

        for (let i in arr) {
          if (arr[i].maxValue >= random && arr[i].leastValue < random) {
            getPrize = prize[i];
            break;
          }
        }

        if (getPrize.type !== 1) {
          // 校验剩余库存 减库存
          let left = await this.client.getAsync(`turntable:${obj.act_id}:prize:${getPrize.prize_idx}:stock`);

          if (left > 0) {
            await this.client.decrAsync(`turntable:${obj.act_id}:prize:${getPrize.prize_idx}:stock`);
          } else {
            for (let p of prize) {
              if (p.type === 1) {
                getPrize = p;
                break;
              }
            }
          }
        }

        if (getPrize.type === 1) {
          sendResult.code = 200;
          getPrize.desc = '对不起,您没有中奖';
        } else if (getPrize.type === 2) {

          try {
            // 调用java接口
            sendResult = await this.get({
              data: {
                method: 'app.redpac.addRedpac',
                actSource: 1001,
                uid: uid,
                redpacToken: getPrize.value
              }
            });

            sendResult = sendResult || {};
            sendResult.data = sendResult.data || {};
            sendMessage(0, {}, {succeedTimes: sendResult.data.amount || 0}, 0);

            if (sendResult.code === 200) {
              if (!sendResult.data.amount) {
                sendResult.code = 201; // 重复领取
              } else {
                getPrize.desc = '恭喜您获得' + sendResult.data.amount + '元红包';
              }
            }
          } catch (e) {
            logger.error(e);
            sendMessage(0, {}, {message: e.message || 'interface error', stack: e}, 1);
          }
        } else if (getPrize.type === 3) {
          try {
            sendResult = await this.get({
              data: {
                method: 'app.coupons.couponsSend',
                uid: uid,
                coupon_send_token: getPrize.value
              }
            });

            sendMessage(1, {}, {succeedTimes: 1}, 0);

            if (sendResult && sendResult.code === 200) {
              getPrize.desc = '恭喜您获得' + getPrize.name + '优惠券';
            }

          } catch (e) {
            logger.error(e);
            sendMessage(1, {}, {message: e.message || 'interface error', stack: e}, 1);
          }
        } else if (getPrize.type === 4) {
          sendResult.code = 200;
          getPrize.desc = '恭喜您获得' + getPrize.name;
        }

        // 插入数据库
        if (sendResult.code !== 200) {
          getPrize = null;
          for (let item of prize) {
            if (item.type === 1) {
              getPrize = item.dataValues;
              break;
            }
          }
          getPrize.desc = '对不起,您没有中奖';
        }

        let score = new Date().getTime();

        getPrize.createTime = score;
        result = await Promise.all([
          this.client.zaddAsync(
            `turntable:${obj.act_id}:user:${obj.uid}:prize`, score, `${JSON.stringify(getPrize)}:::${score}`),
          this.client.zaddAsync(
            `turntable:${obj.act_id}:prize:${getPrize.prize_idx}:users`, score, `${JSON.stringify(getPrize)}:::${score},${obj.uid}`)
        ]);

        if (result
          && result[0] === 1
          && result[1] === 1) {
          delete getPrize.chance;
          delete getPrize.create_time;
          delete getPrize.total;
          delete getPrize.total_left;
          delete getPrize.value;
          return Promise.resolve(getPrize);
        } else {
          return Promise.reject({code: 305, result: false, msg: '服务错误,请稍等'});
        }
      } else {
        return Promise.reject({code: 304, result: false, msg: '用户使用次数不足'});
      }
    } catch (e) {
      logger.error(e);
      return Promise.reject({code: 305, result: false, msg: '服务错误,请稍等'});
    }
  }

  async getUserPrize(obj) {
    try {
      return await this.client.zrevrangeAsync(`turntable:${obj.act_id}:user:${obj.uid}:prize`, 0, 300)
        .then(prizes => {
          return prizes.map(prize => {
            return JSON.parse(prize.split(':::')[0]);
          }).filter(prize => {
            return prize.type !== 1;
          });
        });
    } catch (e) {
      logger.error(e);
      return Promise.reject({code: 305, result: false, msg: '服务错误,请稍等'});
    }
  }
}

module.exports = ActWheelSurfModelRedis;