Authored by 王水玲

mip 商品列表

  1 +'use strict';
  2 +const css = require('../css');
  3 +const _ = require('lodash');
  4 +const co = require('bluebird').coroutine;
  5 +const mRoot = '../models';
  6 +const utils = '../../../utils';
  7 +const productProcess = require(`${utils}/product-process`);
  8 +const searchProcess = require(`${utils}/search-process`);
  9 +const stringProcess = require(`${utils}/string-process`);
  10 +const redis = require(`${utils}/redis`);
  11 +const logger = global.yoho.logger;
  12 +const listModel = require(`${mRoot}/list`);
  13 +const camelCase = global.yoho.camelCase;
  14 +
  15 +/**
  16 + * 封面图
  17 + * @type {{boys: string, gilrs: string}}
  18 + */
  19 +const _coverChannel = {
  20 + boys: '1,3',
  21 + gilrs: '2,3'
  22 +};
  23 +
  24 +const index = (req, res, next) => {
  25 + let params = _.assign({}, req.query);
  26 + let uid = req.user.uid;
  27 +
  28 + // 获取第一页数据做服务端渲染
  29 + let initialData = _.assign({
  30 + gender: params.gender,
  31 + type: 'default',
  32 + order: '0',
  33 + page: 1,
  34 + limit: 24,
  35 + isApp: params.app_version
  36 + }, params);
  37 +
  38 + if (uid) {
  39 + initialData.uid = uid;
  40 + }
  41 +
  42 + co(function* () {
  43 + let result = yield req.ctx(listModel).getCategoryGoods(initialData);
  44 + let categoryIntroRedis = [];
  45 + let responseResult = {
  46 + list: productProcess.processProductList(_.get(result, 'data.product_list', []), {
  47 + isApp: params.isApp || (params.appVersion && params.appVersion !== 'false'),
  48 + gender: _coverChannel[params.coverChannel],
  49 + showSimilar: params.shop_id || params.material === 'true' ? false : true
  50 + })
  51 + };
  52 + let seoParams = searchProcess.getFilterValueForSeo(initialData, _.get(result, 'data', {}));
  53 + let seoRenderData = searchProcess.getListSeoData(seoParams);
  54 + let seoTitle = _.get(seoParams, 'sort');
  55 + let paramsTitle = params.title || params.sort_name; // 可能会配置的标题,优先级最高
  56 +
  57 + if (paramsTitle) {
  58 + seoTitle = stringProcess.decodeURIComponent(paramsTitle);
  59 + }
  60 +
  61 + if (seoTitle) {
  62 + try {
  63 + categoryIntroRedis =
  64 + yield redis.hmgetAsync(`category:description:${md5(seoTitle)}`, 'category', 'description').timeout(200); // eslint-disable-line
  65 + } catch (e) {
  66 + logger.warn(`redis.hmgetAsync error, key is category:description:md5(${seoTitle})`);
  67 + }
  68 + }
  69 +
  70 + let categoryIntro = categoryIntroRedis[1] ? {
  71 + title: categoryIntroRedis[0],
  72 + desc: categoryIntroRedis[1]
  73 + } : null;
  74 +
  75 + // 唤起 APP 的路径
  76 + res.locals.appPath = `yohobuy://yohobuy.com/goapp?openby:yohobuy={"action":"go.list","params":${JSON.stringify(params)}}`;
  77 +
  78 + res.render('list', Object.assign({
  79 + css: yield css('chanpin.css'),
  80 + commonCss: yield css('common.css'),
  81 + title: seoRenderData.title || '商品列表',
  82 + mipFooter: true,
  83 + canonical: {
  84 + currentHref: `https://www.yohobuy.com${req.url}`
  85 + },
  86 + pageTitle: seoTitle || '商品列表',
  87 + }, camelCase(responseResult)));
  88 + })().catch(next);
  89 +}
  90 +
  91 +module.exports = {
  92 + index
  93 +}
