Authored by 周少峰

Merge branch 'gray'

@@ -9,87 +9,10 @@ const list = require(`${mRoot}/list`); @@ -9,87 +9,10 @@ const list = require(`${mRoot}/list`);
9 const listSeoMap = require(`${global.middleware}/seo/listSeoMap`); 9 const listSeoMap = require(`${global.middleware}/seo/listSeoMap`);
10 const helpers = global.yoho.helpers; 10 const helpers = global.yoho.helpers;
11 const _ = require('lodash'); 11 const _ = require('lodash');
12 -const tdk = require('../../../utils/getTDK');  
13 12
14 // 搜索相关接口 13 // 搜索相关接口
15 const searchApi = require(`${mRoot}/search-api`); 14 const searchApi = require(`${mRoot}/search-api`);
16 15
17 -// 店铺页  
18 -const shop = (shopId, req, res, next, brandInfo) => {  
19 - let domain = req.query.domain,  
20 - params = req.query;  
21 -  
22 - _.unset(params, 'domain');  
23 - shopId = parseInt(shopId, 10);  
24 - Object.assign(params, {shopId: shopId});  
25 -  
26 - tdk('shop', shopId, req).then(TDKObj => {  
27 - if (TDKObj[0]) {  
28 - req.tdk = {  
29 - title: TDKObj[1],  
30 - keywords: TDKObj[2],  
31 - description: TDKObj[3]  
32 - };  
33 - }  
34 - return list.getShopInfo(shopId, req.user.uid).then(shopInfo => {  
35 - let pjax = params._pjax;  
36 -  
37 - // 获取不到店铺信息跳转至首页  
38 - if (!shopInfo || _.isEmpty(shopInfo)) {  
39 - return res.redirect(helpers.urlFormat('', null, ''));  
40 - }  
41 -  
42 - // 比较品牌域名与店铺域名是否一致,不一致跳转至店铺域名  
43 - if (!pjax && shopInfo.domain && domain && domain !== _.toLower(shopInfo.domain)) {  
44 - res.redirect(helpers.urlFormat('', params, shopInfo.domain));  
45 - return;  
46 - }  
47 -  
48 - if (+shopInfo.shopTemplateType === 2) { // 经典模板  
49 -  
50 - if (pjax) {  
51 - list.getShopGoodsData(shopId, req.yoho.channel, params, shopInfo).then(result => {  
52 - Object.assign(result, {  
53 - shopId: shopId,  
54 - layout: false  
55 - });  
56 - res.render('list/goods-list', result);  
57 - }).catch(next);  
58 - return;  
59 - }  
60 -  
61 - list.getShopData(shopId, req.yoho.channel, params, shopInfo).then(result => {  
62 - Object.assign(result, {  
63 - page: 'shop',  
64 - shopId: shopId  
65 - });  
66 -  
67 - // 店铺装修为空则不cache  
68 - if (!result.shopTopBanner) {  
69 - res.set('Cache-Control', 'no-cache');  
70 - }  
71 -  
72 - res.render('list/shop-index', result);  
73 - }).catch(next);  
74 - } else { // 基础模板  
75 - list.getBaseShopData(params, Object.assign({uid: req.user.uid}, brandInfo),  
76 - req.yoho.channel, shopId).then(result => {  
77 - Object.assign(result, {page: 'list'});  
78 -  
79 - // 基础店铺装修为空则不cache  
80 - if (!result.brand || !result.brand.shopBanner) {  
81 - res.set('Cache-Control', 'no-cache');  
82 - }  
83 -  
84 - res.render('list/brand', result);  
85 - }).catch(next);  
86 - }  
87 - });  
88 - }).catch(next);  
89 -  
90 -  
91 -};  
92 -  
93 /** 16 /**
94 * 商品分类列表页 17 * 商品分类列表页
95 * @param {[type]} req [description] 18 * @param {[type]} req [description]
@@ -186,47 +109,6 @@ exports.newWithChannel = (req, res, next) => { @@ -186,47 +109,6 @@ exports.newWithChannel = (req, res, next) => {
186 }; 109 };
187 110
188 /** 111 /**
189 - * 品牌页  
190 - * @param {[type]} req [description]  
191 - * @param {[type]} res [description]  
192 - * @return {[type]} [description]  
193 - */  
194 -exports.brand = (req, res, next) => {  
195 - let brandDomain = req.query.domain;  
196 - let shopId = req.query.shopId;  
197 -  
198 - // shopId存在,直接走店铺  
199 - if (shopId) {  
200 - return shop(shopId, req, res, next);  
201 - }  
202 -  
203 - if (!brandDomain) {  
204 - return next();  
205 - }  
206 -  
207 - // 获取品牌信息  
208 - list.getBrandInfo({domain: brandDomain}).then(brandInfo => {  
209 - if (!brandInfo.hasOwnProperty('type')) {  
210 - return res.redirect(helpers.urlFormat(''));  
211 - }  
212 -  
213 - switch (parseInt(brandInfo.type, 10)) {  
214 - case 1: // 搜索  
215 - res.redirect(helpers.urlFormat('', {query: brandInfo.brandDomain}, 'search'));  
216 - break;  
217 - case 2: // 店铺  
218 - return shop(brandInfo.shopId, req, res, next, brandInfo);  
219 - default: // 品牌  
220 - res.redirect(helpers.urlFormat('', {  
221 - query: brandInfo.brandDomain,  
222 - brand: brandInfo.brandId  
223 - }, 'search'));  
224 - break;  
225 - }  
226 - }).catch(next);  
227 -};  
228 -  
229 -/**  
230 * 品牌介绍页 112 * 品牌介绍页
231 * @param {[type]} req [description] 113 * @param {[type]} req [description]
232 * @param {[type]} res [description] 114 * @param {[type]} res [description]
@@ -252,36 +134,6 @@ exports.brandAbout = (req, res, next) => { @@ -252,36 +134,6 @@ exports.brandAbout = (req, res, next) => {
252 }; 134 };
253 135
254 /** 136 /**
255 - * 店铺商品列表页  
256 - * @param {[type]} req [description]  
257 - * @param {[type]} res [description]  
258 - * @return {[type]} [description]  
259 - */  
260 -exports.shopList = (req, res, next) => {  
261 - let shopId = req.query.shopId;  
262 -  
263 - if (!shopId) {  
264 - return next();  
265 - }  
266 -  
267 - list.getShopListData(req.yoho.channel, req.query, req.user.uid).then(result => {  
268 - Object.assign(result, {  
269 - page: 'shop',  
270 - shopId: shopId  
271 - });  
272 - if (req.query.query) {  
273 - result.shopKey = req.query.query;  
274 - }  
275 -  
276 - // 店铺装修为空则不cache  
277 - if (!result.shopTopBanner) {  
278 - res.set('Cache-Control', 'no-cache');  
279 - }  
280 - res.render('list/shop-list', result);  
281 - }).catch(next);  
282 -};  
283 -  
284 -/**  
285 * ajax调用品牌页左侧水牌 137 * ajax调用品牌页左侧水牌
286 * @param {[type]} req [description] 138 * @param {[type]} req [description]
287 * @param {[type]} res [description] 139 * @param {[type]} res [description]
  1 +
  2 +'use strict';
  3 +
  4 +const mRoot = '../models';
  5 +const shopModel = require(`${mRoot}/shop-service`);
  6 +const tdk = require('../../../utils/getTDK');
  7 +
  8 +// 店铺首页(经典&基础)
  9 +exports.index = (req, res, next) => {
  10 + let domain = req.query.domain;
  11 + let shopId = req.query.shopId;
  12 +
  13 + if (!domain) {
  14 + return next();
  15 + }
  16 +
  17 + if (req.xhr && req.query._pjax && shopId) {
  18 + return shopModel.getShopGoodsData(shopId, req.yoho.channel, req.query).then(result => {
  19 + Object.assign(result, {
  20 + shopId: shopId,
  21 + layout: false
  22 + });
  23 + res.render('list/goods-list', result);
  24 + });
  25 + }
  26 +
  27 + return Promise.all([
  28 + tdk('shop', shopId, req),
  29 + shopModel.getShopInfoAsync(domain, req.yoho.channel, req.query)
  30 + ]).then(result => {
  31 + let TDKObj = result[0],
  32 + shopObj = result[1];
  33 +
  34 + if (TDKObj && TDKObj[0]) {
  35 + req.tdk = {
  36 + title: TDKObj[1],
  37 + keywords: TDKObj[2],
  38 + description: TDKObj[3]
  39 + };
  40 + }
  41 +
  42 + // 数据异常,重定向
  43 + if (shopObj.redirect) {
  44 + return res.redirect(shopObj.redirect);
  45 + }
  46 +
  47 + if (shopObj.templateType === 2) { // 经典模板
  48 + Object.assign(shopObj, {page: 'shop'});
  49 +
  50 + // 店铺装修为空则不cache
  51 + if (!shopObj.shopTopBanner) {
  52 + res.set('Cache-Control', 'no-cache');
  53 + }
  54 +
  55 + res.render('shop/index', shopObj);
  56 + } else { // 基础模版
  57 + Object.assign(shopObj, {page: 'list'});
  58 +
  59 + // 基础店铺装修为空则不cache
  60 + if (!shopObj.brand || !shopObj.brand.shopBanner) {
  61 + res.set('Cache-Control', 'no-cache');
  62 + }
  63 +
  64 + res.render('list/brand', shopObj);
  65 + }
  66 + }).catch(next);
  67 +};
  68 +
  69 +// 经典店铺列表
  70 +exports.list = (req, res, next) => {
  71 + let shopId = req.query.shopId;
  72 +
  73 + if (!shopId) {
  74 + return next();
  75 + }
  76 +
  77 + return shopModel.getShopListInfoAsync(req.yoho.channel, req.query).then(result => {
  78 + Object.assign(result, {
  79 + page: 'shop',
  80 + shopId: shopId,
  81 + shopKey: req.query.query || ''
  82 + });
  83 +
  84 + // 店铺装修为空则不cache
  85 + if (!result.shopTopBanner) {
  86 + res.set('Cache-Control', 'no-cache');
  87 + }
  88 + res.render('shop/list', result);
  89 + }).catch(next);
  90 +};
  91 +
  92 +// 经典店铺推荐文章
  93 +exports.article = (req, res, next) => {
  94 + let brands = req.query.brands;
  95 +
  96 + if (!brands) {
  97 + return next();
  98 + }
  99 +
  100 + return shopModel.getShopArticleByBrandsAsync(brands).then(result => {
  101 + res.render('shop/article', Object.assign(result, {layout: false}));
  102 + }).catch(next);
  103 +};
@@ -155,7 +155,7 @@ const getLikeAsync = (skn, limit) => { @@ -155,7 +155,7 @@ const getLikeAsync = (skn, limit) => {
155 method: 'app.search.findLike', 155 method: 'app.search.findLike',
156 limit: limit || 10, 156 limit: limit || 10,
157 product_skn: skn 157 product_skn: skn
158 - }); 158 + }, {cache: 86400});
159 }; 159 };
160 160
161 // 根据small_sort从redis获取分类下的关键词 161 // 根据small_sort从redis获取分类下的关键词
@@ -23,34 +23,12 @@ const brandFolderSeries = '经典系列'; @@ -23,34 +23,12 @@ const brandFolderSeries = '经典系列';
23 const folderTitle = '经典款型'; 23 const folderTitle = '经典款型';
24 const seriesTitle = '经典系列'; 24 const seriesTitle = '经典系列';
25 25
26 -// 经典店铺list url  
27 -const shopListUrl = '/product/shoplist';  
28 -  
29 // 搜索分类信息需要的参数 26 // 搜索分类信息需要的参数
30 const positionId = 10; 27 const positionId = 10;
31 28
32 // 获取分类左侧广告id 29 // 获取分类左侧广告id
33 const sortAdsId = 79; 30 const sortAdsId = 79;
34 31
35 -  
36 -const _getGender = (channel) => {  
37 - let gender;  
38 -  
39 - switch (channel) {  
40 - case 'boys':  
41 - gender = '1,3';  
42 - break;  
43 - case 'girls':  
44 - gender = '2,3';  
45 - break;  
46 - default:  
47 - gender = '1,2,3';  
48 - break;  
49 - }  
50 -  
51 - return gender;  
52 -};  
53 -  
54 /** 32 /**
55 * 获取商品分类列表数据 33 * 获取商品分类列表数据
56 */ 34 */
@@ -566,402 +544,6 @@ const getShopInfo = (shopId, uid) => { @@ -566,402 +544,6 @@ const getShopInfo = (shopId, uid) => {
566 }); 544 });
567 }; 545 };
568 546
569 -/**  
570 - * 获取经典模板店铺数据  
571 - * @param shopId  
572 - * @param uid  
573 - * @param params  
574 - * @param shopInfo 店铺介绍  
575 - */  
576 -const getShopData = (shopId, channel, params, shopInfo) => {  
577 - let gender = _getGender(channel);  
578 -  
579 - params = params || {};  
580 - params.shopId = shopId;  
581 -  
582 - return Promise.all([  
583 - headerModel.requestHeaderData(channel), // 头部数据  
584 - searchApi.getShopDecorator(shopId), // 店铺装修数据  
585 - searchApi.getProductList(Object.assign({  
586 - shop_id: shopId  
587 - }, params), 'shop'), // 搜索店铺商品  
588 - searchApi.getShopBrands(shopId), // 店铺品牌数据  
589 - shopApi.shopCouponListAsync(shopId) // 店铺优惠券数据  
590 - ]).then(result => {  
591 - let finalResult = {};  
592 -  
593 - Object.assign(finalResult,  
594 - result[0], // 头部数据  
595 - searchHandler.handlePathNavData(shopInfo, params, 'shop', channel), // 面包屑导航  
596 - searchHandler.getBrandShopSeo(channel, {shopName: shopInfo.shopName || shopInfo.brandName}, params) // 店铺SEO  
597 - );  
598 -  
599 - _.set(finalResult, 'headerData.header', true);  
600 -  
601 - // 店铺装修  
602 - if (result[1].code === 200) {  
603 - Object.assign(finalResult, shopHandler.getShopDecorator(result[1].data, params, shopId));  
604 -  
605 - _.set(finalResult, 'shopTopBanner.brandIntro', {  
606 - shopId: shopId,  
607 - brandName: shopInfo.brandName || '',  
608 - isFavorite: shopInfo.isFavorite || false,  
609 - brandCont: shopInfo.brandCont || ''  
610 - });  
611 - } else {  
612 - return Promise.reject('No ShopDecorator data');  
613 - }  
614 -  
615 - // 获取商品数据和顶部筛选条件  
616 - if (result[2].code === 200) {  
617 - let allGoods = {  
618 - name: '全部商品 ALL',  
619 - sort: searchHandler.handleOptsData(params, _.get(result[2], 'data.total', 0)),  
620 - list: productProcess.processProductList(_.get(result[2], 'data.product_list', []), {  
621 - newCoverSort: true,  
622 - showDiscount: false,  
623 - gender: gender  
624 - }),  
625 - href: `/product/shoplist?navBar=1&shopId=${shopId}`  
626 - };  
627 -  
628 - _.set(allGoods, 'sort.newPage', true); // 启用新的分页导航  
629 -  
630 - finalResult.allGoods = allGoods;  
631 - }  
632 -  
633 - let sknList = []; // 资源位配置商品skn  
634 - let prodList = _.concat(_.get(finalResult, 'newArrivel.list', []),  
635 - _.get(finalResult, 'hotSingle.list', []));  
636 -  
637 - _.forEach(prodList, value => {  
638 - sknList.push(value.productSkn);  
639 - });  
640 -  
641 - let articleApiMethod = [], // 通过品牌获取相关文章接口  
642 - apiMethod = [  
643 - searchApi.getProductList({  
644 - viewNum: sknList.length,  
645 - query: _.join(_.uniq(sknList), ',')  
646 - }, 'shop')  
647 - ];  
648 -  
649 - if (result[3].code === 200 && result[3].data) {  
650 - _.forEach(result[3].data, value => {  
651 - articleApiMethod.push(  
652 - searchApi.getArticleByBrand(value.brand_id, 'udid') // 品牌推荐文章  
653 - );  
654 - });  
655 - }  
656 -  
657 - if (result[4].data && !_.isEmpty(result[4].data)) {  
658 - finalResult.coupon = searchHandler.handleBrandShopCoupons(result[4].data, {shopId: shopId});  
659 - }  
660 -  
661 - // 根据店铺id获取分类  
662 - apiMethod.push(searchApi.getSortList({shop_id: shopId}));  
663 - apiMethod = _.concat(apiMethod, articleApiMethod);  
664 -  
665 - return Promise.all(apiMethod).then(subRes => {  
666 - // 设置资源位商品封面图  
667 - if (subRes[0].code === 200) {  
668 - let list = {};  
669 -  
670 - prodList = productProcess.processProductList(_.get(subRes[0], 'data.product_list', []), {  
671 - newCoverSort: true,  
672 - showDiscount: false,  
673 - gender: gender  
674 - });  
675 -  
676 - _.forEach(prodList, value => {  
677 - list[value.product_skn] = {  
678 - img: value.default_images,  
679 - title: value.product_name,  
680 - price: ${value.sales_price}`  
681 - };  
682 - });  
683 -  
684 - if (_.has(finalResult, 'newArrivel.list')) {  
685 - _.forEach(finalResult.newArrivel.list, value => {  
686 - if (list[value.productSkn]) {  
687 - Object.assign(value, list[value.productSkn]);  
688 - }  
689 - });  
690 - }  
691 -  
692 - if (_.has(finalResult, 'hotSingle.list')) {  
693 - _.forEach(finalResult.hotSingle.list, value => {  
694 - if (list[value.productSkn]) {  
695 - Object.assign(value, list[value.productSkn]);  
696 - }  
697 - });  
698 - }  
699 - }  
700 -  
701 - if (subRes[1].code === 200) {  
702 - let groupSort = _.get(subRes[1], 'data', []);  
703 -  
704 - finalResult.leftContent = searchHandler.handleSortData(groupSort, params, params, '/product/shoplist');  
705 -  
706 - _.set(finalResult, 'brandShopAd', {baseUrl: shopListUrl});  
707 -  
708 - if (finalResult.allGoods) {  
709 - Object.assign(finalResult.allGoods, searchHandler.setShopSort(groupSort, Object.assign({},  
710 - params, {page: 1})), searchHandler.setGenderFilter(params));  
711 - }  
712 - }  
713 -  
714 - let articleList = [];  
715 -  
716 - for (let i = 2; i < subRes.length; i++) {  
717 - articleList = _.concat(articleList, _.get(subRes[i], 'data', []));  
718 - }  
719 -  
720 - if (articleList.length >= 3) {  
721 - let trendList = [];  
722 -  
723 - for (let i = 0; i < 3; i++) {  
724 - trendList.push({  
725 - href: helpers.urlFormat(`/guang/${articleList[i].id}.html`, null),  
726 - src: helpers.getForceSourceUrl(articleList[i].src) +  
727 - '?imageView2/1/w/{width}/h/{height}',  
728 - mainTitle: articleList[i].title,  
729 - Subtitle: articleList[i].intro  
730 - });  
731 - articleList = _.concat(articleList, _.get(subRes[i], 'data', []));  
732 - }  
733 -  
734 - finalResult.trendInfo = {  
735 - name: '潮流资讯 HOT ITEMS',  
736 - trendList: trendList  
737 - };  
738 - }  
739 -  
740 - return finalResult;  
741 - });  
742 - });  
743 -};  
744 -  
745 -/**  
746 - * 获取店铺商品数据  
747 - */  
748 -const getShopGoodsData = (shopId, channel, params) => {  
749 - let gender = _getGender(channel);  
750 - let resData = {};  
751 -  
752 - _.unset(params, '_pjax');  
753 - return Promise.all([  
754 - searchApi.getProductList(Object.assign({  
755 - shop_id: shopId  
756 - }, params), 'shop'), // 搜索店铺商品  
757 - searchApi.getSortList({shop_id: shopId}) // 根据店铺id获取分类  
758 - ]).then(result => {  
759 - // 获取商品数据和顶部筛选条件  
760 - if (result[0].code === 200) {  
761 - Object.assign(resData, {  
762 - sort: searchHandler.handleOptsData(params, _.get(result[0], 'data.total', 0)),  
763 - list: productProcess.processProductList(_.get(result[0], 'data.product_list', []), {  
764 - newCoverSort: true,  
765 - showDiscount: false,  
766 - gender: gender  
767 - })  
768 - });  
769 - _.set(resData, 'sort.newPage', true); // 启用新的分页导航  
770 - }  
771 -  
772 - if (result[1].code === 200) {  
773 - let groupSort = _.get(result[1], 'data', []);  
774 -  
775 - Object.assign(resData, searchHandler.setShopSort(groupSort, Object.assign({}, params,  
776 - {page: 1})), searchHandler.setGenderFilter(params));  
777 - }  
778 -  
779 - return resData;  
780 - });  
781 -};  
782 -  
783 -const getShopListData = (channel, params, uid) => {  
784 - let gender = _getGender(channel),  
785 - shopId = params.shopId,  
786 - navBar = params.navBar || 1;  
787 - let apiArr = [  
788 - headerModel.requestHeaderData(channel), // 头部数据  
789 - searchApi.getShopDecorator(shopId), // 店铺装修数据  
790 - searchApi.getShopInfo(shopId, uid), // 店铺介绍  
791 - searchApi.getProductList(Object.assign({shop_id: shopId}, params,  
792 - {limit: (params.limit || 60) - 1}), 'shop'), // 搜索店铺商品  
793 - searchApi.getSortList({shop_id: shopId}) // 店铺分类  
794 - ];  
795 -  
796 - if (_.has(params, 'query')) {  
797 - // 如果有店内搜索,则并行查询店铺所有商品,搜索不到商品则显示所有商品  
798 - apiArr.push(searchApi.getProductList(Object.assign({shop_id: shopId},  
799 - params, {query: ''}), 'shop')); // 搜索店铺所有商品  
800 - }  
801 -  
802 -  
803 - return Promise.all(apiArr).then(result => {  
804 - let finalResult = {  
805 - headerData: Object.assign(result[0].headerData, {header: true})  
806 - };  
807 -  
808 - // 面包屑导航  
809 - Object.assign(finalResult, searchHandler.handlePathNavData({}, params, 'shop', channel));  
810 -  
811 - // 店铺装修  
812 - if (result[1].code === 200) {  
813 - Object.assign(finalResult, shopHandler.getShopDecorator(result[1].data, params, shopId));  
814 -  
815 - // 设置shop nav选中状态  
816 - _.set(finalResult, `navigationBar[${navBar}].current`, true);  
817 -  
818 - if (result[2].code === 200) {  
819 - let data = _.get(result[2], 'data', {});  
820 -  
821 - _.set(finalResult, 'shopTopBanner.brandIntro', {  
822 - shopId: shopId,  
823 - brandName: data.shop_name || '',  
824 - isFavorite: data.is_favorite === 'Y',  
825 - brandCont: data.shop_intro || ''  
826 - });  
827 -  
828 - // 店铺SEO  
829 - Object.assign(finalResult, searchHandler.getBrandShopSeo(channel, {  
830 - shopName: data.shop_name  
831 - }, params));  
832 - }  
833 - } else {  
834 - return Promise.reject('No ShopDecorator data');  
835 - }  
836 -  
837 - // 获取商品数据和顶部筛选条件  
838 - if (result[3].code === 200) {  
839 - let info = result[3];  
840 - let goodsList = _.get(info, 'data.product_list', []);  
841 -  
842 - if (goodsList.length) {  
843 - let totalPage = _.get(info, 'data.total', 1);  
844 -  
845 - Object.assign(finalResult, {  
846 - filters: searchHandler.handleFilterDataAll(info.data, params),  
847 - opts: searchHandler.handleOptsData(params, totalPage),  
848 - goods: productProcess.processProductList(goodsList, {  
849 - newCoverSort: true,  
850 - showDiscount: false,  
851 - gender: _getGender(channel),  
852 - query: params.query  
853 - }),  
854 - hasNextPage: searchHandler.handleNextPage(params, totalPage),  
855 - footPager: searchHandler.handlePagerData(totalPage, params)  
856 - });  
857 -  
858 - _.set(finalResult, 'filters.checkedConditions.clearUrl',  
859 - `?navBar=${params.navBar}&shopId=${params.shopId}`);  
860 - } else {  
861 - finalResult.searchEmpty = true;  
862 -  
863 - if (result[5] && result[5].code === 200) {  
864 - let allGoods = {  
865 - name: '全部商品 ALL',  
866 - sort: searchHandler.handleOptsData(params, _.get(result[5], 'data.total', 0)),  
867 - list: productProcess.processProductList(_.get(result[5], 'data.product_list', []), {  
868 - newCoverSort: true,  
869 - showDiscount: false,  
870 - gender: gender  
871 - })  
872 - };  
873 -  
874 - _.set(allGoods, 'sort.newPage', true); // 启用新的分页导航  
875 -  
876 - finalResult.allGoods = allGoods;  
877 - }  
878 - }  
879 - }  
880 -  
881 - if (result[4].code === 200) {  
882 -  
883 - let groupSort = _.get(result[4], 'data', []),  
884 - noPageQs = Object.assign({}, params, {page: 1});  
885 -  
886 - finalResult.leftContent = searchHandler.handleSortData(groupSort, noPageQs, params);  
887 -  
888 - _.set(finalResult, 'brandShopAd', {baseUrl: shopListUrl});  
889 -  
890 - if (finalResult.allGoods) {  
891 - Object.assign(finalResult.allGoods, searchHandler.setShopSort(groupSort, noPageQs));  
892 - }  
893 - }  
894 -  
895 - finalResult.criteo = {skn: searchHandler.getCriteo(_.get(finalResult, 'goods'))};  
896 -  
897 - return finalResult;  
898 - });  
899 -};  
900 -  
901 -/**  
902 - * 获取基础模板店铺数据  
903 - */  
904 -const getBaseShopData = (params, extra, channel, shopId) => {  
905 - let resData = {};  
906 -  
907 - params.shopId = shopId;  
908 -  
909 - return Promise.all([  
910 - getBrandData(params, extra, channel),  
911 - searchApi.getShopDecorator(shopId), // 店铺装修数据  
912 - searchApi.getShopInfo(shopId, extra.uid),  
913 - shopApi.shopCouponListAsync(shopId) // 店铺优惠券数据  
914 - ]).then(result => {  
915 - let brand = result[0] || {};  
916 -  
917 - Object.assign(resData, brand);  
918 -  
919 - if (result[1].code === 200) {  
920 - let data = result[1].data || {},  
921 - decorator = shopHandler.getShopDecorator(data, {}, shopId, true);  
922 -  
923 - Object.assign(decorator.shopTopBannerBase || {}, {  
924 - shopId: shopId,  
925 - bannerHeight: 150,  
926 - shopHome: `/?shopId=${shopId}`,  
927 - shopIntro: `/shop${shopId}-about`,  
928 - coled: _.get(result[2], 'data.is_favorite', 'N') === 'Y'  
929 - });  
930 -  
931 - _.set(resData, 'brand.shopBanner', decorator.shopTopBannerBase);  
932 - _.unset(resData, 'brand.brandBanner');  
933 -  
934 - if (decorator.signboard) {  
935 - _.unset(resData, 'brand.node');  
936 - _.set(resData, 'brand.signboard', decorator.signboard);  
937 - }  
938 - }  
939 -  
940 - if (result[2].code === 200) {  
941 - let shopName = _.get(result[2], 'data.shop_name', '');  
942 -  
943 - _.set(resData, 'brand.shopBanner.shopName', shopName);  
944 - _.set(resData, 'brand.pathNav[2]', {  
945 - name: shopName,  
946 - pathTitle: shopName  
947 - });  
948 -  
949 - // 店铺SEO  
950 - Object.assign(resData, searchHandler.getBrandShopSeo(channel, {  
951 - shopName: shopName  
952 - }, params));  
953 - }  
954 -  
955 - _.unset(resData, 'brand.coupon');  
956 - if (result[3].data && !_.isEmpty(result[3].data)) {  
957 - _.set(resData, 'brand.coupon',  
958 - searchHandler.handleBrandShopCoupons(result[3].data, {shopId: shopId}));  
959 - }  
960 -  
961 - return resData;  
962 - });  
963 -};  
964 -  
965 const getUserCoupunStatus = (id, uid, type) => { 547 const getUserCoupunStatus = (id, uid, type) => {
966 if (type === 'shop') { 548 if (type === 'shop') {
967 return shopApi.shopCouponListAsync(id, uid).then(result => { 549 return shopApi.shopCouponListAsync(id, uid).then(result => {
@@ -1004,9 +586,5 @@ module.exports = { @@ -1004,9 +586,5 @@ module.exports = {
1004 getNodeContentData, 586 getNodeContentData,
1005 getAdnav, 587 getAdnav,
1006 getShopInfo, 588 getShopInfo,
1007 - getShopData,  
1008 - getShopGoodsData,  
1009 - getShopListData,  
1010 - getBaseShopData,  
1011 getUserCoupunStatus 589 getUserCoupunStatus
1012 }; 590 };
@@ -49,3 +49,18 @@ exports.queryShopsByBrandId = (sid, bid) => { @@ -49,3 +49,18 @@ exports.queryShopsByBrandId = (sid, bid) => {
49 shop_id: sid 49 shop_id: sid
50 }); 50 });
51 }; 51 };
  52 +
  53 +
  54 +/**
  55 + * 根据shopId获取店铺基本信息
  56 + * @return
  57 + */
  58 +exports.getShopInfo = (shopId, uid) => {
  59 + let finalParams = {
  60 + method: 'app.shops.getIntro',
  61 + shop_id: shopId || 0,
  62 + uid: uid || 0
  63 + };
  64 +
  65 + return api.get('', finalParams, config.apiCache);
  66 +};
@@ -355,21 +355,26 @@ const _handleSaleCategory = (shopId, baseUrl, resourceObj) => { @@ -355,21 +355,26 @@ const _handleSaleCategory = (shopId, baseUrl, resourceObj) => {
355 */ 355 */
356 exports.getShopDecorator = (data, params, shopId, base) => { 356 exports.getShopDecorator = (data, params, shopId, base) => {
357 let dest = {}; 357 let dest = {};
  358 + let sourceFn;
358 359
359 if (base) { 360 if (base) {
  361 + sourceFn = {
  362 + signboard(info) {
  363 + dest.signboard = signboard(info);
  364 + },
  365 + shopTopBanner_base(info) {
  366 + Object.assign(dest, shopTopBannerBase(info));
  367 + }
  368 + };
  369 +
360 _.forEach(data.list, (value) => { 370 _.forEach(data.list, (value) => {
  371 + if (!sourceFn[value.resource_name]) {
  372 + return;
  373 + }
  374 +
361 let info = Fn.pipe(JSON.parse, _.partial(_handleSaleCategory, shopId, ''))(value.resource_data || '[]'); 375 let info = Fn.pipe(JSON.parse, _.partial(_handleSaleCategory, shopId, ''))(value.resource_data || '[]');
362 376
363 - switch (value.resource_name) {  
364 - case 'signboard':  
365 - dest.signboard = signboard(info);  
366 - break;  
367 - case 'shopTopBanner_base':  
368 - Object.assign(dest, shopTopBannerBase(info));  
369 - break;  
370 - default:  
371 - break;  
372 - } 377 + sourceFn[value.resource_name](info);
373 }); 378 });
374 } else { 379 } else {
375 Object.assign(dest, { 380 Object.assign(dest, {
@@ -377,46 +382,50 @@ exports.getShopDecorator = (data, params, shopId, base) => { @@ -377,46 +382,50 @@ exports.getShopDecorator = (data, params, shopId, base) => {
377 hotSingle: {} 382 hotSingle: {}
378 }); 383 });
379 384
  385 + sourceFn = {
  386 + newProducts(info) {
  387 + Object.assign(dest.newArrivel, newProducts(info));
  388 + },
  389 + hotProducts(info) {
  390 + Object.assign(dest.hotSingle, hotProducts(info));
  391 + },
  392 + goodsTabBar(info) {
  393 + let tabBar = goodsTabBar(info, shopId);
  394 +
  395 + Object.assign(dest.newArrivel, {navs: tabBar.new});
  396 + Object.assign(dest.hotSingle, {navs: tabBar.hot});
  397 + },
  398 + shopTopBanner(info) {
  399 + Object.assign(dest, shopTopBanner(info));
  400 + },
  401 + navigationBar(info) {
  402 + Object.assign(dest, navigationBar(info, shopId, params));
  403 + },
  404 + largeSlideImg(info) {
  405 + Object.assign(dest, largeSlideImg(info, shopId));
  406 + },
  407 + oneRowTwoColImages(info) {
  408 + Object.assign(dest, oneRowTwoColImages(info, shopId));
  409 + },
  410 + recommend(info) {
  411 + Object.assign(dest, recommend(info, shopId));
  412 + },
  413 + brandBrowse(info) {
  414 + Object.assign(dest, brandBrowse(info, params));
  415 + },
  416 + hotRecommend(info) {
  417 + Object.assign(dest, hotRecommend(info));
  418 + }
  419 + };
  420 +
380 _.forEach(data.list, (value) => { 421 _.forEach(data.list, (value) => {
381 - let info = Fn.pipe(JSON.parse, _.partial(_handleSaleCategory, shopId, shopListUrl))(value.resource_data || '[]'); // eslint-disable-line  
382 - let tabBar;  
383 -  
384 - switch (value.resource_name) {  
385 - case 'newProducts':  
386 - Object.assign(dest.newArrivel, newProducts(info));  
387 - break;  
388 - case 'hotProducts':  
389 - Object.assign(dest.hotSingle, hotProducts(info));  
390 - break;  
391 - case 'goodsTabBar':  
392 - tabBar = goodsTabBar(info, shopId);  
393 - Object.assign(dest.newArrivel, {navs: tabBar.new});  
394 - Object.assign(dest.hotSingle, {navs: tabBar.hot});  
395 - break;  
396 - case 'shopTopBanner':  
397 - Object.assign(dest, shopTopBanner(info));  
398 - break;  
399 - case 'navigationBar':  
400 - Object.assign(dest, navigationBar(info, shopId, params));  
401 - break;  
402 - case 'largeSlideImg':  
403 - Object.assign(dest, largeSlideImg(info, shopId));  
404 - break;  
405 - case 'oneRowTwoColImages':  
406 - Object.assign(dest, oneRowTwoColImages(info, shopId));  
407 - break;  
408 - case 'recommend':  
409 - Object.assign(dest, recommend(info, shopId));  
410 - break;  
411 - case 'brandBrowse':  
412 - Object.assign(dest, brandBrowse(info, params));  
413 - break;  
414 - case 'hotRecommend':  
415 - Object.assign(dest, hotRecommend(info));  
416 - break;  
417 - default:  
418 - break; 422 + if (!sourceFn[value.resource_name]) {
  423 + return;
419 } 424 }
  425 +
  426 + let info = Fn.pipe(JSON.parse, _.partial(_handleSaleCategory, shopId, shopListUrl))(value.resource_data || '[]'); // eslint-disable-line
  427 +
  428 + sourceFn[value.resource_name](info);
420 }); 429 });
421 } 430 }
422 431
@@ -6,10 +6,43 @@ @@ -6,10 +6,43 @@
6 const Promise = require('bluebird'); 6 const Promise = require('bluebird');
7 const co = Promise.coroutine; 7 const co = Promise.coroutine;
8 const _ = require('lodash'); 8 const _ = require('lodash');
  9 +const helpers = global.yoho.helpers;
9 10
10 const api = require('./shop-api'); 11 const api = require('./shop-api');
  12 +const searchApi = require('./search-api');
  13 +const shopHandler = require('./shop-handler');
  14 +const searchHandler = require('./search-handler');
  15 +const headerModel = require('../../../doraemon/models/header');
  16 +const productProcess = require('../../../utils/product-process');
  17 +
11 const DEFAULT_IMG = '01091c21f2317a64f123f1649fbbccf7ba'; 18 const DEFAULT_IMG = '01091c21f2317a64f123f1649fbbccf7ba';
12 19
  20 +// 经典店铺list url
  21 +const shopListUrl = '/product/shoplist';
  22 +
  23 +const needParams = ['query', 'msort', 'misort', 'category_id', 'gender', 'shelveTime'];
  24 +
  25 +/**
  26 + * channel=>gender
  27 + */
  28 +const _getGender = (channel) => {
  29 + let gender;
  30 +
  31 + switch (channel) {
  32 + case 'boys':
  33 + gender = '1,3';
  34 + break;
  35 + case 'girls':
  36 + gender = '2,3';
  37 + break;
  38 + default:
  39 + gender = '1,2,3';
  40 + break;
  41 + }
  42 +
  43 + return gender;
  44 +};
  45 +
13 /** 46 /**
14 * 生成缩略图 47 * 生成缩略图
15 */ 48 */
@@ -54,6 +87,477 @@ const _shopTopBanner = data => { @@ -54,6 +87,477 @@ const _shopTopBanner = data => {
54 87
55 const _shopTopBannerBase = _shopTopBanner; 88 const _shopTopBannerBase = _shopTopBanner;
56 89
  90 +const _getShopData = (channel, params, shopInfo) => {
  91 + params = params || {};
  92 +
  93 + let gender = _getGender(channel),
  94 + shopId = params.shopId;
  95 + let resData = {shopId: shopId};
  96 +
  97 + return co(function * () {
  98 + let result = yield Promise.props({
  99 + header: headerModel.requestHeaderData(channel), // 头部数据
  100 + sort: searchApi.getSortList({shop_id: shopId}),
  101 + decorator: searchApi.getShopDecorator(shopId), // 店铺装修数据
  102 + product: searchApi.getProductList(Object.assign({shop_id: shopId,
  103 + need_filter: 'no'}, params), 'shop'), // 搜索店铺商品
  104 + brands: searchApi.getShopBrands(shopId), // 店铺品牌数据
  105 + coupons: api.shopCouponListAsync(shopId), // 店铺优惠券数据
  106 + shopInfo: shopInfo ? Promise.resolve(shopInfo) : api.getShopInfo(shopId)
  107 + });
  108 +
  109 + if (!shopInfo) {
  110 + shopInfo = _.get(result, 'shopInfo.data', {});
  111 + }
  112 +
  113 + Object.assign(resData,
  114 + result.header, // 头部数据
  115 + searchHandler.handlePathNavData({brandName: shopInfo.shop_name}, params, 'shop', channel), // 面包屑导航
  116 + searchHandler.getBrandShopSeo(channel, {shopName: shopInfo.shop_name}, params) // 店铺SEO
  117 + );
  118 +
  119 + _.set(resData, 'headerData.header', true);
  120 +
  121 + // 店铺装修
  122 + if (result.decorator.code === 200) {
  123 + Object.assign(resData, shopHandler.getShopDecorator(result.decorator.data, params, shopId));
  124 +
  125 + _.set(resData, 'shopTopBanner.brandIntro', {
  126 + shopId: shopId,
  127 + brandName: shopInfo.shop_name || '',
  128 + brandCont: shopInfo.shop_intro || ''
  129 + });
  130 + } else {
  131 + return Promise.reject('No ShopDecorator data');
  132 + }
  133 +
  134 + // 获取商品数据和顶部筛选条件
  135 + if (result.product.code === 200) {
  136 + let data = result.product.data;
  137 + let allGoods = {
  138 + name: '全部商品 ALL',
  139 + sort: searchHandler.handleOptsData(params, _.get(data, 'total', 0)),
  140 + list: productProcess.processProductList(_.get(data, 'product_list', []), {
  141 + newCoverSort: true,
  142 + showDiscount: false,
  143 + gender: gender
  144 + }),
  145 + href: `/product/shoplist?navBar=1&shopId=${shopId}`
  146 + };
  147 +
  148 + _.set(allGoods, 'sort.newPage', true); // 启用新的分页导航
  149 +
  150 + resData.allGoods = allGoods;
  151 + }
  152 +
  153 + // 店铺类目
  154 + if (result.sort.code === 200) {
  155 + let groupSort = _.get(result.sort, 'data', []);
  156 +
  157 + resData.leftContent = searchHandler.handleSortData(groupSort, params, params, shopListUrl);
  158 +
  159 + _.set(resData, 'brandShopAd', {baseUrl: shopListUrl});
  160 +
  161 + if (resData.allGoods) {
  162 + Object.assign(resData.allGoods, searchHandler.setShopSort(groupSort, Object.assign({},
  163 + params, {page: 1})), searchHandler.setGenderFilter(params));
  164 + }
  165 + }
  166 +
  167 + // 店铺优惠券
  168 + if (result.coupons.data && !_.isEmpty(result.coupons.data)) {
  169 + resData.coupon = searchHandler.handleBrandShopCoupons(result.coupons.data, {shopId: shopId});
  170 + }
  171 +
  172 + let sknList = []; // 资源位配置商品skn
  173 + let prodList = _.concat(_.get(resData, 'newArrivel.list', []),
  174 + _.get(resData, 'hotSingle.list', []));
  175 +
  176 + _.forEach(prodList, value => {
  177 + sknList.push(value.productSkn);
  178 + });
  179 +
  180 + let apiMethod = [
  181 + searchApi.getProductList({
  182 + viewNum: sknList.length,
  183 + query: _.join(_.uniq(sknList), ',')
  184 + }, 'shop')
  185 + ];
  186 +
  187 + // 店铺品牌
  188 + if (result.brands.code === 200 && result.brands.data) {
  189 + let brands = [];
  190 +
  191 + _.forEach(result.brands.data, value => {
  192 + brands.push(value.brand_id);
  193 + });
  194 +
  195 + resData.shopBrands = brands.join(',');
  196 + }
  197 +
  198 + let subRes = yield Promise.all(apiMethod);
  199 +
  200 + // 设置资源位商品封面图
  201 + if (subRes[0].code === 200) {
  202 + let list = {};
  203 +
  204 + prodList = productProcess.processProductList(_.get(subRes[0], 'data.product_list', []), {
  205 + newCoverSort: true,
  206 + showDiscount: false,
  207 + gender: gender
  208 + });
  209 +
  210 + _.forEach(prodList, value => {
  211 + list[value.product_skn] = {
  212 + img: value.default_images,
  213 + title: value.product_name,
  214 + price: ${value.sales_price}`
  215 + };
  216 + });
  217 +
  218 + if (_.has(resData, 'newArrivel.list')) {
  219 + _.forEach(resData.newArrivel.list, value => {
  220 + if (list[value.productSkn]) {
  221 + Object.assign(value, list[value.productSkn]);
  222 + }
  223 + });
  224 + }
  225 +
  226 + if (_.has(resData, 'hotSingle.list')) {
  227 + _.forEach(resData.hotSingle.list, value => {
  228 + if (list[value.productSkn]) {
  229 + Object.assign(value, list[value.productSkn]);
  230 + }
  231 + });
  232 + }
  233 + }
  234 +
  235 + resData.trendInfo = true; // 展示店铺推荐文章
  236 +
  237 + return resData;
  238 + })();
  239 +};
  240 +
  241 +
  242 +/**
  243 + * 获取基础模板店铺数据
  244 + */
  245 +const _getBaseShopData = (channel, params, shopInfo) => {
  246 + params = params || {};
  247 +
  248 + let searchParams = searchHandler.getSearchParams(params);
  249 + let shopId = params.shopId;
  250 +
  251 + return co(function * () {
  252 + let result = yield Promise.props({
  253 + header: headerModel.requestHeaderData(channel), // 头部数据
  254 + sort: searchApi.getSortList({shop_id: shopId}),
  255 + decorator: searchApi.getShopDecorator(shopId), // 店铺装修数据
  256 + product: searchApi.getProductList(Object.assign(searchParams,
  257 + {shop_id: shopId}), 'shop'), // 搜索店铺商品
  258 + coupons: api.shopCouponListAsync(shopId), // 店铺优惠券数据
  259 + shopInfo: shopInfo ? Promise.resolve(shopInfo) : api.getShopInfo(shopId)
  260 + });
  261 +
  262 + if (!shopInfo) {
  263 + shopInfo = _.get(result, 'shopInfo.data', {});
  264 + }
  265 +
  266 + const shopName = shopInfo.shop_name;
  267 +
  268 + let resData = {
  269 + shopId: shopId,
  270 + brand: Object.assign({brandShopAd: true},
  271 + searchHandler.handlePathNavData({brandName: shopName}, params, 'shop', channel))
  272 + };
  273 +
  274 + Object.assign(resData,
  275 + result.header, // 头部数据
  276 + searchHandler.getBrandShopSeo(channel, {shopName: shopName}, params));
  277 +
  278 + _.set(resData, 'headerData.header', true);
  279 + _.set(resData, 'brand.shopBanner', {
  280 + shopId: shopId,
  281 + shopName: shopName,
  282 + shopHome: `/?shopId=${shopId}`,
  283 + shopIntro: `/shop${shopId}-about`
  284 + });
  285 +
  286 + // 店铺装修
  287 + if (result.decorator.code === 200) {
  288 + let data = result.decorator.data || {},
  289 + decorator = shopHandler.getShopDecorator(data, {}, shopId, true);
  290 +
  291 + Object.assign(resData.brand.shopBanner, decorator.shopTopBannerBase || {});
  292 +
  293 + // 设置店招高度
  294 + _.set(resData, 'brand.shopBanner.bannerHeight', 150);
  295 +
  296 + if (decorator.signboard) {
  297 + _.set(resData, 'brand.signboard', decorator.signboard);
  298 + }
  299 + }
  300 +
  301 + // 获取左侧类目数据
  302 + if (result.sort.code === 200) {
  303 + let dps = {shopId: shopId};
  304 +
  305 + _.forEach(needParams, value => {
  306 + if (params[value]) {
  307 + dps[value] = params[value];
  308 + }
  309 + });
  310 +
  311 + Object.assign(resData.brand, {
  312 + leftContent: searchHandler.handleSortData(result.sort.data, dps, params)
  313 + });
  314 + }
  315 +
  316 + // 获取商品数据和顶部筛选条件
  317 + if (result.product.code === 200) {
  318 + let data = result.product.data;
  319 + let filters = Object.assign(searchHandler.handleFilterDataAll(data, params),
  320 + resData.brand.leftContent.sort);
  321 +
  322 + filters.checkedConditions.conditions = _.concat(filters.checkedConditions.conditions,
  323 + resData.brand.leftContent.checked);
  324 +
  325 + Object.assign(resData.brand, {
  326 + filters: filters,
  327 + opts: searchHandler.handleOptsData(params, data.total, data.filter),
  328 + totalCount: data.total,
  329 + footPager: searchHandler.handlePagerData(data.total, params),
  330 + goods: productProcess.processProductList(data.product_list,
  331 + Object.assign({showDiscount: false, from: {type: 'shop', params: params}}, params)),
  332 + hasNextPage: searchHandler.handleNextPage(params, data.total),
  333 +
  334 + // 最近浏览记录
  335 + latestWalk: 7
  336 + });
  337 +
  338 + // 店铺页不显示品牌筛选项
  339 + _.unset(resData, 'brand.filters.brand');
  340 + }
  341 +
  342 + // 店铺优惠券
  343 + if (result.coupons && !_.isEmpty(result.coupons.data)) {
  344 + _.set(resData, 'brand.coupon',
  345 + searchHandler.handleBrandShopCoupons(result.coupons.data, {shopId: shopId}));
  346 + }
  347 +
  348 + return resData;
  349 + })();
  350 +};
  351 +
  352 +exports.getShopInfoAsync = (domain, channel, params) => {
  353 + let resData;
  354 + let shopId = _.get(params, 'shopId');
  355 +
  356 + return co(function * () {
  357 + let data, shopInfo;
  358 +
  359 + _.unset(params, 'domain');
  360 + domain = _.toLower(domain);
  361 +
  362 + if (shopId) { // 带id访问
  363 + let result = yield api.getShopInfo(shopId);
  364 +
  365 + data = result.data;
  366 +
  367 + // 根据店铺ID,未取到店铺信息,跳转至首页
  368 + if (result.code !== 200 || _.isEmpty(data)) {
  369 + return {redirect: helpers.urlFormat('')};
  370 + }
  371 +
  372 + let lowResDomain = _.toLower(data.shop_domain);
  373 +
  374 + // 根据店铺ID取到的店铺domain与链接中domain不一致,跳转至店铺域名下(解决店铺域名与品牌域名混用的问题)
  375 + if (lowResDomain !== domain) {
  376 + return {redirect: helpers.urlFormat('', params, lowResDomain)};
  377 + }
  378 +
  379 + shopInfo = data;
  380 + } else { // 以店铺域名方式直接访问
  381 + let result = yield searchApi.getBrandData({domain: domain});
  382 +
  383 + data = result.data;
  384 +
  385 + // 未取到domain信息,跳转至首页
  386 + if (result.code !== 200) {
  387 + return {redirect: helpers.urlFormat('')};
  388 + }
  389 +
  390 + // domain类型不为店铺,跳转至搜索
  391 + if (data.type * 1 !== 2) {
  392 + let d = {query: domain};
  393 +
  394 + if (data.id) {
  395 + d.brand = data.id;
  396 + }
  397 +
  398 + return {redirect: helpers.urlFormat('', d, 'search')};
  399 + }
  400 +
  401 + params.shopId = data.shop_id;
  402 + }
  403 +
  404 + if (+data.shop_template_type === 2) { // 经典店铺
  405 + resData = yield _getShopData(channel, params, shopInfo);
  406 + } else {
  407 + resData = yield _getBaseShopData(channel, params, shopInfo);
  408 + }
  409 +
  410 + return Object.assign(resData, {templateType: +data.shop_template_type});
  411 + })();
  412 +};
  413 +
  414 +exports.getShopListInfoAsync = (channel, params) => {
  415 + let gender = _getGender(channel),
  416 + shopId = params.shopId,
  417 + navBar = params.navBar || 1;
  418 +
  419 + let searchParams = searchHandler.getSearchParams(params);
  420 +
  421 + return co(function * () {
  422 + let result = yield Promise.props({
  423 + header: headerModel.requestHeaderData(channel), // 头部数据
  424 + shopInfo: api.getShopInfo(shopId), // 店铺介绍
  425 + decorator: searchApi.getShopDecorator(shopId), // 店铺装修数据
  426 + sort: searchApi.getSortList({shop_id: shopId}),
  427 + product: searchApi.getProductList(Object.assign(searchParams,
  428 + {shop_id: shopId}), 'shop'), // 搜索店铺商品
  429 +
  430 + // 如果有店内搜索,则并行查询店铺所有商品,搜索不到商品则显示所有商品
  431 + allProduct: params.query ? searchApi.getProductList(Object.assign(searchParams,
  432 + {shop_id: shopId, query: ''}), 'shop') : Promise.resolve({})
  433 + });
  434 +
  435 + let resData = {headerData: Object.assign(result.header.headerData, {header: true})};
  436 +
  437 + Object.assign(resData, searchHandler.handlePathNavData({}, params, 'shop', channel));
  438 +
  439 + // 店铺装修
  440 + if (result.decorator.code === 200) {
  441 + Object.assign(resData, shopHandler.getShopDecorator(result.decorator.data, params, shopId));
  442 +
  443 + // 设置shop nav选中状态
  444 + _.set(resData, `navigationBar[${navBar}].current`, true);
  445 +
  446 + if (result.shopInfo.code === 200) {
  447 + let data = _.get(result, 'shopInfo.data', {});
  448 +
  449 + _.set(resData, 'shopTopBanner.brandIntro', {
  450 + shopId: shopId,
  451 + brandName: data.shop_name || '',
  452 + brandCont: data.shop_intro || ''
  453 + });
  454 +
  455 + // 店铺SEO
  456 + Object.assign(resData, searchHandler.getBrandShopSeo(channel, {
  457 + shopName: data.shop_name
  458 + }, params));
  459 + }
  460 + } else {
  461 + return Promise.reject('No ShopDecorator data');
  462 + }
  463 +
  464 + // 获取商品数据和顶部筛选条件
  465 + if (result.product.code === 200) {
  466 + let info = result.product;
  467 + let goodsList = _.get(info, 'data.product_list', []);
  468 +
  469 + if (goodsList.length) {
  470 + let totalPage = _.get(info, 'data.total', 1);
  471 +
  472 + Object.assign(resData, {
  473 + filters: searchHandler.handleFilterDataAll(info.data, params),
  474 + opts: searchHandler.handleOptsData(params, totalPage),
  475 + goods: productProcess.processProductList(goodsList, {
  476 + newCoverSort: true,
  477 + showDiscount: false,
  478 + gender: _getGender(channel),
  479 + query: params.query
  480 + }),
  481 + hasNextPage: searchHandler.handleNextPage(params, totalPage),
  482 + footPager: searchHandler.handlePagerData(totalPage, params)
  483 + });
  484 +
  485 + _.set(resData, 'filters.checkedConditions.clearUrl',
  486 + `?navBar=${params.navBar}&shopId=${params.shopId}`);
  487 + } else {
  488 + resData.searchEmpty = true;
  489 +
  490 + let data = _.get(result, 'allProduct.data.total', 0);
  491 + let plist = _.get(data, 'product_list', []);
  492 +
  493 + if (params.query && plist.length) {
  494 + resData.allGoods = {
  495 + name: '全部商品 ALL',
  496 + sort: searchHandler.handleOptsData(params, data.total || 0),
  497 + list: productProcess.processProductList(plist, {
  498 + newCoverSort: true,
  499 + showDiscount: false,
  500 + gender: gender
  501 + })
  502 + };
  503 +
  504 + _.set(resData.allGoods, 'sort.newPage', true); // 启用新的分页导航
  505 + }
  506 + }
  507 + }
  508 +
  509 + if (result.sort.code === 200) {
  510 + let groupSort = _.get(result.sort, 'data', []),
  511 + noPageQs = Object.assign({}, params, {page: 1});
  512 +
  513 + resData.leftContent = searchHandler.handleSortData(groupSort, noPageQs, params);
  514 +
  515 + _.set(resData, 'brandShopAd', {baseUrl: shopListUrl});
  516 +
  517 + if (resData.allGoods) {
  518 + Object.assign(resData.allGoods, searchHandler.setShopSort(groupSort, noPageQs));
  519 + }
  520 + }
  521 +
  522 + resData.criteo = {skn: searchHandler.getCriteo(_.get(resData, 'goods'))};
  523 +
  524 + return resData;
  525 + })();
  526 +};
  527 +
  528 +exports.getShopGoodsData = (shopId, channel, params) => {
  529 + let gender = _getGender(channel);
  530 + let resData = {};
  531 +
  532 + _.unset(params, '_pjax');
  533 + return Promise.all([
  534 + searchApi.getProductList(Object.assign({shop_id: shopId}, params), 'shop'), // 搜索店铺商品
  535 + searchApi.getSortList({shop_id: shopId}) // 根据店铺id获取分类
  536 + ]).then(result => {
  537 + // 获取商品数据和顶部筛选条件
  538 + if (result[0].code === 200) {
  539 + Object.assign(resData, {
  540 + sort: searchHandler.handleOptsData(params, _.get(result[0], 'data.total', 0)),
  541 + list: productProcess.processProductList(_.get(result[0], 'data.product_list', []), {
  542 + newCoverSort: true,
  543 + showDiscount: false,
  544 + gender: gender
  545 + })
  546 + });
  547 + _.set(resData, 'sort.newPage', true); // 启用新的分页导航
  548 + }
  549 +
  550 + if (result[1].code === 200) {
  551 + let groupSort = _.get(result[1], 'data', []);
  552 +
  553 + Object.assign(resData, searchHandler.setShopSort(groupSort, Object.assign({}, params,
  554 + {page: 1})), searchHandler.setGenderFilter(params));
  555 + }
  556 +
  557 + return resData;
  558 + });
  559 +};
  560 +
57 /** 561 /**
58 * 基础模板 562 * 基础模板
59 */ 563 */
@@ -115,3 +619,40 @@ exports.queryShopByBrandIdAsync = (sid, bid) => { @@ -115,3 +619,40 @@ exports.queryShopByBrandIdAsync = (sid, bid) => {
115 return _.get(result, 'data[0]', {}); 619 return _.get(result, 'data[0]', {});
116 })(); 620 })();
117 }; 621 };
  622 +
  623 +exports.getShopArticleByBrandsAsync = (brands) => {
  624 + let resData = {};
  625 +
  626 + brands = _.split(brands, ',');
  627 +
  628 + if (!brands.length) {
  629 + return Promise.resolve(resData);
  630 + }
  631 +
  632 + return Promise.all(brands.map(value => searchApi.getArticleByBrand(value))).then(result => {
  633 + let articleList = [];
  634 +
  635 + for (let i = 0; i < result.length; i++) {
  636 + articleList = _.concat(articleList, _.get(result[i], 'data', []));
  637 + }
  638 +
  639 + if (articleList.length >= 3) {
  640 + articleList.length = 3;
  641 +
  642 + resData.trendInfo = {
  643 + name: '潮流资讯 HOT ITEMS',
  644 + trendList: articleList.map(value => {
  645 + return {
  646 + href: helpers.urlFormat(`/guang/${value.id}.html`, null),
  647 + src: helpers.getForceSourceUrl(value.src) +
  648 + '?imageView2/1/w/{width}/h/{height}',
  649 + mainTitle: value.title,
  650 + Subtitle: value.intro
  651 + };
  652 + })
  653 + };
  654 + }
  655 +
  656 + return resData;
  657 + });
  658 +};
