Authored by ccbikai(👎🏻🍜)

Merge branch 'release/newSearch'

  1 +// 购物车数量
  2 +
  3 +'use strict';
  4 +
  5 +const countModel = require('../models/count');
  6 +
  7 +let cartCount = (req, res, next) => {
  8 +
  9 + let uid = req.user.uid;
  10 + let shoppingKey = req.cookies._SPK || '';
  11 +
  12 + countModel.cartCount(uid, shoppingKey).then((result) => {
  13 + res.json(result);
  14 + }).catch(next);
  15 +};
  16 +
  17 +module.exports = {
  18 + cartCount
  19 +};
  1 +/**
  2 + * sub app channel
  3 + * @author: Bi Kai<kai.bi@yoho.cn>
  4 + * @date: 2016/05/09
  5 + */
  6 +
  7 +var express = require('express'),
  8 + path = require('path'),
  9 + hbs = require('express-handlebars');
  10 +
  11 +var app = express();
  12 +
  13 +// set view engin
  14 +var doraemon = path.join(__dirname, '../../doraemon/views'); // parent view root
  15 +
  16 +app.on('mount', function(parent) {
  17 + delete parent.locals.settings; // 不继承父 App 的设置
  18 + Object.assign(app.locals, parent.locals);
  19 +});
  20 +
  21 +app.set('views', path.join(__dirname, 'views/action'));
  22 +app.engine('.hbs', hbs({
  23 + extname: '.hbs',
  24 + defaultLayout: 'layout',
  25 + layoutsDir: doraemon,
  26 + partialsDir: [path.join(__dirname, 'views/partial'), `${doraemon}/partial`],
  27 + helpers: global.yoho.helpers
  28 +}));
  29 +
  30 +// router
  31 +app.use(require('./router'));
  32 +
  33 +module.exports = app;
  1 +'use strict';
  2 +
  3 +const api = global.yoho.API;
  4 +
  5 +const cartCount = (uid, shoppingKey) => {
  6 +
  7 + return api.get('', {
  8 + method: 'app.Shopping.count',
  9 + uid: uid,
  10 + shopping_key: shoppingKey
  11 + }).then((result) => {
  12 + return result;
  13 + });
  14 +};
  15 +
  16 +module.exports = {
  17 + cartCount
  18 +};
  1 +/**
  2 + * router of sub app channel
  3 + * @author: Bi Kai<kai.bi@yoho.cn>
  4 + * @date: 2016/05/09
  5 + */
  6 +
  7 +'use strict';
  8 +
  9 +const express = require('express');
  10 +const router = express.Router();
  11 +const cRoot = './controllers';
  12 +const countController = require(`${cRoot}/count`);
  13 +
  14 +router.get('/index/count', countController.cartCount);
  15 +
  16 +module.exports = router;
@@ -5,12 +5,14 @@ @@ -5,12 +5,14 @@
5 */ 5 */
6 6
7 'use strict'; 7 'use strict';
  8 +const utils = '../../../utils';
8 const mRoot = '../models'; 9 const mRoot = '../models';
9 const headerModel = require('../../../doraemon/models/header'); 10 const headerModel = require('../../../doraemon/models/header');
10 const listModel = require(`${mRoot}/list`); 11 const listModel = require(`${mRoot}/list`);
11 const _ = require('lodash'); 12 const _ = require('lodash');
12 const crypto = global.yoho.crypto; 13 const crypto = global.yoho.crypto;
13 const helpers = global.yoho.helpers; 14 const helpers = global.yoho.helpers;
  15 +const productProcess = require(`${utils}/product-process`);
