Authored by zhangxiaoru

合并master 解决冲突

Showing 95 changed files with 2278 additions and 566 deletions

Too many changes to show.

To preserve performance only 95 of 95+ files are displayed.

@@ -109,6 +109,7 @@ const getPlatForm = (req) => { @@ -109,6 +109,7 @@ const getPlatForm = (req) => {
109 if (yoho.app_version) { 109 if (yoho.app_version) {
110 yoho.app_version = _.toString(yoho.app_version); 110 yoho.app_version = _.toString(yoho.app_version);
111 arrs = yoho.app_version.split('.'); 111 arrs = yoho.app_version.split('.');
  112 +
112 // if (arrs.length > 2) { 113 // if (arrs.length > 2) {
113 // if (arrs[0] && +arrs[0] < 4) { 114 // if (arrs[0] && +arrs[0] < 4) {
114 // isNewVersion = false; 115 // isNewVersion = false;
@@ -211,4 +211,4 @@ exports.luckResultCollect = (req, res, next) => { @@ -211,4 +211,4 @@ exports.luckResultCollect = (req, res, next) => {
211 211
212 res.json(result); 212 res.json(result);
213 }); 213 });
214 -};  
  214 +};
@@ -35,4 +35,4 @@ exports.feature = (req, res) => { @@ -35,4 +35,4 @@ exports.feature = (req, res) => {
35 } 35 }
36 36
37 res.json({mktCode: mktCode}); 37 res.json({mktCode: mktCode});
38 -};  
  38 +};