@@ -48,6 +48,9 @@ const newArrive = require(`${cRoot}/newArrive`); @@ -48,6 +48,9 @@ const newArrive = require(`${cRoot}/newArrive`);
48 // 全球购controller 48 // 全球购controller
49 const globalCtrl = require(`${cRoot}/global`); 49 const globalCtrl = require(`${cRoot}/global`);
50 50
  51 +// 店铺controller
  52 +const shop = require(`${cRoot}/shop`);
  53 +
51 // 商品促销routers 54 // 商品促销routers
52 router.get('/sale', sale.index); // sale 首页 55 router.get('/sale', sale.index); // sale 首页
53 router.get(/\/(.*)-sale/, sale.index); // sale 首页(SEO改造) 56 router.get(/\/(.*)-sale/, sale.index); // sale 首页(SEO改造)
@@ -113,12 +116,13 @@ router.get('/list/new', list.new); @@ -113,12 +116,13 @@ router.get('/list/new', list.new);
113 router.get(/\/list\/(.*)-new/, list.newWithChannel); 116 router.get(/\/list\/(.*)-new/, list.newWithChannel);
114 117
115 // 品牌店铺 118 // 品牌店铺
116 -router.get('/index/brand', list.brand); // 品牌店铺页  
117 router.get('/index/about', list.brandAbout); // 品牌店铺介绍页 119 router.get('/index/about', list.brandAbout); // 品牌店铺介绍页
118 router.post('/index/isFavoriteBrand', list.isFavoriteBrand); // 判断用户是否收藏品牌 120 router.post('/index/isFavoriteBrand', list.isFavoriteBrand); // 判断用户是否收藏品牌
119 router.post('/index/getNodeContent', list.getNodeContent); // 品牌页水牌 121 router.post('/index/getNodeContent', list.getNodeContent); // 品牌页水牌
120 router.post('/index/getAdnav', list.getAdnav); // 品牌页系列 122 router.post('/index/getAdnav', list.getAdnav); // 品牌页系列
121 -router.get('/shoplist', list.shopList); // 店铺列表页 123 +router.get('/shop', shop.index); // 店铺首页
  124 +router.get('/shoplist', shop.list); // 店铺列表页
  125 +router.get('/shop/article', shop.article); // 店铺推荐文章