@@ -270,71 +270,4 @@ @@ -270,71 +270,4 @@
270 border: 1px solid #bbb; 270 border: 1px solid #bbb;
271 margin-right: 6px; 271 margin-right: 6px;
272 margin-top: 5px; 272 margin-top: 5px;
273 -}  
274 -  
275 -/* 底部开始 */  
276 -.mip-footer-fixed {  
277 - width: 100%;  
278 - height: 95px;  
279 - position: relative;  
280 - clear: both;  
281 -}  
282 -  
283 -.mip-footer {  
284 - max-width: 750px;  
285 - margin: 0 auto;  
286 - background-color: #fff;  
287 - height: 95px;  
288 - width: 100%;  
289 - clear: both;  
290 - position: fixed;  
291 - bottom: 0;  
292 - left: 0;  
293 - right: 0;  
294 -}  
295 -  
296 -.mip-footer .option {  
297 - background-color: #fff;  
298 - font-size: 0;  
299 -}  
300 -  
301 -.mip-footer .option a {  
302 - line-height: 50px;  
303 - font-size: 13px;  
304 - padding: 0 5%;  
305 -}  
306 -  
307 -.mip-footer .option .login {  
308 - border-right: solid 1px #e0e0e0;  
309 -}  
310 -  
311 -.mip-footer .option .back-to-top {  
312 - line-height: 50px;  
313 - font-size: 13px;  
314 - padding: 0 5%;  
315 - float: right;  
316 -}  
317 -  
318 -.mip-footer .option .back-to-top span {  
319 - font-weight: bold;  
320 - margin-left: 5px;  
321 - transform: scaleY(0.5);  
322 -}  
323 -  
324 -.mip-footer .copy-right {  
325 - background-color: #eee;  
326 - color: #666;  
327 - text-align: center;  
328 - line-height: 45px;  
329 - font-size: 13px;  
330 -}  
331 -  
332 -.mip-footer .mip-fixed {  
333 - position: relative !important;  
334 - z-index: 0 !important;  
335 -}  
336 -  
337 -.mip-footer .mip-gototop {  
338 - display: inline !important;  
339 -}  
340 -/* 底部结束 */ 273 +}
@@ -313,4 +313,71 @@ @@ -313,4 +313,71 @@
313 313
314 .mip-appdl-downbtn { 314 .mip-appdl-downbtn {
315 top: 15px !important; 315 top: 15px !important;
316 -}  
  316 +}
  317 +
  318 +/* 底部开始 */
  319 +.mip-footer-fixed {
  320 + width: 100%;
  321 + height: 95px;
  322 + position: relative;
  323 + clear: both;
  324 +}
  325 +
  326 +.mip-footer {
  327 + max-width: 750px;
  328 + margin: 0 auto;
  329 + background-color: #fff;
  330 + height: 95px;
  331 + width: 100%;
  332 + clear: both;
  333 + position: fixed;
  334 + bottom: 0;
  335 + left: 0;
  336 + right: 0;
  337 +}
  338 +
  339 +.mip-footer .option {
  340 + background-color: #fff;
  341 + font-size: 0;
  342 +}
  343 +
  344 +.mip-footer .option a {
  345 + line-height: 50px;
  346 + font-size: 13px;
  347 + padding: 0 5%;
  348 +}
  349 +
  350 +.mip-footer .option .login {
  351 + border-right: solid 1px #e0e0e0;
  352 +}
  353 +
  354 +.mip-footer .option .back-to-top {
  355 + line-height: 50px;
  356 + font-size: 13px;
  357 + padding: 0 5%;
  358 + float: right;
  359 +}
  360 +
  361 +.mip-footer .option .back-to-top span {
  362 + font-weight: bold;
  363 + margin-left: 5px;
  364 + transform: scaleY(0.5);
  365 +}
  366 +
  367 +.mip-footer .copy-right {
  368 + background-color: #eee;
  369 + color: #666;
  370 + text-align: center;
  371 + line-height: 45px;
  372 + font-size: 13px;
  373 +}
  374 +
  375 +.mip-footer .mip-fixed {
  376 + position: relative !important;
  377 + z-index: 0 !important;
  378 +}
  379 +
  380 +.mip-footer .mip-gototop {
  381 + display: inline !important;
  382 +}
  383 +/* 底部结束 */