@@ -250,11 +250,15 @@ const _getContent = (data, isApp) => { @@ -250,11 +250,15 @@ const _getContent = (data, isApp) => {
250 if (fun === 'getCoupon' && data[i].data.length && _.has(data[i - 1], 'template_name') && data[i - 1].template_name === 'text') { 250 if (fun === 'getCoupon' && data[i].data.length && _.has(data[i - 1], 'template_name') && data[i - 1].template_name === 'text') {
251 data[i].data[0].floorTitle = data[i - 1].data; 251 data[i].data[0].floorTitle = data[i - 1].data;
252 } 252 }
  253 +
253 build = processFun[fun](data[i].data, isApp); 254 build = processFun[fun](data[i].data, isApp);
254 if (!build) { 255 if (!build) {
255 continue; 256 continue;
256 } 257 }
257 - result.push(build); 258 + result.push(_.assign({
  259 + templateName: data[i].templateName || data[i].template_name,
  260 + templateId: data[i].templateId || data[i].template_id
  261 + }, build));
258 } 262 }
259 build = []; 263 build = [];
260 return result; 264 return result;
1 <div class="coupon-area-page yoho-page"> 1 <div class="coupon-area-page yoho-page">
2 {{# content}} 2 {{# content}}
3 {{#if isSingleImage}} 3 {{#if isSingleImage}}
4 - <a href="{{url}}"><img src="{{image src 0 0}}" class="just-img"/></a> 4 + <div data-id="{{templateId}}" data-floor-name="{{templateName}}" class="floor">
  5 + <a href="{{url}}"><img src="{{image src 0 0}}" class="just-img"/></a>
  6 + </div>
5 {{/if}} 7 {{/if}}
6 {{#if isCarouselBanner}} 8 {{#if isCarouselBanner}}
7 - {{> resources/banner-top}} 9 + <div data-id="{{templateId}}" data-floor-name="{{templateName}}" class="floor-focus">
  10 + {{> resources/banner-top}}
  11 + </div>
8 {{/if}} 12 {{/if}}
9 {{#if isFocus}} 13 {{#if isFocus}}
10 - {{> resources/banner-top}} 14 + <div data-id="{{templateId}}" data-floor-name="{{templateName}}" class="floor-focus">
  15 + {{> resources/banner-top}}
  16 + </div>
11 {{/if}} 17 {{/if}}
12 {{#if isCoupon}} 18 {{#if isCoupon}}
13 - <div class="coupon-floor" coupon-id="{{couponID}}">  
14 - {{#if showFloorTitle}}  
15 - <div class="floor-title">  
16 - {{floorTitle}}  
17 - </div>  
18 - {{/if}}  
19 - <div class="floor-main" id="{{couponID}}" style="background-image: url({{image.src}});">  
20 - <a href="{{image.url}}" class="main-left"></a>  
21 - <div class="main-right-receive">  
22 - <span class="on-receive"></span> 19 + <div data-id="{{templateId}}" data-floor-name="{{templateName}}" class="floor">
  20 + <div class="coupon-floor" coupon-id="{{couponID}}">
  21 + {{#if showFloorTitle}}
  22 + <div class="floor-title">
  23 + {{floorTitle}}
  24 + </div>
  25 + {{/if}}
  26 + <div class="floor-main" id="{{couponID}}" style="background-image: url({{image.src}});">
  27 + <a href="{{image.url}}" class="main-left"></a>
  28 + <div class="main-right-receive">
  29 + <span class="on-receive"></span>
  30 + </div>
  31 + <a href="{{image.url}}" class="main-right-use hidden">
  32 + <span class="received"></span>
  33 + </a>
  34 + <a href="{{image.url}}" class="main-right-go hidden">
  35 + <span class="zero"></span>
  36 + </a>
23 </div> 37 </div>
24 - <a href="{{image.url}}" class="main-right-use hidden">  
25 - <span class="received"></span>  
26 - </a>  
27 - <a href="{{image.url}}" class="main-right-go hidden">  
28 - <span class="zero"></span>  
29 - </a>  
30 </div> 38 </div>
31 </div> 39 </div>
32 {{/if}} 40 {{/if}}
@@ -50,6 +58,7 @@ @@ -50,6 +58,7 @@
50 <input id="appurl" type="hidden" value="{{appUrl}}"> 58 <input id="appurl" type="hidden" value="{{appUrl}}">
51 <input id="wapurl" type="hidden" value="{{wapUrl}}"> 59 <input id="wapurl" type="hidden" value="{{wapUrl}}">
52 {{/ noLoginUrl}} 60 {{/ noLoginUrl}}
  61 + {{> common/suspend-home}}
53 </div> 62 </div>
54 <div class="floor-mask"></div> 63 <div class="floor-mask"></div>
55 <div class="floor-message"> 64 <div class="floor-message">
@@ -2,6 +2,11 @@ @@ -2,6 +2,11 @@
2 <div class="ma-header"> 2 <div class="ma-header">
3 <div>{{headerTip}}</div> 3 <div>{{headerTip}}</div>
4 </div> 4 </div>
  5 + {{# download}}
  6 + <a href="{{url}}" class="down">
  7 + <img src="{{img}}" alt="{{alt}}" />
  8 + </a>
  9 + {{/ download}}
5 <div class="tab"> 10 <div class="tab">
6 <div class="swiper-container"> 11 <div class="swiper-container">
7 <div class="swiper-wrapper"> 12 <div class="swiper-wrapper">
@@ -42,9 +47,4 @@ @@ -42,9 +47,4 @@
42 <p>{{title}}</p> 47 <p>{{title}}</p>
43 </div> 48 </div>
44 {{/ newsList}} 49 {{/ newsList}}
45 - {{# download}}  
46 - <a href="{{url}}" class="down">  
47 - <img src="{{img}}" alt="{{alt}}" />  
48 - </a>  
49 - {{/ download}}  
50 </div> 50 </div>
@@ -115,6 +115,9 @@ @@ -115,6 +115,9 @@
115 {{# isLimited}} 115 {{# isLimited}}
116 <p class="good-tag limit-tag">限量</p> 116 <p class="good-tag limit-tag">限量</p>
117 {{/ isLimited}} 117 {{/ isLimited}}
  118 + {{# isPresell}}
  119 + <p class="good-tag is-presell">预售</p>
  120 + {{/ isPresell}}
118 {{/ tags}} 121 {{/ tags}}
119 </div> 122 </div>
120 <div class="good-detail-img"> 123 <div class="good-detail-img">
@@ -44,6 +44,9 @@ @@ -44,6 +44,9 @@
44 {{# isLimited}} 44 {{# isLimited}}
45 <p class="good-tag limit-tag">限量</p> 45 <p class="good-tag limit-tag">限量</p>
46 {{/ isLimited}} 46 {{/ isLimited}}
  47 + {{# isPresell}}
  48 + <p class="good-tag is-presell">预售</p>
  49 + {{/ isPresell}}
47 {{/ tags}} 50 {{/ tags}}
48 </div> 51 </div>
49 <div class="good-detail-img"> 52 <div class="good-detail-img">
  1 +/**
  2 + * 支付成功页
  3 + * @author: jing.li<jing.li@yoho.cn>
  4 + * @date: 2016/10/25
  5 + */
  6 +
  7 +'use strict';
  8 +
  9 +const mRoot = '../models';
  10 +const payModel = require(`${mRoot}/pay`);
  11 +const headerModel = require('../../../doraemon/models/header'); // 头部model
  12 +
  13 +// 货到付款
  14 +const payCod = (req, res, next) => {
  15 + let headerData = headerModel.setNav({
  16 + navTitle: '支付完成'
  17 + });
  18 +
  19 + let responseData = {
  20 + pageHeader: headerData,
  21 + module: 'cart',
  22 + page: 'pay',
  23 + title: '支付中心 | Yoho!Buy有货 | 潮流购物逛不停'
  24 + };
  25 +
  26 + let param = {
  27 + uid: req.user.uid,
  28 + udid: req.sessionID || require('md5')(req.ip) || 'yoho',
  29 + orderCode: req.query.order_code,
  30 + contentCode: '05afedf76886d732573f10f7451a1703'
  31 + };
  32 +
  33 + // 如果没有uid,跳转到首页
  34 + if (!param.uid) {
  35 + res.redirect('/');
  36 + return;
  37 + }
  38 +
  39 + payModel.getPayCod(param).then(result => {
  40 + if (result.match === true) {
  41 + res.render('pay/pay-cod', Object.assign(responseData, result));
  42 + } else {
  43 + res.redirect('/');
  44 + }
  45 +
  46 + }).catch(next);
  47 +};
  48 +
  49 +// 支付宝支付
  50 +const payAli = (req, res, next) => {
  51 + let headerData = headerModel.setNav({
  52 + navTitle: '支付完成'
  53 + });
  54 +
  55 + let responseData = {
  56 + pageHeader: headerData,
  57 + module: 'cart',
  58 + page: 'pay',
  59 + title: '支付中心 | Yoho!Buy有货 | 潮流购物逛不停'
  60 + };
  61 +
  62 + let param = {
  63 + uid: req.user.uid,
  64 + udid: req.sessionID || require('md5')(req.ip) || 'yoho',
  65 + orderCode: req.query.out_trade_no,
  66 + contentCode: '05afedf76886d732573f10f7451a1703'
  67 + };
  68 +
  69 + // 如果没有uid,跳转到首页
  70 + if (!param.uid) {
  71 + res.redirect('/');
  72 + return;
  73 + }
  74 +
  75 + payModel.getPayAli(param).then(result => {
  76 + if (result.match === true) {
  77 + res.render('pay/pay-ali', Object.assign(responseData, result));
  78 + } else {
  79 + res.redirect('/');
  80 + }
  81 +
  82 + }).catch(next);
  83 +};
  84 +
  85 +module.exports = {
  86 + payCod,
  87 + payAli
  88 +};
1 /** 1 /**
  2 +<<<<<<< HEAD
2 * sub app cart 3 * sub app cart
3 * @author: xuan.chen@yoho.cn<xuan.chen@yoho.cn> 4 * @author: xuan.chen@yoho.cn<xuan.chen@yoho.cn>
4 * @date: 2016/09/26 5 * @date: 2016/09/26
  6 +=======
  7 + * sub app guang
  8 + * @author: Bi Kai<kai.bi@yoho.cn>
  9 + * @date: 2016/05/09
  10 +>>>>>>> feature/payment
5 */ 11 */
6 12
7 var express = require('express'), 13 var express = require('express'),
  1 +/**
  2 + * 支付成功页
  3 + * @author: jing.li<jing.li@yoho.cn>
  4 + * @date: 2016/10/25
  5 + */
  6 +
  7 +'use strict';
  8 +
  9 +const api = global.yoho.API;
  10 +const serviceAPI = global.yoho.ServiceAPI;
  11 +const utils = '../../../utils';
  12 +const productProcess = require(`${utils}/product-process`);
  13 +
  14 +// 资源位
  15 +const _getBanner = (param) => {
  16 + return serviceAPI.get('operations/api/v5/resource/get', {
  17 + content_code: param.contentCode
  18 + }, {
  19 + code: 200
  20 + }).then((result) => {
  21 +
  22 + result = result.data;
  23 +
  24 + return result;
  25 + });
  26 +};
  27 +
  28 +// 购买此商品的用户也购买了
  29 +const _getOthersBuy2 = (param) => {
  30 + return api.get('', {
  31 + method: 'app.recommend.purchased',
  32 + productSkn: param.skn,
  33 + udid: param.uid,
  34 + rec_pos: '100005',
  35 + limit: 2
  36 + }, {
  37 + code: 200
  38 + }).then((result) => {
  39 +
  40 + if (result && result.data && result.data.product_list) {
  41 + return productProcess.processProductList(result.data.product_list);
  42 + }
  43 +
  44 + });
  45 +};
  46 +
  47 +// 订单信息
  48 +const _getOtherDetail = (param) => {
  49 + return api.get('', {
  50 + method: 'app.SpaceOrders.detail',
  51 + uid: param.uid,
  52 + order_code: param.orderCode
  53 + }, {
  54 + code: 200
  55 + }).then((result) => {
  56 +
  57 + return result;
  58 +
  59 + });
  60 +};
  61 +
  62 +// 购买此商品的用户也购买了,要先从订单详情获取商品skn
  63 +const _getOthersBuy = (param) => {
  64 + return api.all([
  65 + _getOtherDetail(param)
  66 + ]).then((result) => {
  67 +
  68 + let goodSkn = '';
  69 +
  70 + if (result && result[0] && result[0].data && result[0].data.order_goods) {
  71 + goodSkn = result[0].data.order_goods[0].product_skn;
  72 + }
  73 +
  74 + return _getOthersBuy2(Object.assign(param, {skn: goodSkn}));
  75 +
  76 + }).then((result) => {
  77 +
  78 + return result;
  79 + });
  80 +};
  81 +
  82 +// 货到付款
  83 +const getPayCod = (param) => {
  84 + return api.all([
  85 + _getBanner(param),
  86 + _getOthersBuy(param),
  87 + _getOtherDetail(param)
  88 + ]).then((result) => {
  89 +
  90 + let resu = {
  91 + match: true,
  92 + banner: [],
  93 + othersBuy: []
  94 + };
  95 +
  96 + if (result && result[0]) {
  97 + resu.banner = result[0];
  98 + }
  99 +
  100 + if (result && result[1]) {
  101 + resu.othersBuy = result[1];
  102 + }
  103 +
  104 + if (result && result[2] && result[2].data && result[2].data.payment_amount) {
  105 + resu.payment = result[2].data.payment_amount;
  106 + } else {
  107 + resu.match = false;
  108 + }
  109 +
  110 + resu.orderCode = param.orderCode;
  111 +
  112 + resu.orderUrl = '/home/orders/detail?order_code=' + param.orderCode;
  113 +
  114 + return resu;
  115 + });
  116 +};
  117 +
  118 +// 支付宝支付
  119 +const getPayAli = (param) => {
  120 + return api.all([
  121 + _getBanner(param),
  122 + _getOthersBuy(param),
  123 + _getOtherDetail(param)
  124 + ]).then((result) => {
  125 +
  126 + let resu = {
  127 + match: true,
  128 + banner: [],
  129 + othersBuy: []
  130 + };
  131 +
  132 + if (result && result[0]) {
  133 + resu.banner = result[0];
  134 + }
  135 +
  136 + if (result && result[1]) {
  137 + resu.othersBuy = result[1];
  138 + }
  139 +
  140 + if (result && result[2] && result[2].data && result[2].data.payment_amount) {
  141 + resu.payment = result[2].data.payment_amount;
  142 + } else {
  143 + resu.match = false;
  144 + }
  145 +
  146 + resu.orderCode = param.orderCode;
  147 +
  148 + resu.orderUrl = '/home/orders/detail?order_code=' + param.orderCode;
  149 +
  150 + return resu;
  151 + });
  152 +};
  153 +
  154 +module.exports = {
  155 + getPayCod,
  156 + getPayAli
  157 +};
@@ -39,7 +39,13 @@ exports.compute = options => { @@ -39,7 +39,13 @@ exports.compute = options => {
39 method: 'app.Seckill.compute', 39 method: 'app.Seckill.compute',
40 }, options); 40 }, options);
41 41
42 - return API.post(url, queryData); 42 + return API.post(url, queryData).then(result => {
  43 + // TODO 数据处理
  44 + if (result.code === 200 && result.data) {
  45 + result.data.yohoCoinCompute = paymentProcess.yohoCoinCompute(result.data);
  46 + }
  47 + return result;
  48 + });
43 }; 49 };
44 50
45 51
@@ -12,6 +12,7 @@ const authMW = require('../../doraemon/middleware/auth'); @@ -12,6 +12,7 @@ const authMW = require('../../doraemon/middleware/auth');
12 12
13 const seckill = require(cRoot + '/seckill'); 13 const seckill = require(cRoot + '/seckill');
14 const countController = require(`${cRoot}/count`); 14 const countController = require(`${cRoot}/count`);
  15 +const payController = require(`${cRoot}/pay`);
15 16
16 // Your controller here 17 // Your controller here
17 router.all('/index/seckill/', authMW); 18 router.all('/index/seckill/', authMW);
@@ -21,5 +22,7 @@ router.post('/index/seckill/compute', seckill.compute); @@ -21,5 +22,7 @@ router.post('/index/seckill/compute', seckill.compute);
21 router.post('/index/seckill/submit', seckill.submit); 22 router.post('/index/seckill/submit', seckill.submit);
22 23
23 router.get('/index/count', countController.cartCount); 24 router.get('/index/count', countController.cartCount);
  25 +router.get('/paySuccess/payCod', payController.payCod);// 支付成功,货到付款
  26 +router.get('/shopping/pay/aliwapreturn', payController.payAli);// 支付成功,支付宝付款
24 27
25 module.exports = router; 28 module.exports = router;
@@ -66,11 +66,12 @@ @@ -66,11 +66,12 @@
66 <i class="iconfont hide up">&#xe615;</i> 66 <i class="iconfont hide up">&#xe615;</i>
67 </h3> 67 </h3>
68 <ul> 68 <ul>
  69 + <li class="dispatch-time-info">快递公司会尽力按您选择的送货时间配送,如遇特殊情况(天气、环境等)无法按您要求时间配送,还请您谅解。</li>
69 {{#each dispatchTime}} 70 {{#each dispatchTime}}
70 - <li {{#if isSelected}}class="chosed"{{/if}} data-id="{{id}}">  
71 - <span>{{name}}</span>  
72 - <i class="right iconfont radio {{#if isSelected}}icon-cb-radio{{else}}icon-radio{{/if}}" ></i>  
73 - </li> 71 + <li {{#if isSelected}}class="chosed"{{/if}} data-id="{{id}}">
  72 + <span>{{name}}</span>
  73 + <i class="right iconfont radio {{#if isSelected}}icon-cb-radio{{else}}icon-radio{{/if}}" ></i>
  74 + </li>
74 {{/each}} 75 {{/each}}
75 </ul> 76 </ul>
76 </div> 77 </div>
@@ -111,28 +112,18 @@ @@ -111,28 +112,18 @@
111 </a> 112 </a>
112 </li> 113 </li>
113 {{/if}} 114 {{/if}}
114 - <li class="coin" data-yoho-coin="{{yohoCoin}}"> 115 + <li class="coin" data-yoho-coin="{{yohoCoinCompute.yohoCoin}}" data-yoho-coin-click={{yohoCoinCompute.yohoCoinClick}}>
115 <span class="title">有货币</span> 116 <span class="title">有货币</span>
116 -  
117 - {{#if yohoCoin}}  
118 - <span class="desc used {{#unless useYohoCoin}}hide{{/unless}}">已抵¥{{useYohoCoin}}</span>  
119 - <span class="desc can-use {{#if useYohoCoin}}hide{{/if}}">可抵¥{{yohoCoin}}</span>  
120 -  
121 - {{#if useYohoCoin}}  
122 - <span class="coin-check">  
123 - <!-- <em>- ¥ {{useYohoCoin}}</em> -->  
124 - <i class="iconfont checkbox icon-cb-radio"></i>  
125 - </span> 117 + <span class="desc msg">{{yohoCoinCompute.yohoCoinMsg}}</span>
  118 + <span class="yoho-coin-help">?</span>
  119 + {{#if yohoCoinCompute.useYohoCoin}}
  120 + <span class="coin-check">
  121 + <i class="iconfont checkbox icon-cb-radio"></i>
  122 + </span>
126 {{else}} 123 {{else}}
127 - <span class="coin-check">  
128 - <!-- <em style="display: none;">- ¥ {{useYohoCoin}}</em> -->  
129 - <i class="iconfont checkbox icon-radio"></i>  
130 - </span>  
131 - {{/if}}  
132 - {{^}}  
133 - <span class="not-used coin-check">  
134 - 无有货币可用  
135 - </span> 124 + <span class="coin-check">
  125 + <i class="iconfont checkbox icon-radio"></i>
  126 + </span>
136 {{/if}} 127 {{/if}}
137 </li> 128 </li>
138 129
@@ -190,6 +181,18 @@ @@ -190,6 +181,18 @@
190 <a href="javascript:;">提交订单</a> 181 <a href="javascript:;">提交订单</a>
191 </div> 182 </div>
192 183
  184 + <div class="yoho-coin-help-dialog-bg hide"></div>
  185 + <div class="yoho-coin-help-dialog hide">
  186 + <div class="yoho-coin-title">有货币使用条件:</div>
  187 + <div class="yoho-coin-content">
  188 + <p>1.订单金额大于20元(含)</p>
  189 + <p>2.有货币数量大于{{yohoCoinCompute.yoho_coin_pay_rule.num_limit}}个(含)</p>
  190 + <p>3.有货币支付不得超过每笔订单应付金额的{{yohoCoinCompute.yoho_coin_pay_rule.max_pay_rate_desc}}</p>
  191 + <p>备注:使用有货币数量为{{yohoCoinCompute.yoho_coin_pay_rule.num_limit}}的整数倍,100有货币抵1元。</p>
  192 + </div>
  193 + <div class="yoho-coin-footer">知道了</div>
  194 + </div>
  195 +
193 <input type="hidden" id="product-sku" name="product-sku" value="{{sku}}"> 196 <input type="hidden" id="product-sku" name="product-sku" value="{{sku}}">
194 {{#with seckill}} 197 {{#with seckill}}
195 <input type="hidden" id="activity-id" name="activity-id" value="{{activityId}}"> 198 <input type="hidden" id="activity-id" name="activity-id" value="{{activityId}}">
  1 +<div class="pay-success">
  2 + <div class="top-tip">
  3 + <div class="img-c"></div>
  4 + <p class="ok-tip">恭喜您,付款成功!</p>
  5 + </div>
  6 + <div class="info-table-c">
  7 + <table class="info-table">
  8 + <tr>
  9 + <td>订单编号</td>
  10 + <td>{{orderCode}}</td>
  11 + </tr>
  12 + <tr>
  13 + <td>付款金额</td>
  14 + <td>¥{{payment}}</td>
  15 + </tr>
  16 + <tr>
  17 + <td>付款方式</td>
  18 + <td>支付宝</td>
  19 + </tr>
  20 + </table>
  21 + </div>
  22 + <div class="btn-c">
  23 + <a href="/">随便逛逛</a>
  24 + <a href="{{orderUrl}}">查看订单</a>
  25 + </div>
  26 + {{# banner}}
  27 + {{#data}}
  28 + <a href="{{url}}" class="ad-pic" alt="{{alt}}">
  29 + <img src="{{image src 640 200}}" />
  30 + </a>
  31 + {{/data}}
  32 + {{/banner}}
  33 + <div class="others-buy clearfix">
  34 + <p>购买此商品的用户也购买了</p>
  35 + {{# othersBuy}}
  36 + {{> common/goods}}
  37 + {{/ othersBuy}}
  38 + </div>
  39 + {{> home/maybe-like}}
  40 +</div>
  41 +
  1 +<div class="pay-success">
  2 + <div class="top-tip">
  3 + <div class="img-c"></div>
  4 + <p class="ok-tip">订单提交成功</p>
  5 + <p class="left-tip">您需要在收货时向售货员支付¥{{payment}}</p>
  6 + </div>
  7 + <div class="info-table-c">
  8 + <table class="info-table">
  9 + <tr>
  10 + <td>订单编号</td>
  11 + <td>{{orderCode}}</td>
  12 + </tr>
  13 + <tr>
  14 + <td>付款金额</td>
  15 + <td>¥{{payment}}</td>
  16 + </tr>
  17 + <tr>
  18 + <td>付款方式</td>
  19 + <td>货到付款</td>
  20 + </tr>
  21 + </table>
  22 + </div>
  23 + <div class="btn-c">
  24 + <a href="/">随便逛逛</a>
  25 + <a href="{{orderUrl}}">查看订单</a>
  26 + </div>
  27 + {{# banner}}
  28 + {{#data}}
  29 + <a href="{{url}}" class="ad-pic" alt="{{alt}}">
  30 + <img src="{{image src 640 200}}" />
  31 + </a>
  32 + {{/data}}
  33 + {{/banner}}
  34 + <div class="others-buy clearfix">
  35 + <p>购买此商品的用户也购买了</p>
  36 + {{# othersBuy}}
  37 + {{> common/goods}}
  38 + {{/ othersBuy}}
  39 + </div>
  40 + {{> home/maybe-like}}
  41 +</div>
  42 +
@@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
7 'use strict'; 7 'use strict';
8 8
9 const headerModel = require('../../../doraemon/models/header'); // 头部model 9 const headerModel = require('../../../doraemon/models/header'); // 头部model
  10 +const footerModel = require('../../../doraemon/models/footer_tab'); // 底部tab
10 const indexModel = require('../models/brand'); 11 const indexModel = require('../models/brand');
11 12
12 /** 13 /**
@@ -16,17 +17,11 @@ const indexModel = require('../models/brand'); @@ -16,17 +17,11 @@ const indexModel = require('../models/brand');
16 * @param int channel 1表示男生频道, 2表示女生频道, 3表示潮童频道, 4表示创意生活频道 17 * @param int channel 1表示男生频道, 2表示女生频道, 3表示潮童频道, 4表示创意生活频道
17 */ 18 */
18 let index = (req, res, next) => { 19 let index = (req, res, next) => {
19 -  
20 - let headerData = headerModel.setNav({  
21 - navTitle: '品牌一览'  
22 - });  
23 -  
24 let responseData = { 20 let responseData = {
25 - pageHeader: headerData,  
26 module: 'channel', 21 module: 'channel',
27 page: 'brand', 22 page: 'brand',
28 title: '品牌一览 | Yoho!Buy有货 | 潮流购物逛不停', 23 title: '品牌一览 | Yoho!Buy有货 | 潮流购物逛不停',
29 - //pageFooter: true 24 + showFooterTab: footerModel.getUrlData('category')
30 }; 25 };
31 26
32 let param = { 27 let param = {
@@ -59,6 +54,7 @@ let search = (req, res, next) => { @@ -59,6 +54,7 @@ let search = (req, res, next) => {
59 pageHeader: headerData, 54 pageHeader: headerData,
60 module: 'channel', 55 module: 'channel',
61 page: 'brand', 56 page: 'brand',
  57 + isWechat: req.yoho.isWechat,
62 title: '品牌一览 | Yoho!Buy有货 | 潮流购物逛不停', 58 title: '品牌一览 | Yoho!Buy有货 | 潮流购物逛不停',
63 pageFooter: true 59 pageFooter: true
64 }; 60 };
@@ -89,7 +85,10 @@ let addBrandSearch = (req, res, next) => { @@ -89,7 +85,10 @@ let addBrandSearch = (req, res, next) => {
89 85
90 let records = timestamp + '_' + brandName; 86 let records = timestamp + '_' + brandName;
91 87
92 - let param = {uid, records}; 88 + let param = {
  89 + uid,
  90 + records
  91 + };
93 92
94 indexModel.addSearchHistory(param).then((result) => { 93 indexModel.addSearchHistory(param).then((result) => {
95 res.json(result); 94 res.json(result);
@@ -124,11 +123,19 @@ let searchAsync = (req, res, next) => { @@ -124,11 +123,19 @@ let searchAsync = (req, res, next) => {
124 } 123 }
125 124
126 if (!uid) { 125 if (!uid) {
127 - return res.json({code: 200, data: {}}); 126 + return res.json({
  127 + code: 200,
  128 + data: {}
  129 + });
128 } 130 }
129 131
130 return indexModel.branchSearchHistoryAsync(uid).then((result) => { 132 return indexModel.branchSearchHistoryAsync(uid).then((result) => {
131 - return res.json({code: 200, data: { history: result }}); 133 + return res.json({
  134 + code: 200,
  135 + data: {
  136 + history: result
  137 + }
  138 + });
132 }); 139 });
133 }; 140 };
134 141
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 */ 3 */
4 'use strict'; 4 'use strict';
5 const cateModel = require('../models/cate'); 5 const cateModel = require('../models/cate');
6 -const headerModel = require('../../../doraemon/models/header'); 6 +const footerModel = require('../../../doraemon/models/footer_tab'); // 底部tab
7 const helpers = global.yoho.helpers; 7 const helpers = global.yoho.helpers;
8 8
9 let index = (req, res, next) => { 9 let index = (req, res, next) => {
@@ -12,15 +12,13 @@ let index = (req, res, next) => { @@ -12,15 +12,13 @@ let index = (req, res, next) => {
12 module: 'channel', 12 module: 'channel',
13 page: 'cate', 13 page: 'cate',
14 title: '商品分类', 14 title: '商品分类',
15 - pageHeader: headerModel.setNav({  
16 - navTitle: '商品分类'  
17 - }),  
18 pageFooter: false, 15 pageFooter: false,
19 category: { 16 category: {
20 nav: result.nav, 17 nav: result.nav,
21 list: result.list, 18 list: result.list,
22 searchUrl: helpers.urlFormat('/search', null, 'search') 19 searchUrl: helpers.urlFormat('/search', null, 'search')
23 - } 20 + },
  21 + showFooterTab: footerModel.getUrlData('category')
24 }); 22 });
25 }).catch(next); 23 }).catch(next);
26 }; 24 };
@@ -6,6 +6,8 @@ @@ -6,6 +6,8 @@
6 'use strict'; 6 'use strict';
7 const _ = require('lodash'); 7 const _ = require('lodash');
8 const channelModel = require('../models/channel'); 8 const channelModel = require('../models/channel');
  9 +const homeModel = require('../../home/models/index');
  10 +const footerModel = require('../../../doraemon/models/footer_tab'); // 底部tab
9 11
10 const helpers = global.yoho.helpers; 12 const helpers = global.yoho.helpers;
11 13
@@ -16,13 +18,7 @@ let _renderData = { @@ -16,13 +18,7 @@ let _renderData = {
16 searchUrl: helpers.urlFormat('/search', null, 'search') 18 searchUrl: helpers.urlFormat('/search', null, 'search')
17 }, 19 },
18 maybeLike: true, 20 maybeLike: true,
19 - showFooterTab: {  
20 - indexUrl: helpers.urlFormat('/?go=1'), // 首页  
21 - categoryUrl: helpers.urlFormat('/cate'), // 分类  
22 - guangUrl: helpers.urlFormat('', null, 'guang'), // 逛首页  
23 - shoppingCartUrl: helpers.urlFormat('/cart/index/index'), // 购物车  
24 - mineUrl: helpers.urlFormat('/home') // 个人中心  
25 - }, 21 + showFooterTab: footerModel.getUrlData('home'),
26 pageFooter: true 22 pageFooter: true
27 }; 23 };
28 24
@@ -38,6 +34,8 @@ let _channelPage = (req, res, data) => { @@ -38,6 +34,8 @@ let _channelPage = (req, res, data) => {
38 gender: data.gender, 34 gender: data.gender,
39 uid: _.toString(req.user.uid) 35 uid: _.toString(req.user.uid)
40 }).then(result => { 36 }).then(result => {
  37 + _renderData.homeHeader.defaultTerms = result.defaultTerms;
  38 +
41 if (!result.content.length || !result.sideNav.length) { 39 if (!result.content.length || !result.sideNav.length) {
42 res.set('Cache-Control', 'no-cache'); 40 res.set('Cache-Control', 'no-cache');
43 } 41 }
@@ -102,7 +100,7 @@ let switchChannel = (req, res, next) => { @@ -102,7 +100,7 @@ let switchChannel = (req, res, next) => {
102 let boys = (req, res, next) => { 100 let boys = (req, res, next) => {
103 _channelPage(req, res, { 101 _channelPage(req, res, {
104 gender: 'boys', 102 gender: 'boys',
105 - title: '男生首页', 103 + title: '男生 | Yoho!Buy有货 | 潮流购物逛不停',
106 boysHomePage: true 104 boysHomePage: true
107 }).catch(next); // TODO 我们在路由处理的最上层的方法处理catch 105 }).catch(next); // TODO 我们在路由处理的最上层的方法处理catch
108 }; 106 };
@@ -113,7 +111,7 @@ let boys = (req, res, next) => { @@ -113,7 +111,7 @@ let boys = (req, res, next) => {
113 let girls = (req, res, next) => { 111 let girls = (req, res, next) => {
114 _channelPage(req, res, { 112 _channelPage(req, res, {
115 gender: 'girls', 113 gender: 'girls',
116 - title: '女生首页', 114 + title: '女生 | Yoho!Buy有货 | 潮流购物逛不停',
117 girlsHomePage: true 115 girlsHomePage: true
118 }).catch(next); 116 }).catch(next);
119 }; 117 };
@@ -125,7 +123,7 @@ let girls = (req, res, next) => { @@ -125,7 +123,7 @@ let girls = (req, res, next) => {
125 let kids = (req, res, next) => { 123 let kids = (req, res, next) => {
126 _channelPage(req, res, { 124 _channelPage(req, res, {
127 gender: 'kids', 125 gender: 'kids',
128 - title: '潮童首页', 126 + title: '潮童 | Yoho!Buy有货 | 潮流购物逛不停',
129 kidsHomePage: true 127 kidsHomePage: true
130 }).catch(next); 128 }).catch(next);
131 }; 129 };
@@ -136,7 +134,7 @@ let kids = (req, res, next) => { @@ -136,7 +134,7 @@ let kids = (req, res, next) => {
136 let lifestyle = (req, res, next) => { 134 let lifestyle = (req, res, next) => {
137 _channelPage(req, res, { 135 _channelPage(req, res, {
138 gender: 'lifestyle', 136 gender: 'lifestyle',
139 - title: '创意生活首页', 137 + title: '创意生活 | Yoho!Buy有货 | 潮流购物逛不停',
140 lifestyleHomePage: true 138 lifestyleHomePage: true
141 }).catch(next); 139 }).catch(next);
142 }; 140 };
@@ -155,6 +153,47 @@ let bottomBanner = (req, res, next) => { @@ -155,6 +153,47 @@ let bottomBanner = (req, res, next) => {
155 }).catch(next); 153 }).catch(next);
156 }; 154 };
157 155
  156 +/**
  157 + * 店铺推荐收藏状态人数
  158 + */
  159 +let shopRecom = (req, res, next) => {
  160 + channelModel.shopRecom({
  161 + shopIds: req.body.shopIds || '',
  162 + uid: req.user.uid || 0,
  163 + }).then(result => {
  164 + res.send(result);
  165 + }).catch(next);
  166 +}
  167 +
  168 +/**
  169 + * 获取用户vip信息
  170 + */
  171 +let userVip = (req, res, next) => {
  172 + let uid = req.user.uid;
  173 +
  174 + if (!uid) {
  175 + res.json({
  176 + code: 555,
  177 + msg: '未登录'
  178 + });
  179 + } else {
  180 + homeModel.getGradeGrade(uid, req.query.channel || 1).then(result => {
  181 + if (result.code === 200) {
  182 + res.json({
  183 + code: 200,
  184 + current_vip_level: result.data.current_vip_level,
  185 + });
  186 + } else {
  187 + res.json({
  188 + code: 500,
  189 + msg: '出错了',
  190 + })
  191 + }
  192 + });
  193 + }
  194 +
  195 +}
  196 +
158 module.exports = { 197 module.exports = {
159 switchChannel, 198 switchChannel,
160 index, 199 index,
@@ -162,5 +201,7 @@ module.exports = { @@ -162,5 +201,7 @@ module.exports = {
162 girls, 201 girls,
163 kids, 202 kids,
164 lifestyle, 203 lifestyle,
165 - bottomBanner  
166 -}; 204 + bottomBanner,
  205 + shopRecom,
  206 + userVip,
  207 +};
@@ -121,8 +121,6 @@ const getBrandByChannel = (channel) => { @@ -121,8 +121,6 @@ const getBrandByChannel = (channel) => {
121 searchUrl: helpers.urlFormat('/brands/search', null), 121 searchUrl: helpers.urlFormat('/brands/search', null),
122 brandPage: true, 122 brandPage: true,
123 123
124 - // pageFooter: true,  
125 - showDownloadApp: true,  
126 brandType: '全部品牌', 124 brandType: '全部品牌',
127 secondBrandType: '新入驻品牌', 125 secondBrandType: '新入驻品牌',
128 thirdBrandType: '热门品牌', 126 thirdBrandType: '热门品牌',
@@ -184,7 +182,9 @@ const getBrandByChannel = (channel) => { @@ -184,7 +182,9 @@ const getBrandByChannel = (channel) => {
184 182
185 let obj = {}; 183 let obj = {};
186 184
187 - obj = Object.assign(obj, {title: key}); 185 + obj = Object.assign(obj, {
  186 + title: key
  187 + });
188 188
189 let list = []; 189 let list = [];
190 190
@@ -199,7 +199,9 @@ const getBrandByChannel = (channel) => { @@ -199,7 +199,9 @@ const getBrandByChannel = (channel) => {
199 199
200 }); 200 });
201 201
202 - obj = Object.assign(obj, {list}); 202 + obj = Object.assign(obj, {
  203 + list
  204 + });
203 205
204 resu.channel.brandList.push(obj); 206 resu.channel.brandList.push(obj);
205 207
@@ -224,7 +226,9 @@ const getBrandByChannel = (channel) => { @@ -224,7 +226,9 @@ const getBrandByChannel = (channel) => {
224 img: helpers.image(newList[key].brand_ico, 186, 115), 226 img: helpers.image(newList[key].brand_ico, 186, 115),
225 }); 227 });
226 228
227 - obj = Object.assign(obj, {list}); 229 + obj = Object.assign(obj, {
  230 + list
  231 + });
228 232
229 resu.channel.newBrandWall.push(obj); 233 resu.channel.newBrandWall.push(obj);
230 234
@@ -249,7 +253,9 @@ const getBrandByChannel = (channel) => { @@ -249,7 +253,9 @@ const getBrandByChannel = (channel) => {
249 img: helpers.image(hotList[key].brand_ico, 186, 115), 253 img: helpers.image(hotList[key].brand_ico, 186, 115),
250 }); 254 });
251 255
252 - obj = Object.assign(obj, {list}); 256 + obj = Object.assign(obj, {
  257 + list
  258 + });
253 259
254 resu.channel.recommandBrandWall.push(obj); 260 resu.channel.recommandBrandWall.push(obj);
255 261
@@ -314,7 +320,9 @@ const addSearchHistory = (param) => { @@ -314,7 +320,9 @@ const addSearchHistory = (param) => {
314 uid: param.uid, 320 uid: param.uid,
315 records: param.records 321 records: param.records
316 322
317 - }, { code: 200 }); 323 + }, {
  324 + code: 200
  325 + });
318 }; 326 };
319 327
320 /** 328 /**
@@ -457,7 +465,6 @@ const branchSearch = (params) => { @@ -457,7 +465,6 @@ const branchSearch = (params) => {
457 465
458 let resu = { 466 let resu = {
459 brandPage: true, 467 brandPage: true,
460 - showDownloadApp: true,  
461 pageFooter: true, 468 pageFooter: true,
462 hot: [], 469 hot: [],
463 history: [], 470 history: [],
@@ -504,7 +511,9 @@ const branchSearch = (params) => { @@ -504,7 +511,9 @@ const branchSearch = (params) => {
504 511
505 let obj = {}; 512 let obj = {};
506 513
507 - obj = Object.assign(obj, {name: hotList[key].brandName}); 514 + obj = Object.assign(obj, {
  515 + name: hotList[key].brandName
  516 + });
508 517
509 resu.hot.push(obj); 518 resu.hot.push(obj);
510 519
@@ -550,7 +559,9 @@ const delBrandSearchHistory = (param) => { @@ -550,7 +559,9 @@ const delBrandSearchHistory = (param) => {
550 method: 'app.search.clearHotBrandRecords', 559 method: 'app.search.clearHotBrandRecords',
551 uid: param.uid 560 uid: param.uid
552 561
553 - }, { code: 200 }).then(result => { 562 + }, {
  563 + code: 200
  564 + }).then(result => {
554 565
555 return result; 566 return result;
556 567
@@ -561,7 +572,9 @@ const delBrandSearchHistory = (param) => { @@ -561,7 +572,9 @@ const delBrandSearchHistory = (param) => {
561 * [异步获取用户最近搜索词] 572 * [异步获取用户最近搜索词]
562 */ 573 */
563 const branchSearchHistoryAsync = (uid) => { 574 const branchSearchHistoryAsync = (uid) => {
564 - return branchSearchHistory({uid}).then((result) => { 575 + return branchSearchHistory({
  576 + uid
  577 + }).then((result) => {
565 let hisList = result.data; 578 let hisList = result.data;
566 579
567 let obj = []; 580 let obj = [];
@@ -8,6 +8,7 @@ const utils = '../../../utils'; @@ -8,6 +8,7 @@ const utils = '../../../utils';
8 const contentCodeConfig = require('../../../config/content-code'); 8 const contentCodeConfig = require('../../../config/content-code');
9 const _ = require('lodash'); 9 const _ = require('lodash');
10 const api = global.yoho.ServiceAPI; 10 const api = global.yoho.ServiceAPI;
  11 +const API = global.yoho.API;
11 const logger = global.yoho.logger; 12 const logger = global.yoho.logger;
12 const resourcesProcess = require(`${utils}/resources-process`); 13 const resourcesProcess = require(`${utils}/resources-process`);
13 14
@@ -37,25 +38,23 @@ const bottomBannerCode = contentCodeConfig.bottom; @@ -37,25 +38,23 @@ const bottomBannerCode = contentCodeConfig.bottom;
37 * 频道选择页 默认数据 38 * 频道选择页 默认数据
38 * @type {Object} 39 * @type {Object}
39 */ 40 */
40 -const channelList = [  
41 - {  
42 - href: '/boys',  
43 - title: '男生',  
44 - entitle: 'BOYS'  
45 - }, {  
46 - href: '/girls',  
47 - title: '女生',  
48 - entitle: 'GIRLS'  
49 - }, {  
50 - href: '/kids',  
51 - title: '潮童',  
52 - entitle: 'KIDS'  
53 - }, {  
54 - href: '/lifestyle',  
55 - title: '创意生活',  
56 - entitle: 'LIFESTYLE'  
57 - }  
58 -]; 41 +const channelList = [{
  42 + href: '/boys',
  43 + title: '男生',
  44 + entitle: 'BOYS'
  45 +}, {
  46 + href: '/girls',
  47 + title: '女生',
  48 + entitle: 'GIRLS'
  49 +}, {
  50 + href: '/kids',
  51 + title: '潮童',
  52 + entitle: 'KIDS'
  53 +}, {
  54 + href: '/lifestyle',
  55 + title: '创意生活',
  56 + entitle: 'LIFESTYLE'
  57 +}];
59 58
60 /** 59 /**
61 * 获取二级菜单顶部颜色 60 * 获取二级菜单顶部颜色
@@ -136,8 +135,8 @@ const _getChannelResource = (params) => { @@ -136,8 +135,8 @@ const _getChannelResource = (params) => {
136 if (result && result.code === 200 && result.data && result.data.list) { 135 if (result && result.code === 200 && result.data && result.data.list) {
137 for (let item of result.data.list) { 136 for (let item of result.data.list) {
138 item.template_name === 'single_image' && 137 item.template_name === 'single_image' &&
139 - item.data.length === 1 &&  
140 - (item.singleOne = true); 138 + item.data.length === 1 &&
  139 + (item.singleOne = true);
141 } 140 }
142 return resourcesProcess(result.data.list); 141 return resourcesProcess(result.data.list);
143 } else { 142 } else {
@@ -168,6 +167,24 @@ const _getLeftNav = (choosed) => { @@ -168,6 +167,24 @@ const _getLeftNav = (choosed) => {
168 }; 167 };
169 168
170 /** 169 /**
  170 + * 获取热门搜索
  171 + **/
  172 +const _getSearchIndex = () => {
  173 + return API.get('', {
  174 + method: 'app.search.getTerms'
  175 + }, {
  176 + cache: true
  177 + }).then((result) => {
  178 + if (result && result.code === 200) {
  179 + return result.data;
  180 + } else {
  181 + logger.error('Hot Search return code is not 200');
  182 + return {};
  183 + }
  184 + });
  185 +};
  186 +
  187 +/**
171 * 获取频道选择页数据 188 * 获取频道选择页数据
172 * @return {[type]} 189 * @return {[type]}
173 */ 190 */
@@ -252,10 +269,10 @@ let getChannelData = (params) => { @@ -252,10 +269,10 @@ let getChannelData = (params) => {
252 var channelData = {}; 269 var channelData = {};
253 let navGender = _.cloneDeep(params.gender); 270 let navGender = _.cloneDeep(params.gender);
254 271
255 - return Promise.all([_getChannelResource(params), _getLeftNav(navGender)]).then((data) => { 272 + return Promise.all([_getChannelResource(params), _getLeftNav(navGender), _getSearchIndex()]).then((data) => {
256 channelData.content = data[0] || []; // 资源位数据 273 channelData.content = data[0] || []; // 资源位数据
257 channelData.sideNav = data[1] || []; // 侧边栏数据 274 channelData.sideNav = data[1] || []; // 侧边栏数据
258 - 275 + channelData.defaultTerms = (data[2] && data[2].defaultTerms && data[2].defaultTerms.length !== 0) ? data[2].defaultTerms[0].content : '搜索商品、品牌';
259 return channelData; 276 return channelData;
260 }); 277 });
261 }; 278 };
@@ -282,8 +299,20 @@ let getBottomBannerData = (gender) => { @@ -282,8 +299,20 @@ let getBottomBannerData = (gender) => {
282 }); 299 });
283 }; 300 };
284 301
  302 +/**
  303 + * 获取店铺推荐收藏和人数
  304 + */
  305 +let shopRecom = (params) => {
  306 + return API.get('', {
  307 + method: 'app.shops.floorNewInfo',
  308 + shop_ids: params.shopIds,
  309 + uid: params.uid,
  310 + });
  311 +};
  312 +
285 module.exports = { 313 module.exports = {
286 getChannelData, 314 getChannelData,
287 getChannelSwitchData, 315 getChannelSwitchData,
288 - getBottomBannerData 316 + getBottomBannerData,
  317 + shopRecom,
289 }; 318 };
@@ -29,4 +29,7 @@ router.post('/brands/searchAsync', brandController.searchAsync); // 品牌搜索 @@ -29,4 +29,7 @@ router.post('/brands/searchAsync', brandController.searchAsync); // 品牌搜索
29 router.post('/brands/addBrandSearch', brandController.addBrandSearch); // 添加品牌搜索记录 29 router.post('/brands/addBrandSearch', brandController.addBrandSearch); // 添加品牌搜索记录
30 router.get('/brands/delBrandHistory', brandController.delBrandHistory); // 删除品牌搜索记录 30 router.get('/brands/delBrandHistory', brandController.delBrandHistory); // 删除品牌搜索记录
31 31
  32 +// 5.2新楼层功能
  33 +router.post('/channel/shopRecom', channel.shopRecom); // 店铺推荐收藏状态
  34 +router.post('/channel/userVip', channel.userVip)
32 module.exports = router; 35 module.exports = router;
@@ -101,3 +101,4 @@ @@ -101,3 +101,4 @@
101 101
102 {{/channel}} 102 {{/channel}}
103 </div> 103 </div>
  104 +{{> footer-tab}}
1 <div class="brand-page brand-search-page yoho-page"> 1 <div class="brand-page brand-search-page yoho-page">
2 - <div class="newbrand-search"> 2 + <div class="newbrand-search {{#if isWechat}} wechat {{/if}}">
3 <form class="search-box clearfix"> 3 <form class="search-box clearfix">
4 <input type="text" class="search-input" id="keyword" placeholder="查找品牌"> 4 <input type="text" class="search-input" id="keyword" placeholder="查找品牌">
5 <i class="search-icon iconfont">&#xe60f;</i> 5 <i class="search-icon iconfont">&#xe60f;</i>
@@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@
9 </div> 9 </div>
10 </form> 10 </form>
11 </div> 11 </div>
12 - <div class="search-result"> 12 + <div class="search-result {{#if isWechat}} wechat {{/if}}">
13 </div> 13 </div>
14 </div> 14 </div>
15 15
@@ -45,3 +45,4 @@ @@ -45,3 +45,4 @@
45 </div> 45 </div>
46 {{/ category}} 46 {{/ category}}
47 </div> 47 </div>
  48 +{{> footer-tab}}
@@ -25,7 +25,7 @@ @@ -25,7 +25,7 @@
25 {{> channel/banner-bottom}} 25 {{> channel/banner-bottom}}
26 {{/bannerBottom}} 26 {{/bannerBottom}}
27 27
28 - {{> channel/footer-tab}} 28 + {{> footer-tab}}
29 29
30 <div class="overlay"></div> 30 <div class="overlay"></div>
31 </div> 31 </div>
@@ -14,7 +14,9 @@ @@ -14,7 +14,9 @@
14 {{/announcement}} --}} 14 {{/announcement}} --}}
15 {{! 中间banner}} 15 {{! 中间banner}}
16 {{#if singleImage}} 16 {{#if singleImage}}
  17 + <div data-id="{{template_id}}">
17 {{> resources/banner}} 18 {{> resources/banner}}
  19 + </div>
18 {{/if}} 20 {{/if}}
19 {{! 两个小图}} 21 {{! 两个小图}}
20 {{#if smallPic}} 22 {{#if smallPic}}
@@ -53,7 +55,7 @@ @@ -53,7 +55,7 @@
53 {{> resources/plus-star}} 55 {{> resources/plus-star}}
54 {{/if}} 56 {{/if}}
55 {{! 新人专享}} 57 {{! 新人专享}}
56 - {{#if newUserFloor}} 58 + {{#if oldNewUserFloor}}
57 {{> resources/fresh-only}} 59 {{> resources/fresh-only}}
58 {{/if}} 60 {{/if}}
59 {{! 秒杀}} 61 {{! 秒杀}}
@@ -72,4 +74,32 @@ @@ -72,4 +74,32 @@
72 {{#if sixLinesFloor}} 74 {{#if sixLinesFloor}}
73 {{> resources/six-lines-floor}} 75 {{> resources/six-lines-floor}}
74 {{/if}} 76 {{/if}}
  77 + {{! vip专属}}
  78 + {{#if vipUse}}
  79 + {{> resources/vip-only}}
  80 + {{/if}}
  81 + {{! 店铺推荐}}
  82 + {{#if shopRecommend}}
  83 + {{> resources/shop-recommand}}
  84 + {{/if}}
  85 + {{! 新新人专享}}
  86 + {{#if newUserFloor}}
  87 + {{> resources/new-user-floor}}
  88 + {{/if}}
  89 + {{! 人气单品}}
  90 + {{#if popularSingleProduct}}
  91 + {{> resources/hot-single}}
  92 + {{/if}}
  93 + {{! SALE}}
  94 + {{#if sale1T1L4R}}
  95 + {{> resources/sale-floor}}
  96 + {{/if}}
  97 + {{! 新品首发楼层}}
  98 + {{#if newProductFloor}}
  99 + {{> resources/new-first}}
  100 + {{/if}}
  101 + {{! 分隔楼层}}
  102 + {{#if divideImage}}
  103 + {{> resources/divide-image}}
  104 + {{/if}}
75 {{/content}} 105 {{/content}}
1 -<div class="home-header clearfix" {{# bgColor}}style="background-color:{{.}};background-image:none"{{/ bgColor}}>  
2 - <span class="nav-btn iconfont">&#xe60b;</span>  
3 - <span class="logo"></span>  
4 - <span class="search-btn iconfont"><a href="{{searchUrl}}">&#xe60f;</a></span> 1 +<div id="home-header" class="home-header clearfix" {{# bgColor}}style="background-color:{{.}};background-image:none"{{/ bgColor}}>
  2 + <div id="browser-header">
  3 + <span class="nav-btn iconfont">&#xe60b;</span>
  4 + <span class="logo"></span>
  5 + <span class="search-btn iconfont"><a href="{{searchUrl}}">&#xe60f;</a></span>
  6 + </div>
  7 + <div id="wechat-header" class="hide">
  8 + <span class="nav-btn iconfont">&#xe60b;</span>
  9 + <div class="search-input">
  10 + <a href="{{searchUrl}}">
  11 + <i class="search-icon iconfont">&#xe60f;</i>
  12 + <p>{{defaultTerms}}</p>
  13 + </a>
  14 + </div>
  15 + </div>
  16 + <script type="text/javascript">
  17 + var isWechat = /micromessenger/i.test(navigator.userAgent || '');
  18 + if (isWechat) {
  19 + document.getElementById('browser-header').classList.add('hide');
  20 + document.getElementById('wechat-header').classList.remove('hide');
  21 + document.getElementById('home-header').classList.add('iswechat');
  22 + }
  23 + </script>
5 </div> 24 </div>
@@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
8 const mRoot = '../models'; 8 const mRoot = '../models';
9 const indexModel = require(`${mRoot}/index`); 9 const indexModel = require(`${mRoot}/index`);
10 const headerModel = require('../../../doraemon/models/header'); // 头部model 10 const headerModel = require('../../../doraemon/models/header'); // 头部model
  11 +const footerModel = require('../../../doraemon/models/footer_tab'); // 底部tab
11 const guangProcess = require(`${global.utils}/guang-process`); 12 const guangProcess = require(`${global.utils}/guang-process`);
12 const stringProcess = require(`${global.utils}/string-process`); 13 const stringProcess = require(`${global.utils}/string-process`);
13 const Promise = require('bluebird'); 14 const Promise = require('bluebird');
@@ -50,7 +51,7 @@ const editor = (req, res, next) => { @@ -50,7 +51,7 @@ const editor = (req, res, next) => {
50 articleData.colparam = { 51 articleData.colparam = {
51 urlpath: req.path, 52 urlpath: req.path,
52 param: `?id=${id}` 53 param: `?id=${id}`
53 - } 54 + };
54 55
55 build.push(guangProcess.formatArticle(articleData, true, isApp, false, uid)); 56 build.push(guangProcess.formatArticle(articleData, true, isApp, false, uid));
56 }); 57 });
@@ -151,25 +152,17 @@ const pageData = (req, res, next) => { @@ -151,25 +152,17 @@ const pageData = (req, res, next) => {
151 * @param next 152 * @param next
152 */ 153 */
153 const index = (req, res, next) => { 154 const index = (req, res, next) => {
154 - let headerData = headerModel.setNav({  
155 - navTitle: '逛'  
156 - });  
157 -  
158 let responseData = { 155 let responseData = {
159 - pageHeader: headerData,  
160 module: 'guang', 156 module: 'guang',
161 page: 'index', 157 page: 'index',
162 title: '逛 | Yoho!Buy有货 | 潮流购物逛不停', 158 title: '逛 | Yoho!Buy有货 | 潮流购物逛不停',
163 - pageFooter: true 159 + showFooterTab: footerModel.getUrlData('guang')
164 }; 160 };
165 161
166 let param = { 162 let param = {
167 uid: req.user.uid || req.query.uid, 163 uid: req.user.uid || req.query.uid,
168 -  
169 udid: req.user.udid, 164 udid: req.user.udid,
170 -  
171 type: req.query.type || '0', 165 type: req.query.type || '0',
172 -  
173 gender: req.query.gender || '1,3' 166 gender: req.query.gender || '1,3'
174 }; 167 };
175 168
@@ -278,4 +271,4 @@ module.exports = { @@ -278,4 +271,4 @@ module.exports = {
278 tag, 271 tag,
279 listDynamicData, 272 listDynamicData,
280 detailDynamicData 273 detailDynamicData
281 -};  
  274 +};
@@ -7,6 +7,9 @@ @@ -7,6 +7,9 @@
7 7
8 const mRoot = '../models'; 8 const mRoot = '../models';
9 const rssModel = require(`${mRoot}/rss`); 9 const rssModel = require(`${mRoot}/rss`);
  10 +const Feed = require('feed');
  11 +const _ = require('lodash');
  12 +const moment = require('moment');
10 const helpers = global.yoho.helpers; 13 const helpers = global.yoho.helpers;
11 14
12 /** 15 /**
@@ -15,18 +18,61 @@ const helpers = global.yoho.helpers; @@ -15,18 +18,61 @@ const helpers = global.yoho.helpers;
15 const index = (req, res, next) => { 18 const index = (req, res, next) => {
16 let gender = req.query.gender || '1,2,3', 19 let gender = req.query.gender || '1,2,3',
17 items = []; 20 items = [];
18 - 21 + return rssModel.getRssArticle(gender).then((result) => {
  22 + if (!result) {
  23 + return next();
  24 + }
  25 + res.setHeader('Content-Type', 'text/xml; charset=utf-8');
  26 + var feed = new Feed({
  27 + id: 'http://yohobuy.com',
  28 + title: '有货逛',
  29 + description: 'Yoho!Buy有货 | 年轻人潮流购物中心',
  30 + link: 'http://yohobuy.com',
  31 + copyright: '2015 yoho.inc',
  32 + generator: 'http://m.yohobuy.com',
  33 + updated: new Date(),
  34 + })
  35 + _.forEach(result, item => {
  36 + item.url = item.url.indexOf('http') >= 0 ? item.url : 'http://'+item.url
  37 + feed.addItem({
  38 + title: item.title,
  39 + link: `${item.url}&ref=rss`,
  40 + description: item.intro,
  41 + author: [{
  42 + name: (item.author && item.author.name) || ' '
  43 + }],
  44 + date: new Date(item.publishTimeLong && parseFloat(item.publishTimeLong) || moment(item.publishTime, "MM月DD日 HH:mm"))
  45 + });
  46 + });
  47 + if (req.params[0] && req.params[0] === '/atom') {
  48 + return res.send(feed.render('atom-1.0'));
  49 + }
  50 + return res.send(feed.render('rss-2.0'))
  51 + });
  52 +};
  53 +const rss = (req, res, next, gmt) => {
  54 + let gender = req.query.gender || '1,2,3',
  55 + items = [];
19 res.setHeader('Content-Type', 'text/xml; charset=utf-8'); 56 res.setHeader('Content-Type', 'text/xml; charset=utf-8');
20 return rssModel.getRssArticle(gender).then((result) => { 57 return rssModel.getRssArticle(gender).then((result) => {
  58 + if (!result) {
  59 + return next();
  60 + }
  61 + _.forEach(result, item => {
  62 + item.url = item.url.indexOf('http') >= 0 ? item.url : 'http://'+item.url;
  63 + let time = new Date(item.publishTimeLong && parseFloat(item.publishTimeLong) || moment(item.publishTime, "MM月DD日 HH:mm"));
  64 + let format = gmt ? 'ddd, MM MMM YYYY hh:mm:ss +0800' : 'YYYY-MM-DD hh:mm:ss +0800';
  65 +
  66 + item.publishTime = moment(time).format(format);
  67 + });
21 return res.render('rss/index', { 68 return res.render('rss/index', {
22 layout: false, 69 layout: false,
23 - time: (new Date()).toUTCString(),  
24 items: result 70 items: result
25 }); 71 });
26 }); 72 });
27 }; 73 };
28 74
29 -  
30 module.exports = { 75 module.exports = {
31 - index  
32 -}; 76 + index,
  77 + rss
  78 +};
@@ -179,4 +179,4 @@ const intro = (id) => { @@ -179,4 +179,4 @@ const intro = (id) => {
179 module.exports = { 179 module.exports = {
180 packageData, 180 packageData,
181 intro 181 intro
182 -};  
  182 +};
@@ -41,9 +41,11 @@ const getRssArticle = (gender) => { @@ -41,9 +41,11 @@ const getRssArticle = (gender) => {
41 let artListFunc = (i, len, resolve) => { 41 let artListFunc = (i, len, resolve) => {
42 if (i < len) { 42 if (i < len) {
43 let value = article.data.list.artList[i]; 43 let value = article.data.list.artList[i];
  44 +
44 if (typeof value.id !== 'undefined') { 45 if (typeof value.id !== 'undefined') {
45 build = guangProcess.formatArticle(value, false, false, true); 46 build = guangProcess.formatArticle(value, false, false, true);
46 - build.author.name = (build.author && build.author.name) || ''; 47 + build.author = build.author || {};
  48 + build.author.name = (build.author && build.author.name) || ''
47 return _genIntro(value.id).then((intro) => { 49 return _genIntro(value.id).then((intro) => {
48 build.intro = intro; 50 build.intro = intro;
49 result.push(build); 51 result.push(build);
@@ -91,6 +93,7 @@ const _genIntro = (id) => { @@ -91,6 +93,7 @@ const _genIntro = (id) => {
91 }); 93 });
92 94
93 }; 95 };
  96 +
94 module.exports = { 97 module.exports = {
95 getRssArticle 98 getRssArticle
96 -}; 99 +};
@@ -54,7 +54,9 @@ router.get('/plustar', plustar.getListData); // 国际优选列表页 @@ -54,7 +54,9 @@ router.get('/plustar', plustar.getListData); // 国际优选列表页
54 router.get('/plustar/brandinfo', plustar.getDetailData); // 国际优选详情页 54 router.get('/plustar/brandinfo', plustar.getDetailData); // 国际优选详情页
55 router.post('/plustar/brandinfoAsync', plustar.getDetailDataAsync); // 国际优选详情页异步数据 55 router.post('/plustar/brandinfoAsync', plustar.getDetailDataAsync); // 国际优选详情页异步数据
56 56
57 -router.get('/rss', rss.index); // 订阅资讯 57 +router.get('/rss/new', (req, res, next) => rss.rss(req, res, next, '')); // 订阅资讯
  58 +router.get('/rss/new-gmt', (req, res, next) => rss.rss(req, res, next, 'gmt')); // 订阅资讯
  59 +router.get(/^\/rss(\/\w+)?(\/\w+)?/, rss.index); // 订阅资讯
58 60
59 router.get('/info/listData', index.listDynamicData); 61 router.get('/info/listData', index.listDynamicData);
60 router.get('/info/detailData', index.detailDynamicData); 62 router.get('/info/detailData', index.detailDynamicData);
@@ -44,4 +44,5 @@ @@ -44,4 +44,5 @@
44 </div> 44 </div>
45 <input id="gender" type="hidden" value={{gender}}> 45 <input id="gender" type="hidden" value={{gender}}>
46 {{/ guang}} 46 {{/ guang}}
47 -</div>  
  47 +</div>
  48 +{{> footer-tab}}
@@ -35,4 +35,5 @@ @@ -35,4 +35,5 @@
35 <input id="isApp" type="hidden" value={{isApp}}> 35 <input id="isApp" type="hidden" value={{isApp}}>
36 {{/if}} 36 {{/if}}
37 {{/ guang}} 37 {{/ guang}}
  38 +{{> common/suspend-home}}
38 </div> 39 </div>
@@ -190,5 +190,7 @@ @@ -190,5 +190,7 @@
190 </a> 190 </a>
191 </div> 191 </div>
192 {{/if}} 192 {{/if}}
  193 +
  194 + {{> common/suspend-home}}
193 </div> 195 </div>
194 196
@@ -35,4 +35,5 @@ @@ -35,4 +35,5 @@
35 <input id="isApp" type="hidden" value={{isApp}}> 35 <input id="isApp" type="hidden" value={{isApp}}>
36 {{/if}} 36 {{/if}}
37 {{/ guang}} 37 {{/ guang}}
  38 +{{> common/suspend-home}}
38 </div> 39 </div>
@@ -15,5 +15,5 @@ @@ -15,5 +15,5 @@
15 <div class="plusstar-resources"> 15 <div class="plusstar-resources">
16 <!--资源位数据模板--> 16 <!--资源位数据模板-->
17 </div><!--/plusstar-resources--> 17 </div><!--/plusstar-resources-->
18 - 18 + {{> common/suspend-home}}
19 </div><!--/plusstar-page--> 19 </div><!--/plusstar-page-->
@@ -17,4 +17,5 @@ @@ -17,4 +17,5 @@
17 </div> 17 </div>
18 {{/if}} 18 {{/if}}
19 </div> 19 </div>
  20 + {{> common/suspend-home}}
20 </div> 21 </div>
1 -<?xml version="1.0" encoding="UTF-8"?>  
2 -<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">  
3 - <channel>  
4 - <title>有货逛</title>  
5 - <link>http://yohobuy.com</link>  
6 - <generator>http://m.yohobuy.com</generator>  
7 - <description>Yoho!Buy有货 | 年轻人潮流购物中心</description>  
8 - <atom:link href="http://guang.m.yohobuy.com/rss" rel="self"></atom:link>  
9 - <atom:link rel="hub" href="http://pubsubhubbub.appspot.com"/>  
10 - <language>zh-cn</language>  
11 - <copyright>2015 yoho.inc</copyright>  
12 - <lastBuildDate>{{time}}</lastBuildDate>  
13 - <ttl>50</ttl>  
14 - {{# items}}  
15 - <item>  
16 - <title><![CDATA[{{title}}]]></title>  
17 - <link>  
18 - <![CDATA[{{{url}}}&ref=rss]]>  
19 - </link>  
20 - <description>  
21 - <![CDATA[{{{intro}}}]]>  
22 - </description>  
23 - <pubDate>{{publishTime}}</pubDate>  
24 - <author>  
25 - <![CDATA[{{author.name}}]]>  
26 - </author>  
27 - <guid>  
28 - <![CDATA[{{{url}}}&ref=rss]]>  
29 - </guid>  
30 - <source>有货</source>  
31 - </item>  
32 - {{/items}}  
33 - </channel> 1 +<?xml version='1.0' encoding='utf-8'?>
  2 +<rss version='2.0'>
  3 + <channel>
  4 + <language>zh-cn</language>
  5 + <title><![CDATA[有货逛]]></title>
  6 + <link><![CDATA[http://yohobuy.com]]></link>
  7 + <description><![CDATA[Yoho!Buy有货 | 年轻人潮流购物中心]]></description>
  8 + <generator><![CDATA[yohobuy.com]]></generator>
  9 + <image>
  10 + <title><![CDATA[有货逛]]></title>
  11 + <url><![CDATA[https://cdn.yoho.cn/m-yohobuy-node/assets/img/channel/yohologo.png?v1588b112f08]]></url>
  12 + <link><![CDATA[http://yohobuy.com]]></link>
  13 + <width><![CDATA[ 295 ]]></width>
  14 + <height><![CDATA[ 60 ]]></height>
  15 + <description><![CDATA[yohobuy.com]]></description>
  16 + </image>
  17 + {{# items}}
  18 + <item>
  19 + <title><![CDATA[{{title}}]]></title>
  20 + <link><![CDATA[{{{url}}}&ref=rss]]></link>
  21 + <description><![CDATA[{{{intro}}}]]></description>
  22 + <pubDate><![CDATA[{{publishTime}}]]></pubDate>
  23 + <source><![CDATA[有货逛]]></source>
  24 + <author>有货</author>
  25 + </item>
  26 + {{/items}}
  27 +
  28 + </channel>
34 </rss> 29 </rss>
@@ -18,6 +18,9 @@ @@ -18,6 +18,9 @@
18 {{# is_limited}} 18 {{# is_limited}}
19 <p class="good-tag limit-tag">限量</p> 19 <p class="good-tag limit-tag">限量</p>
20 {{/ is_limited}} 20 {{/ is_limited}}
  21 + {{# is_presell}}
  22 + <p class="good-tag is-presell">预售</p>
  23 + {{/ is_presell}}
21 {{/ tags}} 24 {{/ tags}}
22 </div> 25 </div>
23 <div class="good-detail-img"> 26 <div class="good-detail-img">
@@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
7 'use strict'; 7 'use strict';
8 8
9 const headerModel = require('../../../doraemon/models/header'); // 头部model 9 const headerModel = require('../../../doraemon/models/header'); // 头部model
  10 +const footerModel = require('../../../doraemon/models/footer_tab'); // 底部tab
10 const indexModel = require('../models/index'); 11 const indexModel = require('../models/index');
11 12
12 /** 13 /**
@@ -22,23 +23,18 @@ exports.index = (req, res, next) => { @@ -22,23 +23,18 @@ exports.index = (req, res, next) => {
22 udid: require('md5')(req.ip) 23 udid: require('md5')(req.ip)
23 }; 24 };
24 25
25 - let headerData = headerModel.setNav({  
26 - navTitle: '个人中心',  
27 - backUrl: '//m.yohobuy.com/?go=1'  
28 - });  
29 -  
30 indexModel.index(params).then(result => { 26 indexModel.index(params).then(result => {
31 if (result) { 27 if (result) {
32 res.render('home', Object.assign(result, { 28 res.render('home', Object.assign(result, {
33 isLogin: params.uid ? true : false, 29 isLogin: params.uid ? true : false,
34 module: 'home', 30 module: 'home',
35 page: 'index', 31 page: 'index',
36 - title: 'Yoho!Buy 有货',  
37 - pageHeader: headerData, 32 + title: '个人中心 | Yoho!Buy有货 | 潮流购物逛不停',
38 pageFooter: true, 33 pageFooter: true,
39 pageChannel: { 34 pageChannel: {
40 boys: true 35 boys: true
41 - } 36 + },
  37 + showFooterTab: footerModel.getUrlData('mine')
42 })); 38 }));
43 } 39 }
44 }).catch(next); 40 }).catch(next);
@@ -206,4 +202,3 @@ exports.preferential = (req, res, next) => { @@ -206,4 +202,3 @@ exports.preferential = (req, res, next) => {
206 }).catch(next); 202 }).catch(next);
207 203
208 }; 204 };
209 -  
@@ -15,67 +15,21 @@ const _serverCrash = (res, params) => { @@ -15,67 +15,21 @@ const _serverCrash = (res, params) => {
15 res.render('installment/server-crash', params); 15 res.render('installment/server-crash', params);
16 }; 16 };
17 17
18 -// 判断是否已经获取到了开通的状态值  
19 -const _reviewStatus = (res, req, uid, status) => {  
20 - let jumpUrl = helpers.appUrlFormat('/product/new', 'go.new');  
21 -  
22 - if (status === '1') {  
23 - return {  
24 - review: {  
25 - url: jumpUrl  
26 - }  
27 - };  
28 - } else if (status === '2') {  
29 - return Promise.all([installmentModel.getSearchIntallment({  
30 - page: 1  
31 - }), installmentModel.getQueryCreditInfo(uid)]).then((result) => { //eslint-disable-line  
32 - return {  
33 - success: {  
34 - price: result[1].currCreditLimit,  
35 - installmentOnly: {  
36 - title: {  
37 - title: '分期专享',  
38 - more_url: helpers.appUrlFormat(req.originalUrl, 'go.instalmentlist', {  
39 - title: '分期专享'  
40 - })  
41 - },  
42 - goods: result[0]  
43 - },  
44 - url: helpers.appUrlFormat(req.originalUrl, 'go.instalmentlist', {  
45 - title: '分期专享'  
46 - })  
47 - }  
48 - };  
49 - }).catch(() => {  
50 - _serverCrash(res, {  
51 - url: req.originalUrl,  
52 - title: '分期专享'  
53 - });  
54 - }); 18 +const _banksInit = () => {
  19 + const banks = ['农业银行', '中国银行', '工商银行', '建设银行', '光大银行', '兴业银行', '邮储银行', '民生银行', '中信银行', '广发银行'];
55 20
56 - } else if (status === '3') {  
57 - return {  
58 - error: true,  
59 - failReason: '姓名、身份证、银行卡不匹配'  
60 - };  
61 - } else if (status === '4') {  
62 - return {  
63 - cancel: {  
64 - url: jumpUrl  
65 - }  
66 - };  
67 - } else if (status === '5') {  
68 - return {  
69 - error: true,  
70 - failReason: '您的授信未通过,在有货更多的消费,增加信用度,会大大提升审核通过率奥。'  
71 - }; 21 + if (new Date() >= new Date('2016-10-18 00:00:00')) {
  22 + // 2016年10月12日至17日 平安银行业务暂停(平安银行期间不支持服务)
  23 + banks.push('平安银行');
72 } 24 }
  25 +
  26 + return banks;
73 }; 27 };
74 28
75 // 还款列表公共处理块 29 // 还款列表公共处理块
76 const _repaymentList = (req, res, opt, params) => { 30 const _repaymentList = (req, res, opt, params) => {
77 params = _.assign({ 31 params = _.assign({
78 - uid: req.cookies.installmentUid || 1 32 + uid: req.cookies.installmentUid
79 }, params); 33 }, params);
80 34
81 installmentModel.getQueryAmtList(params).then((result) => { 35 installmentModel.getQueryAmtList(params).then((result) => {
@@ -96,12 +50,14 @@ const _repaymentList = (req, res, opt, params) => { @@ -96,12 +50,14 @@ const _repaymentList = (req, res, opt, params) => {
96 // 开通分期首页 50 // 开通分期首页
97 const index = (req, res) => { 51 const index = (req, res) => {
98 let uid = req.query.uid; 52 let uid = req.query.uid;
  53 + Promise.all([
  54 + installmentModel.getStauts(uid),
  55 + installmentModel.getSearchIntallment({
  56 + page: 1
  57 + })
  58 + ]).then((result) => {
99 59
100 - Promise.all([installmentModel.getStauts(uid), installmentModel.getSearchIntallment({  
101 - page: 1  
102 - })]).then((result) => {  
103 -  
104 - // status:0 未申请 1审核中 2已开通 3 审核未通过 60 + // openStatus:0 未申请 1审核中 2已开通 3 审核未通过
105 let openStatus = result[0]; 61 let openStatus = result[0];
106 let installmentOnly = { 62 let installmentOnly = {
107 title: { 63 title: {
@@ -114,22 +70,32 @@ const index = (req, res) => { @@ -114,22 +70,32 @@ const index = (req, res) => {
114 }; 70 };
115 71
116 if (openStatus === '0') { 72 if (openStatus === '0') {
117 - return installmentModel.getResources().then(data => {  
118 - if (data[0] && data[0].data[0]) {  
119 - data[0].data[0].url = 'javascript:void(0)'; //eslint-disable-line  
120 - } 73 + return Promise.all([installmentModel.getResources('openN'), installmentModel.getNotices()]).then(data => {
  74 + _.forEach(data[0], (item) => {
  75 + if (item.singleOne) {
  76 + item.data[0].url = 'javascript:void(0)'; //eslint-disable-line
  77 + }
  78 + });
121 79
122 return { 80 return {
123 - bannerTop: data, 81 + content: data[0],
  82 + notice: data[1],
124 notOpen: true, 83 notOpen: true,
125 installmentOnly: installmentOnly 84 installmentOnly: installmentOnly
126 }; 85 };
127 }); 86 });
128 } else if (openStatus === '2') { 87 } else if (openStatus === '2') {
129 - return Promise.all([installmentModel.getQueryCreditInfo(uid), installmentModel.getQueryAmtInfo(uid)]).then((data) => { //eslint-disable-line 88 + return Promise.all([
  89 + installmentModel.getQueryCreditInfo(uid),
  90 + installmentModel.getQueryAmtInfo(uid),
  91 + installmentModel.getResources('openY'),
  92 + installmentModel.getNotices()
  93 + ]).then((data) => {
130 let params = _.assign({ 94 let params = _.assign({
131 isOverdue: false, 95 isOverdue: false,
132 - installmentOnly: installmentOnly 96 + installmentOnly: installmentOnly,
  97 + content: data[2],
  98 + notice: data[3]
133 }, data[0], data[1]); 99 }, data[0], data[1]);
134 100
135 // status: 1 正常 2 逾期 3 不可用 4 未开通 101 // status: 1 正常 2 逾期 3 不可用 4 未开通
@@ -144,8 +110,14 @@ const index = (req, res) => { @@ -144,8 +110,14 @@ const index = (req, res) => {
144 }); 110 });
145 } else if (openStatus === '1' || openStatus === '3' || openStatus === '4' || openStatus === '5') { 111 } else if (openStatus === '1' || openStatus === '3' || openStatus === '4' || openStatus === '5') {
146 res.redirect('/home/installment/review?status=' + openStatus); 112 res.redirect('/home/installment/review?status=' + openStatus);
  113 +
  114 + return false;
147 } 115 }
148 }).then((result) => { 116 }).then((result) => {
  117 + if (!result) {
  118 + return;
  119 + }
  120 +
149 res.render('installment/open-index', _.assign({ 121 res.render('installment/open-index', _.assign({
150 module: 'home', 122 module: 'home',
151 page: 'installment', 123 page: 'installment',
@@ -194,13 +166,67 @@ const review = (req, res) => { @@ -194,13 +166,67 @@ const review = (req, res) => {
194 page: 'installment', 166 page: 'installment',
195 title: '有货分期' 167 title: '有货分期'
196 }; 168 };
  169 + let templete = 'installment/open-result';
  170 + let jumpUrl = helpers.appUrlFormat('/product/new', 'go.new');
  171 + let params = {};
  172 +
  173 + if (openStatus === '2') {
  174 + Promise.all([
  175 + installmentModel.getSearchIntallment({
  176 + page: 1
  177 + }),
  178 + installmentModel.getQueryCreditInfo(uid),
  179 + installmentModel.getResources('advertisement')
  180 + ]).then((result) => {
  181 + res.render(templete, _.assign({
  182 + success: {
  183 + price: result[1].currCreditLimit,
  184 + installmentOnly: {
  185 + title: {
  186 + title: '分期专享',
  187 + more_url: helpers.appUrlFormat(req.originalUrl, 'go.instalmentlist', {
  188 + title: '分期专享'
  189 + })
  190 + },
  191 + goods: result[0]
  192 + },
  193 + advertisement: result[2][0].data[0],
  194 + url: helpers.appUrlFormat(req.originalUrl, 'go.instalmentlist', {
  195 + title: '分期专享'
  196 + })
  197 + }
  198 + }, data));
  199 + }).catch(() => {
  200 + _serverCrash(res, {
  201 + url: req.originalUrl
  202 + });
  203 + });
197 204
198 - if (openStatus !== '2') {  
199 - res.render('installment/open-result', _.assign(data, _reviewStatus(res, req, uid, openStatus)));  
200 } else { 205 } else {
201 - _reviewStatus(res, req, uid, openStatus).then((params) => {  
202 - res.render('installment/open-result', _.assign(data, params));  
203 - }); 206 + if (openStatus === '1') {
  207 + params = {
  208 + review: {
  209 + url: jumpUrl
  210 + }
  211 + };
  212 + } else if (openStatus === '3') {
  213 + params = {
  214 + error: true,
  215 + failReason: req.query.failReason || '姓名、身份证、银行卡不匹配'
  216 + };
  217 + } else if (openStatus === '4') {
  218 + params = {
  219 + cancel: {
  220 + url: jumpUrl
  221 + }
  222 + };
  223 + } else if (openStatus === '5') {
  224 + params = {
  225 + error: true,
  226 + failReason: '您的授信未通过,在有货更多的消费,增加信用度,会大大提升审核通过率奥。'
  227 + };
  228 + }
  229 + res.render(templete, _.assign(params, data));
204 } 230 }
205 }; 231 };
206 232
@@ -258,7 +284,7 @@ const repayRecordPage = (req, res) => { @@ -258,7 +284,7 @@ const repayRecordPage = (req, res) => {
258 // ajax 请求还款记录 284 // ajax 请求还款记录
259 const getRepayRecord = (req, res) => { 285 const getRepayRecord = (req, res) => {
260 let params = _.assign({ 286 let params = _.assign({
261 - uid: req.cookies.installmentUid || 1, 287 + uid: req.cookies.installmentUid,
262 pageNo: req.query.page || 1 288 pageNo: req.query.page || 1
263 }); 289 });
264 290
@@ -281,23 +307,38 @@ const getRepayRecord = (req, res) => { @@ -281,23 +307,38 @@ const getRepayRecord = (req, res) => {
281 307
282 // 账号管理 308 // 账号管理
283 const account = (req, res) => { 309 const account = (req, res) => {
  310 + var url = req.yoho.isApp || req.cookies.appVersion ? '/home/installment/account' : '/home/installment/bank-card';
  311 + if (req.cookies.appVersion) {
  312 + var versions = req.cookies.appVersion.split('.');
  313 + if (versions.length >= 2) {
  314 + if (versions[0] < 5 || (parseInt(versions[0], 10)===5 && versions[1] <= 1)) {
  315 +
  316 + } else {
  317 + url = helpers.appUrlFormat(url, 'go.instalmentMyCard')
  318 + }
  319 + }
  320 + }
284 res.render('installment/account', { 321 res.render('installment/account', {
285 module: 'home', 322 module: 'home',
286 page: 'account', 323 page: 'account',
287 title: '账号管理', 324 title: '账号管理',
288 isInstallmentPage: true, 325 isInstallmentPage: true,
289 - posId: 7 326 + posId: 7,
  327 + url: url
290 }); 328 });
291 }; 329 };
292 330
293 // 添加新银行卡 331 // 添加新银行卡
294 const bindCard = (req, res) => { 332 const bindCard = (req, res) => {
  333 + const banks = _banksInit();
  334 +
295 res.render('installment/bind-card', { 335 res.render('installment/bind-card', {
296 module: 'home', 336 module: 'home',
297 page: 'bind-card', 337 page: 'bind-card',
298 - title: '使用新卡还款', 338 + title: req.query.title || '使用新卡还款',
299 bindCard: { 339 bindCard: {
300 - userName: req.query.name 340 + userName: req.query.name,
  341 + banks: banks.join('、')
301 }, 342 },
302 isInstallmentPage: true 343 isInstallmentPage: true
303 }); 344 });
@@ -320,12 +361,7 @@ const postAccount = (req, res) => { @@ -320,12 +361,7 @@ const postAccount = (req, res) => {
320 }; 361 };
321 362
322 const startingService = (req, res) => { 363 const startingService = (req, res) => {
323 - const banks = ['农业银行', '中国银行', '工商银行', '建设银行', '光大银行', '兴业银行', '邮储银行', '民生银行', '中信银行', '广发银行'];  
324 -  
325 - if (new Date() >= new Date('2016-10-18 00:00:00')) {  
326 - // 2016年10月12日至17日 平安银行业务暂停(平安银行期间不支持服务)  
327 - banks.push('平安银行');  
328 - } 364 + const banks = _banksInit();
329 365
330 res.render('installment/starting-service', { 366 res.render('installment/starting-service', {
331 module: 'home', 367 module: 'home',
@@ -354,7 +390,7 @@ function getRealIP(req) { @@ -354,7 +390,7 @@ function getRealIP(req) {
354 const activateService = (req, res) => { 390 const activateService = (req, res) => {
355 391
356 installmentModel.activateService({ 392 installmentModel.activateService({
357 - uid: req.cookies.installmentUid || 532892, 393 + uid: req.cookies.installmentUid,
358 userName: req.body.userName, 394 userName: req.body.userName,
359 identityCardNo: req.body.identityCardNo, 395 identityCardNo: req.body.identityCardNo,
360 cardNo: req.body.cardNo, 396 cardNo: req.body.cardNo,
@@ -378,7 +414,7 @@ const activateService = (req, res) => { @@ -378,7 +414,7 @@ const activateService = (req, res) => {
378 const getBankInfo = (req, res) => { 414 const getBankInfo = (req, res) => {
379 installmentModel.getBankInfo({ 415 installmentModel.getBankInfo({
380 cardNo: req.query.cardNo, 416 cardNo: req.query.cardNo,
381 - uid: req.cookies.installmentUid || 512579468 // TODO: fix uid 417 + uid: req.cookies.installmentUid
382 }).then((result)=> { 418 }).then((result)=> {
383 res.json(result); 419 res.json(result);
384 }).catch(() => { 420 }).catch(() => {
@@ -411,7 +447,7 @@ const orderIndex = (req, res) => { @@ -411,7 +447,7 @@ const orderIndex = (req, res) => {
411 447
412 const orderList = (req, res) => { 448 const orderList = (req, res) => {
413 const params = { 449 const params = {
414 - uid: req.cookies.installmentUid || 8041876, // TODO: fix me 450 + uid: req.cookies.installmentUid,
415 type: req.query.type || 1, 451 type: req.query.type || 1,
416 page: req.query.page || 1, 452 page: req.query.page || 1,
417 limit: req.query.limit || 10 453 limit: req.query.limit || 10
@@ -447,7 +483,7 @@ const orderList = (req, res) => { @@ -447,7 +483,7 @@ const orderList = (req, res) => {
447 483
448 const orderDetail = (req, res) => { 484 const orderDetail = (req, res) => {
449 const params = { 485 const params = {
450 - uid: req.cookies.installmentUid || 8041876, // TODO: fix me 486 + uid: req.cookies.installmentUid,
451 orderCode: req.params.id 487 orderCode: req.params.id
452 }; 488 };
453 489
@@ -490,7 +526,9 @@ const orderDetail = (req, res) => { @@ -490,7 +526,9 @@ const orderDetail = (req, res) => {
490 navBtn: false, 526 navBtn: false,
491 currAmtCount: 0, 527 currAmtCount: 0,
492 currFeeCount: 0, 528 currFeeCount: 0,
493 - isCurrFee: true, 529 + isInstallmentPage: true,
  530 + isCurrFee: true
  531 + }, {
494 helpers: { 532 helpers: {
495 isPaymentComplete: function(status, options) { 533 isPaymentComplete: function(status, options) {
496 if (status === 2 || status === 4 || status === 5) { // 已结清/已取消 534 if (status === 2 || status === 4 || status === 5) { // 已结清/已取消
@@ -539,7 +577,7 @@ const orderDetail = (req, res) => { @@ -539,7 +577,7 @@ const orderDetail = (req, res) => {
539 // 还款详情 577 // 还款详情
540 const repayDetail = (req, res) => { 578 const repayDetail = (req, res) => {
541 let params = { 579 let params = {
542 - uid: req.cookies.installmentUid || 512579468, 580 + uid: req.cookies.installmentUid,
543 rePayNo: req.query.id || '', 581 rePayNo: req.query.id || '',
544 pageNo: 1 582 pageNo: 1
545 }; 583 };
@@ -601,13 +639,16 @@ const serverCrash = (req, res) => { @@ -601,13 +639,16 @@ const serverCrash = (req, res) => {
601 639
602 // 银行卡列表 640 // 银行卡列表
603 const bankCard = (req, res) => { 641 const bankCard = (req, res) => {
604 - let uid = req.cookies.installmentUid || 512579468; 642 + let uid = req.cookies.installmentUid;
605 643
606 installmentModel.getBankCards(uid).then((result) => { 644 installmentModel.getBankCards(uid).then((result) => {
607 res.render('installment/bank-card', { 645 res.render('installment/bank-card', {
  646 + module: 'home',
  647 + page: 'bank-card',
608 title: '我的银行卡', 648 title: '我的银行卡',
609 isInstallmentPage: true, 649 isInstallmentPage: true,
610 - accountList: result 650 + accountList: result,
  651 + userName: result[0].userName
611 }); 652 });
612 }).catch(() => { 653 }).catch(() => {
613 _serverCrash(res, { 654 _serverCrash(res, {
@@ -617,6 +658,62 @@ const bankCard = (req, res) => { @@ -617,6 +658,62 @@ const bankCard = (req, res) => {
617 }); 658 });
618 }; 659 };
619 660
  661 +// 银行卡详情
  662 +const cardDetail = (req, res) => {
  663 + let uid = req.cookies.installmentUid;
  664 + let cardIdNo = req.query.cardIdNo;
  665 +
  666 + installmentModel.getCardDetail(uid, cardIdNo).then((result) => {
  667 + res.render('installment/card-detail', {
  668 + module: 'home',
  669 + page: 'card-detail',
  670 + title: '银行卡详情',
  671 + isInstallmentPage: true,
  672 + width750: true,
  673 + cardDetail: result
  674 + });
  675 + }).catch(() => {
  676 + _serverCrash(res, {
  677 + url: req.originalUrl,
  678 + title: '银行卡详情'
  679 + });
  680 + });
  681 +};
  682 +
  683 +// 删除绑定
  684 +const delBankCard = (req, res) => {
  685 + let params = {
  686 + uid: req.cookies.installmentUid,
  687 + cardIdNo: req.query.cardIdNo
  688 + };
  689 +
  690 + installmentModel.delBankCard(params).then((result) => {
  691 + res.json(result);
  692 + }).catch(() => {
  693 + _serverCrash(res, {
  694 + url: req.originalUrl,
  695 + title: '银行卡详情'
  696 + });
  697 + });
  698 +};
  699 +
  700 +// 切换银行卡绑定
  701 +const setMasterCard = (req, res) => {
  702 + let params = {
  703 + uid: req.cookies.installmentUid,
  704 + cardIdNo: req.query.cardIdNo
  705 + };
  706 +
  707 + installmentModel.setMasterCard(params).then((result) => {
  708 + res.json(result);
  709 + }).catch(() => {
  710 + _serverCrash(res, {
  711 + url: req.originalUrl,
  712 + title: '银行卡详情'
  713 + });
  714 + });
  715 +};
  716 +
620 module.exports = { 717 module.exports = {
621 index, 718 index,
622 review, 719 review,
@@ -643,5 +740,8 @@ module.exports = { @@ -643,5 +740,8 @@ module.exports = {
643 bindCard, 740 bindCard,
644 serverCrash, 741 serverCrash,
645 bankCard, 742 bankCard,
646 - postAccount 743 + postAccount,
  744 + cardDetail,
  745 + delBankCard,
  746 + setMasterCard
647 }; 747 };
@@ -4,13 +4,19 @@ const model = require('../models/myqrcode'), @@ -4,13 +4,19 @@ const model = require('../models/myqrcode'),
4 headerModel = require('../../../doraemon/models/header'); // 头部model 4 headerModel = require('../../../doraemon/models/header'); // 头部model
5 5
6 exports.index = (req, res, next) => { 6 exports.index = (req, res, next) => {
7 - let params = req.query; 7 + let params = req.query,
  8 + esc = false,
  9 + appversion = req.query.app_version;
  10 +
  11 + if (Number(appversion.substr(0, 1) < 5) || (Number(appversion.substr(0, 1)) === 5 && Number(appversion.substr(2, 1)) < 2)) {
  12 + esc = true;
  13 + }
8 14
9 model.getQr({ 15 model.getQr({
10 token: params.token, 16 token: params.token,
11 }).then(result => { 17 }).then(result => {
12 params.token = result; 18 params.token = result;
13 - params.uname = decodeURIComponent(params.uname); 19 + params.uname = esc ? decodeURIComponent(params.uname) : decodeURIComponent(params.uname.replace(/\%/g, escape('%')));
14 params.icon = params.icon || 'https://img11.static.yhbimg.com/yhb-img01/2016/07/05/13/017ec560b82c132ab2fdb22f7cf6f42b83.png?imageView/2/w/{width}/h/{height}'; 20 params.icon = params.icon || 'https://img11.static.yhbimg.com/yhb-img01/2016/07/05/13/017ec560b82c132ab2fdb22f7cf6f42b83.png?imageView/2/w/{width}/h/{height}';
15 res.render('myqrcode', { 21 res.render('myqrcode', {
16 title: '查看二维码', 22 title: '查看二维码',
@@ -14,15 +14,13 @@ const orderDetailData = (req, res, next) => { @@ -14,15 +14,13 @@ const orderDetailData = (req, res, next) => {
14 let orderCode = req.query.order_code; 14 let orderCode = req.query.order_code;
15 15
16 orderDetailModel.orderDetailData(uid, orderCode).then(result => { 16 orderDetailModel.orderDetailData(uid, orderCode).then(result => {
17 - 17 + result.serviceUrl = 'http://chat8.live800.com/live800/chatClient/chatbox.jsp?companyID=620092&configID=149091&jid=8732423409&info=';
18 res.render('orderDetail', { 18 res.render('orderDetail', {
19 module: 'home', 19 module: 'home',
20 page: 'order-detail', 20 page: 'order-detail',
21 pageHeader: headerModel.setNav({ 21 pageHeader: headerModel.setNav({
22 navTitle: '订单详情', 22 navTitle: '订单详情',
23 - navBtn: false,  
24 - orderDetail: true,  
25 - serviceUrl: 'http://chat8.live800.com/live800/chatClient/chatbox.jsp?companyID=620092&configID=149091&jid=8732423409&info=', 23 + navBtn: false
26 }), 24 }),
27 title: '订单详情', 25 title: '订单详情',
28 pageFooter: true, 26 pageFooter: true,
@@ -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',
@@ -84,7 +84,9 @@ const _getAddressData = (params) => { @@ -84,7 +84,9 @@ const _getAddressData = (params) => {
84 return api.get('', { 84 return api.get('', {
85 method: 'app.address.gethidden', 85 method: 'app.address.gethidden',
86 uid: params.uid 86 uid: params.uid
87 - }, {code: 200}); 87 + }, {
  88 + code: 200
  89 + });
88 } else { 90 } else {
89 return false; 91 return false;
90 } 92 }
@@ -98,7 +100,6 @@ const _getAddressData = (params) => { @@ -98,7 +100,6 @@ const _getAddressData = (params) => {
98 const index = (params) => { 100 const index = (params) => {
99 let finalResult = { 101 let finalResult = {
100 myIndexPage: true, 102 myIndexPage: true,
101 - showDownloadApp: true,  
102 navHome: true, 103 navHome: true,
103 pageFooter: true, 104 pageFooter: true,
104 refundExchangeNum: 0, 105 refundExchangeNum: 0,
@@ -452,5 +453,6 @@ module.exports = { @@ -452,5 +453,6 @@ module.exports = {
452 recordContent, 453 recordContent,
453 delRecord, 454 delRecord,
454 getGrade, 455 getGrade,
455 - getPreferential 456 + getPreferential,
  457 + getGradeGrade,
456 }; 458 };
@@ -13,6 +13,11 @@ const api = global.yoho.API; @@ -13,6 +13,11 @@ const api = global.yoho.API;
13 const serviceAPI = global.yoho.ServiceAPI; 13 const serviceAPI = global.yoho.ServiceAPI;
14 const logger = global.yoho.logger; 14 const logger = global.yoho.logger;
15 const API_TIMEOUT = 10000; 15 const API_TIMEOUT = 10000;
  16 +const codeContent = {
  17 + openN: '0876085ff46bed27f1a1eb6ee8b68987',
  18 + openY: 'c233ad4ca91fef45ed7d0b26d9953e61',
  19 + advertisement: 'f3fe0793a7d59479542a14b15359c47d'
  20 +};
16 21
17 // 处理还款列表数据 22 // 处理还款列表数据
18 const _processAmtList = (listData, queryDays) => { 23 const _processAmtList = (listData, queryDays) => {
@@ -145,19 +150,7 @@ const _processBankCards = (list) => { @@ -145,19 +150,7 @@ const _processBankCards = (list) => {
145 list = list || []; 150 list = list || [];
146 151
147 _.forEach(list, (data) => { 152 _.forEach(list, (data) => {
148 - // let newCardNo = data.cardNo.split('');  
149 - // let cardNo = newCardNo.length;  
150 - // data.cardNo = '';  
151 - //  
152 - //  
153 - // for (let i = 1; i < cardNo; i++) {  
154 - // if (i < (cardNo - 4)) {  
155 - // data.cardNo += '*';  
156 - // } else {  
157 - // data.cardNo += newCardNo[i - 1];  
158 - // }  
159 - // }  
160 - 153 + data.url = '/home/installment/card-detail?cardIdNo=' + data.cardIdNo;
161 154
162 // 正则替换卡号,保留后4位 155 // 正则替换卡号,保留后4位
163 data.cardNo = data.cardNo.replace(/(\d+)(\d{4})$/, function(a, b, c) { 156 data.cardNo = data.cardNo.replace(/(\d+)(\d{4})$/, function(a, b, c) {
@@ -169,13 +162,24 @@ const _processBankCards = (list) => { @@ -169,13 +162,24 @@ const _processBankCards = (list) => {
169 return list; 162 return list;
170 }; 163 };
171 164
  165 +// 银行卡详情数据处理
  166 +const _processCardDetail = (list) => {
  167 + list = list || {};
  168 +
  169 + list.isMaster = list.masterType === '1' ? true : false;
  170 + list.cardNo = list.cardNo ? list.cardNo.replace(/\*/g, '') : list.cardNo;
  171 +
  172 + return list;
  173 +};
  174 +
172 /** 175 /**
173 * 获取资源位数据 176 * 获取资源位数据
174 * @return {[array]} 177 * @return {[array]}
175 */ 178 */
176 -const getResources = () => { 179 +const getResources = (code) => {
177 return serviceAPI.get('/operations/api/v5/resource/get', { 180 return serviceAPI.get('/operations/api/v5/resource/get', {
178 - content_code: '0876085ff46bed27f1a1eb6ee8b68987' 181 + content_code: codeContent[code],
  182 + platform: 'iphone'
179 }, { 183 }, {
180 cache: true 184 cache: true
181 }).then((result) => { 185 }).then((result) => {
@@ -481,6 +485,63 @@ const postAccount = (params) => { @@ -481,6 +485,63 @@ const postAccount = (params) => {
481 }); 485 });
482 }; 486 };
483 487
  488 +// 获取银行卡详情
  489 +const getCardDetail = (uid, cardIdNo) => {
  490 + return api.get('', {
  491 + method: 'user.instalment.getBankCardDetail',
  492 + uid: uid,
  493 + cardIdNo: cardIdNo
  494 + }, {
  495 + timeout: API_TIMEOUT
  496 + }).then((result) => {
  497 + if (result && result.code === 200) {
  498 + return _processCardDetail(result.data);
  499 + } else {
  500 + logger.error('get getBankCards data return code is not 200');
  501 + return Promise.reject(result);
  502 + }
  503 + });
  504 +};
  505 +
  506 +// 解除银行卡绑定
  507 +const delBankCard = (params) => {
  508 + return api.get('', _.assign({
  509 + method: 'user.instalment.unbindCard'
  510 + }, params)).then((res) => {
  511 + return res;
  512 + });
  513 +};
  514 +
  515 +// 切换银行卡主卡
  516 +const setMasterCard = (params) => {
  517 + return api.get('', _.assign({
  518 + method: 'user.instalment.toggleCard'
  519 + }, params)).then((res) => {
  520 + return res;
  521 + });
  522 +};
  523 +
  524 +// 公告
  525 +const getNotices = () => {
  526 + return api.get('', {
  527 + method: 'app.resources.getNotices',
  528 + position: 8,
  529 + client_type: 'iphone'
  530 + }, {
  531 + cache: true
  532 + }).then((res) => {
  533 + if (res && res.code === 200) {
  534 + if (res.data && res.data.list.length < 1) {
  535 + return false;
  536 + } else {
  537 + return res.data;
  538 + }
  539 + } else {
  540 + return false;
  541 + }
  542 + });
  543 +};
  544 +
484 module.exports = { 545 module.exports = {
485 getStauts, 546 getStauts,
486 getQueryCreditInfo, 547 getQueryCreditInfo,
@@ -497,5 +558,12 @@ module.exports = { @@ -497,5 +558,12 @@ module.exports = {
497 getInstallmentOrderDetail, 558 getInstallmentOrderDetail,
498 totalAmount, 559 totalAmount,
499 checkVerifyCode, 560 checkVerifyCode,
500 - postAccount 561 + postAccount,
  562 + getCardDetail,
  563 + delBankCard,
  564 + setMasterCard,
  565 + getNotices
501 }; 566 };
  567 +
  568 +
  569 +
@@ -9,8 +9,8 @@ exports.getQr = (params) => { @@ -9,8 +9,8 @@ exports.getQr = (params) => {
9 9
10 try { 10 try {
11 uid = crypto.decrypt(PASSWORD, decodeURIComponent(params.token)); 11 uid = crypto.decrypt(PASSWORD, decodeURIComponent(params.token));
  12 + uid = parseInt(uid, 10)
12 } catch (e) { 13 } catch (e) {
13 - console.error(e);  
14 uid = params.token; 14 uid = params.token;
15 } 15 }
16 16
@@ -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,
@@ -131,6 +131,9 @@ router.get('/installment/agreement', installment.agreement);// æœåŠ¡åè®®é™æ€ @@ -131,6 +131,9 @@ router.get('/installment/agreement', installment.agreement);// æœåŠ¡åè®®é™æ€
131 131
132 router.get('/installment/server-crash', installment.serverCrash); // 服务器崩溃 132 router.get('/installment/server-crash', installment.serverCrash); // 服务器崩溃
133 router.get('/installment/bank-card', installment.bankCard); // 银行卡列表 133 router.get('/installment/bank-card', installment.bankCard); // 银行卡列表
  134 +router.get('/installment/card-detail', installment.cardDetail); // 银行卡详情
  135 +router.get('/installment/delBankCard', installment.delBankCard); // 删除绑定
  136 +router.get('/installment/setMasterCard', installment.setMasterCard); // 切换主卡
134 137
135 router.get('/recommend-for-you/userCenter', recommendForYou.userCenter);// 为你优选 138 router.get('/recommend-for-you/userCenter', recommendForYou.userCenter);// 为你优选
136 139
@@ -130,8 +130,7 @@ @@ -130,8 +130,7 @@
130 {{#unless @root.wap.ucenter.removePrefer}} 130 {{#unless @root.wap.ucenter.removePrefer}}
131 {{> common/recommend-for-you}} 131 {{> common/recommend-for-you}}
132 {{/unless}} 132 {{/unless}}
133 - {{> common/suspend-cart}}  
134 </div> 133 </div>
135 134
136 -{{> download-app}} 135 +{{> footer-tab}}
137 136
1 <div class="account-page" data-pos-id="{{posId}}"> 1 <div class="account-page" data-pos-id="{{posId}}">
2 <ul class="account-list"> 2 <ul class="account-list">
3 - <li><a href="/home/installment/bank-card">我的银行卡:<div class="list-right"><span class="iconfont">&#xe604;</span></div></a></li> 3 + <li><a href="{{url}}">我的银行卡:<div class="list-right"><span class="iconfont">&#xe604;</span></div></a></li>
4 </ul> 4 </ul>
5 </div> 5 </div>
1 <div class="bank-card-page"> 1 <div class="bank-card-page">
2 - <ul class="bank-card-list"> 2 + <div class="bank-card-list" data-user="{{userName}}">
3 {{#accountList}} 3 {{#accountList}}
4 - <li class="card-bg-{{lowerCase bankCode}}"><span>{{cardNo}}</span></li> 4 + <a class="card-bg-{{lowerCase bankCode}} card-nav" href="{{url}}"><span>{{cardNo}}</span></a>
5 {{/accountList}} 5 {{/accountList}}
6 - </ul> 6 + </div>
7 </div> 7 </div>
@@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
8 <li> 8 <li>
9 <label>银行卡</label> 9 <label>银行卡</label>
10 <input id="cardNo" name="cardNo" type="tel" placeholder="请输入本人银行卡号" size="26" maxlength="23"> 10 <input id="cardNo" name="cardNo" type="tel" placeholder="请输入本人银行卡号" size="26" maxlength="23">
  11 + <span class="iconfont notice">&#xe639;</span>
11 </li> 12 </li>
12 <li id="bank-desc" style="display: none;"> 13 <li id="bank-desc" style="display: none;">
13 <div class="bank-info"> 14 <div class="bank-info">
@@ -20,8 +21,19 @@ @@ -20,8 +21,19 @@
20 <input type="number" placeholder="请输入银行预留手机号" id="mobile" name="mobile" pattern="\d*" maxlength="11"> 21 <input type="number" placeholder="请输入银行预留手机号" id="mobile" name="mobile" pattern="\d*" maxlength="11">
21 </li> 22 </li>
22 </ul> 23 </ul>
23 - <a href="" class="open-btn disabled">下一步</a> 24 + <div class="open-btn disabled">下一步</div>
24 <a href="" class="jumpResult">&nbsp;</a> 25 <a href="" class="jumpResult">&nbsp;</a>
  26 +
  27 + <div class="installment-overdue-notice">
  28 + <div class="mask-bg"></div>
  29 + <div class="notice-area">
  30 + <div class="notice-cont">
  31 + <h2>支持银行</h2>
  32 + <p>{{banks}}</p>
  33 + </div>
  34 + <div class="think-ok">我知道了</div>
  35 + </div>
  36 + </div>
25 {{/bindCard}} 37 {{/bindCard}}
26 38
27 <div class="success"> 39 <div class="success">
  1 +<div class="card-detail-page yoho-page">
  2 + {{#cardDetail}}
  3 + <div class="card-detail" data-card-id="{{cardIdNo}}">
  4 + <div class="card-icon card-icon-{{lowerCase bankCode}}"></div>
  5 + <div class="card-right">
  6 + <p class="bank-name">{{bankName}}</p>
  7 + <p class="card-no">储蓄卡 | 尾号{{cardNo}}</p>
  8 + </div>
  9 + </div>
  10 + <ul class="card-info">
  11 + <li><span class="txt-label">持卡人</span><span class="info-right card-user">{{userName}}</span></li>
  12 + <li><span class="txt-label">预留手机号</span><span class="info-right card-mobile">{{mobile}}</span></li>
  13 + <li>
  14 + <span class="txt-label">分期银行</span>
  15 + <span class="info-right card-bank">
  16 + {{#if isMaster}}
  17 + 主卡,用于支付验证和还款验证。
  18 + {{else}}
  19 + 副卡,仅用于还款验证。
  20 + {{/if}}
  21 + </span>
  22 + </li>
  23 + </ul>
  24 + <div class="tip-cont">
  25 + {{#if isMaster}}
  26 + <p>如果您更换银行预留手机号,请先新增其他还款银行卡,并将新增银行卡切换为主卡。然后解除绑定此卡,重新绑定即可。</p>
  27 + {{else}}
  28 + <p>如果您更换银行预留手机号,请先将银行卡解除绑定,再次重新绑定即可。</p>
  29 +
  30 + <div class="card-btn">
  31 + <span class="relieve-btn">解除绑定</span>
  32 + <span class="change-btn">切换为主卡</span>
  33 + </div>
  34 + {{/if}}
  35 + </div>
  36 + {{/cardDetail}}
  37 +</div>
@@ -140,7 +140,7 @@ @@ -140,7 +140,7 @@
140 <div class='help-group'> 140 <div class='help-group'>
141 <h2>五、服务支持</h2> 141 <h2>五、服务支持</h2>
142 <p> 142 <p>
143 - 如您在使用有货分期过程中遇到还款及资金安全方面问题您可联系信而富客服为,您进行相关处理和解答,联系电话:400-688-8692(工作日9:00-18:00),如您无法联系信而富客服您可联系有货客服,我们将在3个工作日内给您回复,感谢您的理解与支持! 143 + 如您在使用有货分期过程中遇到还款及资金安全方面问题,您可联系信而富客服为您进行相关处理和解答,联系电话:400-688-8692(工作日9:00-18:00),如您无法联系信而富客服您可联系有货客服,我们将在3个工作日内给您回复,感谢您的理解与支持!
144 </p> 144 </p>
145 </div> 145 </div>
146 </div> 146 </div>
1 <div class="installment-page installment-bg yoho-page"> 1 <div class="installment-page installment-bg yoho-page">
2 - {{#if notOpen}}  
3 - <input type="hidden" value="false" class="is-open">  
4 - {{# bannerTop}}  
5 - {{> resources/banner-top}}  
6 - {{/ bannerTop}}  
7 - <div class="open-index">  
8 - <ul class="open-info">  
9 - <li>  
10 - <span class="open-icon-1"></span>  
11 - <span>先消费<br>后还款</span>  
12 - </li>  
13 - <li>  
14 - <span class="open-icon-2"></span>  
15 - <span>30天免息<br>灵活分期</span>  
16 - </li>  
17 - <li>  
18 - <span class="open-icon-3"></span>  
19 - <span>指定商品<br>立享优惠</span>  
20 - </li>  
21 - </ul> 2 + <div class="loading-tip">下拉刷新</div>
  3 + <div class="installment-main">
  4 + <div class="main-content">
  5 + {{#if notOpen}}
  6 + <input type="hidden" value="false" class="is-open">
  7 + {{# content}}
  8 + {{#if singleImage}}
  9 + {{> resources/banner}}
  10 + {{/if}}
  11 + {{/ content}}
  12 + {{#notice}}
  13 + {{> installment/installment-notice}}
  14 + {{/notice}}
  15 + <div class="open-index">
  16 + <ul class="open-info">
  17 + <li>
  18 + <span class="open-icon-1"></span>
  19 + <span>先消费<br>后还款</span>
  20 + </li>
  21 + <li>
  22 + <span class="open-icon-2"></span>
  23 + <span>30天免息<br>灵活分期</span>
  24 + </li>
  25 + <li>
  26 + <span class="open-icon-3"></span>
  27 + <span>指定商品<br>立享优惠</span>
  28 + </li>
  29 + </ul>
22 30
23 - <a href="/home/installment/starting-service" class="open-btn">立即开通</a>  
24 - </div> 31 + <a href="/home/installment/starting-service" class="open-btn">立即开通</a>
  32 + </div>
25 33
26 - {{# installmentOnly}}  
27 - {{> installment/installment-only}}  
28 - {{/ installmentOnly}}  
29 - {{else}}  
30 - <input type="hidden" value="true" class="is-open">  
31 - <div class="detail-tab">  
32 - <span class="on is-repay">待还款金额</span>  
33 - <span class="is-usable">可用额度</span>  
34 - </div>  
35 - <div class="repay installment-cont">  
36 - <div class="repay-area detail-bg">  
37 - <p class="detail-txt1">近7日待还款</p>  
38 - <p class="detail-txt1">¥<span class="detail-txt2">{{dayAmt}}</span></p>  
39 - {{#if isOverdue}}  
40 - <p class="detail-txt3">您有¥{{overAmt}}已逾期,点击<a href="/home/installment/repay/overdue" class="nav-bit" data-id="1">查看详情</a></p>  
41 - {{/if}}  
42 - <a href="/home/installment/repay/7daylist" class="see-btn nav-bit" data-id="2">明细</a>  
43 - </div>  
44 - <ul class="group-list">  
45 - <li><a href="/home/installment/repay/month" class="nav-bit" data-id="3">本月待还金额:<div class="list-right"><span class="list-r-txt">¥{{monthAmt}}</span><span class="iconfont"> &#xe604;</span></div></a></li>  
46 - <li><a href="/home/installment/repay/total" class="nav-bit" data-id="4">待还总金额:<div class="list-right"><span class="list-r-txt">¥{{totalAmt}}</span><span class="iconfont"> &#xe604;</span></div></a></li>  
47 - <li><a href="/home/installment/repay/record" class="nav-bit" data-id="5">还款记录:<div class="list-right iconfont">&#xe604;</div></a></li>  
48 - <li><a href="/home/installment/order" class="nav-bit" data-id="6">分期订单:<div class="list-right iconfont">&#xe604;</div></a></li>  
49 - </ul> 34 + {{# installmentOnly}}
  35 + {{> installment/installment-only}}
  36 + {{/ installmentOnly}}
  37 + {{else}}
  38 + <input type="hidden" value="true" class="is-open">
  39 + <div class="detail-tab">
  40 + <span class="on is-repay">待还款金额</span>
  41 + <span class="is-usable">可用额度</span>
  42 + </div>
  43 + <div class="repay installment-cont">
  44 + <div class="repay-area detail-bg">
  45 + <p class="detail-txt1">近7日待还款</p>
  46 + <p class="detail-txt1">¥<span class="detail-txt2">{{dayAmt}}</span></p>
  47 + {{#if isOverdue}}
  48 + <p class="detail-txt3">您有¥{{overAmt}}已逾期,点击<a href="/home/installment/repay/overdue" class="nav-bit" data-id="1">查看详情</a></p>
  49 + {{/if}}
  50 + <a href="/home/installment/repay/7daylist" class="see-btn nav-bit" data-id="2">明细</a>
  51 + </div>
  52 + {{#notice}}
  53 + {{> installment/installment-notice}}
  54 + {{/notice}}
  55 + <ul class="group-list">
  56 + <li><a href="/home/installment/repay/month" class="nav-bit" data-id="3">本月待还金额:<div class="list-right"><span class="list-r-txt">¥{{monthAmt}}</span><span class="iconfont"> &#xe604;</span></div></a></li>
  57 + <li><a href="/home/installment/repay/total" class="nav-bit" data-id="4">待还总金额:<div class="list-right"><span class="list-r-txt">¥{{totalAmt}}</span><span class="iconfont"> &#xe604;</span></div></a></li>
  58 + <li><a href="/home/installment/repay/record" class="nav-bit" data-id="5">还款记录:<div class="list-right iconfont">&#xe604;</div></a></li>
  59 + <li><a href="/home/installment/order" class="nav-bit" data-id="6">分期订单:<div class="list-right iconfont">&#xe604;</div></a></li>
  60 + </ul>
50 61
51 - <ul class="group-list">  
52 - <li><a href="/home/installment/account" class="nav-bit" data-id="7">账户管理:<span class="list-right iconfont">&#xe604;</span></a></li>  
53 - </ul>  
54 - </div>  
55 - <div class="usable installment-cont">  
56 - <div class="usable-area detail-bg">  
57 - {{#replayStatus}}<div class="replay-status">{{.}}</div>{{/replayStatus}}  
58 - <p class="detail-txt1">可用额度</p>  
59 - <p class="detail-txt1">¥<span class="detail-txt2">{{currCreditLimit}}</span></p>  
60 - <p class="detail-txt1">总额度:¥{{initCreditLimit}}</p>  
61 - <a href="/home/installment/agreement" class="terms">服务条款</a>  
62 - </div>  
63 - {{# installmentOnly}}  
64 - {{> installment/installment-only}}  
65 - {{/ installmentOnly}} 62 + <ul class="group-list">
  63 + <li><a href="/home/installment/account" class="nav-bit" data-id="7">账户管理:<span class="list-right iconfont">&#xe604;</span></a></li>
  64 + </ul>
  65 + {{# content}}
  66 + {{#if singleImage}}
  67 + {{> installment/installment-banner}}
  68 + {{/if}}
  69 + {{/ content}}
  70 + </div>
  71 + <div class="usable installment-cont">
  72 + <div class="usable-area detail-bg">
  73 + {{#replayStatus}}<div class="replay-status">{{.}}</div>{{/replayStatus}}
  74 + <p class="detail-txt1">可用额度</p>
  75 + <p class="detail-txt1">¥<span class="detail-txt2">{{currCreditLimit}}</span></p>
  76 + <p class="detail-txt1">总额度:¥{{initCreditLimit}}</p>
  77 + <a href="/home/installment/agreement" class="terms">服务条款</a>
  78 + </div>
  79 + {{# installmentOnly}}
  80 + {{> installment/installment-only}}
  81 + {{/ installmentOnly}}
  82 + </div>
  83 + {{/if}}
66 </div> 84 </div>
67 - {{/if}} 85 + </div>
68 </div> 86 </div>
@@ -17,6 +17,15 @@ @@ -17,6 +17,15 @@
17 {{# installmentOnly}} 17 {{# installmentOnly}}
18 {{> installment/installment-only}} 18 {{> installment/installment-only}}
19 {{/ installmentOnly}} 19 {{/ installmentOnly}}
  20 + {{# advertisement}}
  21 + <div class="advertisement-area">
  22 + <div class="mask-bg"></div>
  23 + <a class="advertisement-box" href="{{url}}">
  24 + <i class="close-box"></i>
  25 + <div style="background-image: url('{{image src 540 550}}');" class="advertisement-img"></div>
  26 + </a>
  27 + </div>
  28 + {{/ advertisement}}
20 {{/ success}} 29 {{/ success}}
21 {{# error}} 30 {{# error}}
22 <div class="error"> 31 <div class="error">
@@ -80,7 +80,6 @@ @@ -80,7 +80,6 @@
80 </ul> 80 </ul>
81 </div> 81 </div>
82 {{/order}} 82 {{/order}}
83 -  
84 {{> installment/repayment-bottom}} 83 {{> installment/repayment-bottom}}
85 84
86 {{#isRefundedAll order.status}} 85 {{#isRefundedAll order.status}}
@@ -11,13 +11,12 @@ @@ -11,13 +11,12 @@
11 <div class="date-box">{{../create_time}}</div> 11 <div class="date-box">{{../create_time}}</div>
12 </div> 12 </div>
13 {{/order_goods}} 13 {{/order_goods}}
  14 + <div class="right-box">
  15 + <div class="amount">¥{{amount}}</div>
  16 + <div class="status">{{install_status}}</div>
  17 + </div>
  18 + <div class="clearfix"></div>
14 </a> 19 </a>
15 -  
16 - <div class="right-box">  
17 - <div class="amount">¥{{amount}}</div>  
18 - <div class="status">{{install_status}}</div>  
19 - </div>  
20 - <div class="clearfix"></div>  
21 </li> 20 </li>
22 {{/each}} 21 {{/each}}
23 {{/if}} 22 {{/if}}
1 <div class="repayment-list-page installment-order-page yoho-page" data-pos-id="{{posId}}"> 1 <div class="repayment-list-page installment-order-page yoho-page" data-pos-id="{{posId}}">
2 - {{> resources/banner-top}}  
3 <ul class="header-tab"> 2 <ul class="header-tab">
4 <li class="active"> 3 <li class="active">
5 <a href="/home/installment/order.html?type=1" data-type="1">全部</a> 4 <a href="/home/installment/order.html?type=1" data-type="1">全部</a>
1 <div class="installment-starting-service-page yoho-page"> 1 <div class="installment-starting-service-page yoho-page">
2 - {{> resources/banner-top}} 2 + {{!-- {{> resources/banner-top}} --}}
3 <div class="exclamation"> 3 <div class="exclamation">
4 基本信息的有效性决定您能否激活有货分期,以及最终可获得的额度! 4 基本信息的有效性决定您能否激活有货分期,以及最终可获得的额度!
5 </div> 5 </div>
@@ -15,7 +15,7 @@ @@ -15,7 +15,7 @@
15 <div class="field"> 15 <div class="field">
16 <label for="identityCardNo">身份证号:</label> 16 <label for="identityCardNo">身份证号:</label>
17 17
18 - <input id="identityCardNo" name="identityCardNo" type="text" placeholder="请填写身份证号" maxlength="18"/> 18 + <input id="identityCardNo" name="identityCardNo" type="tel" placeholder="请填写身份证号" maxlength="18"/>
19 <div class="clearfix"></div> 19 <div class="clearfix"></div>
20 </div> 20 </div>
21 21
@@ -55,10 +55,11 @@ @@ -55,10 +55,11 @@
55 <div class="agreements"> 55 <div class="agreements">
56 <input id="accept-agreements" name="agreements" type="checkbox" class="installment-check-btn" checked/> 56 <input id="accept-agreements" name="agreements" type="checkbox" class="installment-check-btn" checked/>
57 <label for="accept-agreements"> 57 <label for="accept-agreements">
58 - <div class="text-label">免费开通,详情请见  
59 - <a id="agreements" href="" data-href="/home/installment/agreement">《有货分期-信而富用户服务协议&借款服务协议》</a>  
60 - </div> 58 + &nbsp;
61 </label> 59 </label>
  60 + <div class="text-label">免费开通,详情请见
  61 + <a id="agreements" href="" data-href="/home/installment/agreement">《有货分期-信而富用户服务协议&借款服务协议》</a>
  62 + </div>
62 <div class="clearfix"></div> 63 <div class="clearfix"></div>
63 </div> 64 </div>
64 65
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 <ul id="order-nav" class="order-nav clearfix"> 3 <ul id="order-nav" class="order-nav clearfix">
4 {{#each navs}} 4 {{#each navs}}
5 <li class="tap-hightlight {{#if active}}active{{/if}}" data-type="{{typeId}}"> 5 <li class="tap-hightlight {{#if active}}active{{/if}}" data-type="{{typeId}}">
6 - <a href="{{url}}">{{name}}</a> 6 + <a class="nav-tap" data-url="{{url}}">{{name}}</a>
7 </li> 7 </li>
8 {{/each}} 8 {{/each}}
9 </ul> 9 </ul>
@@ -37,6 +37,7 @@ @@ -37,6 +37,7 @@
37 <span >订单状态:{{statusStr}}</span> 37 <span >订单状态:{{statusStr}}</span>
38 <span>下单时间:<b class="createTime">{{createTime}}</b></span> 38 <span>下单时间:<b class="createTime">{{createTime}}</b></span>
39 </p> 39 </p>
  40 + <a href="{{serviceUrl}}" target="_blank" class="iconfont icon-right">&#xe63c;</a>
40 </div> 41 </div>
41 {{#if logisticsUrl}} 42 {{#if logisticsUrl}}
42 <a class="logistics sub" href="{{logisticsUrl}}"> 43 <a class="logistics sub" href="{{logisticsUrl}}">
  1 +<div class="banner-center banner-center-swiper">
  2 + {{#if singleOne}}
  3 + {{#data}}
  4 + <div class="banner-list">
  5 + <a href="{{url}}">
  6 + <img src="{{image src 640 210}}" alt="">
  7 + </a>
  8 + </div>
  9 + {{/data}}
  10 + {{else}}
  11 + <ul class="banner-list swiper-wrapper clearfix">
  12 + {{#data}}
  13 + <li class="swiper-slide">
  14 + <a href="{{url}}">
  15 + <img src="{{image src 640 210}}" alt="">
  16 + </a>
  17 + </li>
  18 + {{/data}}
  19 + </ul>
  20 + {{/if}}
  21 + <div class="swiper-pagination">
  22 + <div class="pagination-inner">
  23 + </div>
  24 + </div>
  25 +</div>
  1 +<div class="notice-wrap clearfix">
  2 + <div class="notice" data-time="{{time}}">
  3 + <span class="notice-icon"></span>
  4 + <div class="swiper-wrapper">
  5 + {{#list}}
  6 + <a class="notice-item swiper-slide swiper-no-swiping item-{{@index}}" href="{{url}}">
  7 + {{title}}
  8 + </a>
  9 + {{/list}}
  10 + </div>
  11 + </div>
  12 +</div>
  1 +/**
  2 + * 服务条款
  3 + * @author: zxr<xiaoru.zhang@yoho.cn>
  4 + * @date: 2016/10/25
  5 + */
  6 +'use strict';
  7 +const headerModel = require('../../../doraemon/models/header'); // 头部model
  8 +
  9 +const privacy = (req, res) => {
  10 +
  11 + res.render('agreement/privacy', {
  12 + title: '隐私条款',
  13 + width750: true
  14 + });
  15 +};
  16 +
  17 +const newpower = (req, res) => {
  18 + let parameter = {};
  19 +
  20 + res.render('agreement/newpower', {
  21 + title: '关于新力传媒',
  22 + width750: true
  23 + });
  24 +};
  25 +
  26 +const aboutYoho = (req, res) => {
  27 +
  28 + res.render('agreement/yohobuy', {
  29 + title: '关于YOHO!BUY有货',
  30 + width750: true
  31 + });
  32 +};
  33 +
  34 +const agreement = (req, res) => {
  35 + let parameter = {};
  36 + let isApp = req.query.app_version || req.query.client_type || false;
  37 +
  38 + if (req.yoho.isApp) {
  39 + parameter = {
  40 + appVersion: '1'
  41 + };
  42 + } else {
  43 + parameter = {
  44 + pageHeader: headerModel.setNav({
  45 + navTitle: 'YOHO!BUY有货app服务条款'
  46 + }),
  47 + };
  48 + }
  49 +
  50 + res.render('agreement/agreement', Object.assign({
  51 + module: 'passport',
  52 + page: 'agreement',
  53 + title: 'YOHO!BUY有货app服务条款',
  54 + width750: true
  55 + }, parameter));
  56 +};
  57 +
  58 +module.exports = {
  59 + privacy,
  60 + newpower,
  61 + aboutYoho,
  62 + agreement
  63 +};
@@ -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,50 @@ const sign = global.yoho.sign; @@ -13,8 +13,50 @@ 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 + message: '页面失效'
  42 + });
  43 + } else {
  44 + return res.redirect('/reg.html');
  45 + }
  46 + }
16 47
  48 + return next();
  49 + };
  50 +};
  51 +
  52 +/**
  53 + * Step1: 输入手机号码 + 验证码
  54 + */
17 let index = (req, res) => { 55 let index = (req, res) => {
  56 + if (req.user.uid) {
  57 + return res.redirect(req.get('refer') || '/');
  58 + }
  59 +
18 // 设置注册有效时间30分钟, 防机器刷 60 // 设置注册有效时间30分钟, 防机器刷
19 // req.session.REG_EXPIRE = Date.now() + 1800000; 61 // req.session.REG_EXPIRE = Date.now() + 1800000;
20 let refer = req.query.refer; 62 let refer = req.query.refer;
@@ -23,17 +65,27 @@ let index = (req, res) => { @@ -23,17 +65,27 @@ let index = (req, res) => {
23 domain: 'yohobuy.com' 65 domain: 'yohobuy.com'
24 }); 66 });
25 67
  68 + // session init
  69 + _.set(req.session, 'phoneReg.step', 1);
  70 +
  71 + if (req.session.phoneReg.count == null) { // eslint-disable-line
  72 + req.session.phoneReg.count = 5;
  73 + }
  74 +
26 res.render('reg/index', { 75 res.render('reg/index', {
27 module: 'passport', 76 module: 'passport',
28 page: 'reg', 77 page: 'reg',
29 title: '注册', 78 title: '注册',
30 backUrl: 'javascript:history.go(-1)', // eslint-disable-line 79 backUrl: 'javascript:history.go(-1)', // eslint-disable-line
  80 + captchaUrl: helpers.urlFormat('/passport/reg/captcha.png', {t: Date.now()}),
31 headerText: '注册', // 头部信息 81 headerText: '注册', // 头部信息
32 isPassportPage: true, // 模板中模块标识 82 isPassportPage: true, // 模板中模块标识
33 areaCode: '+86', // 默认的区号 83 areaCode: '+86', // 默认的区号
34 countrys: RegService.getAreaData() // 地区信息列表 84 countrys: RegService.getAreaData() // 地区信息列表
35 }); 85 });
36 }; 86 };
  87 +
  88 +
37 let verifyMobile = (req, res, next) => { 89 let verifyMobile = (req, res, next) => {
38 let data = { 90 let data = {
39 code: 400, 91 code: 400,
@@ -43,6 +95,28 @@ let verifyMobile = (req, res, next) => { @@ -43,6 +95,28 @@ let verifyMobile = (req, res, next) => {
43 95
44 let mobile = +req.body.phoneNum; 96 let mobile = +req.body.phoneNum;
45 let area = +(req.body.areaCode || 86); 97 let area = +(req.body.areaCode || 86);
  98 + let captcha = (req.body.captcha || '').trim();
  99 + let diffCaptcha = _.get(req.session, 'phoneReg.captcha');
  100 +
  101 + // error case: 没有验证码
  102 + if (!diffCaptcha) {
  103 + return res.json({
  104 + code: 400,
  105 + message: '请求失败',
  106 + refreshCaptcha: true
  107 + });
  108 + }
  109 +
  110 + delete req.session.phoneReg.captcha; // captcha 一次性
  111 +
  112 + // error case: 验证码不匹配
  113 + if (captcha !== diffCaptcha) {
  114 + return res.json({
  115 + code: 400,
  116 + message: '校验码不正确',
  117 + refreshCaptcha: true
  118 + });
  119 + }
46 120
47 // 判断参数是否合法 121 // 判断参数是否合法
48 if (!_.isNumber(mobile) || !_.isNumber(area)) { 122 if (!_.isNumber(mobile) || !_.isNumber(area)) {
@@ -58,6 +132,7 @@ let verifyMobile = (req, res, next) => { @@ -58,6 +132,7 @@ let verifyMobile = (req, res, next) => {
58 // return res.json(data); 132 // return res.json(data);
59 // } 133 // }
60 134
  135 +
61 // 向手机发送注册验证码 136 // 向手机发送注册验证码
62 RegService.sendCodeToMobile(area, mobile).then((result) => { 137 RegService.sendCodeToMobile(area, mobile).then((result) => {
63 if (!result.code) { 138 if (!result.code) {
@@ -68,6 +143,14 @@ let verifyMobile = (req, res, next) => { @@ -68,6 +143,14 @@ let verifyMobile = (req, res, next) => {
68 if (result.code === 200) { 143 if (result.code === 200) {
69 let token = sign.makeToken(mobile); 144 let token = sign.makeToken(mobile);
70 145
  146 + _.set(req.session, 'phoneReg.step', 2); // go step 2
  147 + --req.session.phoneReg.count;
  148 +
  149 + // count is 0, will freeze;
  150 + if (!req.session.phoneReg.count) {
  151 + _.set(req.session, 'phoneReg.expire', Date.now() + 5 * 60 * 1000);
  152 + }
  153 +
71 result.data = helpers.urlFormat('/passport/reg/code', { 154 result.data = helpers.urlFormat('/passport/reg/code', {
72 token: token, 155 token: token,
73 phoneNum: mobile, 156 phoneNum: mobile,
@@ -78,6 +161,11 @@ let verifyMobile = (req, res, next) => { @@ -78,6 +161,11 @@ let verifyMobile = (req, res, next) => {
78 return res.json(result); 161 return res.json(result);
79 }).catch(next); 162 }).catch(next);
80 }; 163 };
  164 +
  165 +
  166 +/**
  167 + * Step2: 校验 手机验证码
  168 + */
81 let codeAction = (req, res, next) => { 169 let codeAction = (req, res, next) => {
82 let token = req.query.token; 170 let token = req.query.token;
83 let mobile = +req.query.phoneNum; 171 let mobile = +req.query.phoneNum;
@@ -94,7 +182,7 @@ let codeAction = (req, res, next) => { @@ -94,7 +182,7 @@ let codeAction = (req, res, next) => {
94 res.render('reg/code', { 182 res.render('reg/code', {
95 page: 'code', 183 page: 'code',
96 title: '注册-验证码', 184 title: '注册-验证码',
97 - backUrl: '/?go=1', // eslint-disable-line 185 + backUrl: '/?go=1', // eslint-disable-line
98 headerText: '注册', // 头部信息 186 headerText: '注册', // 头部信息
99 isPassportPage: true, // 模板中模块标识 187 isPassportPage: true, // 模板中模块标识
100 areaCode: area, // 默认的区号 188 areaCode: area, // 默认的区号
@@ -103,6 +191,36 @@ let codeAction = (req, res, next) => { @@ -103,6 +191,36 @@ let codeAction = (req, res, next) => {
103 serviceUrl: 'http://chat8.live800.com/live800/chatClient/chatbox.jsp?companyID=620092&configID=149091&jid=8732423409&info=' // 在线客服 191 serviceUrl: 'http://chat8.live800.com/live800/chatClient/chatbox.jsp?companyID=620092&configID=149091&jid=8732423409&info=' // 在线客服
104 }); 192 });
105 }; 193 };
  194 +
  195 +let sendCodeBusyBoy = (req, res, next) => {
  196 + let count = _.get(req.session, 'phoneReg.count');
  197 + let expire = _.get(req.session, 'phoneReg.expire');
  198 +
  199 + if (count) {
  200 + return next();
  201 + } else {
  202 +
  203 + /*
  204 + 如果 count === 0
  205 + 1. 没过解冻期
  206 + 2. 过了解冻期, count reset to 5
  207 + */
  208 + let now = Date.now();
  209 +
  210 + if (now > expire) {
  211 + _.set(req.session, 'phoneReg.count', 5);
  212 + return next();
  213 +
  214 + } else {
  215 + return res.json({
  216 + code: 400,
  217 + message: '发送次数太多, 5分钟稍后再试'
  218 + });
  219 + }
  220 +
  221 + }
  222 +};
  223 +
106 let sendCode = (req, res, next) => { 224 let sendCode = (req, res, next) => {
107 let data = { 225 let data = {
108 code: 400, 226 code: 400,
@@ -129,9 +247,22 @@ let sendCode = (req, res, next) => { @@ -129,9 +247,22 @@ let sendCode = (req, res, next) => {
129 247
130 // 向手机发送注册验证码 248 // 向手机发送注册验证码
131 RegService.sendCodeToMobile(area, mobile).then((result) => { 249 RegService.sendCodeToMobile(area, mobile).then((result) => {
132 - return result.code ? res.json(result) : res.json(data); 250 + let code = _.get(result, 'code');
  251 +
  252 + if (code) {
  253 + --req.session.phoneReg.count;
  254 +
  255 + // count is 0, will freeze;
  256 + if (!req.session.phoneReg.count) {
  257 + _.set(req.session, 'phoneReg.expire', Date.now() + 5 * 60 * 1000);
  258 + }
  259 + return res.json(result);
  260 + } else {
  261 + return res.json(data);
  262 + }
133 }).catch(next); 263 }).catch(next);
134 }; 264 };
  265 +
135 let verifyCode = (req, res, next) => { 266 let verifyCode = (req, res, next) => {
136 let data = { 267 let data = {
137 code: 400, 268 code: 400,
@@ -143,7 +274,7 @@ let verifyCode = (req, res, next) => { @@ -143,7 +274,7 @@ let verifyCode = (req, res, next) => {
143 let area = +(req.body.areaCode || 86); 274 let area = +(req.body.areaCode || 86);
144 let code = +req.body.code; 275 let code = +req.body.code;
145 276
146 - /* 判断参数是否合法 */ 277 + /* 判断参数是否合法 */
147 if (!_.isNumber(mobile) || !_.isNumber(area) || !_.isNumber(code)) { 278 if (!_.isNumber(mobile) || !_.isNumber(area) || !_.isNumber(code)) {
148 data.message = '手机号错误'; 279 data.message = '手机号错误';
149 return res.json(data); 280 return res.json(data);
@@ -163,46 +294,58 @@ let verifyCode = (req, res, next) => { @@ -163,46 +294,58 @@ let verifyCode = (req, res, next) => {
163 return res.json(data); 294 return res.json(data);
164 } 295 }
165 296
166 - // 返回跳转到设置密码的链接  
167 - if (result.code === 200) {  
168 - let token = sign.makeToken(mobile);  
169 -  
170 - result.data = helpers.urlFormat('/passport/reg/password', {  
171 - token: token,  
172 - phoneNum: mobile,  
173 - areaCode: area  
174 - });  
175 - } else if (result.code === 404) {  
176 - result.message = '验证码错误'; // 统一验证提示 297 + let resultCode = _.get(result, 'code');
  298 + let token = sign.makeToken(mobile);
  299 +
  300 + switch (resultCode) {
  301 + case 200:
  302 + _.set(req.session, 'phoneReg.step', 3); // go step 3
  303 + result.data = helpers.urlFormat('/passport/reg/password', {
  304 + token: token,
  305 + phoneNum: mobile,
  306 + areaCode: area,
  307 + smsCode: code
  308 + });
  309 + break;
  310 + case 404:
  311 + default:
  312 + result = data;
177 } 313 }
178 314
179 return res.json(result); 315 return res.json(result);
180 }).catch(next); 316 }).catch(next);
181 }; 317 };
  318 +
  319 +/**
  320 + * Step3: set Password
  321 + */
182 let passwordAction = (req, res, next) => { 322 let passwordAction = (req, res, next) => {
183 let token = req.query.token; 323 let token = req.query.token;
184 let mobile = +req.query.phoneNum; 324 let mobile = +req.query.phoneNum;
185 let area = +(req.query.areaCode || 86); 325 let area = +(req.query.areaCode || 86);
  326 + let smsCode = +req.query.smsCode;
186 327
187 // 判断是否允许访问, 不允许则跳转到错误页面 328 // 判断是否允许访问, 不允许则跳转到错误页面
188 - if (!_.isString(token) || !_.isNumber(mobile) || !_.isNumber(area) || !sign.verifyToken(mobile, token)) { 329 + if (!smsCode || !_.isString(token) || !_.isNumber(mobile) || !_.isNumber(area) || !sign.verifyToken(mobile, token)) {
189 return next({ 330 return next({
190 code: 403, 331 code: 403,
191 - message: 'error token or mobile' 332 + message: 'error token, mobile or verifyCode'
192 }); 333 });
193 } 334 }
194 335
195 res.render('reg/password', { 336 res.render('reg/password', {
196 page: 'password', 337 page: 'password',
197 title: '注册-设置密码', 338 title: '注册-设置密码',
198 - backUrl: '/?go=1', // eslint-disable-line 339 + backUrl: '/?go=1', // eslint-disable-line
199 headerText: '注册', // 头部信息 340 headerText: '注册', // 头部信息
200 isPassportPage: true, // 模板中模块标识 341 isPassportPage: true, // 模板中模块标识
201 areaCode: area, // 默认的区号 342 areaCode: area, // 默认的区号
202 phoneNum: mobile, // 手机号 343 phoneNum: mobile, // 手机号
203 - token: token // 访问令牌 344 + token: token, // 访问令牌
  345 + smsCode: smsCode // 手机验证码
204 }); 346 });
205 }; 347 };
  348 +
206 let setPassword = (req, res, next) => { 349 let setPassword = (req, res, next) => {
207 let data = { 350 let data = {
208 code: 400, 351 code: 400,
@@ -214,9 +357,10 @@ let setPassword = (req, res, next) => { @@ -214,9 +357,10 @@ let setPassword = (req, res, next) => {
214 let area = +(req.body.areaCode || 86); 357 let area = +(req.body.areaCode || 86);
215 let password = req.body.password; 358 let password = req.body.password;
216 let token = req.body.token; 359 let token = req.body.token;
  360 + let smsCode = +req.body.smsCode;
217 361
218 // 判断参数是否合法 362 // 判断参数是否合法
219 - if (!_.isString(token) || !_.isNumber(mobile) || !_.isNumber(area) || !password) { 363 + if (!smsCode || !_.isString(token) || !_.isNumber(mobile) || !_.isNumber(area) || !password) {
220 data.message = '请求参数不合法'; 364 data.message = '请求参数不合法';
221 return res.json(data); 365 return res.json(data);
222 } 366 }
@@ -228,7 +372,7 @@ let setPassword = (req, res, next) => { @@ -228,7 +372,7 @@ let setPassword = (req, res, next) => {
228 } 372 }
229 373
230 // 判断密码是否符合规则 374 // 判断密码是否符合规则
231 - if (!helpers.verifyPassword(password)) { 375 + if (!/^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,20}$/.test(password)) {
232 return res.json(data); 376 return res.json(data);
233 } 377 }
234 378
@@ -236,7 +380,7 @@ let setPassword = (req, res, next) => { @@ -236,7 +380,7 @@ let setPassword = (req, res, next) => {
236 let shoppingKey = cookie.getShoppingKey(req); 380 let shoppingKey = cookie.getShoppingKey(req);
237 381
238 // 验证注册的标识码是否有效 382 // 验证注册的标识码是否有效
239 - RegService.regMobileAes(area, mobile, password, shoppingKey).then((result) => { 383 + RegService.regMobileAes(area, mobile, password, shoppingKey, smsCode).then((result) => {
240 if (!result.code || result.code !== 200) { 384 if (!result.code || result.code !== 200) {
241 return Promise.reject(result); 385 return Promise.reject(result);
242 } 386 }
@@ -258,6 +402,8 @@ let setPassword = (req, res, next) => { @@ -258,6 +402,8 @@ let setPassword = (req, res, next) => {
258 refer = '/home'; 402 refer = '/home';
259 } 403 }
260 404
  405 + delete req.session.phoneNum;
  406 +
261 return res.json({ 407 return res.json({
262 code: 200, 408 code: 200,
263 message: '注册成功', 409 message: '注册成功',
@@ -269,12 +415,29 @@ let setPassword = (req, res, next) => { @@ -269,12 +415,29 @@ let setPassword = (req, res, next) => {
269 }).catch(next); 415 }).catch(next);
270 }; 416 };
271 417
  418 +/**
  419 + * 生成 校验码
  420 + */
  421 +const genCaptcha = (req, res) => {
  422 + let captcha = captchaService.generateCaptcha(90, 52, 4);
  423 +
  424 + _.set(req.session, 'phoneReg.captcha', captcha.text);
  425 +
  426 + res.type('png')
  427 + .set('Cache-Control', 'no-cache')
  428 + .status(200)
  429 + .send(captcha.image);
  430 +};
  431 +
272 module.exports = { 432 module.exports = {
  433 + guardStep,
  434 + sendCodeBusyBoy,
273 index, 435 index,
274 verifyMobile, 436 verifyMobile,
275 code: codeAction, 437 code: codeAction,
276 sendCode, 438 sendCode,
277 verifyCode, 439 verifyCode,
278 password: passwordAction, 440 password: passwordAction,
279 - setPassword 441 + setPassword,
  442 + genCaptcha
280 }; 443 };
1 /* eslint no-unused-vars: ["error", { "args": "none" }] */ 1 /* eslint no-unused-vars: ["error", { "args": "none" }] */
2 'use strict'; 2 'use strict';
  3 +const _ = require('lodash');
3 const helpers = global.yoho.helpers; 4 const helpers = global.yoho.helpers;
4 const cookie = global.yoho.cookie; 5 const cookie = global.yoho.cookie;
5 const RegService = require('../models/reg-service'); 6 const RegService = require('../models/reg-service');
6 const PhoneService = require('../models/phone-service'); 7 const PhoneService = require('../models/phone-service');
7 const AuthHelper = require('../models/auth-helper'); 8 const AuthHelper = require('../models/auth-helper');
  9 +const captchaService = require('../models/captcha-service');
8 10
9 // constrant 11 // constrant
10 const CODE_REQUIRED = '请输入校验码'; 12 const CODE_REQUIRED = '请输入校验码';
@@ -23,7 +25,7 @@ exports.beforeIn = (req, res, next) => { @@ -23,7 +25,7 @@ exports.beforeIn = (req, res, next) => {
23 }); 25 });
24 26
25 if (!req.xhr && req.user.uid) { 27 if (!req.xhr && req.user.uid) {
26 - return res.redirect(req.cookies.refer); 28 + return res.redirect(req.cookies.refer || '/');
27 } 29 }
28 30
29 next(); 31 next();
@@ -31,6 +33,12 @@ exports.beforeIn = (req, res, next) => { @@ -31,6 +33,12 @@ exports.beforeIn = (req, res, next) => {
31 33
32 // 短信登录 第一步: 展现页面 34 // 短信登录 第一步: 展现页面
33 const _step1 = (req, res, next) => { 35 const _step1 = (req, res, next) => {
  36 + _.set(req.session, 'smsLogin.step', 1);
  37 +
  38 + if (req.session.smsLogin.count == null) { // eslint-disable-line
  39 + req.session.smsLogin.count = 5;
  40 + }
  41 +
34 let template = 'sms/login'; 42 let template = 'sms/login';
35 let viewData = { 43 let viewData = {
36 module: 'passport', 44 module: 'passport',
@@ -38,6 +46,7 @@ const _step1 = (req, res, next) => { @@ -38,6 +46,7 @@ const _step1 = (req, res, next) => {
38 title: '手机短信登录', 46 title: '手机短信登录',
39 isPassportPage: true, 47 isPassportPage: true,
40 headerText: '手机号码快捷登录', 48 headerText: '手机号码快捷登录',
  49 + captchaUrl: helpers.urlFormat('/passport/sms_login/captcha.png', {t: Date.now()}),
41 areaCode: '+86', // 默认的区号 50 areaCode: '+86', // 默认的区号
42 countrys: RegService.getAreaData() // 地区信息列表 51 countrys: RegService.getAreaData() // 地区信息列表
43 }; 52 };
@@ -58,7 +67,7 @@ const _step2 = (req, res, next) => { @@ -58,7 +67,7 @@ const _step2 = (req, res, next) => {
58 title: '手机短信登录', 67 title: '手机短信登录',
59 isPassportPage: true, 68 isPassportPage: true,
60 headerText: '手机号码快捷登录', 69 headerText: '手机号码快捷登录',
61 - canResend: interval < Date.now(), 70 + countdown: Math.ceil((interval - Date.now()) / 1000),
62 mobile, 71 mobile,
63 area 72 area
64 }; 73 };
@@ -83,7 +92,7 @@ const _step3 = (req, res, next) => { @@ -83,7 +92,7 @@ const _step3 = (req, res, next) => {
83 // 短信 登录 92 // 短信 登录
84 exports.loginPage = (req, res, next) => { 93 exports.loginPage = (req, res, next) => {
85 let step = Number(req.query.step) || 1; 94 let step = Number(req.query.step) || 1;
86 - let smsLoginStep = req.session.smsLoginStep || 1; 95 + let smsLoginStep = _.get(req.session, 'smsLogin.step', 1);
87 96
88 if (step === 2 && smsLoginStep !== 2) { 97 if (step === 2 && smsLoginStep !== 2) {
89 return res.redirect(req.path); 98 return res.redirect(req.path);
@@ -109,23 +118,63 @@ exports.loginPage = (req, res, next) => { @@ -109,23 +118,63 @@ exports.loginPage = (req, res, next) => {
109 exports.tokenBefore = (req, res, next) => { 118 exports.tokenBefore = (req, res, next) => {
110 let area = req.query.area = (req.query.area || '').trim(); 119 let area = req.query.area = (req.query.area || '').trim();
111 let mobile = req.query.mobile = (req.query.mobile || '').trim(); 120 let mobile = req.query.mobile = (req.query.mobile || '').trim();
  121 + let step = _.get(req.session, 'smsLogin.step');
  122 + let count = _.get(req.session, 'smsLogin.count');
  123 + let interval = _.get(req.session, 'smsLogin.interval');
  124 + let captcha1 = _.get(req.session, 'smsLogin.captcha');
  125 + let captcha2 = (req.query.captcha || '').trim();
  126 +
112 127
113 if (!req.xhr) { 128 if (!req.xhr) {
114 return next(404); 129 return next(404);
115 } 130 }
116 131
117 - if (req.session.smsLogin && req.session.smsLogin.interval > Date.now()) { 132 + if ([area, mobile].some(val => val === '')) {
118 return res.json({ 133 return res.json({
119 - code: 429,  
120 - message: TOO_MANY 134 + code: 401,
  135 + message: '手机号 必填'
121 }); 136 });
122 } 137 }
123 138
  139 + delete req.session.smsLogin.captcha; // 图形验证码 一次性
124 140
125 - if ([area, mobile].some(val => val === '')) { 141 + // step1 要 校验图形验证码
  142 + if (step === 1) {
  143 + if (!captcha2) {
  144 + return res.json({
  145 + code: 400,
  146 + message: '请填写验证码'
  147 + });
  148 + }
  149 +
  150 + if (captcha1 !== captcha2) {
  151 + return res.json({
  152 + code: 400,
  153 + message: VERIFY_ERROR
  154 + });
  155 + }
  156 + }
  157 +
  158 + let now = Date.now();
  159 +
  160 + // 重发次数用完了, 回冻结5min
  161 + // 1. 过了冻结期, count 重设为 5次
  162 + // 2. 没过冻结期, end
  163 + // 没有用完, 判断是否请求太频繁
  164 + if (!count) {
  165 + if (interval > now) {
  166 + return res.json({
  167 + code: 400,
  168 + message: TOO_MANY,
  169 + during: Math.ceil((interval - now) / 1000)
  170 + });
  171 + } else {
  172 + _.set(req.session, 'smsLogin.count', 5);
  173 + }
  174 + } else if (interval > now) {
126 return res.json({ 175 return res.json({
127 - code: 401,  
128 - message: '请求参数,无法处理' 176 + code: 429,
  177 + message: TOO_MANY
129 }); 178 });
130 } 179 }
131 180
@@ -139,12 +188,18 @@ exports.token = (req, res, next) => { @@ -139,12 +188,18 @@ exports.token = (req, res, next) => {
139 188
140 PhoneService.sendSMS(mobile, area, 1).then(result => { 189 PhoneService.sendSMS(mobile, area, 1).then(result => {
141 if (result.code === 200) { 190 if (result.code === 200) {
142 - req.session.smsLogin = {  
143 - interval: Date.now() + 60 * 1000, // 重发验证码 间隔: 60s  
144 - area,  
145 - mobile  
146 - };  
147 - req.session.smsLoginStep = 2; // 进入短信登录 step2 191 +
  192 + _.set(req.session, 'smsLogin.step', 2);
  193 + _.set(req.session, 'smsLogin.area', area);
  194 + _.set(req.session, 'smsLogin.mobile', mobile);
  195 +
  196 + --req.session.smsLogin.count;
  197 +
  198 + if (!req.session.smsLogin.count) {
  199 + _.set(req.session, 'smsLogin.interval', Date.now() + 5 * 60 * 1000);
  200 + } else {
  201 + _.set(req.session, 'smsLogin.interval', Date.now() + 60 * 1000);
  202 + }
148 203
149 result.redirect = '/passport/sms_login?step=2'; 204 result.redirect = '/passport/sms_login?step=2';
150 res.json(result); 205 res.json(result);
@@ -157,8 +212,9 @@ exports.token = (req, res, next) => { @@ -157,8 +212,9 @@ exports.token = (req, res, next) => {
157 212
158 exports.checkBefore = (req, res, next) => { 213 exports.checkBefore = (req, res, next) => {
159 let code = req.query.code = (req.query.code || '').trim(); 214 let code = req.query.code = (req.query.code || '').trim();
  215 + let step = _.get(req.session, 'smsLogin.step');
160 216
161 - if (!req.xhr && req.session.smsLoginStep !== 2) { 217 + if (!req.xhr && step !== 2) {
162 return next(404); 218 return next(404);
163 } 219 }
164 220
@@ -214,11 +270,13 @@ exports.check = (req, res, next) => { @@ -214,11 +270,13 @@ exports.check = (req, res, next) => {
214 // 手机号码 没注册 270 // 手机号码 没注册
215 if (r1.data.is_register !== 'Y') { 271 if (r1.data.is_register !== 'Y') {
216 redirect = '/passport/sms_login?step=3'; 272 redirect = '/passport/sms_login?step=3';
217 - req.session.smsLoginStep = 3; 273 + _.set(req.session, 'smsLogin.step', 3);
218 274
219 res.json({ 275 res.json({
220 code: 200, 276 code: 200,
221 - redirect 277 + redirect,
  278 + newer: true,
  279 + registerCode: r1.data.code
222 }); 280 });
223 281
224 return; 282 return;
@@ -246,7 +304,6 @@ exports.check = (req, res, next) => { @@ -246,7 +304,6 @@ exports.check = (req, res, next) => {
246 }); 304 });
247 305
248 delete req.session.smsLogin; 306 delete req.session.smsLogin;
249 - delete req.session.smsLoginStep;  
250 }) 307 })
251 .catch(error => { 308 .catch(error => {
252 res.json(error); 309 res.json(error);
@@ -258,7 +315,9 @@ exports.check = (req, res, next) => { @@ -258,7 +315,9 @@ exports.check = (req, res, next) => {
258 315
259 // AJAX 短信登录 设置密码 in step3 316 // AJAX 短信登录 设置密码 in step3
260 exports.password = (req, res, next) => { 317 exports.password = (req, res, next) => {
261 - if (req.session.smsLoginStep !== 3) { 318 + let step = _.get(req.session, 'smsLogin.step');
  319 +
  320 + if (step !== 3) {
262 return next(); 321 return next();
263 } 322 }
264 323
@@ -268,10 +327,10 @@ exports.password = (req, res, next) => { @@ -268,10 +327,10 @@ exports.password = (req, res, next) => {
268 message: BAD_PASSWORD 327 message: BAD_PASSWORD
269 }; 328 };
270 329
271 - let smsLogin = req.session.smsLogin || {};  
272 - let mobile = smsLogin.mobile;  
273 - let area = smsLogin.area; 330 + let mobile = _.get(req.session, 'smsLogin.mobile');
  331 + let area = _.get(req.session, 'smsLogin.area');
274 let password = (req.body.password || '').trim(); 332 let password = (req.body.password || '').trim();
  333 + let registerCode = +req.body.registerCode || 0;
275 334
276 if (!password) { 335 if (!password) {
277 data.message = PASSWORD_REQUIRED; 336 data.message = PASSWORD_REQUIRED;
@@ -283,7 +342,7 @@ exports.password = (req, res, next) => { @@ -283,7 +342,7 @@ exports.password = (req, res, next) => {
283 return res.json(data); 342 return res.json(data);
284 } 343 }
285 344
286 - if (!helpers.verifyPassword(password)) { 345 + if (!/^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,20}$/.test(password)) {
287 return res.json(data); 346 return res.json(data);
288 } 347 }
289 348
@@ -291,7 +350,7 @@ exports.password = (req, res, next) => { @@ -291,7 +350,7 @@ exports.password = (req, res, next) => {
291 let shoppingKey = cookie.getShoppingKey(req); 350 let shoppingKey = cookie.getShoppingKey(req);
292 351
293 352
294 - RegService.regMobileAes(area, mobile, password, shoppingKey).then(result => { 353 + RegService.regMobileAes(area, mobile, password, shoppingKey, registerCode).then(result => {
295 if (!result.code || result.code !== 200) { 354 if (!result.code || result.code !== 200) {
296 return Promise.reject(result); 355 return Promise.reject(result);
297 } 356 }
@@ -304,11 +363,23 @@ exports.password = (req, res, next) => { @@ -304,11 +363,23 @@ exports.password = (req, res, next) => {
304 res.json({ 363 res.json({
305 code: 200, 364 code: 200,
306 message: LOGIN_SUCCSS, 365 message: LOGIN_SUCCSS,
307 - redirect: req.cookies.refer 366 + redirect: req.cookies.refer || '/'
308 }); 367 });
309 delete req.session.smsLogin; 368 delete req.session.smsLogin;
310 - delete req.session.smsLoginStep;  
311 }).catch(next); 369 }).catch(next);
  370 +};
  371 +
  372 +
  373 +/**
  374 + * 生成 校验码
  375 + */
  376 +exports.genCaptcha = (req, res) => {
  377 + let captcha = captchaService.generateCaptcha(90, 52, 4);
312 378
  379 + _.set(req.session, 'smsLogin.captcha', captcha.text);
313 380
  381 + res.type('png')
  382 + .set('Cache-Control', 'no-cache')
  383 + .status(200)
  384 + .send(captcha.image);
314 }; 385 };
  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 +};
@@ -96,12 +96,13 @@ const RegService = { @@ -96,12 +96,13 @@ const RegService = {
96 96
97 return api.post('', params); 97 return api.post('', params);
98 }, 98 },
99 - regMobileAes(area, mobile, password, shoppingKey) { 99 + regMobileAes(area, mobile, password, shoppingKey, smsCode) {
100 let params = { 100 let params = {
101 method: 'app.passport.registerAES', 101 method: 'app.passport.registerAES',
102 area: area, 102 area: area,
103 profile: mobile, 103 profile: mobile,
104 - password: aes.aesPwd(password) 104 + password: aes.aesPwd(password),
  105 + verifyCode: smsCode
105 }; 106 };
106 107
107 if (shoppingKey) { 108 if (shoppingKey) {
@@ -12,15 +12,18 @@ const login = require(cRoot + '/login'); @@ -12,15 +12,18 @@ 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 +
  16 +const disableBFCahce = require('../../doraemon/middleware/disable-BFCache');
  17 +
15 const smsLogin = require(cRoot + '/sms'); 18 const smsLogin = require(cRoot + '/sms');
16 const update = require(cRoot + '/update'); 19 const update = require(cRoot + '/update');
17 - 20 +const agreement = require(cRoot + '/app-agreement');
18 21
19 const router = express.Router(); // eslint-disable-line 22 const router = express.Router(); // eslint-disable-line
20 23
21 // 兼容老的路由 24 // 兼容老的路由
22 router.get('/signin.html', login.common.beforeLogin, login.local.loginPage); 25 router.get('/signin.html', login.common.beforeLogin, login.local.loginPage);
23 -router.get('/reg.html', reg.index); 26 +router.get('/reg.html', disableBFCahce, reg.index);
24 router.get('/login.html', login.common.beforeLogin, login.local.international); 27 router.get('/login.html', login.common.beforeLogin, login.local.international);
25 router.get('/phoneback.html', back.indexMobilePage); 28 router.get('/phoneback.html', back.indexMobilePage);
26 router.get('/emailback.html', back.indexEmailPage); 29 router.get('/emailback.html', back.indexEmailPage);
@@ -36,15 +39,16 @@ router.get('/passport/international', login.common.beforeLogin, login.local.inte @@ -36,15 +39,16 @@ router.get('/passport/international', login.common.beforeLogin, login.local.inte
36 router.post('/passport/login/auth', login.local.login); 39 router.post('/passport/login/auth', login.local.login);
37 40
38 // SMS 短信 41 // SMS 短信
39 -// router.use('/passport/sms_login', login.common.beforeLogin, smsLogin.beforeIn);  
40 -// router.get('/passport/sms_login', smsLogin.loginPage);  
41 -// router.get('/passport/sms_login/token.json',  
42 -// smsLogin.tokenBefore,  
43 -// smsLogin.token); // only ajax;  
44 -// router.get('/passport/sms_login/check.json',  
45 -// smsLogin.checkBefore,  
46 -// smsLogin.check); // only ajax  
47 -// router.post('/passport/sms_login/password.json', smsLogin.password); 42 +router.use('/passport/sms_login', login.common.beforeLogin, smsLogin.beforeIn);
  43 +router.get('/passport/sms_login', smsLogin.loginPage);
  44 +router.get('/passport/sms_login/token.json',
  45 + smsLogin.tokenBefore,
  46 + smsLogin.token); // only ajax;
  47 +router.get('/passport/sms_login/check.json',
  48 + smsLogin.checkBefore,
  49 + smsLogin.check); // only ajax
  50 +router.post('/passport/sms_login/password.json', smsLogin.password);
  51 +router.get('/passport/sms_login/captcha.png', smsLogin.genCaptcha);
48 52
49 // 微信登录 53 // 微信登录
50 router.get('/passport/login/wechat', login.common.beforeLogin, login.wechat.login); 54 router.get('/passport/login/wechat', login.common.beforeLogin, login.wechat.login);
@@ -83,13 +87,15 @@ router.post('/passport/bind/changeMobile', bind.changeMobile); @@ -83,13 +87,15 @@ router.post('/passport/bind/changeMobile', bind.changeMobile);
83 /** 87 /**
84 * 注册 88 * 注册
85 */ 89 */
  90 +router.use('/passport/reg/*', disableBFCahce);
86 router.get('/passport/reg/index', reg.index); 91 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); 92 +router.get('/passport/reg/captcha.png', reg.genCaptcha);
  93 +router.post('/passport/reg/verifymobile', reg.sendCodeBusyBoy, reg.verifyMobile);
  94 +router.get('/passport/reg/code', reg.guardStep(2), reg.code);
  95 +router.post('/passport/reg/sendcode', reg.guardStep(2), reg.sendCodeBusyBoy, reg.sendCode);
  96 +router.post('/passport/reg/verifycode', reg.guardStep(2), reg.verifyCode);
  97 +router.get('/passport/reg/password', reg.guardStep(3), reg.password);
  98 +router.post('/passport/reg/setpassword', reg.guardStep(3), reg.setPassword);
93 99
94 /** 100 /**
95 * 密码找回 101 * 密码找回
@@ -101,6 +107,7 @@ router.get('/passport/back/success', back.backSuccessByEmailPage);// 邮箱找 @@ -101,6 +107,7 @@ router.get('/passport/back/success', back.backSuccessByEmailPage);// 邮箱找
101 107
102 router.get('/passport/back/mobile', back.indexMobilePage);// 输入手机号找回密码页面 108 router.get('/passport/back/mobile', back.indexMobilePage);// 输入手机号找回密码页面
103 router.get('/passport/back/mobilecode', back.verifyCodeByMobilePage);// 输入手机验证码页面 109 router.get('/passport/back/mobilecode', back.verifyCodeByMobilePage);// 输入手机验证码页面
  110 +router.get('/passport/back/generatecodeimg.png', back.generateCodeImg);// 生成图片验证码
104 router.post('/passport/back/sendcode', back.sendCodeToMobileAPI);// 发送手机验证码 111 router.post('/passport/back/sendcode', back.sendCodeToMobileAPI);// 发送手机验证码
105 router.post('/passport/back/verifycode', back.verifyCodeByMobileAPI);// 校验手机验证码 112 router.post('/passport/back/verifycode', back.verifyCodeByMobileAPI);// 校验手机验证码
106 113
@@ -113,4 +120,10 @@ router.post('/passport/back/passwordbymobile', back.setNewPasswordByMobileAPI);/ @@ -113,4 +120,10 @@ router.post('/passport/back/passwordbymobile', back.setNewPasswordByMobileAPI);/
113 */ 120 */
114 router.get('/passport/update', update.index); 121 router.get('/passport/update', update.index);
115 122
  123 +// 服务条款
  124 +router.get('/passport/privacy', agreement.privacy);// 隐私条款
  125 +router.get('/passport/newpower', agreement.newpower);// 新力传媒
  126 +router.get('/passport/yohobuy', agreement.aboutYoho);// 关于有货
  127 +router.get('/passport/agreement', agreement.agreement);// 服务条款
  128 +
116 module.exports = router; 129 module.exports = router;
  1 +<div class="agreement-page yoho-page">
  2 + <h3>服务条款</h3>
  3 + <p><strong>重要须知:有货(江苏)商贸服务有限公司(下称“YOHO!BUY”)在此特别提醒您仔细阅读</strong>(未成年人应在其法定监护人的陪同下阅读)本《YOHO!BUY用户服务协议》(下称“本协议”)中的各个条款,包括但不限于免除或者限制YOHO!BUY责任的条款、对用户权利进行限制的条款以及约定争议解决方式、司法管辖的条款。您有权选择同意或者不同意本协议。<br>
  4 + </p>
  5 + <p><strong>您如果通过登录YOHO!BUY网站(http://www.yohobuy.com/)用户注册页面或者YOHO!BUY提供的其他用户注册渠道注册用户账号,即视为您完全同意本协议,愿意接受本协议所有及任何条款的约束。</strong></p><br>
  6 + <p><strong>1.名词解释</strong></p><br>
  7 + <p>除您与YOHO!BUY另有约定外,本协议及其补充协议当中的下列名词均采用如下解释:</p>
  8 + <p><strong>1.1 YOHO!BUY网站用户协议:</strong>即本协议,指您与YOHO!BUY当下订立的旨在约定您登录、使用本网站,以及通过本网站下达订单、购买商品、支付货款、收取商品等整个网购过程中,您与YOHO!BUY之间的权利、义务的书面合同。</p><br>
  9 + <p><strong>1.2 YOHO!BUY网站:</strong>即本网站,指YOHO!BUY享有全部著作权的、提供给您及其他用户登录和使用的一个专注潮流的网站,网址为http://www.yohobuy.com/。</p><br>
  10 + <p><strong>1.3 商品:</strong>是YOHO!BUY通过本网站向您推荐并进行销售的具体商品的统称。</p><br>
  11 + <p><strong>1.4 品牌供应商:</strong>与YOHO!BUY签订协议,组织商业活动并通过本网站销售商品和服务的公司,包括品牌供应商或者其授权的经销商。</p><br>
  12 + <p><strong>1.5 购物车:</strong>是模拟线下实体商店提供给顾客放置商品的“购物车”的一个概念,指本网站向您展示您已经下达订单、准备购买但尚未支付相应的购买价款的商品信息的网页区域,又称“虚拟购物车”。</p><br>
  13 + <p><strong>1.6 订单:</strong>指由本网站结帐程序生成的记录会员通过本网站所购买的商品的名称、品牌、价款、折扣等交易信息的表格。这份文件将被用作所有可能发生的与会员购买有关的询问、请求和争议的参考。</p><br>
  14 + <p><strong>1.7 发货单:</strong>指YOHO!BUY或者其品牌供应商、授权的经销商附录在会员所订购的商品的包裹上的、供会员签收的商品销售凭证,发货单一般会简要地说明了对应包裹的每一件商品的名称和数量,如发生退换货必须寄回。</p><br>
  15 + <p><strong>1.8 收货地址:</strong>指您或者其他用户通过本网站购买商品所要求的送货地址,如果没有特别说明,即为会员填写的订单上所记载的送货地址。</p><br>
  16 + <p><strong>1.9 用户账号:</strong>指您通过登录本网站或者YOHO!BUY提供其他的用户账号注册渠道,注册获得并可据以登录本网站的账号。</p><br>
  17 + <p><strong>1.10 恶意评论:</strong>是指个人或组织对本网站、YOHO!BUY和/或本网站对外销售的商品没有兴趣,却组织人力或者采用计算机程序模拟正常用户在本网站上大规模发表用户评论,特别发表对本网站、YOHO!BUY和/或本网站销售的商品负面的评论乃至违反国家有关法律法规的评论。</p><br>
  18 + <p><strong>2.合同目的</strong></p><br>
  19 + <p>本协议旨在约定您在登录、使用本网站,通过本网站购买商品的过程中,您与YOHO!BUY双方分别作为本协议的一方合同当事人所享有的权利和所负有的义务。<br><br>
  20 + <p><strong>3.用户账号</strong></p><br>
  21 + <p>3.1 您可以通过登录本网站的用户账号注册页面注册用户账号并设置相应的登录密码,一经注册成功,您即可以凭借用户账号及登录密码登录及使用本网站。就目前而言,上述用户账号既可能是您的移动电话号码,也可能是您的个人邮箱账号。</p><br>
  22 + <p>3.2 您成功注册用户账号后,如果需要使用该用户账号从本网站购买商品的,至少还应当填写一个收货人、收货地址和手机号码。除此之外,您还可以按照本网站相关页面的说明填写该用户账号项下的用户姓名、性别、生日、移动电话、固定电话、联系地址、QQ、邮编、购物习惯、着装习惯、喜爱品牌等个人信息,上述个人信息仅作为完善您的用户账号资料之用,是否填写并不影响您从本网站购买商品。</p><br>
  23 + <p><strong>3.3 每个手机号码、每个收货地址仅对应一个会员账户。 包含但不限于以下行为,视为虚假注册:</p><br>
  24 + <p>(1)以同一手机号码注册多个账户;</p><br>
  25 + <p>(2)多个账户使用同一收货地址或同一IP地址;</p><br>
  26 + <p>YOHO!BUY有权取消虚假注册账户在YOHO!BUY上消费的权利。</strong></p><br>
  27 + <p>3.4您务必妥善保管您的用户账号、登录密码、支付密码(如有)及您在其项下填写的所有个人信息,不得将其赠与、转让、借用或者以其他的方式提供给第三方。否则,由此给您(或YOHO!BUY、任何第三方)造成的一切损失,概由您自行承担(或者负责赔偿),包括但不限于:</p>
  28 + <p>(1)您无法凭借该用户账号登录、使用本网站及/或从本网站购买商品;</p><br>
  29 + <p>(2)您的该用户账号及其项下的YOHO币(有货币)、优惠券等未经您允许而被第三方盗用。</p><br>
  30 + <p>3.5为了防止您及其他用户的用户账号及其项下的个人信息泄露或者被他人窃取,YOHO!BUY可能会随时采取计算机病毒查杀技术、计算机加密技术等措施进行保护。对此,您完全同意并接受,但这并不能免除本协议第3.3条所述的、您对用户账号及其项下的个人信息所负有的妥善保管义务。</p><br>
  31 + <p>3.6 您如果遗忘了密码或者密码被他人修改,您可以按照YOHO!BUY公布的账号及密码找回规则,通过YOHO!BUY提供的账号及密码找回系统程序进行找回,或者在第一时间联系YOHO!BUY的客服人员协助找回,但YOHO!BUY不保证一定可以找回。</p><br>
  32 + <p><strong>3.7 您充分理解并完全同意:YOHO!BUY是一家面向消费者的专注潮流的网站,YOHO!BUY根据您的用户账号下的商品购买记录及其他相关信息,如果发现您此前通过本网站或者YOHO!BUY提供的其他网购渠道购买的商品大多数并非用于个人消费或者使用用途的,对于您的这个用户账号的商品购买需求,YOHO!BUY有权不予接受;您如果已经下达订单,YOHO!BUY有权不予接受订单;YOHO!BUY如果已经接受订单的,有权单方面解除并不予发货。而且,YOHO!BUY视情况还有权冻结您的这个用户账号,使之无法通过本网站以及YOHO!BUY提供的其他网购渠道下达订单、购买商品。</strong></p><br>
  33 + <p><strong>3.8 作为一个YOHO!BUY的会员,您可以邀请任何一个您的家庭成员、朋友、同事加入本站。这样您就成为他们的邀请人。然而,假如您希望扩大邀请至您家庭成员、朋友、同事等直系圈子以外的人,或者您希望把您的网站链接到本网站,您必须获取YOHO!BUY的预先许可。 在未取得YOHO!BUY事先的书面许可情况下,任何会员通过任何方式组织任何类型的大规模邀请计划,导致不符合前述条款的,将被禁止使用本网站,并且他的个人帐户将被取消。为了防止任何发动自己成为会员的企图,最多两个不同的会员可以使用同一个住所地址。</strong></p><br>
  34 + <p><strong>3.9您充分理解并同意:YOHO!BUY有权使用您的注册信息、用户名、密码等信息,登录进入用户的注册账户,进行证据保全,包括但不限于公证、见证等。</strong></p><br>
  35 + <p><strong>4.商品描述与营销信息</strong></p><br>
  36 + <p><strong>4.1 商品描述:除非YOHO!BUY或者本网站另有说明,本网站出售的商品均为正宗的商品。YOHO!BUY直接与品牌供应商及其授权的经销商合作开展各项营销活动,相关商品信息均由品牌供应商及/或其授权的经销商提供,YOHO!BUY尽可能根据所接收到的商品信息准确、详尽地描述每一件商品。然而,由于品牌供应商及/或其授权的经销商所提供的商品不一定是准确、完整、可靠、有效和没有错误的,因此YOHO!BUY不能保证本网站所有商品的描述和其他相关内容是准确、完整、可靠、有效和没有错误的。</strong></p><br>
  37 + <p>4.2 营销信息:您一经注册用户账号,即视为您同意YOHO!BUY及/或其关联公司通过短信或者电子邮件的方式向您注册时填写的手机号码或者电子邮箱发送相应的商品广告信息、促销优惠等营销信息;您如果不同意发送,您可以通过相应的退订功能进行退订。</p><br>
  38 + <p><strong>5.商品价格</strong></p><br>
  39 + <p>本网站上显示的所有价格都是以人民币为计价单位,不包括运费。结帐之前运费会自动计算包含在订单总价之内。在商品详情页面里您可以找到所有的相关信息,支付价格为下订单时的有效价格。<br></p><br>
  40 + <p><strong>6.订单</strong></p><br>
  41 + <p>6.1 YOHO!BUY保留对单个商品的总出售数量进行限制、对单个订单的商品购买数量及同一IP地址对同类商品购买数量进行限制的权利。</p><br>
  42 + <p>6.2 根据您填写的订单信息,系统将会生成一份包含您的订单的所有必要信息的电子订单表格。在结帐的过程中,您将被邀请复查订购商品的信息、付款方式以及这些商品的运输方式和费用。依据这些信息生成的最终订单表格被认为是该次交易的有效证据,这份文件被认为是所有的发货、问题、退货和争议事项的参考,所以您必须非常仔细地复查这些信息并纠正一切可能的错误。点击“完成”意味着您认可订单表格中包含的所有信息都是正确和完整的。</p><br>
  43 + <p>6.3 如果您填写的收货人与用户本人不一致的,收货人的行为和意思表示视为您的行为和意思表示,您应对收货人的行为及意思表示的法律后果承担连带责任。</p><br>
  44 + <p><strong>7.取消订单</strong></p><br>
  45 + <p>7.1 订单内商品的颜色、尺码、数量下单后无法修改。如您需修改订单收货地址,请在下单后两小时内自助网上修改或联系YOHO!BUY客服修改,我们将协助您联系快递进行修改,但不保证修改成功。</p><br>
  46 + <p>7.2 您也可以选择取消订单或联系YOHO!BUY客服取消,对反复的取消行为,我们可能会调查其原因,也可能会成为我们可能拒绝向您提供服务、冻结或关闭您的个人帐户的原因。</p><br>
  47 + <p><strong>8.合同成立</strong></p><br>
  48 + <p>您充分理解并认可:除法律另有强制性规定外,YOHO!BUY网站上销售方展示的商品和价格等信息仅仅是交易信息的发布,您下单时须填写您希望购买的商品数量、价款及支付方式、收货人、联系方式、收货地址等内容;系统生成的订单信息是计算机信息系统根据您填写的内容自动生成的数据,仅是您向销售方发出的交易诉求;销售方收到您的订单信息后,只有在销售方将您在订单中订购的商品从仓库实际直接向您发出时( 以商品出库为标志),方视为您与销售方之间就实际直接向您发出的商品建立了交易关系;如果您在一份订单里订购了多种商品并且销售方只给您发出了部分商品时,您与销售方之间仅就实际直接向您发出的商品建立了交易关系;只有在销售方实际直接向您发出了订单中订购的其他商品时,您和销售方之间就订单中该其他已实际直接向您发出的商品才成立交易关系。</p><br>
  49 + <p><strong>9.商品缺货</strong></p><br>
  50 + <p>YOHO!BUY接收到您的订单以后,YOHO!BUY发现所订购的商品全部或部分缺货。在这种情况下,YOHO!BUY会就缺货的商品详细情况与您联系后处理退款。如果您在收到此类通知15天之内没有取消订单,YOHO!BUY将把有货的商品送达或者在没有一件订购的商品有货的情况下取消该订单。在任何情况下,由于商品的缺货对您或第三方带来的任何损失,YOHO!BUY不负任何责任。</p><br>
  51 + <p><strong>10.配送服务</strong></p><br>
  52 + <p>10.1您所订购的商品有两种配送方式:(1)由YOHO!BUY选择具有运输服务资质的公司为您提供运输代理服务;(2)由品牌供应商选择具有提供运输服务资质的公司为您提供运输代理服务。上述任一配送方式下,您确认并同意一旦YOHO!BUY或者品牌供应商向运输代理服务公司交付你订购的商品,意味着您与提供运输代理服务公司签订了运输代理协议,形成了运输代理合同法律关系; 相关商品灭失及毁损风险自商品交付至运输代理服务公司起转移给您。</p><br>
  53 + <p>10.2您理解并同意:因以下原因造成订单延迟或无法配送等,YOHO!BUY不承担延迟配送的责任:</p><br>
  54 + <p>(1)您提供的信息错误,地址不详细等原因导致;</p><br>
  55 + <p>(2)货物送达后无人签收,导致无法配送或延迟配送的;</p><br>
  56 + <p>(3)情势变更等因素导致;</p><br>
  57 + <p>(4)不可抗力因素导致,如自然灾害、战争、暴乱等情况</p><br>
  58 + <p><strong>11.交货</strong></p><br>
  59 + <p>11.1 您所订购的商品将被送至订单表格上注明的收货地址。无论什么原因商品不能送达到送货地址的,YOHO!BUY将会尽快跟您取得联系。假如从我们第一次试图跟您联系之日7天内您没有提供答复,YOHO!BUY有权取消该订单。</p><br>
  60 + <p>11.2 在您收到订购商品的同时,请您书面签收证明您收到了完好状态的商品。如果包装出现破损,请拒收。</p><br>
  61 + <p>11.3 如果送货单中的商品列表与您的订单表格中所记录的不同,或者您收到的商品与发货单中的商品列表不符,您可以按照YOHO!BUY对外公布且正在实施的退货政策及退货程序,将相应的商品退回YOHO!BUY或者YOHO!BUY指定的第三方。而且,您务必于收到所订购的商品之日起48小时内,联系YOHO!BUY在线客服或致电400-8899-646将上述情况告知YOHO!BUY;否则,YOHO!BUY有权不予退换货。</p><br>
  62 + <p><strong>12.付款及所有权</p><br>
  63 + <p>YOHO!BUY通过本网站对外销售的商品,如果在YOHO!BUY将商品交付第三方承运人运输之时:
  64 + (1)您已经支付商品的全额的购买价款的,则其所有权于YOHO!BUY将其交付第三方承运人之时转移至您的名下;</p><br>
  65 + <p>(2)您尚未支付商品的全额的购买价款的,则其所有权于您支付全额的购买价款之时转移至您的名下。</p><br>
  66 + <p>在商品所有权按照前款约定转移至您的名下之前,商品所有权由YOHO!BUY、品牌供应商或其授权的经销商所有。</strong></p><br>
  67 + <p><strong>13.退回订单</strong></p><br>
  68 + <p>13.1 如果您对您通过本网站所订购的商品不满意,您可以退回所有或部分商品。对于YOHO!BUY已经收取到的被退回的商品的价款,YOHO!BUY将扣除退货运费后将相应的余额返还给您。您在下达的订单中如果使用了优惠券等其他优惠,YOHO!BUY亦将会按照相应的活动规则进行返还。</p><br>
  69 + <p>13.2 您如果需要退货的,务必于收到商品之日起7天内主动联系YOHO!BUY客服,将您需要退货的需求告知YOHO!BUY。而且,您务必于收到商品之日起7天内,按照不影响商品正常使用及再次销售的原则,将您需要退货的商品及其包装、赠品、发货单、税务发票(如有)等送货时一并交付给您的物品和资料,全部完好无损地退回YOHO!BUY或该商品的品牌供应商。否则,YOHO!BUY有权不予退货。除有相反的证据外,退货的日期以YOHO!BUY或者该商品的品牌供应商收到的包裹上显示的寄出邮戳所显示的日期为准。对于某些商品,如YOHO!BUY在商品详情页面及有关退货政策中已提示该类商品不予以退货的,您的下达订单行为将被视为您已同意接受YOHO!BUY对此类商品不予退货的安排。</p><br>
  70 + <p>13.3 YOHO!BUY有权拒绝不符合YOHO!BUY对外公布实施的退货政策(参阅http://www.yohobuy.com/help/)所规定的条件的所有退货。仅当YOHO!BUY确认以上规定的这些条款得到了适时的遵从后,YOHO!BUY才会启动返还货款金额的程序。YOHO!BUY收到退货后7天内,所有的退款均遵循YOHO!BUY退换货政策操作。</p><br>
  71 + <p>13.4 如果您的退货与上述退货规定不符,您将没有资格得到任何退款。不过,您仍有资格自行支付费用(包括运费)以便接收已经退回到YOHO!BUY的商品。如果您不想接收已经退回到YOHO!BUY的商品,YOHO!BUY有权保有这些商品并保留已经收到的金额。</p><br>
  72 + <p><strong>14.商品保证</strong></p><br>
  73 + <p>本网站所展示的商品完全符合中华人民共和国的相关法律法规的规定。YOHO!BUY保证本网站所售的商品均为正品。如果您对在本网站所购买的商品品牌存在怀疑,只需要在收到商品的90天内,凭工商部门的有效鉴定报告联系YOHO!BUY索取等同该商品售价的全额赔偿。</p><br>
  74 + <p><strong>15.知识产权</strong></p><br>
  75 + <p>15.1 YOHO!BUY对本网站的内容享有全部知识产权,包括但不限于:编码、商标、服务标志、商号、图形、美术品、照片、肖像、文字内容、音频片断、按钮图标已及计算机软件、标识、数码下载、数据汇编都是YOHO!BUY或其内容提供者的财产,受到中华人民共和国版权相关法律法规的保护。您对其仅享有本协议约定范围内的临时的、可撤销的非专有使用权。</p><br>
  76 + <p>15.2 您仅在符合本网站使用目的的前提下被许可浏览和使用本网站,即以个人名义浏览信息和购买供个人使用商品的目的。其他方式的使用都是被严格禁止的,包括但不限于以下方式:复制、修改、销售、传送、再版、删除、添加、展览、记入或演示本网站的内容或以其他方式部分地或整体地非法使用本网站的内容,但经YOHO!BUY允许将本网站当中的资讯转发至微信朋友圈等第三方媒体的除外。</p><br>
  77 + <p><strong>16.用户守则</strong><p><br>
  78 + <p>16.1 本网站与其他在线使用的互联网网站一样,您如果需要进行下载、安装、运行、登录或者使用,您至少必须自备一部可供上网的智能移动终端,并确保其能够通过互联网与本网站服务器软件进行实时的信息(即电子数据)交互,相应的上网流量费等相关费用由您自行承担。除非另有说明,YOHO!BUY存储在其服务器上的数据是YOHO!BUY和其会员之间交易的唯一有效证据。</p><br>
  79 + <p>16.2 本网站目前属于免费使用的网站,YOHO!BUY有权对本网站进行升级及更新,自行设置收费的软件功能、费率标准、收费对象及/或收费时段。您如果不同意YOHO!BUY设置的软件功能、费率标准、收费对象及/或收费时段的,则应当立即停止使用本网站;您如果继续使用的,则视为您接受YOHO!BUY的上述设置,您应当遵照履行并向YOHO!BUY支付相应的费用。</p><br>
  80 + <p>16.3 您不得进行任何侵犯本网站知识产权的行为,或者进行其他的有损于YOHO!BUY或其他用户合法权益的行为,包括但不限于:</p><br>
  81 + <p>(1)删除或修改本网站上的版权信息;</p><br>
  82 + <p>(2)修改、复制和/或发行本网站;</p><br>
  83 + <p>(3)在本网站当中内置各种插件程序或者其他的第三方程序;</p><br>
  84 + <p>(4)进行编译、反编译、反向工程或者以其他方式破解本网站的行为;</p><br>
  85 + <p>(5)使用本网站外挂和/或利用本网站当中的BUG来获得不正当的利益;</p><br>
  86 + <p>(6)利用劫持域名服务器等技术非法侵入、破坏本网站的服务器软件系统,或者修改、增加、删除、窃取、截留、替换本网站的客户端和/或服务器软件系统中的数据,或者非法挤占本网站的服务器空间,或者实施其他的使之超负荷运行的行为;</p><br>
  87 + <p>(7)假冒YOHO!BUY或签约商家在本网站当中发布任何诈骗或虚假信息;</p><br>
  88 + <p>(8)利用本网站故意传播恶意程序或计算机病毒。</p><br>
  89 + <p>16.4 您充分理解到:YOHO!BUY可能会不定期地通过发布软件升级包或软件补丁、在线升级等方式对本网站进行更新。更新的过程中,YOHO!BUY可能通过互联网调取、收集您的PC端终端上的关于本网站的客户端软件版本信息、数据及其他有关资料,并自动进行替换、修改、删除和/或补充。此种行为是网站更新所必须的一种操作或步骤,您如果不同意YOHO!BUY进行此种操作,请您不要进行更新;您更新的行为即视为您同意YOHO!BUY进行此种操作。</p><br>
  90 + <p>16.5 您有权在本网站当中发表评论,转发或者回复其他用户的评论,但您应确保评论真实、客观且不会侵犯任何第三方的著作权、肖像权、名誉权、隐私权等合法权利。而且,您不得借助本网站用户评论功能发布任何广告。</p><br>
  91 + <p>16.6 您应当遵守国家有关法律法规,不得在本网站当中发表、转发或者传播含有下列内容的信息:</p><br>
  92 + <p>(1)反对宪法所确定的基本原则的;</p><br>
  93 + <p>(2)危害国家安全、泄露国家秘密、颠覆国家政权、破坏国家统一的;</p><br>
  94 + <p>(3)损害国家荣誉和利益的;</p><br>
  95 + <p>(4)煽动民族仇恨、民族歧视,破坏民族团结的;</p><br>
  96 + <p>(5)破坏国家宗教政策,宣扬邪教和封建迷信的;</p><br>
  97 + <p>(6)散布谣言,扰乱社会秩序,破坏社会稳定的;</p><br>
  98 + <p>(7)散布淫秽、色情、赌博、暴力、凶杀、恐怖或者教唆犯罪的;</p><br>
  99 + <p>(8)侮辱或者诽谤他人,侵害他人合法权益的;</p><br>
  100 + <p>(9)含有法律、行政法规禁止的其他内容的。</p><br>
  101 + <p>16.7您充分理解并同意:YOHO!BUY保有删除站内各类不符合法律政策或不真实的信息内容而无需通知您的权利。</p><br>
  102 + <p>16.8 个人账户是YOHO!BUY授权您使用YOHO!BUY网站用户管理系统的唯一凭证。YOHO!BUY所提供的优惠券、积分、YOHO币(有货币)、折扣、推送等服务和优惠均通过用户管理系统发放,并且仅提供给获得授权的用户个人使用。您同意在符合法律法规及本条款规定的情况下使用个人帐户,YOHO!BUY有可能在某些情况(例如:您违反本条款和/或其它公开规则,或者您严重违背社会公德、提供虚假注册身份信息或者有其他违反法律禁止性规定的行为或损害YOHO!BUY利益的不正当行为等)下暂时冻结、永久冻结、修改、删除您的个人账户或者采取其他处理措施。特别地,您了解并同意,YOHO!BUY用户管理系统中个人帐户、积分、YOHO币(有货币)、优惠券等互联网产品及服务所有权归属YOHO!BUY,会员在满足YOHO!BUY公布的规则的前提下有权使用上述产品及服务。非经YOHO!BUY同意,您不得将YOHO!BUY各项产品及服务用于商业用途(例如:销售YOHO!BUY个人帐户、销售个人帐户下积分、YOHO币(有货币)、优惠券等)。在使用YOHO!BUY服务过程中,如果您或您的个人帐户刻意规避YOHO!BUY管理措施,或存在涉嫌欺诈、商业牟利、不恰当或不诚实地使用服务或者其他违反本条款和/或其他公开规则的行为(包括但不限于使用作弊软件获取积分及/或优惠券及/或YOHO币(有货币)、贩卖个人帐号、积分及/或优惠券及/或YOHO币(有货币)、盗号、协助盗号、非用于个人或家庭的合理消费等),YOHO!BUY有权拒绝为您继续提供服务,永久冻结您的个人帐户,并根据具体情况并有权对该等个人帐号中因上述手段而产生、获得的一切虚拟产品予以清零。</p><br>
  103 + <p>16.9您理解并同意,如因您违反相关法律与本协议之规定,使YOHO!BUY遭受任何损失,或受到任何第三方索赔,或受到任何行政管理部门的处罚,您应当赔偿YOHO!BUY因此遭受的损失和(或)相关费用,包括但不限于合理的律师费用。</p><br>
  104 + <p><strong>17.免责声明</strong><p><br>
  105 + <p><strong>17.1 关于本网站的免责声明</strong></p><br>
  106 + <p>17.1.1 本网站与其他的在线使用的互联网网站一样,也会受到各种不良信息、网络安全和网络故障问题的困扰,包括但不限于:</p><br>
  107 + <p>(1)其他用户可能会发布诈骗或虚假信息,或者发表有谩骂、诅咒、诋毁、攻击内容的,或者含有淫秽、色情、下流、反动、煽动民族仇恨等让人反感、厌恶的内容的非法言论;</p><br>
  108 + <p>(2)其他用户可能会发布一些侵犯您或者其他第三方知识产权、肖像权、姓名权、名誉权、隐私权和/或其他合法权益的图片、照片、文字等资料;</p><br>
  109 + <p>(3)面临着诸如黑客攻击、计算机病毒困扰、系统崩溃、网络掉线、网速缓慢、程序漏洞等问题的困扰和威胁。</p><br>
  110 + <p><strong>17.1.2 您充分理解到:本协议第17.1.1条所述的各种不良信息、网络安全和网络故障问题,并不是YOHO!BUY或者本网站所导致的问题,由此可能会造成您感到反感、恶心、呕吐等精神损害,或者给您造成其他的损失,概由您自行承担,YOHO!BUY无须向您承担任何责任。</strong></p><br>
  111 + <p>17.1.3 您完全同意:除法律法规规定或者您与YOHO!BUY约定须提前通知的以外,YOHO!BUY有权单方面地中止或者终止本网站所提供的服务而无须提前通知您。该等中止、终止,可能是因为YOHO!BUY解散、注销、合并、分立,也可能是因为YOHO!BUY将本网站或其运营权转让给了第三方,还可能是因为国家法律、法规、政策及国家机关的命令或者其他的诸如地震、火灾、海啸、台风、罢工、战争等不可抗力事件,还可能是因为您违反本协议第16.3条和/或第16.5条所约定的用户守则。</p><br>
  112 + <p><strong>17.2 关于商品销售的免责声明</p><br>
  113 + <p>17.2.1 由于用不同手机终端设备观看时网页显示的差异,YOHO!BUY上促销的商品在图像和颜色方面可能跟真实的物品不尽一致。因此,所有显示的图片、视频和其他商品显示方法仅限于图示目的,在任何情况下不认为是合同的组成部分。假如供出售的商品跟网站上的描述不同,对您唯一的补救措施是根据本协议在没有使用的情况下退回该商品。</p><br>
  114 + <p>17.2.2 YOHO!BUY保留根据市场价格波动随时修改上线商品价格的权利而无须事先通知。在由于系统错误、排版错误或供应商提供价格信息错误的情况下以不正确的价格列出来的商品,YOHO!BUY有拒绝或取消任何对以不正确的价格列出来的商品所下订单的权利。</p><br>
  115 + <p>17.2.3 由于合理的或不可避免的送货延迟对您或第三方带来的任何损失,YOHO!BUY不负任何责任。在这种情况下,YOHO!BUY将尽快地把任何可预知的延迟情况通知您,并在此时请您选择是否取消订单。</p><br>
  116 + <p>17.2.4 YOHO!BUY上面陈列的货物完全符合中华人民共和国的相关法律法规的规定。YOHO!BUY直接与品牌供应商或者他们授权的经销商合作,他们保证其商品是正宗的。您在YOHO!BUY上找到的商品描述均由品牌供应商或者他们授权的经销商提供,仅由他们对其真实性负责。除非另有明确书面说明,YOHO!BUY不对本站上的信息、产品、服务作任何形式的,明示的或默示的担保(法律明确规定的除外)。您应该系统性地参照货物描述找出他们的特征,对于任何种类的直接或间接的、实质或非实质的由于商品的使用造成的损失,YOHO!BUY概不负责。</strong></p><br>
  117 + <p><strong>18.个人信息保护</strong></p><br>
  118 + <p>18.1 YOHO!BUY可能通过本网站在您自愿选择服务或提供信息的情况下收集您的个人信息(简称“个人信息”),例如您的姓名、邮件地址、电话号码及其他身份信息等。我们有可能会保留一些用户的使用习惯信息,用于更好地了解和服务于用户。这些数据将有利于我们开发出更符合用户需求的功能、信息和服务。 </p><br>
  119 + <p>18.2 YOHO!BUY通过本网站可能会收集一些特定的关于您所使用的机器的技术信息,可能会包括:IP地址、操作系统版本、浏览器版本、显示器分辨率、推荐网站等。这些信息将用于提供更好的用户使用体验,提供更方便的服务。 </p><br>
  120 + <p><strong>18.3 YOHO!BUY非常重视保护您的YOHO!BUY账号及密码、电话号码、地理位置、智能移动终端品牌及型号等个人信息,未经您同意,YOHO!BUY不会将其披露给无关的第三方,更不会将其公之于众,但因下列原因而披露给第三方的除外: </p><br>
  121 + <p>(1)基于国家法律法规的规定而对外披露; </p><br>
  122 + <p>(2)应国家司法机关及其他有关机关基于法定程序的要求而披露; </p><br>
  123 + <p>(3)为保护YOHO!BUY或您的合法权益而披露; </p><br>
  124 + <p>(4)在紧急情况,为保护其他用户及第三方人身安全而披露; </p><br>
  125 + <p>(5)经您本人同意或应您的要求而披露。 </p><br>
  126 + <p>18.4 YOHO!BUY将使用各种安全技术和程序防止您及其他用户个人信息的丢失、不当使用、未经授权阅览或披露。但您充分理解到:由于技术的限制以及可能存在的各种恶意手段,在互联网行业,即便竭尽所能加强安全措施,也不可能始终保证信息百分之百的安全。</strong> </p><br>
  127 + <p><strong>19.其他约定</strong></p><br>
  128 + <p>19.1 YOHO!BUY保留随时地、不事先通知地、不需要任何理由地、单方面地修订本协议的权利。本协议一经修订,YOHO!BUY将会用修订后的协议版本完全替代修订前的协议版本,并通过适当的方式向所有用户公布。您应当及时关注和了解本协议的修订情况,如果您不同意修订后协议版本,请您立即停止使用本网站,否则即视同您同意并完全接受修订后的协议版本。</p><br>
  129 + <p><strong>19.2 YOHO!BUY有可能以消费者告知书、买家须知、温馨提示等形式,向您说明您在使用本网站购买商品时应当履行的本协议所约定的义务之外的其他义务,您亦应当仔细阅读并全面履行。上述说明如果与本协议相互冲突或者矛盾的,以上述约定为准;上述约定未涉及的内容,仍适用本协议。</p><br>
  130 + <p>19.3 YOHO!BUY将本协议内置于本网站的注册环节,您在注册的过程中即可查阅、了解本协议,并通过勾选“我已阅读并接受YOHO!BUY用户服务协议”表示您完全同意并接受本协议之约束,或者通过取消勾选“我已阅读并接受YOHO!BUY用户服务协议”表示您不同意本协议。</strong></p><br>
  131 + <p>19.4 本协议各条款是可分的,所约定的任何条款如果部分或者全部无效,不影响该条款其他部分及本协议其他条款的法律效力。</p><br>
  132 + <p>19.5 本协议各条款的标题只是为了方便用户阅读而起到提示、醒目的作用,对本协议的解释及适用没有任何指引作用。</p><br>
  133 + <p>19.6 YOHO!BUY基于本协议及其补充协议的有效弃权必须是书面的,并且该弃权不能产生连带的相同或者类似的弃权。</p><br>
  134 + <p><strong>19.7 您通过本网站购买非商品的服务产品的,您与YOHO!BUY之间的权利义务亦参照本协议的相关约定。</strong></p><br>
  135 + <p>19.8 您与YOHO!BUY均应当严格履行本协议及其补充协议所约定的各项义务,如发生争议或者纠纷,双方可以友好协商解决;协商不成的,任何一方均可提请YOHO!BUY住所所在地人民法院诉讼解决。</p><br>
  136 + <p>19.9 本网站的客户服务电话为:400-8899-646,您如对本协议条款有任何疑问或者需要帮助,可以通过上述电话与YOHO!BUY联系。</p><br>
  137 + <p>19.10 本协议及其补充协议签订地为江苏省南京市建邺区,均受中华人民共和国法律、法规管辖,YOHO!BUY保留最终解释权。</p><br>
  138 +
  139 + <div class="select-btn">
  140 + <span><i class="iconfont pitch select">&#xe60a;</i>我已阅读并同意遵守YOHO!BUY有货app服务条款</span>
  141 + <div class="submit-btn" href="">&nbsp;&nbsp;</div>
  142 + </div>
  143 +
  144 + <input type="hidden" name="app_version" value="{{appVersion}}">
  145 +</div>
  1 +<div class="newpower-page yoho-page">
  2 + <div class="banner"></div>
  3 +
  4 + <p>
  5 + <span>一、公司概况:</span><br>
  6 + 南京新与力文化传播有限公司(简称新力传媒)——中国潮流文化生态圈的创造者和引领者。10年以来,YOHO!致力于中国潮流产业的发展,从一本《YOHO!潮流志》开始,延伸到网络社区、电子商务等等领域,成为中国最权威和最具影响力的潮流“营、销”平台。我们通过媒体+零售线上线下一体化布局,为中国数以亿计的潮流消费者提供潮流讯息、产品及服务,并传播积极健康、全球化的潮流生活方式,更为中国的年轻一代消费者带来了来自全球的潮流生活方式。公司总部位于南京建邺区国家广告产业园,并在北京、上海、广州、香港、东京设立了分(子)公司。公司已获得鼎晖投资、新加坡淡马锡祥峰基金、软银赛富基金、达晨创投、华人文化等数轮投资。公司致力于将“YOHO!”打造成为中国年轻人最喜爱和最值得信赖的品牌,引领中国潮流文化产业的发展。 <br><br>
  7 +
  8 + <span>二、公司主要项目:</span><br>
  9 + 1、平面杂志及电子平台<br>
  10 + 《YOHO!潮流志》、《YOHO!GIRL》为YOHO!旗下在国内潮流领域影响力的杂志媒体。《YOHO!潮流志》2005 年10月创刊。他是国内第一本完全原创版权的,提供潮流和 lifestyle 资讯,属于年轻人的潮流时尚半月刊,通过正规发行渠道(报刊亭、连锁商超等)发行至全国各大中城市,深受全国年轻人的喜爱。设计给国内年轻女性的中高端时装月刊《YOHO!GIRL》,2013年3月正式创刊,在香港、大陆以及日本东京茑屋地区同步发行。以大量独家资讯加上独特的编采手法,改变读者的阅读习惯,扩阔大家在时装、美容、设计、生活、次文化等各方面的视野。深入结构品牌背后的哲学和时装趋势,带领各读者一探最新时尚。<br><br>
  11 +
  12 + 作为中国影响力最大、权威性最高、发行量最广的潮流杂志电子平台, “Yoho!Now”于 iOS 和 Android平台触亮全球潮流资讯,“Yoho!Now”7*24h 无休供应时装、运动、设计、科技、美容、家居、趣闻等严选潮流营养,并于每周发布特别线上专题,与读者Play and Learn。《YOHO!潮流志》和《YOHO!GIRL》亦于各自App內每周上架新鲜线上周刊,打包纸质版内容精华,汇通YOHO!潮流矩阵。 <br><br>
  13 +
  14 + 2、关于“Yoho!Buy有货” <br>
  15 + “Yoho!Buy有货”(www.yohobuy.com)——年轻人潮流购物中心,同样秉承YOHO!“年轻是种态度”的口号,Yoho!Buy有货专注于中国潮流趋势和受众的需要,凭借专业的买手团队和对中国潮流趋势敏锐的嗅觉,积极开拓符合中国年轻人喜爱的品牌和商品。销售包括国际知名、日韩港台流行、明星设计师、内地原创等等超过1000 个潮流品牌商品,满足18-35岁年轻群体的时尚个性化述求,涵盖男女服装、鞋帽、配件、童装及创意生活用品等。Yoho!Buy有货所销售的品牌均与品牌直接签订销售协议,保持货品与国际国内实体店铺同步,通过独家定制、限定发售、明星合作品牌等,并结合“逛”内容频道及社区互动引导消费。Yoho!Buy有货已成为中国年轻态群体最喜爱的潮流购物平台。<br><br>
  16 +
  17 + 3、关于“mars - 新鲜好去处”<br>
  18 + “mars - 新鲜好去处”是一款由YOHO!出品的潮流生活应用,立志为百万年轻人打造最酷的“城市探索”线上枢纽。连续两周被 Apple 评选为App Store“最佳新应用”,并获得 2016 年“一月最佳 App”、“最佳生活 App”等推荐。mars深入探索全球热点城市潮流坐标,现已上线北京、上海、成都、台北、香港、东京、首尔、纽约、洛杉矶等城市,未来还将陆续上线更多城市。集优质潮流攻略、专属玩乐线路、每日热点话题等功能,邀集世界各地时髦生活方式达人与所有用户分享好去处,让潮流随时、随地、随享。我们的目标就是带你去那些“如果你不用 mars 可能一辈子都不知道”的潮流好去处。<br><br>
  19 + </p>
  20 +</div>
  1 +<div class="privacy-page yoho-page">
  2 + <h3>隐私条款</h3>
  3 + <p>欢迎访问YOHO!BUY有货APP!我们以本隐私申明声明对访问者隐私保护的许诺。</p><br>
  4 +
  5 + <p>
  6 + <span>YOHO!BUY有货的信息收集与使用</span><br>
  7 +
  8 + YOHO!BUY有货APP收集用户提交的个人识别信息(下称“个人识别信息”), 一旦注册,YOHO!BUY 有货APP用户即可以建立由一页或多页网页组成的含有用户信息的用户档案。我们将收集用户发布在其用户档案中的数据,包括但不限于: 会员信息,联系信息,购物&着装习惯和喜爱品牌(合称为“用户档案信息”),我们使用这些信息来获得用户的统计资料。我们将会用这些统计数据来给我们的用户分类,以便有针对性地向我们的用户提供新的服务。我们会通过您的邮件地址来通知您这些新的服务。<br><br>
  9 +
  10 + 我们同样从用户处收集其他非个人识别信息(下称“非个人识别信息”),包括IP地址、集合的用户数据和浏览器类型。该等数据会被用来管理YOHO!BUY 有货APP,跟踪使用记录,改进YOHO!BUY 有货APP的服务。该等非个人识别信息通常被用于下列目的:研究和分析站点的使用情况,订制您浏览的广告和内容,满足您对服务的要求,以及改进我们的服务。出于安全和监管的目的,用户的IP地址将会被记录。<br><br>
  11 +
  12 + 我们或其商业伙伴可能在YOHO!BUY 有货APP上不时地进行促销或者抽奖。用户可能会被要求提供个人识别信息,包括姓名,电子邮件地址或家庭住址。因进行促销或者抽奖而收集个人识别信息时,您将清楚地被告知个人识别信息的收集方以及适用的隐私政策。<br><br>
  13 +
  14 + <span>YOHO!BUY 有货APP收集信息的共享与披露</span><br>
  15 +
  16 + 除本隐私政策另有规定,我们不会在未经您同意的情况下在YOHO!BUY 有货APP及其母公司、子公司或者关联公司(为本隐私政策之目的,包括遵守本隐私政策的技术提供者)之外泄露您的个人识别信息或者用户档案信息,除非我们认为这种披露是有必要的:(1)为遵守法律的要求或者回应我们收到的传票、搜查令或者其他法律程序,而不论该等回应是否为适用法律所要求的;(2)为回应主管政府部门的要求;(3)为了保护公众和服务用户的安全;或者(4)为了维护我们的法律权利和利益。<br><br>
  17 +
  18 + 当我们出售YOHO!BUY 有货APP或其全部资产时,我们保留向其继任者转让个人识别信息和用户档案信息的权利。
  19 + 我们也可以向某些您明确同意接收其信息的广告合作伙伴转让您的个人识别信息和用户档案信息。因此进行个人识别信息的收集时,您将清楚地被告知适用的隐私政策。<br><br>
  20 +
  21 + <span>用户名和密码</span><br>
  22 + YOHO!BUY 有货APP用户账号通过用户创设的密码确保其安全性。您应当对您密码的保密负全部责任。请不要和他人分享此信息。如果您泄漏了密码,您可能丢失了您的个人识别信息,并且有可能导致对您不利的司法行为。如果您和他人共享一台电脑,您应该在离开YOHO!BUY 有货APP时退出系统以保证您的信息不被后来使用该电脑者获取。
  23 + 因此不管任何原因使您的密码安全受到危及,您应该立即通过我们的客服热线:400-889-9646和我们取得联系 。<br><br>
  24 +
  25 + <span>您的交易行为</span><br>
  26 + 我们跟踪IP地址仅仅只是为了安全的必要。如果我们没有发现任何安全问题,我们会及时删除我们收集到的IP地址。我们还跟踪全天的页面访问数据。全天页面访问数据被用来反映网站的流量,我们可以为未来的发展制定计划(例如,增加服务器)。<br><br>
  27 +
  28 + <span>邮件 / 短信 / 会刊服务</span><br>
  29 + 我们保留通过邮件、短信、邮寄会刊的形式,对本网站注册、购物用户发送订单信息、促销活动等告知服务的权利。如果您在YOHO!BUY 有货APP注册、购物,表明您已默示同意接受此项服务。如果您不想接收来自我们的邮件、短信或会刊,您可以向我们的客服提出退阅申请,并注明您的E-mail地址、手机号或相关地址信息,我们会在收到申请后为您办理退阅。<br><br>
  30 +
  31 + <span>Cookies 的使用</span><br>
  32 + 我们使用cookies来储存用户的喜好和记录活动信息以确保用户不会重复收到同样的广告和定制的时事通讯、广告以及基于浏览器类型和用户档案信息的网页内容。我们不会把在cookies中保存的信息与您在我们网站上提交的任何个人识别信息相连接。您可以通过设置您的浏览器以接受或者拒绝全部或部分的cookies,或要求在cookies被设置时通知您。由于每个浏览器是不同的,请查看浏览器的“帮助”菜单来了解如何更改您的cookies选择参数。但是,您应允许来自YOHO!BUY 有货APP的cookies以使您可以使用网站的更多的功能。<br><br>
  33 +
  34 + <span>外部链接</span><br>
  35 + YOHO!BUY 有货APP包含其他网站的链接。但我们不对其他网站上的隐私政策和/或其执行承担责任。当链接到其他网站时,用户应该阅读该网站贴示的隐私政策。我们的隐私政策仅适用于自YOHO!BUY 有货APP收集的信息。<br><br>
  36 +
  37 + <span>第三方广告</span><br>
  38 + 我们可能会通过与第三方合作向用户提供服务。因此,我们可能向该第三方提供您通过YOHO!BUY 有货APP提交给我们的个人识别信息和用户档案信息;但该第三方应同意承担与我们相同的责任以保护用户的隐私。另外,在不会披露用户的个人识别信息和用户档案信息的前提下,我们可以对集合的用户个人识别信息和用户档案进行分析和商业性使用。<br><br>
  39 +
  40 + <span>安全</span><br>
  41 + 我们会采取合理措施保护存储在我们数据库中的用户个人识别信息和用户档案信息,并且对那些需要履行其工作职责的雇员,比如我们的客户服务人员和技术人员,获取用户个人识别信息和用户档案信息进行限制。请注意,我们无法保证用户个人识别信息和用户档案信息的安全性。未授权的登陆或使用、硬件或软件的故障、以及其他因素均可能在任何时候危及用户个人识别信息的安全性。<br><br>
  42 +
  43 + <span>隐私政策的变更</span><br>
  44 + 我们可能对本隐私政策不时进行修改。如果我们进行任何修改,我们将在YOHO!BUY 有货APP主页上发布为期30天的通知以使用户知道被修改内容的类型以及指示用户审阅更新的隐私政策。如果您在对本隐私政策任何细微修改发布后继续使用网站,则表示您同意遵守任何该等修改。<br><br>
  45 +
  46 + <span>联系我们</span><br>
  47 + 如果您就本隐私政策有任何疑问,请与我们客服联系客服热线:400-889-9646。<br><br>
  48 + </p>
  49 +</div>
  1 +<div class="about-yohobuy-page yohobuy-page">
  2 + <div class="banner"></div>
  3 +
  4 + <p>
  5 + {{!-- <span>关于“Yoho!Buy 有货”</span><br> --}}
  6 + “Yoho!Buy 有货”( www.yohobuy.com )——年轻人潮流购物中心,同样秉承YOHO!“年轻是种态度”的口号,Yoho!Buy有货专注于中国潮流趋势和受众的需要,凭借专业的买手团队和对中国潮流趋势敏锐的嗅觉,积极开拓符合中国年轻人喜爱的品牌和商品。销售包括国际知名、日韩港台流行、明星设计师、内地原创等等超过1000 个潮流品牌商品,满足18-35岁年轻群体的时尚个性化述求,涵盖男女服装、鞋帽、配件、童装及创意生活用品等。Yoho!Buy有货所销售的品牌均与品牌直接签订销售协议,保持货品与国际国内实体店铺同步,通过独家定制、限定发售、明星合作品牌等,并结合“逛”内容频道及社区互动引导消费。Yoho!Buy有货已成为中国年轻态群体最喜爱的潮流购物平台。
  7 + </p>
  8 +
  9 + <div class="about-bottom"></div>
  10 +</div>
@@ -6,6 +6,12 @@ @@ -6,6 +6,12 @@
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 + <div class="passport-captcha-img"><img id="verify-code-img" src="{{verifySrc}}" alt="verify code"></div>
  11 + <div class="passport-captcha-input">
  12 + <input id="verify-code" type="text" placeholder="验证码">
  13 + </div>
  14 + </div>
9 <span id="btn-next" class="btn btn-next disable row">下一步</span> 15 <span id="btn-next" class="btn btn-next disable row">下一步</span>
10 </div> 16 </div>
11 </div> 17 </div>
1 <div class="back-new-password-page passport-page yoho-page"> 1 <div class="back-new-password-page passport-page yoho-page">
2 {{> passport/header}} 2 {{> passport/header}}
3 <div class="content"> 3 <div class="content">
4 - <div class="input-container row has-eye">  
5 - <input id="pwd" class="input pwd" type="text" placeholder="请输入新密码" autocomplete="off" maxlength="20"> 4 + <div class="row js-password">
  5 + <div class="input-container has-eye">
  6 + <input id="pwd" class="input pwd" type="text" placeholder="请输入新密码" autocomplete="off" maxlength="20">
  7 + </div>
  8 + <div class="pwd-lint">
  9 + <i class="iconfont icon-tip">&#xE61A;</i>
  10 + <span class="pwd-lint-txt">由字母、数字组合,不能包含特殊字符</span>
  11 + </div>
6 </div> 12 </div>
7 <span id="btn-ok" class="btn btn-ok disable">完成</span> 13 <span id="btn-ok" class="btn btn-ok disable">完成</span>
8 </div> 14 </div>
@@ -10,8 +10,14 @@ @@ -10,8 +10,14 @@
10 您以后还可以使手机号+密码的形式登录有货哦! 10 您以后还可以使手机号+密码的形式登录有货哦!
11 </div> 11 </div>
12 {{/if}} 12 {{/if}}
13 - <div class="input-container row has-eye">  
14 - <input id="pwd" class="input pwd" type="text" placeholder="请输入密码" autocomplete="off" maxlength="20"> 13 + <div class="row">
  14 + <div class="input-container row has-eye">
  15 + <input id="pwd" class="input pwd" type="text" placeholder="请输入密码" autocomplete="off" maxlength="20">
  16 + </div>
  17 + <div class="pwd-lint">
  18 + <i class="iconfont icon-tip">&#xE61A;</i>
  19 + <span class="pwd-lint-txt">由字母、数字组合,不能包含特殊字符</span>
  20 + </div>
15 </div> 21 </div>
16 <span id="btn-sure" class="btn btn-sure disable row">确定</span> 22 <span id="btn-sure" class="btn btn-sure disable row">确定</span>
17 </div> 23 </div>
@@ -6,7 +6,17 @@ @@ -6,7 +6,17 @@
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 + <div class="passport-captcha-img">
  12 + <img class="passport-captcha-png" src="{{captchaUrl}}">
  13 + </div>
  14 + <div class="passport-captcha-input">
  15 + <input id="js-captcha" type="text" placeholder="验证码">
  16 + </div>
  17 + </div>
  18 + <!-- 验证码: end-->
9 <span id="btn-next" class="btn btn-next disable row">下一步</span> 19 <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> 20 <p class="register-tip">Yoho!Family账号可登录Yoho!Buy有货、Yoho!Now、mars及SHOW</p>
11 </div> 21 </div>
12 -</div> 22 +</div>
1 <div class="reg-password-page passport-page yoho-page"> 1 <div class="reg-password-page passport-page yoho-page">
2 {{> passport/header}} 2 {{> passport/header}}
3 <div class="content"> 3 <div class="content">
4 - <div class="input-container row has-eye">  
5 - <input id="pwd" class="input pwd" type="text" placeholder="请输入密码" autocomplete="off" maxlength="20"> 4 + <div class="row js-password">
  5 + <div class="input-container has-eye">
  6 + <input id="pwd" class="input pwd" type="text" placeholder="6-20位的密码" autocomplete="off" maxlength="20">
  7 + </div>
  8 + <div class="pwd-lint">
  9 + <i class="iconfont icon-tip">&#xE61A;</i>
  10 + <span class="pwd-lint-txt">由字母、数字组合,不能包含特殊字符</span>
  11 + </div>
6 </div> 12 </div>
7 - <span id="btn-sure" class="btn btn-sure disable row">确定</span> 13 + <span id="btn-sure" class="btn btn-sure disable row">注册</span>
  14 + <div class="app-agreement"><span></span><i class="iconfont pitch select">&#xe60a;</i><a class="agreement-detail">我已阅读并同意遵守YOHO!BUY有货服务条款</a></div>
8 </div> 15 </div>
9 <input id="phone-num" type="hidden" value="{{phoneNum}}"> 16 <input id="phone-num" type="hidden" value="{{phoneNum}}">
10 <input id="area-code" type="hidden" value="{{areaCode}}"> 17 <input id="area-code" type="hidden" value="{{areaCode}}">
11 <input id="token" type="hidden" value="{{token}}"> 18 <input id="token" type="hidden" value="{{token}}">
  19 + <input id="sms-code" type="hidden" value="{{smsCode}}">
  20 +</div>
  21 +
  22 +<div class="prompt">
  23 + <span class="word">是否已阅读并同意遵守YOHO!BUY<br>有货服务条款</span>
  24 + <div class="choose">
  25 + <span class="ensure"></span>
  26 + <span class="deny"></span>
  27 +
  28 + </div>
12 </div> 29 </div>
@@ -15,5 +15,5 @@ @@ -15,5 +15,5 @@
15 <input type="hidden" name="area" id="area" value="{{area}}"> 15 <input type="hidden" name="area" id="area" value="{{area}}">
16 </div> 16 </div>
17 <script> 17 <script>
18 - var canResend = {{canResend}}; 18 + var countdown = {{countdown}};
19 </script> 19 </script>
@@ -7,6 +7,12 @@ @@ -7,6 +7,12 @@
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 <button class="clear-input" type="button"></button> 8 <button class="clear-input" type="button"></button>
9 </div> 9 </div>
  10 + <div class="passport-captcha row">
  11 + <div class="passport-captcha-img"><img src="{{captchaUrl}}" alt=""></div>
  12 + <div class="passport-captcha-input">
  13 + <input id="js-captcha" type="text" placeholder="验证码">
  14 + </div>
  15 + </div>
10 <button id="btn-next" class="btn btn-next disable row" disabled>获取短信验证码</button> 16 <button id="btn-next" class="btn btn-next disable row" disabled>获取短信验证码</button>
11 </div> 17 </div>
12 </div> 18 </div>
@@ -2,9 +2,17 @@ @@ -2,9 +2,17 @@
2 {{> passport/header}} 2 {{> passport/header}}
3 <div class="content"> 3 <div class="content">
4 <p class="sms-login-msg small">你以后还可以使用手机号码 + 密码的形式登录有货哦!</p> 4 <p class="sms-login-msg small">你以后还可以使用手机号码 + 密码的形式登录有货哦!</p>
5 - <div class="input-container row has-eye">  
6 - <input id="pwd" class="pwd input" type="text" placeholder="密码">  
7 - <div class="eye" id="eye"></div> 5 + <div class="row js-password">
  6 + <div class="input-container row has-eye">
  7 + <input id="pwd" class="pwd input" type="text" placeholder="6-20位的密码">
  8 + <div class="eye" id="eye"></div>
  9 + </div>
  10 + <div class="pwd-lint">
  11 + <i class="iconfont icon-tip">&#xE61A;</i>
  12 + <span class="pwd-lint-txt">由字母、数字组合,不能包含特殊字符</span>
  13 + </div>
  14 + </div>
  15 + <div>
8 </div> 16 </div>
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 </div> 18 </div>
@@ -12,6 +12,7 @@ const detailModel = require(`${mRoot}/detail`); // 商品详情 model @@ -12,6 +12,7 @@ const detailModel = require(`${mRoot}/detail`); // 商品详情 model
12 const introModel = require(`${mRoot}/intro`); // 商品尺码信息 model 12 const introModel = require(`${mRoot}/intro`); // 商品尺码信息 model
13 const preferenceModel = require(`${mRoot}/preference`); // 商品偏好 model 13 const preferenceModel = require(`${mRoot}/preference`); // 商品偏好 model
14 const detailRelated = require(`${mRoot}/consult-comment`); // 商品评论咨询 model 14 const detailRelated = require(`${mRoot}/consult-comment`); // 商品评论咨询 model
  15 +const couponModel = require(`${mRoot}/coupon`); // 商品 优惠券 modal
15 const _ = require('lodash'); 16 const _ = require('lodash');
16 17
17 const helpers = global.yoho.helpers; 18 const helpers = global.yoho.helpers;
@@ -138,12 +139,9 @@ exports.intro = (req, res, next) => { @@ -138,12 +139,9 @@ exports.intro = (req, res, next) => {
138 exports.preference = (req, res, next) => { 139 exports.preference = (req, res, next) => {
139 preferenceModel({ 140 preferenceModel({
140 productskn: req.query.productSkn, 141 productskn: req.query.productSkn,
141 - yhchannel: req.yoho.channel,  
142 - brandId: req.query.brandId 142 + limit: '20' // 后期值需要修改的话得手动改
143 }).then((result) => { 143 }).then((result) => {
144 - res.render('detail/preference', Object.assign({  
145 - layout: false  
146 - }, result)); 144 + res.send(result);
147 }).catch(next); 145 }).catch(next);
148 }; 146 };
149 147
@@ -160,6 +158,9 @@ exports.comments = (req, res, next) => { @@ -160,6 +158,9 @@ exports.comments = (req, res, next) => {
160 }); 158 });
161 159
162 detailRelated.comments(req.query).then((result) => { 160 detailRelated.comments(req.query).then((result) => {
  161 + if (result.navTitle) {
  162 + headerData.navTitle = result.navTitle;
  163 + }
163 res.render('detail/comments', Object.assign({ 164 res.render('detail/comments', Object.assign({
164 title: '购买评价', 165 title: '购买评价',
165 pageHeader: headerData, 166 pageHeader: headerData,
@@ -175,12 +176,15 @@ exports.consults = (req, res, next) => { @@ -175,12 +176,15 @@ exports.consults = (req, res, next) => {
175 if (!req.query.product_id) { 176 if (!req.query.product_id) {
176 return next(); 177 return next();
177 } 178 }
178 - 179 + let uid = req.user.uid || 0;
179 let headerData = headerModel.setNav({ 180 let headerData = headerModel.setNav({
180 navTitle: '购买咨询' 181 navTitle: '购买咨询'
181 }); 182 });
182 183
183 - detailRelated.consults(req.query).then((result) => { 184 + detailRelated.consults(req.query, uid).then((result) => {
  185 + if (result.navTitle) {
  186 + headerData.navTitle = result.navTitle;
  187 + }
184 res.render('detail/consults', Object.assign({ 188 res.render('detail/consults', Object.assign({
185 title: '购买咨询', 189 title: '购买咨询',
186 pageHeader: headerData, 190 pageHeader: headerData,
@@ -247,13 +251,12 @@ exports.consultsubmit = (req, res, next) => { @@ -247,13 +251,12 @@ exports.consultsubmit = (req, res, next) => {
247 data: '' 251 data: ''
248 }; 252 };
249 253
250 - // 判断参数是否存在 254 + // 判断参数是否存在
251 if (!req.body.product_id || !req.body.content) { 255 if (!req.body.product_id || !req.body.content) {
252 return res.json(data); 256 return res.json(data);
253 } 257 }
254 258
255 - detailRelated.addConsult(req.user.uid, req.body.product_id, req.body.content).then((result) => {  
256 - 259 + return detailRelated.addConsult(req.user.uid, req.body.product_id, req.body.content).then((result) => {
257 if (result) { 260 if (result) {
258 Object.assign(data, result); 261 Object.assign(data, result);
259 } 262 }
@@ -344,7 +347,7 @@ exports.index = (req, res, next) => { @@ -344,7 +347,7 @@ exports.index = (req, res, next) => {
344 * @param {[type]} res [description] 347 * @param {[type]} res [description]
345 * @return {[type]} [description] 348 * @return {[type]} [description]
346 */ 349 */
347 -exports.indexData = (req, res, next)=> { 350 +exports.indexData = (req, res, next) => {
348 if (!req.xhr) { 351 if (!req.xhr) {
349 return next(); 352 return next();
350 } 353 }
@@ -361,10 +364,59 @@ exports.indexData = (req, res, next)=> { @@ -361,10 +364,59 @@ exports.indexData = (req, res, next)=> {
361 ua: req.get('user-agent') || '' 364 ua: req.get('user-agent') || ''
362 }, req.__User__)).then((result) => { 365 }, req.__User__)).then((result) => {
363 if (_.isEmpty(result)) { 366 if (_.isEmpty(result)) {
364 - return res.json({code: 400, message: '数据错误'}); 367 + return res.json({
  368 + code: 400,
  369 + message: '数据错误'
  370 + });
365 } 371 }
366 result.studentPrice = req.__User__.isStudent && result && result.goodsPrice && result.goodsPrice.studentPrice ? result.goodsPrice.studentPrice : false; 372 result.studentPrice = req.__User__.isStudent && result && result.goodsPrice && result.goodsPrice.studentPrice ? result.goodsPrice.studentPrice : false;
367 return res.json(result); 373 return res.json(result);
368 }).catch(next); 374 }).catch(next);
369 375
370 }; 376 };
  377 +
  378 +
  379 +/**
  380 + * [查询商品 品牌券]
  381 + */
  382 +exports.brandCoupon = (req, res) => {
  383 + const uid = req.user.uid;
  384 + const skn = +req.query.skn;
  385 + const brandId = +req.query.brandId;
  386 +
  387 + if (!(skn && brandId)) {
  388 + return res.json([]);
  389 + }
  390 +
  391 + couponModel.queryProdPageCoupons(uid, skn, brandId)
  392 + .then(
  393 + result => {
  394 + return result.data || [];
  395 + }, () => {
  396 + return [];
  397 + })
  398 + .then(coupons => {
  399 + return res.json(coupons);
  400 + });
  401 +};
  402 +
  403 +/**
  404 + * [获取商品 品牌券]
  405 + */
  406 +exports.getCoupon = (req, res, next) => {
  407 + const uid = req.user.uid;
  408 + const couponId = +req.body.couponId;
  409 +
  410 + if (!couponId) {
  411 + return res.json({
  412 + code: 400,
  413 + message: '优惠券不存在'
  414 + });
  415 + }
  416 +
  417 + return couponModel.getCoupon(uid, couponId)
  418 + .then(data => {
  419 + return res.json(data);
  420 + })
  421 + .catch(next);
  422 +};
@@ -38,13 +38,16 @@ const _getUidFromUserAgent = (req) => { @@ -38,13 +38,16 @@ const _getUidFromUserAgent = (req) => {
38 */ 38 */
39 const _baseShop = (req, res, shopInfo, shopId) => { 39 const _baseShop = (req, res, shopInfo, shopId) => {
40 40
41 - listModel.getBaseShopData(req.query, shopInfo).then(result => { 41 + listModel.getBaseShopData(Object.assign(req.query, {
  42 + channel: req.yoho.channel
  43 + }), shopInfo).then(result => {
42 if (result && result.baseShopHome && result.baseShopHome.banner) { 44 if (result && result.baseShopHome && result.baseShopHome.banner) {
43 if (result.baseShopHome.banner.indexOf('?') < 0) { 45 if (result.baseShopHome.banner.indexOf('?') < 0) {
44 result.baseShopHome.banner += '?imageMogr2/auto-orient/strip/thumbnail/x150/crop/640x150'; 46 result.baseShopHome.banner += '?imageMogr2/auto-orient/strip/thumbnail/x150/crop/640x150';
45 } 47 }
46 } 48 }
47 - res.render('search/goods-list', { 49 +
  50 + res.render('search/goods-list', Object.assign({
48 module: 'product', 51 module: 'product',
49 page: 'search-list', 52 page: 'search-list',
50 pageHeader: headerModel.setNav({ 53 pageHeader: headerModel.setNav({
@@ -53,12 +56,9 @@ const _baseShop = (req, res, shopInfo, shopId) => { @@ -53,12 +56,9 @@ const _baseShop = (req, res, shopInfo, shopId) => {
53 goodList: result, 56 goodList: result,
54 showDownloadApp: true, 57 showDownloadApp: true,
55 pageFooter: true, 58 pageFooter: true,
56 - title: shopInfo.shop_name + '|' + shopInfo.shop_name + '潮流服装服饰-Yoho!Buy有货',  
57 - keywords: shopInfo.shop_name + ',' + shopInfo.shop_name + '服装服饰,' + shopInfo.shop_name + '潮流服装服饰',  
58 - description: shopInfo.shop_name + '|Yoho!Buy有货' + shopInfo.shop_name + '潮流服饰官方授权店!100%品牌正品保证,支持货到付款。',  
59 shopId: shopId, 59 shopId: shopId,
60 shopPage: true 60 shopPage: true
61 - }); 61 + }, result.seoResult));
62 }); 62 });
63 63
64 }; 64 };
@@ -142,19 +142,16 @@ const _shop = (req, res, shopId) => { @@ -142,19 +142,16 @@ const _shop = (req, res, shopId) => {
142 // 有领券功能,不缓存 142 // 有领券功能,不缓存
143 res.set('Cache-Control', 'no-cache'); 143 res.set('Cache-Control', 'no-cache');
144 144
145 - res.render('shop/index', { 145 + res.render('shop/index', Object.assign({
146 module: 'product', 146 module: 'product',
147 page: 'shop', 147 page: 'shop',
148 shopIndex: result, 148 shopIndex: result,
149 shopHeadHide: true, 149 shopHeadHide: true,
150 gender: req.query.gender, 150 gender: req.query.gender,
151 channel: req.query.channel, 151 channel: req.query.channel,
152 - title: result.seoTitle + '|' + result.seoTitle + '潮流服装服饰-Yoho!Buy有货',  
153 - keywords: result.seoTitle + ',' + result.seoTitle + '服装服饰,' + result.seoTitle + '潮流服装服饰',  
154 - description: result.seoTitle + '|Yoho!Buy有货' + result.seoTitle + '潮流服饰官方授权店!100%品牌正品保证,支持货到付款。',  
155 shopId: shopId, 152 shopId: shopId,
156 shopPage: true 153 shopPage: true
157 - }); 154 + }, result.seoResult));
158 155
159 }); 156 });
160 } 157 }
@@ -222,7 +219,8 @@ const category = (req, res) => { @@ -222,7 +219,8 @@ const category = (req, res) => {
222 }), 219 }),
223 goodList: params, 220 goodList: params,
224 showDownloadApp: true, 221 showDownloadApp: true,
225 - pageFooter: true 222 + pageFooter: true,
  223 + category: true
226 }); 224 });
227 }; 225 };
228 226
@@ -272,11 +270,13 @@ const brand = (req, res, next) => { @@ -272,11 +270,13 @@ const brand = (req, res, next) => {
272 if (req.query.from !== 'search' && brandLogo.type === '2' && brandLogo.shopId) { 270 if (req.query.from !== 'search' && brandLogo.type === '2' && brandLogo.shopId) {
273 _shop(req, res, brandLogo.shopId); 271 _shop(req, res, brandLogo.shopId);
274 } else { // 获取品牌店铺信息 272 } else { // 获取品牌店铺信息
275 - listModel.getBrandShops(brandId).then(brandShop => { 273 + listModel.getBrandShops(brandId, req).then(brandShop => {
276 if (brandId === 0) { 274 if (brandId === 0) {
277 params.query = domain; 275 params.query = domain;
278 } 276 }
279 277
  278 + params.seoResult = brandShop.seoResult;
  279 +
280 // 从搜索页过来的,显示搜索框, 和进入品牌引导信息 或者品牌关联多店铺 280 // 从搜索页过来的,显示搜索框, 和进入品牌引导信息 或者品牌关联多店铺
281 if (req.query.from === 'search' || brandShop.length > 0) { 281 if (req.query.from === 'search' || brandShop.length > 0) {
282 params = _.assign({ 282 params = _.assign({
@@ -286,7 +286,7 @@ const brand = (req, res, next) => { @@ -286,7 +286,7 @@ const brand = (req, res, next) => {
286 url: helpers.urlFormat('', null, 'search') 286 url: helpers.urlFormat('', null, 'search')
287 } 287 }
288 }, params); 288 }, params);
289 - } else if (brandId !== 0) { // 品牌一览过来的展示品牌介绍和LOGO 289 + } else if (brandId && brandId !== 0 && brandId !== '' && brandId !== 'undefined') { // 品牌一览过来的展示品牌介绍和LOGO
290 return Promise.all([listModel.getBrandIntro(brandId, uid), listModel.getBrandBanner(brandId)]).then((resData) => { //eslint-disable-line 290 return Promise.all([listModel.getBrandIntro(brandId, uid), listModel.getBrandBanner(brandId)]).then((resData) => { //eslint-disable-line
291 title = resData[0].title; 291 title = resData[0].title;
292 delete resData[0].title; 292 delete resData[0].title;
@@ -303,7 +303,7 @@ const brand = (req, res, next) => { @@ -303,7 +303,7 @@ const brand = (req, res, next) => {
303 res.set('Cache-Control', 'no-cache'); 303 res.set('Cache-Control', 'no-cache');
304 } 304 }
305 305
306 - res.render('search/goods-list', { 306 + res.render('search/goods-list', Object.assign({
307 module: 'product', 307 module: 'product',
308 page: 'search-list', 308 page: 'search-list',
309 pageHeader: headerModel.setNav({ 309 pageHeader: headerModel.setNav({
@@ -312,12 +312,9 @@ const brand = (req, res, next) => { @@ -312,12 +312,9 @@ const brand = (req, res, next) => {
312 goodList: params, 312 goodList: params,
313 showDownloadApp: true, 313 showDownloadApp: true,
314 pageFooter: true, 314 pageFooter: true,
315 - title: title + '|' + title + '潮流服装服饰-Yoho!Buy有货',  
316 - keywords: title + ',' + title + '服装服饰,' + title + '潮流服装服饰',  
317 - description: title + '|Yoho!Buy有货' + title + '潮流服饰官方授权店!100%品牌正品保证,支持货到付款。',  
318 domain: req.query.domain, 315 domain: req.query.domain,
319 shopPage: true 316 shopPage: true
320 - }); 317 + }, params.seoResult));
321 }); 318 });
322 } 319 }
323 }).catch(next); 320 }).catch(next);
@@ -356,7 +353,7 @@ const shopIntro = (req, res, next) => { @@ -356,7 +353,7 @@ const shopIntro = (req, res, next) => {
356 let appVersion = req.body.appVersion || false; 353 let appVersion = req.body.appVersion || false;
357 let params = {}; 354 let params = {};
358 355
359 - if (shopId) { 356 + if (parseInt(shopId, 10)) {
360 listModel.getShopIntro(shopId).then(result => { 357 listModel.getShopIntro(shopId).then(result => {
361 if (appVersion) { 358 if (appVersion) {
362 params = { 359 params = {
@@ -480,20 +477,14 @@ const userCoupon = (req, res, next) => { @@ -480,20 +477,14 @@ const userCoupon = (req, res, next) => {
480 res.setHeader('Access-Control-Allow-Origin', allowOrigin); 477 res.setHeader('Access-Control-Allow-Origin', allowOrigin);
481 res.setHeader('Access-Control-Allow-Credentials', 'true'); 478 res.setHeader('Access-Control-Allow-Credentials', 'true');
482 479
483 - if (!req.query.couponID) { 480 + if (!req.body.couponID) {
484 return; 481 return;
485 } 482 }
486 483
487 - let cryptCouponId = crypto.decrypt('', req.query.couponID);  
488 - let uid = req.user.uid;  
489 -  
490 - if (req.yoho.isApp !== 'false') {  
491 - uid = req.query.uid ? crypto.decrypt('', req.query.uid) : req.cookies.appUid;  
492 -  
493 - if (!uid || uid === 'undefined') {  
494 - uid = _getUidFromUserAgent(req);  
495 - }  
496 - } 484 + let cryptCouponId = crypto.decrypt('', req.body.couponID);
  485 + let uid = req.body.uid || req.user.uid;
  486 + let isApp = req.body.app_version || req.body.appVersion || false;
  487 + let data = {};
497 488
498 cryptCouponId = parseInt(cryptCouponId, 10); 489 cryptCouponId = parseInt(cryptCouponId, 10);
499 uid = parseInt(uid, 10); 490 uid = parseInt(uid, 10);
@@ -507,32 +498,83 @@ const userCoupon = (req, res, next) => { @@ -507,32 +498,83 @@ const userCoupon = (req, res, next) => {
507 return; 498 return;
508 }).catch(next); 499 }).catch(next);
509 } else { 500 } else {
  501 + data.code = 4401;// 401错误已经被接口占用
510 let refer = req.get('referer'); 502 let refer = req.get('referer');
  503 + let toUrl = helpers.urlFormat('/signin.html', {refer: refer});
511 504
512 - if (req.yoho.isApp !== 'false') {  
513 - let toUrl = refer + '&openby:yohobuy={"action":"go.weblogin","params":{"jumpurl":{"url":"' +  
514 - refer + 505 + if (isApp) {
  506 + toUrl += '&openby:yohobuy={"action":"go.weblogin","params":{"jumpurl":{"url":"' + refer +
515 '","param":{}},"requesturl":{"param":{"method":"app.promotion.getCoupon","couponId":"' + 507 '","param":{}},"requesturl":{"param":{"method":"app.promotion.getCoupon","couponId":"' +
516 - cryptCouponId +  
517 - '"},"url":"' +  
518 - _.get(global, 'yoho.API.ApiUrl', '') +  
519 - '"},"priority":"Y"}}';  
520 -  
521 - res.json({  
522 - code: 4401,  
523 - url: toUrl  
524 - }); 508 + cryptCouponId + '"},"url":"' + _.get(global, 'yoho.API.ApiUrl', '') + '"},"priority":"Y"}}';
  509 + }
525 510
526 - } else {  
527 - res.json({  
528 - code: 4401,  
529 - url: helpers.urlFormat('/signin.html', {refer: refer})  
530 - }); 511 + data.url = toUrl;
  512 + res.json(data);
  513 + }
  514 +};
  515 +
  516 +/**
  517 + * 获取店铺优惠券列表
  518 + * @param req
  519 + * @param res
  520 + * @param next
  521 + */
  522 +const getShopCouponsList = (req, res, next) => {
  523 + let allowOrigin = _.get(req, 'headers.origin', null) ?
  524 + req.headers.origin : req.protocol + '://' + req.headers.host;
  525 +
  526 + res.setHeader('Access-Control-Allow-Origin', allowOrigin);
  527 + res.setHeader('Access-Control-Allow-Credentials', 'true');
  528 +
  529 + let uid = req.query.uid || req.user.uid;
  530 + let shopId = parseInt(req.query.shopId, 10);
  531 + let param = {};
  532 +
  533 + if (shopId) {
  534 + if (uid) {
  535 + param.uid = uid;
531 } 536 }
532 537
  538 + param.shop_id = shopId;
533 539
  540 + listModel.shopCouponsList(param).then(result => {
  541 + res.json(result);
  542 + }).catch(next);
  543 + } else {
  544 + res.json([]);
534 } 545 }
  546 +};
  547 +
  548 +/**
  549 + * 获取品牌优惠券列表
  550 + * @param req
  551 + * @param res
  552 + * @param next
  553 + */
  554 +const getBrandCouponsList = (req, res, next) => {
  555 + let allowOrigin = _.get(req, 'headers.origin', null) ?
  556 + req.headers.origin : req.protocol + '://' + req.headers.host;
  557 +
  558 + res.setHeader('Access-Control-Allow-Origin', allowOrigin);
  559 + res.setHeader('Access-Control-Allow-Credentials', 'true');
  560 +
  561 + let uid = req.query.uid || req.user.uid;
  562 + let brandId = parseInt(req.query.brandId, 10);
  563 + let param = {};
535 564
  565 + if (brandId) {
  566 + if (uid) {
  567 + param.uid = uid;
  568 + }
  569 +
  570 + param.brand_id = brandId;
  571 +
  572 + listModel.brandCouponsList(param).then(result => {
  573 + res.json(result);
  574 + }).catch(next);
  575 + } else {
  576 + res.json([]);
  577 + }
536 }; 578 };
537 579
538 module.exports = { 580 module.exports = {
@@ -545,5 +587,7 @@ module.exports = { @@ -545,5 +587,7 @@ module.exports = {
545 shopFav, 587 shopFav,
546 baseShopFav, 588 baseShopFav,
547 shopCategory, 589 shopCategory,
548 - userCoupon 590 + userCoupon,
  591 + getShopCouponsList,
  592 + getBrandCouponsList
549 }; 593 };
@@ -13,6 +13,24 @@ const newModel = require(`${mRoot}/new`); @@ -13,6 +13,24 @@ const newModel = require(`${mRoot}/new`);
13 const _ = require('lodash'); 13 const _ = require('lodash');
14 const helpers = global.yoho.helpers; 14 const helpers = global.yoho.helpers;
15 15
  16 +// 新品到着(blk)
  17 +const blkNewGoods = (req, res) => {
  18 + let params = Object.assign({
  19 + isblknew: true
  20 + }, req.query);
  21 +
  22 + res.render('search/goods-list', {
  23 + module: 'product',
  24 + page: 'search-list',
  25 + pageHeader: headerModel.setNav({
  26 + navTitle: req.query.title || req.query.sort_name || '新品抢先看'
  27 + }),
  28 + goodList: params,
  29 + showDownloadApp: true,
  30 + pageFooter: true
  31 + });
  32 +};
  33 +
16 // 新品到着 34 // 新品到着
17 const newGoods = (req, res, next) => { 35 const newGoods = (req, res, next) => {
18 let channel = req.cookies._Channel; 36 let channel = req.cookies._Channel;
@@ -45,10 +63,15 @@ const selectNewSale = (req, res, next) => { @@ -45,10 +63,15 @@ const selectNewSale = (req, res, next) => {
45 let params = _.assign({}, req.query); 63 let params = _.assign({}, req.query);
46 64
47 newModel.getSearchData(params).then((result) => { 65 newModel.getSearchData(params).then((result) => {
48 - res.render('search/page', {  
49 - layout: false,  
50 - new: result  
51 - }); 66 + if (result.list.length > 0) {
  67 + res.render('search/page', {
  68 + layout: false,
  69 + new: result.list,
  70 + total: result.total
  71 + });
  72 + } else {
  73 + res.json(result);
  74 + }
52 }).catch(next); 75 }).catch(next);
53 }; 76 };
54 77
@@ -72,6 +95,7 @@ let filter = (req, res, next) => { @@ -72,6 +95,7 @@ let filter = (req, res, next) => {
72 95
73 96
74 module.exports = { 97 module.exports = {
  98 + blkNewGoods,
75 newGoods, 99 newGoods,
76 selectNewSale, 100 selectNewSale,
77 filter 101 filter
@@ -25,7 +25,7 @@ const willStartActivity = { @@ -25,7 +25,7 @@ const willStartActivity = {
25 // 奥莱首页控制器 25 // 奥莱首页控制器
26 exports.index = (req, res, next) => { 26 exports.index = (req, res, next) => {
27 let headerData = headerModel.setNav({ 27 let headerData = headerModel.setNav({
28 - navTitle: 'OUTLET', 28 + navTitle: '奥莱',
29 navBtn: false 29 navBtn: false
30 }); 30 });
31 31
@@ -35,7 +35,8 @@ exports.index = (req, res, next) => { @@ -35,7 +35,8 @@ exports.index = (req, res, next) => {
35 35
36 outletModel.getContent(categoryId, yhChannel, contentcode).then(result => { 36 outletModel.getContent(categoryId, yhChannel, contentcode).then(result => {
37 res.render('outlet', Object.assign({ 37 res.render('outlet', Object.assign({
38 - pageHeader: headerData 38 + pageHeader: headerData,
  39 + title: '奥莱 | Yoho!Buy有货 | 潮流购物逛不停',
39 }, result)); 40 }, result));
40 }).catch(next); 41 }).catch(next);
41 }; 42 };
@@ -66,7 +67,7 @@ exports.activityTime = (req, res, next) => { @@ -66,7 +67,7 @@ exports.activityTime = (req, res, next) => {
66 // 奥莱活动频道列表页 67 // 奥莱活动频道列表页
67 exports.activityList = (req, res, next) => { 68 exports.activityList = (req, res, next) => {
68 let headerData = headerModel.setNav({ 69 let headerData = headerModel.setNav({
69 - navTitle: 'OUTLET', 70 + navTitle: '奥莱',
70 navBtn: false 71 navBtn: false
71 }); 72 });
72 73
@@ -35,7 +35,7 @@ exports.cart = (req, res, next) => { @@ -35,7 +35,7 @@ exports.cart = (req, res, next) => {
35 yhChannel = req.query.yh_channel || '1', 35 yhChannel = req.query.yh_channel || '1',
36 limit = 30; 36 limit = 30;
37 if (_.get(req, 'app.locals.wap.cart.removePrefer', false)) { 37 if (_.get(req, 'app.locals.wap.cart.removePrefer', false)) {
38 - return res.send(''); 38 + return res.send('');
39 } 39 }
40 recommendForYouModel.getPreference({ 40 recommendForYouModel.getPreference({
41 yh_channel: yhChannel, 41 yh_channel: yhChannel,
@@ -55,5 +55,5 @@ exports.cart = (req, res, next) => { @@ -55,5 +55,5 @@ exports.cart = (req, res, next) => {
55 page: 'recommend' 55 page: 'recommend'
56 }); 56 });
57 }).catch(next); 57 }).catch(next);
58 - 58 +
59 }; 59 };
@@ -184,10 +184,16 @@ const search = (req, res, next) => { @@ -184,10 +184,16 @@ const search = (req, res, next) => {
184 184
185 params.isApp = req.yoho.isApp; 185 params.isApp = req.yoho.isApp;
186 searchModel.getSearchData(params).then((result) => { 186 searchModel.getSearchData(params).then((result) => {
187 - res.render('search/page', {  
188 - layout: false,  
189 - new: result  
190 - }); 187 + if (result.list && result.list.length > 0) {
  188 + res.render('search/page', {
  189 + layout: false,
  190 + new: result.list,
  191 + total: result.total
  192 + });
  193 + } else {
  194 + res.json(result);
  195 + }
  196 +
191 }).catch(next); 197 }).catch(next);
192 }; 198 };
193 199
@@ -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, {
@@ -146,7 +147,7 @@ let comments = (params) => { @@ -146,7 +147,7 @@ let comments = (params) => {
146 147
147 if (result.comments && result.comments.length) { 148 if (result.comments && result.comments.length) {
148 if (result.commentsNum) { 149 if (result.commentsNum) {
149 - _.set(data, 'pageHeader.navTitle', `购买评价(${result.commentsNum})`); 150 + _.set(data, 'navTitle', `购买评价(${result.commentsNum})`);
150 } 151 }
151 data.comments = result.comments; 152 data.comments = result.comments;
152 } 153 }
@@ -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}`
@@ -173,7 +174,7 @@ let consults = (params) => { @@ -173,7 +174,7 @@ let consults = (params) => {
173 174
174 if (result[1].list && result[1].list.length) { 175 if (result[1].list && result[1].list.length) {
175 if (result[1].total) { 176 if (result[1].total) {
176 - _.set(data, 'pageHeader.navTitle', `购买咨询(${result[1].total})`); 177 + _.set(data, 'navTitle', `购买咨询(${result[1].total})`);
177 } 178 }
178 data.consults = result[1].list; 179 data.consults = result[1].list;
179 } 180 }
@@ -217,9 +218,9 @@ let addConsult = (uid, productId, content) => { @@ -217,9 +218,9 @@ let addConsult = (uid, productId, content) => {
217 218
218 module.exports = { 219 module.exports = {
219 getCommentInfo, // 商品详情相关,获取评价,来自晒单 220 getCommentInfo, // 商品详情相关,获取评价,来自晒单
220 - comments, // 商品详情相关-购买评价  
221 - consults, // 商品详情相关-购买咨询  
222 - addConsult, // 商品详情相关-添加咨询 221 + comments, // 商品详情相关-购买评价
  222 + consults, // 商品详情相关-购买咨询
  223 + addConsult, // 商品详情相关-添加咨询
223 upvoteConsult, // 咨询点赞 224 upvoteConsult, // 咨询点赞
224 getConsults // 获取咨询 225 getConsults // 获取咨询
225 }; 226 };
  1 +'use strict';
  2 +
  3 +const api = global.yoho.API;
  4 +
  5 +/**
  6 + * [查询商品详情页优惠券]
  7 + * doc: http://git.yoho.cn/yoho-documents/api-interfaces/blob/master/促销/product_detail_page_coupon.md
  8 + */
  9 +exports.queryProdPageCoupons = (uid, skn, brandId) => {
  10 + const param = {
  11 + method: 'app.coupons.queryProdPageCoupons',
  12 + uid,
  13 + skn,
  14 + brandId
  15 + };
  16 +
  17 + return api.get('', param, {cache: true});
  18 +};
  19 +
  20 +/**
  21 + * [用户领券]
  22 + * doc: http://git.yoho.cn/yoho-documents/api-interfaces/blob/master/促销/promotion.md
  23 + */
  24 +exports.getCoupon = (uid, couponId) => {
  25 + const param = {
  26 + method: 'app.promotion.getCoupon',
  27 + uid,
  28 + couponId
  29 + };
  30 +
  31 + return api.post('', param);
  32 +};
@@ -1251,8 +1251,10 @@ const _detailDataPkg = (origin, ua) => { @@ -1251,8 +1251,10 @@ const _detailDataPkg = (origin, ua) => {
1251 1251
1252 dest.preferenceUrl = `/product/detail/preference${extra}`; 1252 dest.preferenceUrl = `/product/detail/preference${extra}`;
1253 } 1253 }
  1254 + dest.brandId = origin.brand_id || 0;
1254 1255
1255 dest.productSkn = origin.product_skn; 1256 dest.productSkn = origin.product_skn;
  1257 + dest.isLimitBuy = Number(origin.isLimitBuy); // 1 限购商品, 0 非限购商品
1256 1258
1257 // 商品信息 1259 // 商品信息
1258 if (origin.goods_list.length) { 1260 if (origin.goods_list.length) {
@@ -1267,7 +1269,7 @@ const _detailDataPkg = (origin, ua) => { @@ -1267,7 +1269,7 @@ const _detailDataPkg = (origin, ua) => {
1267 // colorStorageNum = 0; 1269 // colorStorageNum = 0;
1268 // pagecache重构 1270 // pagecache重构
1269 _.forEach(origin.goods_list, function(value) { 1271 _.forEach(origin.goods_list, function(value) {
1270 - //未上架也显示 1272 + // 未上架也显示
1271 // if (value.status === 0 && !origin.isLimitBuy) { 1273 // if (value.status === 0 && !origin.isLimitBuy) {
1272 // return; 1274 // return;
1273 // } 1275 // }
@@ -1468,7 +1470,15 @@ const _detailDataPkg = (origin, ua) => { @@ -1468,7 +1470,15 @@ const _detailDataPkg = (origin, ua) => {
1468 dest.introUrl = '/product/detail/intro/' + origin.product_skn; 1470 dest.introUrl = '/product/detail/intro/' + origin.product_skn;
1469 dest.id = origin.product_id; 1471 dest.id = origin.product_id;
1470 dest.goodsId = origin.goods_id; 1472 dest.goodsId = origin.goods_id;
  1473 + dest.isDepositAdvance = origin.is_deposit_advance === 'Y'; // 是否定金预售
  1474 + dest.isSeckill = origin.is_secKill === 'Y'; // 是否秒杀
  1475 + dest.isLimitBuy = origin.isLimitBuy; // 是否 限购
  1476 + dest.isPresale = Boolean(origin.expect_arrival_time); // 是否普通预售
1471 1477
  1478 + // 自定义 属性
  1479 + dest.showCoupon = !(
  1480 + dest.isDepositAdvance || dest.isSeckill || dest.isLimitBuy || dest.isPresale
  1481 + ); // 商品有限购、秒杀、定金预售、普通预售 不显示领券
1472 1482
1473 1483
1474 return dest; 1484 return dest;
@@ -1520,7 +1530,7 @@ let getProductAsyncData = (data) => { @@ -1520,7 +1530,7 @@ let getProductAsyncData = (data) => {
1520 finalResult.isStudent = data.isStudent; 1530 finalResult.isStudent = data.isStudent;
1521 return finalResult; 1531 return finalResult;
1522 }); 1532 });
1523 - 1533 +
1524 }); 1534 });
1525 1535
1526 }); 1536 });
@@ -1584,7 +1594,8 @@ let _detailDataPkgAsync = (origin, uid, vipLevel, ua) => { @@ -1584,7 +1594,8 @@ let _detailDataPkgAsync = (origin, uid, vipLevel, ua) => {
1584 } 1594 }
1585 1595
1586 if (origin.is_secKill) { 1596 if (origin.is_secKill) {
1587 - dest.isDepositAdvance = origin.is_deposit_advance;// 判断定金预售字段 1597 + dest.isDepositAdvance = origin.isDeposit_advance;// A定金预售字段 = origin.is_deposit_advance === 'Y'; // 是否定金预售
  1598 + dest.isPresale = Boolean(origin.expect_arrival_time)
1588 } 1599 }
1589 1600
1590 // 商品返回 YOHO 币 1601 // 商品返回 YOHO 币
@@ -1624,7 +1635,7 @@ let _detailDataPkgAsync = (origin, uid, vipLevel, ua) => { @@ -1624,7 +1635,7 @@ let _detailDataPkgAsync = (origin, uid, vipLevel, ua) => {
1624 colorStorageNum = 0; 1635 colorStorageNum = 0;
1625 1636
1626 _.forEach(origin.goods_list, function(value) { 1637 _.forEach(origin.goods_list, function(value) {
1627 - //未上架也显示 1638 + // 未上架也显示
1628 // if (value.status === 0) { 1639 // if (value.status === 0) {
1629 // return; 1640 // return;
1630 // } 1641 // }
@@ -1743,6 +1754,7 @@ let _detailDataPkgAsync = (origin, uid, vipLevel, ua) => { @@ -1743,6 +1754,7 @@ let _detailDataPkgAsync = (origin, uid, vipLevel, ua) => {
1743 } 1754 }
1744 let soldOut = (origin.storage_sum === 0) || (totalStorageNum === 0); // status 1755 let soldOut = (origin.storage_sum === 0) || (totalStorageNum === 0); // status
1745 let notForSale = origin.attribute === 2; 1756 let notForSale = origin.attribute === 2;
  1757 + let preSale = (origin.status === 0 && origin.advance_shelve_time > 0);
1746 1758
1747 // 悬浮的购物车信息 1759 // 悬浮的购物车信息
1748 dest.cartInfo = { 1760 dest.cartInfo = {
@@ -1752,7 +1764,7 @@ let _detailDataPkgAsync = (origin, uid, vipLevel, ua) => { @@ -1752,7 +1764,7 @@ let _detailDataPkgAsync = (origin, uid, vipLevel, ua) => {
1752 }; 1764 };
1753 1765
1754 // 显示加入购物车链接 1766 // 显示加入购物车链接
1755 - if (!soldOut && !notForSale || origin.isLimitBuy) { 1767 + if (!soldOut && !notForSale && !preSale || origin.isLimitBuy) {
1756 _.orderBy(colorGroup); 1768 _.orderBy(colorGroup);
1757 Object.assign(dest.cartInfo, { 1769 Object.assign(dest.cartInfo, {
1758 productId: origin.product_id, 1770 productId: origin.product_id,
@@ -1807,12 +1819,15 @@ let _detailDataPkgAsync = (origin, uid, vipLevel, ua) => { @@ -1807,12 +1819,15 @@ let _detailDataPkgAsync = (origin, uid, vipLevel, ua) => {
1807 origin.goods_id + '.html'); 1819 origin.goods_id + '.html');
1808 return callback(); 1820 return callback();
1809 } 1821 }
1810 - } else if (notForSale) { 1822 + } else if (notForSale && !preSale) {
1811 dest.cartInfo.notForSale = true; 1823 dest.cartInfo.notForSale = true;
1812 return callback(); 1824 return callback();
1813 - } else if (soldOut) { 1825 + } else if (soldOut && !preSale) {
1814 dest.cartInfo.soldOut = true; 1826 dest.cartInfo.soldOut = true;
1815 return callback(); 1827 return callback();
  1828 + } else if (preSale) {
  1829 + dest.cartInfo.preSale = true;
  1830 + return callback();
1816 } 1831 }
1817 1832
1818 // 是否收藏 使用单独收藏接口获取 1833 // 是否收藏 使用单独收藏接口获取