122 router.post('/shop/togglecollect', favorite.collectShop); // 店铺收藏 126 router.post('/shop/togglecollect', favorite.collectShop); // 店铺收藏
123 router.post('/index/isFavoriteShop', favorite.isFavShop); // 判断用户是否收藏品牌 127 router.post('/index/isFavoriteShop', favorite.isFavShop); // 判断用户是否收藏品牌
124 router.get('/brand/couponsync', list.brandCouponSync); 128 router.get('/brand/couponsync', list.brandCouponSync);
  1 +{{# trendInfo}}
  2 + <div class="trend-info clearfix">
  3 + {{> common/floor-header}}
  4 +
  5 + <ul class="trend-list">
  6 + {{#each trendList}}
  7 + <li>
  8 + <a href="{{href}}">
  9 + <img src="{{image2 src w=264 h=173}}" />
  10 + <div class="main-title">{{mainTitle}}</div>
  11 + <div class="sub-title">{{Subtitle}}</div>
  12 + </a>
  13 + </li>
  14 + {{/each}}
  15 + </ul>
  16 + </div>
  17 +{{/ trendInfo}}
@@ -6,7 +6,7 @@ @@ -6,7 +6,7 @@
6 6
7 <div class="list-left pull-left"> 7 <div class="list-left pull-left">
8 {{> list/shop-search}} 8 {{> list/shop-search}}
9 - 9 +
10 {{> product/left-content}} 10 {{> product/left-content}}
11 11
12 {{> list/shop-sidebar}} 12 {{> list/shop-sidebar}}
@@ -54,23 +54,9 @@ @@ -54,23 +54,9 @@
54 54
55 {{> list/shop-all-goods}} 55 {{> list/shop-all-goods}}
56 56
57 - {{#trendInfo}}  
58 - <div class="trend-info clearfix">  
59 - {{> common/floor-header}}  
60 -  
61 - <ul class="trend-list">  
62 - {{#each trendList}}  
63 - <li>  
64 - <a href="{{href}}">  
65 - <img src="{{image2 src w=264 h=173}}" />  
66 - <div class="main-title">{{mainTitle}}</div>  
67 - <div class="sub-title">{{Subtitle}}</div>  
68 - </a>  
69 - </li>  
70 - {{/each}}  
71 - </ul>  
72 - </div>  
73 - {{/trendInfo}} 57 + {{# trendInfo}}
  58 + <div class="trend-info" data-brands="{{shopBrands}}"></div>
  59 + {{/ trendInfo}}
74 </div> 60 </div>
75 </div> 61 </div>
76 </div> 62 </div>
@@ -4,8 +4,6 @@ @@ -4,8 +4,6 @@
4 * @date: 2016/6/16 4 * @date: 2016/6/16
5 */ 5 */
6 'use strict'; 6 'use strict';
7 -const _ = require('lodash');  
8 -const qs = require('querystring');  
9 7
10 module.exports = () => { 8 module.exports = () => {
11 return (req, res, next) => { 9 return (req, res, next) => {
@@ -67,21 +65,12 @@ module.exports = () => { @@ -67,21 +65,12 @@ module.exports = () => {
67 } 65 }
68 break; 66 break;
69 } 67 }
70 - default: // 其它(识别为品牌) 68 + default: // 其它(识别为店铺)
71 { // eslint-disable-line 69 { // eslint-disable-line
72 - let queryString = (function() {  
73 - if (!_.isEmpty(req.query)) {  
74 - return '&' + qs.stringify(req.query);  
75 - } else {  
76 - return '';  
77 - }  
78 - }());  
79 -  
80 req.query.domain = req.subdomains[0]; 70 req.query.domain = req.subdomains[0];
  71 +
81 if (!req.path || req.path === '/') { 72 if (!req.path || req.path === '/') {
82 - req.url = `/product/index/brand?domain=${req.subdomains[0]}${queryString}`;  
83 - } else if (req.path === '/about') {  
84 - req.url = `/product/index/brand?domain=${req.subdomains[0]}${queryString}`; 73 + req.url = '/product/shop';
85 } 74 }
86 break; 75 break;
87 } 76 }
1 { 1 {
2 "name": "yohobuy-node", 2 "name": "yohobuy-node",
3 - "version": "5.9.13", 3 + "version": "6.0.1",
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": {
@@ -23,4 +23,9 @@ if ($('.success-box').length > 0) { @@ -23,4 +23,9 @@ if ($('.success-box').length > 0) {
23 23
24 $(function() { 24 $(function() {
25 yas.givePoint('YB_REGISTER_SUCCESS_L'); 25 yas.givePoint('YB_REGISTER_SUCCESS_L');
  26 +
  27 + // 品众统计
  28 + if (window._fxcmd) {
  29 + window._fxcmd.push(['trackOrder', 'event', 'reg', '注册', '1']);
  30 + }
26 }); 31 });
@@ -193,13 +193,27 @@ $(window).on('scroll', function() { @@ -193,13 +193,27 @@ $(window).on('scroll', function() {
193 193
194 if (scrollTop > fixedAreaTop) { 194 if (scrollTop > fixedAreaTop) {
195 $fixedArea.css({ 195 $fixedArea.css({
196 - position: 'fixed',  
197 - top: 0 196 + position: 'fixed'
198 }); 197 });
199 } else { 198 } else {
200 $fixedArea.css({ 199 $fixedArea.css({
201 - position: 'static',  
202 - top: 0 200 + position: 'absolute'
203 }); 201 });
204 } 202 }
205 }); 203 });
  204 +
  205 +// 获取店铺推荐文章
  206 +(function() {
  207 + var $trendInfo = $('.trend-info');
  208 + var brands = $trendInfo.data('brands');
  209 +
  210 + if (brands) {
  211 + $.ajax({
  212 + type: 'GET',
  213 + url: '/product/shop/article',
  214 + data: {brands: brands}
  215 + }).then(function(data) {
  216 + $trendInfo.replaceWith(data);
  217 + });
  218 + }
  219 +}());
@@ -406,6 +406,8 @@ @@ -406,6 +406,8 @@
406 background: #fff; 406 background: #fff;
407 z-index: 1; 407 z-index: 1;
408 width: 970px; 408 width: 970px;
  409 + position: absolute;
  410 + top: 0;
409 } 411 }
410 412
411 .gender-filter { 413 .gender-filter {
@@ -540,6 +542,9 @@ @@ -540,6 +542,9 @@
540 } 542 }
541 543
542 .goods-wrap { 544 .goods-wrap {
  545 + padding-top: 156px;
  546 + position: relative;
  547 +
543 .goods-container { 548 .goods-container {
544 .good-info { 549 .good-info {
545 width: 235px; 550 width: 235px;