Authored by htoooth

Merge branch 'master' into release/6.0

1 -web: npm run dev  
2 -gulp: gulp --cwd=public  
3 proxy: d:\dev\traefik\traefik.exe -c d:\dev\traefik\conf.toml 1 proxy: d:\dev\traefik\traefik.exe -c d:\dev\traefik\conf.toml
4 mem: d:\dev\memcached\memcached.exe 2 mem: d:\dev\memcached\memcached.exe
@@ -20,14 +20,17 @@ const removeBlack = (remoteIp) => { @@ -20,14 +20,17 @@ const removeBlack = (remoteIp) => {
20 keyMax = `pc:limiter:max:${remoteIp}`, 20 keyMax = `pc:limiter:max:${remoteIp}`,
21 key10mMax = `pc:limiter:10m:max:${remoteIp}`, 21 key10mMax = `pc:limiter:10m:max:${remoteIp}`,
22 synchronizeKey = `pc:limiter:synchronize:${remoteIp}`, 22 synchronizeKey = `pc:limiter:synchronize:${remoteIp}`,
  23 + asynchronousKey = `pc:limiter:asynchronous:${remoteIp}`,
23 spiderKey = `pc:limiter:spider:${remoteIp}`; 24 spiderKey = `pc:limiter:spider:${remoteIp}`;
24 25
  26 +
25 return Promise.all([ 27 return Promise.all([
26 cache.delAsync(key), 28 cache.delAsync(key),
27 cache.delAsync(key10m), 29 cache.delAsync(key10m),
28 cache.delAsync(keyMax), 30 cache.delAsync(keyMax),
29 cache.delAsync(key10mMax), 31 cache.delAsync(key10mMax),
30 cache.delAsync(synchronizeKey), 32 cache.delAsync(synchronizeKey),
  33 + cache.delAsync(asynchronousKey),
31 cache.delAsync(spiderKey) 34 cache.delAsync(spiderKey)
32 ]); 35 ]);
33 }; 36 };
@@ -9,11 +9,7 @@ @@ -9,11 +9,7 @@
9 </ul> 9 </ul>
10 </div> 10 </div>
11 <div class="main-container"> 11 <div class="main-container">
12 - {{#if devEnv}}  
13 - <img src="//webstatic.dev.yohobuy.com/img/about/aboutnewpower.png?random=1466056691"/>  
14 - {{^}}  
15 - <img src="//cdn.yoho.cn/yohobuy/assets/img/about/aboutnewpower.png?random=1466056691"/>  
16 - {{/if}} 12 + <img src="//cdn.yoho.cn/yohobuy/assets/img/about/aboutnewpower.png?random=1466056691"/>
17 <div class="text-info"> 13 <div class="text-info">
18 <p style="font-family:微软雅黑; text-align:left;"> 14 <p style="font-family:微软雅黑; text-align:left;">
19 <span style="font-size:18px; line-height:68px;">一、公司概况:</span> 15 <span style="font-size:18px; line-height:68px;">一、公司概况:</span>
@@ -25,7 +21,7 @@ @@ -25,7 +21,7 @@
25 <br/> 21 <br/>
26 1、平面杂志及电子平台 22 1、平面杂志及电子平台
27 <br/> 23 <br/>
28 - &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;《YOHO!潮流志》、《YOHO!GIRL》是YOHO!旗下在国内潮流领域具有深厚影响力的杂志媒体。《YOHO!潮流志》2005 年10月创刊。他是国内第一本完全原创版权的,提供潮流和 lifestyle 资讯,属于年轻人的潮流时尚半月刊,通过正规发行渠道(报刊亭、连锁商超等)发行至全国各大中城市,深受全国年轻人的喜爱。设计给国内年轻女性的中高端时装月刊《YOHO!GIRL》,2013年3月正式创刊,在香港、大陆以及日本东京茑屋地区同步发行。以大量独家资讯加上独特的编采手法,改变读者的阅读习惯,扩阔大家在时装、美容、设计、生活、次文化等各方面的视野。深入结构品牌背后的哲学和时装趋势,带领各读者一探最新时尚。 24 + &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;《YOHO!潮流志》、《YOHO!GIRL》是YOHO!旗下在国内潮流领域具有深厚影响力的杂志媒体。《YOHO!潮流志》2005 年10月创刊。他是一本完全原创版权并提供潮流和 lifestyle 资讯的属于年轻人的潮流时尚半月刊,通过正规发行渠道(报刊亭、连锁商超等)发行至全国各大中城市,深受全国年轻人的喜爱。设计给国内年轻女性的中高端时装月刊《YOHO!GIRL》,2013年3月正式创刊,在香港、大陆以及日本东京茑屋地区同步发行。以大量资讯加上独特的编采手法,改变读者的阅读习惯,扩阔大家在时装、美容、设计、生活、次文化等各方面的视野。深入结构品牌背后的哲学和时装趋势,带领各读者一探时尚。
29 <br/> 25 <br/>
30 <br/> 26 <br/>
31 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;YOHO!作为中国权威的潮流杂志电子平台,无论是影响力或发行量均名列前茅。“Yoho!Now”于 iOS 和 Android平台触亮全球潮流资讯,“Yoho!Now”7*24h 无休供应时装、运动、设计、科技、美容、家居、趣闻等严选潮流营养,并于每周发布特别线上专题,与读者Play and Learn。《YOHO!潮流志》和《YOHO!GIRL》亦于各自App內每周上架新鲜线上周刊,打包纸质版内容精华,汇通YOHO!潮流矩阵。 27 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;YOHO!作为中国权威的潮流杂志电子平台,无论是影响力或发行量均名列前茅。“Yoho!Now”于 iOS 和 Android平台触亮全球潮流资讯,“Yoho!Now”7*24h 无休供应时装、运动、设计、科技、美容、家居、趣闻等严选潮流营养,并于每周发布特别线上专题,与读者Play and Learn。《YOHO!潮流志》和《YOHO!GIRL》亦于各自App內每周上架新鲜线上周刊,打包纸质版内容精华,汇通YOHO!潮流矩阵。
@@ -33,12 +29,12 @@ @@ -33,12 +29,12 @@
33 <br/> 29 <br/>
34 2、关于“Yoho!Buy有货” 30 2、关于“Yoho!Buy有货”
35 <br/> 31 <br/>
36 - &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;“Yoho!Buy有货”(www.yohobuy.com)——年轻人潮流购物中心,同样秉承YOHO!“年轻是种态度”的口号,Yoho!Buy有货专注于中国潮流趋势和受众的需要,凭借专业的买手团队和对中国潮流趋势敏锐的嗅觉,积极开拓符合中国年轻人喜爱的品牌和商品。销售包括国际知名、日韩港台流行、明星设计师、内地原创等等超过1400 个潮流品牌商品,满足18-35岁年轻群体的时尚个性化述求,涵盖男女服装、鞋帽、配件、童装及创意生活用品等。Yoho!Buy有货所销售的品牌均与品牌直接签订销售协议,保持货品与国际国内实体店铺同步,通过独家定制、限定发售、明星合作品牌等,并结合“逛”内容频道及社区互动引导消费。Yoho!Buy有货已成为中国年轻态群体喜爱的潮流购物平台。 32 + &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;“Yoho!Buy有货”(www.yohobuy.com)——年轻人潮流购物中心,同样秉承YOHO!“年轻是种态度”的口号,Yoho!Buy有货专注于中国潮流趋势和受众的需要,凭借专业的买手团队和对中国潮流趋势敏锐的嗅觉,积极开拓符合中国年轻人喜爱的品牌和商品。销售包括国际知名、日韩港台流行、明星设计师、内地原创等等超过1400 个潮流品牌商品,满足18-35岁年轻群体的时尚个性化述求,涵盖男女服装、鞋帽、配件、童装及创意生活用品等。Yoho!Buy有货所销售的品牌均与品牌直接签订销售协议,保持货品与国际国内实体店铺同步,通过定制、限定发售、明星合作品牌等,并结合“逛”内容频道及社区互动引导消费。Yoho!Buy有货已成为中国年轻态群体热爱的潮流购物平台。
37 <br/> 33 <br/>
38 <br/> 34 <br/>
39 3、关于“mars - 新鲜好去处” 35 3、关于“mars - 新鲜好去处”
40 <br/> 36 <br/>
41 - &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;“mars - 新鲜好去处”是一款由YOHO!出品的潮流生活应用,立志为百万年轻人打造酷炫的“城市探索”线上枢纽。连续两周被 Apple 评选为App Store“最佳新应用”,并获得 2016 年“一月最佳 App”、“最佳生活 App”等推荐。mars深入探索全球热点城市潮流坐标,现已上线北京、上海、成都、台北、香港、东京、首尔、纽约、洛杉矶等城市,未来还将陆续上线更多城市。集优质潮流攻略、专属玩乐线路、每日热点话题等功能,邀集世界各地时髦生活方式达人与所有用户分享好去处,让潮流随时、随地、随享。我们的目标就是带你去那些“如果你不用 mars 可能一辈子都不知道”的潮流好去处。 37 + &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;“mars - 新鲜好去处”是一款由YOHO!出品的潮流生活应用,立志为百万年轻人打造酷炫的“城市探索”线上枢纽。多次被 Apple 的 App Store 官方推荐。mars深入探索全球热点城市潮流坐标,现已上线北京、上海、成都、台北、香港、东京、首尔、纽约、洛杉矶等城市,未来还将陆续上线更多城市。集优质潮流攻略、专属玩乐线路、每日热点话题等功能,邀集世界各地时髦生活方式达人与所有用户分享好去处,让潮流随时、随地、随享。我们的目标就是带你去那些“如果你不用 mars 可能一辈子都不知道”的潮流好去处。
42 </p> 38 </p>
43 </div> 39 </div>
44 </div> 40 </div>
@@ -19,14 +19,11 @@ @@ -19,14 +19,11 @@
19 <p style="font-family:微软雅黑; text-align:left;"> 19 <p style="font-family:微软雅黑; text-align:left;">
20 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;“Yoho!Buy 有货”( 20 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;“Yoho!Buy 有货”(
21 <a style=" font:#000;" href="//www.yohobuy.com" target="_blank">www.yohobuy.com</a> 21 <a style=" font:#000;" href="//www.yohobuy.com" target="_blank">www.yohobuy.com</a>
22 - )——年轻人潮流购物中心,同样秉承YOHO!“年轻是种态度”的口号,Yoho!Buy有货专注于中国潮流趋势和受众的需要,凭借专业的买手团队和对中国潮流趋势敏锐的嗅觉,积极开拓符合中国年轻人喜爱的品牌和商品。销售包括国际知名、日韩港台流行、明星设计师、内地原创等等超过1400 个潮流品牌商品,满足18-35岁年轻群体的时尚个性化述求,涵盖男女服装、鞋帽、配件、童装及创意生活用品等。Yoho!Buy有货所销售的品牌均与品牌直接签订销售协议,保持货品与国际国内实体店铺同步,通过独家定制、限定发售、明星合作品牌等,并结合“逛”内容频道及社区互动引导消费。Yoho!Buy有货已成为中国年轻态群体最喜爱的潮流购物平台。<br> 22 + )——年轻人潮流购物中心,同样秉承YOHO!“年轻是种态度”的口号,Yoho!Buy有货专注于中国潮流趋势和受众的需要,凭借专业的买手团队和对中国潮流趋势敏锐的嗅觉,积极开拓符合中国年轻人喜爱的品牌和商品。销售包括国际知名、日韩港台流行、明星设计师、内地原创等等超过1400 个潮流品牌商品,满足18-35岁年轻群体的时尚个性化述求,涵盖男女服装、鞋帽、配件、童装及创意生活用品等。Yoho!Buy有货所销售的品牌均与品牌直接签订销售协议,保持货品与国际国内实体店铺同步,通过定制、限定发售、明星合作品牌等,并结合“逛”内容频道及社区互动引导消费。Yoho!Buy有货已成为中国年轻态群体热爱的潮流购物平台。
  23 + <br>
23 </p> 24 </p>
24 <p> 25 <p>
25 - {{#if devEnv}}  
26 - <img src="//webstatic.dev.yohobuy.com/img/about/about_yohobuy.jpg?random=1466056691" />  
27 - {{^}}  
28 - <img src="//cdn.yoho.cn/yohobuy/assets/img/about/about_yohobuy.jpg?random=1466056691" />  
29 - {{/if}} 26 + <img src="//img11.static.yhbimg.com/evidenceImages/2017/07/11/16/01e66a43c7eff25fef57e5c9795474bddc.jpg" />
30 </p> 27 </p>
31 </div> 28 </div>
32 </div> 29 </div>
@@ -11,7 +11,7 @@ const suggestFeedBackModel = require('../models/suggestFeedBack-service'); @@ -11,7 +11,7 @@ const suggestFeedBackModel = require('../models/suggestFeedBack-service');
11 11
12 const getFeedBack = (req, res, next) => { 12 const getFeedBack = (req, res, next) => {
13 13
14 - suggestFeedBackModel.suggestFeedBack().then((result) => { 14 + suggestFeedBackModel.suggestFeedBack(req.user.uid).then((result) => {
15 res.jsonp(result); 15 res.jsonp(result);
16 }).catch(next); 16 }).catch(next);
17 }; 17 };
@@ -14,9 +14,9 @@ const URL_ACTIVITY_QUESTION = '/activity/question/'; @@ -14,9 +14,9 @@ const URL_ACTIVITY_QUESTION = '/activity/question/';
14 * @param uid 14 * @param uid
15 * @return string 15 * @return string
16 */ 16 */
17 -const feedBackApi = () => { 17 +const feedBackApi = (uid) => {
18 18
19 - return service.get(URL_ACTIVITY_QUESTION + 'questionList', {}); 19 + return service.get(URL_ACTIVITY_QUESTION + 'questionList', {uid: uid});
20 }; 20 };
21 21
22 module.exports = { 22 module.exports = {
@@ -9,9 +9,9 @@ const api = require('./suggestFeedBack-api'); @@ -9,9 +9,9 @@ const api = require('./suggestFeedBack-api');
9 const helpers = global.yoho.helpers; 9 const helpers = global.yoho.helpers;
10 const _ = require('lodash'); 10 const _ = require('lodash');
11 11
12 -const suggestFeedBack = () => { 12 +const suggestFeedBack = (uid) => {
13 13
14 - return api.feedBackApi().then((result) => { 14 + return api.feedBackApi(uid).then((result) => {
15 let suggestData = []; 15 let suggestData = [];
16 16
17 if (result && result.code === 200 && _.get(result, 'data.rows')) { 17 if (result && result.code === 200 && _.get(result, 'data.rows')) {
@@ -210,23 +210,29 @@ const keyId = (req, res, next) => { @@ -210,23 +210,29 @@ const keyId = (req, res, next) => {
210 let params = req.query; 210 let params = req.query;
211 let id = req.params.id; 211 let id = req.params.id;
212 212
213 - return search.getSearchKeywordDataById(id, params, req.yoho.channel).then(result => {  
214 - let query = result.queryKey;  
215 -  
216 - Object.assign(result, {  
217 - pageNoFollow: true,  
218 - title: `${query}价格_图片_品牌_怎么样-YOHO!BUY有货`,  
219 - keywords: `${query},${query}价格,${query}图片,${query}怎么样,${query}品牌,YOHO!BUY有货`,  
220 - description: `YOHO!BUY有货网yohobuy.com是国内专业的${query}网上潮流购物商城,为您找到${_.get(result, 213 + return search.getSearchKeywordDataById(id, Object.assign({stocknumber: -1}, params),
  214 + req.yoho.channel).then(result => {
  215 +
  216 + if (!result) {
  217 + return next();
  218 + }
  219 +
  220 + let query = result.queryKey;
  221 +
  222 + Object.assign(result, {
  223 + pageNoFollow: true,
  224 + title: `${query}价格_图片_品牌_怎么样-YOHO!BUY有货`,
  225 + keywords: `${query},${query}价格,${query}图片,${query}怎么样,${query}品牌,YOHO!BUY有货`,
  226 + description: `YOHO!BUY有货网yohobuy.com是国内专业的${query}网上潮流购物商城,为您找到${_.get(result,
221 'search.totalCount', 0)}${query}、产品的详细参数,实时报价,价格行情,图片、评价、品牌等信息。买${query},就上YOHO!BUY有货` 227 'search.totalCount', 0)}${query}、产品的详细参数,实时报价,价格行情,图片、评价、品牌等信息。买${query},就上YOHO!BUY有货`
222 - }); 228 + });
223 229
224 - if (!_.get(result, 'search.goods') || !_.get(result, 'search.goods').length) {  
225 - _.set(result, 'search.keyWord', query);  
226 - return res.render('search/no-result', result);  
227 - }  
228 - res.render('search/index', result);  
229 - }).catch(next); 230 + if (!_.get(result, 'search.goods') || !_.get(result, 'search.goods').length) {
  231 + _.set(result, 'search.keyWord', query);
  232 + return res.render('search/no-result', result);
  233 + }
  234 + res.render('search/index', result);
  235 + }).catch(next);
230 }; 236 };
231 237
232 module.exports = { 238 module.exports = {
@@ -56,7 +56,7 @@ const indexAsync = pid => { @@ -56,7 +56,7 @@ const indexAsync = pid => {
56 marketPrice: cur.product.productPriceBo.formatMarketPrice, 56 marketPrice: cur.product.productPriceBo.formatMarketPrice,
57 productName: cur.product.productName, 57 productName: cur.product.productName,
58 href: helpers.getUrlBySkc( 58 href: helpers.getUrlBySkc(
59 - _.get(goods, 'goodsImagesList[0].productSkn', '')) 59 + _.get(cur.product, 'productPriceBo.productSkn', ''))
60 }; 60 };
61 acc.push(point); 61 acc.push(point);
62 62
@@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
6 6
7 const api = global.yoho.API; 7 const api = global.yoho.API;
8 const config = global.yoho.config; 8 const config = global.yoho.config;
  9 +const redis = global.yoho.redis;
9 10
10 /** 11 /**
11 * 商品的 banner 12 * 商品的 banner
@@ -131,8 +132,8 @@ const getShopRecommendAsync = (skn, page, limit) => { @@ -131,8 +132,8 @@ const getShopRecommendAsync = (skn, page, limit) => {
131 return api.get('', { 132 return api.get('', {
132 method: 'web.product.shopRecommend', 133 method: 'web.product.shopRecommend',
133 product_skn: skn, 134 product_skn: skn,
134 - page: page,  
135 - limit: limit 135 + page: page || 1,
  136 + limit: limit || 20
136 }); 137 });
137 }; 138 };
138 139
@@ -146,6 +147,24 @@ const getBundleAsync = (skn) => { @@ -146,6 +147,24 @@ const getBundleAsync = (skn) => {
146 }); 147 });
147 }; 148 };
148 149
  150 +/**
  151 + * 找相似
  152 + */
  153 +const getLikeAsync = (skn, limit) => {
  154 + return api.get('', {
  155 + method: 'app.search.findLike',
  156 + limit: limit || 10,
  157 + product_skn: skn
  158 + });
  159 +};
  160 +
  161 +// 根据small_sort从redis获取分类下的关键词
  162 +const getRecommendKeywords = (smallSort) => {
  163 + return redis.all([['get', `golobal:yoho:seo:keywords:sortId:${smallSort}`]]).then(res => {
  164 + return res[0];
  165 + });
  166 +};
  167 +
149 module.exports = { 168 module.exports = {
150 getProductBannerAsync, 169 getProductBannerAsync,
151 sizeInfoAsync, 170 sizeInfoAsync,
@@ -156,5 +175,7 @@ module.exports = { @@ -156,5 +175,7 @@ module.exports = {
156 isSupportReturnedSale, 175 isSupportReturnedSale,
157 getLimitedProductStatusAsync, 176 getLimitedProductStatusAsync,
158 getShopRecommendAsync, 177 getShopRecommendAsync,
159 - getBundleAsync 178 + getBundleAsync,
  179 + getLikeAsync,
  180 + getRecommendKeywords
160 }; 181 };
@@ -35,6 +35,7 @@ const BLANK_STR = ' '; @@ -35,6 +35,7 @@ const BLANK_STR = ' ';
35 const BUNDLE_PRODUCE = 2; // 量贩 35 const BUNDLE_PRODUCE = 2; // 量贩
36 const BUNDLE_PACKAGE = 1; // 套餐 36 const BUNDLE_PACKAGE = 1; // 套餐
37 const tdk = require('../../../utils/getTDK'); 37 const tdk = require('../../../utils/getTDK');
  38 +const Helpers = global.yoho.helpers;
38 39
39 const _getProductAdditionInfoAsync = (data) => { 40 const _getProductAdditionInfoAsync = (data) => {
40 return co(function * () { 41 return co(function * () {
@@ -1007,6 +1008,19 @@ const _getIntroInfo = (productSkn, maxSortId, additionalData)=> { @@ -1007,6 +1008,19 @@ const _getIntroInfo = (productSkn, maxSortId, additionalData)=> {
1007 return result; 1008 return result;
1008 }; 1009 };
1009 1010
  1011 +// 返回6条推荐关键词页面
  1012 +const getKeywordsInfo = (keywords) => {
  1013 + let res = [];
  1014 +
  1015 + _.forEach(_.slice(_.shuffle(keywords), 0, 12), val => {
  1016 + res.push({
  1017 + url: Helpers.urlFormat(`/chanpin/${val.id}.html`),
  1018 + keyword: val.keyword
  1019 + });
  1020 + });
  1021 + return res;
  1022 +};
  1023 +
1010 /** 1024 /**
1011 * 获取seo信息 1025 * 获取seo信息
1012 * 1026 *
@@ -1101,6 +1115,9 @@ const _detailDataPkg = (origin, uid, vipLevel, cookies) => { @@ -1101,6 +1115,9 @@ const _detailDataPkg = (origin, uid, vipLevel, cookies) => {
1101 return result; 1115 return result;
1102 } 1116 }
1103 1117
  1118 + // sku商品信息,尺寸信息
  1119 + let skuData = _getSkuDataByProductBaseInfo(origin);
  1120 +
1104 result.name = propOrigin('product_name'); 1121 result.name = propOrigin('product_name');
1105 result.skn = propOrigin('product_skn'); 1122 result.skn = propOrigin('product_skn');
1106 result.productId = propOrigin('product_id'); 1123 result.productId = propOrigin('product_id');
@@ -1143,6 +1160,17 @@ const _detailDataPkg = (origin, uid, vipLevel, cookies) => { @@ -1143,6 +1160,17 @@ const _detailDataPkg = (origin, uid, vipLevel, cookies) => {
1143 requestApi.bundle = productAPI.getBundleAsync(result.skn); // 量贩 1160 requestApi.bundle = productAPI.getBundleAsync(result.skn); // 量贩
1144 } 1161 }
1145 1162
  1163 + // 找相似
  1164 + if (skuData.totalStorageNum === 0) {
  1165 + requestApi.alike = productAPI.getLikeAsync(result.skn);
  1166 + }
  1167 +
  1168 + // 相关推荐词
  1169 + requestApi.recommendKeywords = productAPI.getRecommendKeywords(result.smallSortId);
  1170 +
  1171 + // 店铺推荐直出(seo需要)
  1172 + requestApi.shopRecommend = productAPI.getShopRecommendAsync(result.skn);
  1173 +
1146 let requestData = yield Promise.props(requestApi); 1174 let requestData = yield Promise.props(requestApi);
1147 1175
1148 let additionalData = requestData.addition; 1176 let additionalData = requestData.addition;
@@ -1151,6 +1179,20 @@ const _detailDataPkg = (origin, uid, vipLevel, cookies) => { @@ -1151,6 +1179,20 @@ const _detailDataPkg = (origin, uid, vipLevel, cookies) => {
1151 let coupon = requestData.coupon; 1179 let coupon = requestData.coupon;
1152 let limitedInfo = requestData.limited; 1180 let limitedInfo = requestData.limited;
1153 let bundle = requestData.bundle; 1181 let bundle = requestData.bundle;
  1182 + let recommendKeywords = requestData.recommendKeywords ? JSON.parse(requestData.recommendKeywords) : [];
  1183 +
  1184 + // 处理相似商品
  1185 + result.alike = _.map(_.get(requestData, 'alike.data.product_list', ''), val =>{
  1186 + return Object.assign({url: Helpers.getUrlBySkc(val.product_skn)}, val);
  1187 + });
  1188 +
  1189 + // 推荐关键词页面
  1190 + result.recommendKeywords = getKeywordsInfo(recommendKeywords);
  1191 +
  1192 + // 处理店铺推荐
  1193 + result.shopRecommend = _.map(_.get(requestData, 'shopRecommend.data.product_list', ''), val =>{
  1194 + return Object.assign({url: Helpers.getUrlBySkc(val.product_skn)}, val);
  1195 + });
1154 1196
1155 // 商品标签 1197 // 商品标签
1156 result.tags = _getTagsDataByProductInfo(origin); 1198 result.tags = _getTagsDataByProductInfo(origin);
@@ -1238,9 +1280,6 @@ const _detailDataPkg = (origin, uid, vipLevel, cookies) => { @@ -1238,9 +1280,6 @@ const _detailDataPkg = (origin, uid, vipLevel, cookies) => {
1238 result.presale = 'Y'; 1280 result.presale = 'Y';
1239 } 1281 }
1240 1282
1241 - // sku商品信息,尺寸信息  
1242 - let skuData = _getSkuDataByProductBaseInfo(origin);  
1243 -  
1244 result.img = skuData.defaultImage; 1283 result.img = skuData.defaultImage;
1245 result.colors = skuData.skuGoods; 1284 result.colors = skuData.skuGoods;
1246 let totalStorageNum = skuData.totalStorageNum; 1285 let totalStorageNum = skuData.totalStorageNum;
@@ -1719,7 +1758,6 @@ const getPackage = co(function * (skn) { @@ -1719,7 +1758,6 @@ const getPackage = co(function * (skn) {
1719 return resData; 1758 return resData;
1720 }); 1759 });
1721 1760
1722 -  
1723 module.exports = { 1761 module.exports = {
1724 getShareOrderListAsync: commentService.getShareOrderListAsync, // 获取评论列表 1762 getShareOrderListAsync: commentService.getShareOrderListAsync, // 获取评论列表
1725 indexConsultAsync: consultService.indexAsync, // 获取咨询列表 1763 indexConsultAsync: consultService.indexAsync, // 获取咨询列表
@@ -419,8 +419,7 @@ exports.getSearchKeywordDataById = (id, params, channel) => { @@ -419,8 +419,7 @@ exports.getSearchKeywordDataById = (id, params, channel) => {
419 ]); 419 ]);
420 420
421 if (!redisData[0]) { 421 if (!redisData[0]) {
422 - return Promise.reject('get redis canpin keywords by id error!' +  
423 - `key: golobal:yoho:seo:keywords:id:${id} value: ${redisData[0]}`); 422 + return false;
424 } 423 }
425 424
426 redisData = JSON.parse(redisData[0]); 425 redisData = JSON.parse(redisData[0]);
@@ -23,6 +23,8 @@ @@ -23,6 +23,8 @@
23 23
24 <div id="package" class="package-box clearfix hide"></div> 24 <div id="package" class="package-box clearfix hide"></div>
25 25
  26 + {{> product/alike}}
  27 +
26 <div class="total-content"> 28 <div class="total-content">
27 <div class="other-infos"> 29 <div class="other-infos">
28 {{> product/description}} 30 {{> product/description}}
@@ -39,6 +41,8 @@ @@ -39,6 +41,8 @@
39 41
40 {{> product/after-service}} 42 {{> product/after-service}}
41 43
  44 + {{> product/recommend-keywords}}
  45 +
42 {{> product/recommend-receiveview}} 46 {{> product/recommend-receiveview}}
43 47
44 </div> 48 </div>
  1 +{{#if goodsInfo.alike}}
  2 + <div class="bottom-tab alike-title">
  3 + <p>
  4 + <span class="bottom-title bottom-cur">相似商品</span>
  5 + <span class="bottom-title change">换一批
  6 + <span class="iconfont change-icon">&#xe6d3;</span>
  7 + </span>
  8 + </p>
  9 + </div>
  10 +
  11 + <div class="individual-comment info-block info-bottom alike">
  12 + <div>
  13 + <div class="recommend-content clearfix">
  14 + <div class="recommend-slider-alike">
  15 + <ul class=" img-list">
  16 + {{# goodsInfo.alike}}
  17 + <li class="img-item">
  18 + <span class="hide goods-id">{{goods_id}}</span>
  19 + <div class="good">
  20 + <a href="{{url}}" target="_blank">
  21 + <img class="lazy" src="{{image2 default_images w=280 h=382}}"/>
  22 + </a>
  23 + <a class="name" href="{{url}}" target="_blank">{{product_name}}</a>
  24 + <p class="price">
  25 + <span class="market-price">¥{{market_price}}</span>
  26 + <span class="sale-price">¥{{sales_price}}</span>
  27 + </p>
  28 + </div>
  29 + </li>
  30 + {{/goodsInfo.alike}}
  31 + </ul>
  32 + <div class="img-brand-switch">
  33 + <a class="prev iconfont" href="javascript:;">&#xe609;</a>
  34 + <a class="next iconfont" href="javascript:;">&#xe608;</a>
  35 + </div>
  36 + </div>
  37 + </div>
  38 + </div>
  39 + </div>
  40 +{{/if}}
  1 +{{#if goodsInfo.recommendKeywords}}
  2 + <div class="recommend-keywords">
  3 + <h3>相关推荐</h3>
  4 + <p>
  5 + {{# goodsInfo.recommendKeywords}}
  6 + <a href="{{url}}" title="{{keyword}}" target="_blank">{{keyword}}</a>
  7 + {{/ goodsInfo.recommendKeywords}}
  8 + </p>
  9 + </div>
  10 +{{/if}}
@@ -25,17 +25,34 @@ @@ -25,17 +25,34 @@
25 {{> product/latest-walk-tpl}} 25 {{> product/latest-walk-tpl}}
26 </div> 26 </div>
27 {{/if}} 27 {{/if}}
28 -  
29 - <div id="recommend-shop" class="hide">  
30 - <div class="recommend-content clearfix">  
31 - <div class="recommend-slider">  
32 - <ul class=" img-list" id="recommend-content"></ul>  
33 - <div class="img-brand-switch">  
34 - <a class="prev iconfont" href="javascript:;">&#xe609;</a>  
35 - <a class="next iconfont" href="javascript:;">&#xe608;</a> 28 + {{#if goodsInfo.shopRecommend}}
  29 + <div id="recommend-shop">
  30 + <div class="recommend-content clearfix">
  31 + <div class="recommend-slider">
  32 + <ul class=" img-list" id="recommend-content">
  33 + {{# goodsInfo.shopRecommend}}
  34 + <li class="img-item">
  35 + <span class="hide goods-id">{{goods_id}}</span>
  36 + <div class="good">
  37 + <a href="{{url}}" target="_blank">
  38 + <img class="lazy" src="{{image2 default_images w=280 h=382}}"/>
  39 + </a>
  40 + <a class="name" href="{{url}}" target="_blank">{{product_name}}</a>
  41 + <p class="price">
  42 + <span class="market-price">¥{{market_price}}</span>
  43 + <span class="sale-price">¥{{sales_price}}</span>
  44 + </p>
  45 + </div>
  46 + </li>
  47 + {{/ goodsInfo.shopRecommend}}
  48 + </ul>
  49 + <div class="img-brand-switch">
  50 + <a class="prev iconfont" href="javascript:;">&#xe609;</a>
  51 + <a class="next iconfont" href="javascript:;">&#xe608;</a>
  52 + </div>
36 </div> 53 </div>
37 </div> 54 </div>
38 </div> 55 </div>
39 - </div> 56 + {{/if}}
40 </div> 57 </div>
41 {{/unless}} 58 {{/unless}}
@@ -37,11 +37,11 @@ module.exports = (req, res, next) => { @@ -37,11 +37,11 @@ module.exports = (req, res, next) => {
37 remoteIp = req.get('X-Real-IP'); 37 remoteIp = req.get('X-Real-IP');
38 } 38 }
39 39
40 - logger.info('request remote ip: ', remoteIp);  
41 -  
42 const excluded = _.includes(IP_WHITE_LIST, remoteIp); 40 const excluded = _.includes(IP_WHITE_LIST, remoteIp);
43 const enabled = !_.get(req.app.locals, 'pc.sys.noLimiter'); 41 const enabled = !_.get(req.app.locals, 'pc.sys.noLimiter');
44 42
  43 + logger.info(`request remote ip: ${remoteIp}; excluded: ${excluded}; enabled: ${enabled}`);
  44 +
45 // 判断获取remoteIp成功,并且开关未关闭 45 // 判断获取remoteIp成功,并且开关未关闭
46 if (enabled && remoteIp && !excluded) { 46 if (enabled && remoteIp && !excluded) {
47 const context = { 47 const context = {
@@ -47,6 +47,7 @@ module.exports = (limiter, policy) => { @@ -47,6 +47,7 @@ module.exports = (limiter, policy) => {
47 logger.debug(results); 47 logger.debug(results);
48 48
49 if (results[spiderKey]) { 49 if (results[spiderKey]) {
  50 + logger.info(results);
50 return Promise.resolve(policy); 51 return Promise.resolve(policy);
51 } 52 }
52 53
@@ -63,6 +64,7 @@ module.exports = (limiter, policy) => { @@ -63,6 +64,7 @@ module.exports = (limiter, policy) => {
63 64
64 if (results[synchronizeKey] > 10 && !results[asynchronousKey]) { 65 if (results[synchronizeKey] > 10 && !results[asynchronousKey]) {
65 cache.setAsync(spiderKey, 1, 60 * 60 * 24); 66 cache.setAsync(spiderKey, 1, 60 * 60 * 24);
  67 + logger.info(results);
66 return Promise.resolve(policy); 68 return Promise.resolve(policy);
67 } 69 }
68 70
@@ -3,6 +3,8 @@ const _ = require('lodash'); @@ -3,6 +3,8 @@ const _ = require('lodash');
3 const redis = require('redis'); 3 const redis = require('redis');
4 const bluebird = require('bluebird'); 4 const bluebird = require('bluebird');
5 const config = require('../../config/common'); 5 const config = require('../../config/common');
  6 +const logger = global.yoho.logger;
  7 +const timeout = 200; // redis 操作超时时间
6 let client; 8 let client;
7 9
8 try { 10 try {
@@ -20,9 +22,14 @@ try { @@ -20,9 +22,14 @@ try {
20 } 22 }
21 } 23 }
22 24
23 - return client.multi.call(client, args).execAsync(); 25 + return client.multi.call(client, args).execAsync().timeout(timeout).catch(()=>{
  26 + logger.err('redis exe time out');
  27 + return false;
  28 + });
24 }; 29 };
25 30
  31 +
  32 +
26 client.on('error', function() { 33 client.on('error', function() {
27 global.yoho.redis = ''; 34 global.yoho.redis = '';
28 }); 35 });
@@ -282,7 +282,7 @@ @@ -282,7 +282,7 @@
282 <p> 282 <p>
283 <a href="//www.yohobuy.com">返回首页</a> 283 <a href="//www.yohobuy.com">返回首页</a>
284 <span>|</span> 284 <span>|</span>
285 - <a href="//www.yohobuy.com">YOHO!BUY 有货</a> 285 + <a href="//www.yohobuy.com/yohobuy.html">YOHO!BUY 有货</a>
286 <span>|</span> 286 <span>|</span>
287 <a href="//www.yohobuy.com/newpower.html" rel="nofollow">新力传媒</a> 287 <a href="//www.yohobuy.com/newpower.html" rel="nofollow">新力传媒</a>
288 <span>|</span> 288 <span>|</span>
@@ -293,6 +293,10 @@ @@ -293,6 +293,10 @@
293 <a href="//www.yohobuy.com/privacy.html" rel="nofollow">隐私条款</a> 293 <a href="//www.yohobuy.com/privacy.html" rel="nofollow">隐私条款</a>
294 <span>|</span> 294 <span>|</span>
295 <a href="//www.yohobuy.com/link.html">友情链接</a> 295 <a href="//www.yohobuy.com/link.html">友情链接</a>
  296 + <span>|</span>
  297 + <a class="police" target="_blank" href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=32010502010132">
  298 + 苏公网安备 32010502010132号
  299 + </a>
296 </p> 300 </p>
297 <p> 301 <p>
298 CopyRight © 2007-2016 南京新与力文化传播有限公司 302 CopyRight © 2007-2016 南京新与力文化传播有限公司
1 { 1 {
2 "name": "yohobuy-node", 2 "name": "yohobuy-node",
3 - "version": "5.9.0", 3 + "version": "5.9.4",
4 "private": true, 4 "private": true,
5 "description": "A New Yohobuy Project With Express", 5 "description": "A New Yohobuy Project With Express",
6 "repository": { 6 "repository": {
@@ -160,8 +160,14 @@ function bindHoverEvent() { @@ -160,8 +160,14 @@ function bindHoverEvent() {
160 $brand.unbind('mouseenter').unbind('mouseleave').hover(function() { 160 $brand.unbind('mouseenter').unbind('mouseleave').hover(function() {
161 var $this = $(this); 161 var $this = $(this);
162 var key = $this.attr('data-key'); 162 var key = $this.attr('data-key');
  163 + var options;
163 164
164 - var options = { 165 + // 全球购品牌不展示品牌简介
  166 + if (+key < 0) {
  167 + return;
  168 + }
  169 +
  170 + options = {
165 url: '/brands/brandinfo', 171 url: '/brands/brandinfo',
166 type: 'get', 172 type: 'get',
167 data: { 173 data: {
@@ -107,7 +107,7 @@ function validateAddress(data) { @@ -107,7 +107,7 @@ function validateAddress(data) {
107 var regx = { 107 var regx = {
108 consignee: /^([\u4e00-\u9fa5\w*]{1,20})$/, 108 consignee: /^([\u4e00-\u9fa5\w*]{1,20})$/,
109 areaCode: /^[0-9]{6,9}$/, 109 areaCode: /^[0-9]{6,9}$/,
110 - mobile: /^\d{3}(\d{4}|\*{4})\d{1,8}$/, 110 + mobile: /^\d{3}(\d{4}|\*{4})\d{4}$/, // 手机号11位校验 by 新飞 2017.7.11
111 phone: /^(\(\d{3,4}\)|\d{3,4}-|\s)?\d{7,14}$/ 111 phone: /^(\(\d{3,4}\)|\d{3,4}-|\s)?\d{7,14}$/
112 }, 112 },
113 pass = true, 113 pass = true,
@@ -114,7 +114,7 @@ function getShoppingKey() { @@ -114,7 +114,7 @@ function getShoppingKey() {
114 a.src = j; 114 a.src = j;
115 m.parentNode.insertBefore(a, m); 115 m.parentNode.insertBefore(a, m);
116 }(window, document, 'script', (document.location.protocol === 'https:' ? 'https:' : 'http:') + '//' + // eslint-disable-line 116 }(window, document, 'script', (document.location.protocol === 'https:' ? 'https:' : 'http:') + '//' + // eslint-disable-line
117 - 'cdn.yoho.cn/yas-jssdk/2.4.1/yas.js', '_yas')); // eslint-disable-line 117 + 'cdn.yoho.cn/yas-jssdk/2.4.2/yas.js', '_yas')); // eslint-disable-line
118 118
119 (function() { 119 (function() {
120 var uid = getUid(); 120 var uid = getUid();
@@ -124,7 +124,7 @@ function getShoppingKey() { @@ -124,7 +124,7 @@ function getShoppingKey() {
124 window._ozuid = uid; // 暴露ozuid 124 window._ozuid = uid; // 暴露ozuid
125 125
126 if (window._yas) { 126 if (window._yas) {
127 - window._yas(1 * new Date(), '2.4.1', 'yohobuy_web', uid, '', ''); 127 + window._yas(1 * new Date(), '2.4.2', 'yohobuy_web', uid, '', '');
128 } 128 }
129 }()); 129 }());
130 130
@@ -230,7 +230,7 @@ function blurAction(opt) { @@ -230,7 +230,7 @@ function blurAction(opt) {
230 } 230 }
231 231
232 if (opt.inputName === 'mobile') { 232 if (opt.inputName === 'mobile') {
233 - regular = /^[0-9]{1,}$/; 233 + regular = /^[0-9]{11}$/; // 手机号11位校验 by 新飞 2017.7.11
234 234
235 if (regular.test(opt.val) === false) { 235 if (regular.test(opt.val) === false) {
236 msg = '您输入的手机号格式不正确'; 236 msg = '您输入的手机号格式不正确';
@@ -1498,45 +1498,29 @@ function initPageYas() { @@ -1498,45 +1498,29 @@ function initPageYas() {
1498 yas.givePoint('YB_CHOOSE_FOR_YOU_Y', loadYas); 1498 yas.givePoint('YB_CHOOSE_FOR_YOU_Y', loadYas);
1499 } 1499 }
1500 1500
1501 -// 店铺推荐 1501 +// 店铺推荐 改为后台直出
1502 function loadRecommend() { 1502 function loadRecommend() {
1503 - return $.ajax({  
1504 - type: 'GET',  
1505 - url: '/product/detail/recommend',  
1506 - data: {  
1507 - skn: skn,  
1508 - size: 20,  
1509 - num: 1  
1510 - }  
1511 - }).then(function(data) {  
1512 - var pro = data.data.products;  
1513 - var recommendTpl = require('hbs/product/recommend.hbs');  
1514 - var html = recommendTpl(data.data);  
1515 -  
1516 - if (data.code === 200 && pro.length !== 0) {  
1517 - $('#recommend-shop').removeClass('hide');  
1518 - $('#recommend-content').append(html);  
1519 - $('.recommend-slider').slider2({  
1520 - shownum: 5,  
1521 - isCircle: true  
1522 - });  
1523 1503
1524 - $('.recommend-slider .img-item .goods-id').each(function() {  
1525 - $goodsIdArr.push($(this).html());  
1526 - });  
1527 - } else {  
1528 - $('.bottom-title').eq(0).removeClass('bottom-cur').addClass('hide');  
1529 - $('.bottom-title').eq(1).addClass('bottom-cur');  
1530 - $('.bottom-title').filter('.change').addClass('hide'); 1504 + var imgItem = $('.recommend-slider .img-item'),
  1505 + $bottomTitle = $('.bottom-tab .bottom-title');
1531 1506
1532 - $('#recommend-shop').remove();  
1533 - $('.individual-comment .latest-walk').show();  
1534 - fetchLatestWalk(); // eslint-disable-line  
1535 - } 1507 + if (imgItem.length !== 0) {
1536 1508
1537 - // 页面加载完,埋点  
1538 - initPageYas();  
1539 - }); 1509 + $('.recommend-slider .img-item .goods-id').each(function() {
  1510 + $goodsIdArr.push($(this).html());
  1511 + });
  1512 + } else {
  1513 + $bottomTitle.eq(0).removeClass('bottom-cur').addClass('hide');
  1514 + $bottomTitle.eq(1).addClass('bottom-cur');
  1515 + $bottomTitle.filter('.change').addClass('hide');
  1516 +
  1517 + $('#recommend-shop').remove();
  1518 + $('.individual-comment .latest-walk').show();
  1519 + fetchLatestWalk(); // eslint-disable-line
  1520 + }
  1521 +
  1522 + // 页面加载完,埋点
  1523 + initPageYas();
1540 } 1524 }
1541 1525
1542 // 点击为您推荐商品埋点 1526 // 点击为您推荐商品埋点
@@ -1838,14 +1822,14 @@ $('.bottom-tab').on('click', '.bottom-title', function() { @@ -1838,14 +1822,14 @@ $('.bottom-tab').on('click', '.bottom-title', function() {
1838 $recommendComment.slideDown(SLIDETIME); 1822 $recommendComment.slideDown(SLIDETIME);
1839 $latestWalk.slideUp(SLIDETIME); 1823 $latestWalk.slideUp(SLIDETIME);
1840 1824
1841 - $('.change').removeClass('hide'); 1825 + $(this).siblings('.change').removeClass('hide');
1842 } else { 1826 } else {
1843 // 最近游览 1827 // 最近游览
1844 window.fetchLatestWalk(); // eslint-disable-line 1828 window.fetchLatestWalk(); // eslint-disable-line
1845 $recommendComment.slideUp(SLIDETIME); 1829 $recommendComment.slideUp(SLIDETIME);
1846 $latestWalk.slideDown(SLIDETIME); 1830 $latestWalk.slideDown(SLIDETIME);
1847 1831
1848 - $('.change').addClass('hide'); 1832 + $(this).siblings('.change').addClass('hide');
1849 } 1833 }
1850 1834
1851 }); 1835 });
@@ -1969,6 +1953,16 @@ $(function() { @@ -1969,6 +1953,16 @@ $(function() {
1969 } 1953 }
1970 }); 1954 });
1971 }); 1955 });
  1956 +
  1957 + // 猜你喜欢、店铺推荐初始化,
  1958 + $('.recommend-slider-alike').slider2({
  1959 + shownum: 5,
  1960 + isCircle: true
  1961 + });
  1962 + $('.recommend-slider').slider2({
  1963 + shownum: 5,
  1964 + isCircle: true
  1965 + });
1972 }); 1966 });
1973 1967
1974 yasAtBottom.yasBottom(); 1968 yasAtBottom.yasBottom();
@@ -346,6 +346,13 @@ @@ -346,6 +346,13 @@
346 padding: 0 10px; 346 padding: 0 10px;
347 } 347 }
348 } 348 }
  349 +
  350 + .police {
  351 + background: resolve(layout/police.png) no-repeat;
  352 + height: 20px;
  353 + display: inline-block;
  354 + padding-left: 25px;
  355 + }
349 } 356 }
350 357
351 .right-floating-layer { 358 .right-floating-layer {
@@ -1013,7 +1013,8 @@ @@ -1013,7 +1013,8 @@
1013 } 1013 }
1014 } 1014 }
1015 1015
1016 - .bottom-tab { 1016 + .bottom-tab,
  1017 + .alike-title {
1017 .bottom-title { 1018 .bottom-title {
1018 font-size: 15px; 1019 font-size: 15px;
1019 display: inline-block; 1020 display: inline-block;
@@ -1808,6 +1809,31 @@ @@ -1808,6 +1809,31 @@
1808 } 1809 }
1809 } 1810 }
1810 1811
  1812 + .recommend-keywords {
  1813 + margin-top: 30px;
  1814 + margin-bottom: 20px;
  1815 + border: 1px #e0e0e0 solid;
  1816 +
  1817 + h3 {
  1818 + height: 46px;
  1819 + border-bottom: 1px #e0e0e0 solid;
  1820 + line-height: 44px;
  1821 + background: #f5f5f5;
  1822 + text-align: center;
  1823 + font-size: 15px;
  1824 + }
  1825 +
  1826 + p {
  1827 + padding: 10px;
  1828 +
  1829 + a {
  1830 + display: inline-block;
  1831 + margin: 5px 15px;
  1832 + font-size: 12px;
  1833 + }
  1834 + }
  1835 + }
  1836 +
1811 .support-salereturned-service { 1837 .support-salereturned-service {
1812 $service: product/service.png; 1838 $service: product/service.png;
1813 1839
@@ -2096,6 +2122,20 @@ @@ -2096,6 +2122,20 @@
2096 } 2122 }
2097 } 2123 }
2098 } 2124 }
  2125 +
  2126 + .alike-title {
  2127 + margin-top: 30px;
  2128 + }
  2129 +
  2130 + .alike {
  2131 + .recommend-content {
  2132 + height: 340px;
  2133 +
  2134 + li {
  2135 + height: 340px;
  2136 + }
  2137 + }
  2138 + }
2099 } 2139 }
2100 2140
2101 .coupon-big { 2141 .coupon-big {
1 User-Agent: * 1 User-Agent: *
2 -Disallow: /passport/  
3 -Disallow: /help 2 +Disallow: /passport/
4 Disallow: signin.html 3 Disallow: signin.html
5 Disallow: reg.html 4 Disallow: reg.html
6 Disallow: /cart/ 5 Disallow: /cart/