Authored by 沈志敏

Merge branch 'release/5.2' of git.yoho.cn:fe/yohobuywap-node into release/5.2

@@ -55,7 +55,6 @@ const getRssArticle = (gender) => { @@ -55,7 +55,6 @@ const getRssArticle = (gender) => {
55 resolve(result); 55 resolve(result);
56 } 56 }
57 }; 57 };
58 -  
59 return new Promise((resolve) => { 58 return new Promise((resolve) => {
60 artListFunc(0, article.data.list.artList.length, resolve); 59 artListFunc(0, article.data.list.artList.length, resolve);
61 }); 60 });
@@ -96,4 +95,4 @@ const _genIntro = (id) => { @@ -96,4 +95,4 @@ const _genIntro = (id) => {
96 95
97 module.exports = { 96 module.exports = {
98 getRssArticle 97 getRssArticle
99 -}; 98 +};
@@ -11,11 +11,11 @@ const headerModel = require('../../../doraemon/models/header'); // 头部model @@ -11,11 +11,11 @@ const headerModel = require('../../../doraemon/models/header'); // 头部model
11 const _ = require('lodash'); 11 const _ = require('lodash');
12 12
13 const suggestData = (req, res, next) => { 13 const suggestData = (req, res, next) => {
  14 + let uid = req.user.uid;
14 let udid = req.sessionID || 'yoho'; 15 let udid = req.sessionID || 'yoho';
15 let page = req.query.page || 1; 16 let page = req.query.page || 1;
16 let limit = 10; 17 let limit = 10;
17 -  
18 - suggestModel.suggestData(udid, page, limit).then((result) => { 18 + suggestModel.suggestData(uid, udid, page, limit).then((result) => {
19 19
20 res.render('suggest', { 20 res.render('suggest', {
21 module: 'home', 21 module: 'home',
@@ -11,14 +11,13 @@ const serviceAPI = global.yoho.ServiceAPI; @@ -11,14 +11,13 @@ const serviceAPI = global.yoho.ServiceAPI;
11 const camelCase = global.yoho.camelCase; 11 const camelCase = global.yoho.camelCase;
12 const _ = require('lodash'); 12 const _ = require('lodash');
13 13
14 -const suggestData = (udid, page, limit) => { 14 +const suggestData = (uid, udid, page, limit) => {
15 15
16 return serviceAPI.get('suggest/api/v1/suggest/getList', { 16 return serviceAPI.get('suggest/api/v1/suggest/getList', {
17 udid: udid, 17 udid: udid,
18 page: page, 18 page: page,
19 limit: limit 19 limit: limit
20 }).then((result) => { 20 }).then((result) => {
21 -  
22 if (result && result.code === 200 && result.data) { 21 if (result && result.code === 200 && result.data) {
23 _.forEach(result.data.list, function(data) { 22 _.forEach(result.data.list, function(data) {
24 23
@@ -36,7 +35,6 @@ const suggestData = (udid, page, limit) => { @@ -36,7 +35,6 @@ const suggestData = (udid, page, limit) => {
36 }; 35 };
37 36
38 const upAndDown = (uid, udid, reliable, suggestId) => { 37 const upAndDown = (uid, udid, reliable, suggestId) => {
39 -  
40 return serviceAPI.get('suggest/api/v1/suggest/is_reliable', { 38 return serviceAPI.get('suggest/api/v1/suggest/is_reliable', {
41 uid: uid, 39 uid: uid,
42 udid: udid, 40 udid: udid,
@@ -10,6 +10,7 @@ const _ = require('lodash'); @@ -10,6 +10,7 @@ const _ = require('lodash');
10 const helpers = global.yoho.helpers; 10 const helpers = global.yoho.helpers;
11 11
12 const service = require('../models/back-service'); 12 const service = require('../models/back-service');
  13 +const captchaService = require('../models/captcha-service');
13 14
14 const SIGN_IN = helpers.urlFormat('/passport/login'); 15 const SIGN_IN = helpers.urlFormat('/passport/login');
15 16
@@ -150,18 +151,93 @@ const indexMobilePage = (req, res, next) => { @@ -150,18 +151,93 @@ const indexMobilePage = (req, res, next) => {
150 isPassportPage: true, 151 isPassportPage: true,
151 backMobile: true, 152 backMobile: true,
152 countrys: result.data, 153 countrys: result.data,
153 - areaCode: '+86' 154 + areaCode: '+86',
  155 + verifySrc: helpers.urlFormat('/passport/back/generatecodeimg.png', {t: Date.now()})
154 })); 156 }));
155 }) 157 })
156 .catch(next); 158 .catch(next);
157 }; 159 };
158 160
159 /** 161 /**
  162 + * 生成验证码
  163 + * @param req
  164 + * @param res
  165 + */
  166 +const generateCodeImg = (req, res) => {
  167 + let verifyCodeImg = captchaService.generateCaptcha(109, 50, 4);
  168 +
  169 + if (verifyCodeImg) {
  170 +
  171 + if (req.session.backupCaptch) {
  172 + req.session.backupCaptch.code = verifyCodeImg.text;
  173 + req.session.backupCaptch.verifyResult = false;
  174 + } else {
  175 + req.session.backupCaptch = {
  176 + code: verifyCodeImg.text,
  177 + verifyResult: false
  178 + };
  179 + }
  180 +
  181 + res.set('Cache-Control', 'no-cache').send(verifyCodeImg.image);
  182 + }
  183 +};
  184 +
  185 +/**
160 * 发送手机验证码 186 * 发送手机验证码
161 */ 187 */
162 const sendCodeToMobileAPI = (req, res, next) => { 188 const sendCodeToMobileAPI = (req, res, next) => {
  189 + let verifyCode = req.body.verifyCode || '';
163 let phoneNum = req.body.phoneNum || ''; 190 let phoneNum = req.body.phoneNum || '';
164 let areaCode = req.body.areaCode || '86'; 191 let areaCode = req.body.areaCode || '86';
  192 +
  193 + /* 如果设置了冻结时间,验证 */
  194 + if (_.has(req.session, 'backupCaptch.timeout')) {
  195 + let untilTime = (parseInt(req.session.backupCaptch.timeout, 10) -
  196 + parseInt(Date.now(), 10)) / 1000 / 60;
  197 +
  198 + if (parseInt(Date.now(), 10) < parseInt(req.session.backupCaptch.timeout, 10)) {
  199 + return res.json({
  200 + code: 401,
  201 + message: '请' + (parseInt(untilTime, 10) + 1) + '分钟后尝试!'
  202 + });
  203 + }
  204 + }
  205 +
  206 + /* 如果设置了验证次数,验证是否合法,验证次数减 1;没有,设置验证次数 */
  207 + if (_.has(req.session, 'backupCaptch.useTime')) {
  208 + if (parseInt(req.session.backupCaptch.useTime, 10) <= 0) {
  209 +
  210 + /* 如果超过验证次数,冻结 5 分钟,更新验证次数 */
  211 + req.session.backupCaptch.timeout = Date.now() + 5 * 60 * 1000;
  212 + req.session.backupCaptch.useTime = 5;
  213 + return res.json({
  214 + code: 401,
  215 + message: '请5分钟后尝试!'
  216 + });
  217 + }
  218 + req.session.backupCaptch.useTime = req.session.backupCaptch.useTime - 1;
  219 + } else {
  220 + req.session.backupCaptch.useTime = 5;
  221 + }
  222 +
  223 + if (verifyCode) {
  224 + if (verifyCode.toString() === _.get(req, 'session.backupCaptch.code', '').toString()) {
  225 + req.session.backupCaptch.verifyResult = true;
  226 + } else {
  227 + return res.json({
  228 + code: 400,
  229 + message: '验证码输入错误'
  230 + });
  231 + }
  232 + } else if (!req.session.backupCaptch.verifyResult) {
  233 +
  234 + return res.json({
  235 + code: 409,
  236 + message: '非法请求!',
  237 + refer: helpers.urlFormat('/')
  238 + });
  239 + }
  240 +
165 let ERR = { 241 let ERR = {
166 code: 400, 242 code: 400,
167 message: '输入手机号码出错' 243 message: '输入手机号码出错'
@@ -198,6 +274,11 @@ const verifyCodeByMobilePage = (req, res) => { @@ -198,6 +274,11 @@ const verifyCodeByMobilePage = (req, res) => {
198 let phoneNum = req.query.phoneNum || ''; 274 let phoneNum = req.query.phoneNum || '';
199 let areaCode = req.query.areaCode || '86'; 275 let areaCode = req.query.areaCode || '86';
200 276
  277 + /* 用户直接进入第二个页面的情况 */
  278 + if (!_.get(req, 'session.backupCaptch.verifyResult')) {
  279 + return res.redirect(helpers.urlFormat('/'));
  280 + }
  281 +
201 res.render('back/mobile-code', Object.assign({ 282 res.render('back/mobile-code', Object.assign({
202 module: 'passport', 283 module: 'passport',
203 page: 'back-code', 284 page: 'back-code',
@@ -208,8 +289,8 @@ const verifyCodeByMobilePage = (req, res) => { @@ -208,8 +289,8 @@ const verifyCodeByMobilePage = (req, res) => {
208 isPassportPage: true, 289 isPassportPage: true,
209 backCode: true, 290 backCode: true,
210 areaCode: areaCode, 291 areaCode: areaCode,
211 - phoneNum: phoneNum  
212 - 292 + phoneNum: phoneNum,
  293 + verifySrc: helpers.urlFormat('/passport/back/generatecodeimg.png', {t: Date.now()})
213 })); 294 }));
214 }; 295 };
215 296
@@ -309,5 +390,6 @@ module.exports = { @@ -309,5 +390,6 @@ module.exports = {
309 verifyCodeByMobilePage, 390 verifyCodeByMobilePage,
310 verifyCodeByMobileAPI, 391 verifyCodeByMobileAPI,
311 setNewPasswordByMobilePage, 392 setNewPasswordByMobilePage,
312 - setNewPasswordByMobileAPI 393 + setNewPasswordByMobileAPI,
  394 + generateCodeImg
313 }; 395 };
@@ -13,8 +13,49 @@ const sign = global.yoho.sign; @@ -13,8 +13,49 @@ const sign = global.yoho.sign;
13 const cookie = global.yoho.cookie; 13 const cookie = global.yoho.cookie;
14 const RegService = require('../models/reg-service'); 14 const RegService = require('../models/reg-service');
15 const AuthHelper = require('../models/auth-helper'); 15 const AuthHelper = require('../models/auth-helper');
  16 +const captchaService = require('../models/captcha-service');
  17 +
  18 +/*
  19 + session 结构
  20 + phoneReg: {
  21 + step //当前步骤
  22 + captcha // step1 的校验码
  23 + count: 5 // 默认可以重发5次, 当count: 0, 冻结30min,之后解冻
  24 + expire // 解冻时间
  25 + }
  26 +*/
  27 +
  28 +/**
  29 + * 步骤校验
  30 + * step: 预期步骤
  31 + */
  32 +let guardStep = function(step) {
  33 + return (req, res, next) => {
  34 + let curStep = _.get(req.session, 'phoneReg.step');
  35 +
  36 + if (curStep !== step) {
  37 + if (req.xhr) {
  38 + return res.json({
  39 + code: 400,
  40 + refer: '/reg.html'
  41 + });
  42 + } else {
  43 + return res.redirect('/reg.html');
  44 + }
  45 + }
  46 +
  47 + return next();
  48 + };
  49 +};
16 50
  51 +/**
  52 + * Step1: 输入手机号码 + 验证码
  53 + */
17 let index = (req, res) => { 54 let index = (req, res) => {
  55 + if (req.user.uid) {
  56 + return res.redirect(req.get('refer') || '/');
  57 + }
  58 +
18 // 设置注册有效时间30分钟, 防机器刷 59 // 设置注册有效时间30分钟, 防机器刷
19 // req.session.REG_EXPIRE = Date.now() + 1800000; 60 // req.session.REG_EXPIRE = Date.now() + 1800000;
20 let refer = req.query.refer; 61 let refer = req.query.refer;
@@ -23,17 +64,27 @@ let index = (req, res) => { @@ -23,17 +64,27 @@ let index = (req, res) => {
23 domain: 'yohobuy.com' 64 domain: 'yohobuy.com'
24 }); 65 });
25 66
  67 + // session init
  68 + _.set(req.session, 'phoneReg.step', 1);
  69 +
  70 + if (req.session.phoneReg.count == null) { // eslint-disable-line
  71 + req.session.phoneReg.count = 5;
  72 + }
  73 +
26 res.render('reg/index', { 74 res.render('reg/index', {
27 module: 'passport', 75 module: 'passport',
28 page: 'reg', 76 page: 'reg',
29 title: '注册', 77 title: '注册',
30 backUrl: 'javascript:history.go(-1)', // eslint-disable-line 78 backUrl: 'javascript:history.go(-1)', // eslint-disable-line
  79 + captchaUrl: helpers.urlFormat('/passport/reg/captcha.png', {t: Date.now()}),
31 headerText: '注册', // 头部信息 80 headerText: '注册', // 头部信息
32 isPassportPage: true, // 模板中模块标识 81 isPassportPage: true, // 模板中模块标识
33 areaCode: '+86', // 默认的区号 82 areaCode: '+86', // 默认的区号
34 countrys: RegService.getAreaData() // 地区信息列表 83 countrys: RegService.getAreaData() // 地区信息列表
35 }); 84 });
36 }; 85 };
  86 +
  87 +
37 let verifyMobile = (req, res, next) => { 88 let verifyMobile = (req, res, next) => {
38 let data = { 89 let data = {
39 code: 400, 90 code: 400,
@@ -43,6 +94,15 @@ let verifyMobile = (req, res, next) => { @@ -43,6 +94,15 @@ let verifyMobile = (req, res, next) => {
43 94
44 let mobile = +req.body.phoneNum; 95 let mobile = +req.body.phoneNum;
45 let area = +(req.body.areaCode || 86); 96 let area = +(req.body.areaCode || 86);
  97 + let captcha = (req.body.captcha || '').trim();
  98 +
  99 + if (captcha !== _.get(req.session, 'phoneReg.captcha')) {
  100 + return res.json({
  101 + code: 400,
  102 + message: '校验码不正确',
  103 + refreshCaptcha: true
  104 + });
  105 + }
46 106
47 // 判断参数是否合法 107 // 判断参数是否合法
48 if (!_.isNumber(mobile) || !_.isNumber(area)) { 108 if (!_.isNumber(mobile) || !_.isNumber(area)) {
@@ -58,6 +118,7 @@ let verifyMobile = (req, res, next) => { @@ -58,6 +118,7 @@ let verifyMobile = (req, res, next) => {
58 // return res.json(data); 118 // return res.json(data);
59 // } 119 // }
60 120
  121 +
61 // 向手机发送注册验证码 122 // 向手机发送注册验证码
62 RegService.sendCodeToMobile(area, mobile).then((result) => { 123 RegService.sendCodeToMobile(area, mobile).then((result) => {
63 if (!result.code) { 124 if (!result.code) {
@@ -68,6 +129,8 @@ let verifyMobile = (req, res, next) => { @@ -68,6 +129,8 @@ let verifyMobile = (req, res, next) => {
68 if (result.code === 200) { 129 if (result.code === 200) {
69 let token = sign.makeToken(mobile); 130 let token = sign.makeToken(mobile);
70 131
  132 + _.set(req.session, 'phoneReg.step', 2); // go step 2
  133 +
71 result.data = helpers.urlFormat('/passport/reg/code', { 134 result.data = helpers.urlFormat('/passport/reg/code', {
72 token: token, 135 token: token,
73 phoneNum: mobile, 136 phoneNum: mobile,
@@ -78,6 +141,11 @@ let verifyMobile = (req, res, next) => { @@ -78,6 +141,11 @@ let verifyMobile = (req, res, next) => {
78 return res.json(result); 141 return res.json(result);
79 }).catch(next); 142 }).catch(next);
80 }; 143 };
  144 +
  145 +
  146 +/**
  147 + * Step2: 校验 手机验证码
  148 + */
81 let codeAction = (req, res, next) => { 149 let codeAction = (req, res, next) => {
82 let token = req.query.token; 150 let token = req.query.token;
83 let mobile = +req.query.phoneNum; 151 let mobile = +req.query.phoneNum;
@@ -103,6 +171,36 @@ let codeAction = (req, res, next) => { @@ -103,6 +171,36 @@ let codeAction = (req, res, next) => {
103 serviceUrl: 'http://chat8.live800.com/live800/chatClient/chatbox.jsp?companyID=620092&configID=149091&jid=8732423409&info=' // 在线客服 171 serviceUrl: 'http://chat8.live800.com/live800/chatClient/chatbox.jsp?companyID=620092&configID=149091&jid=8732423409&info=' // 在线客服
104 }); 172 });
105 }; 173 };
  174 +
  175 +let sendCodeBusyBoy = (req, res, next) => {
  176 + let count = _.get(req.session, 'phoneReg.count');
  177 + let expire = _.get(req.session, 'phoneReg.expire');
  178 +
  179 + if (count) {
  180 + return next();
  181 + } else {
  182 +
  183 + /*
  184 + 如果 count === 0
  185 + 1. 没过解冻期
  186 + 2. 过了解冻期, count reset to 5
  187 + */
  188 + let now = Date.now();
  189 +
  190 + if (now > expire) {
  191 + _.set(req.session, 'phoneReg.count', 5);
  192 + return next();
  193 +
  194 + } else {
  195 + return res.json({
  196 + code: 400,
  197 + message: '错误次数太多, 5分钟稍后再试'
  198 + });
  199 + }
  200 +
  201 + }
  202 +};
  203 +
106 let sendCode = (req, res, next) => { 204 let sendCode = (req, res, next) => {
107 let data = { 205 let data = {
108 code: 400, 206 code: 400,
@@ -129,10 +227,21 @@ let sendCode = (req, res, next) => { @@ -129,10 +227,21 @@ let sendCode = (req, res, next) => {
129 227
130 // 向手机发送注册验证码 228 // 向手机发送注册验证码
131 RegService.sendCodeToMobile(area, mobile).then((result) => { 229 RegService.sendCodeToMobile(area, mobile).then((result) => {
132 - return result.code ? res.json(result) : res.json(data); 230 + let code = _.get(result, 'code');
  231 +
  232 + if (code) {
  233 + --req.session.phoneReg.count;
  234 +
  235 + // count is 0, will freeze;
  236 + if (!req.session.phoneReg.count) {
  237 + _.set(req.session, 'phoneReg.expire', Date.now() + 5 * 60 * 1000);
  238 + }
  239 + return res.json(result);
  240 + } else {
  241 + return res.json(data);
  242 + }
133 }).catch(next); 243 }).catch(next);
134 }; 244 };
135 -  
136 let verifyCode = (req, res, next) => { 245 let verifyCode = (req, res, next) => {
137 let data = { 246 let data = {
138 code: 400, 247 code: 400,
@@ -164,26 +273,33 @@ let verifyCode = (req, res, next) => { @@ -164,26 +273,33 @@ let verifyCode = (req, res, next) => {
164 return res.json(data); 273 return res.json(data);
165 } 274 }
166 275
167 - // 返回跳转到设置密码的链接  
168 - if (result.code === 200) {  
169 - let token = sign.makeToken(mobile);  
170 -  
171 - result.data = helpers.urlFormat('/passport/reg/password', {  
172 - token: token,  
173 - phoneNum: mobile,  
174 - areaCode: area,  
175 - smsCode: code  
176 - });  
177 - } else if (result.code === 404) {  
178 - result.message = '验证码错误'; // 统一验证提示 276 + let resultCode = _.get(result, 'code');
  277 + let token = sign.makeToken(mobile);
  278 +
  279 + switch (resultCode) {
  280 + case 200:
  281 + _.set(req.session, 'phoneReg.step', 3); // go step 3
  282 + result.data = helpers.urlFormat('/passport/reg/password', {
  283 + token: token,
  284 + phoneNum: mobile,
  285 + areaCode: area,
  286 + smsCode: code
  287 + });
  288 + break;
  289 + case 404:
  290 + default:
  291 + result = data;
179 } 292 }
180 293
181 return res.json(result); 294 return res.json(result);
182 }).catch(next); 295 }).catch(next);
183 }; 296 };
184 297
  298 +/**
  299 + * Step3: set Password
  300 + */
185 301
186 -let passwordAction = (req, res, next) => { 302 +let passwordAction = (req, res) => {
187 let token = req.query.token; 303 let token = req.query.token;
188 let mobile = +req.query.phoneNum; 304 let mobile = +req.query.phoneNum;
189 let area = +(req.query.areaCode || 86); 305 let area = +(req.query.areaCode || 86);
@@ -210,7 +326,6 @@ let passwordAction = (req, res, next) => { @@ -210,7 +326,6 @@ let passwordAction = (req, res, next) => {
210 }); 326 });
211 }; 327 };
212 328
213 -  
214 let setPassword = (req, res, next) => { 329 let setPassword = (req, res, next) => {
215 let data = { 330 let data = {
216 code: 400, 331 code: 400,
@@ -267,6 +382,8 @@ let setPassword = (req, res, next) => { @@ -267,6 +382,8 @@ let setPassword = (req, res, next) => {
267 refer = '/home'; 382 refer = '/home';
268 } 383 }
269 384
  385 + delete req.session.phoneNum;
  386 +
270 return res.json({ 387 return res.json({
271 code: 200, 388 code: 200,
272 message: '注册成功', 389 message: '注册成功',
@@ -278,12 +395,29 @@ let setPassword = (req, res, next) => { @@ -278,12 +395,29 @@ let setPassword = (req, res, next) => {
278 }).catch(next); 395 }).catch(next);
279 }; 396 };
280 397
  398 +/**
  399 + * 生成 校验码
  400 + */
  401 +const genCaptcha = (req, res) => {
  402 + let captcha = captchaService.generateCaptcha(90, 52, 4);
  403 +
  404 + _.set(req.session, 'phoneReg.captcha', captcha.text);
  405 +
  406 + res.type('png')
  407 + .set('Cache-Control', 'no-cache')
  408 + .status(200)
  409 + .send(captcha.image);
  410 +};
  411 +
281 module.exports = { 412 module.exports = {
  413 + guardStep,
  414 + sendCodeBusyBoy,
282 index, 415 index,
283 verifyMobile, 416 verifyMobile,
284 code: codeAction, 417 code: codeAction,
285 sendCode, 418 sendCode,
286 verifyCode, 419 verifyCode,
287 password: passwordAction, 420 password: passwordAction,
288 - setPassword 421 + setPassword,
  422 + genCaptcha
289 }; 423 };
  1 +/**
  2 + * Created by TaoHuang on 2016/7/1.
  3 + */
  4 +
  5 +'use strict';
  6 +
  7 +const _ = require('lodash');
  8 +const Captchapng = require('captchapng');
  9 +
  10 +exports.generateCaptcha = (width, height, length) => {
  11 + let min = Math.pow(10, (length - 1 || 1));
  12 + let max = Math.pow(10, (length - 1 || 1)) * 9;
  13 + let token = '' + _.random(min, max);
  14 +
  15 + let png = new Captchapng(width, height, token);//
  16 +
  17 + png.color(0, 0, 0, 0); // First color: background (red, green, blue, alpha)
  18 + png.color(80, 80, 80, 255); // Second color: paint (red, green, blue, alpha)
  19 +
  20 + return {
  21 + image: new Buffer(png.getBase64(), 'base64'),
  22 + text: token
  23 + };
  24 +};
@@ -12,7 +12,8 @@ const login = require(cRoot + '/login'); @@ -12,7 +12,8 @@ const login = require(cRoot + '/login');
12 const back = require(cRoot + '/back'); 12 const back = require(cRoot + '/back');
13 const bind = require(cRoot + '/bind'); 13 const bind = require(cRoot + '/bind');
14 const reg = require(cRoot + '/reg'); 14 const reg = require(cRoot + '/reg');
15 -const smsLogin = require(cRoot + '/sms'); 15 +
  16 +// const smsLogin = require(cRoot + '/sms');
16 const update = require(cRoot + '/update'); 17 const update = require(cRoot + '/update');
17 const agreement = require(cRoot + '/app-agreement'); 18 const agreement = require(cRoot + '/app-agreement');
18 19
@@ -84,12 +85,13 @@ router.post('/passport/bind/changeMobile', bind.changeMobile); @@ -84,12 +85,13 @@ router.post('/passport/bind/changeMobile', bind.changeMobile);
84 * 注册 85 * 注册
85 */ 86 */
86 router.get('/passport/reg/index', reg.index); 87 router.get('/passport/reg/index', reg.index);
87 -router.post('/passport/reg/verifymobile', reg.verifyMobile);  
88 -router.get('/passport/reg/code', reg.code);  
89 -router.post('/passport/reg/sendcode', reg.sendCode);  
90 -router.post('/passport/reg/verifycode', reg.verifyCode);  
91 -router.get('/passport/reg/password', reg.password);  
92 -router.post('/passport/reg/setpassword', reg.setPassword); 88 +router.get('/passport/reg/captcha.png', reg.genCaptcha);
  89 +router.post('/passport/reg/verifymobile', reg.sendCodeBusyBoy, reg.verifyMobile);
  90 +router.get('/passport/reg/code', reg.guardStep(2), reg.code);
  91 +router.post('/passport/reg/sendcode', reg.guardStep(2), reg.sendCodeBusyBoy, reg.sendCode);
  92 +router.post('/passport/reg/verifycode', reg.guardStep(2), reg.verifyCode);
  93 +router.get('/passport/reg/password', reg.guardStep(3), reg.password);
  94 +router.post('/passport/reg/setpassword', reg.guardStep(3), reg.setPassword);
93 95
94 /** 96 /**
95 * 密码找回 97 * 密码找回
@@ -101,6 +103,7 @@ router.get('/passport/back/success', back.backSuccessByEmailPage);// 邮箱找 @@ -101,6 +103,7 @@ router.get('/passport/back/success', back.backSuccessByEmailPage);// 邮箱找
101 103
102 router.get('/passport/back/mobile', back.indexMobilePage);// 输入手机号找回密码页面 104 router.get('/passport/back/mobile', back.indexMobilePage);// 输入手机号找回密码页面
103 router.get('/passport/back/mobilecode', back.verifyCodeByMobilePage);// 输入手机验证码页面 105 router.get('/passport/back/mobilecode', back.verifyCodeByMobilePage);// 输入手机验证码页面
  106 +router.get('/passport/back/generatecodeimg.png', back.generateCodeImg);// 生成图片验证码
104 router.post('/passport/back/sendcode', back.sendCodeToMobileAPI);// 发送手机验证码 107 router.post('/passport/back/sendcode', back.sendCodeToMobileAPI);// 发送手机验证码
105 router.post('/passport/back/verifycode', back.verifyCodeByMobileAPI);// 校验手机验证码 108 router.post('/passport/back/verifycode', back.verifyCodeByMobileAPI);// 校验手机验证码
106 109
@@ -6,6 +6,10 @@ @@ -6,6 +6,10 @@
6 <span id="area-code" class="area-code">{{areaCode}}</span> 6 <span id="area-code" class="area-code">{{areaCode}}</span>
7 <input id="phone-num" class="input phone-num" type="text" placeholder="手机号"> 7 <input id="phone-num" class="input phone-num" type="text" placeholder="手机号">
8 </div> 8 </div>
  9 + <div class="passport-captcha row">
  10 + <input id="verify-code" type="text" placeholder="验证码">
  11 + <div class="passport-captcha-img"><img id="verify-code-img" src="{{verifySrc}}" alt="verify code"></div>
  12 + </div>
9 <span id="btn-next" class="btn btn-next disable row">下一步</span> 13 <span id="btn-next" class="btn btn-next disable row">下一步</span>
10 </div> 14 </div>
11 </div> 15 </div>
@@ -6,7 +6,15 @@ @@ -6,7 +6,15 @@
6 <span id="area-code" class="area-code">{{areaCode}}</span> 6 <span id="area-code" class="area-code">{{areaCode}}</span>
7 <input id="phone-num" class="input phone-num" type="text" placeholder="手机号"> 7 <input id="phone-num" class="input phone-num" type="text" placeholder="手机号">
8 </div> 8 </div>
  9 + <!-- 验证码: start-->
  10 + <div class="passport-captcha row">
  11 + <input id="js-captcha" type="text" placeholder="验证码">
  12 + <div class="passport-captcha-img">
  13 + <img class="passport-captcha-png" src="{{captchaUrl}}">
  14 + </div>
  15 + </div>
  16 + <!-- 验证码: end-->
9 <span id="btn-next" class="btn btn-next disable row">下一步</span> 17 <span id="btn-next" class="btn btn-next disable row">下一步</span>
10 <p class="register-tip">Yoho!Family账号可登录Yoho!Buy有货、Yoho!Now、mars及SHOW</p> 18 <p class="register-tip">Yoho!Family账号可登录Yoho!Buy有货、Yoho!Now、mars及SHOW</p>
11 </div> 19 </div>
12 -</div> 20 +</div>
@@ -176,12 +176,12 @@ exports.consults = (req, res, next) => { @@ -176,12 +176,12 @@ exports.consults = (req, res, next) => {
176 if (!req.query.product_id) { 176 if (!req.query.product_id) {
177 return next(); 177 return next();
178 } 178 }
179 - 179 + let uid = req.user.uid || 0;
180 let headerData = headerModel.setNav({ 180 let headerData = headerModel.setNav({
181 navTitle: '购买咨询' 181 navTitle: '购买咨询'
182 }); 182 });
183 183
184 - detailRelated.consults(req.query).then((result) => { 184 + detailRelated.consults(req.query, uid).then((result) => {
185 res.render('detail/consults', Object.assign({ 185 res.render('detail/consults', Object.assign({
186 title: '购买咨询', 186 title: '购买咨询',
187 pageHeader: headerData, 187 pageHeader: headerData,
@@ -253,8 +253,7 @@ exports.consultsubmit = (req, res, next) => { @@ -253,8 +253,7 @@ exports.consultsubmit = (req, res, next) => {
253 return res.json(data); 253 return res.json(data);
254 } 254 }
255 255
256 - detailRelated.addConsult(req.user.uid, req.body.product_id, req.body.content).then((result) => {  
257 - 256 + return detailRelated.addConsult(req.user.uid, req.body.product_id, req.body.content).then((result) => {
258 if (result) { 257 if (result) {
259 Object.assign(data, result); 258 Object.assign(data, result);
260 } 259 }
@@ -64,12 +64,13 @@ const _formatConsultsList = (data) => { @@ -64,12 +64,13 @@ const _formatConsultsList = (data) => {
64 * @limit {[number]} 每页咨询数量 64 * @limit {[number]} 每页咨询数量
65 * @return {[object]} 65 * @return {[object]}
66 */ 66 */
67 -const getConsults = (id, page, limit) => { 67 +const getConsults = (id, page, limit, uid) => {
68 let params = { 68 let params = {
69 method: 'app.consult.li', 69 method: 'app.consult.li',
70 product_id: id, 70 product_id: id,
71 page: page ? page : 1, 71 page: page ? page : 1,
72 - limit: limit ? limit : 300 72 + limit: limit ? limit : 300,
  73 + uid
73 }; 74 };
74 75
75 return api.get('', params, { 76 return api.get('', params, {
@@ -160,10 +161,10 @@ let comments = (params) => { @@ -160,10 +161,10 @@ let comments = (params) => {
160 * @params {[object]} 查询参数 161 * @params {[object]} 查询参数
161 * @return {[object]} 162 * @return {[object]}
162 */ 163 */
163 -let consults = (params) => { 164 +let consults = (params, uid) => {
164 return api.all([ 165 return api.all([
165 _getCommonConsult(), 166 _getCommonConsult(),
166 - getConsults(params.product_id, 1, 60) 167 + getConsults(params.product_id, 1, 60, uid)
167 ]).then(result => { 168 ]).then(result => {
168 let data = { 169 let data = {
169 link: `/product/detail/consultform?product_id=${params.product_id}` 170 link: `/product/detail/consultform?product_id=${params.product_id}`
@@ -515,6 +515,7 @@ const getShopData = (req, shopId, uid, isApp) => { @@ -515,6 +515,7 @@ const getShopData = (req, shopId, uid, isApp) => {
515 return Promise.all([ 515 return Promise.all([
516 searchModel.getFilterSearchData({ 516 searchModel.getFilterSearchData({
517 shop_id: shopId, 517 shop_id: shopId,
  518 + type: 'default',//默认
518 brand: brandData.join(','), 519 brand: brandData.join(','),
519 order: '0', 520 order: '0',
520 channel: channel 521 channel: channel
@@ -121,9 +121,9 @@ @@ -121,9 +121,9 @@
121 121
122 <div class="discount-area first" id="navlist2"> 122 <div class="discount-area first" id="navlist2">
123 <ul id="list-nav" class="home-sub-nav list-nav pos-list clearfix"> 123 <ul id="list-nav" class="home-sub-nav list-nav pos-list clearfix">
124 - <li data-bp-id="shop_listnav_new_1" class="new active buriedpoint first-li-more"> 124 + <li data-bp-id="shop_listnav_default_1" class="default active buriedpoint first-li-more">
125 <a href="javascript:void(0);"> 125 <a href="javascript:void(0);">
126 - <span class="spanTest">最新</span> 126 + <span class="spanTest">默认</span>
127 <span class="iconfont up cur hide">&#xe615;</span> 127 <span class="iconfont up cur hide">&#xe615;</span>
128 <span class="iconfont down cur">&#xe616;</span> 128 <span class="iconfont down cur">&#xe616;</span>
129 </a> 129 </a>
@@ -191,9 +191,9 @@ @@ -191,9 +191,9 @@
191 </ul> 191 </ul>
192 <div id="pos-list" class='hide'> 192 <div id="pos-list" class='hide'>
193 <ul class="home-sub-nav pos-list"> 193 <ul class="home-sub-nav pos-list">
194 - <li class="new active buriedpoint first-li-more" data-bp-id="shop_poslist_new_1"> 194 + <li class="default active buriedpoint first-li-more" data-bp-id="shop_listnav_default_1">
195 <a href="javascript:void(0);"> 195 <a href="javascript:void(0);">
196 - <span class="spanTest">最新</span> 196 + <span class="spanTest">默认</span>
197 <span class="iconfont cur">&#xe616;</span> 197 <span class="iconfont cur">&#xe616;</span>
198 <b></b> 198 <b></b>
199 </a> 199 </a>
@@ -230,7 +230,6 @@ @@ -230,7 +230,6 @@
230 <ul> 230 <ul>
231 <li class='active default' data-bp-id='shop_listnav_default_1'>默认</li> 231 <li class='active default' data-bp-id='shop_listnav_default_1'>默认</li>
232 <li class='new' data-bp-id='shop_listnav_new_1'>最新</li> 232 <li class='new' data-bp-id='shop_listnav_new_1'>最新</li>
233 - <li class='sale' data-bp-id='shop_listnav_sale_1'>销量</li>  
234 </ul> 233 </ul>
235 </div> 234 </div>
236 </div> 235 </div>
@@ -92,9 +92,9 @@ @@ -92,9 +92,9 @@
92 92
93 <div> 93 <div>
94 <ul id="list-nav" class="list-nav clearfix"> 94 <ul id="list-nav" class="list-nav clearfix">
95 - <li class="new active buriedpoint first-li-more" data-bp-id="shop_listnav_new_1"> 95 + <li class="default active buriedpoint first-li-more" data-bp-id="shop_listnav_default_1">
96 <a href="javascript:void(0);"> 96 <a href="javascript:void(0);">
97 - <span class="nav-txt">最新</span> 97 + <span class="nav-txt">默认</span>
98 <span class="iconfont up cur hide">&#xe615;</span> 98 <span class="iconfont up cur hide">&#xe615;</span>
99 <span class="iconfont down cur">&#xe616;</span> 99 <span class="iconfont down cur">&#xe616;</span>
100 </a> 100 </a>
@@ -20,6 +20,7 @@ @@ -20,6 +20,7 @@
20 "dependencies": { 20 "dependencies": {
21 "bluebird": "^3.4.6", 21 "bluebird": "^3.4.6",
22 "body-parser": "^1.15.2", 22 "body-parser": "^1.15.2",
  23 + "captchapng": "0.0.1",
23 "cheerio": "^0.22.0", 24 "cheerio": "^0.22.0",
24 "compression": "^1.6.2", 25 "compression": "^1.6.2",
25 "connect-multiparty": "^2.0.0", 26 "connect-multiparty": "^2.0.0",
@@ -196,7 +196,7 @@ getChannel = function functionName() { @@ -196,7 +196,7 @@ getChannel = function functionName() {
196 C_ID = getChannel(); 196 C_ID = getChannel();
197 197
198 $('.floor-focus').find('li').on('click', function() { 198 $('.floor-focus').find('li').on('click', function() {
199 - event.preventDefault(); 199 + // event.preventDefault();
200 var foId = $(this).parents('.floor-focus').data('id'), 200 var foId = $(this).parents('.floor-focus').data('id'),
201 foName = $(this).parents('.floor-focus').data('floor-name'), 201 foName = $(this).parents('.floor-focus').data('floor-name'),
202 foindex = $(this).parents('.floor-focus').index() + 1, 202 foindex = $(this).parents('.floor-focus').index() + 1,
@@ -9,6 +9,8 @@ var $ = require('yoho-jquery'); @@ -9,6 +9,8 @@ var $ = require('yoho-jquery');
9 var $phoneNum = $('#phone-num'), 9 var $phoneNum = $('#phone-num'),
10 $countrySelect = $('#country-select'), 10 $countrySelect = $('#country-select'),
11 $areaCode = $('#area-code'), 11 $areaCode = $('#area-code'),
  12 + $verifyCode = $('#verify-code'),
  13 + $verifyCodeImg = $('#verify-code-img'),
12 $btnNext = $('#btn-next'); 14 $btnNext = $('#btn-next');
13 15
14 var api = require('../api'); 16 var api = require('../api');
@@ -33,25 +35,36 @@ $countrySelect.change(function() { @@ -33,25 +35,36 @@ $countrySelect.change(function() {
33 $areaCode.text($countrySelect.val()); 35 $areaCode.text($countrySelect.val());
34 }); 36 });
35 37
  38 +$verifyCodeImg.on('touchstart', function() {
  39 + var oldSrc = $verifyCodeImg.attr('src').split('=');
  40 +
  41 + $verifyCodeImg.attr('src', oldSrc[0] + '=' + Date.now());
  42 +});
  43 +
36 $btnNext.on('touchstart', function() { 44 $btnNext.on('touchstart', function() {
37 var pn = trim($phoneNum.val()), 45 var pn = trim($phoneNum.val()),
38 - area = trim($countrySelect.val()); 46 + area = trim($countrySelect.val()),
  47 + verify = trim($verifyCode.val());
39 48
40 if ($btnNext.hasClass('disable')) { 49 if ($btnNext.hasClass('disable')) {
41 return; 50 return;
42 } 51 }
43 52
44 - if (area && pn && api.phoneRegx[area].test(pn)) { 53 + if (verify && area && pn && api.phoneRegx[area].test(pn)) {
45 $.ajax({ 54 $.ajax({
46 url: '/passport/back/sendcode', 55 url: '/passport/back/sendcode',
47 type: 'POST', 56 type: 'POST',
48 data: { 57 data: {
49 areaCode: area.replace('+', ''), 58 areaCode: area.replace('+', ''),
50 - phoneNum: pn 59 + phoneNum: pn,
  60 + verifyCode: verify
51 }, 61 },
52 success: function(data) { 62 success: function(data) {
53 if (data.code === 200) { 63 if (data.code === 200) {
54 location.href = data.data; 64 location.href = data.data;
  65 + } else if (data.code === 409) {
  66 + showErrTip(data.message);
  67 + location.href = data.refer;
55 } else { 68 } else {
56 showErrTip(data.message); 69 showErrTip(data.message);
57 } 70 }
@@ -59,6 +72,8 @@ $btnNext.on('touchstart', function() { @@ -59,6 +72,8 @@ $btnNext.on('touchstart', function() {
59 }); 72 });
60 } else if (!area) { 73 } else if (!area) {
61 showErrTip('出错了,请重新刷新页面'); 74 showErrTip('出错了,请重新刷新页面');
  75 + } else if (!verify) {
  76 + showErrTip('请输入验证码');
62 } else { 77 } else {
63 showErrTip('手机号格式不正确,请重新输入'); 78 showErrTip('手机号格式不正确,请重新输入');
64 } 79 }
@@ -8,6 +8,8 @@ var $ = require('yoho-jquery'); @@ -8,6 +8,8 @@ var $ = require('yoho-jquery');
8 var $phoneNum = $('#phone-num'), 8 var $phoneNum = $('#phone-num'),
9 $countrySelect = $('#country-select'), 9 $countrySelect = $('#country-select'),
10 $areaCode = $('#area-code'), 10 $areaCode = $('#area-code'),
  11 + $captcha = $('#js-captcha'),
  12 + $captchaPNG = $('.passport-captcha-png'),
11 $btnNext = $('#btn-next'); 13 $btnNext = $('#btn-next');
12 14
13 var api = require('../api'); 15 var api = require('../api');
@@ -22,13 +24,44 @@ api.selectCssHack($('#country-select')); @@ -22,13 +24,44 @@ api.selectCssHack($('#country-select'));
22 24
23 api.bindClearEvt(); 25 api.bindClearEvt();
24 26
25 -$phoneNum.bind('input', function() {  
26 - if (trim($phoneNum.val()) === '') {  
27 - $btnNext.addClass('disable');  
28 - } else {  
29 - $btnNext.removeClass('disable');  
30 - }  
31 -}); 27 +/**
  28 + * 必填校验
  29 + */
  30 +function checkEnableNext() {
  31 + var phone = trim($phoneNum.val());
  32 + var area = trim($countrySelect.val());
  33 + var captcha = trim($captcha.val());
  34 +
  35 + var ret = true;
  36 +
  37 + $.each([phone, area, captcha], function(i, val) {
  38 + if (!val) {
  39 + ret = false;
  40 + return ret;
  41 + }
  42 + });
  43 +
  44 + return ret;
  45 +}
  46 +
  47 +
  48 +/**
  49 + * 刷新 校验码
  50 + */
  51 +function refreshCaptcha() {
  52 + $captcha.val('').focus();
  53 + $captchaPNG.attr('src', ['//m.yohobuy.com/passport/reg/captcha.png', '?t=', Date.now()].join(''));
  54 +}
  55 +
  56 +
  57 +/*
  58 + Event bind
  59 +*/
  60 +$('.reg-page')
  61 + .on('input', '.phone-num, #js-captcha', function() {
  62 + $btnNext.toggleClass('disable', !checkEnableNext());
  63 + })
  64 + .on('click', '.passport-captcha-png', refreshCaptcha);
32 65
33 $countrySelect.change(function() { 66 $countrySelect.change(function() {
34 $areaCode.text($countrySelect.val()); 67 $areaCode.text($countrySelect.val());
@@ -36,7 +69,13 @@ $countrySelect.change(function() { @@ -36,7 +69,13 @@ $countrySelect.change(function() {
36 69
37 $btnNext.on('touchstart', function() { 70 $btnNext.on('touchstart', function() {
38 var pn = trim($phoneNum.val()), 71 var pn = trim($phoneNum.val()),
39 - areaCode = $countrySelect.val(); 72 + areaCode = $countrySelect.val(),
  73 + captcha = $captcha.val().trim();
  74 +
  75 + if (!captcha) {
  76 + tip.show('请输入验证码');
  77 + return false;
  78 + }
40 79
41 if ($btnNext.hasClass('disable')) { 80 if ($btnNext.hasClass('disable')) {
42 return; 81 return;
@@ -56,12 +95,15 @@ $btnNext.on('touchstart', function() { @@ -56,12 +95,15 @@ $btnNext.on('touchstart', function() {
56 type: 'POST', 95 type: 'POST',
57 data: { 96 data: {
58 areaCode: areaCode.replace('+', ''), 97 areaCode: areaCode.replace('+', ''),
59 - phoneNum: pn 98 + phoneNum: pn,
  99 + captcha: captcha
60 }, 100 },
61 success: function(data) { 101 success: function(data) {
62 if (data.code === 200) { 102 if (data.code === 200) {
63 location.href = data.data; 103 location.href = data.data;
64 } else { 104 } else {
  105 + data.refreshCaptcha && refreshCaptcha();
  106 +
65 showErrTip(data.message); 107 showErrTip(data.message);
66 requested = false; 108 requested = false;
67 } 109 }
@@ -76,7 +76,9 @@ if (navtabHammer) { @@ -76,7 +76,9 @@ if (navtabHammer) {
76 76
77 if (gotoConsultHammer) { 77 if (gotoConsultHammer) {
78 gotoConsultHammer.on('tap', function() { 78 gotoConsultHammer.on('tap', function() {
79 - location.href = $(gotoConsultEle).find('a').attr('href'); 79 + var link = $(gotoConsultEle).find('a').attr('href');
  80 + link += (link.indexOf('?') >=0 ? '&' : '?') + 'from=' + encodeURIComponent(location.href);
  81 + location.href = link;
80 }); 82 });
81 } 83 }
82 84
@@ -32,6 +32,11 @@ $content.on('focus', function() { @@ -32,6 +32,11 @@ $content.on('focus', function() {
32 $content.val('请输入咨询内容'); 32 $content.val('请输入咨询内容');
33 } 33 }
34 }); 34 });
  35 +var getUrlParam = function (paramName) {
  36 + var reg = "[\\?|\\&]+" + paramName + "=([^&]*)[^&]?";
  37 + var exp = (window.location.href + "").match(reg);
  38 + return exp ? exp[1] : "";
  39 +}
35 40
36 // 提交表单请求 41 // 提交表单请求
37 $consultForm.on('submit', function() { 42 $consultForm.on('submit', function() {
@@ -68,7 +73,12 @@ $consultForm.on('submit', function() { @@ -68,7 +73,12 @@ $consultForm.on('submit', function() {
68 } else { 73 } else {
69 tip.show('提交成功~'); 74 tip.show('提交成功~');
70 setTimeout(function() { 75 setTimeout(function() {
71 - window.history.go(-1); 76 + var from = getUrlParam('from');
  77 + if (from) {
  78 + window.location = decodeURIComponent(from);
  79 + } else {
  80 + window.history.go(-1);
  81 + }
72 }, 3000); 82 }, 3000);
73 } 83 }
74 }).fail(function() { 84 }).fail(function() {
@@ -127,7 +127,7 @@ function render(data) { @@ -127,7 +127,7 @@ function render(data) {
127 $('#limitProductCode').val(data.cartInfo.limitProductCode).removeClass(dbClass); 127 $('#limitProductCode').val(data.cartInfo.limitProductCode).removeClass(dbClass);
128 } 128 }
129 } 129 }
130 - if (data.isCollect) { 130 + if (data.isCollect === true) {
131 $('#likeBtn').addClass('liked'); 131 $('#likeBtn').addClass('liked');
132 } 132 }
133 if (data.tickets) { 133 if (data.tickets) {
@@ -8,3 +8,4 @@ @@ -8,3 +8,4 @@
8 @import "success"; 8 @import "success";
9 @import "app-update"; 9 @import "app-update";
10 @import "app-agreement"; 10 @import "app-agreement";
  11 +@import "passport-captcha"
  1 +/* 验证码 css
  2 +-----------------------------------
  3 +结构:
  4 +div.passport-captch
  5 + input
  6 + div.passport-captcha-img
  7 + img
  8 +
  9 +emmet:
  10 +div.passport-captcha>input+div.passport-captcha-img>img
  11 +
  12 +*/
  13 +
  14 +.passport-captcha {
  15 + text-align: left;
  16 +
  17 + input {
  18 + position: relative;
  19 + padding-left: 15px;
  20 + height: 52PX;
  21 + font-size: 20PX;
  22 + background-color: #575757;
  23 + border: 1px solid #606060;
  24 + border-radius: 5PX;
  25 + color: #fff;
  26 + }
  27 +}
  28 +
  29 +.passport-captcha-img {
  30 + float: right;
  31 + text-align: right;
  32 +
  33 + img {
  34 + display: inline-block;
  35 + background-color: #fff;
  36 + height: 52PX;
  37 + width: 90PX;
  38 + vertical-align: bottom;
  39 + }
  40 +}
@@ -40,6 +40,11 @@ $basicBtnC: #eb0313; @@ -40,6 +40,11 @@ $basicBtnC: #eb0313;
40 margin-bottom: 20px; 40 margin-bottom: 20px;
41 } 41 }
42 42
  43 + video {
  44 + width: 100%;
  45 + height: auto;
  46 + }
  47 +
43 .detail { 48 .detail {
44 margin-top: 20px; 49 margin-top: 20px;
45 margin-bottom: 20px; 50 margin-bottom: 20px;
@@ -313,7 +318,7 @@ $basicBtnC: #eb0313; @@ -313,7 +318,7 @@ $basicBtnC: #eb0313;
313 margin-right: 20px; 318 margin-right: 20px;
314 } 319 }
315 320
316 - .font-right{ 321 + .font-right {
317 color: $subFontC; 322 color: $subFontC;
318 } 323 }
319 324
@@ -428,8 +433,8 @@ $basicBtnC: #eb0313; @@ -428,8 +433,8 @@ $basicBtnC: #eb0313;
428 433
429 .seckill-chose { 434 .seckill-chose {
430 position: absolute; 435 position: absolute;
431 - bottom: 0px;  
432 - right: 0px; 436 + bottom: 0;
  437 + right: 0;
433 } 438 }
434 439
435 .limit-num-text { 440 .limit-num-text {
@@ -792,6 +797,7 @@ $basicBtnC: #eb0313; @@ -792,6 +797,7 @@ $basicBtnC: #eb0313;
792 } 797 }
793 } 798 }
794 } 799 }
  800 +
795 /* 801 /*
796 秒杀倒计时栏 802 秒杀倒计时栏
797 */ 803 */
@@ -827,6 +833,7 @@ $basicBtnC: #eb0313; @@ -827,6 +833,7 @@ $basicBtnC: #eb0313;
827 font-size: 28px; 833 font-size: 28px;
828 } 834 }
829 } 835 }
  836 +
830 /* 837 /*
831 底部固定栏 838 底部固定栏
832 */ 839 */