@@ -947,71 +947,4 @@ @@ -947,71 +947,4 @@
947 .mip-footer { 947 .mip-footer {
948 bottom: 60px !important; 948 bottom: 60px !important;
949 position: relative !important; 949 position: relative !important;
950 -}  
951 -  
952 -/* 底部开始 */  
953 -.mip-footer-fixed {  
954 - width: 100%;  
955 - height: 95px;  
956 - position: relative;  
957 - clear: both;  
958 -}  
959 -  
960 -.mip-footer {  
961 - max-width: 750px;  
962 - margin: 0 auto;  
963 - background-color: #fff;  
964 - height: 95px;  
965 - width: 100%;  
966 - clear: both;  
967 - position: fixed;  
968 - bottom: 0;  
969 - left: 0;  
970 - right: 0;  
971 -}  
972 -  
973 -.mip-footer .option {  
974 - background-color: #fff;  
975 - font-size: 0;  
976 -}  
977 -  
978 -.mip-footer .option a {  
979 - line-height: 50px;  
980 - font-size: 13px;  
981 - padding: 0 5%;  
982 -}  
983 -  
984 -.mip-footer .option .login {  
985 - border-right: solid 1px #e0e0e0;  
986 -}  
987 -  
988 -.mip-footer .option .back-to-top {  
989 - line-height: 50px;  
990 - font-size: 13px;  
991 - padding: 0 5%;  
992 - float: right;  
993 -}  
994 -  
995 -.mip-footer .option .back-to-top span {  
996 - font-weight: bold;  
997 - margin-left: 5px;  
998 - transform: scaleY(0.5);  
999 -}  
1000 -  
1001 -.mip-footer .copy-right {  
1002 - background-color: #eee;  
1003 - color: #666;  
1004 - text-align: center;  
1005 - line-height: 45px;  
1006 - font-size: 13px;  
1007 -}  
1008 -  
1009 -.mip-footer .mip-fixed {  
1010 - position: relative !important;  
1011 - z-index: 0 !important;  
1012 -}  
1013 -  
1014 -.mip-footer .mip-gototop {  
1015 - display: inline !important;  
1016 -}  
1017 -/* 底部结束 */  
  950 +}
  1 +/**
  2 + * list model
  3 + * @author: wsl<shuiling.wang@yoho.cn>
  4 + * @date: 2018/08/20
  5 + */
  6 +'use strict';
  7 +const utils = '../../../utils';
  8 +// const productProcess = require(`${utils}/product-process`);
  9 +const searchProcess = require(`${utils}/search-process`);
  10 +const _ = require('lodash');
  11 +// const logger = global.yoho.logger;
  12 +// const cache = require('memory-cache');
  13 +// const helpers = global.yoho.helpers;
  14 +// const co = require('bluebird').coroutine;
  15 +
  16 +module.exports = class extends global.yoho.BaseModel {
  17 + constructor(ctx) {
  18 + super(ctx);
  19 + }
  20 +
  21 + /**
  22 + * 获取品类下的商品列表
  23 + * @param isSearch 是否是搜索列表页
  24 + * 搜索列表页默认调用 app.search.li 接口
  25 + * 类目列表页默认调用 web.search.search 接口
  26 + */
  27 + getCategoryGoods(params, isSearch) {
  28 + let method = isSearch ? 'app.search.li' : 'web.search.search';
  29 +
  30 + if (params.filter_poolId) {
  31 + method = 'app.search.pool';
  32 + }
  33 +
  34 + if (params.shop_id && !params.filter_poolId && !params.productPool) {
  35 + method = 'app.search.li';
  36 + }
  37 +
  38 + // 个人中心优惠券立即使用 - 商品列表
  39 + if (params.coupon_id || params.coupon_code) {
  40 + method = 'app.search.coupon';
  41 + }
  42 +
  43 + // 物料商品列表增加
  44 + if (params.material === 'true') {
  45 + method = 'app.search.recommendProduct';
  46 + }
  47 +
  48 + if (params.isblknew) {
  49 + method = 'app.search.newProduct';
  50 + }
  51 +
  52 + if (params.promotion_id) {
  53 + method = 'app.search.promotion';
  54 + }
  55 +
  56 + // 学生优惠
  57 + if (params.students) {
  58 + method = 'app.student.discount';
  59 + }
  60 +
  61 + // 学生返币查询
  62 + if (params.coin) {
  63 + method = 'app.student.rebate';
  64 + }
  65 +
  66 + // 促销活动
  67 + if (params.specialsale_id) {
  68 + method = 'app.search.li';
  69 + }
  70 +
  71 + if (method === 'web.search.search') {
  72 + params.from = 'categoryList';
  73 + }
  74 +
  75 + let paramsForApi = searchProcess.getSearchParamsWithoutMethod(params);
  76 +
  77 + return this.get({
  78 + data: _.assign({}, paramsForApi, {
  79 + method: method
  80 + })
  81 + });
  82 + }
  83 +
  84 +}
