Authored by 毕凯

Merge branch 'hotfix/apple' into 'release/5.9'

促销标签



See merge request !702
@@ -154,8 +154,9 @@ class BuyNowController { @@ -154,8 +154,9 @@ class BuyNowController {
154 * @param {*} next 154 * @param {*} next
155 */ 155 */
156 orderSub(req, res, next) { 156 orderSub(req, res, next) {
  157 + let uid = req.user.uid;
157 let params = { 158 let params = {
158 - uid: req.user.uid, 159 + uid: uid,
159 product_sku: req.body.product_sku, 160 product_sku: req.body.product_sku,
160 sku_type: req.body.sku_type, 161 sku_type: req.body.sku_type,
161 buy_number: req.body.buy_number, 162 buy_number: req.body.buy_number,
@@ -170,7 +171,8 @@ class BuyNowController { @@ -170,7 +171,8 @@ class BuyNowController {
170 product_sku_list: req.body.product_sku_list, 171 product_sku_list: req.body.product_sku_list,
171 is_print_price: req.body.is_print_price, 172 is_print_price: req.body.is_print_price,
172 remark: req.body.remark, 173 remark: req.body.remark,
173 - activity_id: req.body.activity_id 174 + activity_id: req.body.activity_id,
  175 + ip: req.yoho.clientIp
174 }; 176 };
175 177
176 // 是否开发票 178 // 是否开发票
@@ -186,6 +188,13 @@ class BuyNowController { @@ -186,6 +188,13 @@ class BuyNowController {
186 } 188 }
187 } 189 }
188 190
  191 + if (req.cookies.mkt_code || req.cookies._QYH_UNION) {
  192 + let unionInfo = paymentProcess.unionInfoHandle(req.cookies, uid);
  193 +
  194 + params.qhy_union = _.get(unionInfo, 'unionKey', false);
  195 + params.userAgent = _.get(unionInfo, 'userAgent', '');
  196 + }
  197 +
189 co(function * () { 198 co(function * () {
190 let result = yield req.ctx(BuyNowModel).submit(params); 199 let result = yield req.ctx(BuyNowModel).submit(params);
191 200
@@ -231,7 +231,7 @@ exports.orderSub = (req, res, next) => { @@ -231,7 +231,7 @@ exports.orderSub = (req, res, next) => {
231 unionKey: unionInfo.unionKey, // 友盟数据 231 unionKey: unionInfo.unionKey, // 友盟数据
232 userAgent: unionInfo.userAgent, 232 userAgent: unionInfo.userAgent,
233 isWechat: req.yoho.isWechat, 233 isWechat: req.yoho.isWechat,
234 - ip: req.ip || '', 234 + ip: req.yoho.clientIp,
235 udid: req.cookies._yasvd || 'yoho' 235 udid: req.cookies._yasvd || 'yoho'
236 }; 236 };
237 237
@@ -159,7 +159,16 @@ class BuyNowModel extends global.yoho.BaseModel { @@ -159,7 +159,16 @@ class BuyNowModel extends global.yoho.BaseModel {
159 finalParams.promotion_code = params.promotion_code; 159 finalParams.promotion_code = params.promotion_code;
160 } 160 }
161 161
162 - return api.post('', finalParams, {cache: false}); 162 + if (params.qhy_union) {
  163 + finalParams.qhy_union = params.qhy_union;
  164 + }
  165 +
  166 + return api.post('', finalParams, {
  167 + headers: {
  168 + 'X-Forwarded-For': params.ip || '',
  169 + 'User-Agent': params.userAgent
  170 + }
  171 + });
163 } 172 }
164 173
165 /** 174 /**
@@ -304,11 +304,47 @@ const keyword = (req, res, next) => { @@ -304,11 +304,47 @@ const keyword = (req, res, next) => {
304 }).catch(next); 304 }).catch(next);
305 }; 305 };
306 306
  307 +// 关键词页with id
  308 +const keyId = (req, res, next) => {
  309 + let params = {
  310 + isSearch: true, // 搜索列表将最新改成默认的标识
  311 + cartUrl: helpers.urlFormat('/cart/index/index')
  312 + };
  313 +
  314 + params.isApp = req.yoho.isApp;
  315 + params.physical_channel = req.yoho.channel && searchProcess.getChannelType(req.yoho.channel);
  316 +
  317 + return searchModel.getSearchKeywordDataById(req.params.id, params, req.user.uid).then(result => {
  318 + let queryKey = result.queryKey;
  319 +
  320 + // 唤起 APP 的路径
  321 + res.locals.appPath = `yohobuy://yohobuy.com/goapp?openby:yohobuy={"action":"go.list","params":${JSON.stringify(params)}}`;
  322 +
  323 + res.render('search/list', {
  324 + _noLazy: true,
  325 + module: 'product',
  326 + page: 'search-list',
  327 + pageHeader: headerModel.setNav({
  328 + navTitle: queryKey
  329 + }),
  330 + goodList: params,
  331 + firstPageGoods: result || [],
  332 + fuzzyWord: result.fuzzyWord,
  333 + title: `${queryKey}价格_图片_品牌_怎么样-YOHO!BUY有货`,
  334 + keywords: `${queryKey},${queryKey}价格,${queryKey}图片,${queryKey}怎么样,${queryKey}品牌,YOHO!BUY有货`,
  335 + description: `YOHO!BUY有货网yohobuy.com是国内专业的${queryKey}网上潮流购物商城,为您找到${_.get(result,
  336 + 'total', 0)}${queryKey}、产品的详细参数,实时报价,价格行情,图片、评价、品牌等信息。买${queryKey},就上YOHO!BUY有货`,
  337 + pageFooter: true
  338 + });
  339 + }).catch(next);
  340 +};
  341 +
307 module.exports = { 342 module.exports = {
308 list, 343 list,
309 filter, 344 filter,
310 search, 345 search,
311 index, 346 index,
312 fuzzyDatas, 347 fuzzyDatas,
313 - keyword 348 + keyword,
  349 + keyId
314 }; 350 };
@@ -13,6 +13,7 @@ const logger = global.yoho.logger; @@ -13,6 +13,7 @@ const logger = global.yoho.logger;
13 const api = global.yoho.API; 13 const api = global.yoho.API;
14 const cache = require('memory-cache'); 14 const cache = require('memory-cache');
15 const helpers = global.yoho.helpers; 15 const helpers = global.yoho.helpers;
  16 +const redis = global.yoho.redis;
16 17
17 /** 18 /**
18 * 封面图 19 * 封面图
@@ -539,6 +540,41 @@ const getSearchKeywordData = (params, uid) => { @@ -539,6 +540,41 @@ const getSearchKeywordData = (params, uid) => {
539 }); 540 });
540 }; 541 };
541 542
  543 +const getSearchKeywordDataById = (id, params, uid) => {
  544 + return redis.all([
  545 + ['get', `golobal:yoho:seo:keywords:id:${id}`]
  546 + ]).then(redisData => {
  547 + if (!redisData[0]) {
  548 + return Promise.reject('get redis canpin keywords by id error!' +
  549 + `key: golobal:yoho:seo:keywords:id:${id} value: ${redisData[0]}`);
  550 + }
  551 +
  552 + redisData = JSON.parse(redisData[0]);
  553 + params.query = redisData.name;
  554 +
  555 + return getSearchKeywordData(params, uid).then(result => {
  556 + result.queryKey = params.query;
  557 +
  558 + if (!_.isEmpty(redisData.data)) {
  559 + _.forEach(redisData.data, value => {
  560 + if (!value) {
  561 + return;
  562 + }
  563 +
  564 + Object.assign(value, {
  565 + name: value.keyword,
  566 + link: helpers.urlFormat(`/chanpin/${value.id}.html`, null)
  567 + });
  568 + });
  569 +
  570 + _.set(result, 'fuzzyWord', redisData.data);
  571 + }
  572 +
  573 + return result;
  574 + });
  575 + });
  576 +};
  577 +
542 module.exports = { 578 module.exports = {
543 getSearchData, 579 getSearchData,
544 getFilterData, 580 getFilterData,
@@ -549,5 +585,6 @@ module.exports = { @@ -549,5 +585,6 @@ module.exports = {
549 getFuzzyDatas, 585 getFuzzyDatas,
550 searchKeyActivity, 586 searchKeyActivity,
551 getBrandDomain, 587 getBrandDomain,
552 - getSearchKeywordData 588 + getSearchKeywordData,
  589 + getSearchKeywordDataById
553 }; 590 };
@@ -134,8 +134,9 @@ router.get('/seckill/get-product-list', seckill.getProductList); // 秒杀列表 @@ -134,8 +134,9 @@ router.get('/seckill/get-product-list', seckill.getProductList); // 秒杀列表
134 // 搜索主页 134 // 搜索主页
135 router.get('/search/index', search.index); 135 router.get('/search/index', search.index);
136 136
137 -// 搜索落地页  
138 -router.get('/search/keyword/:query', rewrite.sortParams, search.keyword); 137 +// 推广落地页
  138 +router.get('/search/so/:query.html', rewrite.sortParams, search.keyword);
  139 +router.get('/search/chanpin/:id.html', rewrite.sortParams, search.keyId);
139 140
140 // 搜索落地页 141 // 搜索落地页
141 router.get('/search/list', rewrite.sortParams, search.list); 142 router.get('/search/list', rewrite.sortParams, search.list);
@@ -104,7 +104,8 @@ const cachePage = { @@ -104,7 +104,8 @@ const cachePage = {
104 '/activity/shopNav': 30 * SECOND, 104 '/activity/shopNav': 30 * SECOND,
105 105
106 // 关键词页面 106 // 关键词页面
107 - '/product/search/keyword/:query': 7 * DAY 107 + '/product/search/so/:query.html': 7 * DAY,
  108 + '/product/search/chanpin/:id.html': 7 * DAY
108 109
109 }; 110 };
110 111
  1 +
  2 +const _ = require('lodash');
1 const redis = require('redis'); 3 const redis = require('redis');
2 const bluebird = require('bluebird'); 4 const bluebird = require('bluebird');
3 const config = require('../../config/common'); 5 const config = require('../../config/common');
@@ -9,6 +11,18 @@ try { @@ -9,6 +11,18 @@ try {
9 bluebird.promisifyAll(redis.RedisClient.prototype); 11 bluebird.promisifyAll(redis.RedisClient.prototype);
10 bluebird.promisifyAll(redis.Multi.prototype); 12 bluebird.promisifyAll(redis.Multi.prototype);
11 13
  14 + client.all = args => {
  15 + if (!client.ready) {
  16 + if (Array.isArray(args)) {
  17 + return Promise.resolve(_.fill(args, false));
  18 + } else {
  19 + return Promise.resolve(false);
  20 + }
  21 + }
  22 +
  23 + return client.multi.call(client, args).execAsync();
  24 + };
  25 +
12 client.on('error', function() { 26 client.on('error', function() {
13 global.yoho.redis = ''; 27 global.yoho.redis = '';
14 }); 28 });
@@ -84,14 +84,8 @@ module.exports = () => { @@ -84,14 +84,8 @@ module.exports = () => {
84 } 84 }
85 break; 85 break;
86 } 86 }
87 - } else {  
88 - let soReg = /\/so\/(.*).html/;  
89 -  
90 - if (soReg.test(req.path)) {  
91 - soReg.exec(req.url);  
92 - req.url = `/product/search/keyword/${RegExp.$1}`;  
93 - }  
94 } 87 }
  88 +
95 next(); 89 next();
96 }; 90 };
97 }; 91 };
@@ -61,6 +61,11 @@ module.exports = () => { @@ -61,6 +61,11 @@ module.exports = () => {
61 req.url = '/activity/couponSend'; 61 req.url = '/activity/couponSend';
62 } 62 }
63 63
  64 + if (/\/chanpin\/(.*).html/.test(req.url) || /\/so\/(.*).html/.test(req.url)) {
  65 + // 获取seo兼容
  66 + req.url = `/product/search${req.path}`;
  67 + }
  68 +
64 next(); 69 next();
65 }; 70 };
66 }; 71 };
@@ -3,10 +3,10 @@ @@ -3,10 +3,10 @@
3 <div class="goods-discount" id="goodsDiscount"> 3 <div class="goods-discount" id="goodsDiscount">
4 {{#each promotion}} 4 {{#each promotion}}
5 {{#if @first}} 5 {{#if @first}}
6 - <h1 class="first-item short-text tap-hightlight">{{promotionTitle}}<span class="icon-down iconfont dropdown">&#xe609;</span></h1> 6 + <h1 class="first-item short-text tap-hightlight"><span class="promotion-icon"></span>{{promotionTitle}}<span class="icon-down iconfont dropdown">&#xe609;</span></h1>
7 {{else}} 7 {{else}}
8 <div class="discount-folder"> 8 <div class="discount-folder">
9 - <h1 class="folder-item tap-hightlight">{{promotionTitle}}</h1> 9 + <h1 class="folder-item tap-hightlight"><span class="promotion-icon"></span>{{promotionTitle}}</h1>
10 </div> 10 </div>
11 {{/if}} 11 {{/if}}
12 {{/each}} 12 {{/each}}
@@ -11,7 +11,7 @@ let $ = require('yoho-jquery'), @@ -11,7 +11,7 @@ let $ = require('yoho-jquery'),
11 11
12 require('./detail/page-render')(function() { 12 require('./detail/page-render')(function() {
13 let $discountFolder = $('.goods-discount .discount-folder'), 13 let $discountFolder = $('.goods-discount .discount-folder'),
14 - $discountArrow = $('.goods-discount .first-item span'); 14 + $discountArrow = $('.goods-discount .first-item .iconfont');
15 15
16 let goodsDiscountEl = document.getElementById('goodsDiscount'), 16 let goodsDiscountEl = document.getElementById('goodsDiscount'),
17 goodsDiscountHammer = goodsDiscountEl && new Hammer(goodsDiscountEl), 17 goodsDiscountHammer = goodsDiscountEl && new Hammer(goodsDiscountEl),
@@ -304,7 +304,7 @@ setTimeout(() => { @@ -304,7 +304,7 @@ setTimeout(() => {
304 let $goodsDiscount = $('#goodsDiscount'); 304 let $goodsDiscount = $('#goodsDiscount');
305 let $discountFirstItem = $goodsDiscount.find('.first-item'); 305 let $discountFirstItem = $goodsDiscount.find('.first-item');
306 let $discountFolder = $goodsDiscount.find('.discount-folder'); 306 let $discountFolder = $goodsDiscount.find('.discount-folder');
307 - let $discountArrow = $goodsDiscount.find('.first-item span'); 307 + let $discountArrow = $goodsDiscount.find('.first-item .iconfont');
308 308
309 // 初始化goods-discount 309 // 初始化goods-discount
310 if ($discountFolder.children().length === 0) { 310 if ($discountFolder.children().length === 0) {
@@ -711,6 +711,17 @@ $basicBtnC: #eb0313; @@ -711,6 +711,17 @@ $basicBtnC: #eb0313;
711 line-height: 36px; 711 line-height: 36px;
712 } 712 }
713 713
  714 + .first-item > .promotion-icon,
  715 + .folder-item > .promotion-icon {
  716 + background-color: #d0021b;
  717 + color: #fff;
  718 + padding: 0 4px;
  719 + border-radius: 4px;
  720 + margin-right: 10px;
  721 + font-size: 22px;
  722 + float: left;
  723 + }
  724 +
714 .short-text { 725 .short-text {
715 overflow: hidden; 726 overflow: hidden;
716 text-overflow: ellipsis; 727 text-overflow: ellipsis;
@@ -336,10 +336,10 @@ function coupon(count, orderInfo, orderComputeData) { @@ -336,10 +336,10 @@ function coupon(count, orderInfo, orderComputeData) {
336 count: count 336 count: count
337 }; 337 };
338 338
339 - if (  
340 - orderComputeData.coupon_amount ||  
341 - (orderComputeData.coupon_amount === 0 && orderComputeData.shipping_cost === 0)  
342 - ) { 339 + let couponAmount = _.get(orderComputeData, 'coupon_amount', false);
  340 + let shippingCost = _.get(orderComputeData, 'shipping_cost', false); // shipping_cost 是普通运费
  341 +
  342 + if (couponAmount || (couponAmount === 0 && shippingCost === 0)) {
343 coupons.couponName = orderInfo.couponName; 343 coupons.couponName = orderInfo.couponName;
344 } 344 }
345 345
@@ -443,8 +443,10 @@ function unionInfoHandle(cookies, uid) { @@ -443,8 +443,10 @@ function unionInfoHandle(cookies, uid) {
443 } 443 }
444 444
445 /* 模拟APP的User-Agent */ 445 /* 模拟APP的User-Agent */
446 - userAgent = clientId ? 'YOHO!Buy/3.8.2.259(Model/PC;Channel/' +  
447 - clientId + ';uid/' + uid + ')' : null; 446 + let clientIdSub = _.split(clientId, ',')[0];
  447 +
  448 + userAgent = clientIdSub ? 'YOHO!Buy/3.8.2.259(Model/H5;Channel/' +
  449 + clientIdSub + ';uid/' + uid + ')' : null;
448 450
449 return { 451 return {
450 unionKey: unionKey, 452 unionKey: unionKey,