14 16
15 /** 17 /**
16 * 店铺 - 基础模板 18 * 店铺 - 基础模板
@@ -80,40 +82,37 @@ const _shop = (req, res, shopId) => { @@ -80,40 +82,37 @@ const _shop = (req, res, shopId) => {
80 }; 82 };
81 } 83 }
82 84
83 - // uid = req.user.uid;  
84 - // } else {  
85 - // uid = req.query.uid;  
86 - // req.session.appUid = uid;  
87 - // res.cookie('appUid', uid, {  
88 - // domain: 'yohobuy.com',  
89 - // expires: new Date(Date.now() + 2592000000) // 有效期一年  
90 - // });  
91 - // }  
92 -  
93 listModel.getShopData(req, shopId, uid, isApp).then(result => { 85 listModel.getShopData(req, shopId, uid, isApp).then(result => {
94 if (result.goBrand) { 86 if (result.goBrand) {
95 87
96 /* 若店铺使用基础模板跳转基础模板 */ 88 /* 若店铺使用基础模板跳转基础模板 */
97 _baseShop(req, res, result.goBrand, shopId); 89 _baseShop(req, res, result.goBrand, shopId);
98 } else { 90 } else {
99 - result = _.assign(result, pageHeader);  
100 -  
101 - res.render('shop/index', {  
102 - module: 'product',  
103 - page: 'shop',  
104 - shopIndex: result,  
105 - shopHeadHide: true,  
106 - gender: req.query.gender,  
107 - channel: req.query.channel,  
108 -  
109 - // pageHeader: headerModel.setNav({  
110 - // navTitle: result.storeName  
111 - // }),  
112 - title: result.storeName + '|' + result.storeName + '潮流服装服饰-Yoho!Buy有货',  
113 - keywords: result.storeName + ',' + result.storeName + '服装服饰,' + result.storeName + '潮流服装服饰',  
114 - description: result.storeName + '|Yoho!Buy有货' + result.storeName + '潮流服饰官方授权店!100%品牌正品保证,支持货到付款。',  
115 - shopId: shopId,  
116 - shopPage: true 91 + listModel.searchProductBySkn(result.hotListproductSkn).then(hotList => {
  92 + result = _.assign(result, pageHeader, {
  93 + hotList: productProcess.processProductList(hotList)
  94 + });
  95 +
  96 + _.forEach(result.hotList, (value, key) => {
  97 + result.hotList[key].tags = {};
  98 + result.hotList[key].is_soon_sold_out = false;
  99 + result.hotList[key].tags.isHot = true;
  100 + });
  101 +
  102 + res.render('shop/index', {
  103 + module: 'product',
  104 + page: 'shop',
  105 + shopIndex: result,
  106 + shopHeadHide: true,
  107 + gender: req.query.gender,
  108 + channel: req.query.channel,
  109 + title: result.storeName + '|' + result.storeName + '潮流服装服饰-Yoho!Buy有货',
  110 + keywords: result.storeName + ',' + result.storeName + '服装服饰,' + result.storeName + '潮流服装服饰',
  111 + description: result.storeName + '|Yoho!Buy有货' + result.storeName + '潮流服饰官方授权店!100%品牌正品保证,支持货到付款。',
  112 + shopId: shopId,
  113 + shopPage: true
  114 + });
  115 +
117 }); 116 });
118 } 117 }
119 }); 118 });
@@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
4 * @date: 2016/07/21 4 * @date: 2016/07/21
5 */ 5 */
6 'use strict'; 6 'use strict';
  7 +const utils = '../../../utils';
7 const logger = global.yoho.logger; 8 const logger = global.yoho.logger;
8 const crypto = global.yoho.crypto; 9 const crypto = global.yoho.crypto;
9 const camelCase = global.yoho.camelCase; 10 const camelCase = global.yoho.camelCase;
@@ -11,6 +12,7 @@ const _ = require('lodash'); @@ -11,6 +12,7 @@ const _ = require('lodash');
11 const helpers = global.yoho.helpers; 12 const helpers = global.yoho.helpers;
12 const api = global.yoho.API; 13 const api = global.yoho.API;
13 const searchModel = require('./search'); 14 const searchModel = require('./search');
  15 +const productProcess = require(`${utils}/product-process`);
