Authored by 李奇

Merge branch 'master' into feature/add-verify

... ... @@ -20,6 +20,7 @@ const moment = require('moment');
const _ = require('lodash');
const pkg = require('./package.json');
const Sender = require('influx-batch-sender');
const Redis = require('./utils/redis');
let logger;
... ... @@ -49,6 +50,7 @@ global.yoho.utils = {
yoho: Yoho
};
global.yoho.redis = new Redis(config.redis);
global.yoho.sender = new Sender(config.monitorReport); // 初始化数据上报
app.use(cookieSession({
... ...
... ... @@ -409,7 +409,7 @@ module.exports = class extends global.yoho.BaseModel {
* @param isRetry
* @returns {*}
*/
async createPrizeCode(length = 8, isRetry) {
async createPrizeCode(actPrizeId, length = 8, isRetry) {
const mapStr = 'QQWERTYUIOPASDFGHJKLZXCVBNM12345678900';
let prizeCode = '';
... ... @@ -418,7 +418,7 @@ module.exports = class extends global.yoho.BaseModel {
}
const info = await mysqlCli.query(`select id from ${TABLE_ACT_PRIZE_PRODUCT_USER}
where prize_code = :prizeCode limit 1`, {prizeCode});
where act_prize_id = :actPrizeId and prize_code = :prizeCode limit 1`, {actPrizeId, prizeCode});
if (info && info.length) {
if (isRetry) {
... ... @@ -426,7 +426,7 @@ module.exports = class extends global.yoho.BaseModel {
return '';
} else {
return this.createPrizeCode(length, true);
return this.createPrizeCode(actPrizeId, length, true);
}
} else {
prizeCodeCreateCount.success(); // 记录生成抽奖码成功
... ... @@ -489,7 +489,7 @@ module.exports = class extends global.yoho.BaseModel {
return errorData;
}
const prizeCode = await this.createPrizeCode();
const prizeCode = await this.createPrizeCode(actPrizeId);
if (!prizeCode) {
return errorData;
... ...
... ... @@ -29,7 +29,6 @@ const adminController = {
const userName = req.body.userName || '';
const password = req.body.password || '';
// TODO 管理员暂时写死
if (userName !== 'admin' || password !== 'yap@admin') {
return res.json({
code: 400,
... ...
... ... @@ -3,8 +3,10 @@
* @author: leo <qi.li@yoho.cn>
* @date: 26/09/2018
*/
const moment = require('moment');
const wheelSurfModel = require('../models/wheel-surf');
const valid = require('../../../utils/validator');
const {excel_export} = require('../../../utils/excel');
const whSurfController = {
entry(req, res) {
... ... @@ -75,21 +77,12 @@ const whSurfController = {
}
},
getConfigList: async function(req, res) {
let result = await req.ctx(wheelSurfModel).configList();
return res.json({
code: 200,
data: result
});
},
configModify: async function(req, res) {
try {
let data = valid(req.body, {
id: {type: 'number', empty: true},
act_id: {type: 'number', empty: false},
act_id: {type: 'string', empty: false},
rule_btn_bg: {type: 'string', empty: true},
rule_url: {type: 'string', empty: true},
share_btn_bg: {type: 'string', empty: true},
... ... @@ -115,7 +108,7 @@ const whSurfController = {
status: {type: 'number', empty: true}
});
let result = await req.ctx(wheelSurfModel).configModify(data);
let result = await req.ctx(wheelSurfModel).setActConf(data.act_id, data);
return res.json({
code: 200,
... ... @@ -141,11 +134,18 @@ const whSurfController = {
});
}
let actInfo = await req.ctx(wheelSurfModel).actInfo(actId);
let result = await req.ctx(wheelSurfModel).configFindOne(actId);
let result = await req.ctx(wheelSurfModel).getActConf(actId);
let actStatus = 2; // 1: 活动未开始 2: 活动进行中 3:活动已过期
let now = parseInt(new Date().getTime() / 1000);
if (!actInfo) {
return res.json({
code: 404,
message: '活动不存在'
});
}
if (now < actInfo.startTime) {
actStatus = 1;
} else if (now > actInfo.endTime) {
... ... @@ -168,7 +168,7 @@ const whSurfController = {
if (param && param.length && param instanceof Array) {
let arr = param.map((value) => {
return valid(value, {
act_id: {type: 'number', empty: false},
act_id: {type: 'string', empty: false},
name: {type: 'string', empty: true},
type: {type: 'number', empty: true},
value: {type: 'string', empty: true},
... ... @@ -180,7 +180,8 @@ const whSurfController = {
prize_idx: {type: 'number', empty: true},
});
});
let result = await req.ctx(wheelSurfModel).prizeCreate(arr);
let result = await req.ctx(wheelSurfModel).createActPrize(arr[0].act_id, arr);
return res.json({
code: 200,
... ... @@ -210,7 +211,7 @@ const whSurfController = {
let arr = param.map((value) => {
return valid(value, {
id: {type: 'number', empty: true},
act_id: {type: 'number', empty: false},
act_id: {type: 'string', empty: false},
name: {type: 'string', empty: true},
type: {type: 'number', empty: true},
value: {type: 'string', empty: true},
... ... @@ -222,7 +223,8 @@ const whSurfController = {
prize_idx: {type: 'number', empty: true},
});
});
let result = await req.ctx(wheelSurfModel).prizeUpdate(arr);
let result = await req.ctx(wheelSurfModel).updateActPrize(arr[0].act_id, arr);
return res.json({
code: 200,
... ... @@ -254,7 +256,8 @@ const whSurfController = {
msg: '参数为空'
});
}
let result = await req.ctx(wheelSurfModel).prizeFindByActId(actId);
let result = await req.ctx(wheelSurfModel).getActPrize(actId);
return res.json({
code: 200,
... ... @@ -262,45 +265,9 @@ const whSurfController = {
});
},
prizeModify: async function(req, res) {
try {
let data = valid(req.body, {
id: {type: 'number', empty: true},
act_id: {type: 'number', empty: false},
name: {type: 'string', empty: true},
type: {type: 'number', empty: true},
value: {type: 'string', empty: true},
img: {type: 'string', empty: true},
total: {type: 'number', empty: true},
total_left: {type: 'number', empty: true},
chance: {type: 'number', empty: true},
prize_bg: {type: 'string', empty: true},
prize_idx: {type: 'number', empty: true},
});
let result = await req.ctx(wheelSurfModel).prizeModify(data);
return res.json(result);
} catch (e) {
return res.json({
code: 203,
result: false,
msg: e
});
}
},
prizeDelete: async function(req, res) {
let id = req.query.id;
if (!id) {
return res.json({
code: 202,
result: false,
msg: '参数为空'
});
}
let result = await req.ctx(wheelSurfModel).prizeDelete(id);
userFind: async function(req, res) {
let obj = req.body;
let result = await req.ctx(wheelSurfModel).userFind(obj);
return res.json({
code: 200,
... ... @@ -308,18 +275,34 @@ const whSurfController = {
});
},
userFind: async function(req, res) {
let obj = req.body;
exportRecords: async function(req, res) {
let result = await req.ctx(wheelSurfModel).exportRecords(req.query.actId);
let result = await req.ctx(wheelSurfModel).userFind(obj);
let excelConf = {
name: 'mysheet',
cols: ['用户UID', '奖品类型', '奖品名称', '中奖时间'],
rows: []
};
return res.json({
code: 200,
data: {
list: result[1],
total: result[0]
}
let temp = [];
result.forEach(item => {
temp = [];
temp.push(item.uid);
temp.push(item.type);
temp.push(item.name);
temp.push(moment(+item.time).format('YYYY-MM-DD HH:mm:ss'));
excelConf.rows.push(temp);
});
return excel_export({
title: excelConf.cols,
data: excelConf.rows,
fileName: 'ActivityUserList',
sheetName: excelConf.name,
res
});
}
};
... ...
/* eslint-disable array-callback-return */
const {ActWheelSurfConf, ActWheelSurfPrize, Activity, ActWheelSurfUser} = require('../../../db');
const mysqlCli = global.yoho.utils.mysqlCli;
const _ = require('lodash');
const aes = require('../../../utils/aes');
class ActWheelSurfModel extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
this.redis = global.yoho.redis;
this.client = this.redis.client;
}
list() {
return Activity.findAll({where: {type: 1}});
async list() {
let len = await this.client.llenAsync('turntable:activity');
return this.client.lrangeAsync('turntable:activity', 0, len - 1).then(acts => {
return acts.filter(act => act).map(act => {
return JSON.parse(act);
});
});
}
create(data) {
return Activity.create(data);
async create(data) {
let len = await this.client.llenAsync('turntable:activity');
data.id = len + 1;
data.encryptedId = aes.encryptUid(len + 1);
return this.client.rpushAsync('turntable:activity', JSON.stringify(data));
}
async actDelete(id) {
await Activity.destroy({where: {id}});
await ActWheelSurfConf.destroy({where: {act_id: id}});
await ActWheelSurfPrize.destroy({where: {act_id: id}});
return true;
}
configModify(obj) {
if (obj.id) {
let where = {id: obj.id};
delete obj.id;
return ActWheelSurfConf.update(obj, {where: where});
} else {
return ActWheelSurfConf.create(obj);
}
}
configList() {
return ActWheelSurfConf.findAll();
}
configFindOne(act_id) {
return ActWheelSurfConf.findOne({where: {act_id}});
id = parseInt(aes.decryptUid(id), 10);
return this.client.lsetAsync('turntable:activity', id - 1, '');
}
actInfo(act_id) {
return Activity.findOne({where: {id: act_id}});
}
prizeCreate(arr) {
return ActWheelSurfPrize.bulkCreate(arr);
let idx = parseInt(aes.decryptUid(act_id), 10) - 1;
return this.client.lrangeAsync('turntable:activity', idx, idx).then(act => {
return JSON.parse(act[0] || {});
});
}
prizeUpdate(arr) {
try {
arr.map((value) => {
let where = {id: value.id};
delete value.id;
ActWheelSurfPrize.update(value, {where: where});
async userFind(obj) {
let pageNo = obj.pageNo || 1;
let pageSize = obj.pageSize || 20;
let actId = parseInt(aes.decryptUid(obj.act_id), 10);
let len = await this.client.llenAsync(`turntable:${actId}:prize:users`);
return this.client.lrangeAsync(`turntable:${actId}:prize:users`, (pageNo - 1) * pageSize, pageNo * pageSize - 1).then(prizes => {
let afters = prizes.map(prize => {
prize = prize.split(':::');
return {
uid: prize[0],
type: prize[1],
name: prize[2],
time: +prize[3]
}
});
return Promise.resolve({code: 200, result: true});
} catch (e) {
return Promise.resolve({code: 201, result: false, msg: e});
}
return {
total: len,
list: afters
}
});
}
prizeFindByActId(act_id) {
return ActWheelSurfPrize.findAll({where: {act_id}});
async exportRecords(actId) {
actId = parseInt(aes.decryptUid(actId), 10);
let len = await this.client.llenAsync(`turntable:${actId}:prize:user`);
return this.client.lrangeAsync(`turntable:${actId}:prize:users`, 0, len - 1).then(prizes => {
return prizes.map(prize => {
prize = prize.split(':::');
return {
uid: prize[0],
type: prize[1],
name: prize[2],
time: prize[3]
}
});
});
}
prizeDelete(id) {
return ActWheelSurfPrize.destroy({where: {id}});
getActConf(actId) {
actId = parseInt(aes.decryptUid(actId), 10);
return this.client.hgetallAsync(`turntable:${actId}`).then(conf => {
conf = conf || {};
Object.keys(conf).forEach(key => {
if (conf[key] && !_.isNaN(Number(conf[key]))) {
conf[key] = Number(conf[key])
}
});
return conf;
});
}
async prizeModify(obj) {
if (obj.id) {
let where = {id: obj.id};
delete obj.id;
if (obj.total) {
let prize = await ActWheelSurfPrize.findOne({where: where});
let count = obj.total - prize.total;
setActConf(actId, confObj) {
confObj.id = 1;
actId = parseInt(aes.decryptUid(actId), 10);
return this.client.HMSET(`turntable:${actId}`, confObj);
}
if (count > 0) {
await prize.increment({total_left: count});
} else if (count < 0) {
return Promise.resolve({result: false, code: 204, msg: '总数不能小于原来的总数'});
getActPrize(actId, len = 7) {
actId = parseInt(aes.decryptUid(actId), 10);
return this.client.lrangeAsync(`turntable:${actId}:prize`, 0, len)
.then(async (prizes) => {
let left = 0;
for (let i = 0; i < prizes.length; i++) {
prizes[i] =JSON.parse(prizes[i]);
left = await this.client.getAsync(`turntable:${actId}:prize:${prizes[i].prize_idx}:stock`);
prizes[i].total_left = +left;
}
}
await ActWheelSurfPrize.update(obj, {where: where});
return Promise.resolve({result: true, code: 200, msg: '修改成功'});
} else {
await ActWheelSurfPrize.create(obj);
return Promise.resolve({result: true, code: 200, msg: '插入成功'});
}
return prizes;
});
}
userFind(obj) {
let pageNo = obj.pageNo || 1;
let pageSize = obj.pageSize || 20;
obj.start = (pageNo - 1) * pageSize;
obj.page = pageSize;
createActPrize(actId, prizesList) {
prizesList = prizesList || [];
actId = parseInt(aes.decryptUid(actId), 10);
let sql = `select u.uid, u.act_id act_id, u.prize_id prize_id, u.create_time create_time,a.title title,p.name name,p.type type ,p.value value,p.img img
from act_wheel_surf_user u , act_wheel_surf_prize p ,activity a where u.prize_id = p.id and u.act_id =:act_id and a.id=:act_id`;
let arr = Object.keys(obj);
let multi = this.client.multi();
prizesList.map((prize, idx) => {
prize.id = idx + 1;
multi.lpush(`turntable:${actId}:prize`, JSON.stringify(prize));
multi.set(`turntable:${actId}:prize:${prize.prize_idx}:stock`, prize.total_left);
});
return multi.execAsync();
}
let countSql = `select count(1) total
from act_wheel_surf_user u , act_wheel_surf_prize p where u.prize_id = p.id and u.act_id =:act_id`;
updateActPrize(actId, prizesList) {
prizesList = prizesList || [];
actId = parseInt(aes.decryptUid(actId), 10);
arr.forEach(function(value, index) {
if (!obj[value]) {
return;
}
switch (value) {
case 'type':
sql += ' and p.type=:type';
countSql += ' and p.type=:type';
break;
case 'title':
sql += ' and a.title=:title';
break;
case 'uid':
sql += ' and u.uid=:uid';
countSql += ' and u.uid=:uid';
break;
case 'name':
sql += ' and p.name=:name';
countSql += ' and p.name=:name';
break;
}
if (index === arr.length - 1) {
sql += ' order by u.create_time desc limit :start, :page;';
}
let multi = this.client.multi();
prizesList.map((prize, idx) => {
multi.lset(`turntable:${actId}:prize`, idx, JSON.stringify(prize));
multi.set(`turntable:${actId}:prize:${prize.prize_idx}:stock`, prize.total_left);
});
try {
return Promise.all([mysqlCli.query(countSql, obj).then(res => {return res[0].total}), mysqlCli.query(sql, obj)]);
} catch (e) {
return Promise.reject({code: 305, result: false, msg: '服务错误,请稍等'});
}
return multi.execAsync();
}
}
... ...
... ... @@ -98,16 +98,14 @@ router.post('/wheelSurf/api/create', wheelSurf.actCreate);
router.post('/wheelSurf/api/delete', wheelSurf.actDelete);
router.get('/wheelSurf/api/list', wheelSurf.actList);
router.get('/wheelSurf/api/config/list', wheelSurf.getConfigList);
router.post('/wheelSurf/api/config/modify', wheelSurf.configModify);
router.get('/wheelSurf/api/config/detail', wheelSurf.configFindOne);
router.get('/wheelSurf/api/prize/list', wheelSurf.prizeFindByActId);
router.post('/wheelSurf/api/prize/create', wheelSurf.prizeCreate);
router.post('/wheelSurf/api/prize/update', wheelSurf.prizeUpdate);
router.get('/wheelSurf/api/prize/delete', wheelSurf.prizeDelete);
router.post('/wheelSurf/api/prize/modify', wheelSurf.prizeModify);
router.post('/wheelSurf/api/prize/userFind', wheelSurf.userFind);
router.get('/wheelSurf/api/prize/exportRecords', wheelSurf.exportRecords);
router.get('/wheelSurf/*', wheelSurf.entry);
... ...
... ... @@ -10,7 +10,7 @@ const whSurfController = {
getNowConf: async function(req, res) {
try {
let data = valid(req.body, {
act_id: {type: 'number', empty: false},
act_id: {type: 'string', empty: false},
uid: {type: 'number', empty: true},
});
let result = await req.ctx(wheelSurfModel).getNowConf(data);
... ... @@ -25,7 +25,7 @@ const whSurfController = {
// 校验用户登录
try {
let data = valid(req.body, {
act_id: {type: 'number', empty: false},
act_id: {type: 'string', empty: false},
uid: {type: 'number', empty: false},
sessionKey: {type: 'string', empty: false},
appVersion: {type: 'string', empty: false},
... ... @@ -42,7 +42,7 @@ const whSurfController = {
getUserPrize: async function(req, res) {
try {
let data = valid(req.body, {
act_id: {type: 'number', empty: false},
act_id: {type: 'string', empty: false},
uid: {type: 'number', empty: false},
});
let result = await req.ctx(wheelSurfModel).getUserPrize(data);
... ...
/* eslint-disable array-callback-return */
const {ActWheelSurfConf, ActWheelSurfPrize, ActWheelSurfUser, Activity, sequelize} = require('../../../db');
// const md5 = require('yoho-md5');
const _ = require('lodash');
const aes = require('../../../utils/aes');
const logger = global.yoho.logger;
const mysqlCli = global.yoho.utils.mysqlCli;
const _sender = global.yoho.sender;
const mysqlCli = global.yoho.utils.mysqlCli;
/**
* 上报
... ... @@ -45,28 +41,55 @@ const sendMessage = (type, tags, fields, isFail) => {
}
};
class ActWheelSurfModel extends global.yoho.BaseModel {
const prizeType = {
1: '谢谢惠顾',
2: '红包',
3: '优惠券',
4: '实物奖品'
};
class ActWheelSurfModelRedis extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
this.cache = global.yoho.cache;
this.redis = global.yoho.redis;
this.client = this.redis.client;
}
async getNowConf(obj) {
try {
// let data = await this.cache.get(md5('act' + obj.act_id));
let data = {};
// 获取当前活动基础信息,从redis里面取prize和conf,如果没有则查表再放入redis
// if (data) {
// data = JSON.parse(data);
// } else {
// 从redis取,如果没有则去数据查询,然后再到放到redis
// 获取活动基础
// 兼容线上活动
if (+obj.act_id !== 44) {
try {
obj.act_id = parseInt(aes.decryptUid(obj.act_id), 10);
} catch (err) {
obj.act_id = 0;
}
}
if (!obj.act_id) {
return {};
}
data.conf = await ActWheelSurfConf.findOne({where: {act_id: obj.act_id}});
data.conf = await this.client.hgetallAsync(`turntable:${obj.act_id}`)
.then(conf => {
conf = conf || {};
Object.keys(conf).forEach(key => {
if (conf[key] && !_.isNaN(Number(conf[key]))) {
conf[key] = Number(conf[key])
}
});
return conf;
});
// 获取当前活动奖品
let prize = await ActWheelSurfPrize.findAll({where: {act_id: obj.act_id}});
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 = {};
... ... @@ -78,9 +101,10 @@ class ActWheelSurfModel extends global.yoho.BaseModel {
}
}
// this.cache.set(md5('act' + obj.act_id), data);
// }
let act = await Activity.findOne({where: {id: obj.act_id}});
let idx = obj.act_id - 1;
let act = await this.client.lrangeAsync('turntable:activity', idx, idx).then(act => {
return JSON.parse(act[0] || {});
});
let nowDate = new Date();
nowDate = parseInt(nowDate.getTime() / 1000);
... ... @@ -103,19 +127,14 @@ class ActWheelSurfModel extends global.yoho.BaseModel {
// 每日最大次数
if (data.conf.times_type === 1) {
// 获取当天0点和23:59:59
let endTime = new Date(new Date(new Date().toLocaleDateString()).getTime() + 24 * 60 * 60 * 1000 - 1);
let startTime = new Date(new Date(new Date().toLocaleDateString()).getTime());
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);
obj.create_time = {gt: startTime, lte: endTime};
residueCount = data.conf.day_limit_times - await ActWheelSurfUser.count({
where: obj
});
} else {
// 活动最大次数
residueCount = data.conf.act_total_times - await ActWheelSurfUser.count({where: obj});
residueCount = data.conf.day_limit_times - usedArr.length;
}
} else {
residueCount = data.conf.times_type === 3 ? data.conf.act_total_times : data.conf.day_limit_times;
residueCount = 0;
}
data.residueCount = residueCount;
return Promise.resolve(data);
... ... @@ -125,11 +144,28 @@ class ActWheelSurfModel extends global.yoho.BaseModel {
}
}
// noinspection JSAnnotator
async goPrize(obj) {
try {
// 校验有效活动时间
let act = await Activity.findOne({where: {id: obj.act_id}});
// 兼容线上活动
if (+obj.act_id !== 44) {
try {
obj.act_id = parseInt(aes.decryptUid(obj.act_id), 10);
} catch (err) {
obj.act_id = 0;
}
}
if (!obj.act_id) {
return {};
}
let idx = obj.act_id - 1;
let act = await this.client.lrangeAsync('turntable:activity', idx, idx).then(act => {
return JSON.parse(act[0] || {});
});
let nowDate = new Date();
nowDate = parseInt(nowDate.getTime() / 1000);
... ... @@ -141,7 +177,16 @@ class ActWheelSurfModel extends global.yoho.BaseModel {
}
// 获取活动信息
let conf = await ActWheelSurfConf.findOne({where: {act_id: obj.act_id}});
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: () => {
... ... @@ -159,22 +204,22 @@ class ActWheelSurfModel extends global.yoho.BaseModel {
// 计算用户剩余次数校验
if (conf.times_type === 1) {
// 获取当天0点和23:59:59
let endTime = new Date(new Date(new Date().toLocaleDateString()).getTime() + 24 * 60 * 60 * 1000 - 1);
let startTime = new Date(new Date(new Date().toLocaleDateString()).getTime());
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);
obj.create_time = {gt: startTime, lte: endTime};
residueCount = conf.day_limit_times - await ActWheelSurfUser.count({
where: obj
});
} else {
// 活动最大次数
residueCount = conf.act_total_times - await ActWheelSurfUser.count({where: obj});
residueCount = conf.day_limit_times - usedArr.length;
}
if (residueCount > 0) {
// 获取抽取到奖品
// 获取奖品信息
let prize = await ActWheelSurfPrize.findAll({where: {act_id: obj.act_id}});
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;
... ... @@ -198,7 +243,7 @@ class ActWheelSurfModel extends global.yoho.BaseModel {
let random = Math.random() * 100;
// 判定随机数在奖品池子取件 选定中奖奖品
let getPrize, sendResult = {}, result, reduce;
let getPrize, sendResult = {}, result;
for (let i in arr) {
if (arr[i].maxValue >= random && arr[i].leastValue < random) {
... ... @@ -209,15 +254,11 @@ class ActWheelSurfModel extends global.yoho.BaseModel {
if (getPrize.type !== 1) {
// 校验剩余库存 减库存
reduce = await ActWheelSurfPrize.update({total_left: sequelize.literal('`total_left`-1')}, {
where: {
total_left: {$gt: 0},
id: getPrize.id
}
});
let left = await this.client.getAsync(`turntable:${obj.act_id}:prize:${getPrize.prize_idx}:stock`);
// 如果库存不够则返回当前type=1的商品
if (reduce[0] !== 1) {
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;
... ... @@ -227,7 +268,6 @@ class ActWheelSurfModel extends global.yoho.BaseModel {
}
}
getPrize = getPrize.dataValues;
if (getPrize.type === 1) {
sendResult.code = 200;
getPrize.desc = '对不起,您没有中奖';
... ... @@ -289,13 +329,23 @@ class ActWheelSurfModel extends global.yoho.BaseModel {
getPrize = null;
for (let item of prize) {
if (item.type === 1) {
getPrize = item.dataValues;
getPrize = item;
break;
}
}
getPrize.desc = '对不起,您没有中奖';
}
result = await ActWheelSurfUser.create({act_id: obj.act_id, uid: obj.uid, prize_id: getPrize.id});
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.lpushAsync(
`turntable:${obj.act_id}:prize:users`, `${obj.uid}:::${prizeType[getPrize.type]}:::${getPrize.name}:::${score}`)
]);
if (result) {
delete getPrize.chance;
delete getPrize.create_time;
... ... @@ -316,18 +366,52 @@ class ActWheelSurfModel extends global.yoho.BaseModel {
}
async getUserPrize(obj) {
// 兼容线上活动
if (+obj.act_id !== 44) {
try {
obj.act_id = parseInt(aes.decryptUid(obj.act_id), 10);
} catch (err) {
obj.act_id = 0;
}
}
if (!obj.act_id) {
return [];
}
try {
return await mysqlCli.query(
`select u.id, u.act_id act_id, u.prize_id prize_id, u.create_time createTime, p.name name,p.type type ,p.value value,p.img img
// 兼容线上活动奖品
if (+obj.act_id === 44) {
let oddPrizes = [];
try {
oddPrizes = await mysqlCli.query(
`select u.id, u.act_id act_id, u.prize_id prize_id, u.create_time createTime, p.name name,p.type type ,p.value value,p.img img
from act_wheel_surf_user u , act_wheel_surf_prize p where u.prize_id = p.id and u.act_id =:act_id and u.uid = :uid and type != :type
order by u.create_time desc`, {act_id: obj.act_id, uid: obj.uid, type: 1});
// return await ActWheelSurfUser.findAll({include: [{
// model: ActWheelSurfPrize,
// as: 'ActWheelSurfPrize',
// }],
// where: obj
// });
order by u.create_time desc`, {act_id: obj.act_id, uid: obj.uid, type: 1}, {timeout: 2000});
} catch(e) {
oddPrizes = [];
logger.error(e);
}
return 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;
}).concat(oddPrizes);
});
} else {
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: '服务错误,请稍等'});
... ... @@ -335,4 +419,4 @@ class ActWheelSurfModel extends global.yoho.BaseModel {
}
}
module.exports = ActWheelSurfModel;
module.exports = ActWheelSurfModelRedis;
... ...
... ... @@ -108,7 +108,8 @@ module.exports = {
port: '3306',
user: 'root',
password: '',
charset: 'utf8mb4'
charset: 'utf8mb4',
timezone: '+08:00'
},
database: 'yoho_activity_platform',
},
... ... @@ -197,7 +198,8 @@ if (isProduction) {
port: '3306',
user: 'yh_vpc_bak',
password: 'yoho@2Y$^YpNb7hp',
charset: 'utf8mb4'
charset: 'utf8mb4',
timezone: '+08:00'
},
database: 'yoho_activity_platform',
}
... ... @@ -223,7 +225,8 @@ if (isProduction) {
port: '3306',
user: 'yh_test',
password: 'yh_test',
charset: 'utf8mb4'
charset: 'utf8mb4',
timezone: '+08:00'
},
database: 'yoho_activity_platform',
}
... ...
... ... @@ -6,6 +6,7 @@ module.exports = {
port: '3306',
host: '0.0.0.0',
dialect: 'mysql',
timezone: '+08:00',
pool: {
max: 5,
min: 0,
... ... @@ -21,6 +22,7 @@ module.exports = {
port: '3306',
host: '192.168.102.219',
dialect: 'mysql',
timezone: '+08:00',
pool: {
max: 5,
min: 0,
... ... @@ -36,6 +38,7 @@ module.exports = {
port: '3306',
host: '10.66.106.4',
dialect: 'mysql',
timezone: '+08:00',
pool: {
max: 5,
min: 0,
... ...
... ... @@ -22,19 +22,9 @@ module.exports = (req, res, next) => {
}
if (!isAdmin) {
if (req.xhr) {
return res.json({
code: 401,
message: '抱歉,您没有管理员权限'
});
}
return res.render('error/403', {
layout: false
});
return res.redirect('/admin/login');
}
req.isAdmin = true;
next();
};
... ...
... ... @@ -5,14 +5,14 @@
<div slot="left" class="split-pane">
<Form ref="prizeForm" :model="prize" :rules="prizeRules" :label-width="120">
<FormItem label="奖品位置" prop="prize_idx">
<Input v-model="prize.prize_idx" :disabled="status == 2 || status == 3"
<Input v-model="prize.prize_idx"
placeholder="奖品位置序号(竖直方向顺时针从1开始)" :maxlength="1"></Input>
</FormItem>
<FormItem label="奖品名称" prop="name">
<Input v-model="prize.name" placeholder="奖品名称" :maxlength="50"></Input>
</FormItem>
<FormItem label="奖品类型" prop="type">
<Select v-model="prize.type" @on-change="typeChange" :disabled="status == 2 || status == 3">
<Select v-model="prize.type" @on-change="typeChange">
<Option :value="1">谢谢惠顾</Option>
<Option :value="2">红包</Option>
<Option :value="3">优惠券</Option>
... ... @@ -21,7 +21,6 @@
</FormItem>
<FormItem label="奖品token" prop="value">
<Input v-model="prize.value"
:disabled="status == 2 || status == 3"
placeholder="红包优惠券token(实物奖品和谢谢惠顾不填)" :maxlenght="200"></Input>
</FormItem>
<FormItem label="奖品总数" prop="total">
... ...
... ... @@ -13,7 +13,7 @@
columns1: [
{
title: '活动ID',
key: 'id'
key: 'encryptedId'
},
{
title: '活动标题',
... ... @@ -47,7 +47,7 @@
},
on: {
click: () => {
this.conf(row.id);
this.conf(row.encryptedId);
}
}
}, '配置'),
... ... @@ -61,7 +61,7 @@
},
on: {
click: () => {
this.prizeSent(row.id);
this.prizeSent(row.encryptedId);
}
}
}, '中奖一览'),
... ... @@ -72,7 +72,7 @@
},
on: {
click: () => {
this.delete(row.id);
this.delete(row.encryptedId);
}
}
}, '删除')
... ... @@ -94,9 +94,10 @@
this.$router.push({name: 'prizeSent', query: {actId}});
},
delete(id) {
this.$Modal.warning({
this.$Modal.confirm({
title: '删除',
content: '删除后不可恢复,确认删除?',
cancelText: '取消',
onOk: () => {
$.ajax({
method: 'post',
... ...
... ... @@ -2,24 +2,7 @@
<div class="list">
<div class="filter">
<Row>
<Col span="6" class="field-col">
<Input v-model="uid" placeholder="用户UID" :maxlength="20"></Input>
</Col>
<Col span="6" class="field-col">
<Select v-model="type">
<Option :value="1">谢谢惠顾</Option>
<Option :value="2">红包</Option>
<Option :value="3">优惠券</Option>
<Option :value="4">实物奖品</Option>
</Select>
</Col>
<Col span="6" class="field-col">
<Input v-model="name" placeholder="奖品名称" :maxlength="100"></Input>
</Col>
<Col span="6">
<Button type="primary" @click="search">检索</Button>
<Button @click="reset" type="warning" style="margin-left: 10px;">重置
</Button></Col>
<Button type="primary" @click="output">导出中奖记录</Button>
</Row>
</div>
<Table :columns="columns1" :data="data"></Table>
... ... @@ -52,36 +35,17 @@
},
{
title: '奖品类型',
key: 'type',
render: (h, {row}) => {
return h('span', {}, pirzeType[row.type]);
}
key: 'type'
},
{
title: '奖品名称',
key: 'name'
},
{
title: '奖品图片',
key: 'img',
render: (h, {row}) => {
return h('img', {
attrs: {
src: row.img
},
style: {
width: '100%',
height: 'auto',
maxWidth: '70px'
}
});
}
},
{
title: '中奖时间',
key: 'endTime',
key: 'time',
render: (h, {row}) => {
return h('span', {}, moment(new Date(row.create_time).getTime()).format('YYYY-MM-DD HH:mm:ss '));
return h('span', {}, moment(row.time).format('YYYY-MM-DD HH:mm:ss'));
}
}
],
... ... @@ -102,27 +66,6 @@
this.total = res.data.total;
});
},
search() {
let params = {
act_id: this.actId,
pageNo: 1,
pageSize: 10
};
if (this.uid) {
params.uid = this.uid;
}
if (this.type) {
params.type = this.type;
}
if (this.name) {
params.name = this.name;
}
this.list(params);
},
pageChange(page) {
this.pageNo = page;
... ... @@ -132,26 +75,10 @@
pageSize: this.pageSize
};
if (this.uid) {
params.uid = this.uid;
}
if (this.type) {
params.type = this.type;
}
if (this.name) {
params.name = this.name;
}
this.list(params);
},
reset() {
this.uid = '';
this.type = '';
this.name = '';
this.pageNo = 1;
this.list();
output() {
window.open(`/admin/wheelSurf/api/prize/exportRecords?actId=${this.actId}`, '_blank');
}
},
created() {
... ...
... ... @@ -97,6 +97,8 @@ class SqlHelper {
resolve(result);
}
});
}).catch(e => {
reject(e);
});
});
}
... ...
'use strict';
const util = require('util');
const redis = require('redis');
const bluebird = require('bluebird');
const _ = require('lodash');
bluebird.promisifyAll(redis);
class Redis {
constructor(options) {
this.client = redis.createClient(options.connect);
}
}
module.exports = Redis;
... ...