Authored by 李奇

Merge remote-tracking branch 'origin/master' into feature/coupons-expansion

... ... @@ -7,7 +7,8 @@
"html"
],
"rules": {
"camelcase": "off"
"camelcase": "off",
"no-trailing-spaces": "off"
}
}
\ No newline at end of file
}
... ...
... ... @@ -70,6 +70,7 @@ const activity = {
item.endTime = timeFormat(item.endTime);
item.startTime = timeFormat(item.startTime);
item.createTime = timeFormat(item.createTime);
item.repeatLimit = item.repeatLimit === 1 ? '是' : '否';
});
res.render('activity/list', {
... ... @@ -92,6 +93,8 @@ const activity = {
const title = req.body.title;
const startTime = req.body.startTime;
const endTime = req.body.endTime;
const repeat_limit = req.body.repeatLimit;
const vote_limit = req.body.voteLimit;
if (!title || !startTime || !endTime) {
return res.json({
... ... @@ -103,7 +106,9 @@ const activity = {
const params = {
title,
startTime,
endTime
endTime,
repeat_limit,
vote_limit
};
req.ctx(ActivityModel).createActivity(params)
... ... @@ -179,9 +184,11 @@ const activity = {
*/
createArticlePage(req, res) {
const actId = req.query.actId;
let date = new Date();
res.render('activity/create-article', {
actId,
date: moment(date.getTime()).format('YYYY-MM-DD HH:mm:ss'),
bodyClass: 'nav-md',
module: 'admin',
page: 'activity'
... ...
... ... @@ -25,13 +25,16 @@ class AdminModel extends global.yoho.BaseModel {
* @param endTime 活动结束时间
* @returns {*}
*/
createActivity({title, startTime, endTime}) {
createActivity({title, startTime, endTime, repeat_limit, vote_limit}) {
return mysqlCli.insert(
`insert into ${TB_ACTIVITY} (title, start_time, end_time) values (:title, :startTime, :endTime);`,
`insert into ${TB_ACTIVITY} (title, start_time, end_time, repeat_limit, vote_limit)
values (:title, :startTime, :endTime, :repeat_limit, :vote_limit);`,
{
title,
startTime,
endTime
endTime,
repeat_limit,
vote_limit
}
);
}
... ... @@ -42,7 +45,8 @@ class AdminModel extends global.yoho.BaseModel {
*/
activityList() {
return mysqlCli.query(
`select id, title, start_time startTime, end_time endTime, create_time createTime from ${TB_ACTIVITY};`
`select id, title, start_time startTime, end_time endTime, create_time createTime,
repeat_limit repeatLimit, vote_limit voteLimit from ${TB_ACTIVITY};`
);
}
... ... @@ -72,11 +76,13 @@ class AdminModel extends global.yoho.BaseModel {
limitSql = 'limit :start, :page';
return mysqlCli.query(
`select taa.id, taa.content, taa.create_time createTime, taa.good_count goodCount,
tu.user_name userName, tu.user_phone phone
`select taa.id, taai.img_url imgUrl, taa.content, taa.create_time createTime, taa.good_count goodCount,
taa.user_name userName, tu.user_phone phone
from ${TB_ACT_ARTICLE} taa
left join ${TB_USER} tu
on taa.user_id = tu.id
left join ${TB_ACT_ARTICLE_IMG} taai
on taai.article_id = taa.id
where act_id = :actId
${orderSql} ${limitSql};`, {
actId,
... ... @@ -123,10 +129,11 @@ class AdminModel extends global.yoho.BaseModel {
* @param id 文章ID
* @returns {*}
*/
createArticle({actId, userName, content, createTime}) {
createArticle(actId, userName, content, createTime) {
return mysqlCli.insert(
`insert into ${TB_ACT_ARTICLE}
(act_id, user_name, content, create_time) values (:actId, :userName, :content, :createTime);`,
(act_id, user_name, content, create_time) values
(:actId, :userName, :content, :createTime);`,
{
actId,
userName,
... ...
... ... @@ -14,6 +14,7 @@
<thead>
<tr class="headings">
<th class="column-title">文章ID</th>
<th class="clolumn-title">照片</th>
<th class="column-title">内容</th>
<th class="column-title">赞数</th>
<th class="column-title">发布者</th>
... ...
... ... @@ -50,7 +50,7 @@
</label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input type="text" name="createTime" required="required"
class="form-control col-md-7 col-xs-12">
class="form-control col-md-7 col-xs-12" value="{{date}}">
</div>
</div>
<div class="ln_solid"></div>
... ... @@ -60,6 +60,7 @@
</div>
</div>
</form>
<p style="color: red;text-align: center;" id="message"></p>
</div>
</div>
</div>
... ...
... ... @@ -34,7 +34,34 @@
placeholder="开始时间 - 结束时间"/>
</div>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">
是否可以重复投票
</label>
<div class="col-md-6 col-sm-6 col-xs-12">
<label class="control-label col-md-1">
<input type="radio" name="repeatRadio" required="required"
class="form-contro col-md-7 col-xs-12" checked value="1">
</label>
<label class="control-label col-md-1">
<input type="radio" name="repeatRadio" required="required"
class="form-contro col-md-7 col-xs-12" value="0">
</label>
</div>
</div>
<div class="item form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12" for="actName">每天投票限制数<span
class="required">*</span>
</label>
<div class="col-md-2 col-sm-2 col-xs-12">
<input id="actVoteLimit" class="form-control col-md-2"
data-toggle="tooltip" data-placement="bottom" title="投票限制"
name="actVoteLimit"
type="text" maxlength="3" value="5">
</div>
</div>
<div class="ln_solid"></div>
<div class="form-group">
... ...
... ... @@ -15,6 +15,8 @@
<tr class="headings">
<th class="column-title">活动ID</th>
<th class="column-title">活动名称</th>
<th class="column-title">重复投票</th>
<th class="column-title">投票数限制</th>
<th class="column-title">开始时间</th>
<th class="column-title">结束时间</th>
<th class="column-title">创建时间</th>
... ... @@ -25,11 +27,13 @@
<tbody>
{{#each activityList}}
<tr class="even pointer">
<td class="">{{id}}</td>
<td class="">{{title}}</td>
<td class="">{{startTime}}</td>
<td class="">{{endTime}}</td>
<td class="">{{createTime}}</td>
<td class="text-center">{{id}}</td>
<td class="text-center">{{title}}</td>
<td class="text-center">{{repeatLimit}}</td>
<td class="text-center">{{voteLimit}}</td>
<td class="text-center">{{startTime}}</td>
<td class="text-center">{{endTime}}</td>
<td class="text-center">{{createTime}}</td>
<td class="">
<a class="btn btn-info" href="/admin/activity/article?actId={{id}}">文章列表</a>
<a class="btn btn-primary" href="/admin/activity/createArticle?actId={{id}}">
... ...
... ... @@ -10,6 +10,8 @@ const ArticleModel = require('../models/article');
const POST_SUCCESS = '操作成功';
const GET_SUCCESS = '获取成功';
const INVALID_PARAMS = '参数错误';
const VOTE_REPEAT = '不能给同一位选手重复投票';
const VOTE_MAX = '达到每天投票上限';
const article = {
/**
... ... @@ -178,6 +180,7 @@ const article = {
const order = ((query.order || 'desc') + '').toLowerCase();
const orderByFields = ['createTime', 'goodCount'];
const dateTime = query.dateTime || '';
const limitDate = query.limitDate || '';
if (!actId) {
return res.json({
... ... @@ -206,7 +209,8 @@ const article = {
orderBy,
pageNo,
pageSize,
dateTime
dateTime,
limitDate
})
.then(result => {
let list = [];
... ... @@ -456,25 +460,53 @@ const article = {
const actId = req.body.actId;
const articleId = req.body.articleId;
let vote = function() {
req.ctx(ArticleModel).likeArticle(actId, articleId)
.then(() => {
return req.ctx(ArticleModel)
.insertLikeDetail(actId, articleId);
})
.then(() => {
res.json({
code: 200,
message: POST_SUCCESS
});
})
.catch(next);
};
if (!actId || !articleId) {
return res.json({
code: 400,
message: INVALID_PARAMS
});
}
const user_ip = req.headers['X-Forwarded-For'] || req.ip || req.connection.remoteAddress;
req.ctx(ArticleModel).likeArticle(actId, articleId)
.then(() => {
return req.ctx(ArticleModel)
.insertLikeDetail(actId, articleId);
})
.then(() => {
res.json({
code: 200,
message: POST_SUCCESS
// 获取活动投票限制参数
return req.ctx(ArticleModel).getActLimit(actId).then(actInfo => {
const {repeat_limit, vote_limit} = actInfo[0];
// 获取用户IP今日已投票次数
return req.ctx(ArticleModel).getIpCount(actId, user_ip).then(userCount => {
if (userCount.length > 0 && userCount[0].vote_count >= vote_limit) {
return Promise.reject({code: 201, message: VOTE_MAX});
}
if (repeat_limit) {
return Promise.resolve();
}
return req.ctx(ArticleModel).getArticleIp(actId, articleId, user_ip).then(actCount => {
if (actCount.length > 0 && actCount[0].vote_count > 0) {
return Promise.reject({code: 203, message: VOTE_REPEAT});
}
return Promise.resolve();
});
})
.catch(next);
});
}).then(() => {
return vote();
}, (result) => {
return res.json(result);
}).catch(next);
}
};
... ...
... ... @@ -59,13 +59,14 @@ class ArticleModel extends global.yoho.BaseModel {
* 获取文章无用户
* @returns {*}
*/
articleListWithoutUser({actId, pageNo, pageSize, orderBy, order, dateTime}) {
articleListWithoutUser({actId, pageNo, pageSize, orderBy, order, dateTime, limitDate}) {
const orderMapping = {
goodCount: 'good_count',
createTime: 'create_time'
};
const date = dateTime || '';
const limit_date = limitDate || '';
let limitSql;
let orderSql;
... ... @@ -75,6 +76,9 @@ class ArticleModel extends global.yoho.BaseModel {
if (date !== '') {
whereSql += ' AND to_days(AA.create_time) = to_days(\'' + date + '\')';
}
if (limit_date !== '') {
whereSql += ' AND to_days(AA.create_time) <= to_days(\'' + limit_date + '\')';
}
orderSql = `ORDER BY AA.${orderMapping[orderBy]} ${order}`;
limitSql = 'LIMIT :start, :page';
... ... @@ -167,12 +171,13 @@ class ArticleModel extends global.yoho.BaseModel {
const userId = _.get(session, 'user.id');
return mysqlCli.insert(
`insert into ${TABLE_ACT_ARTICLE} (act_id, user_id, content) values (:actId, :userId, :content);`,
`insert into ${TABLE_ACT_ARTICLE} (act_id, user_id, content)
values (:actId, :userId, :content);`,
{
actId,
userId,
imgUrl,
content
content,
imgUrl
}
);
}
... ... @@ -285,6 +290,58 @@ class ArticleModel extends global.yoho.BaseModel {
}
/**
* 获取当前点赞用户点赞的文章的投票限制状态(repeat字段表示该文章是否可以重复投票,vote_limit字段表示该文章)
* @param actId
* @param articleId
* @returns {*}
*/
getActLimit(actId) {
let sqlStr = `SELECT repeat_limit, vote_limit FROM activity WHERE
id = ${actId}`;
return mysqlCli.query(sqlStr);
}
/**
* 获取当前点赞用户点赞时的IP,对应到当天(如果repeat为false,那么代表当前文章不能重复投票)
* @param actId 活动id
* @param articleId 文章id
* @param repeat 是否对于该文章可以重复投票
* @returns {*}
*/
getArticleIp(actId, articleId, ip) {
let sqlStr = `SELECT COUNT(*) as vote_count
FROM ${TABLE_ACT_ARTICLE_GOOD} WHERE act_id = :actId
AND ip = :ip
AND article_id = :articleId
AND to_days(create_time) = to_days(now())`;
return mysqlCli.query(sqlStr, {
actId,
ip,
articleId
});
}
/**
* 获取当前点赞用户的ip今天已经投票的次数
* @param actId
* @param ip
* @returns {*}
*/
getIpCount(actId, ip) {
let sqlStr = `SELECT count(*) AS vote_count
FROM ${TABLE_ACT_ARTICLE_GOOD} WHERE act_id = :actId
AND ip = :ip
AND to_days(create_time) = to_days(now())`;
return mysqlCli.query(sqlStr, {
actId,
ip
});
}
/**
* 文章点赞
* @param actId
* @param articleId
... ...
/*
控制用户投票
@author: qiuj <jun.qiu@yoho.cn>
@date: 2017-10-25 14:54:23
*/
#注意:GO;分割执行块
USE yoho_activity_platform;
GO;
ALTER TABLE activity ADD `repeat_limit` TINYINT DEFAULT 1;
GO;
ALTER TABLE activity ADD `vote_limit` INT DEFAULT 5;
GO;
... ...
module.exports = ['_migration', '20170913102356', '20170927092926'];
module.exports = ['_migration', '20170913102356', '20170927092926', '20171025145423'];
... ...
... ... @@ -31,6 +31,8 @@ function bind_create_act() {
const timeArray = actTime.split(' - ');
const startTime = toUnixTimestamp(timeArray[0]);
const endTime = toUnixTimestamp(timeArray[1]);
const repeat_limit = $('input[name=repeatRadio]:checked').val() || 1;
const vote_limit = $('#actVoteLimit').val() || 5;
if (!actName.length) {
return $actName.tooltip('show');
... ... @@ -42,10 +44,13 @@ function bind_create_act() {
data: {
startTime,
endTime,
title: actName
title: actName,
repeatLimit: repeat_limit,
voteLimit: vote_limit
}
})
.then(result => {
if (result.code !== 200) {
return;
}
... ... @@ -150,6 +155,7 @@ function bind_table_pagination() {
html += `
<tr class="even pointer">
<td>${item.id}</td>
<td><img src="${item.imgUrl}" style="width: 100px"></td>
<td>${(item.content || '').substr(0, 50) + ((item.content || '').length > 50 ? '...' : '')}</td>
<td>${item.goodCount}</td>
<td>${item.userName || '-'}</td>
... ... @@ -256,16 +262,27 @@ function bind_qiniu_upload() {
});
$('.article-create-btn').on('click', function() {
var $form = $('#createArticleForm');
let $form = $('#createArticleForm');
let userName = $form[0][0].value;
let content = $form[0][1].value;
let imgUrl = $form[0][2].value;
let actId = $form[0][3].value;
let createTime = $form[0][5].value;
console.log($form.serialize(), userName, content, imgUrl, actId, createTime);
if (userName !== '' && content !== '' && imgUrl !== '' && actId !== '') {
$('#message').text('');
$.ajax({
method: 'post',
url: '/admin/api/activity/createArticle',
data: $form.serialize()
}).then(() => {
location.reload();
});
} else {
$('#message').text('请填写完整的信息');
}
$.ajax({
method: 'post',
url: '/admin/api/activity/createArticle',
data: $form.serialize()
})
.then(() => {
location.reload();
});
});
}
... ...