14 16
15 /** 17 /**
16 * 频道 18 * 频道
@@ -222,13 +224,28 @@ const getShopBrands = (shopId) => { @@ -222,13 +224,28 @@ const getShopBrands = (shopId) => {
222 }); 224 });
223 }; 225 };
224 226
  227 +/**
  228 + * 通过 skn 搜索商品
  229 + * @param productSkn
  230 + * @returns {*|Promise.<TResult>}
  231 + * @private
  232 + */
  233 +const searchProductBySkn = (productSkn) => {
  234 + return api.get('', {
  235 + method: 'h5.product.batch',
  236 + productSkn: productSkn,
  237 + }).then(result => {
  238 + return _.get(result, 'data.product_list', []);
  239 + });
  240 +};
  241 +
225 242
226 /** 243 /**
227 * 组织店铺页面数据 244 * 组织店铺页面数据
228 * @param {array} data 接口返回的店铺页所需数据 245 * @param {array} data 接口返回的店铺页所需数据
229 * @param {int} shopId 店铺id 246 * @param {int} shopId 店铺id
230 * @param {int} isApp app版本 247 * @param {int} isApp app版本
231 - * @return array 248 + * @return {shopId: int, appVersion: int}
232 */ 249 */
233 const _formShopData = (data, shopId, isApp) => { 250 const _formShopData = (data, shopId, isApp) => {
234 let formatData = { 251 let formatData = {
@@ -350,25 +367,13 @@ const _formShopData = (data, shopId, isApp) => { @@ -350,25 +367,13 @@ const _formShopData = (data, shopId, isApp) => {
350 367
351 // 人气单品 368 // 人气单品
352 if (floor.hotProductsApp) { 369 if (floor.hotProductsApp) {
353 - let goods = [];  
354 -  
355 - _.forEach(resData, (item) => {  
356 - let url = '//item.yohobuy.com/product/pro_'; 370 + let productSkn = '';
357 371
358 - if (!item.cnAlphabet) {  
359 - item.cnAlphabet = 'goods.html';  
360 - }  
361 - url += item.productId + '_' + item.goodsId + '/' + item.cnAlphabet + '.html';  
362 - goods.push({  
363 - url: url + (isApp ? `?openby:yohobuy={"action":"go.productDetail","params":{"product_skn":${item.productSkn}}}` : ''),//eslint-disable-line  
364 - img: helpers.image(item.src, 235, 314),  
365 - productName: item.productName,  
366 - salesPrice: item.salesPrice,  
367 - presentPrice: item.salesPrice  
368 - }); 372 + _.forEach(resData, value => {
  373 + productSkn += value.productSkn + ',';
369 }); 374 });
370 375
371 - formatData.hotList = goods; 376 + formatData.hotListproductSkn = productSkn;
372 } 377 }
373 }); 378 });
374 } 379 }
@@ -527,12 +532,7 @@ const getShopData = (req, shopId, uid, isApp) => { @@ -527,12 +532,7 @@ const getShopData = (req, shopId, uid, isApp) => {
527 532
528 return Promise.all([ 533 return Promise.all([
529 _getShopDecorator(shopId), 534 _getShopDecorator(shopId),
530 - searchModel.getFilterData({  
531 - shop_id: shopId,  
532 - gender: req.query.gender || '1,3',  
533 - channel: channel  
534 - }),  
535 - searchModel.getSearchData({ 535 + searchModel.getFilterSearchData({
536 shop_id: shopId, 536 shop_id: shopId,
537 gender: req.query.gender || '1,3', 537 gender: req.query.gender || '1,3',
538 channel: channel 538 channel: channel
@@ -544,8 +544,19 @@ const getShopData = (req, shopId, uid, isApp) => { @@ -544,8 +544,19 @@ const getShopData = (req, shopId, uid, isApp) => {
544 shopInfo: shopInfoResult // 店铺信息 544 shopInfo: shopInfoResult // 店铺信息
545 }; 545 };
546 546
  547 + /* 获取一次分类和商品数据 */
  548 + let shopFilterSearchData = {
  549 + filter: [],
  550 + goods: []
  551 + };
  552 +
  553 + if (result[1]) {
  554 + shopFilterSearchData.filter = productProcess.processFilter(result[1].filter || []);
  555 + shopFilterSearchData.goods = productProcess.processProductList(result[1].product_list || []);
  556 + }
  557 +
547 /* 店鋪優惠券 */ 558 /* 店鋪優惠券 */
548 - let shopCoupons = result[3] || []; 559 + let shopCoupons = result[2] || [];
549 560
550 // 店铺分类 561 // 店铺分类
551 return _getShopCategory(shopId, channel).then((shopCategory) => { 562 return _getShopCategory(shopId, channel).then((shopCategory) => {
@@ -554,14 +565,16 @@ const getShopData = (req, shopId, uid, isApp) => { @@ -554,14 +565,16 @@ const getShopData = (req, shopId, uid, isApp) => {
554 }, shopData); 565 }, shopData);
555 566
556 // noinspection JSCheckFunctionSignatures 567 // noinspection JSCheckFunctionSignatures
557 - return Object.assign(_formShopData(shopData, shopId, isApp), {  
558 - filter: result[1],  
559 - goods: result[2],  
560 - shopId: shopId,  
561 - coverChannel: channel,  
562 - shopCoupons: shopCoupons,  
563 - shopCouponsOne: shopCoupons.length === 1  
564 - }); 568 + return Object.assign(
  569 + _formShopData(shopData, shopId, isApp),
  570 + shopFilterSearchData,
  571 + {
  572 + shopId: shopId,
  573 + coverChannel: channel,
  574 + shopCoupons: shopCoupons,
  575 + shopCouponsOne: shopCoupons.length === 1
  576 + }
  577 + );
565 }); 578 });
566 }); 579 });
567 580
@@ -573,10 +586,9 @@ const getShopData = (req, shopId, uid, isApp) => { @@ -573,10 +586,9 @@ const getShopData = (req, shopId, uid, isApp) => {
573 * @param req 586 * @param req
574 * @param shopId 587 * @param shopId
575 * @param uid 588 * @param uid
576 - * @param isApp  
577 * @returns {Promise.<TResult>|*} 589 * @returns {Promise.<TResult>|*}
578 */ 590 */
579 -const getShopFav = (req, shopId, uid, isApp) => { 591 +const getShopFav = (req, shopId, uid) => {
580 return _getShopInfo(shopId, uid).then(shopInfoResult => { 592 return _getShopInfo(shopId, uid).then(shopInfoResult => {
581 return shopInfoResult; 593 return shopInfoResult;
582 }); 594 });
@@ -802,5 +814,6 @@ module.exports = { @@ -802,5 +814,6 @@ module.exports = {
802 getShopBrands, 814 getShopBrands,
803 getShopCategory, 815 getShopCategory,
804 receiveCoupon, 816 receiveCoupon,
805 - getShopFav 817 + getShopFav,
  818 + searchProductBySkn
806 }; 819 };
@@ -144,6 +144,22 @@ const getFilterData = (params) => { @@ -144,6 +144,22 @@ const getFilterData = (params) => {
144 }; 144 };
145 145
146 /** 146 /**
  147 + * 获取筛选数据
  148 + * @param {[object]} params
  149 + * @return {[array]}
  150 + */
  151 +const getFilterSearchData = (params) => {
  152 + return _searchGoods(params).then((result) => {
  153 + if (result && result.code === 200) {
  154 + return result.data;
  155 + } else {
  156 + logger.error('get filter data api return code is not 200');
  157 + return [];
  158 + }
  159 + });
  160 +};
  161 +
  162 +/**
147 * 获取所有的品类名称 163 * 获取所有的品类名称
148 **/ 164 **/
149 const getClassNames = () => { 165 const getClassNames = () => {
@@ -235,6 +251,7 @@ const searchKeyActivity = (params) => { @@ -235,6 +251,7 @@ const searchKeyActivity = (params) => {
235 module.exports = { 251 module.exports = {
236 getSearchData, 252 getSearchData,
237 getFilterData, 253 getFilterData,
  254 + getFilterSearchData,
238 getAllBrandNames, 255 getAllBrandNames,
239 getClassNames, 256 getClassNames,
240 getSearchIndex, 257 getSearchIndex,
@@ -112,21 +112,11 @@ @@ -112,21 +112,11 @@
112 &#xe618;</a> 112 &#xe618;</a>
113 </div> 113 </div>
114 <div class="product-warp"> 114 <div class="product-warp">
115 - <ul class="product-list first">  
116 - {{#each hotList}}  
117 - <li class="buriedpoint" data-bp-id="shop_hotList_{{url}}">  
118 - <a href="{{url}}">  
119 - <img src="{{img}}">  
120 - </a>  
121 - <div class="list-price">  
122 - <p>{{productName}}</p>  
123 - <p><span class="red">{{originalPrice}}</span>  
124 - <span>{{presentPrice}}</span>  
125 - </p>  
126 - </div>  
127 - </li>  
128 - {{/each}}  
129 - </ul> 115 + <div class="goods-container clearfix">
  116 + {{# hotList}}
  117 + {{> common/goods}}
  118 + {{/ hotList}}
  119 + </div>
130 </div> 120 </div>
131 </div> 121 </div>
132 122
@@ -17,6 +17,7 @@ module.exports = app => { @@ -17,6 +17,7 @@ module.exports = app => {
17 app.use('/product', require('./apps/product')); 17 app.use('/product', require('./apps/product'));
18 app.use('/guang', require('./apps/guang')); 18 app.use('/guang', require('./apps/guang'));
19 app.use('/activity', require('./apps/activity')); 19 app.use('/activity', require('./apps/activity'));
  20 + app.use('/cart', require('./apps/cart'));
20 21
21 // 分期付款 22 // 分期付款
22 app.use('/home', require('./apps/home')); 23 app.use('/home', require('./apps/home'));
@@ -5,6 +5,9 @@ @@ -5,6 +5,9 @@
5 {{# isNew}} 5 {{# isNew}}
6 <p class="good-tag new-tag">NEW</p> 6 <p class="good-tag new-tag">NEW</p>
7 {{/ isNew}} 7 {{/ isNew}}
  8 + {{# isHot}}
  9 + <p class="good-tag hot-tag">HOT</p>
  10 + {{/ isHot}}
8 {{# isAdvance}} 11 {{# isAdvance}}
9 <p class="good-tag renew-tag">再到着</p> 12 <p class="good-tag renew-tag">再到着</p>
10 {{/ isAdvance}} 13 {{/ isAdvance}}
@@ -30,6 +30,12 @@ @@ -30,6 +30,12 @@
30 color: #fff; 30 color: #fff;
31 } 31 }
32 32
  33 + .hot-tag {
  34 + width: 60px;
  35 + background-color: #ff575c;
  36 + color: #fff;
  37 + }
  38 +
33 .renew-tag { 39 .renew-tag {
34 width: 90px; 40 width: 90px;
35 background-color: #78dc7e; 41 background-color: #78dc7e;
@@ -145,6 +145,12 @@ $basicBtnC: #eb0313; @@ -145,6 +145,12 @@ $basicBtnC: #eb0313;
145 color: #fff; 145 color: #fff;
146 } 146 }
147 147
  148 + .hot-tag {
  149 + width: 60px;
  150 + background-color: #ff575c;
  151 + color: #fff;
  152 + }
  153 +
148 .renew-tag { 154 .renew-tag {
149 background-color: #78dc7e; 155 background-color: #78dc7e;
150 color: #fff; 156 color: #fff;