@@ -15,6 +15,7 @@ const guang = require(`${cRoot}/guang`); @@ -15,6 +15,7 @@ const guang = require(`${cRoot}/guang`);
15 const chanpin = require(`${cRoot}/chanpin`); 15 const chanpin = require(`${cRoot}/chanpin`);
16 const hot = require(`${cRoot}/hot`); 16 const hot = require(`${cRoot}/hot`);
17 const productDetail = require(`${cRoot}/product-detail`); 17 const productDetail = require(`${cRoot}/product-detail`);
  18 +const list = require(`${cRoot}/list`);
18 19
19 router.use(mip); 20 router.use(mip);
20 21
@@ -22,10 +23,12 @@ router.get(/^\/guang\/info\/(.*?)\.html/, rewrite.resolve, guang.detailIndex); @@ -22,10 +23,12 @@ router.get(/^\/guang\/info\/(.*?)\.html/, rewrite.resolve, guang.detailIndex);
22 router.get(/^\/guang\/(.*?)\.html/, rewrite.resolve, guang.detailIndex); 23 router.get(/^\/guang\/(.*?)\.html/, rewrite.resolve, guang.detailIndex);
23 24
24 router.get('/chanpin/:id.html', chanpin.index); 25 router.get('/chanpin/:id.html', chanpin.index);
25 -router.get('/list/:id.html', chanpin.redirect); 26 +
  27 +// router.get('/list/:id.html', chanpin.redirect);
26 28
27 router.get('/product/:skn.html', productDetail.index); 29 router.get('/product/:skn.html', productDetail.index);
28 30
29 router.get('/hot/:id.html', hot.index); 31 router.get('/hot/:id.html', hot.index);
  32 +router.get('/list(/:pathParams)?', rewrite.resolvePathParams, list.index)
30 33
31 module.exports = router; 34 module.exports = router;
  1 +<div class="good-list-page search-page yoho-page">
  2 + {{> mip-head}}
  3 + {{> mip-product-list}}
  4 + {{> mip-footer}}
  5 +</div>
@@ -13,10 +13,10 @@ const isTest = process.env.NODE_ENV === 'test'; @@ -13,10 +13,10 @@ const isTest = process.env.NODE_ENV === 'test';
13 13
14 const domains = { 14 const domains = {
15 15
16 - api: 'http://api.yoho.cn/',  
17 - service: 'http://service.yoho.cn/',  
18 - liveApi: 'http://testapi.live.yohops.com:9999/',  
19 - singleApi: 'http://api-test3.yohops.com:9999/', 16 + // api: 'http://api.yoho.cn/',
  17 + // service: 'http://service.yoho.cn/',
  18 + // liveApi: 'http://testapi.live.yohops.com:9999/',
  19 + // singleApi: 'http://api-test3.yohops.com:9999/',
20 20
21 // gray 21 // gray
22 // api: 'http://apigray.yoho.cn/', 22 // api: 'http://apigray.yoho.cn/',
@@ -24,10 +24,10 @@ const domains = { @@ -24,10 +24,10 @@ const domains = {
24 24
25 // platformApi: 'http://172.16.6.210:8088/', 25 // platformApi: 'http://172.16.6.210:8088/',
26 26
27 - // api: 'http://api-test3.dev.yohocorp.com/',  
28 - // service: 'http://api-test3.dev.yohocorp.com/',  
29 - // liveApi: 'http://testapi.live.yohops.com:9999/',  
30 - // singleApi: 'http://api-test3.dev.yohocorp.com/', 27 + api: 'http://api-test3.dev.yohocorp.com/',
  28 + service: 'http://api-test3.dev.yohocorp.com/',
  29 + liveApi: 'http://testapi.live.yohops.com:9999/',
  30 + singleApi: 'http://api-test3.dev.yohocorp.com/',
31 31
32 imSocket: 'ws://socket.yohobuy.com:10240', 32 imSocket: 'ws://socket.yohobuy.com:10240',
33 imCs: 'http://im.yohobuy.com/api', 33 imCs: 'http://im.yohobuy.com/api',