Authored by 李奇

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

@@ -7,7 +7,8 @@ @@ -7,7 +7,8 @@
7 "html" 7 "html"
8 ], 8 ],
9 "rules": { 9 "rules": {
10 - "camelcase": "off" 10 + "camelcase": "off",
  11 + "no-trailing-spaces": "off"
11 } 12 }
12 13
13 -}  
  14 +}
@@ -70,6 +70,7 @@ const activity = { @@ -70,6 +70,7 @@ const activity = {
70 item.endTime = timeFormat(item.endTime); 70 item.endTime = timeFormat(item.endTime);
71 item.startTime = timeFormat(item.startTime); 71 item.startTime = timeFormat(item.startTime);
72 item.createTime = timeFormat(item.createTime); 72 item.createTime = timeFormat(item.createTime);
  73 + item.repeatLimit = item.repeatLimit === 1 ? '是' : '否';
73 }); 74 });
74 75
75 res.render('activity/list', { 76 res.render('activity/list', {
@@ -92,6 +93,8 @@ const activity = { @@ -92,6 +93,8 @@ const activity = {
92 const title = req.body.title; 93 const title = req.body.title;
93 const startTime = req.body.startTime; 94 const startTime = req.body.startTime;
94 const endTime = req.body.endTime; 95 const endTime = req.body.endTime;
  96 + const repeat_limit = req.body.repeatLimit;
  97 + const vote_limit = req.body.voteLimit;
95 98
96 if (!title || !startTime || !endTime) { 99 if (!title || !startTime || !endTime) {
97 return res.json({ 100 return res.json({
@@ -103,7 +106,9 @@ const activity = { @@ -103,7 +106,9 @@ const activity = {
103 const params = { 106 const params = {
104 title, 107 title,
105 startTime, 108 startTime,
106 - endTime 109 + endTime,
  110 + repeat_limit,
  111 + vote_limit
107 }; 112 };
108 113
109 req.ctx(ActivityModel).createActivity(params) 114 req.ctx(ActivityModel).createActivity(params)
@@ -179,9 +184,11 @@ const activity = { @@ -179,9 +184,11 @@ const activity = {
179 */ 184 */
180 createArticlePage(req, res) { 185 createArticlePage(req, res) {
181 const actId = req.query.actId; 186 const actId = req.query.actId;
  187 + let date = new Date();
182 188
183 res.render('activity/create-article', { 189 res.render('activity/create-article', {
184 actId, 190 actId,
  191 + date: moment(date.getTime()).format('YYYY-MM-DD HH:mm:ss'),
185 bodyClass: 'nav-md', 192 bodyClass: 'nav-md',
186 module: 'admin', 193 module: 'admin',
187 page: 'activity' 194 page: 'activity'
@@ -25,13 +25,16 @@ class AdminModel extends global.yoho.BaseModel { @@ -25,13 +25,16 @@ class AdminModel extends global.yoho.BaseModel {
25 * @param endTime 活动结束时间 25 * @param endTime 活动结束时间
26 * @returns {*} 26 * @returns {*}
27 */ 27 */
28 - createActivity({title, startTime, endTime}) { 28 + createActivity({title, startTime, endTime, repeat_limit, vote_limit}) {
29 return mysqlCli.insert( 29 return mysqlCli.insert(
30 - `insert into ${TB_ACTIVITY} (title, start_time, end_time) values (:title, :startTime, :endTime);`, 30 + `insert into ${TB_ACTIVITY} (title, start_time, end_time, repeat_limit, vote_limit)
  31 + values (:title, :startTime, :endTime, :repeat_limit, :vote_limit);`,
31 { 32 {
32 title, 33 title,
33 startTime, 34 startTime,
34 - endTime 35 + endTime,
  36 + repeat_limit,
  37 + vote_limit
35 } 38 }
36 ); 39 );
37 } 40 }
@@ -42,7 +45,8 @@ class AdminModel extends global.yoho.BaseModel { @@ -42,7 +45,8 @@ class AdminModel extends global.yoho.BaseModel {
42 */ 45 */
43 activityList() { 46 activityList() {
44 return mysqlCli.query( 47 return mysqlCli.query(
45 - `select id, title, start_time startTime, end_time endTime, create_time createTime from ${TB_ACTIVITY};` 48 + `select id, title, start_time startTime, end_time endTime, create_time createTime,
  49 + repeat_limit repeatLimit, vote_limit voteLimit from ${TB_ACTIVITY};`
46 ); 50 );
47 } 51 }
48 52
@@ -72,11 +76,13 @@ class AdminModel extends global.yoho.BaseModel { @@ -72,11 +76,13 @@ class AdminModel extends global.yoho.BaseModel {
72 limitSql = 'limit :start, :page'; 76 limitSql = 'limit :start, :page';
73 77
74 return mysqlCli.query( 78 return mysqlCli.query(
75 - `select taa.id, taa.content, taa.create_time createTime, taa.good_count goodCount,  
76 - tu.user_name userName, tu.user_phone phone 79 + `select taa.id, taai.img_url imgUrl, taa.content, taa.create_time createTime, taa.good_count goodCount,
  80 + taa.user_name userName, tu.user_phone phone
77 from ${TB_ACT_ARTICLE} taa 81 from ${TB_ACT_ARTICLE} taa
78 left join ${TB_USER} tu 82 left join ${TB_USER} tu
79 on taa.user_id = tu.id 83 on taa.user_id = tu.id
  84 + left join ${TB_ACT_ARTICLE_IMG} taai
  85 + on taai.article_id = taa.id
80 where act_id = :actId 86 where act_id = :actId
81 ${orderSql} ${limitSql};`, { 87 ${orderSql} ${limitSql};`, {
82 actId, 88 actId,
@@ -123,10 +129,11 @@ class AdminModel extends global.yoho.BaseModel { @@ -123,10 +129,11 @@ class AdminModel extends global.yoho.BaseModel {
123 * @param id 文章ID 129 * @param id 文章ID
124 * @returns {*} 130 * @returns {*}
125 */ 131 */
126 - createArticle({actId, userName, content, createTime}) { 132 + createArticle(actId, userName, content, createTime) {
127 return mysqlCli.insert( 133 return mysqlCli.insert(
128 `insert into ${TB_ACT_ARTICLE} 134 `insert into ${TB_ACT_ARTICLE}
129 - (act_id, user_name, content, create_time) values (:actId, :userName, :content, :createTime);`, 135 + (act_id, user_name, content, create_time) values
  136 + (:actId, :userName, :content, :createTime);`,
130 { 137 {
131 actId, 138 actId,
132 userName, 139 userName,
@@ -14,6 +14,7 @@ @@ -14,6 +14,7 @@
14 <thead> 14 <thead>
15 <tr class="headings"> 15 <tr class="headings">
16 <th class="column-title">文章ID</th> 16 <th class="column-title">文章ID</th>
  17 + <th class="clolumn-title">照片</th>
17 <th class="column-title">内容</th> 18 <th class="column-title">内容</th>
18 <th class="column-title">赞数</th> 19 <th class="column-title">赞数</th>
19 <th class="column-title">发布者</th> 20 <th class="column-title">发布者</th>
@@ -50,7 +50,7 @@ @@ -50,7 +50,7 @@
50 </label> 50 </label>
51 <div class="col-md-6 col-sm-6 col-xs-12"> 51 <div class="col-md-6 col-sm-6 col-xs-12">
52 <input type="text" name="createTime" required="required" 52 <input type="text" name="createTime" required="required"
53 - class="form-control col-md-7 col-xs-12"> 53 + class="form-control col-md-7 col-xs-12" value="{{date}}">
54 </div> 54 </div>
55 </div> 55 </div>
56 <div class="ln_solid"></div> 56 <div class="ln_solid"></div>
@@ -60,6 +60,7 @@ @@ -60,6 +60,7 @@
60 </div> 60 </div>
61 </div> 61 </div>
62 </form> 62 </form>
  63 + <p style="color: red;text-align: center;" id="message"></p>
63 </div> 64 </div>
64 </div> 65 </div>
65 </div> 66 </div>
@@ -34,7 +34,34 @@ @@ -34,7 +34,34 @@
34 placeholder="开始时间 - 结束时间"/> 34 placeholder="开始时间 - 结束时间"/>
35 </div> 35 </div>
36 </div> 36 </div>
37 - 37 + </div>
  38 + <div class="form-group">
  39 + <label class="control-label col-md-3 col-sm-3 col-xs-12">
  40 + 是否可以重复投票
  41 + </label>
  42 + <div class="col-md-6 col-sm-6 col-xs-12">
  43 + <label class="control-label col-md-1">
  44 + <input type="radio" name="repeatRadio" required="required"
  45 + class="form-contro col-md-7 col-xs-12" checked value="1">
  46 +
  47 + </label>
  48 + <label class="control-label col-md-1">
  49 + <input type="radio" name="repeatRadio" required="required"
  50 + class="form-contro col-md-7 col-xs-12" value="0">
  51 +
  52 + </label>
  53 + </div>
  54 + </div>
  55 + <div class="item form-group">
  56 + <label class="control-label col-md-3 col-sm-3 col-xs-12" for="actName">每天投票限制数<span
  57 + class="required">*</span>
  58 + </label>
  59 + <div class="col-md-2 col-sm-2 col-xs-12">
  60 + <input id="actVoteLimit" class="form-control col-md-2"
  61 + data-toggle="tooltip" data-placement="bottom" title="投票限制"
  62 + name="actVoteLimit"
  63 + type="text" maxlength="3" value="5">
  64 + </div>
38 </div> 65 </div>
39 <div class="ln_solid"></div> 66 <div class="ln_solid"></div>
40 <div class="form-group"> 67 <div class="form-group">
@@ -15,6 +15,8 @@ @@ -15,6 +15,8 @@
15 <tr class="headings"> 15 <tr class="headings">
16 <th class="column-title">活动ID</th> 16 <th class="column-title">活动ID</th>
17 <th class="column-title">活动名称</th> 17 <th class="column-title">活动名称</th>
  18 + <th class="column-title">重复投票</th>
  19 + <th class="column-title">投票数限制</th>
18 <th class="column-title">开始时间</th> 20 <th class="column-title">开始时间</th>
19 <th class="column-title">结束时间</th> 21 <th class="column-title">结束时间</th>
20 <th class="column-title">创建时间</th> 22 <th class="column-title">创建时间</th>
@@ -25,11 +27,13 @@ @@ -25,11 +27,13 @@
25 <tbody> 27 <tbody>
26 {{#each activityList}} 28 {{#each activityList}}
27 <tr class="even pointer"> 29 <tr class="even pointer">
28 - <td class="">{{id}}</td>  
29 - <td class="">{{title}}</td>  
30 - <td class="">{{startTime}}</td>  
31 - <td class="">{{endTime}}</td>  
32 - <td class="">{{createTime}}</td> 30 + <td class="text-center">{{id}}</td>
  31 + <td class="text-center">{{title}}</td>
  32 + <td class="text-center">{{repeatLimit}}</td>
  33 + <td class="text-center">{{voteLimit}}</td>
  34 + <td class="text-center">{{startTime}}</td>
  35 + <td class="text-center">{{endTime}}</td>
  36 + <td class="text-center">{{createTime}}</td>
33 <td class=""> 37 <td class="">
34 <a class="btn btn-info" href="/admin/activity/article?actId={{id}}">文章列表</a> 38 <a class="btn btn-info" href="/admin/activity/article?actId={{id}}">文章列表</a>
35 <a class="btn btn-primary" href="/admin/activity/createArticle?actId={{id}}"> 39 <a class="btn btn-primary" href="/admin/activity/createArticle?actId={{id}}">
@@ -10,6 +10,8 @@ const ArticleModel = require('../models/article'); @@ -10,6 +10,8 @@ const ArticleModel = require('../models/article');
10 const POST_SUCCESS = '操作成功'; 10 const POST_SUCCESS = '操作成功';
11 const GET_SUCCESS = '获取成功'; 11 const GET_SUCCESS = '获取成功';
12 const INVALID_PARAMS = '参数错误'; 12 const INVALID_PARAMS = '参数错误';
  13 +const VOTE_REPEAT = '不能给同一位选手重复投票';
  14 +const VOTE_MAX = '达到每天投票上限';
13 15
14 const article = { 16 const article = {
15 /** 17 /**
@@ -178,6 +180,7 @@ const article = { @@ -178,6 +180,7 @@ const article = {
178 const order = ((query.order || 'desc') + '').toLowerCase(); 180 const order = ((query.order || 'desc') + '').toLowerCase();
179 const orderByFields = ['createTime', 'goodCount']; 181 const orderByFields = ['createTime', 'goodCount'];
180 const dateTime = query.dateTime || ''; 182 const dateTime = query.dateTime || '';
  183 + const limitDate = query.limitDate || '';
181 184
182 if (!actId) { 185 if (!actId) {
183 return res.json({ 186 return res.json({
@@ -206,7 +209,8 @@ const article = { @@ -206,7 +209,8 @@ const article = {
206 orderBy, 209 orderBy,
207 pageNo, 210 pageNo,
208 pageSize, 211 pageSize,
209 - dateTime 212 + dateTime,
  213 + limitDate
210 }) 214 })
211 .then(result => { 215 .then(result => {
212 let list = []; 216 let list = [];
@@ -456,25 +460,53 @@ const article = { @@ -456,25 +460,53 @@ const article = {
456 const actId = req.body.actId; 460 const actId = req.body.actId;
457 const articleId = req.body.articleId; 461 const articleId = req.body.articleId;
458 462
  463 + let vote = function() {
  464 + req.ctx(ArticleModel).likeArticle(actId, articleId)
  465 + .then(() => {
  466 + return req.ctx(ArticleModel)
  467 + .insertLikeDetail(actId, articleId);
  468 + })
  469 + .then(() => {
  470 + res.json({
  471 + code: 200,
  472 + message: POST_SUCCESS
  473 + });
  474 + })
  475 + .catch(next);
  476 + };
  477 +
459 if (!actId || !articleId) { 478 if (!actId || !articleId) {
460 return res.json({ 479 return res.json({
461 code: 400, 480 code: 400,
462 message: INVALID_PARAMS 481 message: INVALID_PARAMS
463 }); 482 });
464 } 483 }
  484 + const user_ip = req.headers['X-Forwarded-For'] || req.ip || req.connection.remoteAddress;
465 485
466 - req.ctx(ArticleModel).likeArticle(actId, articleId)  
467 - .then(() => {  
468 - return req.ctx(ArticleModel)  
469 - .insertLikeDetail(actId, articleId);  
470 - })  
471 - .then(() => {  
472 - res.json({  
473 - code: 200,  
474 - message: POST_SUCCESS 486 + // 获取活动投票限制参数
  487 + return req.ctx(ArticleModel).getActLimit(actId).then(actInfo => {
  488 + const {repeat_limit, vote_limit} = actInfo[0];
  489 +
  490 + // 获取用户IP今日已投票次数
  491 + return req.ctx(ArticleModel).getIpCount(actId, user_ip).then(userCount => {
  492 + if (userCount.length > 0 && userCount[0].vote_count >= vote_limit) {
  493 + return Promise.reject({code: 201, message: VOTE_MAX});
  494 + }
  495 + if (repeat_limit) {
  496 + return Promise.resolve();
  497 + }
  498 + return req.ctx(ArticleModel).getArticleIp(actId, articleId, user_ip).then(actCount => {
  499 + if (actCount.length > 0 && actCount[0].vote_count > 0) {
  500 + return Promise.reject({code: 203, message: VOTE_REPEAT});
  501 + }
  502 + return Promise.resolve();
475 }); 503 });
476 - })  
477 - .catch(next); 504 + });
  505 + }).then(() => {
  506 + return vote();
  507 + }, (result) => {
  508 + return res.json(result);
  509 + }).catch(next);
478 } 510 }
479 }; 511 };
480 512
@@ -59,13 +59,14 @@ class ArticleModel extends global.yoho.BaseModel { @@ -59,13 +59,14 @@ class ArticleModel extends global.yoho.BaseModel {
59 * 获取文章无用户 59 * 获取文章无用户
60 * @returns {*} 60 * @returns {*}
61 */ 61 */
62 - articleListWithoutUser({actId, pageNo, pageSize, orderBy, order, dateTime}) { 62 + articleListWithoutUser({actId, pageNo, pageSize, orderBy, order, dateTime, limitDate}) {
63 const orderMapping = { 63 const orderMapping = {
64 goodCount: 'good_count', 64 goodCount: 'good_count',
65 createTime: 'create_time' 65 createTime: 'create_time'
66 }; 66 };
67 67
68 const date = dateTime || ''; 68 const date = dateTime || '';
  69 + const limit_date = limitDate || '';
69 70
70 let limitSql; 71 let limitSql;
71 let orderSql; 72 let orderSql;
@@ -75,6 +76,9 @@ class ArticleModel extends global.yoho.BaseModel { @@ -75,6 +76,9 @@ class ArticleModel extends global.yoho.BaseModel {
75 if (date !== '') { 76 if (date !== '') {
76 whereSql += ' AND to_days(AA.create_time) = to_days(\'' + date + '\')'; 77 whereSql += ' AND to_days(AA.create_time) = to_days(\'' + date + '\')';
77 } 78 }
  79 + if (limit_date !== '') {
  80 + whereSql += ' AND to_days(AA.create_time) <= to_days(\'' + limit_date + '\')';
  81 + }
78 orderSql = `ORDER BY AA.${orderMapping[orderBy]} ${order}`; 82 orderSql = `ORDER BY AA.${orderMapping[orderBy]} ${order}`;
79 limitSql = 'LIMIT :start, :page'; 83 limitSql = 'LIMIT :start, :page';
80 84
@@ -167,12 +171,13 @@ class ArticleModel extends global.yoho.BaseModel { @@ -167,12 +171,13 @@ class ArticleModel extends global.yoho.BaseModel {
167 const userId = _.get(session, 'user.id'); 171 const userId = _.get(session, 'user.id');
168 172
169 return mysqlCli.insert( 173 return mysqlCli.insert(
170 - `insert into ${TABLE_ACT_ARTICLE} (act_id, user_id, content) values (:actId, :userId, :content);`, 174 + `insert into ${TABLE_ACT_ARTICLE} (act_id, user_id, content)
  175 + values (:actId, :userId, :content);`,
171 { 176 {
172 actId, 177 actId,
173 userId, 178 userId,
174 - imgUrl,  
175 - content 179 + content,
  180 + imgUrl
176 } 181 }
177 ); 182 );
178 } 183 }
@@ -285,6 +290,58 @@ class ArticleModel extends global.yoho.BaseModel { @@ -285,6 +290,58 @@ class ArticleModel extends global.yoho.BaseModel {
285 } 290 }
286 291
287 /** 292 /**
  293 + * 获取当前点赞用户点赞的文章的投票限制状态(repeat字段表示该文章是否可以重复投票,vote_limit字段表示该文章)
  294 + * @param actId
  295 + * @param articleId
  296 + * @returns {*}
  297 + */
  298 + getActLimit(actId) {
  299 + let sqlStr = `SELECT repeat_limit, vote_limit FROM activity WHERE
  300 + id = ${actId}`;
  301 +
  302 + return mysqlCli.query(sqlStr);
  303 + }
  304 +
  305 + /**
  306 + * 获取当前点赞用户点赞时的IP,对应到当天(如果repeat为false,那么代表当前文章不能重复投票)
  307 + * @param actId 活动id
  308 + * @param articleId 文章id
  309 + * @param repeat 是否对于该文章可以重复投票
  310 + * @returns {*}
  311 + */
  312 + getArticleIp(actId, articleId, ip) {
  313 + let sqlStr = `SELECT COUNT(*) as vote_count
  314 + FROM ${TABLE_ACT_ARTICLE_GOOD} WHERE act_id = :actId
  315 + AND ip = :ip
  316 + AND article_id = :articleId
  317 + AND to_days(create_time) = to_days(now())`;
  318 +
  319 + return mysqlCli.query(sqlStr, {
  320 + actId,
  321 + ip,
  322 + articleId
  323 + });
  324 + }
  325 +
  326 + /**
  327 + * 获取当前点赞用户的ip今天已经投票的次数
  328 + * @param actId
  329 + * @param ip
  330 + * @returns {*}
  331 + */
  332 + getIpCount(actId, ip) {
  333 + let sqlStr = `SELECT count(*) AS vote_count
  334 + FROM ${TABLE_ACT_ARTICLE_GOOD} WHERE act_id = :actId
  335 + AND ip = :ip
  336 + AND to_days(create_time) = to_days(now())`;
  337 +
  338 + return mysqlCli.query(sqlStr, {
  339 + actId,
  340 + ip
  341 + });
  342 + }
  343 +
  344 + /**
288 * 文章点赞 345 * 文章点赞
289 * @param actId 346 * @param actId
290 * @param articleId 347 * @param articleId
  1 +/*
  2 + 控制用户投票
  3 + @author: qiuj <jun.qiu@yoho.cn>
  4 + @date: 2017-10-25 14:54:23
  5 +*/
  6 +#注意:GO;分割执行块
  7 +USE yoho_activity_platform;
  8 +GO;
  9 +ALTER TABLE activity ADD `repeat_limit` TINYINT DEFAULT 1;
  10 +GO;
  11 +ALTER TABLE activity ADD `vote_limit` INT DEFAULT 5;
  12 +GO;
1 -module.exports = ['_migration', '20170913102356', '20170927092926']; 1 +module.exports = ['_migration', '20170913102356', '20170927092926', '20171025145423'];
@@ -31,6 +31,8 @@ function bind_create_act() { @@ -31,6 +31,8 @@ function bind_create_act() {
31 const timeArray = actTime.split(' - '); 31 const timeArray = actTime.split(' - ');
32 const startTime = toUnixTimestamp(timeArray[0]); 32 const startTime = toUnixTimestamp(timeArray[0]);
33 const endTime = toUnixTimestamp(timeArray[1]); 33 const endTime = toUnixTimestamp(timeArray[1]);
  34 + const repeat_limit = $('input[name=repeatRadio]:checked').val() || 1;
  35 + const vote_limit = $('#actVoteLimit').val() || 5;
34 36
35 if (!actName.length) { 37 if (!actName.length) {
36 return $actName.tooltip('show'); 38 return $actName.tooltip('show');
@@ -42,10 +44,13 @@ function bind_create_act() { @@ -42,10 +44,13 @@ function bind_create_act() {
42 data: { 44 data: {
43 startTime, 45 startTime,
44 endTime, 46 endTime,
45 - title: actName 47 + title: actName,
  48 + repeatLimit: repeat_limit,
  49 + voteLimit: vote_limit
46 } 50 }
47 }) 51 })
48 .then(result => { 52 .then(result => {
  53 +
49 if (result.code !== 200) { 54 if (result.code !== 200) {
50 return; 55 return;
51 } 56 }
@@ -150,6 +155,7 @@ function bind_table_pagination() { @@ -150,6 +155,7 @@ function bind_table_pagination() {
150 html += ` 155 html += `
151 <tr class="even pointer"> 156 <tr class="even pointer">
152 <td>${item.id}</td> 157 <td>${item.id}</td>
  158 + <td><img src="${item.imgUrl}" style="width: 100px"></td>
153 <td>${(item.content || '').substr(0, 50) + ((item.content || '').length > 50 ? '...' : '')}</td> 159 <td>${(item.content || '').substr(0, 50) + ((item.content || '').length > 50 ? '...' : '')}</td>
154 <td>${item.goodCount}</td> 160 <td>${item.goodCount}</td>
155 <td>${item.userName || '-'}</td> 161 <td>${item.userName || '-'}</td>
@@ -256,16 +262,27 @@ function bind_qiniu_upload() { @@ -256,16 +262,27 @@ function bind_qiniu_upload() {
256 }); 262 });
257 263
258 $('.article-create-btn').on('click', function() { 264 $('.article-create-btn').on('click', function() {
259 - var $form = $('#createArticleForm'); 265 + let $form = $('#createArticleForm');
  266 + let userName = $form[0][0].value;
  267 + let content = $form[0][1].value;
  268 + let imgUrl = $form[0][2].value;
  269 + let actId = $form[0][3].value;
  270 + let createTime = $form[0][5].value;
  271 +
  272 + console.log($form.serialize(), userName, content, imgUrl, actId, createTime);
  273 + if (userName !== '' && content !== '' && imgUrl !== '' && actId !== '') {
  274 + $('#message').text('');
  275 + $.ajax({
  276 + method: 'post',
  277 + url: '/admin/api/activity/createArticle',
  278 + data: $form.serialize()
  279 + }).then(() => {
  280 + location.reload();
  281 + });
  282 + } else {
  283 + $('#message').text('请填写完整的信息');
  284 + }
260 285
261 - $.ajax({  
262 - method: 'post',  
263 - url: '/admin/api/activity/createArticle',  
264 - data: $form.serialize()  
265 - })  
266 - .then(() => {  
267 - location.reload();  
268 - });  
269 }); 286 });
270 } 287 }
271 288