Merge branch 'master' into hotfix/baseshopName
Showing
80 changed files
with
4624 additions
and
1146 deletions
apps/activity/controllers/coupon.js
0 → 100644
1 | +/** | ||
2 | + * 领券中心 controller | ||
3 | + * @author: shenzm<zhimin.shen@yoho.cn> | ||
4 | + * @date: 2016/09/29 | ||
5 | + */ | ||
6 | + | ||
7 | +'use strict'; | ||
8 | + | ||
9 | +const couponModel = require('../models/coupon'); | ||
10 | + | ||
11 | +exports.index = (req, res, next) => { | ||
12 | + const channel = req.cookies._Channel || 'boys'; | ||
13 | + | ||
14 | + couponModel.getCouponData(channel, { | ||
15 | + uid: req.user.uid, | ||
16 | + contentCode: req.query.contentCode | ||
17 | + }).then(result => { | ||
18 | + res.render('coupon', Object.assign({ | ||
19 | + module: 'activity', | ||
20 | + page: 'coupon' | ||
21 | + }, result)); | ||
22 | + }).catch(next); | ||
23 | +}; | ||
24 | + | ||
25 | +exports.getCouponStatus = (req, res, next) => { | ||
26 | + couponModel.getCouponStatus({ | ||
27 | + uid: req.user.uid, | ||
28 | + contentCode: req.query.contentCode | ||
29 | + }).then(result => { | ||
30 | + res.json(result); | ||
31 | + }).catch(next); | ||
32 | +}; | ||
33 | + | ||
34 | +exports.sendcoupon = (req, res, next) => { | ||
35 | + couponModel.sendcoupon(req.query.id, req.user.uid).then(result => { | ||
36 | + res.json(result); | ||
37 | + }).catch(next); | ||
38 | +}; |
apps/activity/models/coupon.js
0 → 100644
1 | +/** | ||
2 | + * activity model | ||
3 | + * @author: shenzm<zhimin.shen@yoho.cn> | ||
4 | + * @date: 2016/09/29 | ||
5 | + */ | ||
6 | +'use strict'; | ||
7 | + | ||
8 | +const Promise = require('bluebird'); | ||
9 | +const api = global.yoho.API; | ||
10 | +const crypto = global.yoho.crypto; | ||
11 | +const helpers = global.yoho.helpers; | ||
12 | +const HeaderModel = require('../../../doraemon/models/header'); | ||
13 | +const homeService = require('../../product/models/home-service'); | ||
14 | + | ||
15 | +exports.getCouponData = (channel, params) => { | ||
16 | + return Promise.coroutine(function*() { | ||
17 | + const result = { | ||
18 | + pathNav: [homeService.getHomeChannelNav(channel), { | ||
19 | + name: '领券频道' | ||
20 | + }], | ||
21 | + footerTop: true, | ||
22 | + topBanner: { | ||
23 | + list: [] | ||
24 | + }, | ||
25 | + categories: [] | ||
26 | + }; | ||
27 | + | ||
28 | + const requestData = yield Promise.all([ | ||
29 | + api.get('', Object.assign(params, { | ||
30 | + method: 'app.promotion.queryCouponCenter' | ||
31 | + })), | ||
32 | + HeaderModel.requestHeaderData(channel) | ||
33 | + ]); | ||
34 | + | ||
35 | + const coupon = requestData[0]; | ||
36 | + | ||
37 | + result.headerData = requestData[1].headerData; | ||
38 | + | ||
39 | + do { | ||
40 | + if (!coupon.data || !Array.isArray(coupon.data) || coupon.data.length === 0) { | ||
41 | + break; | ||
42 | + } | ||
43 | + | ||
44 | + let i = 0; | ||
45 | + | ||
46 | + coupon.data.forEach(function(val, index) { | ||
47 | + // 头部banner | ||
48 | + if (val.templateName === 'focus') { | ||
49 | + val.data.forEach(function(item) { | ||
50 | + result.topBanner.list.push({ | ||
51 | + href: item.url.replace('http:', ''), // banner跳转链接 | ||
52 | + img: item.src // banner图片 | ||
53 | + }); | ||
54 | + }); | ||
55 | + } else if (val.template_name === 'getCoupon' && val.data.length) { | ||
56 | + // 优惠券楼层 | ||
57 | + if (!coupon.data[index - 1].data || !coupon.data[index - 1].data.text) { | ||
58 | + return; | ||
59 | + } | ||
60 | + | ||
61 | + const obj = { | ||
62 | + title: coupon.data[index - 1].data.text, // 楼层标题 | ||
63 | + coupons: [] | ||
64 | + }; | ||
65 | + | ||
66 | + val.data.forEach(function(item) { | ||
67 | + obj.coupons.push({ | ||
68 | + id: crypto.encryption('yoho9646abcdefgh', item.couponID), // 加密优惠券号 | ||
69 | + img: helpers.image(item.image.src, 0, 0), // 优惠券图片 | ||
70 | + url: item.image.url.replace('http:', '') // 去逛逛链接 | ||
71 | + }); | ||
72 | + }); | ||
73 | + | ||
74 | + result.categories.push(obj); | ||
75 | + i++; | ||
76 | + } | ||
77 | + }); | ||
78 | + } | ||
79 | + while (false); | ||
80 | + return result; | ||
81 | + })(); | ||
82 | +}; | ||
83 | + | ||
84 | +exports.getCouponStatus = (params) => { | ||
85 | + return Promise.coroutine(function*() { | ||
86 | + const coupon = yield api.get('', Object.assign(params, { | ||
87 | + method: 'app.promotion.queryCouponCenter' | ||
88 | + })); | ||
89 | + const result = { | ||
90 | + code: coupon.code, | ||
91 | + categories: [] | ||
92 | + }; | ||
93 | + | ||
94 | + do { | ||
95 | + if (!coupon.data || !Array.isArray(coupon.data) || coupon.data.length === 0) { | ||
96 | + break; | ||
97 | + } | ||
98 | + | ||
99 | + let i = 0; | ||
100 | + | ||
101 | + coupon.data.forEach(function(val, index) { | ||
102 | + if (val.template_name === 'getCoupon' && val.data.length) { | ||
103 | + // 优惠券楼层 | ||
104 | + if (!coupon.data[index - 1].data || !coupon.data[index - 1].data.text) { | ||
105 | + return; | ||
106 | + } | ||
107 | + | ||
108 | + val.data.forEach(function(item) { | ||
109 | + const status = Number(item.status); | ||
110 | + | ||
111 | + if ([2, 3].indexOf(status) > -1) { | ||
112 | + const cou = { | ||
113 | + id: crypto.encryption('yoho9646abcdefgh', item.couponID) // 加密优惠券号 | ||
114 | + }; | ||
115 | + | ||
116 | + if (status === 2) { | ||
117 | + cou.empty = true; // 优惠券已抢光 | ||
118 | + } else if (status === 3) { | ||
119 | + cou.got = true; // 优惠券已领取 | ||
120 | + } | ||
121 | + | ||
122 | + result.categories.push(cou); | ||
123 | + } | ||
124 | + }); | ||
125 | + i++; | ||
126 | + } | ||
127 | + }); | ||
128 | + } | ||
129 | + while (false); | ||
130 | + return result; | ||
131 | + })(); | ||
132 | +}; | ||
133 | + | ||
134 | +exports.sendcoupon = (couponId, uid) => { | ||
135 | + let returnData = {}; | ||
136 | + | ||
137 | + couponId = crypto.decrypt('yoho9646abcdefgh', couponId); | ||
138 | + | ||
139 | + // 领取优惠券 | ||
140 | + return api.get('', { | ||
141 | + method: 'app.promotion.getCoupon', | ||
142 | + couponId: couponId, | ||
143 | + uid: uid | ||
144 | + }).then(result => { | ||
145 | + switch (result.code) { | ||
146 | + case 200: | ||
147 | + returnData = { | ||
148 | + code: 200, | ||
149 | + message: '恭喜您,成功领取优惠券', | ||
150 | + url: helpers.urlFormat('/home/coupons') | ||
151 | + }; | ||
152 | + break; | ||
153 | + case 401: | ||
154 | + returnData = { | ||
155 | + code: 401, | ||
156 | + message: '您已领取过优惠券' | ||
157 | + }; | ||
158 | + break; | ||
159 | + case 315: | ||
160 | + returnData = { | ||
161 | + code: 315, | ||
162 | + message: '优惠券已过期' | ||
163 | + }; | ||
164 | + break; | ||
165 | + case 300: | ||
166 | + returnData = { | ||
167 | + code: 300, | ||
168 | + message: '请求参数错误' | ||
169 | + }; | ||
170 | + break; | ||
171 | + default: | ||
172 | + returnData = { | ||
173 | + code: 500, | ||
174 | + message: '领券失败!' | ||
175 | + }; | ||
176 | + break; | ||
177 | + } | ||
178 | + return returnData; | ||
179 | + }); | ||
180 | +}; |
@@ -9,10 +9,17 @@ | @@ -9,10 +9,17 @@ | ||
9 | const express = require('express'); | 9 | const express = require('express'); |
10 | const router = express.Router(); // eslint-disable-line | 10 | const router = express.Router(); // eslint-disable-line |
11 | const cRoot = './controllers'; | 11 | const cRoot = './controllers'; |
12 | +const auth = require(`${global.middleware}/auth`); | ||
12 | 13 | ||
13 | const specialController = require(`${cRoot}/special`); | 14 | const specialController = require(`${cRoot}/special`); |
15 | +const coupon = require(`${cRoot}/coupon`); | ||
14 | 16 | ||
15 | // 专题活动 | 17 | // 专题活动 |
16 | router.get(/^\/special\/(\d+)_(.*)\.html$/, specialController.special); | 18 | router.get(/^\/special\/(\d+)_(.*)\.html$/, specialController.special); |
17 | 19 | ||
18 | -module.exports = router; | 20 | +// 领券中心 |
21 | +router.get('/coupon/index', coupon.index); | ||
22 | +router.get('/coupon/couponstatus', coupon.getCouponStatus); | ||
23 | +router.get('/coupon/sendcoupon', auth, coupon.sendcoupon); | ||
24 | + | ||
25 | +module.exports = router; |
apps/activity/views/action/coupon.hbs
0 → 100644
1 | +<div class="coupon-page yoho-page"> | ||
2 | + {{> common/path-nav}} | ||
3 | + {{> common/slide-banner}} | ||
4 | +{{# categories}} | ||
5 | + <div class="title clearfix"> | ||
6 | + <span>{{title}}</span> | ||
7 | + </div> | ||
8 | + {{# coupons}} | ||
9 | + <div class="coupon"> | ||
10 | + <a href="{{url}}" target="_blank" href="javascript:void(0);" data-id="{{id}}"> | ||
11 | + <img src="{{img}}"> | ||
12 | + {{#if empty}} | ||
13 | + <div class="coupon-mask"></div> | ||
14 | + {{/if}} | ||
15 | + <div class="enable info" id="{{id}}"> | ||
16 | + <div class="normal"> | ||
17 | + <p>点击</p> | ||
18 | + <p>领取</p> | ||
19 | + </div> | ||
20 | + <div class="got hidden"> | ||
21 | + <p>已领取</p> | ||
22 | + <p class="guang">去使用</p> | ||
23 | + </div> | ||
24 | + <div class="empty hidden"> | ||
25 | + <p>已抢光</p> | ||
26 | + <p class="guang">去逛逛</p> | ||
27 | + </div> | ||
28 | + </div> | ||
29 | + </a> | ||
30 | + </div> | ||
31 | + {{/ coupons}} | ||
32 | +{{/ categories}} | ||
33 | + | ||
34 | +</div> |
apps/brands/controllers/brands.js
0 → 100644
1 | +/** | ||
2 | + * 品牌一览 controller | ||
3 | + * @author: ghw<hongwei.gao@yoho.cn> | ||
4 | + * @date: 2016/9/29 | ||
5 | + */ | ||
6 | + | ||
7 | +'use strict'; | ||
8 | +const mRoot = '../models'; | ||
9 | + | ||
10 | +const brandsService = require(`${mRoot}/brands-service`); // students 页 model | ||
11 | + | ||
12 | +/** | ||
13 | + * brands 首页 | ||
14 | + * @param {[type]} req [description] | ||
15 | + * @param {[type]} res [description] | ||
16 | + * @return {[type]} [description] | ||
17 | + */ | ||
18 | + | ||
19 | +exports.index = (req, res, next) => { | ||
20 | + let channel = req.query.channel || req.cookies._Channel || 'boys'; | ||
21 | + | ||
22 | + brandsService.getBrandViewList(channel, req).then(result => { | ||
23 | + | ||
24 | + res.render('brands/brands', result); | ||
25 | + | ||
26 | + }).catch(next); | ||
27 | +}; | ||
28 | + | ||
29 | +/** | ||
30 | + * brandList-Ajax调用 | ||
31 | + */ | ||
32 | +exports.brandList = (req, res, next) => { | ||
33 | + let channel = req.query.channel || req.cookies._Channel || 'boys'; | ||
34 | + | ||
35 | + brandsService.getBrandList(channel, req.body.start).then(result => { | ||
36 | + | ||
37 | + res.render('brands/brand-list', Object.assign({layout: false}, result)); | ||
38 | + | ||
39 | + }).catch(next); | ||
40 | +}; | ||
41 | + | ||
42 | +/** | ||
43 | + * 品牌接口数据 | ||
44 | + * | ||
45 | + * @param string brandId 获取品牌ID | ||
46 | + * @return json | ||
47 | + */ | ||
48 | +exports.brandInfo = (req, res, next) => { | ||
49 | + | ||
50 | + let brandId = req.query.brandId || 0; | ||
51 | + | ||
52 | + brandsService.brandInfo(brandId, req.user.uid).then(result => { | ||
53 | + res.json(result); | ||
54 | + }).catch(next); | ||
55 | +}; | ||
56 | + | ||
57 | +/** | ||
58 | + * 品牌plusstar列表 | ||
59 | + */ | ||
60 | +exports.plusstarList = (req, res, next) => { | ||
61 | + let channel = req.query.channel || req.cookies._Channel || 'boys'; | ||
62 | + | ||
63 | + brandsService.plusstarList(channel, req).then(result => { | ||
64 | + res.render('brands/plusstar', result); | ||
65 | + }).catch(next); | ||
66 | +}; |
apps/brands/index.js
0 → 100644
1 | +/** | ||
2 | + * router of sub app brands | ||
3 | + * @author: ghw<hongwei.gao@yoho.cn> | ||
4 | + * @date: 2016/09/29 | ||
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; |
apps/brands/models/brands-api.js
0 → 100644
1 | +/** | ||
2 | + * 品牌一览 api | ||
3 | + * @author: ghw<hongwei.gao@yoho.cn> | ||
4 | + * @date: 2016/9/29 | ||
5 | + */ | ||
6 | +'use strict'; | ||
7 | +const api = global.yoho.API; | ||
8 | +const serviceAPI = global.yoho.ServiceAPI; | ||
9 | + | ||
10 | +/** | ||
11 | + * 分开取数,品牌一览 顶部的轮翻广告及热门品牌数据-PC | ||
12 | + * 顶部的轮翻广告及热门品牌数据 | ||
13 | + * @param string $contentCode 获取广告资源需要的位置码 | ||
14 | + */ | ||
15 | +const getBrandTopData = (contentCode) => { | ||
16 | + return serviceAPI.get('operations/api/v5/resource/get', { | ||
17 | + content_code: contentCode | ||
18 | + }, {cache: 3600}); | ||
19 | +}; | ||
20 | + | ||
21 | +/** | ||
22 | + * 分开取数,获取品牌一览 "按字母'A-Z'分组的品牌列表数据" | ||
23 | + * @param int $channel 频道标识 1:男,2:女,3:潮童,4:创意生活 | ||
24 | + */ | ||
25 | +const getBrandListData = channel => { | ||
26 | + let params = {method: 'app.brand.brandlist'}; | ||
27 | + | ||
28 | + if (!isNaN(channel)) { | ||
29 | + params.yh_channel = channel; | ||
30 | + } | ||
31 | + return api.get('', params); | ||
32 | +}; | ||
33 | + | ||
34 | +/** | ||
35 | + * 获取品牌简介 | ||
36 | + * | ||
37 | + * @param integer $brandId 品牌ID | ||
38 | + * @param int 用户ID | ||
39 | + * @return array 品牌介绍信息 | ||
40 | + */ | ||
41 | +const getBrandIntro = (brandId, uid) => { | ||
42 | + let param = {}; | ||
43 | + | ||
44 | + if (!uid) { | ||
45 | + param.cache = 3600; | ||
46 | + } | ||
47 | + return api.get('', { | ||
48 | + method: 'app.brand.getBrandIntro', | ||
49 | + brand_id: brandId, | ||
50 | + uid: uid | ||
51 | + }, param); | ||
52 | +}; | ||
53 | + | ||
54 | +/** | ||
55 | + * 获取品牌中产品图片 | ||
56 | + * @param int 品牌ID | ||
57 | + * @return array 品牌产品信息 | ||
58 | + */ | ||
59 | +const getProductByBrand = (brandId, limit) => { | ||
60 | + return api.get('', { | ||
61 | + method: 'web.search.search', | ||
62 | + brand: brandId, | ||
63 | + limit: limit | ||
64 | + }); | ||
65 | +}; | ||
66 | + | ||
67 | +/** | ||
68 | + * 获取品牌信息 | ||
69 | + * | ||
70 | + * @param array $ids | ||
71 | + * @return array | ||
72 | + */ | ||
73 | +const getBrandInfoByIds = (ids) => { | ||
74 | + return api.get('', { | ||
75 | + method: 'web.brand.info', | ||
76 | + ids: ids instanceof Array ? ids.join(',') : parseInt(ids, 10) | ||
77 | + }, {cache: 3600}); | ||
78 | +}; | ||
79 | + | ||
80 | +/** | ||
81 | + * 获取品牌列表 | ||
82 | + * | ||
83 | + * @param int $brandType | ||
84 | + * @param string $gender | ||
85 | + * @param string $type | ||
86 | + * @return array | ||
87 | + */ | ||
88 | +const getPlusstarList = (brandType, gender) => { | ||
89 | + return serviceAPI.get('guang/api/v3/plustar/getlist', { | ||
90 | + gender: gender, | ||
91 | + brand_type: brandType | ||
92 | + }, {cache: 3600}); | ||
93 | +}; | ||
94 | + | ||
95 | +module.exports = { | ||
96 | + getBrandTopData, | ||
97 | + getBrandListData, | ||
98 | + getBrandIntro, | ||
99 | + getProductByBrand, | ||
100 | + getPlusstarList, | ||
101 | + getBrandInfoByIds | ||
102 | +}; |
apps/brands/models/brands-model.js
0 → 100644
1 | + | ||
2 | +/** | ||
3 | + * 品牌一览 model | ||
4 | + * @author: ghw<hongwei.gao@yoho.cn> | ||
5 | + * @date: 2016/9/29 | ||
6 | + */ | ||
7 | +'use strict'; | ||
8 | + | ||
9 | +const Promise = require('bluebird'); | ||
10 | +const co = Promise.coroutine; | ||
11 | +const _ = require('lodash'); | ||
12 | +const helpers = global.yoho.helpers; | ||
13 | +const brandApi = require('./brands-api'); | ||
14 | +const serviceApi = global.yoho.ServiceAPI; | ||
15 | + | ||
16 | +// 品牌一览资源位CODE码 | ||
17 | +const channelCode = { | ||
18 | + boys_brand: '8b16b7baf9a66fbe553a6caa97d2ce2a', | ||
19 | + girls_brand: 'c95ae9e40f0add10549b819f821ad626', | ||
20 | + kids_brand: 'c575c6bfdfa4125fae7d24bbec7119c8', | ||
21 | + lifestyle_brand: '84b7926282fdef92f1039bdcf77c18ba', | ||
22 | + brand_list: 'f0f72b1e8f30e6ad086dfc4401f3a856', // 品牌列表资源位CODE码 | ||
23 | + brand_plusstar_banner_boys: 'd0149783b8dd2adaf083fd10556c39a9', | ||
24 | + brand_plusstar_banner_girls: 'aad7a43e9a04ac7c70ae7f0c1acf86ef', | ||
25 | + brand_plusstarindex_boys: 'a833aed63d28457156310e97faa7fa37', // plusstarindex男首资源位 | ||
26 | + brand_plusstarindex_girls: '6e4f162be3b3ba44f3bfcf1c38bdb745' // plusstarindex女首资源位 | ||
27 | +}; | ||
28 | + | ||
29 | +const BOYS = 'boys'; | ||
30 | +const GIRLS = 'girls'; | ||
31 | +const KIDS = 'kids'; | ||
32 | +const LIFESTYLE = 'lifestyle'; | ||
33 | + | ||
34 | +/** | ||
35 | + * 获取品牌一览资源位&channelType | ||
36 | + * | ||
37 | + * @param string $channelStr | ||
38 | + * @return array | ||
39 | + */ | ||
40 | +const switchBrandParams = channel => { | ||
41 | + let req = {}; | ||
42 | + | ||
43 | + switch (channel) { | ||
44 | + | ||
45 | + case BOYS: | ||
46 | + req = { | ||
47 | + channelType: 1, | ||
48 | + brandCode: channelCode.brand_plusstar_banner_boys | ||
49 | + }; | ||
50 | + break; | ||
51 | + case GIRLS: | ||
52 | + req = { | ||
53 | + channelType: 2, | ||
54 | + brandCode: channelCode.brand_plusstar_banner_girls | ||
55 | + }; | ||
56 | + break; | ||
57 | + case KIDS: | ||
58 | + req = { | ||
59 | + channelType: 3, | ||
60 | + brandCode: channelCode.kids_brand | ||
61 | + }; | ||
62 | + break; | ||
63 | + case LIFESTYLE: | ||
64 | + req = { | ||
65 | + channelType: 4, | ||
66 | + brandCode: channelCode.lifestyle_brand | ||
67 | + }; | ||
68 | + break; | ||
69 | + default: | ||
70 | + req = { | ||
71 | + channelType: 1, | ||
72 | + brandCode: channelCode.boys_brand | ||
73 | + }; | ||
74 | + break; | ||
75 | + } | ||
76 | + return req; | ||
77 | +}; | ||
78 | + | ||
79 | +/** | ||
80 | + * 获取品牌一览页面,品牌top | ||
81 | + * @param string $channel 频道名称 | ||
82 | + */ | ||
83 | +const getBrandViewTop = channel => { | ||
84 | + return co(function*() { | ||
85 | + let switchParams = switchBrandParams(channel); | ||
86 | + | ||
87 | + let res = yield brandApi.getBrandTopData(switchParams.brandCode); | ||
88 | + | ||
89 | + let result = {}, | ||
90 | + brandAds = [], | ||
91 | + brandLogos = []; | ||
92 | + | ||
93 | + if (!res || res.code !== 200) { | ||
94 | + return result; | ||
95 | + } | ||
96 | + | ||
97 | + // 头部10个品牌小图块 url | ||
98 | + if (res.data && res.data instanceof Array && res.data[1].data && res.data[1].data.list) { | ||
99 | + | ||
100 | + _.forEach(res.data[1].data.list, subValue => { | ||
101 | + brandAds.push({ | ||
102 | + name: subValue.name, | ||
103 | + src: helpers.image(subValue.src, 80, 50, 3), | ||
104 | + url: subValue.url | ||
105 | + }); | ||
106 | + }); | ||
107 | + } | ||
108 | + | ||
109 | + // 头部品牌图块,广告位 | ||
110 | + if (res.data && res.data instanceof Array && res.data[0].data) { | ||
111 | + _.forEach(res.data[0].data, (subValue, k) => { | ||
112 | + let srcUrl; | ||
113 | + | ||
114 | + // kids lifestyle 第一张图尺寸不同 | ||
115 | + if (switchParams.channelType === 1 || switchParams.channelType === 2) { | ||
116 | + srcUrl = helpers.image(subValue.src, 222, 180, 3); | ||
117 | + } else { | ||
118 | + srcUrl = (k === 0) ? helpers.image(subValue.src, 570, 280, 3) : | ||
119 | + helpers.image(subValue.src, 280, 280, 3); | ||
120 | + } | ||
121 | + let brandPlusstarItem = { | ||
122 | + name: subValue.title, | ||
123 | + src: srcUrl, | ||
124 | + url: subValue.url | ||
125 | + }; | ||
126 | + | ||
127 | + if (channel === BOYS || channel === GIRLS) { | ||
128 | + if (k === 0) { | ||
129 | + brandPlusstarItem.url = helpers.urlFormat('/brands/plusstar', {channel: channel}); | ||
130 | + } else { | ||
131 | + brandPlusstarItem.url = helpers.urlFormat('/brands/plusstar', {id: k, channel: channel}); | ||
132 | + } | ||
133 | + } | ||
134 | + | ||
135 | + brandLogos.push(brandPlusstarItem); | ||
136 | + }); | ||
137 | + } | ||
138 | + | ||
139 | + // 整合brandTop数据结构,boys、girls | ||
140 | + if (switchParams.channelType === 1 || switchParams.channelType === 2) { | ||
141 | + result.isTab = true; | ||
142 | + } | ||
143 | + result.tabHeader = brandLogos; | ||
144 | + result.logos = brandAds; | ||
145 | + | ||
146 | + return result; | ||
147 | + })(); | ||
148 | +}; | ||
149 | + | ||
150 | +/** | ||
151 | + * 获取品牌一览list | ||
152 | + * @param string $channel 频道名称 | ||
153 | + * @param int start 开始位置 1 开始 | ||
154 | + * @param int length 取数长度 0 取到最后 | ||
155 | + */ | ||
156 | +const getBrandViewList = (channel, start, length) => { | ||
157 | + return co(function*() { | ||
158 | + let switchParams = switchBrandParams(channel); | ||
159 | + | ||
160 | + let res = yield brandApi.getBrandListData(switchParams.channelType); | ||
161 | + | ||
162 | + let result = [], | ||
163 | + navigation = []; | ||
164 | + | ||
165 | + if (!res || res.code !== 200) { | ||
166 | + return result; | ||
167 | + } | ||
168 | + | ||
169 | + // 品牌list A-Z 0-9 | ||
170 | + if (res.data && res.data.brands) { | ||
171 | + | ||
172 | + _.forEach(res.data.brands, (subValue, key) => { | ||
173 | + let listTmp = []; | ||
174 | + | ||
175 | + _.forEach(subValue, ssubValue => { | ||
176 | + // 为品牌名称 | ||
177 | + let href; | ||
178 | + | ||
179 | + if (switchParams.channelType === 1) { | ||
180 | + href = helpers.urlFormat('', {gender: '1,3'}, ssubValue.brand_domain); | ||
181 | + } else if (switchParams.channelType === 2) { | ||
182 | + href = helpers.urlFormat('', {gender: '2,3'}, ssubValue.brand_domain); | ||
183 | + } else { | ||
184 | + href = helpers.urlFormat('', '', ssubValue.brand_domain); | ||
185 | + } | ||
186 | + let brandItem = { | ||
187 | + name: ssubValue.brand_name, | ||
188 | + key: ssubValue.id, | ||
189 | + href: href | ||
190 | + }; | ||
191 | + | ||
192 | + if (ssubValue.is_hot === 'Y') { | ||
193 | + brandItem.hot = 'hot'; | ||
194 | + } | ||
195 | + listTmp.push(brandItem); | ||
196 | + | ||
197 | + }); | ||
198 | + navigation.push(key); | ||
199 | + | ||
200 | + result.push({ | ||
201 | + key: key, | ||
202 | + val: _.sortBy(listTmp, 'name')// 对name排序 | ||
203 | + }); | ||
204 | + }); | ||
205 | + | ||
206 | + } | ||
207 | + | ||
208 | + // 只取部分数据 | ||
209 | + let begin; | ||
210 | + | ||
211 | + | ||
212 | + if (start) { | ||
213 | + begin = (start - 1) ? (start - 1) : 0; | ||
214 | + begin = (begin > 0) ? begin : 0; | ||
215 | + result = length ? result.slice(begin, length + begin) : result.slice(begin); | ||
216 | + } | ||
217 | + | ||
218 | + result.navigation = navigation; | ||
219 | + | ||
220 | + return result; | ||
221 | + })(); | ||
222 | +}; | ||
223 | + | ||
224 | +/** | ||
225 | + * 获取单个广告浮窗内容 | ||
226 | + * | ||
227 | + * @param int $brandId | ||
228 | + * @param int $uid | ||
229 | + * @return array | ||
230 | + */ | ||
231 | +const getBrandInfo = (brandId, uid) => { | ||
232 | + return co(function*() { | ||
233 | + let data = {}, | ||
234 | + imgs = []; | ||
235 | + | ||
236 | + // 获取品牌简介 | ||
237 | + let res = yield brandApi.getBrandIntro(brandId, uid); | ||
238 | + | ||
239 | + if (!res || res.code !== 200) { | ||
240 | + return data; | ||
241 | + } | ||
242 | + if (res.data) { | ||
243 | + // 获取品牌下的产品信息 | ||
244 | + let proInfo = yield brandApi.getProductByBrand(brandId, 3); | ||
245 | + | ||
246 | + if (!proInfo || proInfo.code !== 200) { | ||
247 | + return data; | ||
248 | + } | ||
249 | + let proInfoTmp = proInfo.data.product_list ? proInfo.data.product_list : []; | ||
250 | + | ||
251 | + if (!_.isEmpty(proInfoTmp)) { | ||
252 | + _.forEach(proInfoTmp, subValue => { | ||
253 | + imgs.push({ | ||
254 | + src: helpers.image(subValue.default_images, 80, 100, 3) | ||
255 | + }); | ||
256 | + }); | ||
257 | + } | ||
258 | + | ||
259 | + // 整合 | ||
260 | + data = { | ||
261 | + key: res.data.brand_id, | ||
262 | + icon: helpers.image(res.data.brand_ico, 80, 50, 3), | ||
263 | + title: res.data.brand_name, | ||
264 | + content: res.data.brand_intro, | ||
265 | + subtitle: 'FEATURED ITEMS', | ||
266 | + imgs: imgs | ||
267 | + }; | ||
268 | + } | ||
269 | + return data; | ||
270 | + })(); | ||
271 | +}; | ||
272 | + | ||
273 | +/** | ||
274 | + * 多个品牌ID获取品牌信息 | ||
275 | + * | ||
276 | + * @param array $brandIds | ||
277 | + * @return array | ||
278 | + */ | ||
279 | +const getBrandInfoByIds = (brandIds) => { | ||
280 | + return co(function*() { | ||
281 | + let res = yield brandApi.getBrandInfoByIds(brandIds); | ||
282 | + | ||
283 | + let brandsInfo = {}; | ||
284 | + | ||
285 | + if (!res || res.code !== 200) { | ||
286 | + return brandsInfo; | ||
287 | + } | ||
288 | + if (res.data && res.code === 200) { | ||
289 | + _.forEach(res.data, (subValue, k) => { | ||
290 | + subValue.desc = _.trim(subValue.brand_intro.replace(/(\t)|(\n)|(\r)|( )/g, '') | ||
291 | + .replace(/<.*?>/ig, '')); | ||
292 | + subValue.url = subValue.brand_domain; | ||
293 | + delete subValue.brand_intro; | ||
294 | + brandsInfo[k] = subValue; | ||
295 | + }); | ||
296 | + } | ||
297 | + | ||
298 | + return brandsInfo; | ||
299 | + })(); | ||
300 | +}; | ||
301 | + | ||
302 | +/** | ||
303 | + * 获取plusstar品牌列表项目 | ||
304 | + * | ||
305 | + * @param string $channel | ||
306 | + * @return array | ||
307 | + */ | ||
308 | +const getPlusstarBrandListItem = (channel) => { | ||
309 | + return co(function*() { | ||
310 | + let code = channel === 'girls' ? channelCode.brand_plusstar_banner_girls : | ||
311 | + channelCode.brand_plusstar_banner_boys; | ||
312 | + | ||
313 | + // 资源位数据 | ||
314 | + let resource = yield serviceApi.get('operations/api/v5/resource/get', {content_code: code}, {cache: 3600}); | ||
315 | + | ||
316 | + let items = []; | ||
317 | + | ||
318 | + if (!resource || resource.code !== 200) { | ||
319 | + return items; | ||
320 | + } | ||
321 | + if (resource.data && resource.code === 200) { | ||
322 | + items[0] = {name: '所有品牌', src: '', url: helpers.urlFormat('/brands', {channel: channel}), brandType: ''}; | ||
323 | + items[1] = {name: '设计新潮', src: '', url: '', brandType: 4}; | ||
324 | + items[2] = {name: '潮流经典', src: '', url: '', brandType: 1}; | ||
325 | + items[3] = {name: '明星潮牌', src: '', url: '', brandType: 2}; | ||
326 | + items[4] = {name: '原创潮牌', src: '', url: '', brandType: 3}; | ||
327 | + | ||
328 | + let resourceData = resource.data, | ||
329 | + pos = 0; | ||
330 | + | ||
331 | + _.forEach(items, (subValue, k) => { | ||
332 | + if (_.isEmpty(subValue.url)) { | ||
333 | + subValue.url = helpers.urlFormat('/brands/plusstar', {id: k, channel: channel}); | ||
334 | + } | ||
335 | + | ||
336 | + if (pos in resourceData[0].data) { | ||
337 | + subValue.src = helpers.image(resourceData[0].data[pos].src, 222, 180, 1); | ||
338 | + subValue.name = resourceData[0].data[pos].title; | ||
339 | + } | ||
340 | + pos++; | ||
341 | + }); | ||
342 | + } | ||
343 | + | ||
344 | + return items; | ||
345 | + })(); | ||
346 | +}; | ||
347 | + | ||
348 | +/** | ||
349 | + * 获取Plustar列表 | ||
350 | + * | ||
351 | + * @param string $brandType | ||
352 | + * @param string $gender | ||
353 | + * @return array | ||
354 | + */ | ||
355 | +const getPlustarList = (brandType, gender) => { | ||
356 | + return co(function*() { | ||
357 | + let list = yield brandApi.getPlusstarList(brandType, gender); | ||
358 | + | ||
359 | + let brandList = {}, | ||
360 | + data = {}, | ||
361 | + brandsIds = [], | ||
362 | + result = {brandsIds: [], data: {}}; | ||
363 | + | ||
364 | + if (!list || list.code !== 200) { | ||
365 | + return result; | ||
366 | + } | ||
367 | + if (list.data && list.data.data && list.data.data.list) { | ||
368 | + brandList = list.data.data.list[0]; | ||
369 | + } | ||
370 | + if (brandList.data) { | ||
371 | + _.forEach(brandList.data, brand => { | ||
372 | + let src = ''; | ||
373 | + | ||
374 | + if (brand.data[0]) { | ||
375 | + src = helpers.image(brand.data[0].src, 320, 160, 1); | ||
376 | + } | ||
377 | + data[brand.brand_id] = { | ||
378 | + brand_id: brand.brand_id, | ||
379 | + name: brand.brand_name, | ||
380 | + sort_id: brand.sort_id, | ||
381 | + src: src, | ||
382 | + desc: '', | ||
383 | + url: '' | ||
384 | + }; | ||
385 | + brandsIds.push(brand.brand_id); | ||
386 | + }); | ||
387 | + | ||
388 | + result.brandsIds = brandsIds; | ||
389 | + result.data = data; | ||
390 | + } | ||
391 | + | ||
392 | + return result; | ||
393 | + })(); | ||
394 | +}; | ||
395 | + | ||
396 | +module.exports = { | ||
397 | + getBrandViewTop, | ||
398 | + getBrandViewList, | ||
399 | + getBrandInfo, | ||
400 | + getBrandInfoByIds, | ||
401 | + getPlusstarBrandListItem, | ||
402 | + getPlustarList | ||
403 | +}; |
apps/brands/models/brands-service.js
0 → 100644
1 | +/** | ||
2 | + * 品牌一览 controller | ||
3 | + * @author: ghw<hongwei.gao@yoho.cn> | ||
4 | + * @date: 2016/9/29 | ||
5 | + */ | ||
6 | +'use strict'; | ||
7 | + | ||
8 | +const Promise = require('bluebird'); | ||
9 | +const co = Promise.coroutine; | ||
10 | +const api = global.yoho.API; | ||
11 | +const headerModel = require('../../../doraemon/models/header'); | ||
12 | +const brandsModel = require('./brands-model'); | ||
13 | +const _ = require('lodash'); | ||
14 | +const helpers = global.yoho.helpers; | ||
15 | +const pager = require(`${global.utils}/pager`).setPager; | ||
16 | + | ||
17 | +const BOYS = 'boys'; | ||
18 | +const GIRLS = 'girls'; | ||
19 | +const KIDS = 'kids'; | ||
20 | +const LIFESTYLE = 'lifestyle'; | ||
21 | + | ||
22 | +/** | ||
23 | + * 获取品牌一览资源位&channelType | ||
24 | + * | ||
25 | + * @param string $channelStr | ||
26 | + * @return array | ||
27 | + */ | ||
28 | +const getGenderByChannel = channel => { | ||
29 | + let gender = ''; | ||
30 | + | ||
31 | + switch (channel) { | ||
32 | + | ||
33 | + case BOYS: | ||
34 | + gender = '1,3'; | ||
35 | + break; | ||
36 | + case GIRLS: | ||
37 | + gender = '2,3'; | ||
38 | + break; | ||
39 | + default: | ||
40 | + gender = '1,2,3'; | ||
41 | + break; | ||
42 | + } | ||
43 | + return gender; | ||
44 | +}; | ||
45 | + | ||
46 | +const getHomeurlByChannel = channel => { | ||
47 | + let home; | ||
48 | + | ||
49 | + switch (channel) { | ||
50 | + case GIRLS: | ||
51 | + home = helpers.urlFormat('/woman', {}, 'new'); | ||
52 | + break; | ||
53 | + case LIFESTYLE: | ||
54 | + home = helpers.urlFormat('/lifestyle', {}, 'new'); | ||
55 | + break; | ||
56 | + case KIDS: | ||
57 | + home = helpers.urlFormat('/kids', {}, 'new'); | ||
58 | + break; | ||
59 | + default: | ||
60 | + home = helpers.urlFormat(''); | ||
61 | + break; | ||
62 | + } | ||
63 | + return home; | ||
64 | +}; | ||
65 | + | ||
66 | +// 添加网站的SEO | ||
67 | +const seoMap = { | ||
68 | + boys: { | ||
69 | + title: '品牌一览|男装品牌排行榜,男装品牌大全|YOHO!BUY 有货 100%正品保证', | ||
70 | + keywords: '品牌一览,男装品牌,男装品牌排行榜,男装品牌大全,YOHO!BUY 有货', | ||
71 | + description: 'YOHO!BUY 有货男装品牌一览汇集国内国际各大男装品牌大全,为广大爱好时尚的男士青年提供品牌男装、' + | ||
72 | + '休闲男装、商务男装.YOHO!BUY 有货,100%正品保证' | ||
73 | + }, | ||
74 | + girls: { | ||
75 | + title: '品牌一览|女装品牌排行榜,女装品牌大全|YOHO!BUY 有货 100%正品保证', | ||
76 | + keywords: '品牌一览,女装品牌,女装品牌排行榜,女装品牌大全,YOHO!BUY 有货', | ||
77 | + description: 'YOHO!BUY 有货女装品牌一览汇集国内国际各大女装品牌,为广大爱美女生提供品牌女装、休闲女装、' + | ||
78 | + '商务女装.买品牌女装就上YOHO!BUY 有货,100%正品保证' | ||
79 | + }, | ||
80 | + kids: { | ||
81 | + title: '品牌一览|童装童鞋品牌,儿童鞋包配饰排行榜,潮童品牌大全|YOHO!BUY 有货 100%正品保证', | ||
82 | + keywords: '童装品牌,童装童鞋排行榜,儿童鞋包配饰排行榜,潮童品牌大全,品牌一览,YOHO!BUY 有货', | ||
83 | + description: 'YOHO!BUY 有货童装品牌一览汇集国内国际各大童装品牌大全,为广大爱好潮流的儿童提供品牌童装、童鞋,' + | ||
84 | + '儿童鞋包配饰.YOHO!BUY 有货,100%正品保证' | ||
85 | + }, | ||
86 | + lifestyle: { | ||
87 | + title: '品牌一览|数码3c,居家,玩具娱乐,文具,美妆品牌|YOHO!BUY 有货 100%正品保证', | ||
88 | + keywords: '数码3c品牌,居家品牌,玩具娱乐品牌,文具品牌,美妆品牌', | ||
89 | + description: 'YOHO!BUY 有货女装品牌一览汇集国内国际各大数码3c品牌,居家品牌,玩具娱乐品牌,文具品牌,' + | ||
90 | + '美妆品牌.买创意生活家居就上YOHO!BUY 有货,100%正品保证' | ||
91 | + } | ||
92 | +}; | ||
93 | + | ||
94 | +/** | ||
95 | + * 获取品牌一览list | ||
96 | + * @param string $channel 频道名称 | ||
97 | + * @param int start 开始位置 1 开始 | ||
98 | + * @param int length 取数长度 0 取到最后 | ||
99 | + */ | ||
100 | +exports.getBrandViewList = (channel) => { | ||
101 | + let apiMethod = [ | ||
102 | + headerModel.requestHeaderData(channel), | ||
103 | + brandsModel.getBrandViewTop(channel), | ||
104 | + brandsModel.getBrandViewList(channel, 1, 5) // 分屏加载 | ||
105 | + ]; | ||
106 | + | ||
107 | + return api.all(apiMethod).then(result => { | ||
108 | + let responseData = { | ||
109 | + module: 'brands', | ||
110 | + page: 'brands' | ||
111 | + }; | ||
112 | + | ||
113 | + // 头部数据 | ||
114 | + Object.assign(responseData, result[0]); | ||
115 | + | ||
116 | + // 品牌一览列表 | ||
117 | + responseData.brands = result[1]; | ||
118 | + responseData.brands.navigation = result[2].navigation; | ||
119 | + responseData.brands.category = result[2]; | ||
120 | + | ||
121 | + // 导航pathNav | ||
122 | + responseData.brands.pathNav = [ | ||
123 | + { | ||
124 | + href: getHomeurlByChannel(channel), | ||
125 | + name: `${_.toUpper(channel)}首页`, | ||
126 | + pathTitle: 'YOHO!BUY 有货' | ||
127 | + }, | ||
128 | + { | ||
129 | + href: helpers.urlFormat('/brands'), | ||
130 | + name: '品牌一览', | ||
131 | + pathTitle: '品牌一览' | ||
132 | + } | ||
133 | + ]; | ||
134 | + | ||
135 | + // SEO | ||
136 | + Object.assign(responseData, seoMap[channel]); | ||
137 | + | ||
138 | + return responseData; | ||
139 | + }); | ||
140 | +}; | ||
141 | + | ||
142 | +/** | ||
143 | + * brandList-Ajax调用 | ||
144 | + */ | ||
145 | +exports.getBrandList = (channel, start) => { | ||
146 | + let apiMethod = [ | ||
147 | + brandsModel.getBrandViewList(channel, start) | ||
148 | + ]; | ||
149 | + | ||
150 | + return api.all(apiMethod).then(result => { | ||
151 | + let responseData = {}; | ||
152 | + | ||
153 | + // 品牌一览列表 | ||
154 | + responseData.category = result[0]; | ||
155 | + return responseData; | ||
156 | + }); | ||
157 | +}; | ||
158 | + | ||
159 | +/** | ||
160 | + * 品牌接口数据 | ||
161 | + * | ||
162 | + * @param string brandId 获取品牌ID | ||
163 | + * @return json | ||
164 | + */ | ||
165 | +exports.brandInfo = (brandId, uid) => { | ||
166 | + let apiMethod = [ | ||
167 | + brandsModel.getBrandInfo(brandId, uid) | ||
168 | + ]; | ||
169 | + | ||
170 | + return api.all(apiMethod).then(result => { | ||
171 | + | ||
172 | + return { | ||
173 | + code: _.isEmpty(result[0]) ? 400 : 200, | ||
174 | + brand: _.isEmpty(result[0]) ? '' : result[0] | ||
175 | + }; | ||
176 | + }); | ||
177 | +}; | ||
178 | + | ||
179 | +/** | ||
180 | + * 多个品牌ID获取品牌信息 | ||
181 | + * | ||
182 | + * @param array $brandIds | ||
183 | + * @return array | ||
184 | + */ | ||
185 | +exports.plusstarList = (channel, req) => { | ||
186 | + return co(function*() { | ||
187 | + let headerData = yield headerModel.requestHeaderData(channel); | ||
188 | + | ||
189 | + let responseData = { | ||
190 | + module: 'brands', | ||
191 | + page: 'brands', | ||
192 | + brandsHomePage: true | ||
193 | + }; | ||
194 | + | ||
195 | + let id = req.query.id || '', | ||
196 | + gender = req.query.gender || getGenderByChannel(channel), | ||
197 | + limit = 20, | ||
198 | + page = parseInt(req.query.page, 10) || 1; | ||
199 | + | ||
200 | + let items = yield brandsModel.getPlusstarBrandListItem(channel); | ||
201 | + | ||
202 | + let brandType = 1; | ||
203 | + | ||
204 | + if (items[id]) { | ||
205 | + brandType = items[id].brandType; | ||
206 | + } | ||
207 | + let plustarList = yield brandsModel.getPlustarList(brandType, gender); | ||
208 | + | ||
209 | + let list = plustarList.data; | ||
210 | + | ||
211 | + let brandIds = [], | ||
212 | + brands = [], | ||
213 | + pageList = {}; | ||
214 | + | ||
215 | + brandIds = plustarList.brandsIds.slice((page - 1) * limit, page * limit); | ||
216 | + if (plustarList.brandsIds.length > limit) { | ||
217 | + pageList = pager(Math.ceil(plustarList.brandsIds.length / limit), { | ||
218 | + channel: channel, | ||
219 | + page: page, | ||
220 | + id: id | ||
221 | + }); | ||
222 | + } | ||
223 | + | ||
224 | + if (brandIds.length > 0) { | ||
225 | + // 获取品牌信息 | ||
226 | + let brandsInfo = yield brandsModel.getBrandInfoByIds(brandIds); | ||
227 | + | ||
228 | + _.forEach(brandIds, brandId => { | ||
229 | + if (brandsInfo[brandId]) { | ||
230 | + list[brandId].desc = brandsInfo[brandId].desc; | ||
231 | + list[brandId].url = helpers.urlFormat('', {gender: gender}, brandsInfo[brandId].url); | ||
232 | + } | ||
233 | + brands.push(list[brandId]); | ||
234 | + }); | ||
235 | + } | ||
236 | + let data = { | ||
237 | + brandsHomePage: true, | ||
238 | + brands: { | ||
239 | + items: brands, | ||
240 | + tabs: items | ||
241 | + | ||
242 | + } | ||
243 | + }; | ||
244 | + | ||
245 | + // 头部数据 | ||
246 | + Object.assign(responseData, headerData); | ||
247 | + | ||
248 | + // 产品信息 | ||
249 | + Object.assign(responseData, data); | ||
250 | + | ||
251 | + // 页码 | ||
252 | + Object.assign(responseData, pageList); | ||
253 | + | ||
254 | + // SEO | ||
255 | + Object.assign(responseData, seoMap[channel]); | ||
256 | + return responseData; | ||
257 | + })(); | ||
258 | + | ||
259 | +}; |
apps/brands/router.js
0 → 100644
1 | +/** | ||
2 | + * router of sub app brands | ||
3 | + * @author: ghw<hongwei.gao@yoho.cn> | ||
4 | + * @date: 2016/09/29 | ||
5 | + */ | ||
6 | + | ||
7 | +'use strict'; | ||
8 | + | ||
9 | +const express = require('express'); | ||
10 | +const cRoot = './controllers'; | ||
11 | + | ||
12 | +const router = express.Router(); // eslint-disable-line | ||
13 | +const brandsController = require(`${cRoot}/brands`); | ||
14 | + | ||
15 | +// 品牌一览 | ||
16 | +router.get('', brandsController.index); | ||
17 | + | ||
18 | +// 悬浮出现品牌信息 | ||
19 | +router.get('/brandinfo', brandsController.brandInfo); | ||
20 | + | ||
21 | +// 品牌没有加载完全,继续加载 | ||
22 | +router.post('/brandList', brandsController.brandList); | ||
23 | + | ||
24 | +// brands/plusstar | ||
25 | +router.get('/plusstar', brandsController.plusstarList); | ||
26 | + | ||
27 | +module.exports = router; |
1 | +{{> brand-list}} |
apps/brands/views/action/brands/brands.hbs
0 → 100644
1 | +<div class="home-page yoho-page brands" data-page="brands"> | ||
2 | + {{# brands}} | ||
3 | + | ||
4 | + {{> common/path-nav}} | ||
5 | + | ||
6 | + {{#if isTab}} | ||
7 | + <div class="brands-tabs"> | ||
8 | + <ul class="clearfix"> | ||
9 | + {{#each tabHeader}} | ||
10 | + <li> | ||
11 | + <a href="{{url}}"> | ||
12 | + <div class="g-mask"></div> | ||
13 | + <p class="tips">{{name}}</p> | ||
14 | + <img class="lazy" data-original="{{src}}"/> | ||
15 | + </a> | ||
16 | + </li> | ||
17 | + {{/each}} | ||
18 | + </ul> | ||
19 | + <div class="hover-contain"> | ||
20 | + <div class="hoverarr"> | ||
21 | + <i></i> | ||
22 | + </div> | ||
23 | + </div> | ||
24 | + </div> | ||
25 | + {{^}} | ||
26 | + <ul class="brands-ad clearfix"> | ||
27 | + {{#each tabHeader}} | ||
28 | + <li> | ||
29 | + <a href="{{url}}" target="_blank"> | ||
30 | + <img class="lazy" data-original="{{src}}"> | ||
31 | + </a> | ||
32 | + </li> | ||
33 | + {{/each}} | ||
34 | + </ul> | ||
35 | + {{/if}} | ||
36 | + <div class="brands-logo clearfix"> | ||
37 | + {{#each logos}} | ||
38 | + <a href="{{url}}" title="{{name}}" target="_blank"> | ||
39 | + <img class="lazy" data-original="{{src}}"> | ||
40 | + </a> | ||
41 | + {{/each}} | ||
42 | + </div> | ||
43 | + <div class="brands-category"> | ||
44 | + <div class="category-nav"> | ||
45 | + <span>BRANDS A-Z:</span> | ||
46 | + {{#each navigation}} | ||
47 | + <a href="#{{this}}">{{this}}</a> | ||
48 | + {{/each}} | ||
49 | + </div> | ||
50 | + </div> | ||
51 | + <div class="brands-list" > | ||
52 | + {{> brand-list}} | ||
53 | + </div> | ||
54 | + {{/ brands}} | ||
55 | +</div> |
apps/brands/views/action/brands/index.hbs
0 → 100644
1 | +{{> layout/header}} | ||
2 | +<div class="home-page yoho-page brands" data-page="brands"> | ||
3 | +{{# brands}} | ||
4 | + | ||
5 | + | ||
6 | + {{! 头部banner}} | ||
7 | + {{# slide}} | ||
8 | + {{>index/slide-banner}} | ||
9 | + {{/ slide}} | ||
10 | + | ||
11 | + {{! 品牌 BRAND}} | ||
12 | + {{# brand}} | ||
13 | + {{> index/floor-header}} | ||
14 | + <div class="brandfloor clearfix"> | ||
15 | + <ul class="g-list"> | ||
16 | + {{# list}} | ||
17 | + <li> | ||
18 | + <a href="{{url}}" target= "_blank"> | ||
19 | + <img class="lazy" data-original="{{src}}" alt=""> | ||
20 | + | ||
21 | + </a> | ||
22 | + </li> | ||
23 | + {{/ list}} | ||
24 | + </ul> | ||
25 | + </div> | ||
26 | + {{/ brand}} | ||
27 | + | ||
28 | + {{! 单品 SINGLE GOODS}} | ||
29 | + {{# singlegoods}} | ||
30 | + {{> index/floor-header}} | ||
31 | + <div class="singlegoods clearfix"> | ||
32 | + <ul class="g-list"> | ||
33 | + {{# list}} | ||
34 | + <li> | ||
35 | + <a href="{{url}}" target= "_blank"> | ||
36 | + <img class="lazy" data-original="{{src}}" alt=""> | ||
37 | + <div class="singlegoods-title"> | ||
38 | + <div class="g-mask"></div> | ||
39 | + <p>{{name}}</p> | ||
40 | + </div> | ||
41 | + </a> | ||
42 | + </li> | ||
43 | + {{/ list}} | ||
44 | + </ul> | ||
45 | + </div> | ||
46 | + {{/ singlegoods}} | ||
47 | + | ||
48 | + {{!视频 VIDEO}} | ||
49 | + {{# video}} | ||
50 | + {{> index/floor-header}} | ||
51 | + <div class="video clearfix"> | ||
52 | + <ul class="g-list"> | ||
53 | + {{# list}} | ||
54 | + <li> | ||
55 | + <a href="{{url}}" target= "_blank"> | ||
56 | + <img class="lazy" data-original="{{src}}" alt="" /><i class="video-play"></i> | ||
57 | + <div class="video-title"> | ||
58 | + <div class="g-mask"></div> | ||
59 | + <p>{{name}}</p> | ||
60 | + </div> | ||
61 | + </a> | ||
62 | + </li> | ||
63 | + {{/ list}} | ||
64 | + </ul> | ||
65 | + </div> | ||
66 | + {{/ video}} | ||
67 | + | ||
68 | + {{!新闻 NEWS}} | ||
69 | + {{# news}} | ||
70 | + {{> index/floor-header}} | ||
71 | + <div class="news clearfix"> | ||
72 | + <div class="news-pic"> | ||
73 | + {{# pics}} | ||
74 | + {{>index/slide-banner}} | ||
75 | + {{/ pics}} | ||
76 | + </div> | ||
77 | + <div class="news-txt"> | ||
78 | + {{# txts}} | ||
79 | + <ul> | ||
80 | + {{#each list}} | ||
81 | + <li> | ||
82 | + <i class="iconfont"></i><a href="{{url}}">{{name}}</a> | ||
83 | + </li> | ||
84 | + {{/each}} | ||
85 | + </ul> | ||
86 | + {{/ txts}} | ||
87 | + </div> | ||
88 | + </div> | ||
89 | + {{/ news}} | ||
90 | + | ||
91 | + {{!推广 AD}} | ||
92 | + {{# ads}} | ||
93 | + <div class="ads clearfix"> | ||
94 | + <ul class="g-list"> | ||
95 | + {{# list}} | ||
96 | + <li> | ||
97 | + <a href="{{url}}" target= "_blank"> | ||
98 | + <img class="lazy" data-original="{{src}}" alt=""> | ||
99 | + <span class="name g-title">{{name}}</span> | ||
100 | + <span class="des g-title">{{des}}</span> | ||
101 | + </a> | ||
102 | + </li> | ||
103 | + {{/ list}} | ||
104 | + </ul> | ||
105 | + </div> | ||
106 | + {{/ ads}} | ||
107 | +{{/ brands}} | ||
108 | +</div> | ||
109 | +{{> layout/footer}} |
apps/brands/views/action/brands/list.hbs
0 → 100644
1 | +{{> layout/header}} | ||
2 | +<div class="home-page yoho-page brands" data-page="brands"> | ||
3 | +{{# brands}} | ||
4 | + <div class="sit-nav"> | ||
5 | + <a href="#">BOYS首页</a><span class="sep">></span><a href="#">品牌一览</a> | ||
6 | + </div> | ||
7 | + <div class="brands-tabs height-initial"> | ||
8 | + <ul class="clearfix"> | ||
9 | + {{#each tabs}} | ||
10 | + <li> | ||
11 | + <a href="{{url}}" target="_blank"> | ||
12 | + <div class="g-mask"></div> | ||
13 | + <p class="tips">{{name}}</p> | ||
14 | + <img class="lazy" data-original="{{src}}"/> | ||
15 | + </a> | ||
16 | + </li> | ||
17 | + {{/each}} | ||
18 | + </ul> | ||
19 | + <div class="hover-contain"> | ||
20 | + <div class="hoverarr"> | ||
21 | + <i></i> | ||
22 | + </div> | ||
23 | + </div> | ||
24 | + </div> | ||
25 | + <div class="brands-items clearfix"> | ||
26 | + {{#each items}} | ||
27 | + <div class="brands-item clearfix"> | ||
28 | + <a class="brands-pic" title="{{name}}" href="{{url}}" target="_blank"> | ||
29 | + <img class="lazy" data-original="{{src}}"/> | ||
30 | + </a> | ||
31 | + <div class="brand-info"> | ||
32 | + <a title="{{name}}" href="{{url}}" target="_blank"> | ||
33 | + <h3> | ||
34 | + {{name}} | ||
35 | + </h3> | ||
36 | + </a> | ||
37 | + <div class="brand-desc">{{desc}}</div> | ||
38 | + </div> | ||
39 | + </div> | ||
40 | + {{/each}} | ||
41 | + </div> | ||
42 | + <div class="pagination"> | ||
43 | + <a href="#" class="page_pre" title="上一页"><i class="iconfont"></i>上一页</a> | ||
44 | + <a href="#"><span>1</span></a> | ||
45 | + <a href="#" class="cur"><span>2</span></a> | ||
46 | + <a href="#"><span>3</span></a> | ||
47 | + <a href="#"><span>4</span></a> | ||
48 | + <a href="#"><span>5</span></a> | ||
49 | + <a><span>...</span></a> | ||
50 | + <a href="#"><span>215</span></a> | ||
51 | + <a href="#" title="下一页">下一页<i class="iconfont"></i></a> | ||
52 | + </div> | ||
53 | +{{/ brands}} | ||
54 | +</div> | ||
55 | +{{> layout/footer}} |
apps/brands/views/action/brands/plusstar.hbs
0 → 100644
1 | +<div class="home-page yoho-page brands" data-page="brands"> | ||
2 | +{{# brands}} | ||
3 | + | ||
4 | + {{> common/path-nav}} | ||
5 | + | ||
6 | + <div class="brands-tabs height-initial"> | ||
7 | + <ul class="clearfix"> | ||
8 | + {{#each tabs}} | ||
9 | + <li> | ||
10 | + <a href="{{url}}"> | ||
11 | + <div class="g-mask"></div> | ||
12 | + <p class="tips">{{name}}</p> | ||
13 | + <img class="lazy" data-original="{{src}}"/> | ||
14 | + </a> | ||
15 | + </li> | ||
16 | + {{/each}} | ||
17 | + </ul> | ||
18 | + <div class="hover-contain"> | ||
19 | + <div class="hoverarr"> | ||
20 | + <i></i> | ||
21 | + </div> | ||
22 | + </div> | ||
23 | + </div> | ||
24 | + <div class="brands-items clearfix"> | ||
25 | + {{#each items}} | ||
26 | + <div class="brands-item clearfix"> | ||
27 | + <a class="brands-pic" title="{{name}}" href="{{url}}" target="_blank"> | ||
28 | + <img class="lazy" data-original="{{src}}"/> | ||
29 | + </a> | ||
30 | + <div class="brand-info"> | ||
31 | + <a title="{{name}}" href="{{url}}" target="_blank"> | ||
32 | + <h3> | ||
33 | + {{name}} | ||
34 | + </h3> | ||
35 | + </a> | ||
36 | + <div class="brand-desc">{{{desc}}}</div> | ||
37 | + </div> | ||
38 | + </div> | ||
39 | + {{/each}} | ||
40 | + </div> | ||
41 | +{{/ brands}} | ||
42 | + <div class="pagination clearfix"> | ||
43 | + {{# prePage}} | ||
44 | + <a href="{{url}}" title="上一页">上一页<span class="iconfont"></span></a> | ||
45 | + {{/ prePage}} | ||
46 | + | ||
47 | + {{# pages}} | ||
48 | + <a{{#if url}} href="{{url}}"{{/if}}{{#if cur}} class="cur"{{/if}}>{{num}}</a> | ||
49 | + {{/ pages}} | ||
50 | + | ||
51 | + {{# nextPage}} | ||
52 | + <a href="{{url}}" title="下一页">下一页<span class="iconfont"></span></a> | ||
53 | + {{/ nextPage}} | ||
54 | + </div> | ||
55 | +</div> |
1 | +{{> layout/header}} | ||
2 | +<div class="home-page yoho-page brands" data-page="brands"> | ||
3 | +{{# brands}} | ||
4 | + | ||
5 | + | ||
6 | + {{! 头部banner}} | ||
7 | + {{# slide}} | ||
8 | + {{>index/slide-banner}} | ||
9 | + {{/ slide}} | ||
10 | + | ||
11 | + {{! 品牌 BRAND}} | ||
12 | + {{# brand}} | ||
13 | + {{> index/floor-header}} | ||
14 | + <div class="brandfloor list-floor clearfix"> | ||
15 | + <ul class="g-list"> | ||
16 | + {{# list}} | ||
17 | + <li> | ||
18 | + <a href="{{href}}" target= "_blank"> | ||
19 | + <img class="lazy" data-original="{{img}}" alt=""> | ||
20 | + | ||
21 | + </a> | ||
22 | + </li> | ||
23 | + {{/ list}} | ||
24 | + </ul> | ||
25 | + </div> | ||
26 | + {{/ brand}} | ||
27 | + | ||
28 | + {{! 单品 SINGLE GOODS}} | ||
29 | + {{# singlegoods}} | ||
30 | + {{> index/floor-header}} | ||
31 | + <div class="singlegoods list-floor clearfix"> | ||
32 | + <ul class="g-list"> | ||
33 | + {{# list}} | ||
34 | + <li> | ||
35 | + <a href="{{href}}" target= "_blank"> | ||
36 | + <img class="lazy" data-original="{{img}}" alt=""> | ||
37 | + <div class="singlegoods-title"> | ||
38 | + <div class="g-mask"></div> | ||
39 | + <p>{{name}}</p> | ||
40 | + </div> | ||
41 | + </a> | ||
42 | + </li> | ||
43 | + {{/ list}} | ||
44 | + </ul> | ||
45 | + </div> | ||
46 | + {{/ singlegoods}} | ||
47 | + | ||
48 | + {{!视频 VIDEO}} | ||
49 | + {{# video}} | ||
50 | + {{> index/floor-header}} | ||
51 | + <div class="video list-floor clearfix"> | ||
52 | + <ul class="g-list"> | ||
53 | + {{# list}} | ||
54 | + <li> | ||
55 | + <a href="{{href}}" target= "_blank"> | ||
56 | + <img class="lazy" data-original="{{img}}" alt="" /><i class="video-play"></i> | ||
57 | + <div class="video-title"> | ||
58 | + <div class="g-mask"></div> | ||
59 | + <p>{{name}}</p> | ||
60 | + </div> | ||
61 | + </a> | ||
62 | + </li> | ||
63 | + {{/ list}} | ||
64 | + </ul> | ||
65 | + </div> | ||
66 | + {{/ video}} | ||
67 | + | ||
68 | + {{!新闻 NEWS}} | ||
69 | + {{# news}} | ||
70 | + {{> index/floor-header}} | ||
71 | + <div class="news clearfix"> | ||
72 | + <div class="news-pic"> | ||
73 | + {{# pics}} | ||
74 | + {{>index/slide-banner}} | ||
75 | + {{/ pics}} | ||
76 | + </div> | ||
77 | + <div class="news-txt"> | ||
78 | + {{# txts}} | ||
79 | + <ul> | ||
80 | + {{#each list}} | ||
81 | + <li> | ||
82 | + <i class="iconfont"></i><a href="{{href}}" target= "_blank">{{name}}</a> | ||
83 | + </li> | ||
84 | + {{/each}} | ||
85 | + </ul> | ||
86 | + {{/ txts}} | ||
87 | + </div> | ||
88 | + </div> | ||
89 | + {{/ news}} | ||
90 | + | ||
91 | + {{!推广 AD}} | ||
92 | + {{# ads}} | ||
93 | + <div class="ads list-floor clearfix"> | ||
94 | + <ul class="g-list"> | ||
95 | + {{# list}} | ||
96 | + <li> | ||
97 | + <a href="{{href}}" target= "_blank"> | ||
98 | + <img class="lazy" data-original="{{img}}" alt=""> | ||
99 | + <span class="name g-title">{{name}}</span> | ||
100 | + <span class="des g-title">{{des}}</span> | ||
101 | + </a> | ||
102 | + </li> | ||
103 | + {{/ list}} | ||
104 | + </ul> | ||
105 | + </div> | ||
106 | + {{/ ads}} | ||
107 | +{{/ brands}} | ||
108 | +</div> | ||
109 | +{{> layout/footer}} |
apps/brands/views/partial/brand-list.hbs
0 → 100644
1 | +{{#each category}} | ||
2 | + <dl class="clearfix" name="{{key}}"> | ||
3 | + <dt>{{key}}</dt> | ||
4 | + <dd> | ||
5 | + <ul class="clearfix"> | ||
6 | + {{#each val}} | ||
7 | + <li> | ||
8 | + <a class="{{hot}}" data-key="{{key}}" href="{{href}}" target="_blank"> | ||
9 | + <span>{{name}}</span> | ||
10 | + </a> | ||
11 | + {{# hot}} | ||
12 | + <i class="iconfont"></i> | ||
13 | + {{/ hot}} | ||
14 | + </li> | ||
15 | + {{/each}} | ||
16 | + </ul> | ||
17 | + </dd> | ||
18 | + </dl> | ||
19 | +{{/each}} |
apps/cart/controllers/cart.js
0 → 100644
1 | +/** | ||
2 | + * Created by TaoHuang on 2016/10/19. | ||
3 | + */ | ||
4 | + | ||
5 | +'use strict'; | ||
6 | + | ||
7 | +const service = require('../models/cart-service'); | ||
8 | + | ||
9 | +const getProductInfo = (req, res, next) => { | ||
10 | + let pid = req.query.productId || ''; | ||
11 | + | ||
12 | + service.getProductInfoAsync(pid).then((result) => { | ||
13 | + return res.render('goods-detail', Object.assign({ | ||
14 | + layout: false | ||
15 | + }, result)); | ||
16 | + }).catch(next); | ||
17 | +}; | ||
18 | + | ||
19 | + | ||
20 | +module.exports = { | ||
21 | + getProductInfo | ||
22 | +}; |
apps/cart/index.js
0 → 100644
1 | +/** | ||
2 | + * sub app cart | ||
3 | + * @author: htoooth<ht.anglenx@gmail.com> | ||
4 | + * @date: 2016/10/19 | ||
5 | + */ | ||
6 | + | ||
7 | +'use strict'; | ||
8 | + | ||
9 | +var express = require('express'), | ||
10 | + path = require('path'), | ||
11 | + hbs = require('express-handlebars'); | ||
12 | + | ||
13 | +var app = express(); | ||
14 | + | ||
15 | +// set view engin | ||
16 | +var doraemon = path.join(__dirname, '../../doraemon/views'); //parent view root | ||
17 | + | ||
18 | +app.on('mount', function(parent) { | ||
19 | + delete parent.locals.settings; // 不继承父 App 的设置 | ||
20 | + Object.assign(app.locals, parent.locals); | ||
21 | +}); | ||
22 | + | ||
23 | +app.set('views', path.join(__dirname, 'views/action')); | ||
24 | +app.engine('.hbs', hbs({ | ||
25 | + extname: '.hbs', | ||
26 | + defaultLayout: 'layout', | ||
27 | + layoutsDir: doraemon, | ||
28 | + partialsDir: [path.join(__dirname, 'views/partial'), `${doraemon}/partial`], | ||
29 | + helpers: global.yoho.helpers | ||
30 | +})); | ||
31 | + | ||
32 | +// router | ||
33 | +app.use(require('./router')); | ||
34 | + | ||
35 | +module.exports = app; |
apps/cart/models/cart-service.js
0 → 100644
1 | +/** | ||
2 | + * 商品详情models | ||
3 | + * @author: xuqi<qi.xu@yoho.cn> | ||
4 | + * @date: 2016/5/6 | ||
5 | + */ | ||
6 | + | ||
7 | +'use strict'; | ||
8 | + | ||
9 | +const Promise = require('bluebird'); | ||
10 | +const co = Promise.coroutine; | ||
11 | +const _ = require('lodash'); | ||
12 | +const helpers = global.yoho.helpers; | ||
13 | + | ||
14 | +const productAPI = require('./product-api'); | ||
15 | + | ||
16 | +const _getProductIntroAsync = (productSkn) => { | ||
17 | + return co(function * () { | ||
18 | + let result = yield Promise.props({ | ||
19 | + sizeInfo: productAPI.sizeInfoAsync(productSkn) | ||
20 | + }); | ||
21 | + | ||
22 | + return result; | ||
23 | + })(); | ||
24 | +}; | ||
25 | + | ||
26 | +/** | ||
27 | + * 获得sku商品数据 | ||
28 | + */ | ||
29 | +const _getSkuDataByProductBaseInfo = (data) => { | ||
30 | + let totalStorageNum = 0; | ||
31 | + let skuGoods = null;// sku商品 | ||
32 | + let defaultImage = '';// 默认图 | ||
33 | + let chooseSkuFlag = false; // 选中状态 | ||
34 | + | ||
35 | + if (_.isEmpty(_.get(data, 'goods_list', []))) { | ||
36 | + return { | ||
37 | + totalStorageNum, | ||
38 | + skuGoods, | ||
39 | + defaultImage | ||
40 | + }; | ||
41 | + } | ||
42 | + | ||
43 | + skuGoods = _.get(data, 'goods_list', []).reduce((acc, cur, pos)=> { | ||
44 | + | ||
45 | + // 如果status为0,即skc下架时就跳过该商品$value['status'] === 0 | ||
46 | + let goodsGroup = {}; | ||
47 | + | ||
48 | + if (_.isEmpty(cur.color_image)) { | ||
49 | + return acc; | ||
50 | + } | ||
51 | + | ||
52 | + if (cur.images_list) { | ||
53 | + // 商品列表 | ||
54 | + goodsGroup.productSkc = cur.product_skc; | ||
55 | + goodsGroup.src = helpers.image(cur.color_image, 40, 40); | ||
56 | + goodsGroup.title = `${_.trim(data.product_name)} ${cur.color_name}`; | ||
57 | + goodsGroup.name = cur.color_name; | ||
58 | + goodsGroup.focus = false; | ||
59 | + goodsGroup.total = 0; | ||
60 | + goodsGroup.thumbs = []; | ||
61 | + goodsGroup.size = []; | ||
62 | + } | ||
63 | + | ||
64 | + _.get(cur, 'images_list', []).forEach((good) => { | ||
65 | + if (good.image_url) { | ||
66 | + goodsGroup.thumbs.push({ | ||
67 | + url: '', | ||
68 | + shower: helpers.image(good.image_url, 420, 560), | ||
69 | + img: helpers.image(good.image_url, 75, 100) | ||
70 | + }); | ||
71 | + } | ||
72 | + }); | ||
73 | + | ||
74 | + // 缩略图空,不显示 | ||
75 | + if (_.isEmpty(goodsGroup.thumbs)) { | ||
76 | + return acc; | ||
77 | + } | ||
78 | + | ||
79 | + // 默认第一张图片 | ||
80 | + if (pos === 0) { | ||
81 | + defaultImage = helpers.image(cur.color_image, 420, 560); | ||
82 | + } | ||
83 | + | ||
84 | + // 商品的尺码列表 | ||
85 | + _.get(cur, 'size_list', []).forEach((size) => { | ||
86 | + if (data.attribute === 3) { | ||
87 | + // 虚拟商品,门票默认最大为4, | ||
88 | + size.storage_number = size.storage_number > 4 ? 4 : size.storage_number; | ||
89 | + } | ||
90 | + | ||
91 | + // 如果status为0,即skc下架时就跳过该商品 | ||
92 | + if (cur.status === 0) { | ||
93 | + size.storage_number = 0; | ||
94 | + } | ||
95 | + | ||
96 | + goodsGroup.size.push({ | ||
97 | + name: size.size_name, | ||
98 | + sku: size.product_sku, | ||
99 | + num: _.parseInt(size.storage_number), | ||
100 | + goodsId: size.size_id | ||
101 | + }); | ||
102 | + | ||
103 | + // 单个sku商品的总数 | ||
104 | + goodsGroup.total += _.parseInt(size.storage_number); | ||
105 | + | ||
106 | + if (goodsGroup.total > 0 && !chooseSkuFlag) { // 默认选中该sku商品 | ||
107 | + goodsGroup.focus = true; | ||
108 | + chooseSkuFlag = true;// 选中sku商品 | ||
109 | + } | ||
110 | + | ||
111 | + totalStorageNum += _.parseInt(size.storage_number); | ||
112 | + | ||
113 | + }); | ||
114 | + | ||
115 | + acc.push(goodsGroup); | ||
116 | + return acc; | ||
117 | + }, []); | ||
118 | + | ||
119 | + if (!_.isEmpty(skuGoods) && !chooseSkuFlag) { // 没有选中一个sku商品,默认选中第一个sku商品 | ||
120 | + _.head(skuGoods).focus = true; | ||
121 | + } | ||
122 | + | ||
123 | + return { | ||
124 | + defaultImage: defaultImage, | ||
125 | + skuGoods: skuGoods, | ||
126 | + totalStorageNum: totalStorageNum | ||
127 | + }; | ||
128 | +}; | ||
129 | + | ||
130 | +/** | ||
131 | + * 使sizeBoList id以 sizeAttributeBos id顺序一样 | ||
132 | + * @param sizeInfoBo | ||
133 | + */ | ||
134 | +const _sizeInfoBoSort = (sizeInfoBo) => { | ||
135 | + if (!sizeInfoBo.sizeBoList || !sizeInfoBo.sizeAttributeBos) { | ||
136 | + return {}; | ||
137 | + } | ||
138 | + | ||
139 | + _.get(sizeInfoBo, 'sizeBoList', []).forEach((sizeBoList, sizek)=> { | ||
140 | + let sortAttr = {}; | ||
141 | + | ||
142 | + sizeBoList.sortAttributes.forEach(sortAttributes => { | ||
143 | + sortAttr[sortAttributes.id] = sortAttributes; | ||
144 | + }); | ||
145 | + | ||
146 | + sizeInfoBo.sizeBoList[sizek].sortAttributes = sortAttr; | ||
147 | + }); | ||
148 | + | ||
149 | + _.get(sizeInfoBo, 'sizeBoList', []).forEach((sizeBoList, sizek)=> { | ||
150 | + let sortAttr = []; | ||
151 | + | ||
152 | + sizeInfoBo.sizeAttributeBos.forEach(val => { | ||
153 | + if (sizeBoList.sortAttributes[val.id]) { | ||
154 | + sortAttr.push(sizeBoList.sortAttributes[val.id]); | ||
155 | + } | ||
156 | + }); | ||
157 | + | ||
158 | + sizeInfoBo.sizeBoList[sizek].sortAttributes = sortAttr; | ||
159 | + | ||
160 | + }); | ||
161 | + | ||
162 | + return sizeInfoBo; | ||
163 | +}; | ||
164 | + | ||
165 | +/** | ||
166 | + * 获取尺寸信息 | ||
167 | + * @param sizeInfo | ||
168 | + * @returns {{}} | ||
169 | + */ | ||
170 | +const _getSizeData = (sizeInfo) => { | ||
171 | + | ||
172 | + // 尺码信息 | ||
173 | + if (!_.has(sizeInfo, 'sizeInfoBo')) { | ||
174 | + return {}; | ||
175 | + } | ||
176 | + | ||
177 | + sizeInfo.sizeInfoBo = _sizeInfoBoSort(sizeInfo.sizeInfoBo); | ||
178 | + | ||
179 | + let boyReference = _.get(sizeInfo, 'productExtra.boyReference', false); | ||
180 | + let girlReference = _.get(sizeInfo, 'productExtra.girlReference', false); | ||
181 | + let gender = _.get(sizeInfo, 'productDescBo.gender', 3); | ||
182 | + let referenceName = (function() { | ||
183 | + if (gender === 3 && boyReference) { | ||
184 | + return '参考尺码(男)'; | ||
185 | + } else if (gender === 3 && girlReference) { | ||
186 | + return '参考尺码(女)'; | ||
187 | + } else { | ||
188 | + return '参考尺码'; | ||
189 | + } | ||
190 | + }()); | ||
191 | + | ||
192 | + // 判断是否显示参考尺码 | ||
193 | + let showReference = (boyReference && _.get(sizeInfo, 'sizeInfoBo.sizeBoList[0].boyReferSize', false)) || | ||
194 | + (girlReference && _.get(sizeInfo, 'sizeInfoBo.sizeBoList[0].girlReferSize', false)); | ||
195 | + | ||
196 | + if (!_.has(sizeInfo, 'sizeInfoBo.sizeAttributeBos')) { | ||
197 | + return {}; | ||
198 | + } | ||
199 | + | ||
200 | + // 尺码信息头部 | ||
201 | + let size = { | ||
202 | + thead: [{name: '吊牌尺码', id: ''}], | ||
203 | + tbody: [] | ||
204 | + }; | ||
205 | + | ||
206 | + // 显示参考尺码 | ||
207 | + if (showReference) { | ||
208 | + size.thead[1] = {name: referenceName, id: ''}; | ||
209 | + } | ||
210 | + | ||
211 | + _.get(sizeInfo, 'sizeInfoBo.sizeAttributeBos', []).forEach((value) => { | ||
212 | + size.thead.push({ | ||
213 | + name: value.attributeName || ' ', | ||
214 | + id: value.id | ||
215 | + }); | ||
216 | + }); | ||
217 | + | ||
218 | + _.get(sizeInfo, 'sizeInfoBo.sizeBoList', []).forEach((value) => { | ||
219 | + let sizes = []; | ||
220 | + | ||
221 | + // 吊牌尺码 | ||
222 | + sizes.push(value.sizeName); | ||
223 | + | ||
224 | + // 判断是否显示参考尺码 | ||
225 | + if (boyReference && (gender === 1 || gender === 3) && showReference) { | ||
226 | + sizes.push(_.get(value, 'boyReferSize.referenceName', ' ')); | ||
227 | + } else if (girlReference && (gender === 2 || gender === 3) && showReference) { | ||
228 | + sizes.push(_.get(value, 'girlReferSize.referenceName', ' ')); | ||
229 | + } else { | ||
230 | + if (size.thead[1] && showReference) { | ||
231 | + size.thead[1] = {}; | ||
232 | + } | ||
233 | + } | ||
234 | + | ||
235 | + // 其他尺码信息 | ||
236 | + _.get(value, 'sortAttributes', []).forEach(attr => { | ||
237 | + sizes.push(_.get(attr, 'sizeValue', ' ')); | ||
238 | + }); | ||
239 | + | ||
240 | + // 尺码信息 | ||
241 | + size.tbody.push(sizes); | ||
242 | + }); | ||
243 | + | ||
244 | + // 参考尺码为空 | ||
245 | + if (_.isEmpty(size.thead[1]) && showReference) { | ||
246 | + // 移除这个值 | ||
247 | + size.thead.splice(1, 1); | ||
248 | + } | ||
249 | + | ||
250 | + // 测量方式 | ||
251 | + if (sizeInfo.sizeImage) { | ||
252 | + size.sizeImg = sizeInfo.sizeImage; | ||
253 | + } | ||
254 | + | ||
255 | + return size; | ||
256 | +}; | ||
257 | + | ||
258 | +/** | ||
259 | + * 商品尺码信息 | ||
260 | + * | ||
261 | + * @param productSkn | ||
262 | + * @param maxSortId | ||
263 | + * @return object | ||
264 | + */ | ||
265 | +const _getIntroInfo = (productSkn, additionalData)=> { | ||
266 | + if (!productSkn) { | ||
267 | + return {}; | ||
268 | + } | ||
269 | + | ||
270 | + let sizeInfo = additionalData.sizeInfo; | ||
271 | + | ||
272 | + if (_.isEmpty(sizeInfo)) { | ||
273 | + return {}; | ||
274 | + } | ||
275 | + | ||
276 | + let result = {}; | ||
277 | + | ||
278 | + // 尺寸数据 | ||
279 | + result.size = _getSizeData(sizeInfo); | ||
280 | + | ||
281 | + return result; | ||
282 | +}; | ||
283 | + | ||
284 | +/** | ||
285 | + * 详情页数据格式化 | ||
286 | + * @param origin Object 原始数据 | ||
287 | + * @return result Object 格式化数据 | ||
288 | + */ | ||
289 | +const _detailDataPkg = (origin) => { | ||
290 | + return co(function*() { | ||
291 | + if (_.isEmpty(origin) || _.isEmpty(origin)) { | ||
292 | + return {}; | ||
293 | + } | ||
294 | + | ||
295 | + let result = {}; | ||
296 | + | ||
297 | + let propOrigin = _.partial(_.get, origin); | ||
298 | + | ||
299 | + // 商品名称 | ||
300 | + if (!propOrigin('product_name')) { | ||
301 | + return result; | ||
302 | + } | ||
303 | + | ||
304 | + result.name = propOrigin('product_name'); | ||
305 | + result.skn = propOrigin('product_skn'); | ||
306 | + result.productId = propOrigin('product_id'); | ||
307 | + | ||
308 | + // 商品价格 | ||
309 | + result.marketPrice = propOrigin('format_market_price'); | ||
310 | + result.salePrice = propOrigin('format_sales_price'); | ||
311 | + result.hasOtherPrice = true; | ||
312 | + | ||
313 | + if (result.salePrice === '0') { | ||
314 | + delete result.salePrice; | ||
315 | + result.hasOtherPrice = false; | ||
316 | + } | ||
317 | + | ||
318 | + // 上市期 | ||
319 | + if (propOrigin('expect_arrival_time')) { | ||
320 | + result.arrivalDate = `${propOrigin('expect_arrival_time')}月`; | ||
321 | + result.presalePrice = propOrigin('format_sales_price'); | ||
322 | + delete result.salePrice; | ||
323 | + result.hasOtherPrice = false; | ||
324 | + } | ||
325 | + | ||
326 | + // sku商品信息 | ||
327 | + let skuData = _getSkuDataByProductBaseInfo(origin); | ||
328 | + | ||
329 | + // 商品购买状态 | ||
330 | + let soldOut = !!(propOrigin('status') === 0 || skuData.totalStorageNum === 0); | ||
331 | + let notForSale = propOrigin('attribute') === 2; // 非卖品 | ||
332 | + let virtualGoods = propOrigin('attribute') === 3; // 虚拟商品 | ||
333 | + | ||
334 | + if (!soldOut && !notForSale && !virtualGoods) { | ||
335 | + result.addToCart = 1; | ||
336 | + } | ||
337 | + | ||
338 | + result.colors = skuData.skuGoods; | ||
339 | + | ||
340 | + return result; | ||
341 | + })(); | ||
342 | +}; | ||
343 | + | ||
344 | +/** | ||
345 | + * 获取某一个商品详情主页面 | ||
346 | + */ | ||
347 | +const getProductInfoAsync = (pid) => { | ||
348 | + return co(function * () { | ||
349 | + if (!pid) { | ||
350 | + return {}; | ||
351 | + } | ||
352 | + | ||
353 | + // 获取商品基本信息 | ||
354 | + let productData = yield productAPI.getProductAsync(pid); | ||
355 | + | ||
356 | + if (_.isEmpty(productData.data)) { | ||
357 | + return Promise.reject({ | ||
358 | + code: 404, | ||
359 | + message: 'app.product.data api wrong' | ||
360 | + }); | ||
361 | + } | ||
362 | + | ||
363 | + let productSkn = _.get(productData, 'data.product_skn'); | ||
364 | + | ||
365 | + let requestData = yield Promise.all([ | ||
366 | + _getProductIntroAsync(productSkn), // 商品详细介绍 | ||
367 | + _detailDataPkg(productData.data) // 商品详细价格 | ||
368 | + ]); | ||
369 | + | ||
370 | + let productDescription = requestData[0]; | ||
371 | + let productInfo = requestData[1]; | ||
372 | + | ||
373 | + let intro = _getIntroInfo(productSkn, productDescription); | ||
374 | + | ||
375 | + return Object.assign(productInfo, intro); | ||
376 | + })(); | ||
377 | +}; | ||
378 | + | ||
379 | +module.exports = { | ||
380 | + getProductInfoAsync // 获取某一个商品详情主页面 | ||
381 | +}; |
apps/cart/models/product-api.js
0 → 100644
1 | +/** | ||
2 | + * Created by TaoHuang on 2016/10/19. | ||
3 | + */ | ||
4 | + | ||
5 | +const api = global.yoho.API; | ||
6 | + | ||
7 | +const sizeInfoAsync = skn => { | ||
8 | + return api.get('', { | ||
9 | + method: 'h5.product.intro', | ||
10 | + productskn: skn | ||
11 | + }); | ||
12 | + | ||
13 | +}; | ||
14 | + | ||
15 | +/** | ||
16 | + * 获得产品信息 | ||
17 | + * @param pid | ||
18 | + * @returns {Promise.<type>} | ||
19 | + */ | ||
20 | +const getProductAsync = (pid) => { | ||
21 | + | ||
22 | + return api.get('', { | ||
23 | + method: 'app.product.data', | ||
24 | + product_id: pid | ||
25 | + }); | ||
26 | +}; | ||
27 | + | ||
28 | +module.exports = { | ||
29 | + sizeInfoAsync, | ||
30 | + getProductAsync | ||
31 | +}; |
apps/cart/router.js
0 → 100644
1 | +/** | ||
2 | + * router of sub app cart | ||
3 | + * @author: htoooth<ht.anglenx@gmail.com> | ||
4 | + * @date: 2016/10/19 | ||
5 | + */ | ||
6 | + | ||
7 | +'use strict'; | ||
8 | + | ||
9 | +const router = require('express').Router(); // eslint-disable-line | ||
10 | +const cRoot = './controllers'; | ||
11 | + | ||
12 | +const cart = require(`${cRoot}/cart`); | ||
13 | + | ||
14 | +router.get('/index/getProductInfo', cart.getProductInfo); | ||
15 | + | ||
16 | +// Your controller here | ||
17 | + | ||
18 | +module.exports = router; |
apps/cart/views/action/goods-detail.hbs
0 → 100644
1 | +<div class="detail-header"> | ||
2 | + <span class="colse">X关闭</span> | ||
3 | +</div> | ||
4 | +<div class="detail-body"> | ||
5 | + <span class="magnify"></span> | ||
6 | + {{#colors}} | ||
7 | + <div class="detail-bigpic {{#unless focus}}none{{/unless}}"> | ||
8 | + {{#thumbs}} | ||
9 | + <div class="bigpic"> | ||
10 | + <img src="{{shower}}"> | ||
11 | + </div> | ||
12 | + {{/thumbs}} | ||
13 | + <div class="piclist"> | ||
14 | + <span class="pre"></span> | ||
15 | + <div class="con"> | ||
16 | + <ul> | ||
17 | + {{#thumbs}} | ||
18 | + <li><img src="{{img}}"></li> | ||
19 | + {{/thumbs}} | ||
20 | + </ul> | ||
21 | + </div> | ||
22 | + <span class="next"></span> | ||
23 | + </div> | ||
24 | + </div> | ||
25 | + {{/colors}} | ||
26 | + <div class="detail-info"> | ||
27 | + <div class="title"> | ||
28 | + <h2>{{name}}</h2> | ||
29 | + </div> | ||
30 | + <div class="type"> | ||
31 | + <span class="type-s">新品</span> | ||
32 | + </div> | ||
33 | + <div class="price"> | ||
34 | + | ||
35 | + {{#if salePrice}} | ||
36 | + <span class="oldprice">原价:<del>¥{{marketPrice}}</del></span> | ||
37 | + <span class="newprice">现价:<b class="promotion-price">¥{{salePrice}}</b></span> | ||
38 | + {{^}} | ||
39 | + <span class="newprice {{#presalePrice}}none{{/presalePrice}}">原价:<b class="promotion-price">¥{{marketPrice}}</b></span> | ||
40 | + {{/if}} | ||
41 | + | ||
42 | + {{#if presalePrice}} | ||
43 | + <span class="oldprice">原价:<del>¥{{marketPrice}}</del></span> | ||
44 | + <span class="newprice">预售价:<b class="promotion-price">¥{{presalePrice}}</b></span> | ||
45 | + {{/if}} | ||
46 | + {{#arrivalDate}} | ||
47 | + <span class="arrivalDate">上市期:{{arrivalDate}}</span> | ||
48 | + {{/arrivalDate}} | ||
49 | + </div> | ||
50 | + <div class="order"> | ||
51 | + <dl> | ||
52 | + <dd class="colorBox">选颜色:</dd> | ||
53 | + <dt> | ||
54 | + <div class="colorBox"> | ||
55 | + <ul> | ||
56 | + {{#colors}} | ||
57 | + <li class="color"> | ||
58 | + <p class="{{#if focus}}atcive{{/if}}"><span></span><img src="{{src}}"></p> | ||
59 | + <span>{{name}}</span> | ||
60 | + </li> | ||
61 | + {{/colors}} | ||
62 | + </ul> | ||
63 | + </div> | ||
64 | + </dt> | ||
65 | + <dd class="">选尺码:</dd> | ||
66 | + <dt> | ||
67 | + {{#colors}} | ||
68 | + <div class="showSizeBox {{#unless focus}}none{{/unless}}"> | ||
69 | + {{#size}} | ||
70 | + <span data-sku="{{sku}}" data-num="{{num}}">{{name}}</span> | ||
71 | + {{/size}} | ||
72 | + </div> | ||
73 | + {{/colors}} | ||
74 | + </dt> | ||
75 | + <dd>选件数:</dd> | ||
76 | + <dt> | ||
77 | + <div class="amount_wrapper"> | ||
78 | + <i class="amount cut"></i> | ||
79 | + <input type="text" id="mnum" class="mnum" value="1" readonly="readonly"> | ||
80 | + <i class="amount add"></i> | ||
81 | + | ||
82 | + </div> | ||
83 | + </dt> | ||
84 | + </dl> | ||
85 | + </div> | ||
86 | + <div class="submit"> | ||
87 | + <input class="addcart" type="button"> | ||
88 | + <input class="btn_pre_sale none" type="button"> | ||
89 | + <input class="btn_sellout none" type="button"> | ||
90 | + <input class="fav_count" type="button"> | ||
91 | + </div> | ||
92 | + </div> | ||
93 | + | ||
94 | + <div class="detail-size"> | ||
95 | + <h3>尺码信息<span>(单位:厘米)</span></h3> | ||
96 | + {{# size}} | ||
97 | + <table> | ||
98 | + <thead> | ||
99 | + <tr> | ||
100 | + {{# thead}} | ||
101 | + <td width="{{width}}">{{name}}</td> | ||
102 | + {{/ thead}} | ||
103 | + </tr> | ||
104 | + </thead> | ||
105 | + <tbody> | ||
106 | + {{# tbody}} | ||
107 | + <tr> | ||
108 | + {{#each .}} | ||
109 | + <td>{{.}}</td> | ||
110 | + {{/each}} | ||
111 | + </tr> | ||
112 | + {{/ tbody}} | ||
113 | + </tbody> | ||
114 | + </table> | ||
115 | + {{/ size}} | ||
116 | + <div class="size-info"> | ||
117 | + ※ 以上尺寸为实物实际测量,因测量方式不同会有略微误差,相关数据仅作参考,以收到实物为准。 | ||
118 | + </div> | ||
119 | + </div> | ||
120 | +</div> | ||
121 | +<input value="{{addToCart}}" id="addToCart" type="hidden" /> |
apps/common/controllers/recent-view.js
0 → 100644
1 | +/** | ||
2 | + * 最近浏览controller | ||
3 | + * @author: xuqi<qi.xu@yoho.cn> | ||
4 | + * @date: 2016/10/11 | ||
5 | + */ | ||
6 | + | ||
7 | +'use strict'; | ||
8 | + | ||
9 | +const rvModel = require('../models/recent-view'); | ||
10 | +const _ = require('lodash'); | ||
11 | + | ||
12 | +const index = (req, res, next) => { | ||
13 | + | ||
14 | + let limit = req.query.limit; | ||
15 | + | ||
16 | + let browserSkn = decodeURIComponent(req.cookies._browseskn); | ||
17 | + | ||
18 | + // 拆解skn | ||
19 | + let skn = browserSkn ? browserSkn.replace(/\-(\d)+(\,){0,1}/g, ',') : ''; | ||
20 | + | ||
21 | + // 去除skn字符串的最后一个多余的, | ||
22 | + if (skn && skn.lastIndexOf(',') === skn.length - 1) { | ||
23 | + skn = skn.slice(0, -1); | ||
24 | + } | ||
25 | + | ||
26 | + if (!skn) { | ||
27 | + res.jsonp({ | ||
28 | + code: 200, | ||
29 | + data: [], | ||
30 | + message: 'User info' | ||
31 | + }); | ||
32 | + } else { | ||
33 | + skn = _.slice(_.uniq(skn.split(',')), 0, limit).join(','); // 去重+截取 | ||
34 | + rvModel.index(skn, limit).then(data => { | ||
35 | + res.jsonp(data); | ||
36 | + }).catch(next); | ||
37 | + } | ||
38 | + | ||
39 | +}; | ||
40 | + | ||
41 | +module.exports = { | ||
42 | + index | ||
43 | +}; |
apps/common/index.js
0 → 100644
1 | +/** | ||
2 | + * sub app common | ||
3 | + * @author: xuqi<qi.xu@yoho.cn> | ||
4 | + * @date: 2016/10/11 | ||
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; |
apps/common/models/recent-view.js
0 → 100644
1 | +/** | ||
2 | + * recent view model | ||
3 | + * @author: xuqi<qi.xu@yoho.cn> | ||
4 | + * @date: 2016/10/11 | ||
5 | + */ | ||
6 | + | ||
7 | +'use strict'; | ||
8 | + | ||
9 | +const _ = require('lodash'); | ||
10 | +const api = global.yoho.API; | ||
11 | +const helper = global.yoho.helpers; | ||
12 | + | ||
13 | +const index = (skn, limit) => { | ||
14 | + | ||
15 | + return api.get('', { | ||
16 | + method: 'h5.product.batch', | ||
17 | + productSkn: skn, | ||
18 | + limit: limit | ||
19 | + }).then(result => { | ||
20 | + | ||
21 | + if (result.code === 200) { | ||
22 | + let data = []; | ||
23 | + let historyProduct = result.data.product_list; | ||
24 | + | ||
25 | + _.forEach(historyProduct, hp => { | ||
26 | + if (!hp) { | ||
27 | + return; | ||
28 | + } | ||
29 | + | ||
30 | + let mp = hp.market_price; | ||
31 | + let sp = hp.sales_price; | ||
32 | + | ||
33 | + let defaultGoods = _.find(hp.goods_list, {is_default: 'Y'}); | ||
34 | + | ||
35 | + // 无默认商品取商品列表第一个 | ||
36 | + if (!defaultGoods) { | ||
37 | + defaultGoods = hp.goods_list[0]; | ||
38 | + } | ||
39 | + | ||
40 | + data.push({ | ||
41 | + market_price: mp === sp ? '' : `¥${helper.round(mp, 2)}`, | ||
42 | + price: `¥${helper.round(sp, 2)}`, | ||
43 | + product_name: hp.product_name, | ||
44 | + url: helper.urlFormat( | ||
45 | + `/product/pro_${hp.product_id}_${defaultGoods.goods_id}/${hp.cn_alphabet}.html`, '', 'item'), | ||
46 | + pic_url: helper.image(defaultGoods.images_url, 150, 200, 2, 70) | ||
47 | + }); | ||
48 | + }); | ||
49 | + | ||
50 | + return { | ||
51 | + code: 200, | ||
52 | + data: data, | ||
53 | + message: result.message | ||
54 | + }; | ||
55 | + } else { | ||
56 | + | ||
57 | + // get list error | ||
58 | + return { | ||
59 | + code: result.code, | ||
60 | + message: result.message, | ||
61 | + data: [] | ||
62 | + }; | ||
63 | + } | ||
64 | + }); | ||
65 | +}; | ||
66 | + | ||
67 | +module.exports = { | ||
68 | + index | ||
69 | +}; |
apps/common/router.js
0 → 100644
1 | +/** | ||
2 | + * router of sub app common | ||
3 | + * @author: xuqi<qi.xu@yoho.cn> | ||
4 | + * @date: 2016/10/11 | ||
5 | + */ | ||
6 | + | ||
7 | +'use strict'; | ||
8 | + | ||
9 | +const router = require('express').Router(); // eslint-disable-line | ||
10 | +const cRoot = './controllers'; | ||
11 | + | ||
12 | +const rvCtrl = require(`${cRoot}/recent-view`); | ||
13 | + | ||
14 | +router.get('/recentReview', rvCtrl.index); // 最近浏览 | ||
15 | + | ||
16 | +module.exports = router; |
@@ -15,6 +15,14 @@ const _ = require('lodash'); | @@ -15,6 +15,14 @@ const _ = require('lodash'); | ||
15 | * 找回密码主页面 | 15 | * 找回密码主页面 |
16 | */ | 16 | */ |
17 | const index = (req, res, next) => { | 17 | const index = (req, res, next) => { |
18 | + // 清除cookie | ||
19 | + res.clearCookie('_UID', { | ||
20 | + domain: 'yohobuy.com' | ||
21 | + }); | ||
22 | + res.clearCookie('_TOKEN', { | ||
23 | + domain: 'yohobuy.com' | ||
24 | + }); | ||
25 | + | ||
18 | service.indexPageDataAsync() | 26 | service.indexPageDataAsync() |
19 | .then(result => { | 27 | .then(result => { |
20 | res.render('back/index', Object.assign({ | 28 | res.render('back/index', Object.assign({ |
@@ -33,38 +33,33 @@ function doPassportCallback(req, res, user) { | @@ -33,38 +33,33 @@ function doPassportCallback(req, res, user) { | ||
33 | refer = config.siteUrl; | 33 | refer = config.siteUrl; |
34 | } | 34 | } |
35 | if (user.openId) { | 35 | if (user.openId) { |
36 | - let signinByOpenID; | ||
37 | - | ||
38 | user.nickname = _.trim(user.nickname); | 36 | user.nickname = _.trim(user.nickname); |
39 | 37 | ||
40 | if (user.sourceType === 'wechat') { | 38 | if (user.sourceType === 'wechat') { |
41 | - | ||
42 | - // PC 的微信登录之前使用了 open_id, 所以需要特别的接口处理 | ||
43 | - signinByOpenID = AuthHelper.signinByWechat( | ||
44 | - user.nickname, user.openId, user.unionId, user.sourceType, shoppingKey); | ||
45 | - } else { | ||
46 | - signinByOpenID = AuthHelper.signinByOpenID( | ||
47 | - user.nickname, user.openId, user.sourceType, shoppingKey); | 39 | + // PC 的微信登录使用unionId |
40 | + user.openId = user.unionId; | ||
48 | } | 41 | } |
49 | 42 | ||
50 | - return signinByOpenID.then((result) => { | ||
51 | - if (result.code !== 200) { | ||
52 | - return Promise.reject(result); | ||
53 | - } | ||
54 | - if (result.data['is_bind'] && result.data['is_bind'] === 'N') { //eslint-disable-line | ||
55 | - return helpers.urlFormat('/passport/thirdlogin/index', { | ||
56 | - openId: user.unionId || user.openId, | ||
57 | - sourceType: user.sourceType, | ||
58 | - refer: refer | ||
59 | - }); | ||
60 | - } else if (result.code === 200 && result.data.uid) { | ||
61 | - return AuthHelper.syncUserSession(result.data.uid, req, res).then(() => { | ||
62 | - return refer; | ||
63 | - }); | ||
64 | - } | ||
65 | - }).then((redirectTo) => { | ||
66 | - return res.redirect(redirectTo); | ||
67 | - }); | 43 | + return AuthHelper.signinByOpenID(user.nickname, user.openId, user.sourceType, shoppingKey) |
44 | + .then((result) => { | ||
45 | + if (result.code !== 200) { | ||
46 | + return res.redirect(config.siteUrl); | ||
47 | + } | ||
48 | + if (result.data['is_bind'] && result.data['is_bind'] === 'N') { //eslint-disable-line | ||
49 | + return helpers.urlFormat('/passport/thirdlogin/index', { | ||
50 | + openId: user.unionId || user.openId, | ||
51 | + sourceType: user.sourceType, | ||
52 | + refer: refer | ||
53 | + }); | ||
54 | + } else if (result.code === 200 && result.data.uid) { | ||
55 | + return AuthHelper.syncUserSession(result.data.uid, req, res).then(() => { | ||
56 | + return refer; | ||
57 | + }); | ||
58 | + } | ||
59 | + }) | ||
60 | + .then((redirectTo) => { | ||
61 | + return res.redirect(redirectTo); | ||
62 | + }); | ||
68 | } else { | 63 | } else { |
69 | return Promise.resolve(res.redirect(loginPage)); | 64 | return Promise.resolve(res.redirect(loginPage)); |
70 | } | 65 | } |
@@ -75,7 +70,7 @@ const common = { | @@ -75,7 +70,7 @@ const common = { | ||
75 | let refer = req.query.refer || req.get('Referer'); | 70 | let refer = req.query.refer || req.get('Referer'); |
76 | 71 | ||
77 | refer && res.cookie('refer', encodeURI(refer), { | 72 | refer && res.cookie('refer', encodeURI(refer), { |
78 | - domain: 'yohobuy.com' | 73 | + domain: '.yohobuy.com' |
79 | }); | 74 | }); |
80 | next(); | 75 | next(); |
81 | }, | 76 | }, |
@@ -122,11 +117,7 @@ const local = { | @@ -122,11 +117,7 @@ const local = { | ||
122 | areaName = area ? area.name : ''; | 117 | areaName = area ? area.name : ''; |
123 | } | 118 | } |
124 | 119 | ||
125 | - let refer = req.query.refer; | ||
126 | - | ||
127 | - refer && res.cookie('refer', encodeURI(refer), { | ||
128 | - domain: 'yohobuy.com' | ||
129 | - }); | 120 | + let refer = req.query.refer || req.cookies.refer || req.get('Referer'); |
130 | 121 | ||
131 | PassportHelper.getLeftBannerAsync(SIGNIN_LEFT_BANNER_CODE).then(cover => { | 122 | PassportHelper.getLeftBannerAsync(SIGNIN_LEFT_BANNER_CODE).then(cover => { |
132 | res.render('login', { | 123 | res.render('login', { |
@@ -176,13 +167,13 @@ const local = { | @@ -176,13 +167,13 @@ const local = { | ||
176 | let refer = (function() { | 167 | let refer = (function() { |
177 | if (/sign|login|reg|passport/.test(_.get(req, 'cookies.refer', ''))) { | 168 | if (/sign|login|reg|passport/.test(_.get(req, 'cookies.refer', ''))) { |
178 | return `${config.siteUrl}/home`; | 169 | return `${config.siteUrl}/home`; |
179 | - } else if (_.has(req, 'cookies.refer')) { | 170 | + } else if (_.get(req, 'cookies.refer')) { |
180 | return decodeURI(req.cookies.refer); | 171 | return decodeURI(req.cookies.refer); |
181 | } else { | 172 | } else { |
182 | return `${config.siteUrl}/home`; | 173 | return `${config.siteUrl}/home`; |
183 | } | 174 | } |
184 | }()); | 175 | }()); |
185 | - | 176 | + console.log(user.uid); |
186 | AuthHelper.syncUserSession(user.uid, req, res).then(() => { | 177 | AuthHelper.syncUserSession(user.uid, req, res).then(() => { |
187 | res.json({ | 178 | res.json({ |
188 | code: 200, | 179 | code: 200, |
@@ -6,6 +6,11 @@ const aes = require('./aes-pwd'); | @@ -6,6 +6,11 @@ const aes = require('./aes-pwd'); | ||
6 | const cache = global.yoho.cache; | 6 | const cache = global.yoho.cache; |
7 | const sign = global.yoho.sign; | 7 | const sign = global.yoho.sign; |
8 | const api = global.yoho.API; | 8 | const api = global.yoho.API; |
9 | +const cookie = global.yoho.cookie; | ||
10 | + | ||
11 | +const Promise = require('bluebird'); | ||
12 | + | ||
13 | +const cartService = require('./cart-service'); | ||
9 | 14 | ||
10 | const Auth = { | 15 | const Auth = { |
11 | signin(type, area, profile, password, shoppingKey) { | 16 | signin(type, area, profile, password, shoppingKey) { |
@@ -137,12 +142,11 @@ const Auth = { | @@ -137,12 +142,11 @@ const Auth = { | ||
137 | return api.get('', param); | 142 | return api.get('', param); |
138 | }, | 143 | }, |
139 | syncUserSession(uid, req, res) { | 144 | syncUserSession(uid, req, res) { |
140 | - return Auth.profile(uid).then((userInfo) => { | 145 | + return Promise.all([Auth.profile(uid), cartService.goodsCount(uid)]).spread((userInfo, count) => { |
141 | let token = sign.makeToken(uid); | 146 | let token = sign.makeToken(uid); |
142 | let data = userInfo.data; | 147 | let data = userInfo.data; |
143 | let encryptionUid = aes.encryptionUid(data.uid); | 148 | let encryptionUid = aes.encryptionUid(data.uid); |
144 | 149 | ||
145 | - | ||
146 | if (data) { | 150 | if (data) { |
147 | let uidCookie = `${data.profile_name}::${encryptionUid}::${data.vip_info.title}::${token}`; | 151 | let uidCookie = `${data.profile_name}::${encryptionUid}::${data.vip_info.title}::${token}`; |
148 | let isStudent = data.vip_info.is_student || 0; | 152 | let isStudent = data.vip_info.is_student || 0; |
@@ -156,6 +160,16 @@ const Auth = { | @@ -156,6 +160,16 @@ const Auth = { | ||
156 | res.cookie('isStudent', isStudent, { | 160 | res.cookie('isStudent', isStudent, { |
157 | domain: 'yohobuy.com' | 161 | domain: 'yohobuy.com' |
158 | }); | 162 | }); |
163 | + | ||
164 | + // 购物车中商品的数量 | ||
165 | + res.cookie('_g', JSON.stringify({ | ||
166 | + _k: cookie.getShoppingKey(req), | ||
167 | + _nac: count, | ||
168 | + _ac: 0, | ||
169 | + _c: 1 | ||
170 | + }), { | ||
171 | + domain: 'yohobuy.com' | ||
172 | + }); | ||
159 | } | 173 | } |
160 | req.session._TOKEN = token; // esline-disable-line | 174 | req.session._TOKEN = token; // esline-disable-line |
161 | req.session._LOGIN_UID = uid; // esline-disable-line | 175 | req.session._LOGIN_UID = uid; // esline-disable-line |
apps/passport/models/cart-api.js
0 → 100644
1 | +/** | ||
2 | + * Created by TaoHuang on 2016/9/28. | ||
3 | + */ | ||
4 | + | ||
5 | +'use strict'; | ||
6 | + | ||
7 | +const api = global.yoho.API; | ||
8 | + | ||
9 | +const goodsCount = (uid, shoppingKey) => { | ||
10 | + let params = { | ||
11 | + method: 'app.Shopping.count' | ||
12 | + }; | ||
13 | + | ||
14 | + if (uid) { | ||
15 | + params.uid = uid; | ||
16 | + } | ||
17 | + | ||
18 | + if (shoppingKey) { | ||
19 | + params.shopping_key = shoppingKey; | ||
20 | + } | ||
21 | + | ||
22 | + return api.get('', params); | ||
23 | +}; | ||
24 | + | ||
25 | +module.exports = { | ||
26 | + goodsCount | ||
27 | +}; |
apps/passport/models/cart-service.js
0 → 100644
1 | +/** | ||
2 | + * Created by TaoHuang on 2016/9/28. | ||
3 | + */ | ||
4 | + | ||
5 | +'use strict'; | ||
6 | + | ||
7 | + | ||
8 | +const api = require('./cart-api'); | ||
9 | + | ||
10 | +const _ = require('lodash'); | ||
11 | + | ||
12 | +const goodsCount = (uid, shoppingKey) => { | ||
13 | + return api.goodsCount(uid, shoppingKey).then(result => _.get(result, 'data.cart_goods_count', 0)); | ||
14 | +}; | ||
15 | + | ||
16 | +module.exports = { | ||
17 | + goodsCount | ||
18 | +}; | ||
19 | + |
@@ -11,189 +11,230 @@ const mRoot = '../models'; | @@ -11,189 +11,230 @@ const mRoot = '../models'; | ||
11 | const service = require(`${mRoot}/detail-service`); | 11 | const service = require(`${mRoot}/detail-service`); |
12 | const detailHelper = require(`${mRoot}/detail-helper`); | 12 | const detailHelper = require(`${mRoot}/detail-helper`); |
13 | 13 | ||
14 | -const Actions = require('./lib/actions'); | ||
15 | -const YohoAction = require('./lib/yoho-action'); | ||
16 | const moment = require('moment'); | 14 | const moment = require('moment'); |
17 | const DEFAULT_AVATAR_ICO = 'http://static.yohobuy.com/images/v3/boy.jpg'; | 15 | const DEFAULT_AVATAR_ICO = 'http://static.yohobuy.com/images/v3/boy.jpg'; |
16 | +const SEO_SLOGAN = 'YOHO!BUY 有货'; | ||
18 | const _ = require('lodash'); | 17 | const _ = require('lodash'); |
19 | 18 | ||
20 | -class DetailAction extends YohoAction { | ||
21 | - /** | ||
22 | - * 渲染商品详情 | ||
23 | - */ | ||
24 | - render() { | ||
25 | - const req = this.request; | ||
26 | - | ||
27 | - let pid = req.params[0]; | ||
28 | - let gid = req.params[1]; | ||
29 | - let saveCurrentGoodsInCookies = _.partial(service.saveRecentGoodInCookies, | ||
30 | - req.cookies._browse, | ||
31 | - req.cookies._browseskn, | ||
32 | - this.response | ||
33 | - ); | ||
34 | - let vipLevel = detailHelper.vipLevel(req.user.vip); | ||
35 | - let uid = req.user.uid || 0; | ||
36 | - let isStudent = req.user.isStudent || 0; | ||
37 | - | ||
38 | - return service.showMainAsync({ | ||
39 | - pid: pid, | ||
40 | - gid: gid, | ||
41 | - channel: this.getSessionChannel(), | ||
42 | - gender: this.guessUserGender(), | ||
43 | - uid: uid, | ||
44 | - isStudent: isStudent, | ||
45 | - vipLevel: vipLevel, | ||
46 | - saveInCookies: saveCurrentGoodsInCookies | ||
47 | - }).then(result=> { | ||
48 | - const seo = result.seo; | ||
49 | - | ||
50 | - this.setTitle(seo.title, true, '|'); | ||
51 | - this.setKeywords(seo.keywords); | ||
52 | - this.setDescription(seo.description, true); | ||
53 | - | ||
54 | - this.setEntry('product', 'detail'); | ||
55 | - this.renderTemplate('product/detail', result); | ||
56 | - }).catch(err => { | ||
57 | - if (err.code === 404) { | ||
58 | - return this.next(); | ||
59 | - } | 19 | +const CHANNEL = { |
20 | + boys: 'boys', | ||
21 | + girls: 'girls', | ||
22 | + kids: 'kids' | ||
23 | +}; | ||
60 | 24 | ||
61 | - return this.next(err); | 25 | +const _getChannel = (req, res) => { |
26 | + let channel = req.cookies._Channel; | ||
27 | + | ||
28 | + if (!channel) { | ||
29 | + res.cookie('_Channel', CHANNEL.boys, { | ||
30 | + domain: '.yohobuy.com', | ||
31 | + maxAge: moment.duration(300, 'days').seconds() | ||
62 | }); | 32 | }); |
33 | + | ||
34 | + channel = 'boys'; // 设置默认值 | ||
35 | + } | ||
36 | + | ||
37 | + return channel; | ||
38 | +}; | ||
39 | + | ||
40 | +const _getGender = (channel) => { | ||
41 | + switch (channel) { | ||
42 | + case 'boys': | ||
43 | + return '1,3'; | ||
44 | + case 'girls': | ||
45 | + return '2,3'; | ||
46 | + default: | ||
47 | + return '1,2,3'; | ||
48 | + } | ||
49 | +}; | ||
50 | + | ||
51 | +/** | ||
52 | + * 首屏渲染商品详情 | ||
53 | + */ | ||
54 | +const showMain = (req, res, next) => { | ||
55 | + let pid = req.params[0]; | ||
56 | + let channel = _getChannel(req, res); | ||
57 | + let gender = _getGender(channel); | ||
58 | + | ||
59 | + const nullUserInfo = { | ||
60 | + uid: null, | ||
61 | + isStudent: null, | ||
62 | + vipLevel: null, | ||
63 | + saveInCookies: null | ||
64 | + }; | ||
65 | + | ||
66 | + return service.showMainAsync(Object.assign({ | ||
67 | + pid: pid, | ||
68 | + channel: channel, | ||
69 | + gender: gender | ||
70 | + }, nullUserInfo)).then((result)=> { | ||
71 | + return res.render('product/detail', Object.assign({ | ||
72 | + module: 'product', | ||
73 | + page: 'detail', | ||
74 | + title_more: true, | ||
75 | + title: _.get(result, 'seo.title', '') + ' | ' + SEO_SLOGAN, | ||
76 | + keywords: _.get(result, 'seo.keywords', '').replace(/~+/, ''), | ||
77 | + description_more: true, | ||
78 | + description: result.description | ||
79 | + }, result)); | ||
80 | + }).catch(next); | ||
81 | + | ||
82 | +}; | ||
83 | + | ||
84 | +/** | ||
85 | + * 商品价格相关的数据 | ||
86 | + */ | ||
87 | +const detailHeader = (req, res, next) => { | ||
88 | + let pid = req.query.productId || 0; | ||
89 | + let uid = req.user.uid || 0; | ||
90 | + let vipLevel = detailHelper.vipLevel(req.user.vip); | ||
91 | + let dataMd5 = req.query.md5 || 0; | ||
92 | + | ||
93 | + let saveCurrentGoodsInCookies = _.partial(service.saveRecentGoodInCookies, | ||
94 | + req.cookies._browseskn, | ||
95 | + res | ||
96 | + ); | ||
97 | + | ||
98 | + return service.getDetailHeader(pid, uid, req.user.isStudent, vipLevel, dataMd5, saveCurrentGoodsInCookies) | ||
99 | + .then((result) => { | ||
100 | + if (result.code === 200) { | ||
101 | + return res.render('product/detail-header', Object.assign({layout: false}, result.data)); | ||
102 | + } else { | ||
103 | + return res.status(204).end(); | ||
104 | + } | ||
105 | + }).catch(next); | ||
106 | +}; | ||
107 | + | ||
108 | +/** | ||
109 | + * 特殊商品退换货 | ||
110 | + */ | ||
111 | +const detailReturn = (req, res, next) => { | ||
112 | + let skn = req.query.skn || 0; | ||
113 | + | ||
114 | + if (!skn) { | ||
115 | + return { | ||
116 | + code: 400, | ||
117 | + message: '商品数据出错' | ||
118 | + }; | ||
63 | } | 119 | } |
64 | -} | 120 | + |
121 | + return service.saleReturn(skn).then(result => { | ||
122 | + return res.json({ | ||
123 | + code: 200, | ||
124 | + data: { | ||
125 | + result: result | ||
126 | + } | ||
127 | + }); | ||
128 | + }).catch(next); | ||
129 | +}; | ||
65 | 130 | ||
66 | /** | 131 | /** |
67 | * 获取热区图 | 132 | * 获取热区图 |
68 | */ | 133 | */ |
69 | -class HotAreaAction extends YohoAction { | ||
70 | - render() { | ||
71 | - let pid = this.request.query.productId || 0; | ||
72 | - | ||
73 | - return service.indexHotAreaAsync(pid).then(result => { | ||
74 | - this.renderTemplate('product/hotarea', { | ||
75 | - hotArea: result, | ||
76 | - layout: false | ||
77 | - }); | 134 | +const indexHotArea = (req, res, next) => { |
135 | + let pid = req.query.productId || 0; | ||
136 | + | ||
137 | + return service.indexHotAreaAsync(pid).then((result) => { | ||
138 | + res.render('product/hotarea', { | ||
139 | + hotArea: result, | ||
140 | + layout: false | ||
78 | }); | 141 | }); |
79 | - } | ||
80 | -} | 142 | + }).catch(next); |
143 | +}; | ||
81 | 144 | ||
82 | /** | 145 | /** |
83 | * 获得评论列表 | 146 | * 获得评论列表 |
84 | */ | 147 | */ |
85 | -class CommentAction extends YohoAction { | ||
86 | - render() { | ||
87 | - const req = this.request; | ||
88 | - let pid = req.query.productId || 0; | ||
89 | - let page = req.query.page || 1; | ||
90 | - let size = req.query.size || 10; | ||
91 | - | ||
92 | - return service.getShareOrderListAsync(pid, page, size).then((result) => { | ||
93 | - let pageResponse = _.get(result, 'data.pageResponse', {}); | ||
94 | - | ||
95 | - this.response.json({ | ||
96 | - code: result.code, | ||
97 | - data: _.get(pageResponse, 'list', []).map((item)=> { | ||
98 | - | ||
99 | - return { | ||
100 | - avatar: _.get(item, 'userInfo.headIco', '') ? | ||
101 | - helpers.image(item.userInfo.headIco, 30, 30) : | ||
102 | - DEFAULT_AVATAR_ICO, | ||
103 | - userName: _.get(item, 'userInfo.nickName', ''), | ||
104 | - date: moment(item.createTime, 'X').format('YYYY-MM-DD HH:mm:ss'), | ||
105 | - color: _.get(item, 'goods.color_name', ''), | ||
106 | - size: _.get(item, 'goods.size_name', ''), | ||
107 | - comment: item.content, | ||
108 | - total: pageResponse.totalCount | ||
109 | - }; | ||
110 | - }) | ||
111 | - }); | 148 | + |
149 | +const indexComment = (req, res, next) => { | ||
150 | + let pid = req.query.productId || 0; | ||
151 | + let page = req.query.page || 1; | ||
152 | + let size = req.query.size || 10; | ||
153 | + | ||
154 | + return service.getShareOrderListAsync(pid, page, size).then((result) => { | ||
155 | + let pageResponse = _.get(result, 'data.pageResponse', {}); | ||
156 | + | ||
157 | + return res.json({ | ||
158 | + code: result.code, | ||
159 | + data: _.get(pageResponse, 'list', []).map((item)=> { | ||
160 | + | ||
161 | + return { | ||
162 | + avatar: _.get(item, 'userInfo.headIco', '') ? | ||
163 | + helpers.image(item.userInfo.headIco, 30, 30) : | ||
164 | + DEFAULT_AVATAR_ICO, | ||
165 | + userName: _.get(item, 'userInfo.nickName', ''), | ||
166 | + date: moment(item.createTime, 'X').format('YYYY-MM-DD HH:mm:ss'), | ||
167 | + color: _.get(item, 'goods.color_name', ''), | ||
168 | + size: _.get(item, 'goods.size_name', ''), | ||
169 | + comment: item.content, | ||
170 | + total: pageResponse.totalCount | ||
171 | + }; | ||
172 | + }) | ||
112 | }); | 173 | }); |
113 | - } | ||
114 | -} | 174 | + }).catch(next); |
175 | +}; | ||
115 | 176 | ||
116 | /** | 177 | /** |
117 | * 获得咨询列表 | 178 | * 获得咨询列表 |
118 | */ | 179 | */ |
119 | -class ConsultAction extends YohoAction { | ||
120 | - render() { | ||
121 | - const req = this.request; | ||
122 | - let uid = req.user.uid || ''; | ||
123 | - let pid = req.query.productId || 0; | ||
124 | - let page = req.query.page || 1; | ||
125 | - let size = req.query.size || 10; | ||
126 | - | ||
127 | - return service.indexConsultAsync(uid, pid, page, size).then(result => { | ||
128 | - this.response.json({ | ||
129 | - code: 200, | ||
130 | - data: result | ||
131 | - }); | 180 | +const indexConsult = (req, res, next) => { |
181 | + let uid = req.user.uid || ''; | ||
182 | + let pid = req.query.productId || 0; | ||
183 | + let page = req.query.page || 1; | ||
184 | + let size = req.query.size || 10; | ||
185 | + | ||
186 | + return service.indexConsultAsync(uid, pid, page, size).then(result => { | ||
187 | + return res.json({ | ||
188 | + code: 200, | ||
189 | + data: result | ||
132 | }); | 190 | }); |
133 | - } | ||
134 | -} | 191 | + }).catch(next); |
192 | +}; | ||
135 | 193 | ||
136 | /** | 194 | /** |
137 | * 新建咨询 | 195 | * 新建咨询 |
138 | */ | 196 | */ |
139 | -class CreateConsultAction extends YohoAction { | ||
140 | - render() { | ||
141 | - const req = this.request, res = this.response; | ||
142 | - let uid = req.user.uid || ''; | ||
143 | - let pid = req.body.productId || 0; | ||
144 | - let content = req.body.content; | ||
145 | - | ||
146 | - if (content && uid) { | ||
147 | - return service.createConsultAsync(uid, pid, content).then(result => { | ||
148 | - res.json(result); | ||
149 | - }); | ||
150 | - } else if (!content) { | ||
151 | - res.json({ | ||
152 | - code: 400, | ||
153 | - message: '请输入咨询内容' | ||
154 | - }); | ||
155 | - | ||
156 | - } else if (!uid) { | ||
157 | - res.json({ | ||
158 | - code: 403, | ||
159 | - message: '用户没有登录', | ||
160 | - data: { | ||
161 | - url: helpers.urlFormat('/signin.html') | ||
162 | - } | ||
163 | - }); | ||
164 | - | ||
165 | - } else { | ||
166 | - res.json({ | ||
167 | - code: 400, | ||
168 | - message: '请输入咨询内容' | ||
169 | - }); | ||
170 | - } | ||
171 | - } | ||
172 | -} | 197 | +const createConsult = (req, res, next) => { |
198 | + let uid = req.user.uid || ''; | ||
199 | + let pid = req.body.productId || 0; | ||
200 | + let content = req.body.content; | ||
201 | + | ||
202 | + if (content && uid) { | ||
203 | + return service.createConsultAsync(uid, pid, content).then(result => { | ||
204 | + res.json(result); | ||
205 | + }).catch(next); | ||
206 | + } else if (!content) { | ||
207 | + res.json({ | ||
208 | + code: 400, | ||
209 | + message: '请输入咨询内容' | ||
210 | + }); | ||
173 | 211 | ||
174 | -const detailHeader = (req, res, next) => { | ||
175 | - let pid = req.query.productId || 0; | ||
176 | - let uid = req.user.uid || 0; | ||
177 | - let vipLevel = detailHelper.vipLevel(req.user.vip); | ||
178 | - let dataMd5 = req.query.md5 || 0; | 212 | + } else if (!uid) { |
213 | + res.json({ | ||
214 | + code: 403, | ||
215 | + message: '用户没有登录', | ||
216 | + data: { | ||
217 | + url: helpers.urlFormat('/signin.html') | ||
218 | + } | ||
219 | + }); | ||
179 | 220 | ||
180 | - service.getDetailHeader(pid, uid, req.user.isStudent, vipLevel, dataMd5).then((result) => { | ||
181 | - if (result.code === 200) { | ||
182 | - return res.render('product/detail-header', Object.assign({layout: false}, result.data)); | ||
183 | - } else { | ||
184 | - return res.status(204).end(); | ||
185 | - } | ||
186 | - }).catch(next); | 221 | + } else { |
222 | + res.json({ | ||
223 | + code: 400, | ||
224 | + message: '请输入咨询内容' | ||
225 | + }); | ||
226 | + } | ||
187 | }; | 227 | }; |
188 | 228 | ||
189 | -module.exports = { | ||
190 | - showMain: Actions.createAction(DetailAction), | ||
191 | - indexHotArea: Actions.createAction(HotAreaAction), | ||
192 | - indexComment: Actions.createAction(CommentAction), | ||
193 | - indexConsult: Actions.createAction(ConsultAction), | ||
194 | - createConsult: Actions.createAction(CreateConsultAction), | ||
195 | - productHeader: detailHeader | ||
196 | 229 | ||
230 | +module.exports = { | ||
231 | + showMain, | ||
232 | + indexHotArea, | ||
233 | + indexComment, | ||
234 | + indexConsult, | ||
235 | + createConsult, | ||
236 | + productHeader: detailHeader, | ||
237 | + detailReturn | ||
197 | }; | 238 | }; |
198 | 239 | ||
199 | 240 |
@@ -17,10 +17,10 @@ const changeFavoriteBrand = (req, res, next) => { | @@ -17,10 +17,10 @@ const changeFavoriteBrand = (req, res, next) => { | ||
17 | 17 | ||
18 | if (uid && brandId) { | 18 | if (uid && brandId) { |
19 | brandService.changeAsync(uid, brandId).then(result => { | 19 | brandService.changeAsync(uid, brandId).then(result => { |
20 | - res.json(result); | 20 | + return res.json(result); |
21 | }).catch(next); | 21 | }).catch(next); |
22 | } else if (!uid) { | 22 | } else if (!uid) { |
23 | - res.json({ | 23 | + return res.json({ |
24 | code: 403, | 24 | code: 403, |
25 | message: '用户ID不存在', | 25 | message: '用户ID不存在', |
26 | data: { | 26 | data: { |
@@ -28,13 +28,29 @@ const changeFavoriteBrand = (req, res, next) => { | @@ -28,13 +28,29 @@ const changeFavoriteBrand = (req, res, next) => { | ||
28 | } | 28 | } |
29 | }); | 29 | }); |
30 | } else { | 30 | } else { |
31 | - res.json({ | 31 | + return res.json({ |
32 | code: 400, | 32 | code: 400, |
33 | message: '操作失败' | 33 | message: '操作失败' |
34 | }); | 34 | }); |
35 | } | 35 | } |
36 | }; | 36 | }; |
37 | 37 | ||
38 | +const isFavoriteBrand = (req, res, next) => { | ||
39 | + let uid = req.user.uid || ''; | ||
40 | + let brandId = req.query.brandId; | ||
41 | + | ||
42 | + if (uid && brandId) { | ||
43 | + brandService.isFavoriteAsync(uid, brandId).then(result => { | ||
44 | + return res.json(result); | ||
45 | + }).catch(next); | ||
46 | + } else { | ||
47 | + return res.json({ | ||
48 | + code: 400, | ||
49 | + message: '状态失败' | ||
50 | + }); | ||
51 | + } | ||
52 | +}; | ||
53 | + | ||
38 | const collectProduct = (req, res, next) => { | 54 | const collectProduct = (req, res, next) => { |
39 | let uid = req.user.uid || ''; | 55 | let uid = req.user.uid || ''; |
40 | let pid = req.body.productId; | 56 | let pid = req.body.productId; |
@@ -43,8 +59,7 @@ const collectProduct = (req, res, next) => { | @@ -43,8 +59,7 @@ const collectProduct = (req, res, next) => { | ||
43 | if (uid && pid) { | 59 | if (uid && pid) { |
44 | switch (type) { | 60 | switch (type) { |
45 | case 'add': | 61 | case 'add': |
46 | - { | ||
47 | - productService.createAsync(uid, pid) | 62 | + productService.createAsync(uid, pid) |
48 | .then(result => { | 63 | .then(result => { |
49 | if (result.code === 413) { | 64 | if (result.code === 413) { |
50 | result.message = '该商品已经收藏'; | 65 | result.message = '该商品已经收藏'; |
@@ -53,22 +68,17 @@ const collectProduct = (req, res, next) => { | @@ -53,22 +68,17 @@ const collectProduct = (req, res, next) => { | ||
53 | res.json(result); | 68 | res.json(result); |
54 | }) | 69 | }) |
55 | .catch(next); | 70 | .catch(next); |
56 | - break; | ||
57 | - } | 71 | + break; |
58 | case 'cancel': | 72 | case 'cancel': |
59 | - { | ||
60 | - productService.deleteAsync(uid, pid) | 73 | + productService.deleteAsync(uid, pid) |
61 | .then(result => res.json(result)) | 74 | .then(result => res.json(result)) |
62 | .catch(next); | 75 | .catch(next); |
63 | - break; | ||
64 | - } | 76 | + break; |
65 | default: | 77 | default: |
66 | - { | ||
67 | - res.json({ | ||
68 | - code: 400, | ||
69 | - message: '错误类型' | ||
70 | - }); | ||
71 | - } | 78 | + res.json({ |
79 | + code: 400, | ||
80 | + message: '错误类型' | ||
81 | + }); | ||
72 | } | 82 | } |
73 | } else if (!uid) { | 83 | } else if (!uid) { |
74 | res.json({ | 84 | res.json({ |
@@ -117,5 +127,6 @@ const collectShop = (req, res, next) => { | @@ -117,5 +127,6 @@ const collectShop = (req, res, next) => { | ||
117 | module.exports = { | 127 | module.exports = { |
118 | changeFavoriteBrand, | 128 | changeFavoriteBrand, |
119 | collectProduct, | 129 | collectProduct, |
120 | - collectShop | 130 | + collectShop, |
131 | + isFavoriteBrand | ||
121 | }; | 132 | }; |
1 | -/** | ||
2 | - * AbstractAction | ||
3 | - * | ||
4 | - * @author: Aiden Xu<aiden.xu@yoho.cn> | ||
5 | - * @date: 2016/7/11 | ||
6 | - */ | ||
7 | -'use strict'; | ||
8 | - | ||
9 | -const _ = require('lodash'); | ||
10 | -const Promise = require('bluebird'); | ||
11 | - | ||
12 | -class AbstractAction { | ||
13 | - constructor(req, res, next) { | ||
14 | - if (!req || !res) { | ||
15 | - throw new Error('Request and response object must be specified.'); | ||
16 | - } | ||
17 | - | ||
18 | - this.request = req; | ||
19 | - this.response = res; | ||
20 | - this.next = next; | ||
21 | - this.renderContext = {}; | ||
22 | - } | ||
23 | - | ||
24 | - /** | ||
25 | - * 判断是否是AJAX请求 | ||
26 | - * | ||
27 | - * @return boolean 如果是AJAX请求返回 true | ||
28 | - */ | ||
29 | - | ||
30 | - /** | ||
31 | - * 设置入口 | ||
32 | - * | ||
33 | - * @param module 模块名称 | ||
34 | - * @param entry 入口名称 | ||
35 | - */ | ||
36 | - setEntry(module, entry) { | ||
37 | - _.merge(this.renderContext, { | ||
38 | - module: module, | ||
39 | - page: entry | ||
40 | - }); | ||
41 | - } | ||
42 | - | ||
43 | - /** | ||
44 | - * 渲染视图 | ||
45 | - * | ||
46 | - * @param template 模版名称 | ||
47 | - * @param context 上下文 | ||
48 | - */ | ||
49 | - renderTemplate(template, context) { | ||
50 | - this.response.render(template, _.merge({}, this.renderContext, context)); | ||
51 | - } | ||
52 | - | ||
53 | - /** | ||
54 | - * 内部渲染方法,该方法应该由 ActionCreator 来调用 | ||
55 | - * | ||
56 | - * @returns Promise | ||
57 | - */ | ||
58 | - _render() { | ||
59 | - return this.render(); | ||
60 | - } | ||
61 | - | ||
62 | - /** | ||
63 | - * 渲染回调方法 | ||
64 | - * | ||
65 | - * @returns {Promise} | ||
66 | - */ | ||
67 | - render() { | ||
68 | - return new Promise(function(resolve) { | ||
69 | - return resolve(); | ||
70 | - }); | ||
71 | - } | ||
72 | -} | ||
73 | - | ||
74 | -module.exports = AbstractAction; |
1 | -/** | ||
2 | - * Actions | ||
3 | - * | ||
4 | - * @author: Aiden Xu<aiden.xu@yoho.cn> | ||
5 | - * @date: 2016/7/11 | ||
6 | - */ | ||
7 | -'use strict'; | ||
8 | - | ||
9 | -const AbstractAction = require('./abstract-action'); | ||
10 | - | ||
11 | -/** | ||
12 | - * 创建 Action | ||
13 | - * @param Action | ||
14 | - * @returns {Function} | ||
15 | - */ | ||
16 | -const createAction = Action => { | ||
17 | - return ((req, res, next) => { | ||
18 | - const ret = new Action(req, res, next)._render(); | ||
19 | - | ||
20 | - if (ret && typeof Promise.catch === 'function') { | ||
21 | - ret.catch(next); | ||
22 | - } | ||
23 | - }); | ||
24 | -}; | ||
25 | - | ||
26 | -module.exports = { | ||
27 | - createAction, | ||
28 | - AbstractAction | ||
29 | -}; |
1 | -/** | ||
2 | - * YohoAction | ||
3 | - * | ||
4 | - * @author: Aiden Xu<aiden.xu@yoho.cn> | ||
5 | - * @date: 2016/7/11 | ||
6 | - */ | ||
7 | -'use strict'; | ||
8 | - | ||
9 | -const CHANNEL_BOYS = 'boys'; | ||
10 | -const CHANNEL_GIRLS = 'girls'; | ||
11 | -const CHANNEL_KIDS = 'kids'; | ||
12 | -const CHANNEL_DEFAULT = CHANNEL_BOYS; | ||
13 | - | ||
14 | -module.exports = { | ||
15 | - CHANNEL_DEFAULT, | ||
16 | - CHANNEL_BOYS, | ||
17 | - CHANNEL_GIRLS, | ||
18 | - CHANNEL_KIDS | ||
19 | -}; |
1 | -/** | ||
2 | - * YohoAction | ||
3 | - * | ||
4 | - * @author: Aiden Xu<aiden.xu@yoho.cn> | ||
5 | - * @date: 2016/7/11 | ||
6 | - */ | ||
7 | -'use strict'; | ||
8 | - | ||
9 | -const AbstractAction = require('./abstract-action'); | ||
10 | -const Channel = require('./channel'); | ||
11 | -const moment = require('moment'); | ||
12 | -const COOKIE_DOMAIN = '.yohobuy.com'; | ||
13 | -const COOKIE_CHANEL_MAX_AGE = 300; | ||
14 | -const _ = require('lodash'); | ||
15 | - | ||
16 | -class YohoAction extends AbstractAction { | ||
17 | - | ||
18 | - /** | ||
19 | - * 设置网站SEO的标题 | ||
20 | - * | ||
21 | - * @param title 标题 | ||
22 | - * @param sign 连接的字符串 | ||
23 | - * @param showMore 是否显示更多内容 | ||
24 | - * @return void | ||
25 | - */ | ||
26 | - setTitle(title, showMore, sign) { | ||
27 | - showMore = showMore || true; | ||
28 | - sign = sign || ' | '; | ||
29 | - | ||
30 | - _.merge(this.renderContext, { | ||
31 | - title_more: showMore, | ||
32 | - title: title + sign | ||
33 | - }); | ||
34 | - } | ||
35 | - | ||
36 | - getUid() { | ||
37 | - return this.request.user.uid; | ||
38 | - } | ||
39 | - | ||
40 | - /** | ||
41 | - * 获得当前用户所在的频道 | ||
42 | - * | ||
43 | - * @returns {*} | ||
44 | - */ | ||
45 | - getSessionChannel() { | ||
46 | - const channel = this.request.cookies._Channel || Channel.CHANNEL_DEFAULT; | ||
47 | - | ||
48 | - if (!channel) { | ||
49 | - // 设置默认频道 | ||
50 | - this.setSessionChannel(Channel.CHANNEL_BOYS); | ||
51 | - } | ||
52 | - | ||
53 | - return channel; | ||
54 | - } | ||
55 | - | ||
56 | - /** | ||
57 | - * 设置当前用户的频道 | ||
58 | - */ | ||
59 | - setSessionChannel(channel) { | ||
60 | - this.response.cookie('_Channel', channel || Channel.CHANNEL_DEFAULT, { | ||
61 | - domain: COOKIE_DOMAIN, | ||
62 | - maxAge: moment.duration(COOKIE_CHANEL_MAX_AGE, 'days').seconds() | ||
63 | - }); | ||
64 | - } | ||
65 | - | ||
66 | - /** | ||
67 | - * 根据用户访问的频道猜测用户性别 | ||
68 | - */ | ||
69 | - guessUserGender() { | ||
70 | - switch (this.getSessionChannel()) { | ||
71 | - case 'boys': | ||
72 | - return '1,3'; | ||
73 | - case 'girls': | ||
74 | - return '2,3'; | ||
75 | - default: | ||
76 | - return '1,2,3'; | ||
77 | - } | ||
78 | - } | ||
79 | - | ||
80 | - /** | ||
81 | - * 设置网站SEO的关键词 | ||
82 | - * | ||
83 | - * @param keywords 关键词,多个之间用","逗号分隔 | ||
84 | - */ | ||
85 | - setKeywords(keywords) { | ||
86 | - // this->_view->assign('keywords', rtrim(keywords, ',') . ','); | ||
87 | - _.merge(this.renderContext, { | ||
88 | - keywords: keywords.replace(/~+/, '') | ||
89 | - }); | ||
90 | - } | ||
91 | - | ||
92 | - /** | ||
93 | - * 设置网站SEO的描述内容 | ||
94 | - * | ||
95 | - * @param description 描述内容 | ||
96 | - * @param showMore 是否显示更多内容 | ||
97 | - * @param sign 连接的字符串 | ||
98 | - */ | ||
99 | - setDescription(description, showMore, sign) { | ||
100 | - _.merge(this.renderContext, { | ||
101 | - description_more: showMore, | ||
102 | - description: description + sign | ||
103 | - }); | ||
104 | - } | ||
105 | -} | ||
106 | - | ||
107 | -module.exports = YohoAction; |
@@ -6,6 +6,7 @@ | @@ -6,6 +6,7 @@ | ||
6 | const Promise = require('bluebird'); | 6 | const Promise = require('bluebird'); |
7 | const co = Promise.coroutine; | 7 | const co = Promise.coroutine; |
8 | const api = require('./brand-api'); | 8 | const api = require('./brand-api'); |
9 | +const _ = require('lodash'); | ||
9 | 10 | ||
10 | const getBrandByDomainAsync = domain => { | 11 | const getBrandByDomainAsync = domain => { |
11 | return co(function*() { | 12 | return co(function*() { |
@@ -24,7 +25,7 @@ const getBrandByDomainAsync = domain => { | @@ -24,7 +25,7 @@ const getBrandByDomainAsync = domain => { | ||
24 | result.brandNameCn = brandInfo.data.brand_name_cn || ''; | 25 | result.brandNameCn = brandInfo.data.brand_name_cn || ''; |
25 | result.brandAbout = brandInfo.data.brand_intro || ''; | 26 | result.brandAbout = brandInfo.data.brand_intro || ''; |
26 | result.shopTemplateType = brandInfo.data.shop_template_type ? | 27 | result.shopTemplateType = brandInfo.data.shop_template_type ? |
27 | - parseInt(brandInfo.data.shop_template_type) : ''; | 28 | + _.parseInt(brandInfo.data.shop_template_type) : ''; |
28 | result.type = brandInfo.data.type ? +brandInfo.data.type : 0; | 29 | result.type = brandInfo.data.type ? +brandInfo.data.type : 0; |
29 | result.shopId = brandInfo.data.shop_id || ''; | 30 | result.shopId = brandInfo.data.shop_id || ''; |
30 | 31 |
@@ -86,6 +86,23 @@ const getPromotionAsync = (skn) => { | @@ -86,6 +86,23 @@ const getPromotionAsync = (skn) => { | ||
86 | return api.get('', params); | 86 | return api.get('', params); |
87 | }; | 87 | }; |
88 | 88 | ||
89 | +const getLimitedProductStatusAsync = (code, uid, skn) => { | ||
90 | + let params = { | ||
91 | + method: 'app.limitProduct.productStatus', | ||
92 | + limitProductCode: code | ||
93 | + }; | ||
94 | + | ||
95 | + if (uid) { | ||
96 | + params.uid = uid; | ||
97 | + } | ||
98 | + | ||
99 | + if (skn) { | ||
100 | + params.product_skn = skn; | ||
101 | + } | ||
102 | + | ||
103 | + return api.get('', params); | ||
104 | +}; | ||
105 | + | ||
89 | module.exports = { | 106 | module.exports = { |
90 | getProductBannerAsync, | 107 | getProductBannerAsync, |
91 | sizeInfoAsync, | 108 | sizeInfoAsync, |
@@ -94,5 +111,6 @@ module.exports = { | @@ -94,5 +111,6 @@ module.exports = { | ||
94 | getProductModelTryAsync, | 111 | getProductModelTryAsync, |
95 | getProductAsync, | 112 | getProductAsync, |
96 | getPromotionAsync, | 113 | getPromotionAsync, |
97 | - isSupportReturnedSale | 114 | + isSupportReturnedSale, |
115 | + getLimitedProductStatusAsync | ||
98 | }; | 116 | }; |
@@ -35,16 +35,11 @@ const EXHIBITION_TICKET = 51335912; | @@ -35,16 +35,11 @@ const EXHIBITION_TICKET = 51335912; | ||
35 | const _getProductAdditionInfoAsync = (data) => { | 35 | const _getProductAdditionInfoAsync = (data) => { |
36 | return co(function * () { | 36 | return co(function * () { |
37 | let productId = _.get(data, 'product_id', 0); | 37 | let productId = _.get(data, 'product_id', 0); |
38 | - let productSkn = _.get(data, 'product_skn', 0); | ||
39 | let brandId = _.get(data, 'brand_info.brand_id', 0); | 38 | let brandId = _.get(data, 'brand_info.brand_id', 0); |
40 | 39 | ||
41 | // 获取相关数据 | 40 | // 获取相关数据 |
42 | let promiseData = { | 41 | let promiseData = { |
43 | productBanner: productAPI.getProductBannerAsync(productId), | 42 | productBanner: productAPI.getProductBannerAsync(productId), |
44 | - sizeInfo: productAPI.sizeInfoAsync(productSkn), | ||
45 | - productComfort: productAPI.getProductComfortAsync(productId), | ||
46 | - productModelCard: productAPI.getProductModelCardAsync(productId), | ||
47 | - productModelTry: productAPI.getProductModelTryAsync(productSkn), | ||
48 | bannerInfo: brandService.getBannerInfoAsync(brandId) | 43 | bannerInfo: brandService.getBannerInfoAsync(brandId) |
49 | }; | 44 | }; |
50 | 45 | ||
@@ -54,12 +49,25 @@ const _getProductAdditionInfoAsync = (data) => { | @@ -54,12 +49,25 @@ const _getProductAdditionInfoAsync = (data) => { | ||
54 | })(); | 49 | })(); |
55 | }; | 50 | }; |
56 | 51 | ||
52 | +const _getProductIntroAsync = (productId, productSkn) => { | ||
53 | + return co(function * () { | ||
54 | + let result = yield Promise.props({ | ||
55 | + sizeInfo: productAPI.sizeInfoAsync(productSkn), | ||
56 | + productComfort: productAPI.getProductComfortAsync(productId), | ||
57 | + productModelCard: productAPI.getProductModelCardAsync(productId), | ||
58 | + productModelTry: productAPI.getProductModelTryAsync(productSkn) | ||
59 | + }); | ||
60 | + | ||
61 | + return result; | ||
62 | + })(); | ||
63 | +}; | ||
64 | + | ||
57 | /** | 65 | /** |
58 | * 获取商品的喜欢 | 66 | * 获取商品的喜欢 |
59 | * pid : product id | 67 | * pid : product id |
60 | * bid : brand id | 68 | * bid : brand id |
61 | */ | 69 | */ |
62 | -const _getProductFavoriteDataAsync = (uid, pid, bid) => { | 70 | +const _getProductFavoriteDataAsync = (uid, pid) => { |
63 | return co(function*() { | 71 | return co(function*() { |
64 | let result = { | 72 | let result = { |
65 | product: false, | 73 | product: false, |
@@ -70,16 +78,18 @@ const _getProductFavoriteDataAsync = (uid, pid, bid) => { | @@ -70,16 +78,18 @@ const _getProductFavoriteDataAsync = (uid, pid, bid) => { | ||
70 | return result; | 78 | return result; |
71 | } | 79 | } |
72 | 80 | ||
73 | - if (pid) { | ||
74 | - let productData = yield favoriteProductService.isFavoriteAsync(uid, pid); | 81 | + let requestApi = {}; |
75 | 82 | ||
76 | - result.product = productData.code === 200 && productData.data ? true : false; | 83 | + if (pid) { |
84 | + requestApi.product = favoriteProductService.isFavoriteAsync(uid, pid); | ||
77 | } | 85 | } |
78 | 86 | ||
79 | - if (bid) { | ||
80 | - let brandData = yield favoriteBrandService.isFavoriteAsync(uid, bid); | 87 | + let requestData = yield Promise.props(requestApi); |
88 | + | ||
89 | + let productData = requestData.product; | ||
81 | 90 | ||
82 | - result.brand = brandData.code && brandData.code === 200 ? true : false; | 91 | + if (productData) { |
92 | + result.product = productData.code === 200 && productData.data ? true : false; | ||
83 | } | 93 | } |
84 | 94 | ||
85 | return result; | 95 | return result; |
@@ -162,7 +172,7 @@ const _getVipDataByProductBaseInfo = (data, vipLevel, uid) => { | @@ -162,7 +172,7 @@ const _getVipDataByProductBaseInfo = (data, vipLevel, uid) => { | ||
162 | const _getProductActivityBanner = (additionalData) => { | 172 | const _getProductActivityBanner = (additionalData) => { |
163 | let data = additionalData.productBanner; | 173 | let data = additionalData.productBanner; |
164 | 174 | ||
165 | - if (_.isElement(data) || _.get(data, 'code', 400) !== 200 || !_.get(data, 'data.bannerImg')) { | 175 | + if (_.isEmpty(data) || _.get(data, 'code', 400) !== 200 || !_.get(data, 'data.bannerImg')) { |
166 | return {}; | 176 | return {}; |
167 | } | 177 | } |
168 | 178 | ||
@@ -191,20 +201,10 @@ const _getActivityDataByProductBaseInfo = (data, additionalData) => { | @@ -191,20 +201,10 @@ const _getActivityDataByProductBaseInfo = (data, additionalData) => { | ||
191 | }; | 201 | }; |
192 | 202 | ||
193 | /** | 203 | /** |
194 | - * 获取商品咨询和评论数据 | ||
195 | - * @param data | ||
196 | - */ | ||
197 | -const _getConsultCommentDataByProductInfo = () => { | ||
198 | - return { | ||
199 | - commentUrl: helpers.urlFormat('/home/comment') | ||
200 | - }; | ||
201 | -}; | ||
202 | - | ||
203 | -/** | ||
204 | * 获取品牌数据 | 204 | * 获取品牌数据 |
205 | */ | 205 | */ |
206 | const _getBrandDataByProductBaseInfo = (data, additionalData) => { | 206 | const _getBrandDataByProductBaseInfo = (data, additionalData) => { |
207 | - if (!data.brand_info) { | 207 | + if (!_.get(data, 'brand_info')) { |
208 | return {}; | 208 | return {}; |
209 | } | 209 | } |
210 | 210 | ||
@@ -212,7 +212,7 @@ const _getBrandDataByProductBaseInfo = (data, additionalData) => { | @@ -212,7 +212,7 @@ const _getBrandDataByProductBaseInfo = (data, additionalData) => { | ||
212 | let bgImg = ''; | 212 | let bgImg = ''; |
213 | let logo = ''; | 213 | let logo = ''; |
214 | let bannerInfo = null; | 214 | let bannerInfo = null; |
215 | - let result = additionalData.bannerInfo; | 215 | + let result = _.get(additionalData, 'bannerInfo', {}); |
216 | 216 | ||
217 | if (_.isEmpty(result)) { | 217 | if (_.isEmpty(result)) { |
218 | return {}; | 218 | return {}; |
@@ -236,7 +236,7 @@ const _getBrandDataByProductBaseInfo = (data, additionalData) => { | @@ -236,7 +236,7 @@ const _getBrandDataByProductBaseInfo = (data, additionalData) => { | ||
236 | 236 | ||
237 | let homeUrl = 'javascript:void(0)'; // eslint-disable-line no-script-url | 237 | let homeUrl = 'javascript:void(0)'; // eslint-disable-line no-script-url |
238 | 238 | ||
239 | - if (data.brand_info.brand_domain) { | 239 | + if (_.get(data, 'brand_info.brand_domain')) { |
240 | homeUrl = helpers.urlFormat('', null, data.brand_info.brand_domain); | 240 | homeUrl = helpers.urlFormat('', null, data.brand_info.brand_domain); |
241 | } | 241 | } |
242 | 242 | ||
@@ -262,7 +262,7 @@ const _getSkuDataByProductBaseInfo = (data) => { | @@ -262,7 +262,7 @@ const _getSkuDataByProductBaseInfo = (data) => { | ||
262 | let defaultImage = '';// 默认图 | 262 | let defaultImage = '';// 默认图 |
263 | let chooseSkuFlag = false; // 选中状态 | 263 | let chooseSkuFlag = false; // 选中状态 |
264 | 264 | ||
265 | - if (!data.goods_list) { | 265 | + if (_.isEmpty(_.get(data, 'goods_list', []))) { |
266 | return { | 266 | return { |
267 | totalStorageNum, | 267 | totalStorageNum, |
268 | skuGoods, | 268 | skuGoods, |
@@ -475,25 +475,17 @@ function _getSortNavAsync(smallSortId, gender) { | @@ -475,25 +475,17 @@ function _getSortNavAsync(smallSortId, gender) { | ||
475 | } | 475 | } |
476 | 476 | ||
477 | // 保存在 gids 和 skns ,最近流览功能 | 477 | // 保存在 gids 和 skns ,最近流览功能 |
478 | -const saveRecentGoodInCookies = (oldGids, oldSkns, res, addGids, addSkns) => { | ||
479 | - oldGids = (oldGids || '').split(','); | ||
480 | - oldSkns = (oldSkns || '').split(','); | ||
481 | - addSkns = `${addSkns}-${addGids}`; | 478 | +const saveRecentGoodInCookies = (oldSkns, res, addSkns) => { |
482 | 479 | ||
483 | - _.remove(oldGids, addGids); | ||
484 | - _.remove(oldSkns, addSkns); | 480 | + oldSkns = oldSkns ? oldSkns.split(',') : []; |
485 | 481 | ||
486 | - oldGids.unshift(addGids); | ||
487 | - oldSkns.unshift(addSkns); | 482 | + oldSkns = _.reject(oldSkns, old => old === String(addSkns) ? true : false); |
488 | 483 | ||
489 | - res.cookie('_browse', oldGids.splice(0, 30).join(','), { | ||
490 | - maxAge: 2000000000, | ||
491 | - domain: 'yohobuy.com' | ||
492 | - }); | 484 | + oldSkns.unshift(addSkns); |
493 | 485 | ||
494 | res.cookie('_browseskn', oldSkns.splice(0, 30).join(','), { | 486 | res.cookie('_browseskn', oldSkns.splice(0, 30).join(','), { |
495 | maxAge: 2000000000, | 487 | maxAge: 2000000000, |
496 | - domain: 'yohobuy.com' | 488 | + domain: '.yohobuy.com' |
497 | }); | 489 | }); |
498 | }; | 490 | }; |
499 | 491 | ||
@@ -948,7 +940,7 @@ const _getSizeAttrByMaxSortId = (maxSortId, sizeList) => { | @@ -948,7 +940,7 @@ const _getSizeAttrByMaxSortId = (maxSortId, sizeList) => { | ||
948 | * @param maxSortId | 940 | * @param maxSortId |
949 | * @return object | 941 | * @return object |
950 | */ | 942 | */ |
951 | -const _getSizeInfo = (productSkn, maxSortId, additionalData)=> { | 943 | +const _getIntroInfo = (productSkn, maxSortId, additionalData)=> { |
952 | if (!productSkn) { | 944 | if (!productSkn) { |
953 | return {}; | 945 | return {}; |
954 | } | 946 | } |
@@ -1004,17 +996,15 @@ const _getSizeInfo = (productSkn, maxSortId, additionalData)=> { | @@ -1004,17 +996,15 @@ const _getSizeInfo = (productSkn, maxSortId, additionalData)=> { | ||
1004 | * @param array $navs | 996 | * @param array $navs |
1005 | * @return array | 997 | * @return array |
1006 | */ | 998 | */ |
1007 | -const _getSeoByGoodsInfo = function(goodsInfo, navs) { | 999 | +const _getSeoByGoodsInfo = (goodsInfo, navs) => { |
1008 | let title = ''; | 1000 | let title = ''; |
1009 | - let keywords = ''; | ||
1010 | let brandName = ''; | 1001 | let brandName = ''; |
1011 | let sortName = ''; | 1002 | let sortName = ''; |
1012 | - let description = ''; | ||
1013 | 1003 | ||
1014 | goodsInfo = goodsInfo || {}; | 1004 | goodsInfo = goodsInfo || {}; |
1015 | navs = navs || []; | 1005 | navs = navs || []; |
1016 | 1006 | ||
1017 | - if (!_.isEmpty(goodsInfo.brandName)) { | 1007 | + if (goodsInfo.brandName) { |
1018 | title = goodsInfo.brandName + ' '; | 1008 | title = goodsInfo.brandName + ' '; |
1019 | brandName = goodsInfo.brandName; | 1009 | brandName = goodsInfo.brandName; |
1020 | } | 1010 | } |
@@ -1025,9 +1015,9 @@ const _getSeoByGoodsInfo = function(goodsInfo, navs) { | @@ -1025,9 +1015,9 @@ const _getSeoByGoodsInfo = function(goodsInfo, navs) { | ||
1025 | } | 1015 | } |
1026 | 1016 | ||
1027 | title += goodsInfo.name + '正品 '; | 1017 | title += goodsInfo.name + '正品 '; |
1028 | - keywords = brandName + sortName + ',' + brandName + '官网专卖店,' + brandName + '官方授权店,' + | 1018 | + let keywords = brandName + sortName + ',' + brandName + '官网专卖店,' + brandName + '官方授权店,' + |
1029 | brandName + '正品,' + brandName + '打折,' + brandName + '折扣店,' + brandName + '真品,' + brandName + '代购'; | 1019 | brandName + '正品,' + brandName + '打折,' + brandName + '折扣店,' + brandName + '真品,' + brandName + '代购'; |
1030 | - description = !goodsInfo.shareDesc ? goodsInfo.name : goodsInfo.shareDesc; | 1020 | + let description = !goodsInfo.shareDesc ? goodsInfo.name : goodsInfo.shareDesc; |
1031 | 1021 | ||
1032 | return { | 1022 | return { |
1033 | title: title, | 1023 | title: title, |
@@ -1041,12 +1031,22 @@ const _getSeoByGoodsInfo = function(goodsInfo, navs) { | @@ -1041,12 +1031,22 @@ const _getSeoByGoodsInfo = function(goodsInfo, navs) { | ||
1041 | * @param origin Object 原始数据 | 1031 | * @param origin Object 原始数据 |
1042 | * @return result Object 格式化数据 | 1032 | * @return result Object 格式化数据 |
1043 | */ | 1033 | */ |
1044 | -const _detailDataPkg = (origin, uid, vipLevel) => { | 1034 | +const _detailDataPkg = (origin, uid, vipLevel, cookies) => { |
1045 | return co(function*() { | 1035 | return co(function*() { |
1046 | - let result = {}; // 结果输出 | ||
1047 | - let md5 = origin.md5; | 1036 | + if (_.isEmpty(origin) || _.isEmpty(origin.data)) { |
1037 | + return {}; | ||
1038 | + } | ||
1039 | + | ||
1040 | + let result = {}; | ||
1041 | + | ||
1042 | + result.md5 = origin.md5;// 用于前端数据变化的对比 | ||
1048 | 1043 | ||
1049 | origin = origin.data; | 1044 | origin = origin.data; |
1045 | + | ||
1046 | + if (uid) { | ||
1047 | + origin.uid = uid; | ||
1048 | + } | ||
1049 | + | ||
1050 | let propOrigin = _.partial(_.get, origin); | 1050 | let propOrigin = _.partial(_.get, origin); |
1051 | 1051 | ||
1052 | // 商品名称 | 1052 | // 商品名称 |
@@ -1054,34 +1054,51 @@ const _detailDataPkg = (origin, uid, vipLevel) => { | @@ -1054,34 +1054,51 @@ const _detailDataPkg = (origin, uid, vipLevel) => { | ||
1054 | return result; | 1054 | return result; |
1055 | } | 1055 | } |
1056 | 1056 | ||
1057 | - origin.uid = uid; | ||
1058 | result.name = propOrigin('product_name'); | 1057 | result.name = propOrigin('product_name'); |
1059 | result.skn = propOrigin('product_skn'); | 1058 | result.skn = propOrigin('product_skn'); |
1060 | result.productId = propOrigin('product_id'); | 1059 | result.productId = propOrigin('product_id'); |
1061 | - result.md5 = md5; // 用于前端数据变化的对比 | ||
1062 | 1060 | ||
1063 | result.maxSortId = propOrigin('maxSortId', ''); | 1061 | result.maxSortId = propOrigin('maxSortId', ''); |
1064 | result.smallSortId = propOrigin('smallSortId', ''); | 1062 | result.smallSortId = propOrigin('smallSortId', ''); |
1065 | 1063 | ||
1066 | result.goCartUrl = helpers.urlFormat('/shopping/cart'); | 1064 | result.goCartUrl = helpers.urlFormat('/shopping/cart'); |
1067 | 1065 | ||
1068 | - let brandId = propOrigin('brand_info.brand_id', 0); | ||
1069 | - let requestData = yield Promise.all([ | ||
1070 | - _getProductAdditionInfoAsync(origin), // 预处理所有的数据 | ||
1071 | - _getProductFavoriteDataAsync(uid, result.productId, brandId), // 处理收藏喜欢数据 | ||
1072 | - productAPI.getPromotionAsync(result.skn) | ||
1073 | - ]); | 1066 | + let requestApi = { |
1067 | + addition: _getProductAdditionInfoAsync(origin), // 预处理所有的数据 | ||
1068 | + fav: _getProductFavoriteDataAsync(uid, result.productId), // 处理收藏喜欢数据 | ||
1069 | + promotion: productAPI.getPromotionAsync(result.skn) // 打折信息 | ||
1070 | + }; | ||
1071 | + | ||
1072 | + if (propOrigin('isLimitBuy', false) && propOrigin('limitProductCode', '')) { | ||
1073 | + requestApi.limited = productAPI.getLimitedProductStatusAsync( | ||
1074 | + propOrigin('limitProductCode'), | ||
1075 | + uid, | ||
1076 | + result.skn | ||
1077 | + ); // 限购商品的状态 | ||
1078 | + } | ||
1079 | + | ||
1080 | + if (propOrigin('brand_info', '')) { | ||
1081 | + requestApi.brand = | ||
1082 | + brandService.getBrandByDomainAsync(propOrigin('brand_info.brand_domain')); // 品牌信息 | ||
1083 | + } | ||
1084 | + | ||
1085 | + let requestData = yield Promise.props(requestApi); | ||
1074 | 1086 | ||
1075 | - let additionalData = requestData[0]; | ||
1076 | - let favoriteData = requestData[1]; | ||
1077 | - let promotionData = requestData[2]; | 1087 | + let additionalData = requestData.addition; |
1088 | + let favoriteData = requestData.fav; | ||
1089 | + let promotionData = requestData.promotion; | ||
1090 | + let limitedInfo = requestData.limited; | ||
1091 | + let domainBrand = requestData.brand; | ||
1078 | 1092 | ||
1079 | // 商品标签 | 1093 | // 商品标签 |
1080 | result.tags = _getTagsDataByProductInfo(origin); | 1094 | result.tags = _getTagsDataByProductInfo(origin); |
1081 | 1095 | ||
1082 | - // 商品促销短语 | 1096 | + // 商品促销短语 |
1083 | result.saleTip = propOrigin('sales_phrase', ''); | 1097 | result.saleTip = propOrigin('sales_phrase', ''); |
1084 | 1098 | ||
1099 | + // 是否收藏 | ||
1100 | + result.isCollect = favoriteData.product; | ||
1101 | + | ||
1085 | // 商品价格 | 1102 | // 商品价格 |
1086 | result.marketPrice = propOrigin('format_market_price'); | 1103 | result.marketPrice = propOrigin('format_market_price'); |
1087 | result.salePrice = propOrigin('format_sales_price'); | 1104 | result.salePrice = propOrigin('format_sales_price'); |
@@ -1127,20 +1144,6 @@ const _detailDataPkg = (origin, uid, vipLevel) => { | @@ -1127,20 +1144,6 @@ const _detailDataPkg = (origin, uid, vipLevel) => { | ||
1127 | result.hasOtherPrice = false; | 1144 | result.hasOtherPrice = false; |
1128 | } | 1145 | } |
1129 | 1146 | ||
1130 | - // 商品咨询和评论数据,当前为空 | ||
1131 | - let consultComment = _getConsultCommentDataByProductInfo(); | ||
1132 | - | ||
1133 | - // 品牌信息 | ||
1134 | - let banner = {}; | ||
1135 | - | ||
1136 | - if (propOrigin('brand_info', '')) { | ||
1137 | - result.brandImg = helpers.image(propOrigin('brand_info.brand_ico', ''), 47, 47); | ||
1138 | - result.brandName = propOrigin('brand_info.brand_name', ''); | ||
1139 | - result.brandUrl = helpers.urlFormat('', null, propOrigin('brand_info.brand_domain')); | ||
1140 | - banner = _getBrandDataByProductBaseInfo(origin, additionalData); | ||
1141 | - banner.isCollect = favoriteData.brand; | ||
1142 | - } | ||
1143 | - | ||
1144 | // sku商品信息 | 1147 | // sku商品信息 |
1145 | let skuData = _getSkuDataByProductBaseInfo(origin); | 1148 | let skuData = _getSkuDataByProductBaseInfo(origin); |
1146 | 1149 | ||
@@ -1148,15 +1151,13 @@ const _detailDataPkg = (origin, uid, vipLevel) => { | @@ -1148,15 +1151,13 @@ const _detailDataPkg = (origin, uid, vipLevel) => { | ||
1148 | result.colors = skuData.skuGoods; | 1151 | result.colors = skuData.skuGoods; |
1149 | let totalStorageNum = skuData.totalStorageNum; | 1152 | let totalStorageNum = skuData.totalStorageNum; |
1150 | 1153 | ||
1151 | - // 是否收藏 | ||
1152 | - result.isCollect = favoriteData.product; | ||
1153 | - | ||
1154 | - if (propOrigin('isLimitBuy', false)) { | 1154 | + // 限购商品 |
1155 | + if (limitedInfo && limitedInfo.code === 200 && _.get(limitedInfo, 'data.isLimitBuy', false) === true) { | ||
1155 | // 是否开售 | 1156 | // 是否开售 |
1156 | - let isBeginSale = propOrigin('saleStatus', 0) === 1; | 1157 | + let isBeginSale = _.get(limitedInfo, 'data.saleStatus', 0) === 1; |
1157 | 1158 | ||
1158 | // 限购商品有关的展示状态 | 1159 | // 限购商品有关的展示状态 |
1159 | - let showStatus = propOrigin('showStatus', 1); | 1160 | + let showStatus = _.get(limitedInfo, 'data.showStatus', 1); |
1160 | 1161 | ||
1161 | let fashTopGoods = _getFashionTopGoodsStatus(uid, showStatus, isBeginSale); | 1162 | let fashTopGoods = _getFashionTopGoodsStatus(uid, showStatus, isBeginSale); |
1162 | 1163 | ||
@@ -1177,6 +1178,7 @@ const _detailDataPkg = (origin, uid, vipLevel) => { | @@ -1177,6 +1178,7 @@ const _detailDataPkg = (origin, uid, vipLevel) => { | ||
1177 | } | 1178 | } |
1178 | } | 1179 | } |
1179 | 1180 | ||
1181 | + // 商品购买状态 | ||
1180 | let soldOut = !!(propOrigin('status') === 0 || totalStorageNum === 0); | 1182 | let soldOut = !!(propOrigin('status') === 0 || totalStorageNum === 0); |
1181 | let notForSale = propOrigin('attribute') === 2; // 非卖品 | 1183 | let notForSale = propOrigin('attribute') === 2; // 非卖品 |
1182 | let virtualGoods = propOrigin('attribute') === 3; // 虚拟商品 | 1184 | let virtualGoods = propOrigin('attribute') === 3; // 虚拟商品 |
@@ -1244,44 +1246,62 @@ const _detailDataPkg = (origin, uid, vipLevel) => { | @@ -1244,44 +1246,62 @@ const _detailDataPkg = (origin, uid, vipLevel) => { | ||
1244 | statGoodsInfo.smallSortId = result.smallSortId; | 1246 | statGoodsInfo.smallSortId = result.smallSortId; |
1245 | statGoodsInfo.soldOut = soldOut ? 1 : 0; | 1247 | statGoodsInfo.soldOut = soldOut ? 1 : 0; |
1246 | 1248 | ||
1247 | - if (banner.brandId) { | ||
1248 | - let domainBrand = yield brandService.getBrandByDomainAsync(banner.brandDomain); | 1249 | + // 商品的品牌信息 |
1250 | + let bandInfo = {}; | ||
1251 | + | ||
1252 | + if (propOrigin('brand_info', '')) { | ||
1253 | + result.brandImg = helpers.image(propOrigin('brand_info.brand_ico', ''), 47, 47); | ||
1254 | + result.brandName = propOrigin('brand_info.brand_name', ''); | ||
1255 | + result.brandUrl = helpers.urlFormat('', null, propOrigin('brand_info.brand_domain')); | ||
1256 | + bandInfo = _getBrandDataByProductBaseInfo(origin, additionalData); | ||
1257 | + bandInfo.isCollect = favoriteData.brand; | ||
1249 | 1258 | ||
1250 | if (domainBrand.type && domainBrand.shopId) { | 1259 | if (domainBrand.type && domainBrand.shopId) { |
1251 | let type = _.parseInt(domainBrand.type); | 1260 | let type = _.parseInt(domainBrand.type); |
1252 | 1261 | ||
1253 | if (type === 1) { | 1262 | if (type === 1) { |
1254 | // 多品店不显示 | 1263 | // 多品店不显示 |
1255 | - banner = {}; | 1264 | + bandInfo = {}; |
1256 | } else if (type === 2) { | 1265 | } else if (type === 2) { |
1257 | // 单品店显示新版的店铺banner | 1266 | // 单品店显示新版的店铺banner |
1258 | let basisData = yield shopService.basisTemplateAsync(domainBrand.shopId); | 1267 | let basisData = yield shopService.basisTemplateAsync(domainBrand.shopId); |
1259 | 1268 | ||
1260 | - banner.bgImg = basisData.shopTopBanner.banner || banner.bgImg; | 1269 | + bandInfo.bgImg = basisData.shopTopBanner.banner || bandInfo.bgImg; |
1261 | } | 1270 | } |
1262 | } | 1271 | } |
1263 | } | 1272 | } |
1264 | 1273 | ||
1274 | + // 最近浏览功能 ,限量商品不加入到最近浏览 | ||
1275 | + if (!_.has(result, 'fashionTopGoods')) { | ||
1276 | + cookies && cookies(_.get(result, 'skn', '')); | ||
1277 | + } | ||
1265 | 1278 | ||
1266 | - // 获取商品尺寸相关 | ||
1267 | - let sizeInfo = _getSizeInfo(result, result.maxSortId, additionalData); | ||
1268 | - | ||
1269 | - return Object.assign({ | 1279 | + return { |
1270 | goodsInfo: result, | 1280 | goodsInfo: result, |
1271 | - consultComment: consultComment, | ||
1272 | - banner: _.isEmpty(banner) ? null : banner, | 1281 | + banner: _.isEmpty(bandInfo) ? null : bandInfo, |
1273 | statGoodsInfo: statGoodsInfo | 1282 | statGoodsInfo: statGoodsInfo |
1274 | - }, sizeInfo); | 1283 | + |
1284 | + }; | ||
1275 | })(); | 1285 | })(); |
1276 | }; | 1286 | }; |
1277 | 1287 | ||
1278 | -const getDetailHeader = (pid, uid, isStudent, vipLevel, dataMd5) => { | ||
1279 | - let currentUserProductInfo = _.partial(_detailDataPkg, _, uid, vipLevel); | 1288 | +/** |
1289 | + * 获得商品价格,活动等数据 | ||
1290 | + */ | ||
1291 | +const getDetailHeader = (pid, uid, isStudent, vipLevel, dataMd5, cookie) => { | ||
1292 | + let currentUserProductInfo = _.partial(_detailDataPkg, _, uid, vipLevel, cookie); | ||
1280 | 1293 | ||
1281 | return productAPI.getProductAsync(pid, uid, isStudent, vipLevel) | 1294 | return productAPI.getProductAsync(pid, uid, isStudent, vipLevel) |
1282 | - .then(result => currentUserProductInfo(result)) | 1295 | + .then(currentUserProductInfo) |
1283 | .then((result) => { | 1296 | .then((result) => { |
1284 | - if (result.goodsInfo.md5 !== dataMd5 || uid) { | 1297 | + if (_.isEmpty(result) || !_.get(result, 'goodsInfo.md5')) { |
1298 | + return { | ||
1299 | + code: 204, // 没有改变数据 | ||
1300 | + data: {} | ||
1301 | + }; | ||
1302 | + } | ||
1303 | + | ||
1304 | + if (_.get(result, 'goodsInfo.md5') !== dataMd5 || uid) { | ||
1285 | return { | 1305 | return { |
1286 | code: 200, // 改变数据 | 1306 | code: 200, // 改变数据 |
1287 | data: result | 1307 | data: result |
@@ -1296,60 +1316,81 @@ const getDetailHeader = (pid, uid, isStudent, vipLevel, dataMd5) => { | @@ -1296,60 +1316,81 @@ const getDetailHeader = (pid, uid, isStudent, vipLevel, dataMd5) => { | ||
1296 | }; | 1316 | }; |
1297 | 1317 | ||
1298 | /** | 1318 | /** |
1319 | + * 是否支持退换货,true 支持,false 不支持 | ||
1320 | + */ | ||
1321 | +const saleReturn = (skn) => { | ||
1322 | + return productAPI.isSupportReturnedSale(skn).then(result => _.get(result, `data.${skn}`, 'N') === 'N' ? 'Y' : 'N'); | ||
1323 | +}; | ||
1324 | + | ||
1325 | +/** | ||
1299 | * 获取某一个商品详情主页面 | 1326 | * 获取某一个商品详情主页面 |
1300 | */ | 1327 | */ |
1301 | const showMainAsync = (data) => { | 1328 | const showMainAsync = (data) => { |
1302 | return co(function * () { | 1329 | return co(function * () { |
1303 | - let result = {}; | ||
1304 | - let currentUserProductInfo = _.partial(_detailDataPkg, _, data.uid, data.vipLevel); | 1330 | + // 获取商品基本信息 |
1331 | + let productData = yield productAPI.getProductAsync(data.pid, data.uid, data.isStudent, data.vipLevel); | ||
1305 | 1332 | ||
1306 | - // 获取商品信息 | ||
1307 | - let productInfo = yield productAPI.getProductAsync(data.pid, data.uid, data.isStudent, data.vipLevel) | ||
1308 | - .then(currentUserProductInfo); | ||
1309 | - | ||
1310 | - if (_.isEmpty(productInfo) || _.isEmpty(productInfo.goodsInfo)) { | 1333 | + if (_.isEmpty(productData.data)) { |
1311 | return Promise.reject({ | 1334 | return Promise.reject({ |
1312 | - code: 404 | 1335 | + code: 404, |
1336 | + message: 'app.product.data api wrong' | ||
1313 | }); | 1337 | }); |
1314 | } | 1338 | } |
1315 | 1339 | ||
1340 | + let smallSortId = _.get(productData, 'data.smallSortId'); | ||
1341 | + let maxSortId = _.get(productData, 'data.maxSortId'); | ||
1342 | + let productId = _.get(productData, 'data.product_id'); | ||
1343 | + let productSkn = _.get(productData, 'data.product_skn'); | ||
1344 | + let curUserProduct = _.partial(_detailDataPkg, _, data.uid, data.vipLevel, data.gid, data.saveInCookies); | ||
1345 | + | ||
1316 | let requestData = yield Promise.all([ | 1346 | let requestData = yield Promise.all([ |
1317 | - _getSortNavAsync(productInfo.goodsInfo.smallSortId, data.gender), | ||
1318 | - HeaderModel.requestHeaderData(data.channel), | ||
1319 | - productAPI.isSupportReturnedSale(productInfo.goodsInfo.skn) | 1347 | + _getSortNavAsync(smallSortId, data.gender), // 面包屑导航 |
1348 | + HeaderModel.requestHeaderData(data.channel), // 通用头部数据 | ||
1349 | + _getProductIntroAsync(productId, productSkn), // 商品详细介绍 | ||
1350 | + curUserProduct(productData) // 商品详细价格 | ||
1320 | ]); | 1351 | ]); |
1321 | 1352 | ||
1322 | - // 分类导航 ,seo | ||
1323 | - let navs = requestData[0]; | ||
1324 | - let seo = _getSeoByGoodsInfo(productInfo.goodsInfo, navs); | ||
1325 | - | ||
1326 | - result.seo = seo; | ||
1327 | - | ||
1328 | - // 最近浏览功能 ,限量商品不能使用这个功能 | ||
1329 | - if (!_.has(productInfo, 'goodsInfo.fashionTopGoods')) { | ||
1330 | - data.saveInCookies(data.gid, _.get(productInfo, 'goodsInfo.skn', '')); | ||
1331 | - } | 1353 | + let smallSortNavigator = requestData[0]; |
1354 | + let navigatorHeader = requestData[1]; | ||
1355 | + let productDescription = requestData[2]; | ||
1356 | + let productInfo = requestData[3]; | ||
1332 | 1357 | ||
1358 | + // 拼装数据 | ||
1359 | + let result = {}; | ||
1333 | 1360 | ||
1334 | - result.headerData = requestData[1].headerData; | 1361 | + // 商品价格 |
1335 | result.productDetailPage = true; | 1362 | result.productDetailPage = true; |
1336 | result.detail = productInfo; | 1363 | result.detail = productInfo; |
1337 | - result.statGoodsInfo = Object.assign({fullSortName: navs.map(x => x.name).join('-')}, | 1364 | + |
1365 | + // 商品介绍 | ||
1366 | + let intro = _getIntroInfo(productSkn, maxSortId, productDescription); | ||
1367 | + | ||
1368 | + result.deatil = Object.assign(result.detail, intro); | ||
1369 | + | ||
1370 | + // seo | ||
1371 | + result.seo = _getSeoByGoodsInfo(productInfo.goodsInfo, smallSortNavigator); | ||
1372 | + | ||
1373 | + // 商品页面统计 | ||
1374 | + result.statGoodsInfo = Object.assign({fullSortName: smallSortNavigator.map(x => x.name).join('-')}, | ||
1338 | productInfo.statGoodsInfo | 1375 | productInfo.statGoodsInfo |
1339 | ); | 1376 | ); |
1340 | 1377 | ||
1341 | - // 是否支持退换货,true 支持,false 不支持 | ||
1342 | - result.detail.supportSaleReturnedService = | ||
1343 | - _.get(requestData, `[2].data.${productInfo.goodsInfo.skn}`, 'N') === 'N'; | ||
1344 | - | ||
1345 | - // 导航 | 1378 | + // 面包屑导航 |
1346 | result.detail.pathNav = _.concat( | 1379 | result.detail.pathNav = _.concat( |
1347 | homeService.getHomeChannelNav(data.channel), | 1380 | homeService.getHomeChannelNav(data.channel), |
1348 | - navs, | ||
1349 | - [{name: productInfo.goodsInfo.name}] | 1381 | + smallSortNavigator, |
1382 | + [{name: _.get(productInfo, 'goodsInfo.name')}] | ||
1350 | ); | 1383 | ); |
1351 | 1384 | ||
1385 | + // 头部数据 | ||
1386 | + result.headerData = navigatorHeader.headerData; | ||
1387 | + | ||
1388 | + // 咨询和评论 | ||
1389 | + result.detail.consultComment = true; | ||
1390 | + | ||
1391 | + // 最近浏览,最多5条记录 | ||
1352 | result.detail.latestWalk = 5; | 1392 | result.detail.latestWalk = 5; |
1393 | + | ||
1353 | return result; | 1394 | return result; |
1354 | })(); | 1395 | })(); |
1355 | }; | 1396 | }; |
@@ -1362,5 +1403,6 @@ module.exports = { | @@ -1362,5 +1403,6 @@ module.exports = { | ||
1362 | showMainAsync: showMainAsync, // 获取某一个商品详情主页面 | 1403 | showMainAsync: showMainAsync, // 获取某一个商品详情主页面 |
1363 | indexHotAreaAsync: hotAreaService.indexAsync, // 获取某一个商品的热区数据 | 1404 | indexHotAreaAsync: hotAreaService.indexAsync, // 获取某一个商品的热区数据 |
1364 | saveRecentGoodInCookies, // 保存最近的商品 | 1405 | saveRecentGoodInCookies, // 保存最近的商品 |
1365 | - getDetailHeader | 1406 | + getDetailHeader, |
1407 | + saleReturn | ||
1366 | }; | 1408 | }; |
@@ -492,7 +492,7 @@ const getAdnav = (params) => { | @@ -492,7 +492,7 @@ const getAdnav = (params) => { | ||
492 | 492 | ||
493 | if (result[1].code === 200 && result[1].data) { | 493 | if (result[1].code === 200 && result[1].data) { |
494 | dest.picTitle = brandFolderSeries; | 494 | dest.picTitle = brandFolderSeries; |
495 | - Object.assign(dest.list, searchHandler.handleFolderData(result[0].data)); | 495 | + Object.assign(dest.list, searchHandler.handleSeriesData(result[1].data)); |
496 | } | 496 | } |
497 | 497 | ||
498 | 498 | ||
@@ -516,6 +516,7 @@ const getShopInfo = (shopId, uid) => { | @@ -516,6 +516,7 @@ const getShopInfo = (shopId, uid) => { | ||
516 | isFavorite: result.data.is_favorite === 'Y', | 516 | isFavorite: result.data.is_favorite === 'Y', |
517 | shopTemplateType: result.data.shop_template_type, | 517 | shopTemplateType: result.data.shop_template_type, |
518 | multBrandShopType: result.data.mult_brand_shop_type, | 518 | multBrandShopType: result.data.mult_brand_shop_type, |
519 | + shopName: result.data.shop_name, | ||
519 | showShopName: result.data.is_show_shop_name === 'Y' | 520 | showShopName: result.data.is_show_shop_name === 'Y' |
520 | }; | 521 | }; |
521 | } else { | 522 | } else { |
@@ -549,7 +550,8 @@ const getShopData = (shopId, channel, params, shopInfo) => { | @@ -549,7 +550,8 @@ const getShopData = (shopId, channel, params, shopInfo) => { | ||
549 | 550 | ||
550 | Object.assign(finalResult, | 551 | Object.assign(finalResult, |
551 | result[0], // 头部数据 | 552 | result[0], // 头部数据 |
552 | - searchHandler.handlePathNavData(shopInfo, params, 'shop', channel) // 面包屑导航 | 553 | + searchHandler.handlePathNavData(shopInfo, params, 'shop', channel), // 面包屑导航 |
554 | + shopHandler.setShopSeo(shopInfo.shopName || shopInfo.brandName) // 店铺SEO | ||
553 | ); | 555 | ); |
554 | 556 | ||
555 | _.set(finalResult, 'headerData.header', true); | 557 | _.set(finalResult, 'headerData.header', true); |
@@ -786,6 +788,9 @@ const getShopListData = (channel, params, uid) => { | @@ -786,6 +788,9 @@ const getShopListData = (channel, params, uid) => { | ||
786 | isFavorite: data.is_favorite === 'Y', | 788 | isFavorite: data.is_favorite === 'Y', |
787 | brandCont: data.shop_intro || '' | 789 | brandCont: data.shop_intro || '' |
788 | }); | 790 | }); |
791 | + | ||
792 | + // 店铺SEO | ||
793 | + Object.assign(finalResult, shopHandler.setShopSeo(data.shop_name)); | ||
789 | } | 794 | } |
790 | } else { | 795 | } else { |
791 | return Promise.reject('No ShopDecorator data'); | 796 | return Promise.reject('No ShopDecorator data'); |
@@ -915,6 +920,9 @@ const getBaseShopData = (params, extra, channel, shopId) => { | @@ -915,6 +920,9 @@ const getBaseShopData = (params, extra, channel, shopId) => { | ||
915 | name: shopName, | 920 | name: shopName, |
916 | pathTitle: shopName | 921 | pathTitle: shopName |
917 | }); | 922 | }); |
923 | + | ||
924 | + // 店铺SEO | ||
925 | + Object.assign(resData, shopHandler.setShopSeo(shopName)); | ||
918 | } | 926 | } |
919 | 927 | ||
920 | // 临时删除seo信息 | 928 | // 临时删除seo信息 |
@@ -731,9 +731,9 @@ exports.handlePagerData = (total, params) => { | @@ -731,9 +731,9 @@ exports.handlePagerData = (total, params) => { | ||
731 | pages: [] | 731 | pages: [] |
732 | }; | 732 | }; |
733 | 733 | ||
734 | - let currentPage = parseInt((_.isEmpty(params.page) ? 1 : params.page), 10); // 当前页 | ||
735 | - let perPageCount = parseInt((_.isEmpty(params.limit) ? 60 : params.limit), 10); // 每页商品数 | ||
736 | - let totalPage = parseInt(total / perPageCount, 10) + 1; // 总页数 | 734 | + let currentPage = parseInt(_.get(params, 'page', 1), 10); // 当前页 |
735 | + let perPageCount = parseInt(_.get(params, 'limit', 60), 10); // 每页商品数 | ||
736 | + let totalPage = Math.ceil(total / perPageCount); // 总页数 | ||
737 | 737 | ||
738 | if (currentPage === 1) { | 738 | if (currentPage === 1) { |
739 | // 当前页为 1,一定没有上一页 | 739 | // 当前页为 1,一定没有上一页 |
@@ -773,11 +773,14 @@ exports.handlePagerData = (total, params) => { | @@ -773,11 +773,14 @@ exports.handlePagerData = (total, params) => { | ||
773 | } | 773 | } |
774 | } else if (currentPage > totalPage - 2) { | 774 | } else if (currentPage > totalPage - 2) { |
775 | for (let i = totalPage; i >= totalPage - 4; i--) { | 775 | for (let i = totalPage; i >= totalPage - 4; i--) { |
776 | - pages.push({ | ||
777 | - url: handleFilterUrl(params, {page: i}), | ||
778 | - num: i, | ||
779 | - cur: currentPage === i | ||
780 | - }); | 776 | + |
777 | + if (i > 0) { | ||
778 | + pages.push({ | ||
779 | + url: handleFilterUrl(params, {page: i}), | ||
780 | + num: i, | ||
781 | + cur: currentPage === i | ||
782 | + }); | ||
783 | + } | ||
781 | } | 784 | } |
782 | pages = _.sortBy(pages, ['num']); | 785 | pages = _.sortBy(pages, ['num']); |
783 | } | 786 | } |
@@ -795,7 +798,7 @@ exports.handlePagerData = (total, params) => { | @@ -795,7 +798,7 @@ exports.handlePagerData = (total, params) => { | ||
795 | num: '...' | 798 | num: '...' |
796 | }); | 799 | }); |
797 | } | 800 | } |
798 | - if (currentPage < totalPage - 2) { | 801 | + if (currentPage < totalPage - 2 && totalPage > 5) { |
799 | nextPages.push({ | 802 | nextPages.push({ |
800 | num: '...' | 803 | num: '...' |
801 | }); | 804 | }); |
1 | /** | 1 | /** |
2 | * Created by TaoHuang on 2016/6/14. | 2 | * Created by TaoHuang on 2016/6/14. |
3 | */ | 3 | */ |
4 | - | ||
5 | - | ||
6 | 'use strict'; | 4 | 'use strict'; |
5 | +const _ = require('lodash'); | ||
6 | +const md5 = require('md5'); | ||
7 | 7 | ||
8 | -const api = global.yoho.SearchAPI; | ||
9 | - | ||
10 | -const yohoApi = global.yoho.API; | ||
11 | - | 8 | +const api = global.yoho.API; |
12 | const serviceApi = global.yoho.ServiceAPI; | 9 | const serviceApi = global.yoho.ServiceAPI; |
13 | -const _ = require('lodash'); | 10 | + |
14 | const helpers = global.yoho.helpers; | 11 | const helpers = global.yoho.helpers; |
15 | -const images = require('../../../utils/images.js'); | ||
16 | const cache = global.yoho.cache; | 12 | const cache = global.yoho.cache; |
17 | const logger = global.yoho.logger; | 13 | const logger = global.yoho.logger; |
18 | -const md5 = require('md5'); | ||
19 | const config = require('../../../config/common'); | 14 | const config = require('../../../config/common'); |
15 | +const images = require('../../../utils/images.js'); | ||
20 | 16 | ||
21 | const getSortByConditionAsync = (condition) => { | 17 | const getSortByConditionAsync = (condition) => { |
22 | - return api.get('sortgroup.json', condition); | 18 | + return api.get('', Object.assign({ |
19 | + method: 'web.regular.groupsort' | ||
20 | + }, condition)); | ||
23 | }; | 21 | }; |
24 | 22 | ||
25 | // 判断用户是否收藏品牌 | 23 | // 判断用户是否收藏品牌 |
@@ -40,12 +38,7 @@ const getSearchCackeKey = params => { | @@ -40,12 +38,7 @@ const getSearchCackeKey = params => { | ||
40 | return md5(ks.join('_')); | 38 | return md5(ks.join('_')); |
41 | }; | 39 | }; |
42 | 40 | ||
43 | -const getProductListOrig = (finalParams) => { | ||
44 | - | ||
45 | - return yohoApi.get('', finalParams).then(result => { | ||
46 | - return result; | ||
47 | - }); | ||
48 | -}; | 41 | +const getProductListOrig = finalParams => api.get('', finalParams); |
49 | 42 | ||
50 | /** | 43 | /** |
51 | * 获取商品列表 | 44 | * 获取商品列表 |
@@ -104,11 +97,7 @@ const getProductList = (params) => { | @@ -104,11 +97,7 @@ const getProductList = (params) => { | ||
104 | } | 97 | } |
105 | }; | 98 | }; |
106 | 99 | ||
107 | -const getSortListOrig = (finalParams) => { | ||
108 | - return yohoApi.get('', finalParams).then(ret => { | ||
109 | - return ret; | ||
110 | - }); | ||
111 | -}; | 100 | +const getSortListOrig = (finalParams) => api.get('', finalParams); |
112 | 101 | ||
113 | /** | 102 | /** |
114 | * 获取分类列表 | 103 | * 获取分类列表 |
@@ -164,7 +153,7 @@ const getSortIntro = (params) => { | @@ -164,7 +153,7 @@ const getSortIntro = (params) => { | ||
164 | }; | 153 | }; |
165 | 154 | ||
166 | Object.assign(finalParams, params); | 155 | Object.assign(finalParams, params); |
167 | - return yohoApi.get('', finalParams); | 156 | + return api.get('', finalParams); |
168 | }; | 157 | }; |
169 | 158 | ||
170 | /** | 159 | /** |
@@ -177,7 +166,7 @@ const getSortAds = (params) => { | @@ -177,7 +166,7 @@ const getSortAds = (params) => { | ||
177 | }; | 166 | }; |
178 | 167 | ||
179 | Object.assign(finalParams, params); | 168 | Object.assign(finalParams, params); |
180 | - return yohoApi.get('', finalParams); | 169 | + return api.get('', finalParams); |
181 | }; | 170 | }; |
182 | 171 | ||
183 | /** | 172 | /** |
@@ -192,7 +181,7 @@ const getBrandSeries = (params) => { | @@ -192,7 +181,7 @@ const getBrandSeries = (params) => { | ||
192 | status: params.status || 1 | 181 | status: params.status || 1 |
193 | }; | 182 | }; |
194 | 183 | ||
195 | - return yohoApi.get('', finalParams); | 184 | + return api.get('', finalParams); |
196 | }; | 185 | }; |
197 | 186 | ||
198 | /** | 187 | /** |
@@ -207,7 +196,7 @@ const getBrandFolder = (params) => { | @@ -207,7 +196,7 @@ const getBrandFolder = (params) => { | ||
207 | status: params.status || 1 | 196 | status: params.status || 1 |
208 | }; | 197 | }; |
209 | 198 | ||
210 | - return yohoApi.get('', finalParams); | 199 | + return api.get('', finalParams); |
211 | }; | 200 | }; |
212 | 201 | ||
213 | /** | 202 | /** |
@@ -221,7 +210,7 @@ const getNodeContent = (params) => { | @@ -221,7 +210,7 @@ const getNodeContent = (params) => { | ||
221 | node: params.node || '' | 210 | node: params.node || '' |
222 | }; | 211 | }; |
223 | 212 | ||
224 | - return yohoApi.get('', finalParams); | 213 | + return api.get('', finalParams); |
225 | }; | 214 | }; |
226 | 215 | ||
227 | /** | 216 | /** |
@@ -235,7 +224,7 @@ const getWeekNew = (params) => { | @@ -235,7 +224,7 @@ const getWeekNew = (params) => { | ||
235 | }; | 224 | }; |
236 | 225 | ||
237 | Object.assign(finalParams, params); | 226 | Object.assign(finalParams, params); |
238 | - return yohoApi.get('', finalParams); | 227 | + return api.get('', finalParams); |
239 | }; | 228 | }; |
240 | 229 | ||
241 | /** | 230 | /** |
@@ -266,7 +255,7 @@ const getBrandShop = (query) => { | @@ -266,7 +255,7 @@ const getBrandShop = (query) => { | ||
266 | if (retObj) { | 255 | if (retObj) { |
267 | return retObj; | 256 | return retObj; |
268 | } else { | 257 | } else { |
269 | - return yohoApi.get('', finalParams).then(ret => { | 258 | + return api.get('', finalParams).then(ret => { |
270 | if (ret && ret.code === 200) { | 259 | if (ret && ret.code === 200) { |
271 | 260 | ||
272 | cache.set(cKey, ret.data, 3600); | 261 | cache.set(cKey, ret.data, 3600); |
@@ -304,7 +293,7 @@ const getShopsByBrandId = bid => { | @@ -304,7 +293,7 @@ const getShopsByBrandId = bid => { | ||
304 | if (cdataObj) { | 293 | if (cdataObj) { |
305 | return cdataObj; | 294 | return cdataObj; |
306 | } else { | 295 | } else { |
307 | - return yohoApi.get('', finalParams).then(ret => { | 296 | + return api.get('', finalParams).then(ret => { |
308 | if (ret && ret.code === 200) { | 297 | if (ret && ret.code === 200) { |
309 | 298 | ||
310 | cache.set(cKey, ret.data, 3600); | 299 | cache.set(cKey, ret.data, 3600); |
@@ -438,7 +427,7 @@ const getSuggest = (params) => { | @@ -438,7 +427,7 @@ const getSuggest = (params) => { | ||
438 | keyword: params.keyword || '' | 427 | keyword: params.keyword || '' |
439 | }; | 428 | }; |
440 | 429 | ||
441 | - return yohoApi.get('', finalParams); | 430 | + return api.get('', finalParams); |
442 | }; | 431 | }; |
443 | 432 | ||
444 | 433 | ||
@@ -452,7 +441,7 @@ const getBrandData = (params) => { | @@ -452,7 +441,7 @@ const getBrandData = (params) => { | ||
452 | domain: params.domain || '' | 441 | domain: params.domain || '' |
453 | }; | 442 | }; |
454 | 443 | ||
455 | - return yohoApi.get('', finalParams); | 444 | + return api.get('', finalParams); |
456 | }; | 445 | }; |
457 | 446 | ||
458 | /** | 447 | /** |
@@ -477,7 +466,7 @@ const getShopInfo = (shopId, uid) => { | @@ -477,7 +466,7 @@ const getShopInfo = (shopId, uid) => { | ||
477 | uid: uid || 0 | 466 | uid: uid || 0 |
478 | }; | 467 | }; |
479 | 468 | ||
480 | - return yohoApi.get('', finalParams); | 469 | + return api.get('', finalParams); |
481 | 470 | ||
482 | }; | 471 | }; |
483 | 472 | ||
@@ -485,15 +474,14 @@ const getShopInfo = (shopId, uid) => { | @@ -485,15 +474,14 @@ const getShopInfo = (shopId, uid) => { | ||
485 | * 查询店铺下面的所有品牌 | 474 | * 查询店铺下面的所有品牌 |
486 | */ | 475 | */ |
487 | const getShopBrands = (shopId) => { | 476 | const getShopBrands = (shopId) => { |
488 | - | ||
489 | - return yohoApi.get('', {method: 'app.shops.getShopsBrands', shop_id: shopId || 0}); | 477 | + return api.get('', {method: 'app.shops.getShopsBrands', shop_id: shopId || 0}); |
490 | }; | 478 | }; |
491 | 479 | ||
492 | /** | 480 | /** |
493 | * 查询店铺装修 | 481 | * 查询店铺装修 |
494 | */ | 482 | */ |
495 | const getShopDecorator = (shopId) => { | 483 | const getShopDecorator = (shopId) => { |
496 | - return yohoApi.get('', {method: 'app.shopsdecorator.getList', shop_id: shopId || 0}); | 484 | + return api.get('', {method: 'app.shopsdecorator.getList', shop_id: shopId || 0}); |
497 | }; | 485 | }; |
498 | 486 | ||
499 | /** | 487 | /** |
@@ -515,7 +503,7 @@ const getBrands4Filter = (params) => { | @@ -515,7 +503,7 @@ const getBrands4Filter = (params) => { | ||
515 | method: 'web.regular.aggBrand' | 503 | method: 'web.regular.aggBrand' |
516 | }; | 504 | }; |
517 | 505 | ||
518 | - return yohoApi.get('', Object.assign({}, params, finalParams)); | 506 | + return api.get('', Object.assign(params, finalParams)); |
519 | }; | 507 | }; |
520 | 508 | ||
521 | module.exports = { | 509 | module.exports = { |
@@ -1249,7 +1249,7 @@ exports.handleBrandBanner = (data) => { | @@ -1249,7 +1249,7 @@ exports.handleBrandBanner = (data) => { | ||
1249 | }; | 1249 | }; |
1250 | 1250 | ||
1251 | /** | 1251 | /** |
1252 | - * 处理品牌系列 | 1252 | + * 处理品牌系列folder_id |
1253 | * @type {[type]} | 1253 | * @type {[type]} |
1254 | */ | 1254 | */ |
1255 | exports.handleFolderData = (data) => { | 1255 | exports.handleFolderData = (data) => { |
@@ -1266,6 +1266,23 @@ exports.handleFolderData = (data) => { | @@ -1266,6 +1266,23 @@ exports.handleFolderData = (data) => { | ||
1266 | }; | 1266 | }; |
1267 | 1267 | ||
1268 | /** | 1268 | /** |
1269 | + * 处理品牌系列series | ||
1270 | + * @type {[type]} | ||
1271 | + */ | ||
1272 | +exports.handleSeriesData = (data) => { | ||
1273 | + let dest = []; | ||
1274 | + | ||
1275 | + _.forEach(data, (value) => { | ||
1276 | + dest.push({ | ||
1277 | + href: '?series=' + value.id, | ||
1278 | + src: value.series_banner | ||
1279 | + }); | ||
1280 | + }); | ||
1281 | + | ||
1282 | + return dest; | ||
1283 | +}; | ||
1284 | + | ||
1285 | +/** | ||
1269 | * 筛选类链接处理的对外接口 | 1286 | * 筛选类链接处理的对外接口 |
1270 | * @type {[type]} | 1287 | * @type {[type]} |
1271 | */ | 1288 | */ |
@@ -16,6 +16,14 @@ const newProductsName = '新品上架 NEW'; | @@ -16,6 +16,14 @@ const newProductsName = '新品上架 NEW'; | ||
16 | const hotProductsName = '人气单品 HOT'; | 16 | const hotProductsName = '人气单品 HOT'; |
17 | const shopListUrl = '/product/shoplist'; | 17 | const shopListUrl = '/product/shoplist'; |
18 | 18 | ||
19 | +exports.setShopSeo = (shopName) => { | ||
20 | + return { | ||
21 | + title: `${shopName} | ${shopName} 潮流服装服饰-Yoho!Buy有货`, | ||
22 | + keywords: `${shopName},${shopName} 服装服饰,${shopName} 潮流服装服饰`, | ||
23 | + description: `${shopName} | Yoho!Buy有货 ${shopName} 潮流服饰官方授权店!100%品牌正品保证,支持货到付款。` | ||
24 | + }; | ||
25 | +}; | ||
26 | + | ||
19 | /** | 27 | /** |
20 | * 新品上架 | 28 | * 新品上架 |
21 | */ | 29 | */ |
@@ -59,6 +59,9 @@ router.post('/detail/consult', auth, detail.createConsult);// 创建咨询 | @@ -59,6 +59,9 @@ router.post('/detail/consult', auth, detail.createConsult);// 创建咨询 | ||
59 | router.get('/detail/hotarea', detail.indexHotArea);// 商品热区 | 59 | router.get('/detail/hotarea', detail.indexHotArea);// 商品热区 |
60 | router.post('/index/favoriteBrand', favorite.changeFavoriteBrand);// 收藏品牌 | 60 | router.post('/index/favoriteBrand', favorite.changeFavoriteBrand);// 收藏品牌 |
61 | router.post('/item/togglecollect', favorite.collectProduct); // 收藏商品 | 61 | router.post('/item/togglecollect', favorite.collectProduct); // 收藏商品 |
62 | +router.get('/detail/header', detail.productHeader); // 价格数据重新获取接口 | ||
63 | +router.get('/detail/return', detail.detailReturn);// 特殊商品退换货 | ||
64 | +router.get('/index/isfav', favorite.isFavoriteBrand);// 品牌收藏状态 | ||
62 | 65 | ||
63 | // 搜索 | 66 | // 搜索 |
64 | router.get('/search/index', search.index); | 67 | router.get('/search/index', search.index); |
@@ -23,7 +23,8 @@ | @@ -23,7 +23,8 @@ | ||
23 | {{> common/path-nav}} | 23 | {{> common/path-nav}} |
24 | 24 | ||
25 | {{# goodsInfo}} | 25 | {{# goodsInfo}} |
26 | - <div class="main clearfix" data-skn="{{skn}}" data-id="{{productId}}"> | 26 | + <div class="main clearfix" data-skn="{{skn}}" data-id="{{productId}}" data-md5="{{md5}}" |
27 | + data-skn="{{skn}}"> | ||
27 | <div class="pull-left imgs clearfix"> | 28 | <div class="pull-left imgs clearfix"> |
28 | <div class="pull-left img"> | 29 | <div class="pull-left img"> |
29 | <div class="tags clearfix"> | 30 | <div class="tags clearfix"> |
@@ -540,12 +541,20 @@ | @@ -540,12 +541,20 @@ | ||
540 | <span class="title cur">商品详情 DETAILS</span> | 541 | <span class="title cur">商品详情 DETAILS</span> |
541 | </p> | 542 | </p> |
542 | <div id="details-html" class="details-html"> | 543 | <div id="details-html" class="details-html"> |
544 | + <div class="lazy-load-object"> | ||
545 | + <textarea class="datalazyload" style="visibility: hidden;"> | ||
546 | + <script> | ||
547 | + fetchHotArea(); | ||
548 | + </script> | ||
549 | + </textarea> | ||
550 | + </div> | ||
543 | {{{details}}} | 551 | {{{details}}} |
544 | </div> | 552 | </div> |
545 | </div> | 553 | </div> |
546 | 554 | ||
547 | {{# consultComment}} | 555 | {{# consultComment}} |
548 | <div class="consult-comment info-block"> | 556 | <div class="consult-comment info-block"> |
557 | + | ||
549 | <p class="block-title"> | 558 | <p class="block-title"> |
550 | <span class="title">顾客咨询(<em class="consult-num">0</em>)</span> | 559 | <span class="title">顾客咨询(<em class="consult-num">0</em>)</span> |
551 | <span class="sep">|</span> | 560 | <span class="sep">|</span> |
@@ -561,7 +570,7 @@ | @@ -561,7 +570,7 @@ | ||
561 | </span> | 570 | </span> |
562 | </p> | 571 | </p> |
563 | <p class="btn-wrap"> | 572 | <p class="btn-wrap"> |
564 | - <a class="btn" href="{{commentUrl}}" target="_blank"> | 573 | + <a class="btn" href="//www.yohobuy.com/home/comment" target="_blank"> |
565 | <i class="iconfont"></i> | 574 | <i class="iconfont"></i> |
566 | 我要评论 | 575 | 我要评论 |
567 | </a> | 576 | </a> |
@@ -599,6 +608,16 @@ | @@ -599,6 +608,16 @@ | ||
599 | </p> | 608 | </p> |
600 | </div> | 609 | </div> |
601 | </div> | 610 | </div> |
611 | + | ||
612 | + <div class="lazy-load-object"> | ||
613 | + <textarea class="datalazyload" style="visibility: hidden;"> | ||
614 | + <script> | ||
615 | + fetchComment(); | ||
616 | + fetchReturn(); | ||
617 | + </script> | ||
618 | + </textarea> | ||
619 | + </div> | ||
620 | + | ||
602 | </div> | 621 | </div> |
603 | {{/ consultComment}} | 622 | {{/ consultComment}} |
604 | 623 | ||
@@ -635,11 +654,8 @@ | @@ -635,11 +654,8 @@ | ||
635 | </div> | 654 | </div> |
636 | </div> | 655 | </div> |
637 | 656 | ||
638 | - {{#if supportSaleReturnedService}} | ||
639 | - <div class="support-saleReturned-service"></div> | ||
640 | - {{^}} | ||
641 | - <div class="not-support-saleReturned-service"></div> | ||
642 | - {{/if}} | 657 | + <div id="saleReturn" class="support-saleReturned-service"></div> |
658 | + | ||
643 | 659 | ||
644 | <div class="service"></div> | 660 | <div class="service"></div> |
645 | {{#if latestWalk}} | 661 | {{#if latestWalk}} |
@@ -649,7 +665,7 @@ | @@ -649,7 +665,7 @@ | ||
649 | <span class="title cur">最近浏览 RECENT REVIEW</span> | 665 | <span class="title cur">最近浏览 RECENT REVIEW</span> |
650 | </p> | 666 | </p> |
651 | <div id="latest-walk-goods" class="goods clearfix"></div> | 667 | <div id="latest-walk-goods" class="goods clearfix"></div> |
652 | - {{> product/latest-walk}} | 668 | + {{> product/latest-walk-tpl}} |
653 | </div> | 669 | </div> |
654 | {{/if}} | 670 | {{/if}} |
655 | </div> | 671 | </div> |
@@ -724,7 +740,8 @@ | @@ -724,7 +740,8 @@ | ||
724 | 740 | ||
725 | (function() { | 741 | (function() { |
726 | var mvl = document.createElement('script'); | 742 | var mvl = document.createElement('script'); |
727 | - mvl.type = 'text/javascript'; mvl.async = true; | 743 | + mvl.type = 'text/javascript'; |
744 | + mvl.async = true; | ||
728 | mvl.src = ('https:' == document.location.protocol ? 'https://static-ssl.mediav.com/mvl.js' : 'http://static.mediav.com/mvl.js'); | 745 | mvl.src = ('https:' == document.location.protocol ? 'https://static-ssl.mediav.com/mvl.js' : 'http://static.mediav.com/mvl.js'); |
729 | var s = document.getElementsByTagName('script')[0]; | 746 | var s = document.getElementsByTagName('script')[0]; |
730 | s.parentNode.insertBefore(mvl, s); | 747 | s.parentNode.insertBefore(mvl, s); |
@@ -732,13 +749,3 @@ | @@ -732,13 +749,3 @@ | ||
732 | </script> | 749 | </script> |
733 | {{/statGoodsInfo}} | 750 | {{/statGoodsInfo}} |
734 | 751 | ||
735 | -<script type="text/javascript"> | ||
736 | - (function() { | ||
737 | - try { | ||
738 | - var timestamp = (new Date()).valueOf(); | ||
739 | - var view = document.createElement('img'); | ||
740 | - view.src = 'http://shopping.yohobuy.com/1.jpg?t=' + timestamp; | ||
741 | - } catch (e) { | ||
742 | - } | ||
743 | - })(); | ||
744 | -</script> |
@@ -18,7 +18,7 @@ | @@ -18,7 +18,7 @@ | ||
18 | <a name="stu-rights"> | 18 | <a name="stu-rights"> |
19 | <h2 class="floor-title">学生权益</h2> | 19 | <h2 class="floor-title">学生权益</h2> |
20 | </a> | 20 | </a> |
21 | - <span id="rights-dia" class="floor-more">更多细则 ></span> | 21 | + <span id="rights-dia" class="floor-more">全部权益 ></span> |
22 | </div> | 22 | </div> |
23 | <div class="commodity-list clearfix"> | 23 | <div class="commodity-list clearfix"> |
24 | {{> students/stu-rights}} | 24 | {{> students/stu-rights}} |
1 | -<script id="latest-walk-tpl" type="text/html"> | ||
2 | - \{{# latestWalk}} | ||
3 | - <div class="good"> | ||
4 | - <a href="\{{href}}" target="_blank"> | ||
5 | - <img class="lazy" data-original="\{{img}}"> | ||
6 | - </a> | ||
7 | - <a class="name" href="\{{href}}" target="_blank">\{{name}}</a> | ||
8 | - <p class="price"> | ||
9 | - <span class="market-price">\{{marketPrice}}</span> | ||
10 | - <span class="sale-price">\{{salePrice}}</span> | ||
11 | - </p> | ||
12 | - </div> | ||
13 | - \{{/ latestWalk}} | ||
14 | -</script> |
1 | -<div class="stu-rights clearfix"> | 1 | +<div id="stuRights" class="stu-rights clearfix"> |
2 | {{#rightsItem}} | 2 | {{#rightsItem}} |
3 | <div class="stu-rights-item"> | 3 | <div class="stu-rights-item"> |
4 | <img class="" src="{{image src 300 300}}"> | 4 | <img class="" src="{{image src 300 300}}"> |
5 | </img> | 5 | </img> |
6 | </div> | 6 | </div> |
7 | {{/rightsItem}} | 7 | {{/rightsItem}} |
8 | -</div> | ||
8 | +</div> |
@@ -36,8 +36,7 @@ module.exports = { | @@ -36,8 +36,7 @@ module.exports = { | ||
36 | master: ['127.0.0.1:11211'], | 36 | master: ['127.0.0.1:11211'], |
37 | slave: ['127.0.0.1:11211'], | 37 | slave: ['127.0.0.1:11211'], |
38 | session: ['127.0.0.1:11211'], | 38 | session: ['127.0.0.1:11211'], |
39 | - reconnect: 5000, | ||
40 | - timeout: 100, | 39 | + timeout: 1000, |
41 | retries: 0 | 40 | retries: 0 |
42 | }, | 41 | }, |
43 | interfaceShunt: { | 42 | interfaceShunt: { |
@@ -116,9 +115,8 @@ if (isProduction) { | @@ -116,9 +115,8 @@ if (isProduction) { | ||
116 | master: ['127.0.0.1:12111'], | 115 | master: ['127.0.0.1:12111'], |
117 | slave: ['127.0.0.1:12112'], | 116 | slave: ['127.0.0.1:12112'], |
118 | session: ['127.0.0.1:12111'], | 117 | session: ['127.0.0.1:12111'], |
119 | - timeout: 100, | ||
120 | - retries: 0, | ||
121 | - reconnect: 5000 | 118 | + timeout: 1000, |
119 | + retries: 0 | ||
122 | } | 120 | } |
123 | }); | 121 | }); |
124 | } | 122 | } |
@@ -7,6 +7,7 @@ | @@ -7,6 +7,7 @@ | ||
7 | module.exports = app => { | 7 | module.exports = app => { |
8 | 8 | ||
9 | // 公共服务 | 9 | // 公共服务 |
10 | + app.use('/common', require('./apps/common')); | ||
10 | 11 | ||
11 | // 业务模块 | 12 | // 业务模块 |
12 | app.use(require('./apps/channel')); // 频道页 | 13 | app.use(require('./apps/channel')); // 频道页 |
@@ -14,5 +15,7 @@ module.exports = app => { | @@ -14,5 +15,7 @@ module.exports = app => { | ||
14 | app.use('/product', require('./apps/product')); // 商品相关页面 | 15 | app.use('/product', require('./apps/product')); // 商品相关页面 |
15 | app.use(require('./apps/passport')); // 登录注册 | 16 | app.use(require('./apps/passport')); // 登录注册 |
16 | app.use('/home', require('./apps/home')); // 会员中心 | 17 | app.use('/home', require('./apps/home')); // 会员中心 |
18 | + app.use('/brands', require('./apps/brands')); | ||
17 | app.use('/guang', require('./apps/guang')); | 19 | app.use('/guang', require('./apps/guang')); |
20 | + app.use('/cart', require('./apps/cart'));// 购物车 | ||
18 | }; | 21 | }; |
@@ -52,10 +52,13 @@ const getNavBar = (data, type) => { | @@ -52,10 +52,13 @@ const getNavBar = (data, type) => { | ||
52 | let obj = {}; | 52 | let obj = {}; |
53 | let lowEn = _.camelCase(item.sort_name_en).toLowerCase(); | 53 | let lowEn = _.camelCase(item.sort_name_en).toLowerCase(); |
54 | 54 | ||
55 | - obj.link = item.sort_url; | ||
56 | - obj.cn = item.sort_name; | ||
57 | - obj.en = item.sort_name_en; | ||
58 | - obj.isNewPage = item.is_new_page === 'Y' ? true : false; | 55 | + Object.assign(obj, { |
56 | + type: lowEn, | ||
57 | + link: item.sort_url, | ||
58 | + cn: item.sort_name, | ||
59 | + en: item.sort_name_en, | ||
60 | + isNewPage: item.is_new_page === 'Y' | ||
61 | + }); | ||
59 | 62 | ||
60 | if (type === lowEn) { | 63 | if (type === lowEn) { |
61 | obj.active = true; | 64 | obj.active = true; |
@@ -135,30 +138,38 @@ const getThirdNav = (data) => { | @@ -135,30 +138,38 @@ const getThirdNav = (data) => { | ||
135 | * @param {String} type 频道类型 | 138 | * @param {String} type 频道类型 |
136 | * @return {array} 子菜单数组 | 139 | * @return {array} 子菜单数组 |
137 | */ | 140 | */ |
138 | -const getSubNav = (data, type) => { | ||
139 | - let subNav = []; | 141 | +const getSubNavGroup = (data, type) => { |
142 | + let subNavGroup = []; | ||
140 | 143 | ||
141 | _.forEach(data, it => { | 144 | _.forEach(data, it => { |
142 | - if (type === _.camelCase(it.sort_name_en).toLowerCase()) { | ||
143 | - _.forEach(it.sub, item => { | ||
144 | - let obj = {}; | ||
145 | - | ||
146 | - obj.link = item.sort_url; | ||
147 | - obj.name = item.sort_name; | ||
148 | - obj.isHot = item.is_hot === 'Y' ? true : false; | ||
149 | - obj.isNew = item.is_new === 'Y' ? true : false; | ||
150 | - | ||
151 | - if (item.sub) { | ||
152 | - obj.thirdNav = getThirdNav(item.sub); | ||
153 | - obj.imgCode = item.content_code; | ||
154 | - } | ||
155 | - | ||
156 | - subNav.push(obj); | ||
157 | - }); | ||
158 | - } | 145 | + let subNav = []; |
146 | + | ||
147 | + _.forEach(it.sub, item => { | ||
148 | + let obj = {}; | ||
149 | + | ||
150 | + obj.link = item.sort_url; | ||
151 | + obj.name = item.sort_name; | ||
152 | + obj.isHot = item.is_hot === 'Y' ? true : false; | ||
153 | + obj.isNew = item.is_new === 'Y' ? true : false; | ||
154 | + | ||
155 | + if (item.sub) { | ||
156 | + obj.thirdNav = getThirdNav(item.sub); | ||
157 | + obj.imgCode = item.content_code; | ||
158 | + } | ||
159 | + | ||
160 | + subNav.push(obj); | ||
161 | + }); | ||
162 | + | ||
163 | + let lowEn = _.camelCase(it.sort_name_en).toLowerCase(); | ||
164 | + | ||
165 | + subNavGroup.push({ | ||
166 | + subType: lowEn, | ||
167 | + subNav: subNav, | ||
168 | + active: lowEn === type | ||
169 | + }); | ||
159 | }); | 170 | }); |
160 | 171 | ||
161 | - return subNav; | 172 | + return subNavGroup; |
162 | }; | 173 | }; |
163 | 174 | ||
164 | 175 | ||
@@ -174,7 +185,7 @@ const setHeaderData = (resData, type) => ( | @@ -174,7 +185,7 @@ const setHeaderData = (resData, type) => ( | ||
174 | headType: type, | 185 | headType: type, |
175 | yohoGroup: getMenuData(), | 186 | yohoGroup: getMenuData(), |
176 | navbars: resData ? getNavBar(resData, type) : [], | 187 | navbars: resData ? getNavBar(resData, type) : [], |
177 | - subNav: resData ? getSubNav(resData, type) : [] | 188 | + subNavGroup: resData ? getSubNavGroup(resData, type) : [] |
178 | } | 189 | } |
179 | ); | 190 | ); |
180 | 191 |
1 | {{# headerData}} | 1 | {{# headerData}} |
2 | - <div class="yoho-header {{headType}}"> | 2 | + <div id="yoho-header" class="yoho-header" data-type="{{headType}}"> |
3 | <div class="tool-wrapper clearfix"> | 3 | <div class="tool-wrapper clearfix"> |
4 | <div class="center-content"> | 4 | <div class="center-content"> |
5 | <div class="yoho-group-map left"> | 5 | <div class="yoho-group-map left"> |
@@ -19,8 +19,8 @@ | @@ -19,8 +19,8 @@ | ||
19 | <ul> | 19 | <ul> |
20 | <li id="loginBox"> | 20 | <li id="loginBox"> |
21 | <span class="hi">Hi~</span> | 21 | <span class="hi">Hi~</span> |
22 | - [ <a href="//www.yohobuy.com/signin.html" class="loginbar">请登录</a> ] | ||
23 | - [ <a href="//www.yohobuy.com/reg.html" class="registbar">免费注册</a> ] | 22 | + [ <a id="signin-url" href="//www.yohobuy.com/signin.html" class="loginbar">请登录</a> ] |
23 | + [ <a id="reg-url" href="//www.yohobuy.com/reg.html" class="registbar">免费注册</a> ] | ||
24 | </li> | 24 | </li> |
25 | <li class="myyoho" id="myYohoBox"> | 25 | <li class="myyoho" id="myYohoBox"> |
26 | <span class="tag-seprate"></span> | 26 | <span class="tag-seprate"></span> |
@@ -66,7 +66,7 @@ | @@ -66,7 +66,7 @@ | ||
66 | <div class="main-logo"><a href="//www.yohobuy.com/" class="main-link"></a></div> | 66 | <div class="main-logo"><a href="//www.yohobuy.com/" class="main-link"></a></div> |
67 | <ul class="main-nav-list"> | 67 | <ul class="main-nav-list"> |
68 | {{# navbars}} | 68 | {{# navbars}} |
69 | - <li {{#if active}} class="cure"{{/if}}{{#if ico}} style="background: url({{image ico 54 32}}) no-repeat center center"{{/if}}> | 69 | + <li class="{{type}}"{{#if ico}} style="background: url({{image ico 54 32}}) no-repeat center center"{{/if}}> |
70 | {{#if ico}} | 70 | {{#if ico}} |
71 | <a href="{{link}}"{{#if isNewPage}} target="_blank"{{/if}} class="menu-ico"></a> | 71 | <a href="{{link}}"{{#if isNewPage}} target="_blank"{{/if}} class="menu-ico"></a> |
72 | {{^}} | 72 | {{^}} |
@@ -80,7 +80,7 @@ | @@ -80,7 +80,7 @@ | ||
80 | </li> | 80 | </li> |
81 | {{/ navbars}} | 81 | {{/ navbars}} |
82 | </ul> | 82 | </ul> |
83 | - <div class="func-area"> | 83 | + <div class="func-area hide"> |
84 | <ul class="search-suggest"></ul> | 84 | <ul class="search-suggest"></ul> |
85 | <div class="search-2016"> | 85 | <div class="search-2016"> |
86 | <form action="//search.yohobuy.com" method="get" id="search-form"> | 86 | <form action="//search.yohobuy.com" method="get" id="search-form"> |
@@ -108,7 +108,8 @@ | @@ -108,7 +108,8 @@ | ||
108 | </div> | 108 | </div> |
109 | <div class="nav-wrapper clearfix"> | 109 | <div class="nav-wrapper clearfix"> |
110 | <div class="center-content"> | 110 | <div class="center-content"> |
111 | - <ul class="sub-nav-list"> | 111 | + {{# subNavGroup}} |
112 | + <ul class="sub-nav-list {{subType}}"> | ||
112 | {{# subNav}} | 113 | {{# subNav}} |
113 | <li {{#if thirdNav}}class="contain-third"{{/if}}> | 114 | <li {{#if thirdNav}}class="contain-third"{{/if}}> |
114 | <a href="{{link}}">{{name}} | 115 | <a href="{{link}}">{{name}} |
@@ -141,6 +142,7 @@ | @@ -141,6 +142,7 @@ | ||
141 | </li> | 142 | </li> |
142 | {{/ subNav}} | 143 | {{/ subNav}} |
143 | </ul> | 144 | </ul> |
145 | + {{/ subNavGroup}} | ||
144 | </div> | 146 | </div> |
145 | </div> | 147 | </div> |
146 | </div> | 148 | </div> |
@@ -272,4 +274,4 @@ | @@ -272,4 +274,4 @@ | ||
272 | </div> | 274 | </div> |
273 | 275 | ||
274 | <input id="api-domain" type="hidden" value="{{apiDomain}}"> | 276 | <input id="api-domain" type="hidden" value="{{apiDomain}}"> |
275 | -{{/ headerData}} | ||
277 | +{{/ headerData}} |
@@ -11,4 +11,9 @@ | @@ -11,4 +11,9 @@ | ||
11 | </p> | 11 | </p> |
12 | </div> | 12 | </div> |
13 | \{{/ latestWalk}} | 13 | \{{/ latestWalk}} |
14 | -</script> | ||
14 | +</script> | ||
15 | +<div class="lazy-load-object"> | ||
16 | + <textarea class="latest-walk-datalazyload" style="visibility: hidden;"> | ||
17 | + <script> fetchLatestWalk(); </script> | ||
18 | + </textarea> | ||
19 | +</div> |
@@ -39,6 +39,7 @@ | @@ -39,6 +39,7 @@ | ||
39 | "express": "^4.13.1", | 39 | "express": "^4.13.1", |
40 | "handlebars": "^4.0.5", | 40 | "handlebars": "^4.0.5", |
41 | "express-handlebars": "^3.0.0", | 41 | "express-handlebars": "^3.0.0", |
42 | + "express-session": "^1.13.0", | ||
42 | "influxdb-winston": "^1.0.1", | 43 | "influxdb-winston": "^1.0.1", |
43 | "lodash": "^4.13.1", | 44 | "lodash": "^4.13.1", |
44 | "md5": "^2.1.0", | 45 | "md5": "^2.1.0", |
@@ -103,7 +104,6 @@ | @@ -103,7 +104,6 @@ | ||
103 | "yoho-handlebars": "^4.0.5", | 104 | "yoho-handlebars": "^4.0.5", |
104 | "yoho-jquery": "^1.12.4", | 105 | "yoho-jquery": "^1.12.4", |
105 | "yoho-jquery-lazyload": "^1.9.7", | 106 | "yoho-jquery-lazyload": "^1.9.7", |
106 | - "yoho-jquery-pjax": "0.0.1", | ||
107 | "yoho-jquery-placeholder": "^2.3.1", | 107 | "yoho-jquery-placeholder": "^2.3.1", |
108 | "yoho-slider": "0.0.2", | 108 | "yoho-slider": "0.0.2", |
109 | "yoho-jquery-dotdotdot": "0.0.1", | 109 | "yoho-jquery-dotdotdot": "0.0.1", |
public/js/activity/coupon.page.js
0 → 100644
1 | +/** | ||
2 | + * 领券频道 | ||
3 | + * @author: 赵彪<bill.zhao@yoho.cn> | ||
4 | + * @date: 2016/04/14 | ||
5 | + */ | ||
6 | +var $ = require('yoho-jquery'), | ||
7 | + lazyLoad = require('yoho-jquery-lazyload'), | ||
8 | + Dialog = require('../common/dialog').Dialog; | ||
9 | + | ||
10 | + | ||
11 | +var alertConfig, | ||
12 | + makeAlert; | ||
13 | + | ||
14 | +// j面跳转对象 | ||
15 | +var redirect = { | ||
16 | + | ||
17 | + // 去逛逛跳转链接 | ||
18 | + gunangSrc: null, | ||
19 | + | ||
20 | + // 查看优惠券跳转链接 | ||
21 | + checkCouponSrc: null, | ||
22 | + goToGuang: function() { | ||
23 | + window.location.href = this.gunangSrc; | ||
24 | + }, | ||
25 | + goToCheck: function() { | ||
26 | + window.location.href = this.checkCouponSrc; | ||
27 | + }, | ||
28 | + 200: function(url) { | ||
29 | + this.checkCouponSrc = url; | ||
30 | + } | ||
31 | +}; | ||
32 | + | ||
33 | +require('../common'); | ||
34 | +require('../plugins/slider'); | ||
35 | + | ||
36 | +// 加载底部图片 | ||
37 | +lazyLoad($('img.lazy')); | ||
38 | +$('.slide-container').slider(); | ||
39 | + | ||
40 | +// 根据配置执行展示弹窗 | ||
41 | +function couponAlert(opt) { | ||
42 | + var newAlert = new Dialog(opt); | ||
43 | + | ||
44 | + newAlert.show(); | ||
45 | +} | ||
46 | + | ||
47 | +// 配置弹窗 | ||
48 | +alertConfig = { | ||
49 | + success: { | ||
50 | + content: '恭喜您,成功领取优惠券', | ||
51 | + subContents: ['特殊情况下到账有延时', '请耐心等待'], | ||
52 | + className: 'subcontent-dialog', | ||
53 | + refreshOnClose: true, | ||
54 | + btns: [{ | ||
55 | + id: 1, | ||
56 | + name: '去购物啦', | ||
57 | + btnClass: ['black', 'btn-close'], | ||
58 | + cb: function() { | ||
59 | + redirect.goToGuang(); | ||
60 | + } | ||
61 | + }, { | ||
62 | + id: 2, | ||
63 | + name: '查看优惠券', | ||
64 | + btnClass: ['btn-close'], | ||
65 | + cb: function() { | ||
66 | + redirect.goToCheck(); | ||
67 | + } | ||
68 | + }] | ||
69 | + }, | ||
70 | + alreadyGot: { | ||
71 | + content: '您已领取过优惠券', | ||
72 | + subContent: '快去选购心仪的潮品吧', | ||
73 | + className: 'subcontent-dialog', | ||
74 | + btns: [{ | ||
75 | + id: 1, | ||
76 | + name: '去使用', | ||
77 | + btnClass: ['btn-close'], | ||
78 | + cb: function() { | ||
79 | + redirect.goToGuang(); | ||
80 | + } | ||
81 | + }] | ||
82 | + }, | ||
83 | + expired: { | ||
84 | + content: '优惠券已过期', | ||
85 | + subContent: '去领最新的优惠券吧', | ||
86 | + className: 'subcontent-dialog', | ||
87 | + btns: [{ | ||
88 | + id: 1, | ||
89 | + name: '关闭', | ||
90 | + btnClass: ['btn-close'] | ||
91 | + }] | ||
92 | + }, | ||
93 | + paramerror: { | ||
94 | + content: '请求参数出错', | ||
95 | + subContents: ['请检查参数后重试'], | ||
96 | + className: 'subcontent-dialog', | ||
97 | + btns: [{ | ||
98 | + id: 1, | ||
99 | + name: '关闭', | ||
100 | + btnClass: ['btn-close'] | ||
101 | + }] | ||
102 | + }, | ||
103 | + failed: { | ||
104 | + content: '领取失败', | ||
105 | + subContents: ['请刷新重试,', '多次无效请联系客服'], | ||
106 | + className: 'subcontent-dialog', | ||
107 | + btns: [{ | ||
108 | + id: 1, | ||
109 | + name: '刷新', | ||
110 | + btnClass: ['btn-close'], | ||
111 | + cb: function() { | ||
112 | + window.location.reload(); | ||
113 | + } | ||
114 | + }] | ||
115 | + } | ||
116 | +}; | ||
117 | + | ||
118 | +// 对应不同的网络返回码展示不同的弹窗 | ||
119 | +makeAlert = { | ||
120 | + 200: function() { | ||
121 | + couponAlert(alertConfig.success); | ||
122 | + }, | ||
123 | + 401: function() { | ||
124 | + couponAlert(alertConfig.alreadyGot); | ||
125 | + }, | ||
126 | + 315: function() { | ||
127 | + couponAlert(alertConfig.expired); | ||
128 | + }, | ||
129 | + 300: function() { | ||
130 | + couponAlert(alertConfig.paramerror); | ||
131 | + }, | ||
132 | + 500: function() { | ||
133 | + couponAlert(alertConfig.failed); | ||
134 | + } | ||
135 | +}; | ||
136 | + | ||
137 | +function requestCoupon(id) { | ||
138 | + $.ajax({ | ||
139 | + type: 'GET', | ||
140 | + url: '/coupon/sendcoupon', | ||
141 | + data: { | ||
142 | + id: id | ||
143 | + }, | ||
144 | + success: function(res) { | ||
145 | + var code = res.code; | ||
146 | + | ||
147 | + if (code === 400) { | ||
148 | + window.location.href = res.data.refer; // 未登录情况下,跳转到登录页 | ||
149 | + return; | ||
150 | + } | ||
151 | + | ||
152 | + // 如果返回的数据里有url,则执行redirect里的方法 | ||
153 | + res.url && res.url.length > 0 && redirect[code] && redirect[code](res.url + '?' + location.href.split('?')[1]); | ||
154 | + | ||
155 | + // 如果能找到对应code则执行相应方法,如果没有的对应code则执行error提示 | ||
156 | + makeAlert[code] ? makeAlert[code]() : makeAlert['500'](); | ||
157 | + }, | ||
158 | + error: function() { | ||
159 | + var Alert = require('../common/dialog').Alert; | ||
160 | + | ||
161 | + new Alert('网络异常').show(); | ||
162 | + } | ||
163 | + }); | ||
164 | +} | ||
165 | + | ||
166 | +function getCouponStatus() { | ||
167 | + var hash, | ||
168 | + data = {}, | ||
169 | + search = window.location.search, | ||
170 | + hashes = search ? decodeURIComponent(search).slice(1).split('&') : []; | ||
171 | + | ||
172 | + for (i = 0; i < hashes.length; i++) { | ||
173 | + hash = hashes[i].split('='); | ||
174 | + data[hash[0]] = hash[1]; | ||
175 | + } | ||
176 | + | ||
177 | + if (!data.contentCode) { | ||
178 | + return; | ||
179 | + } | ||
180 | + | ||
181 | + $.ajax({ | ||
182 | + type: 'GET', | ||
183 | + url: '/coupon/couponstatus', | ||
184 | + data: data, | ||
185 | + success: function(res) { | ||
186 | + if (res.code === 200) { | ||
187 | + var cates = res.categories || []; | ||
188 | + | ||
189 | + cates.forEach(function(obj) { | ||
190 | + var e = document.getElementById(obj.id); | ||
191 | + var child = e.children; | ||
192 | + | ||
193 | + if (!child.length) { | ||
194 | + return; | ||
195 | + } | ||
196 | + | ||
197 | + e.classList.remove('enable'); | ||
198 | + | ||
199 | + for (var i = 0; i < child.length; i++) { | ||
200 | + if (child[i].className === 'normal') { | ||
201 | + child[i].classList.add('hidden'); | ||
202 | + } | ||
203 | + | ||
204 | + if ((obj.got && child[i].className.indexOf('got') > -1) || (obj.empty && child[i].className.indexOf('empty') > -1)) { | ||
205 | + child[i].classList.remove('hidden'); | ||
206 | + } | ||
207 | + } | ||
208 | + }) | ||
209 | + } | ||
210 | + } | ||
211 | + }); | ||
212 | +} | ||
213 | + | ||
214 | +// 获取领券状态 | ||
215 | +getCouponStatus(); | ||
216 | + | ||
217 | +$('.info').on('click', function(e) { | ||
218 | + if (this.className.indexOf('enable') > -1) { | ||
219 | + e.preventDefault(); | ||
220 | + requestCoupon($(this).closest('a').data('id')); | ||
221 | + redirect.gunangSrc = $(this).closest('a').get(0).href; | ||
222 | + } | ||
223 | +}); |
public/js/brands/brands.page.js
0 → 100644
1 | +/** | ||
2 | + * 首页 | ||
3 | + * @author: xuqi<qi.xu@yoho.cn> | ||
4 | + * @date: 2015/11/23 | ||
5 | + */ | ||
6 | + | ||
7 | +var $ = require('yoho-jquery'), | ||
8 | + lazyLoad = require('yoho-jquery-lazyload'); | ||
9 | + | ||
10 | +var Handlebars = require('yoho-handlebars'); | ||
11 | + | ||
12 | +var $tabs = $('.brands-tabs'); | ||
13 | +var $list = $('.brands-list'); | ||
14 | +var $gory = $('.brands-category'); | ||
15 | +var $news = $('.news-txt ul'); | ||
16 | +var $clearfix = $list.find('dl.clearfix'); | ||
17 | +var $brand = $list.find('li>a'); | ||
18 | +var $category = $gory.find('a'); | ||
19 | +var $tab = $tabs.find('li>a'); | ||
20 | +var $arr = $tabs.find('.hoverarr'); | ||
21 | +var $thisTab; | ||
22 | + | ||
23 | +var categoryHeight = $category.height(); | ||
24 | +var categoryTop = $category.offset() ? $category.offset().top : 0; | ||
25 | +var newsHeight = $news.height(); | ||
26 | +var newsTop = $news.offset() ? $news.offset().top : 0; | ||
27 | +var timeout, _id; | ||
28 | + | ||
29 | + | ||
30 | +// 用于临时存储数据 | ||
31 | +var tempdata = {}; | ||
32 | + | ||
33 | +var templete = '<div class="brands-dialog">'; | ||
34 | + | ||
35 | +require('../common'); | ||
36 | +require('yoho-jquery-dotdotdot'); | ||
37 | + | ||
38 | +templete += ' <div class="brands-layer">'; | ||
39 | +templete += ' <div class="layer-content">'; | ||
40 | +templete += ' <div class="title">{{title}}</div>'; | ||
41 | +templete += ' <div class="clearfix desc">'; | ||
42 | +templete += ' <img src="{{icon}}">'; | ||
43 | +templete += ' <p class="right">{{content}}</p>'; | ||
44 | +templete += ' </div> '; | ||
45 | +templete += ' <div class="featured">'; | ||
46 | +templete += ' <p>{{subtitle}}</p> '; | ||
47 | +templete += ' <div class="clearfix"> '; | ||
48 | +templete += ' {{#each imgs}}'; | ||
49 | +templete += ' <img src="{{src}}">'; | ||
50 | +templete += ' {{/each}}'; | ||
51 | +templete += ' </div>'; | ||
52 | +templete += ' </div>'; | ||
53 | +templete += ' </div>'; | ||
54 | +templete += ' </div>'; | ||
55 | +templete += '</div>'; | ||
56 | + | ||
57 | +$('.brand-desc').dotdotdot({ | ||
58 | + wrap: 'letter' | ||
59 | +}); | ||
60 | + | ||
61 | + | ||
62 | +lazyLoad($('img.lazy')); | ||
63 | + | ||
64 | +// $('.slide-container').slider({ | ||
65 | +// orient: true | ||
66 | +// }); | ||
67 | + | ||
68 | +$.easing.easeOutQuint = function(x, t, b, c, d) { | ||
69 | + return c * ((t = t / d - 1) * t * t * t * t + 1) + b; | ||
70 | +}; | ||
71 | + | ||
72 | +function getQueryString(name) { | ||
73 | + var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)'); | ||
74 | + var r = window.location.search.substr(1).match(reg); | ||
75 | + | ||
76 | + if (r !== null) { | ||
77 | + return window.unescape(r[2]); | ||
78 | + } | ||
79 | + return null; | ||
80 | +} | ||
81 | + | ||
82 | +// 格式化资讯NEWS标题数量 | ||
83 | +if ($news.length) { | ||
84 | + $news.find('li').each(function() { | ||
85 | + var $dom = $(this); | ||
86 | + var domHeight = $dom.offset().top - newsTop + $dom.height(); | ||
87 | + | ||
88 | + if (domHeight > newsHeight) { | ||
89 | + $dom.hide(); | ||
90 | + } | ||
91 | + }); | ||
92 | +} | ||
93 | + | ||
94 | +// 头部图片TAB切换展示 | ||
95 | +$tab.eq(0).parent('li').find('.brands-content').css('z-index', '1'); | ||
96 | + | ||
97 | +_id = getQueryString('id') ? getQueryString('id') : 0; | ||
98 | + | ||
99 | +// 设置对应TAB选中 | ||
100 | +$thisTab = $tab.eq(_id); | ||
101 | +$thisTab.find('.g-mask').addClass('g-mask-on'); | ||
102 | + | ||
103 | +if (_id && $thisTab.length) { | ||
104 | + $arr.css({ | ||
105 | + left: parseFloat($thisTab.offset().left) - parseFloat($tabs.offset().left) | ||
106 | + }); | ||
107 | +} | ||
108 | +$tab.hover(function() { | ||
109 | + var $this = $(this); | ||
110 | + | ||
111 | + clearTimeout(timeout); | ||
112 | + timeout = setTimeout(function() { | ||
113 | + var targetLeft = parseFloat($this.offset().left) - parseFloat($tabs.offset().left); | ||
114 | + | ||
115 | + $arr.animate({ | ||
116 | + left: targetLeft | ||
117 | + }, 200, 'easeOutQuint'); | ||
118 | + }, 50); | ||
119 | + $tabs.find('.brands-content').removeAttr('style'); | ||
120 | + $this.parent('li').find('.brands-content').css('z-index', '1'); | ||
121 | + | ||
122 | +}, function() { | ||
123 | + clearTimeout(timeout); | ||
124 | +}); | ||
125 | + | ||
126 | +// 品牌类别滚动事件 | ||
127 | +$(window).scroll(function() { | ||
128 | + if ($(this).scrollTop() >= categoryTop) { | ||
129 | + $gory.addClass('category-fix'); | ||
130 | + } else { | ||
131 | + $gory.removeClass('category-fix'); | ||
132 | + } | ||
133 | +}); | ||
134 | + | ||
135 | +// 点击字母,页面滚动到相关区域 | ||
136 | +$category.click(function() { | ||
137 | + var name = $(this).attr('href').split('#')[1]; | ||
138 | + var targetTop = $list.find('[name="' + name + '"]').offset().top - categoryHeight; | ||
139 | + | ||
140 | + if (!$gory.hasClass('category-fix')) { | ||
141 | + targetTop -= categoryHeight; | ||
142 | + } | ||
143 | + | ||
144 | + $('html,body').animate({ | ||
145 | + scrollTop: targetTop | ||
146 | + }, 200); | ||
147 | + return false; | ||
148 | +}); | ||
149 | + | ||
150 | + | ||
151 | +// 浮层代码 | ||
152 | +function bindTemplete($select, data, tmp) { | ||
153 | + var $this = $select; | ||
154 | + var offset = { | ||
155 | + width: $this.width(), | ||
156 | + left: $this.offset().left, | ||
157 | + right: parseFloat($(window).width()) - parseFloat($this.offset().left) - parseFloat($this.width()) | ||
158 | + }; | ||
159 | + | ||
160 | + var $parent = $this.parent('li'); | ||
161 | + var myTemplate; | ||
162 | + | ||
163 | + $list.find('.brands-dialog').remove(); | ||
164 | + myTemplate = Handlebars.compile(tmp); | ||
165 | + $parent.append(myTemplate(data)); | ||
166 | + $parent.find('.right').dotdotdot({ | ||
167 | + wrap: 'letter' | ||
168 | + }); | ||
169 | + | ||
170 | + if (offset.right - 350 < 0) { | ||
171 | + $parent.find('.brands-layer') | ||
172 | + .addClass('brands-layer-right').css('left', -330 - offset.width); | ||
173 | + } | ||
174 | +} | ||
175 | + | ||
176 | +// 鼠标悬浮品牌,请求数据,并且展示 | ||
177 | +function bindHoverEvent() { | ||
178 | + $brand.unbind('mouseenter').unbind('mouseleave').hover(function() { | ||
179 | + var $this = $(this); | ||
180 | + var key = $this.attr('data-key'); | ||
181 | + | ||
182 | + var options = { | ||
183 | + url: '/brands/brandinfo', | ||
184 | + type: 'get', | ||
185 | + data: { | ||
186 | + brandId: key | ||
187 | + }, | ||
188 | + success: function(_data) { | ||
189 | + | ||
190 | + if (_data.code === 200 && _data.brand) { | ||
191 | + if (!tempdata.hasOwnProperty(_data.brand.key)) { | ||
192 | + tempdata[_data.brand.key] = _data.brand; | ||
193 | + } | ||
194 | + bindTemplete($this, tempdata[_data.brand.key], templete); | ||
195 | + } | ||
196 | + } | ||
197 | + }; | ||
198 | + | ||
199 | + clearTimeout(timeout); | ||
200 | + timeout = setTimeout(function() { | ||
201 | + if (!tempdata.hasOwnProperty(key)) { | ||
202 | + $.ajax(options); | ||
203 | + } else { | ||
204 | + bindTemplete($this, tempdata[key], templete); | ||
205 | + } | ||
206 | + }, 200); | ||
207 | + }, function() { | ||
208 | + clearTimeout(timeout); | ||
209 | + $list.find('.brands-dialog').remove(); | ||
210 | + }); | ||
211 | +} | ||
212 | + | ||
213 | +if ($clearfix.length < 26) { | ||
214 | + $.ajax({ | ||
215 | + url: '/brands/brandList', | ||
216 | + type: 'POST', | ||
217 | + data: { | ||
218 | + start: $clearfix.length ? ($clearfix.length + 1) : 1 | ||
219 | + }, | ||
220 | + success: function(_data) { | ||
221 | + if (_data) { | ||
222 | + $list.append(_data); | ||
223 | + $brand = $list.find('li>a'); | ||
224 | + bindHoverEvent(); | ||
225 | + } | ||
226 | + } | ||
227 | + }); | ||
228 | +} | ||
229 | + | ||
230 | +bindHoverEvent(); |
@@ -9,6 +9,9 @@ var $ = require('yoho-jquery'); | @@ -9,6 +9,9 @@ var $ = require('yoho-jquery'); | ||
9 | var homePage = $('.home-page').data('page'), | 9 | var homePage = $('.home-page').data('page'), |
10 | brandUrl = $('.logo-brand').data('url'); | 10 | brandUrl = $('.logo-brand').data('url'); |
11 | 11 | ||
12 | +// 给头部js获取当前频道 | ||
13 | +window.homePage = homePage; | ||
14 | + | ||
12 | require('../common'); | 15 | require('../common'); |
13 | 16 | ||
14 | require('../plugins/slider'); | 17 | require('../plugins/slider'); |
@@ -74,6 +74,16 @@ function getUid() { | @@ -74,6 +74,16 @@ function getUid() { | ||
74 | return user[1]; | 74 | return user[1]; |
75 | } | 75 | } |
76 | 76 | ||
77 | +function getProfileName() { | ||
78 | + var user = getUser(); | ||
79 | + | ||
80 | + if (user === 0) { | ||
81 | + return 0; | ||
82 | + } | ||
83 | + | ||
84 | + return user[0]; | ||
85 | +} | ||
86 | + | ||
77 | function getShoppingKey() { | 87 | function getShoppingKey() { |
78 | var c = cookie('_g'); | 88 | var c = cookie('_g'); |
79 | 89 | ||
@@ -132,16 +142,19 @@ $(window).on('resize', function() { | @@ -132,16 +142,19 @@ $(window).on('resize', function() { | ||
132 | } | 142 | } |
133 | }).trigger('resize'); | 143 | }).trigger('resize'); |
134 | 144 | ||
145 | +// 对特殊的情况进行处理 | ||
135 | function queryString() { | 146 | function queryString() { |
136 | var vars = {}, | 147 | var vars = {}, |
137 | hash, | 148 | hash, |
149 | + index, | ||
138 | i, | 150 | i, |
139 | search = window.location.search, | 151 | search = window.location.search, |
140 | hashes = search ? decodeURIComponent(search).slice(1).split('&') : []; | 152 | hashes = search ? decodeURIComponent(search).slice(1).split('&') : []; |
141 | 153 | ||
142 | for (i = 0; i < hashes.length; i++) { | 154 | for (i = 0; i < hashes.length; i++) { |
143 | - hash = hashes[i].split('='); | ||
144 | - vars[hash[0]] = hash[1]; | 155 | + index = hashes[i].indexOf('='); |
156 | + hash = hashes[i].substring(0, index); | ||
157 | + vars[hash] = hashes[i].substring(++index); | ||
145 | } | 158 | } |
146 | return vars; | 159 | return vars; |
147 | } | 160 | } |
@@ -174,6 +187,8 @@ window.getUser = getUser; | @@ -174,6 +187,8 @@ window.getUser = getUser; | ||
174 | 187 | ||
175 | window.getUid = getUid; | 188 | window.getUid = getUid; |
176 | 189 | ||
190 | +window.getProfileName = getProfileName; | ||
191 | + | ||
177 | window.getShoppingKey = getShoppingKey; | 192 | window.getShoppingKey = getShoppingKey; |
178 | 193 | ||
179 | window.queryString = queryString; | 194 | window.queryString = queryString; |
@@ -15,10 +15,13 @@ var $head = $('.head-wrapper'), | @@ -15,10 +15,13 @@ var $head = $('.head-wrapper'), | ||
15 | $logotrans = $head.find('.main-logo'), | 15 | $logotrans = $head.find('.main-logo'), |
16 | $searchSug = $head.find('.search-suggest'), | 16 | $searchSug = $head.find('.search-suggest'), |
17 | $goCart = $head.find('.go-cart'), | 17 | $goCart = $head.find('.go-cart'), |
18 | + $myYohoBox = $('#myYohoBox'), | ||
18 | $goodsNum = $goCart.find('.goods-num-tip'), | 19 | $goodsNum = $goCart.find('.goods-num-tip'), |
19 | $miniCart = $head.find('.mini-cart-wrapper'); | 20 | $miniCart = $head.find('.mini-cart-wrapper'); |
20 | 21 | ||
21 | -var $subNav = $('.sub-nav-list .contain-third'); | 22 | +var $subNav = $('.sub-nav-list.cure .contain-third'); |
23 | + | ||
24 | +var fetchUserInfoEvent = $.Callbacks('once'); // eslint-disable-line | ||
22 | 25 | ||
23 | var thirdLineNum = 9, | 26 | var thirdLineNum = 9, |
24 | delayer, | 27 | delayer, |
@@ -72,6 +75,12 @@ var bannerMap = { | @@ -72,6 +75,12 @@ var bannerMap = { | ||
72 | }, | 75 | }, |
73 | cookieMap = {}; | 76 | cookieMap = {}; |
74 | 77 | ||
78 | +var $signinBtn = $('#signin-url'); | ||
79 | +var $regBtn = $('#reg-url'); | ||
80 | + | ||
81 | +$signinBtn.attr('href', '//www.yohobuy.com/signin.html?refer=' + window.location.href); | ||
82 | +$regBtn.attr('href', '//www.yohobuy.com/reg.html?refer=' + window.location.href); | ||
83 | + | ||
75 | // handlebars模板 | 84 | // handlebars模板 |
76 | centerFn = handlebars.compile($('#simple-account-info-tpl').html() || ''); | 85 | centerFn = handlebars.compile($('#simple-account-info-tpl').html() || ''); |
77 | loginFn = handlebars.compile($('#header-login-info-tpl').html() || ''); | 86 | loginFn = handlebars.compile($('#header-login-info-tpl').html() || ''); |
@@ -111,16 +120,16 @@ function setTopBanner(data) { | @@ -111,16 +120,16 @@ function setTopBanner(data) { | ||
111 | } else { | 120 | } else { |
112 | topbanner = '<div class="yoho-notice">' + | 121 | topbanner = '<div class="yoho-notice">' + |
113 | '<div class="notice-container center-content">' + | 122 | '<div class="notice-container center-content">' + |
114 | - '<h1 class="notice-title">关于系统升级的公告</h1>' + | ||
115 | - '<div class="notice-content">' + | ||
116 | - '<p class="tips">尊敬的顾客:</p>' + | ||
117 | - '<p class="detail">您好!为了向您提供更优质的服务,目前系统正在升级,请耐心等待。</p>' + | ||
118 | - '<p class="detail">系统升级期间,部分地区用户体验会有暂时中断,如遇紧急事宜,欢迎垂询客服热线:' + | ||
119 | - '400-889-9646 09:00-22:30(周一至周日)。稍后系统将恢复正常' + | ||
120 | - '使用,欢迎您继续光顾YOHO!BUY有货!带来不便之处深表歉意,请您谅解!</p>' + | ||
121 | - '</div>' + | 123 | + '<h1 class="notice-title">关于系统升级的公告</h1>' + |
124 | + '<div class="notice-content">' + | ||
125 | + '<p class="tips">尊敬的顾客:</p>' + | ||
126 | + '<p class="detail">您好!为了向您提供更优质的服务,目前系统正在升级,请耐心等待。</p>' + | ||
127 | + '<p class="detail">系统升级期间,部分地区用户体验会有暂时中断,如遇紧急事宜,欢迎垂询客服热线:' + | ||
128 | + '400-889-9646 09:00-22:30(周一至周日)。稍后系统将恢复正常' + | ||
129 | + '使用,欢迎您继续光顾YOHO!BUY有货!带来不便之处深表歉意,请您谅解!</p>' + | ||
122 | '</div>' + | 130 | '</div>' + |
123 | - '</div>'; | 131 | + '</div>' + |
132 | + '</div>'; | ||
124 | } | 133 | } |
125 | $('body').prepend(topbanner); | 134 | $('body').prepend(topbanner); |
126 | } | 135 | } |
@@ -239,18 +248,11 @@ function formatThirdMenu() { | @@ -239,18 +248,11 @@ function formatThirdMenu() { | ||
239 | 248 | ||
240 | // 更新头部登陆信息 | 249 | // 更新头部登陆信息 |
241 | function updateLoginInfo(data) { | 250 | function updateLoginInfo(data) { |
242 | - var info = { | ||
243 | - usercenter: '//www.yohobuy.com/home?t=' + new Date().getTime(), | ||
244 | - nickname: data.profileName, | ||
245 | - signout: '//www.yohobuy.com/logout.html' | ||
246 | - }; | ||
247 | - | ||
248 | if (data.curLevel * 1 === 3) { | 251 | if (data.curLevel * 1 === 3) { |
249 | data.vip3 = true; | 252 | data.vip3 = true; |
250 | } | 253 | } |
251 | 254 | ||
252 | $tool.find('.simple-user-center').html(centerFn(data)); | 255 | $tool.find('.simple-user-center').html(centerFn(data)); |
253 | - $loginBox.html(loginFn(info)); | ||
254 | } | 256 | } |
255 | 257 | ||
256 | // 同步sso登录状态 | 258 | // 同步sso登录状态 |
@@ -260,7 +262,7 @@ function syncLoginInfo() { | @@ -260,7 +262,7 @@ function syncLoginInfo() { | ||
260 | method: 'open.passport.get' | 262 | method: 'open.passport.get' |
261 | }; | 263 | }; |
262 | 264 | ||
263 | - $.getJSON('//www.yohobuy.com/common/passport/?callback=?', param, function(jsonData) { | 265 | + return $.getJSON('//www.yohobuy.com/common/passport/?callback=?', param, function(jsonData) { |
264 | if (jsonData && jsonData.data && jsonData.data.result !== -1) { | 266 | if (jsonData && jsonData.data && jsonData.data.result !== -1) { |
265 | updateLoginInfo(jsonData.data); | 267 | updateLoginInfo(jsonData.data); |
266 | } else { | 268 | } else { |
@@ -269,7 +271,6 @@ function syncLoginInfo() { | @@ -269,7 +271,6 @@ function syncLoginInfo() { | ||
269 | expires: -1 | 271 | expires: -1 |
270 | }); | 272 | }); |
271 | } | 273 | } |
272 | - $loginBox.show(); | ||
273 | }); | 274 | }); |
274 | } | 275 | } |
275 | 276 | ||
@@ -481,7 +482,35 @@ function isSupportCss3Animation() { | @@ -481,7 +482,35 @@ function isSupportCss3Animation() { | ||
481 | return false; | 482 | return false; |
482 | } | 483 | } |
483 | } | 484 | } |
485 | +} | ||
486 | + | ||
487 | +// 处理pageCache频道显示异常问题 | ||
488 | +function syncPageChannel() { | ||
489 | + var $header = $('#yoho-header'), | ||
490 | + $navs; | ||
491 | + var channel = window.homePage || window.cookie('_Channel') || 'boys', | ||
492 | + qs = window.queryString(); | ||
493 | + | ||
494 | + channel = qs.channel ? qs.channel : channel; | ||
484 | 495 | ||
496 | + if ($header && $header.length) { | ||
497 | + $navs = $header.find('.' + channel); | ||
498 | + | ||
499 | + if (!$navs.length) { | ||
500 | + channel = 'boys'; | ||
501 | + $navs = $header.find('.' + channel); | ||
502 | + } | ||
503 | + | ||
504 | + // 更新频道菜单选中状态 | ||
505 | + $navs.siblings('.cure').removeClass('cure'); | ||
506 | + $navs.addClass('cure'); | ||
507 | + | ||
508 | + // 更新频道颜色 | ||
509 | + $header.addClass(channel).find('.func-area').removeClass('hide'); | ||
510 | + | ||
511 | + // 更新三级菜单jq对象 | ||
512 | + $subNav = $('.sub-nav-list.cure .contain-third'); | ||
513 | + } | ||
485 | } | 514 | } |
486 | 515 | ||
487 | if (isSupportCss3Animation()) { | 516 | if (isSupportCss3Animation()) { |
@@ -490,11 +519,45 @@ if (isSupportCss3Animation()) { | @@ -490,11 +519,45 @@ if (isSupportCss3Animation()) { | ||
490 | } else { | 519 | } else { |
491 | window.setTimeout(fadeAnimate, 3000); | 520 | window.setTimeout(fadeAnimate, 3000); |
492 | } | 521 | } |
522 | +syncPageChannel(); | ||
493 | getBannerAndNotice(); // 获取头部banner | 523 | getBannerAndNotice(); // 获取头部banner |
494 | -syncLoginInfo(); // 同步登陆信息 | ||
495 | formatThirdMenu(); // 格式化三级菜单 | 524 | formatThirdMenu(); // 格式化三级菜单 |
496 | setInterval(syncCratInfo, 2000); // 定时同步购物车数量 | 525 | setInterval(syncCratInfo, 2000); // 定时同步购物车数量 |
497 | 526 | ||
527 | +// 获取头部登陆信息 | ||
528 | +(function() { | ||
529 | + var uid = getUid(), //eslint-disable-line | ||
530 | + profileName = getProfileName(); // eslint-disable-line | ||
531 | + | ||
532 | + var info = { | ||
533 | + usercenter: '//www.yohobuy.com/home?t=' + new Date().getTime(), | ||
534 | + nickname: profileName, | ||
535 | + signout: '//www.yohobuy.com/logout.html' | ||
536 | + }; | ||
537 | + | ||
538 | + if (uid !== 0) { | ||
539 | + $loginBox.html(loginFn(info)); | ||
540 | + } | ||
541 | + | ||
542 | + $loginBox.show(); | ||
543 | +}()); | ||
544 | + | ||
545 | +fetchUserInfoEvent.add(syncLoginInfo); | ||
546 | + | ||
547 | +$myYohoBox.hover(function() { | ||
548 | + var uid = getUid(); // eslint-disable-line | ||
549 | + | ||
550 | + $myYohoBox.addClass('myyoho-hover'); | ||
551 | + | ||
552 | + if (uid === 0) { | ||
553 | + return; | ||
554 | + } | ||
555 | + | ||
556 | + fetchUserInfoEvent.fire(); | ||
557 | +}, function() { | ||
558 | + $myYohoBox.removeClass('myyoho-hover'); | ||
559 | +}); | ||
560 | + | ||
498 | $yohoGroup.hover(function() { | 561 | $yohoGroup.hover(function() { |
499 | var data = $(this).data(); | 562 | var data = $(this).data(); |
500 | 563 |
@@ -912,6 +912,26 @@ function authUntilThreeTimesAsync() { | @@ -912,6 +912,26 @@ function authUntilThreeTimesAsync() { | ||
912 | }); | 912 | }); |
913 | } | 913 | } |
914 | 914 | ||
915 | +// 设置 refer 信息 | ||
916 | +function setRefer() { | ||
917 | + var refer = queryString().refer || '', // eslint-disable-line | ||
918 | + regUrl; | ||
919 | + | ||
920 | + if (refer) { | ||
921 | + setCookie('refer', refer, {domain: '.yohobuy.com', path: '/'}); // eslint-disable-line | ||
922 | + } | ||
923 | + | ||
924 | + regUrl = (function() { | ||
925 | + if (refer) { | ||
926 | + return '/reg.html?refer=' + refer; | ||
927 | + } else { | ||
928 | + return '/reg.html'; | ||
929 | + } | ||
930 | + }()); | ||
931 | + | ||
932 | + $('.fast-reg').attr('href', regUrl); | ||
933 | +} | ||
934 | + | ||
915 | /** ************************************************************************/ | 935 | /** ************************************************************************/ |
916 | /* 事件绑定 */ | 936 | /* 事件绑定 */ |
917 | /** ************************************************************************/ | 937 | /** ************************************************************************/ |
@@ -948,7 +968,7 @@ $(document).on('click', function(e) { | @@ -948,7 +968,7 @@ $(document).on('click', function(e) { | ||
948 | 968 | ||
949 | /** ************************************************************************/ | 969 | /** ************************************************************************/ |
950 | 970 | ||
951 | - // 邮箱自动完成后失去焦点:仅进行本地格式验证格式; | 971 | + // 邮箱自动完成后失去焦点:仅进行本地格式验证格式; |
952 | mailAc($accountInput1, function() { | 972 | mailAc($accountInput1, function() { |
953 | return currentLogin.validateAccountLocal(); | 973 | return currentLogin.validateAccountLocal(); |
954 | }); | 974 | }); |
@@ -1128,6 +1148,9 @@ if (($accountInput1.val() !== '' || | @@ -1128,6 +1148,9 @@ if (($accountInput1.val() !== '' || | ||
1128 | $passwordInput.focus(); | 1148 | $passwordInput.focus(); |
1129 | } | 1149 | } |
1130 | 1150 | ||
1151 | +// 设置 refer | ||
1152 | +setRefer(); | ||
1153 | + | ||
1131 | /** ************************************************************************/ | 1154 | /** ************************************************************************/ |
1132 | /* 结束 */ | 1155 | /* 结束 */ |
1133 | /** ************************************************************************/ | 1156 | /** ************************************************************************/ |
@@ -252,7 +252,6 @@ function validateRule(page, $element, callback) { | @@ -252,7 +252,6 @@ function validateRule(page, $element, callback) { | ||
252 | regionCode; | 252 | regionCode; |
253 | 253 | ||
254 | 254 | ||
255 | - | ||
256 | // 根据需求http://redmine.yoho.cn/issues/3117改成上边的正则 | 255 | // 根据需求http://redmine.yoho.cn/issues/3117改成上边的正则 |
257 | // 对应的错误提示语也改了,感觉要不了多久就会改回来 | 256 | // 对应的错误提示语也改了,感觉要不了多久就会改回来 |
258 | // pwdReg = /^([a-zA-Z0-9\-\+_!@\#$%\^&\*\(\)\:\;\.=\[\]\\\',\?]){6,20}$/gi; | 257 | // pwdReg = /^([a-zA-Z0-9\-\+_!@\#$%\^&\*\(\)\:\;\.=\[\]\\\',\?]){6,20}$/gi; |
@@ -279,7 +278,7 @@ function validateRule(page, $element, callback) { | @@ -279,7 +278,7 @@ function validateRule(page, $element, callback) { | ||
279 | } | 278 | } |
280 | } | 279 | } |
281 | 280 | ||
282 | - // 图形验证码校验 | 281 | + // 图形验证码校验 |
283 | } else if ($element.hasClass('captcha')) { | 282 | } else if ($element.hasClass('captcha')) { |
284 | if (val === '') { | 283 | if (val === '') { |
285 | validateResult[1].message = '请输入图形验证码'; | 284 | validateResult[1].message = '请输入图形验证码'; |
@@ -304,7 +303,7 @@ function validateRule(page, $element, callback) { | @@ -304,7 +303,7 @@ function validateRule(page, $element, callback) { | ||
304 | 303 | ||
305 | } | 304 | } |
306 | 305 | ||
307 | - // 短信验证码校验 | 306 | + // 短信验证码校验 |
308 | } else if ($element.hasClass('msg-captcha')) { | 307 | } else if ($element.hasClass('msg-captcha')) { |
309 | 308 | ||
310 | if (val === '') { | 309 | if (val === '') { |
@@ -329,7 +328,7 @@ function validateRule(page, $element, callback) { | @@ -329,7 +328,7 @@ function validateRule(page, $element, callback) { | ||
329 | } | 328 | } |
330 | } | 329 | } |
331 | 330 | ||
332 | - // 密码校验 | 331 | + // 密码校验 |
333 | } else if ($element.hasClass('pwd')) { | 332 | } else if ($element.hasClass('pwd')) { |
334 | if (val === '') { | 333 | if (val === '') { |
335 | validateResult[3].message = '请输入密码'; | 334 | validateResult[3].message = '请输入密码'; |
@@ -349,7 +348,7 @@ function validateRule(page, $element, callback) { | @@ -349,7 +348,7 @@ function validateRule(page, $element, callback) { | ||
349 | } | 348 | } |
350 | return callback(); | 349 | return callback(); |
351 | 350 | ||
352 | - // 二次密码校验 | 351 | + // 二次密码校验 |
353 | } else if ($element.hasClass('repwd')) { | 352 | } else if ($element.hasClass('repwd')) { |
354 | if (val === '') { | 353 | if (val === '') { |
355 | validateResult[4].message = '请输入密码确认'; | 354 | validateResult[4].message = '请输入密码确认'; |
@@ -572,9 +571,9 @@ exports.init = function(page) { | @@ -572,9 +571,9 @@ exports.init = function(page) { | ||
572 | }).blur(function() { | 571 | }).blur(function() { |
573 | 572 | ||
574 | /* validateRule($(this), function() { | 573 | /* validateRule($(this), function() { |
575 | - showErrTip(); | ||
576 | - showBorder(); // 显示红色边框 | ||
577 | - });*/ | 574 | + showErrTip(); |
575 | + showBorder(); // 显示红色边框 | ||
576 | + });*/ | ||
578 | }); | 577 | }); |
579 | 578 | ||
580 | $regionSelect.change(function() { | 579 | $regionSelect.change(function() { |
@@ -721,4 +720,15 @@ exports.init = function(page) { | @@ -721,4 +720,15 @@ exports.init = function(page) { | ||
721 | $countDown.text(countDown--); | 720 | $countDown.text(countDown--); |
722 | }, 1000); | 721 | }, 1000); |
723 | } | 722 | } |
723 | + | ||
724 | + // 设置 refer 信息 | ||
725 | + (function() { | ||
726 | + var refer = queryString().refer || ''; // eslint-disable-line | ||
727 | + | ||
728 | + if (refer) { | ||
729 | + setCookie('refer', refer); // eslint-disable-line | ||
730 | + } else { | ||
731 | + setCookie('refer', ''); // eslint-disable-line | ||
732 | + } | ||
733 | + }()); | ||
724 | }; | 734 | }; |
public/js/plugins/lazy-load.js
0 → 100644
1 | +/* eslint-disable */ | ||
2 | +/** | ||
3 | + * Created by TaoHuang on 2016/10/10. | ||
4 | + */ | ||
5 | + | ||
6 | +var $ = require('yoho-jquery'); | ||
7 | + | ||
8 | +require('./throttle'); | ||
9 | + | ||
10 | +function dataLazyLoad(doc) { | ||
11 | + | ||
12 | + // 兼容低版本 IE | ||
13 | + Function.prototype.bind = Function.prototype.bind || function(context) { | ||
14 | + var that = this; | ||
15 | + return function() { | ||
16 | + return that.apply(context, arguments); | ||
17 | + }; | ||
18 | + }; | ||
19 | + | ||
20 | + // 工具方法 begin | ||
21 | + var Util = { | ||
22 | + getElements: function(cls) { | ||
23 | + return $(cls).toArray(); | ||
24 | + }, | ||
25 | + addEvent: function(ele, type, fn) { | ||
26 | + ele.attachEvent ? ele.attachEvent("on" + type, fn) : ele.addEventListener(type, fn, false); | ||
27 | + }, | ||
28 | + removeEvent: function(ele, type, fn) { | ||
29 | + ele.detachEvent ? ele.detachEvent("on" + type, fn) : ele.removeEventListener(type, fn, false); | ||
30 | + }, | ||
31 | + getPos: function(ele) { | ||
32 | + var pos = { | ||
33 | + x: 0, | ||
34 | + y: 0 | ||
35 | + }; | ||
36 | + | ||
37 | + var offset = $(ele).offset(); | ||
38 | + | ||
39 | + pos.x = offset.left; | ||
40 | + pos.y = offset.top; | ||
41 | + | ||
42 | + return pos; | ||
43 | + }, | ||
44 | + getViewport: function() { | ||
45 | + var html = doc.documentElement; | ||
46 | + | ||
47 | + return { | ||
48 | + w: !window.innerWidth ? html.clientHeight : window.innerWidth, | ||
49 | + h: !window.innerHeight ? html.clientHeight : window.innerHeight | ||
50 | + }; | ||
51 | + }, | ||
52 | + getScrollHeight: function() { | ||
53 | + html = doc.documentElement, bd = doc.body; | ||
54 | + return Math.max(window.pageYOffset || 0, html.scrollTop, bd.scrollTop); | ||
55 | + }, | ||
56 | + getEleSize: function(ele) { | ||
57 | + return { | ||
58 | + w: ele.offsetWidth, | ||
59 | + h: ele.offsetHeight | ||
60 | + }; | ||
61 | + } | ||
62 | + }; | ||
63 | + // 工具方法 end | ||
64 | + | ||
65 | + return { | ||
66 | + threshold: 0, // {number} 阈值,预加载高度,单位(px) | ||
67 | + els: null, // {Array} 延迟加载元素集合(数组) | ||
68 | + fn: null, // {Function} scroll、resize、touchmove 所绑定方法,即为 pollTextareas() | ||
69 | + | ||
70 | + evalScripts: function(code) { | ||
71 | + var head = $(".yoho-footer")[0], | ||
72 | + js = doc.createElement("script"); | ||
73 | + | ||
74 | + js.text = code; | ||
75 | + head.appendChild(js, head.firstChild); | ||
76 | + head.removeChild(js); | ||
77 | + }, | ||
78 | + | ||
79 | + evalStyles: function(code) { | ||
80 | + var head = doc.getElementsByTagName("head")[0], | ||
81 | + css = doc.createElement("style"); | ||
82 | + | ||
83 | + css.type = "text/css"; | ||
84 | + | ||
85 | + try { | ||
86 | + css.appendChild(doc.createTextNode(code)); | ||
87 | + } catch (e) { | ||
88 | + css.styleSheet.cssText = code; | ||
89 | + } | ||
90 | + | ||
91 | + head.appendChild(css); | ||
92 | + }, | ||
93 | + | ||
94 | + extractCode: function(str, isStyle) { | ||
95 | + var cata = isStyle ? "style" : "script", | ||
96 | + scriptFragment = "<" + cata + "[^>]*>([\\S\\s]*?)</" + cata + "\\s*>", | ||
97 | + matchAll = new RegExp(scriptFragment, "img"), | ||
98 | + matchOne = new RegExp(scriptFragment, "im"), | ||
99 | + matchResults = str.match(matchAll) || [], | ||
100 | + ret = []; | ||
101 | + | ||
102 | + for (var i = 0, len = matchResults.length; i < len; i++) { | ||
103 | + var temp = (matchResults[i].match(matchOne) || ["", ""])[1]; | ||
104 | + temp && ret.push(temp); | ||
105 | + } | ||
106 | + return ret; | ||
107 | + }, | ||
108 | + | ||
109 | + decodeHTML: function(str) { | ||
110 | + return str.replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&") | ||
111 | + .replace(/</g, '<').replace(/>/g, '>'); | ||
112 | + }, | ||
113 | + | ||
114 | + insert: function(ele) { | ||
115 | + var parent = ele.parentNode, | ||
116 | + txt = this.decodeHTML(ele.innerHTML), | ||
117 | + matchStyles = this.extractCode(txt, true), | ||
118 | + matchScripts = this.extractCode(txt); | ||
119 | + | ||
120 | + parent.innerHTML = txt | ||
121 | + .replace(new RegExp("<script[^>]*>([\\S\\s]*?)</script\\s*>", "img"), "") | ||
122 | + .replace(new RegExp("<style[^>]*>([\\S\\s]*?)</style\\s*>", "img"), ""); | ||
123 | + | ||
124 | + if (matchStyles.length) { | ||
125 | + for (var i = matchStyles.length; i--;) { | ||
126 | + this.evalStyles(matchStyles[i]); | ||
127 | + } | ||
128 | + } | ||
129 | + | ||
130 | + | ||
131 | + // 如果延迟部分需要做 loading 效果 | ||
132 | + parent.className = parent.className.replace("loading", ""); | ||
133 | + | ||
134 | + if (matchScripts.length) { | ||
135 | + for (var i = 0, len = matchScripts.length; i < len; i++) { | ||
136 | + this.evalScripts(matchScripts[i]); | ||
137 | + } | ||
138 | + } | ||
139 | + }, | ||
140 | + | ||
141 | + inView: function(ele) { | ||
142 | + var top = Util.getPos(ele).y | ||
143 | + , viewVal = Util.getViewport().h | ||
144 | + , scrollVal = Util.getScrollHeight() | ||
145 | + , eleHeight = Util.getEleSize(ele).h; | ||
146 | + | ||
147 | + if (top >= scrollVal - eleHeight - this.threshold && top <= scrollVal + viewVal + this.threshold) { | ||
148 | + return true; | ||
149 | + } | ||
150 | + | ||
151 | + return false; | ||
152 | + }, | ||
153 | + | ||
154 | + pollTextareas: function() { | ||
155 | + // 需延迟加载的元素已经全部加载完 | ||
156 | + if (!this.els.length) { | ||
157 | + Util.removeEvent(window, "scroll", this.fn); | ||
158 | + Util.removeEvent(window, "resize", this.fn); | ||
159 | + Util.removeEvent(doc.body, "touchMove", this.fn); | ||
160 | + return; | ||
161 | + } | ||
162 | + | ||
163 | + // 判断是否需要加载 | ||
164 | + for (var i = this.els.length; i--;) { | ||
165 | + var ele = this.els[i]; | ||
166 | + | ||
167 | + if (!this.inView(ele)) { | ||
168 | + continue; | ||
169 | + } | ||
170 | + | ||
171 | + this.insert(ele); | ||
172 | + this.els.splice(i, 1); | ||
173 | + } | ||
174 | + }, | ||
175 | + | ||
176 | + init: function(config) { | ||
177 | + var cls = config.cls; | ||
178 | + this.threshold = config.threshold ? config.threshold : 0; | ||
179 | + | ||
180 | + this.els = Array.prototype.slice.call(Util.getElements(cls)); | ||
181 | + this.fn = this.pollTextareas.bind(this); | ||
182 | + | ||
183 | + this.fn(); | ||
184 | + | ||
185 | + var _this = this; | ||
186 | + Util.addEvent(window, "scroll", $.throttle(500, true, _this.fn)); | ||
187 | + Util.addEvent(window, "resize", $.throttle(500, true, _this.fn)); | ||
188 | + Util.addEvent(doc.body, "touchMove", $.throttle(500, true, _this.fn)); | ||
189 | + } | ||
190 | + }; | ||
191 | +} | ||
192 | + | ||
193 | +module.exports = dataLazyLoad; | ||
194 | + | ||
195 | +/** | ||
196 | + * demo | ||
197 | + * datalazyload.init({ | ||
198 | + * cls: ".datalazyload", // 需要延迟加载的类,即 textarea 的类名 | ||
199 | + * threshold: 100 // 距离底部多高,进行延迟加载的阈值 | ||
200 | + * }); | ||
201 | + */ |
public/js/plugins/throttle.js
0 → 100644
1 | +/* eslint-disable */ | ||
2 | +/*! | ||
3 | + * jQuery throttle / debounce - v1.1 - 3/7/2010 | ||
4 | + * http://benalman.com/projects/jquery-throttle-debounce-plugin/ | ||
5 | + * | ||
6 | + * Copyright (c) 2010 "Cowboy" Ben Alman | ||
7 | + * Dual licensed under the MIT and GPL licenses. | ||
8 | + * http://benalman.com/about/license/ | ||
9 | + */ | ||
10 | + | ||
11 | +// Script: jQuery throttle / debounce: Sometimes, less is more! | ||
12 | +// | ||
13 | +// *Version: 1.1, Last updated: 3/7/2010* | ||
14 | +// | ||
15 | +// Project Home - http://benalman.com/projects/jquery-throttle-debounce-plugin/ | ||
16 | +// GitHub - http://github.com/cowboy/jquery-throttle-debounce/ | ||
17 | +// Source - http://github.com/cowboy/jquery-throttle-debounce/raw/master/jquery.ba-throttle-debounce.js | ||
18 | +// (Minified) - http://github.com/cowboy/jquery-throttle-debounce/raw/master/jquery.ba-throttle-debounce.min.js (0.7kb) | ||
19 | +// | ||
20 | +// About: License | ||
21 | +// | ||
22 | +// Copyright (c) 2010 "Cowboy" Ben Alman, | ||
23 | +// Dual licensed under the MIT and GPL licenses. | ||
24 | +// http://benalman.com/about/license/ | ||
25 | +// | ||
26 | +// About: Examples | ||
27 | +// | ||
28 | +// These working examples, complete with fully commented code, illustrate a few | ||
29 | +// ways in which this plugin can be used. | ||
30 | +// | ||
31 | +// Throttle - http://benalman.com/code/projects/jquery-throttle-debounce/examples/throttle/ | ||
32 | +// Debounce - http://benalman.com/code/projects/jquery-throttle-debounce/examples/debounce/ | ||
33 | +// | ||
34 | +// About: Support and Testing | ||
35 | +// | ||
36 | +// Information about what version or versions of jQuery this plugin has been | ||
37 | +// tested with, what browsers it has been tested in, and where the unit tests | ||
38 | +// reside (so you can test it yourself). | ||
39 | +// | ||
40 | +// jQuery Versions - none, 1.3.2, 1.4.2 | ||
41 | +// Browsers Tested - Internet Explorer 6-8, Firefox 2-3.6, Safari 3-4, Chrome 4-5, Opera 9.6-10.1. | ||
42 | +// Unit Tests - http://benalman.com/code/projects/jquery-throttle-debounce/unit/ | ||
43 | +// | ||
44 | +// About: Release History | ||
45 | +// | ||
46 | +// 1.1 - (3/7/2010) Fixed a bug in <jQuery.throttle> where trailing callbacks | ||
47 | +// executed later than they should. Reworked a fair amount of internal | ||
48 | +// logic as well. | ||
49 | +// 1.0 - (3/6/2010) Initial release as a stand-alone project. Migrated over | ||
50 | +// from jquery-misc repo v0.4 to jquery-throttle repo v1.0, added the | ||
51 | +// no_trailing throttle parameter and debounce functionality. | ||
52 | +// | ||
53 | +// Topic: Note for non-jQuery users | ||
54 | +// | ||
55 | +// jQuery isn't actually required for this plugin, because nothing internal | ||
56 | +// uses any jQuery methods or properties. jQuery is just used as a namespace | ||
57 | +// under which these methods can exist. | ||
58 | +// | ||
59 | +// Since jQuery isn't actually required for this plugin, if jQuery doesn't exist | ||
60 | +// when this plugin is loaded, the method described below will be created in | ||
61 | +// the `Cowboy` namespace. Usage will be exactly the same, but instead of | ||
62 | +// $.method() or jQuery.method(), you'll need to use Cowboy.method(). | ||
63 | + | ||
64 | +(function($) { | ||
65 | + '$:nomunge'; // Used by YUI compressor. | ||
66 | + | ||
67 | + // Since jQuery really isn't required for this plugin, use `jQuery` as the | ||
68 | + // namespace only if it already exists, otherwise use the `Cowboy` namespace, | ||
69 | + // creating it if necessary. | ||
70 | + | ||
71 | + // Internal method reference. | ||
72 | + var jq_throttle; | ||
73 | + | ||
74 | + // Method: jQuery.throttle | ||
75 | + // | ||
76 | + // Throttle execution of a function. Especially useful for rate limiting | ||
77 | + // execution of handlers on events like resize and scroll. If you want to | ||
78 | + // rate-limit execution of a function to a single time, see the | ||
79 | + // <jQuery.debounce> method. | ||
80 | + // | ||
81 | + // In this visualization, | is a throttled-function call and X is the actual | ||
82 | + // callback execution: | ||
83 | + // | ||
84 | + // > Throttled with `no_trailing` specified as false or unspecified: | ||
85 | + // > ||||||||||||||||||||||||| (pause) ||||||||||||||||||||||||| | ||
86 | + // > X X X X X X X X X X X X | ||
87 | + // > | ||
88 | + // > Throttled with `no_trailing` specified as true: | ||
89 | + // > ||||||||||||||||||||||||| (pause) ||||||||||||||||||||||||| | ||
90 | + // > X X X X X X X X X X | ||
91 | + // | ||
92 | + // Usage: | ||
93 | + // | ||
94 | + // > var throttled = jQuery.throttle( delay, [ no_trailing, ] callback ); | ||
95 | + // > | ||
96 | + // > jQuery('selector').bind( 'someevent', throttled ); | ||
97 | + // > jQuery('selector').unbind( 'someevent', throttled ); | ||
98 | + // | ||
99 | + // This also works in jQuery 1.4+: | ||
100 | + // | ||
101 | + // > jQuery('selector').bind( 'someevent', jQuery.throttle( delay, [ no_trailing, ] callback ) ); | ||
102 | + // > jQuery('selector').unbind( 'someevent', callback ); | ||
103 | + // | ||
104 | + // Arguments: | ||
105 | + // | ||
106 | + // delay - (Number) A zero-or-greater delay in milliseconds. For event | ||
107 | + // callbacks, values around 100 or 250 (or even higher) are most useful. | ||
108 | + // no_trailing - (Boolean) Optional, defaults to false. If no_trailing is | ||
109 | + // true, callback will only execute every `delay` milliseconds while the | ||
110 | + // throttled-function is being called. If no_trailing is false or | ||
111 | + // unspecified, callback will be executed one final time after the last | ||
112 | + // throttled-function call. (After the throttled-function has not been | ||
113 | + // called for `delay` milliseconds, the internal counter is reset) | ||
114 | + // callback - (Function) A function to be executed after delay milliseconds. | ||
115 | + // The `this` context and all arguments are passed through, as-is, to | ||
116 | + // `callback` when the throttled-function is executed. | ||
117 | + // | ||
118 | + // Returns: | ||
119 | + // | ||
120 | + // (Function) A new, throttled, function. | ||
121 | + | ||
122 | + $.throttle = jq_throttle = function(delay, no_trailing, callback, debounce_mode) { | ||
123 | + // After wrapper has stopped being called, this timeout ensures that | ||
124 | + // `callback` is executed at the proper times in `throttle` and `end` | ||
125 | + // debounce modes. | ||
126 | + var timeout_id, | ||
127 | + | ||
128 | + // Keep track of the last time `callback` was executed. | ||
129 | + last_exec = 0; | ||
130 | + | ||
131 | + // `no_trailing` defaults to falsy. | ||
132 | + if (typeof no_trailing !== 'boolean') { | ||
133 | + debounce_mode = callback; | ||
134 | + callback = no_trailing; | ||
135 | + no_trailing = undefined; | ||
136 | + } | ||
137 | + | ||
138 | + // The `wrapper` function encapsulates all of the throttling / debouncing | ||
139 | + // functionality and when executed will limit the rate at which `callback` | ||
140 | + // is executed. | ||
141 | + function wrapper() { | ||
142 | + var that = this, | ||
143 | + elapsed = +new Date() - last_exec, | ||
144 | + args = arguments; | ||
145 | + | ||
146 | + // Execute `callback` and update the `last_exec` timestamp. | ||
147 | + function exec() { | ||
148 | + last_exec = +new Date(); | ||
149 | + callback.apply(that, args); | ||
150 | + }; | ||
151 | + | ||
152 | + // If `debounce_mode` is true (at_begin) this is used to clear the flag | ||
153 | + // to allow future `callback` executions. | ||
154 | + function clear() { | ||
155 | + timeout_id = undefined; | ||
156 | + }; | ||
157 | + | ||
158 | + if (debounce_mode && !timeout_id) { | ||
159 | + // Since `wrapper` is being called for the first time and | ||
160 | + // `debounce_mode` is true (at_begin), execute `callback`. | ||
161 | + exec(); | ||
162 | + } | ||
163 | + | ||
164 | + // Clear any existing timeout. | ||
165 | + timeout_id && clearTimeout(timeout_id); | ||
166 | + | ||
167 | + if (debounce_mode === undefined && elapsed > delay) { | ||
168 | + // In throttle mode, if `delay` time has been exceeded, execute | ||
169 | + // `callback`. | ||
170 | + exec(); | ||
171 | + | ||
172 | + } else if (no_trailing !== true) { | ||
173 | + // In trailing throttle mode, since `delay` time has not been | ||
174 | + // exceeded, schedule `callback` to execute `delay` ms after most | ||
175 | + // recent execution. | ||
176 | + // | ||
177 | + // If `debounce_mode` is true (at_begin), schedule `clear` to execute | ||
178 | + // after `delay` ms. | ||
179 | + // | ||
180 | + // If `debounce_mode` is false (at end), schedule `callback` to | ||
181 | + // execute after `delay` ms. | ||
182 | + timeout_id = setTimeout(debounce_mode ? clear : exec, debounce_mode === undefined ? delay - elapsed : delay); | ||
183 | + } | ||
184 | + }; | ||
185 | + | ||
186 | + // Set the guid of `wrapper` function to the same of original callback, so | ||
187 | + // it can be removed in jQuery 1.4+ .unbind or .die by using the original | ||
188 | + // callback as a reference. | ||
189 | + if ($.guid) { | ||
190 | + wrapper.guid = callback.guid = callback.guid || $.guid++; | ||
191 | + } | ||
192 | + | ||
193 | + // Return the wrapper function. | ||
194 | + return wrapper; | ||
195 | + }; | ||
196 | + | ||
197 | + // Method: jQuery.debounce | ||
198 | + // | ||
199 | + // Debounce execution of a function. Debouncing, unlike throttling, | ||
200 | + // guarantees that a function is only executed a single time, either at the | ||
201 | + // very beginning of a series of calls, or at the very end. If you want to | ||
202 | + // simply rate-limit execution of a function, see the <jQuery.throttle> | ||
203 | + // method. | ||
204 | + // | ||
205 | + // In this visualization, | is a debounced-function call and X is the actual | ||
206 | + // callback execution: | ||
207 | + // | ||
208 | + // > Debounced with `at_begin` specified as false or unspecified: | ||
209 | + // > ||||||||||||||||||||||||| (pause) ||||||||||||||||||||||||| | ||
210 | + // > X X | ||
211 | + // > | ||
212 | + // > Debounced with `at_begin` specified as true: | ||
213 | + // > ||||||||||||||||||||||||| (pause) ||||||||||||||||||||||||| | ||
214 | + // > X X | ||
215 | + // | ||
216 | + // Usage: | ||
217 | + // | ||
218 | + // > var debounced = jQuery.debounce( delay, [ at_begin, ] callback ); | ||
219 | + // > | ||
220 | + // > jQuery('selector').bind( 'someevent', debounced ); | ||
221 | + // > jQuery('selector').unbind( 'someevent', debounced ); | ||
222 | + // | ||
223 | + // This also works in jQuery 1.4+: | ||
224 | + // | ||
225 | + // > jQuery('selector').bind( 'someevent', jQuery.debounce( delay, [ at_begin, ] callback ) ); | ||
226 | + // > jQuery('selector').unbind( 'someevent', callback ); | ||
227 | + // | ||
228 | + // Arguments: | ||
229 | + // | ||
230 | + // delay - (Number) A zero-or-greater delay in milliseconds. For event | ||
231 | + // callbacks, values around 100 or 250 (or even higher) are most useful. | ||
232 | + // at_begin - (Boolean) Optional, defaults to false. If at_begin is false or | ||
233 | + // unspecified, callback will only be executed `delay` milliseconds after | ||
234 | + // the last debounced-function call. If at_begin is true, callback will be | ||
235 | + // executed only at the first debounced-function call. (After the | ||
236 | + // throttled-function has not been called for `delay` milliseconds, the | ||
237 | + // internal counter is reset) | ||
238 | + // callback - (Function) A function to be executed after delay milliseconds. | ||
239 | + // The `this` context and all arguments are passed through, as-is, to | ||
240 | + // `callback` when the debounced-function is executed. | ||
241 | + // | ||
242 | + // Returns: | ||
243 | + // | ||
244 | + // (Function) A new, debounced, function. | ||
245 | + | ||
246 | + $.debounce = function(delay, at_begin, callback) { | ||
247 | + return callback === undefined | ||
248 | + ? jq_throttle(delay, at_begin, false) | ||
249 | + : jq_throttle(delay, callback, at_begin !== false); | ||
250 | + }; | ||
251 | + | ||
252 | +})(jQuery); |
@@ -11,10 +11,15 @@ | @@ -11,10 +11,15 @@ | ||
11 | 11 | ||
12 | var $ = require('yoho-jquery'), | 12 | var $ = require('yoho-jquery'), |
13 | lazyLoad = require('yoho-jquery-lazyload'), | 13 | lazyLoad = require('yoho-jquery-lazyload'), |
14 | + dataLazyLoad = require('../plugins/lazy-load')(document), | ||
14 | Handlebars = require('yoho-handlebars'); | 15 | Handlebars = require('yoho-handlebars'); |
15 | 16 | ||
17 | +var bindEvent = $.Callbacks(); // eslint-disable-line | ||
18 | + | ||
16 | var $main = $('.main'), | 19 | var $main = $('.main'), |
17 | - id = $main.data('id'); | 20 | + id = $main.data('id'), |
21 | + md5 = $main.data('md5'), | ||
22 | + skn = $main.data('skn'); | ||
18 | 23 | ||
19 | var SLIDETIME = 200; | 24 | var SLIDETIME = 200; |
20 | 25 | ||
@@ -24,475 +29,480 @@ var colTxt = { | @@ -24,475 +29,480 @@ var colTxt = { | ||
24 | hover: '取消收藏' | 29 | hover: '取消收藏' |
25 | }; | 30 | }; |
26 | 31 | ||
27 | -var $imgShow = $('#img-show'), | ||
28 | - $thumbs = $('#thumbs > .thumb-wrap'); | 32 | +var $saleReturn = $('#saleReturn'); |
29 | 33 | ||
30 | -var $size = $('#sizes'), | ||
31 | - $sizes = $size.children('.size'), | ||
32 | - $sizeWarn = $size.find('.size-warn'), | ||
33 | - $colorSizeTip = $size.children('.color-size-tip'); | 34 | +bindEvent.add(function() { |
35 | + var $imgShow = $('#img-show'), | ||
36 | + $thumbs = $('#thumbs > .thumb-wrap'); | ||
34 | 37 | ||
35 | -var $num = $('#num'), | ||
36 | - $plusNum = $('#plus-num'), | ||
37 | - $minusNum = $('#minus-num'); | 38 | + var $size = $('#sizes'), |
39 | + $sizes = $size.children('.size'), | ||
40 | + $sizeWarn = $size.find('.size-warn'), | ||
41 | + $colorSizeTip = $size.children('.color-size-tip'); | ||
38 | 42 | ||
39 | -var $addToCart = $('#add-to-cart'), | ||
40 | - $soldOut = $('#sold-out'); | 43 | + var $num = $('#num'), |
44 | + $plusNum = $('#plus-num'), | ||
45 | + $minusNum = $('#minus-num'); | ||
41 | 46 | ||
42 | -var $lcContainer = $('.lc-container'), | ||
43 | - $itemBuy = $('.item-buy'); | 47 | + var $addToCart = $('#add-to-cart'), |
48 | + $soldOut = $('#sold-out'); | ||
44 | 49 | ||
45 | -var $descColor = $('#desc-color'); | 50 | + var $lcContainer = $('.lc-container'), |
51 | + $itemBuy = $('.item-buy'); | ||
46 | 52 | ||
47 | -var thumbsLoaded = {}; | 53 | + var $descColor = $('#desc-color'); |
48 | 54 | ||
49 | -var isTicket = $('input[name="isTicket"]').length > 0 && $('input[name="isTicket"]').val() === 'true'; | 55 | + var thumbsLoaded = {}; |
50 | 56 | ||
51 | -var maxStock = -1; // 记录当前选中的颜色-尺码的库存量,若为-1,代表未选择尺码 | 57 | + var isTicket = $('input[name="isTicket"]').length > 0 && $('input[name="isTicket"]').val() === 'true'; |
52 | 58 | ||
53 | -var Alert = require('../common/dialog').Alert; | 59 | + var maxStock = -1; // 记录当前选中的颜色-尺码的库存量,若为-1,代表未选择尺码 |
54 | 60 | ||
55 | -function imgShow(src) { | ||
56 | - $imgShow.attr('src', src); | ||
57 | -} | 61 | + var Alert = require('../common/dialog').Alert; |
58 | 62 | ||
59 | -/** | ||
60 | - * 获取当前选择的商品数目 | ||
61 | - * @return [Number] | ||
62 | - */ | ||
63 | -function getNum() { | ||
64 | - return +$num.text(); | ||
65 | -} | 63 | + function imgShow(src) { |
64 | + $imgShow.attr('src', src); | ||
65 | + } | ||
66 | 66 | ||
67 | -// 重置Num显示为1 | ||
68 | -function resetNum() { | ||
69 | - $num.text('1'); | 67 | + /** |
68 | + * 获取当前选择的商品数目 | ||
69 | + * @return [Number] | ||
70 | + */ | ||
71 | + function getNum() { | ||
72 | + return +$num.text(); | ||
73 | + } | ||
70 | 74 | ||
71 | - // +-按钮状态重置 | ||
72 | - if (maxStock === 1 || maxStock === 0) { | 75 | + // 重置Num显示为1 |
76 | + function resetNum() { | ||
77 | + $num.text('1'); | ||
73 | 78 | ||
74 | - // 数目为1/0时 | ||
75 | - $plusNum.addClass('dis'); | ||
76 | - $minusNum.addClass('dis'); | ||
77 | - } else { | ||
78 | - $plusNum.removeClass('dis'); | ||
79 | - $minusNum.addClass('dis'); | 79 | + // +-按钮状态重置 |
80 | + if (maxStock === 1 || maxStock === 0) { | ||
81 | + | ||
82 | + // 数目为1/0时 | ||
83 | + $plusNum.addClass('dis'); | ||
84 | + $minusNum.addClass('dis'); | ||
85 | + } else { | ||
86 | + $plusNum.removeClass('dis'); | ||
87 | + $minusNum.addClass('dis'); | ||
88 | + } | ||
80 | } | 89 | } |
81 | -} | ||
82 | 90 | ||
83 | -// 加入购物车和已售罄状态控制 | ||
84 | -function switchBtnStatus($color) { | ||
85 | - if ($itemBuy.length === 0) { | 91 | + // 加入购物车和已售罄状态控制 |
92 | + function switchBtnStatus($color) { | ||
93 | + if ($itemBuy.length === 0) { | ||
86 | 94 | ||
87 | - // 全部售罄,按钮状态不变 | ||
88 | - return; | ||
89 | - } | 95 | + // 全部售罄,按钮状态不变 |
96 | + return; | ||
97 | + } | ||
90 | 98 | ||
91 | - // 选中的商品存量为0或者某个颜色的total为0 | ||
92 | - if (maxStock === 0 || ($color && ~~$color.data('total') === 0)) { | ||
93 | - $itemBuy.addClass('hide'); // 隐藏加入购物车、即将开始、立即购买等相同位置的按钮 | ||
94 | - $soldOut.removeClass('hide'); | ||
95 | - } else { | 99 | + // 选中的商品存量为0或者某个颜色的total为0 |
100 | + if (maxStock === 0 || ($color && ~~$color.data('total') === 0)) { | ||
101 | + $itemBuy.addClass('hide'); // 隐藏加入购物车、即将开始、立即购买等相同位置的按钮 | ||
102 | + $soldOut.removeClass('hide'); | ||
103 | + } else { | ||
96 | 104 | ||
97 | - // 包括默认的-1情况下 | ||
98 | - $itemBuy.removeClass('hide'); | ||
99 | - $soldOut.addClass('hide'); | 105 | + // 包括默认的-1情况下 |
106 | + $itemBuy.removeClass('hide'); | ||
107 | + $soldOut.addClass('hide'); | ||
108 | + } | ||
100 | } | 109 | } |
101 | -} | ||
102 | 110 | ||
103 | -// size warn | ||
104 | -function showSizeWarn() { | ||
105 | - $sizes.not('.hide').children('.size-warn').removeClass('hide'); | ||
106 | -} | 111 | + // size warn |
112 | + function showSizeWarn() { | ||
113 | + $sizes.not('.hide').children('.size-warn').removeClass('hide'); | ||
114 | + } | ||
107 | 115 | ||
108 | -// size title | ||
109 | -(function() { | ||
110 | - var $sizeTitleJson = $('#size-title-json'), | ||
111 | - jsonHtml = $sizeTitleJson.html(), | ||
112 | - sizeTitle; | 116 | + // size title |
117 | + (function() { | ||
118 | + var $sizeTitleJson = $('#size-title-json'), | ||
119 | + jsonHtml = $sizeTitleJson.html(), | ||
120 | + sizeTitle; | ||
113 | 121 | ||
114 | - if (!jsonHtml) { | ||
115 | - return; | ||
116 | - } | 122 | + if (!jsonHtml) { |
123 | + return; | ||
124 | + } | ||
117 | 125 | ||
118 | - sizeTitle = $.parseJSON(jsonHtml); | 126 | + sizeTitle = $.parseJSON(jsonHtml); |
119 | 127 | ||
120 | - // 数据获取后删除 | ||
121 | - $sizeTitleJson.remove(); | 128 | + // 数据获取后删除 |
129 | + $sizeTitleJson.remove(); | ||
122 | 130 | ||
123 | - $sizes.children('li').each(function() { | ||
124 | - var $this = $(this), | ||
125 | - key = $this.data('name'); | 131 | + $sizes.children('li').each(function() { |
132 | + var $this = $(this), | ||
133 | + key = $this.data('name'); | ||
126 | 134 | ||
127 | - $this.data('title', sizeTitle[key]); | ||
128 | - }); | ||
129 | -}()); | 135 | + $this.data('title', sizeTitle[key]); |
136 | + }); | ||
137 | + }()); | ||
130 | 138 | ||
131 | -// 初始化thumbsLoaded | ||
132 | -thumbsLoaded[$('.colors .focus').index()] = true; | 139 | + require('../plugins/share'); |
133 | 140 | ||
134 | -// 品牌收藏 | ||
135 | -$('#brand-favour').click(function() { | ||
136 | - var $this = $(this); | 141 | + // 品牌收藏 |
142 | + $('#brand-favour').click(function() { | ||
143 | + var $this = $(this); | ||
137 | 144 | ||
138 | - $.ajax({ | ||
139 | - type: 'POST', | ||
140 | - url: '/product/index/favoriteBrand', | ||
141 | - data: { | ||
142 | - brandId: $this.data('id') | ||
143 | - } | ||
144 | - }).then(function(data) { | ||
145 | - if (data.code === 200) { | ||
146 | - $this.toggleClass('coled'); | ||
147 | - } else if (data.code === 403) { | ||
148 | - location.href = data.data.url; | ||
149 | - } | 145 | + $.ajax({ |
146 | + type: 'POST', | ||
147 | + url: '/product/index/favoriteBrand', | ||
148 | + data: { | ||
149 | + brandId: $this.data('id') | ||
150 | + } | ||
151 | + }).then(function(data) { | ||
152 | + if (data.code === 200) { | ||
153 | + $this.toggleClass('coled'); | ||
154 | + } else if (data.code === 403) { | ||
155 | + location.href = data.data.url; | ||
156 | + } | ||
157 | + }); | ||
150 | }); | 158 | }); |
151 | -}); | ||
152 | 159 | ||
153 | -// 颜色 | ||
154 | -$('.colors').on('click', 'li', function() { | ||
155 | - var $this = $(this), | ||
156 | - index = $this.index(); | 160 | + // 颜色 |
161 | + $('.colors').on('click', 'li', function() { | ||
162 | + var $this = $(this), | ||
163 | + index = $this.index(); | ||
157 | 164 | ||
158 | - var $imgs; | 165 | + var $imgs; |
159 | 166 | ||
160 | - // 初始化color-size显示或隐藏 | ||
161 | - $colorSizeTip.addClass('hide'); | 167 | + // 初始化color-size显示或隐藏 |
168 | + $colorSizeTip.addClass('hide'); | ||
162 | 169 | ||
163 | - // 隐藏尺码提示 | ||
164 | - $sizeWarn.addClass('hide'); | 170 | + // 隐藏尺码提示 |
171 | + $sizeWarn.addClass('hide'); | ||
165 | 172 | ||
166 | - maxStock = -1; | 173 | + maxStock = -1; |
167 | 174 | ||
168 | - if ($this.hasClass('focus')) { | 175 | + if ($this.hasClass('focus')) { |
169 | 176 | ||
170 | - // 已获取焦点的颜色再次点击,清除尺码的选中 | ||
171 | - $sizes.eq(index).children('li').removeClass('focus'); | ||
172 | - } else { | 177 | + // 已获取焦点的颜色再次点击,清除尺码的选中 |
178 | + $sizes.eq(index).children('li').removeClass('focus'); | ||
179 | + } else { | ||
173 | 180 | ||
174 | - // 未获取焦点,选择尺码 | ||
175 | - $this.siblings('.focus').removeClass('focus'); | ||
176 | - $this.addClass('focus'); | 181 | + // 未获取焦点,选择尺码 |
182 | + $this.siblings('.focus').removeClass('focus'); | ||
183 | + $this.addClass('focus'); | ||
177 | 184 | ||
178 | - // 切换图片显示 | ||
179 | - $thumbs.not('.hide').addClass('hide'); | ||
180 | - $imgs = $thumbs.eq(index).removeClass('hide').find('img'); | 185 | + // 切换图片显示 |
186 | + $thumbs.not('.hide').addClass('hide'); | ||
187 | + $imgs = $thumbs.eq(index).removeClass('hide').find('img'); | ||
181 | 188 | ||
182 | - if (typeof thumbsLoaded[index] === 'undefined') { | 189 | + if (typeof thumbsLoaded[index] === 'undefined') { |
183 | 190 | ||
184 | - // trigger layLoad | ||
185 | - lazyLoad($imgs, { | ||
186 | - event: 'sporty' | ||
187 | - }); | 191 | + // trigger layLoad |
192 | + lazyLoad($imgs, { | ||
193 | + event: 'sporty' | ||
194 | + }); | ||
188 | 195 | ||
189 | - $imgs.trigger('sporty'); | 196 | + $imgs.trigger('sporty'); |
190 | 197 | ||
191 | - thumbsLoaded[index] = true; | ||
192 | - } | 198 | + thumbsLoaded[index] = true; |
199 | + } | ||
193 | 200 | ||
194 | - imgShow($imgs.first().data('shower')); | 201 | + imgShow($imgs.first().data('shower')); |
195 | 202 | ||
196 | - // 切换详细信息的颜色显示 | ||
197 | - $descColor.text($this.data('color')); | 203 | + // 切换详细信息的颜色显示 |
204 | + $descColor.text($this.data('color')); | ||
198 | 205 | ||
199 | - // 切换尺码显示 | ||
200 | - $sizes.not('.hide').addClass('hide').children('li').removeClass('focus'); | ||
201 | - $sizes.eq(index).removeClass('hide'); | 206 | + // 切换尺码显示 |
207 | + $sizes.not('.hide').addClass('hide').children('li').removeClass('focus'); | ||
208 | + $sizes.eq(index).removeClass('hide'); | ||
202 | 209 | ||
203 | - // 是否展览票 | ||
204 | - if (isTicket) { | ||
205 | - $sizes.eq(index).children('li').trigger('click'); | ||
206 | - $('.chose-size').addClass('hide'); | 210 | + // 是否展览票 |
211 | + if (isTicket) { | ||
212 | + $sizes.eq(index).children('li').trigger('click'); | ||
213 | + $('.chose-size').addClass('hide'); | ||
214 | + } | ||
207 | } | 215 | } |
208 | - } | ||
209 | - | ||
210 | - resetNum(); | ||
211 | - switchBtnStatus($this); | ||
212 | -}); | ||
213 | 216 | ||
214 | -// 缩略图鼠标移入显示 | ||
215 | -$('#thumbs').on('mouseenter', '.thumb', function() { | ||
216 | - imgShow($(this).data('shower')); | ||
217 | -}); | 217 | + resetNum(); |
218 | + switchBtnStatus($this); | ||
219 | + }); | ||
218 | 220 | ||
219 | -// 尺码 | ||
220 | -$size.on('click', 'li', function() { | ||
221 | - var $this = $(this); | 221 | + // 缩略图鼠标移入显示 |
222 | + $('#thumbs').on('mouseenter', '.thumb', function() { | ||
223 | + imgShow($(this).data('shower')); | ||
224 | + }); | ||
222 | 225 | ||
223 | - if ($this.hasClass('focus')) { | ||
224 | - return; | ||
225 | - } | 226 | + // 尺码 |
227 | + $size.on('click', 'li', function() { | ||
228 | + var $this = $(this); | ||
226 | 229 | ||
227 | - maxStock = +$this.data('num'); | 230 | + if ($this.hasClass('focus')) { |
231 | + return; | ||
232 | + } | ||
228 | 233 | ||
229 | - $this.siblings('.focus').removeClass('focus'); | ||
230 | - $this.addClass('focus'); | 234 | + maxStock = +$this.data('num'); |
231 | 235 | ||
232 | - $colorSizeTip.html($this.data('title')).removeClass('hide'); | 236 | + $this.siblings('.focus').removeClass('focus'); |
237 | + $this.addClass('focus'); | ||
233 | 238 | ||
234 | - $sizeWarn.addClass('hide'); | 239 | + $colorSizeTip.html($this.data('title')).removeClass('hide'); |
235 | 240 | ||
236 | - switchBtnStatus(); | 241 | + $sizeWarn.addClass('hide'); |
237 | 242 | ||
238 | - resetNum(); | ||
239 | -}).on('click', '.size-ruler', function() { | 243 | + switchBtnStatus(); |
240 | 244 | ||
241 | - // 尺码帮助 | 245 | + resetNum(); |
246 | + }).on('click', '.size-ruler', function() { | ||
242 | 247 | ||
243 | - $('body,html').animate({ | ||
244 | - scrollTop: $('.size-info').offset().top | ||
245 | - }, 300); | ||
246 | -}); | 248 | + // 尺码帮助 |
247 | 249 | ||
248 | -// 增加购买数量 | ||
249 | -$plusNum.click(function() { | ||
250 | - var num = getNum(); | 250 | + $('body,html').animate({ |
251 | + scrollTop: $('.size-info').offset().top | ||
252 | + }, 300); | ||
253 | + }); | ||
251 | 254 | ||
252 | - if ($(this).hasClass('dis')) { | ||
253 | - return; | ||
254 | - } | 255 | + // 增加购买数量 |
256 | + $plusNum.click(function() { | ||
257 | + var num = getNum(); | ||
255 | 258 | ||
256 | - if (maxStock === -1) { | ||
257 | - showSizeWarn();// 显示选择尺码提示 | ||
258 | - return; | ||
259 | - } | 259 | + if ($(this).hasClass('dis')) { |
260 | + return; | ||
261 | + } | ||
260 | 262 | ||
261 | - // 已售罄 | ||
262 | - if (maxStock === 0) { | ||
263 | - return; | ||
264 | - } | 263 | + if (maxStock === -1) { |
264 | + showSizeWarn();// 显示选择尺码提示 | ||
265 | + return; | ||
266 | + } | ||
265 | 267 | ||
266 | - if (num === maxStock - 1) { | 268 | + // 已售罄 |
269 | + if (maxStock === 0) { | ||
270 | + return; | ||
271 | + } | ||
267 | 272 | ||
268 | - // +按钮不可点 | ||
269 | - $(this).addClass('dis'); | ||
270 | - } | 273 | + if (num === maxStock - 1) { |
271 | 274 | ||
272 | - // 数目为1时点+则移除-不可点状态 | ||
273 | - if (num === 1) { | ||
274 | - $minusNum.removeClass('dis'); | ||
275 | - } | 275 | + // +按钮不可点 |
276 | + $(this).addClass('dis'); | ||
277 | + } | ||
276 | 278 | ||
277 | - $num.text(num + 1 > maxStock ? maxStock : num + 1); | ||
278 | -}).on('selectstart', function() { | ||
279 | - return false; | ||
280 | -}); | 279 | + // 数目为1时点+则移除-不可点状态 |
280 | + if (num === 1) { | ||
281 | + $minusNum.removeClass('dis'); | ||
282 | + } | ||
281 | 283 | ||
282 | -// 减少购买数量 | ||
283 | -$minusNum.click(function() { | ||
284 | - var num = getNum(); | 284 | + $num.text(num + 1 > maxStock ? maxStock : num + 1); |
285 | + }).on('selectstart', function() { | ||
286 | + return false; | ||
287 | + }); | ||
285 | 288 | ||
286 | - if ($(this).hasClass('dis')) { | ||
287 | - return; | ||
288 | - } | 289 | + // 减少购买数量 |
290 | + $minusNum.click(function() { | ||
291 | + var num = getNum(); | ||
289 | 292 | ||
290 | - if (num === 2) { | ||
291 | - $(this).addClass('dis'); | ||
292 | - } | 293 | + if ($(this).hasClass('dis')) { |
294 | + return; | ||
295 | + } | ||
293 | 296 | ||
294 | - if (num === maxStock) { | 297 | + if (num === 2) { |
298 | + $(this).addClass('dis'); | ||
299 | + } | ||
295 | 300 | ||
296 | - // 恢复+可点 | ||
297 | - $plusNum.removeClass('dis'); | ||
298 | - } | 301 | + if (num === maxStock) { |
299 | 302 | ||
300 | - $num.text(num - 1 < 0 ? 0 : num - 1); | ||
301 | -}).on('selectstart', function() { | ||
302 | - return false; | ||
303 | -}); | 303 | + // 恢复+可点 |
304 | + $plusNum.removeClass('dis'); | ||
305 | + } | ||
304 | 306 | ||
305 | -// 限购码 | ||
306 | -$('.get-lc:not(.dis)').hover(function() { | ||
307 | - $lcContainer.removeClass('hide'); | ||
308 | -}, function() { | ||
309 | - $lcContainer.addClass('hide'); | ||
310 | -}); | 307 | + $num.text(num - 1 < 0 ? 0 : num - 1); |
308 | + }).on('selectstart', function() { | ||
309 | + return false; | ||
310 | + }); | ||
311 | 311 | ||
312 | -// 加入购物车 | ||
313 | -$addToCart.click(function() { | ||
314 | - if (maxStock === -1) { | ||
315 | - showSizeWarn(); | ||
316 | - return; | ||
317 | - } | 312 | + // 限购码 |
313 | + $('.get-lc:not(.dis)').hover(function() { | ||
314 | + $lcContainer.removeClass('hide'); | ||
315 | + }, function() { | ||
316 | + $lcContainer.addClass('hide'); | ||
317 | + }); | ||
318 | 318 | ||
319 | - $.ajax({ | ||
320 | - type: 'POST', | ||
321 | - url: '/cart/index/add', | ||
322 | - data: { | ||
323 | - productSku: $('.size:not(.hide) li.focus').data('sku'), | ||
324 | - buyNumber: getNum() | 319 | + // 加入购物车 |
320 | + $addToCart.click(function() { | ||
321 | + if (maxStock === -1) { | ||
322 | + showSizeWarn(); | ||
323 | + return; | ||
325 | } | 324 | } |
326 | - }).then(function(data) { | ||
327 | - var code = data.code; | ||
328 | 325 | ||
329 | - if (code === 200) { | ||
330 | - $('#type-chose').slideUp(SLIDETIME); | ||
331 | - $('#balance').slideDown(SLIDETIME); | 326 | + $.ajax({ |
327 | + type: 'POST', | ||
328 | + url: '/cart/index/add', | ||
329 | + data: { | ||
330 | + productSku: $('.size:not(.hide) li.focus').data('sku'), | ||
331 | + buyNumber: getNum() | ||
332 | + } | ||
333 | + }).then(function(data) { | ||
334 | + var code = data.code; | ||
335 | + | ||
336 | + if (code === 200) { | ||
337 | + $('#type-chose').slideUp(SLIDETIME); | ||
338 | + $('#balance').slideDown(SLIDETIME); | ||
332 | 339 | ||
333 | - $('#cart-num').text(data.data.goods_count); // 更新数目 | ||
334 | - } | 340 | + $('#cart-num').text(data.data.goods_count); // 更新数目 |
341 | + } | ||
342 | + }); | ||
335 | }); | 343 | }); |
336 | -}); | ||
337 | - | ||
338 | -// 收藏 | ||
339 | -$('#collect-product').click(function() { | ||
340 | - var $this = $(this), | ||
341 | - cancel; | ||
342 | 344 | ||
343 | - if ($this.hasClass('coled')) { | ||
344 | - cancel = true; | ||
345 | - } | 345 | + // 收藏 |
346 | + $('#collect-product').click(function() { | ||
347 | + var $this = $(this), | ||
348 | + cancel; | ||
346 | 349 | ||
347 | - $.ajax({ | ||
348 | - type: 'POST', | ||
349 | - url: '/product/item/togglecollect', | ||
350 | - data: { | ||
351 | - productId: id, | ||
352 | - type: cancel ? 'cancel' : 'add' | 350 | + if ($this.hasClass('coled')) { |
351 | + cancel = true; | ||
353 | } | 352 | } |
354 | - }).then(function(data) { | ||
355 | - var code = data.code; | ||
356 | 353 | ||
357 | - if (code === 200) { | 354 | + $.ajax({ |
355 | + type: 'POST', | ||
356 | + url: '/product/item/togglecollect', | ||
357 | + data: { | ||
358 | + productId: id, | ||
359 | + type: cancel ? 'cancel' : 'add' | ||
360 | + } | ||
361 | + }).then(function(data) { | ||
362 | + var code = data.code; | ||
363 | + | ||
364 | + if (code === 200) { | ||
358 | 365 | ||
359 | - $this.toggleClass('coled'); | 366 | + $this.toggleClass('coled'); |
360 | 367 | ||
361 | - if (cancel) { | ||
362 | - $this.find('em').text(colTxt.def); | ||
363 | - } else { | ||
364 | - $this.find('em').text(colTxt.coled); | 368 | + if (cancel) { |
369 | + $this.find('em').text(colTxt.def); | ||
370 | + } else { | ||
371 | + $this.find('em').text(colTxt.coled); | ||
372 | + } | ||
373 | + } else if (code === 403) { | ||
374 | + location.href = data.data.url; | ||
365 | } | 375 | } |
366 | - } else if (code === 403) { | ||
367 | - location.href = data.data.url; | 376 | + }); |
377 | + }).hover(function() { | ||
378 | + var $this = $(this); | ||
379 | + | ||
380 | + if ($this.hasClass('coled')) { | ||
381 | + $this.find('em').text(colTxt.hover); | ||
368 | } | 382 | } |
369 | - }); | ||
370 | -}).hover(function() { | ||
371 | - var $this = $(this); | 383 | + }, function() { |
384 | + var $this = $(this); | ||
372 | 385 | ||
373 | - if ($this.hasClass('coled')) { | ||
374 | - $this.find('em').text(colTxt.hover); | ||
375 | - } | ||
376 | -}, function() { | ||
377 | - var $this = $(this); | 386 | + if ($this.hasClass('coled')) { |
387 | + $this.find('em').text(colTxt.coled); | ||
388 | + } | ||
389 | + }); | ||
378 | 390 | ||
379 | - if ($this.hasClass('coled')) { | ||
380 | - $this.find('em').text(colTxt.coled); | ||
381 | - } | ||
382 | -}); | 391 | + // 继续购物 |
392 | + $('#keep-shopping').click(function() { | ||
393 | + $('#type-chose').slideDown(SLIDETIME); | ||
394 | + $('#balance').slideUp(SLIDETIME); | ||
395 | + }); | ||
383 | 396 | ||
384 | -// 继续购物 | ||
385 | -$('#keep-shopping').click(function() { | ||
386 | - $('#type-chose').slideDown(SLIDETIME); | ||
387 | - $('#balance').slideUp(SLIDETIME); | ||
388 | -}); | 397 | + // 电子票立即购买 |
398 | + $('#buy-ticket').click(function() { | ||
399 | + var sku, | ||
400 | + buyNumber; | ||
389 | 401 | ||
390 | -// 电子票立即购买 | ||
391 | -$('#buy-ticket').click(function() { | ||
392 | - var sku, | ||
393 | - buyNumber; | 402 | + if (maxStock === -1) { |
403 | + showSizeWarn(); | ||
404 | + return; | ||
405 | + } | ||
394 | 406 | ||
395 | - if (maxStock === -1) { | ||
396 | - showSizeWarn(); | ||
397 | - return; | ||
398 | - } | 407 | + if ($(this).hasClass('dis')) { |
408 | + return; | ||
409 | + } | ||
399 | 410 | ||
400 | - if ($(this).hasClass('dis')) { | ||
401 | - return; | ||
402 | - } | 411 | + sku = $('.size:not(.hide) li.focus').data('sku'); |
412 | + buyNumber = getNum(); | ||
403 | 413 | ||
404 | - sku = $('.size:not(.hide) li.focus').data('sku'); | ||
405 | - buyNumber = getNum(); | 414 | + $.ajax({ |
415 | + type: 'POST', | ||
416 | + url: '/cart/index/setTicket', | ||
417 | + data: { | ||
418 | + productSku: sku, | ||
419 | + buyNumber: buyNumber | ||
420 | + } | ||
421 | + }).then(function(data) { | ||
422 | + var $ticketForm, | ||
423 | + myAlert; | ||
424 | + | ||
425 | + if (data.code * 1 === 200) { | ||
426 | + $ticketForm = $('form[name="ticket-form"]'); | ||
427 | + $ticketForm.html( | ||
428 | + '<input name="productSku" value="' + sku + '" />' + | ||
429 | + '<input name="buyNumber" value="' + buyNumber + '" />' | ||
430 | + ); | ||
431 | + $ticketForm.submit(); | ||
432 | + } else if (data.code * 1 === 401) { | ||
433 | + document.location.href = data.message; | ||
434 | + } else { | ||
435 | + myAlert = new Alert(data.message); | ||
436 | + myAlert.show(); | ||
437 | + } | ||
438 | + }); | ||
439 | + }); | ||
406 | 440 | ||
407 | - $.ajax({ | ||
408 | - type: 'POST', | ||
409 | - url: '/cart/index/setTicket', | ||
410 | - data: { | ||
411 | - productSku: sku, | ||
412 | - buyNumber: buyNumber | ||
413 | - } | ||
414 | - }).then(function(data) { | ||
415 | - var $ticketForm, | 441 | + // 立即购买 |
442 | + $('#buy-now').click(function() { | ||
443 | + var sku, | ||
444 | + base, | ||
416 | myAlert; | 445 | myAlert; |
417 | 446 | ||
418 | - if (data.code * 1 === 200) { | ||
419 | - $ticketForm = $('form[name="ticket-form"]'); | ||
420 | - $ticketForm.html( | ||
421 | - '<input name="productSku" value="' + sku + '" />' + | ||
422 | - '<input name="buyNumber" value="' + buyNumber + '" />' | ||
423 | - ); | ||
424 | - $ticketForm.submit(); | ||
425 | - } else if (data.code * 1 === 401) { | ||
426 | - document.location.href = data.message; | ||
427 | - } else { | ||
428 | - myAlert = new Alert(data.message); | ||
429 | - myAlert.show(); | 447 | + if ($(this).hasClass('dis')) { |
448 | + return; | ||
430 | } | 449 | } |
431 | - }); | ||
432 | -}); | ||
433 | - | ||
434 | -// 立即购买 | ||
435 | -$('#buy-now').click(function() { | ||
436 | - var sku, | ||
437 | - base, | ||
438 | - myAlert; | ||
439 | 450 | ||
440 | - if (maxStock === -1) { | ||
441 | - showSizeWarn(); | ||
442 | - return; | ||
443 | - } | 451 | + if (maxStock === -1) { |
452 | + showSizeWarn(); | ||
453 | + return; | ||
454 | + } | ||
444 | 455 | ||
445 | - if ($(this).hasClass('dis')) { | ||
446 | - return; | ||
447 | - } | 456 | + base = $(this).data('base'); |
448 | 457 | ||
449 | - base = $(this).data('base'); | 458 | + // 潮流尖货 |
459 | + if (!base) { | ||
460 | + myAlert = new Alert('打开APP可抢购该商品哦~~'); | ||
461 | + myAlert.show(); | ||
462 | + return; | ||
463 | + } | ||
450 | 464 | ||
451 | - // 潮流尖货 | ||
452 | - if (!base) { | ||
453 | - myAlert = new Alert('打开APP可抢购该商品哦~~'); | ||
454 | - myAlert.show(); | ||
455 | - return; | ||
456 | - } | 465 | + sku = $sizes.find('.focus').data('sku'); |
457 | 466 | ||
458 | - sku = $sizes.find('.focus').data('sku'); | 467 | + if (sku && base) { |
468 | + location.href = base + '?product_sku=' + sku; | ||
469 | + } | ||
470 | + }); | ||
459 | 471 | ||
460 | - if (sku && base) { | ||
461 | - location.href = base + '?product_sku=' + sku; | ||
462 | - } | ||
463 | -}); | 472 | + // 按钮鼠标移入效果【dis状态的按钮状态不变】 |
473 | + $('.buy-btn').mouseover(function() { | ||
474 | + if ($(this).hasClass('dis')) { | ||
475 | + return; | ||
476 | + } | ||
464 | 477 | ||
465 | -// 按钮鼠标移入效果【dis状态的按钮状态不变】 | ||
466 | -$('.buy-btn').mouseover(function() { | ||
467 | - if ($(this).hasClass('dis')) { | ||
468 | - return; | ||
469 | - } | 478 | + $(this).addClass('hover'); |
479 | + }).mouseleave(function() { | ||
480 | + $(this).removeClass('hover'); | ||
481 | + }); | ||
470 | 482 | ||
471 | - $(this).addClass('hover'); | ||
472 | -}).mouseleave(function() { | ||
473 | - $(this).removeClass('hover'); | ||
474 | -}); | 483 | + // 只有一个尺码(多个或一个颜色)时默认选中第一个未售罄的颜色的第一个尺码 |
484 | + (function() { | ||
485 | + var hasOnlyOneSize = true, | ||
486 | + i; | ||
475 | 487 | ||
476 | -// 只有一个尺码(多个或一个颜色)时默认选中第一个未售罄的颜色的第一个尺码 | ||
477 | -(function() { | ||
478 | - var hasOnlyOneSize = true, | ||
479 | - i; | 488 | + for (i = 0; i < $sizes.length; i++) { |
489 | + if ($sizes.eq(i).find('li').length !== 1) { | ||
490 | + hasOnlyOneSize = false; | ||
491 | + break; | ||
492 | + } | ||
493 | + } | ||
480 | 494 | ||
481 | - for (i = 0; i < $sizes.length; i++) { | ||
482 | - if ($sizes.eq(i).find('li').length !== 1) { | ||
483 | - hasOnlyOneSize = false; | ||
484 | - break; | 495 | + if (hasOnlyOneSize) { |
496 | + $sizes.eq($('.colors .focus').index()).find('li').click(); | ||
485 | } | 497 | } |
486 | - } | 498 | + }()); |
487 | 499 | ||
488 | - if (hasOnlyOneSize) { | ||
489 | - $sizes.eq($('.colors .focus').index()).find('li').click(); | ||
490 | - } | ||
491 | -}()); | 500 | +}); |
501 | + | ||
502 | +// yas | ||
503 | +require('../common'); | ||
492 | 504 | ||
493 | -require('../common'); // yas | ||
494 | require('./detail/latest-walk'); // 最近浏览 | 505 | require('./detail/latest-walk'); // 最近浏览 |
495 | -require('../plugins/share'); // 分享 | ||
496 | 506 | ||
497 | // 商品详情/材质洗涤切换 | 507 | // 商品详情/材质洗涤切换 |
498 | $('.description-material').on('click', '.title', function() { | 508 | $('.description-material').on('click', '.title', function() { |
@@ -541,52 +551,40 @@ $('.after-service-switch').click(function() { | @@ -541,52 +551,40 @@ $('.after-service-switch').click(function() { | ||
541 | } | 551 | } |
542 | }); | 552 | }); |
543 | 553 | ||
544 | - | ||
545 | // 商品详情区的热点 | 554 | // 商品详情区的热点 |
546 | -$.ajax({ | ||
547 | - type: 'GET', | ||
548 | - url: '/product/detail/hotarea', | ||
549 | - data: { | ||
550 | - productId: id | ||
551 | - } | ||
552 | -}).then(function(html) { | ||
553 | - $('#details-html').prepend(html); | ||
554 | 555 | ||
555 | - // 修正热区尺寸使居中 | ||
556 | - $('.hot-point-wrap > img').load(function() { | ||
557 | - $(this).parent('.hot-point-wrap').width($(this).width()); | ||
558 | - }); | 556 | +function fetchHotArea() { |
557 | + $.ajax({ | ||
558 | + type: 'GET', | ||
559 | + url: '/product/detail/hotarea', | ||
560 | + data: { | ||
561 | + productId: id | ||
562 | + } | ||
563 | + }).then(function(html) { | ||
564 | + $('#details-html').prepend(html); | ||
559 | 565 | ||
560 | - // Bind Hover event | ||
561 | - $('.hot-point').hover(function() { | ||
562 | - $(this).addClass('hover'); | ||
563 | - }, function() { | ||
564 | - $(this).removeClass('hover'); | ||
565 | - }); | ||
566 | -}); | 566 | + // 修正热区尺寸使居中 |
567 | + $('.hot-point-wrap > img').load(function() { | ||
568 | + $(this).parent('.hot-point-wrap').width($(this).width()); | ||
569 | + }); | ||
567 | 570 | ||
568 | -// 商品详情懒加载 | ||
569 | -lazyLoad($('#details-html img')); | 571 | + // Bind Hover event |
572 | + $('.hot-point').hover(function() { | ||
573 | + $(this).addClass('hover'); | ||
574 | + }, function() { | ||
575 | + $(this).removeClass('hover'); | ||
576 | + }); | ||
577 | + }); | ||
578 | +} | ||
570 | 579 | ||
571 | -// 只有一个尺码(多个或一个颜色)时默认选中第一个未售罄的颜色的第一个尺码 | ||
572 | -(function() { | ||
573 | - var hasOnlyOneSize = true, | ||
574 | - i; | 580 | +window.fetchHotArea = fetchHotArea; |
575 | 581 | ||
576 | - for (i = 0; i < $sizes.length; i++) { | ||
577 | - if ($sizes.eq(i).find('li').length !== 1) { | ||
578 | - hasOnlyOneSize = false; | ||
579 | - break; | ||
580 | - } | ||
581 | - } | 582 | +// 商品详情图片懒加载 |
583 | +lazyLoad($('#details-html img')); | ||
582 | 584 | ||
583 | - if (hasOnlyOneSize) { | ||
584 | - $sizes.eq($('.colors .focus').index()).find('li').click(); | ||
585 | - } | ||
586 | -}()); | ||
587 | 585 | ||
588 | // 咨询和评价 | 586 | // 咨询和评价 |
589 | -(function() { | 587 | +function fetchComment() { |
590 | var commentPage = 1, | 588 | var commentPage = 1, |
591 | consultPage = 1; | 589 | consultPage = 1; |
592 | 590 | ||
@@ -773,4 +771,58 @@ lazyLoad($('#details-html img')); | @@ -773,4 +771,58 @@ lazyLoad($('#details-html img')); | ||
773 | 771 | ||
774 | loadComments(); | 772 | loadComments(); |
775 | loadConsults(); | 773 | loadConsults(); |
774 | +} | ||
775 | + | ||
776 | +window.fetchComment = fetchComment; | ||
777 | + | ||
778 | +// 特殊商品退换货 | ||
779 | +function fetchReturn() { | ||
780 | + return $.ajax({ | ||
781 | + type: 'GET', | ||
782 | + url: '/product/detail/return', | ||
783 | + data: { | ||
784 | + skn: skn | ||
785 | + } | ||
786 | + }).then(function(result) { | ||
787 | + if (result.code === 200) { | ||
788 | + if (result.data.result === 'N') { | ||
789 | + $saleReturn.removeClass().addClass('not-support-saleReturned-service'); | ||
790 | + } | ||
791 | + } | ||
792 | + }); | ||
793 | +} | ||
794 | + | ||
795 | +window.fetchReturn = fetchReturn; | ||
796 | + | ||
797 | +// 首屏加载后,对比数据是否变化,如果变化,重新渲染,重新绑定事件 | ||
798 | +// 当前只渲染商品详情页的变化敏感的部分 | ||
799 | +(function() { | ||
800 | + $.ajax({ | ||
801 | + type: 'GET', | ||
802 | + url: '/product/detail/header', | ||
803 | + dataType: 'html', | ||
804 | + data: { | ||
805 | + productId: id, | ||
806 | + md5: md5 | ||
807 | + } | ||
808 | + }).then(function(result) { | ||
809 | + $('.main').html(result); | ||
810 | + bindEvent.fire(); | ||
811 | + }); | ||
812 | + | ||
813 | + $.ajax({ | ||
814 | + type: 'GET', | ||
815 | + url: '/product/index/isfav', | ||
816 | + data: { | ||
817 | + brandId: $('#brand-favour').data('id') | ||
818 | + } | ||
819 | + }).then(function(result) { | ||
820 | + if (result.code === 200) { | ||
821 | + $('#brand-favour').addClass('coled'); | ||
822 | + } | ||
823 | + }); | ||
824 | + | ||
776 | }()); | 825 | }()); |
826 | + | ||
827 | +// 数据懒加载 | ||
828 | +dataLazyLoad.init({cls: '.datalazyload', threshold: 0}); |
@@ -7,10 +7,11 @@ | @@ -7,10 +7,11 @@ | ||
7 | var $ = require('yoho-jquery'); | 7 | var $ = require('yoho-jquery'); |
8 | var Handlebars = require('yoho-handlebars'); | 8 | var Handlebars = require('yoho-handlebars'); |
9 | var lazyLoad = require('yoho-jquery-lazyload'); | 9 | var lazyLoad = require('yoho-jquery-lazyload'); |
10 | +var dataLazyLoad = require('../../plugins/lazy-load')(document); | ||
10 | 11 | ||
11 | var $latestWalkCount = $('#latest-walk-count'); | 12 | var $latestWalkCount = $('#latest-walk-count'); |
12 | 13 | ||
13 | -(function() { | 14 | +function fetchLatestWalk() { |
14 | var tpl; | 15 | var tpl; |
15 | 16 | ||
16 | if ($latestWalkCount.length === 0) { | 17 | if ($latestWalkCount.length === 0) { |
@@ -59,4 +60,9 @@ var $latestWalkCount = $('#latest-walk-count'); | @@ -59,4 +60,9 @@ var $latestWalkCount = $('#latest-walk-count'); | ||
59 | } | 60 | } |
60 | } | 61 | } |
61 | }); | 62 | }); |
62 | -}()); | 63 | +} |
64 | + | ||
65 | +window.fetchLatestWalk = fetchLatestWalk; | ||
66 | + | ||
67 | +// 数据懒加载 | ||
68 | +dataLazyLoad.init({cls: '.latest-walk-datalazyload', threshold: 700}); |
@@ -659,6 +659,29 @@ $(function() { | @@ -659,6 +659,29 @@ $(function() { | ||
659 | } | 659 | } |
660 | }, 100); | 660 | }, 100); |
661 | 661 | ||
662 | + | ||
663 | + var rightsFirst = '<div class="item-content hide">' + | ||
664 | + '<p class="item-title">新品立享9折</p>' + | ||
665 | + '<p>学生购买原价新品时,可立即享受9折优惠,与VIP折扣不可同时享受。</p></div>'; | ||
666 | + | ||
667 | + var rightsSecond = '<div class="item-content hide">' + | ||
668 | + '<p class="item-title">每1元返1个有货币</p>' + | ||
669 | + '<p>学生购买指定商品时,以商品的实际成交金额计算,每1元返1个有货币;</p>' + | ||
670 | + '<p>返有货币时间:确认收货7日后,系统将自动将对应数量的有货币返至购买账户;</p>' + | ||
671 | + '<p>有货币有效期:获得当日至次年12月31日,逾期自动作废;</p>' + | ||
672 | + '<p>查看有货币:登录后,点击“个人中心”在“我的有货币”中可以查看有货币余额及明细。</p></div>'; | ||
673 | + | ||
674 | + var rightsThird = '<div class="item-content hide">' + | ||
675 | + '<p class="item-title">免单抽奖</p>' + | ||
676 | + '<p>每月将在累计购物金额最高的学校中,抽取3名幸运学生用户,获得免单资格;</p>' + | ||
677 | + '<p>免单用户名单将在每月第1个工作日公布在有货微信公众号上,可关注【有货YOHOBUY】;</p>' + | ||
678 | + '<p>免单用户将在中奖次日获得与实付金额等额的现金券,使用时间:中奖当月。</p></div>'; | ||
679 | + | ||
680 | + var rightsFourth = '<div class="item-content hide">' + | ||
681 | + '<p class="item-title">学生专享活动</p>' + | ||
682 | + '<p>每月不定期的开展学生专享活动,可打开有货APP推送,及时查收学生专享活动通知。</p></div>'; | ||
683 | + | ||
684 | + | ||
662 | $('.coupon > a').each(function() { | 685 | $('.coupon > a').each(function() { |
663 | couponIds.push($(this).attr('data-id')); | 686 | couponIds.push($(this).attr('data-id')); |
664 | }); | 687 | }); |
@@ -790,6 +813,30 @@ $(function() { | @@ -790,6 +813,30 @@ $(function() { | ||
790 | F_INDEX: 6, | 813 | F_INDEX: 6, |
791 | I_INDEX: parseInt(index, 0) + 1}); | 814 | I_INDEX: parseInt(index, 0) + 1}); |
792 | }); | 815 | }); |
816 | + | ||
817 | + // 学生权益,悬浮显示内容 | ||
818 | + $('#stuRights .stu-rights-item:eq(0)').append(rightsFirst); | ||
819 | + $('#stuRights .stu-rights-item:eq(1)').append(rightsSecond); | ||
820 | + $('#stuRights .stu-rights-item:eq(2)').append(rightsThird); | ||
821 | + $('#stuRights .stu-rights-item:eq(3)').append(rightsFourth); | ||
822 | + | ||
823 | + // 悬浮效果 | ||
824 | + $('#stuRights .stu-rights-item:eq(0), #stuRights .stu-rights-item:eq(1),' + | ||
825 | + '#stuRights .stu-rights-item:eq(2), #stuRights .stu-rights-item:eq(3)').hover(function() { | ||
826 | + var content = $(this).find('.item-content'); | ||
827 | + | ||
828 | + content.removeClass('hide'); | ||
829 | + | ||
830 | + let gapHeight = parseInt(content.height(), 10) + 40 - parseInt($(this).height(), 10); | ||
831 | + | ||
832 | + if (gapHeight > 0) { | ||
833 | + content.css('margin-top', -(gapHeight) + 'px'); | ||
834 | + } | ||
835 | + }, function() { | ||
836 | + var content = $(this).find('.item-content'); | ||
837 | + | ||
838 | + content.addClass('hide').css('margin-top', '0'); | ||
839 | + }); | ||
793 | }); | 840 | }); |
794 | 841 | ||
795 | window.onbeforeunload = function() { | 842 | window.onbeforeunload = function() { |
@@ -2,6 +2,8 @@ var $ = require('yoho-jquery'); | @@ -2,6 +2,8 @@ var $ = require('yoho-jquery'); | ||
2 | 2 | ||
3 | var $apiDom = $('#api-domain'); | 3 | var $apiDom = $('#api-domain'); |
4 | 4 | ||
5 | +require('./common'); | ||
6 | + | ||
5 | // var apiDomain = $apiDom.val(); // 获取数据的地址 | 7 | // var apiDomain = $apiDom.val(); // 获取数据的地址 |
6 | 8 | ||
7 | $apiDom.remove(); // 删除API信息 | 9 | $apiDom.remove(); // 删除API信息 |
@@ -70,12 +72,12 @@ function setLoginStatus(data) { | @@ -70,12 +72,12 @@ function setLoginStatus(data) { | ||
70 | if (data.result !== -1) { | 72 | if (data.result !== -1) { |
71 | name = formatUsernName(info.profileName); | 73 | name = formatUsernName(info.profileName); |
72 | loginHtml = '<span>Hi~</span>' + | 74 | loginHtml = '<span>Hi~</span>' + |
73 | - '<a href="//www.yohobuy.com/home?t=' + info.random + '">' + name + '</a> ' + | ||
74 | - '<a href="//www.yohobuy.com/logout.html">[退出]</a>'; | 75 | + '<a href="//www.yohobuy.com/home?t=' + info.random + '">' + name + '</a> ' + |
76 | + '<a href="//www.yohobuy.com/logout.html">[退出]</a>'; | ||
75 | } else { | 77 | } else { |
76 | loginHtml = '<span>Hi~</span> ' + | 78 | loginHtml = '<span>Hi~</span> ' + |
77 | - '<a href="//www.yohobuy.com/signin.html">[请登录]</a> ' + | ||
78 | - '<a href="//www.yohobuy.com/reg.html">[免费注册]</a>'; | 79 | + '<a href="//www.yohobuy.com/signin.html?refer="' + window.location.href + '>[请登录]</a> ' + |
80 | + '<a href="//www.yohobuy.com/reg.html"' + window.location.href + '>[免费注册]</a>'; | ||
79 | } | 81 | } |
80 | $('.header-tool li').eq(0).html(loginHtml); | 82 | $('.header-tool li').eq(0).html(loginHtml); |
81 | } | 83 | } |
@@ -96,5 +98,22 @@ function actionLoginInfo() { | @@ -96,5 +98,22 @@ function actionLoginInfo() { | ||
96 | }); | 98 | }); |
97 | } | 99 | } |
98 | 100 | ||
99 | -actionLoginInfo(); // 获取登录信息 | 101 | +// 获取头部登陆信息 |
102 | +(function() { | ||
103 | + var uid = getUid(), //eslint-disable-line | ||
104 | + profileName = getProfileName(); // eslint-disable-line | ||
105 | + | ||
106 | + var info = { | ||
107 | + random: $.now(), | ||
108 | + profileName: profileName | ||
109 | + }; | ||
110 | + | ||
111 | + if (uid !== 0) { | ||
112 | + info.result = 1; | ||
113 | + } else { | ||
114 | + info.result = -1; | ||
115 | + } | ||
116 | + | ||
117 | + setLoginStatus(info); | ||
118 | +}()); | ||
100 | 119 |
@@ -324,7 +324,7 @@ | @@ -324,7 +324,7 @@ | ||
324 | margin-top: -28px; | 324 | margin-top: -28px; |
325 | width: 60px; | 325 | width: 60px; |
326 | height: 56px; | 326 | height: 56px; |
327 | - background-image: resolve(img/index/play.png); | 327 | + background-image: resolve(index/play.png); |
328 | } | 328 | } |
329 | 329 | ||
330 | .video-title { | 330 | .video-title { |
@@ -714,7 +714,7 @@ | @@ -714,7 +714,7 @@ | ||
714 | margin-top: -28px; | 714 | margin-top: -28px; |
715 | width: 60px; | 715 | width: 60px; |
716 | height: 56px; | 716 | height: 56px; |
717 | - background-image: resolve(img/index/play.png); | 717 | + background-image: resolve(index/play.png); |
718 | } | 718 | } |
719 | 719 | ||
720 | .video-title { | 720 | .video-title { |
@@ -812,7 +812,7 @@ | @@ -812,7 +812,7 @@ | ||
812 | left: 15px; | 812 | left: 15px; |
813 | width: 325px; | 813 | width: 325px; |
814 | height: 287px; | 814 | height: 287px; |
815 | - background: resolve(img/index/brands-layer.png) no-repeat; | 815 | + background: resolve(index/brands-layer.png) no-repeat; |
816 | font-weight: normal; | 816 | font-weight: normal; |
817 | 817 | ||
818 | .layer-content { | 818 | .layer-content { |
@@ -864,7 +864,7 @@ | @@ -864,7 +864,7 @@ | ||
864 | } | 864 | } |
865 | 865 | ||
866 | .brands-layer-right { | 866 | .brands-layer-right { |
867 | - background: resolve(img/index/brands-layer.png) no-repeat 0 -287px; | 867 | + background: resolve(index/brands-layer.png) no-repeat 0 -287px; |
868 | left: -325px; | 868 | left: -325px; |
869 | top: -83px; | 869 | top: -83px; |
870 | 870 |
@@ -90,10 +90,10 @@ | @@ -90,10 +90,10 @@ | ||
90 | 90 | ||
91 | a { | 91 | a { |
92 | color: #8e8e8e; | 92 | color: #8e8e8e; |
93 | - | ||
94 | - span { | ||
95 | - color: #d0021b; | ||
96 | - } | 93 | + } |
94 | + | ||
95 | + a > span { | ||
96 | + color: #d0021b; | ||
97 | } | 97 | } |
98 | } | 98 | } |
99 | 99 | ||
@@ -214,7 +214,7 @@ | @@ -214,7 +214,7 @@ | ||
214 | } | 214 | } |
215 | } | 215 | } |
216 | 216 | ||
217 | - .myyoho:hover { | 217 | + .myyoho-hover { |
218 | background-color: #dcdcdc; | 218 | background-color: #dcdcdc; |
219 | 219 | ||
220 | .simple-user-center { | 220 | .simple-user-center { |
@@ -598,10 +598,15 @@ | @@ -598,10 +598,15 @@ | ||
598 | .nav-wrapper { | 598 | .nav-wrapper { |
599 | height: 40px; | 599 | height: 40px; |
600 | width: 100%; | 600 | width: 100%; |
601 | - background-color: #3a3a3a; | ||
602 | position: relative; | 601 | position: relative; |
603 | 602 | ||
604 | .sub-nav-list { | 603 | .sub-nav-list { |
604 | + display: none; | ||
605 | + | ||
606 | + &.cure { | ||
607 | + display: block; | ||
608 | + } | ||
609 | + | ||
605 | li { | 610 | li { |
606 | line-height: 40px; | 611 | line-height: 40px; |
607 | padding-right: 46px; | 612 | padding-right: 46px; |
@@ -720,6 +725,12 @@ | @@ -720,6 +725,12 @@ | ||
720 | } | 725 | } |
721 | } | 726 | } |
722 | 727 | ||
728 | +.yoho-header.boys { | ||
729 | + .nav-wrapper { | ||
730 | + background-color: #3a3a3a; | ||
731 | + } | ||
732 | +} | ||
733 | + | ||
723 | .yoho-header.girls { | 734 | .yoho-header.girls { |
724 | .search-2016 { | 735 | .search-2016 { |
725 | background-color: #ff88ae; | 736 | background-color: #ff88ae; |
@@ -705,7 +705,7 @@ | @@ -705,7 +705,7 @@ | ||
705 | left: 15px; | 705 | left: 15px; |
706 | width: 325px; | 706 | width: 325px; |
707 | height: 287px; | 707 | height: 287px; |
708 | - background: resolve(/index/brands-layer.png) no-repeat; | 708 | + background: resolve(index/brands-layer.png) no-repeat; |
709 | font-weight: normal; | 709 | font-weight: normal; |
710 | 710 | ||
711 | .layer-content { | 711 | .layer-content { |
@@ -750,11 +750,11 @@ | @@ -750,11 +750,11 @@ | ||
750 | } | 750 | } |
751 | } | 751 | } |
752 | .brands-layer-right { | 752 | .brands-layer-right { |
753 | - background: resolve(/index/brands-layer.png) no-repeat 0 -287px; | 753 | + background: resolve(index/brands-layer.png) no-repeat 0 -287px; |
754 | left: -325px; | 754 | left: -325px; |
755 | top: -83px; | 755 | top: -83px; |
756 | 756 | ||
757 | .layer-content { | 757 | .layer-content { |
758 | padding: 20px 35px 20px 20px; | 758 | padding: 20px 35px 20px 20px; |
759 | } | 759 | } |
760 | -} | ||
760 | +} |
@@ -96,6 +96,7 @@ | @@ -96,6 +96,7 @@ | ||
96 | padding: 20px 0 20px 20px; | 96 | padding: 20px 0 20px 20px; |
97 | 97 | ||
98 | .stu-rights-item { | 98 | .stu-rights-item { |
99 | + position: relative; | ||
99 | float: left; | 100 | float: left; |
100 | width: 262px; | 101 | width: 262px; |
101 | height: 200px; | 102 | height: 200px; |
@@ -103,6 +104,7 @@ | @@ -103,6 +104,7 @@ | ||
103 | text-align: center; | 104 | text-align: center; |
104 | background-color: #fff; | 105 | background-color: #fff; |
105 | border-radius: 5px; | 106 | border-radius: 5px; |
107 | + overflow: hidden; | ||
106 | } | 108 | } |
107 | 109 | ||
108 | .stu-rights-item img { | 110 | .stu-rights-item img { |
@@ -110,6 +112,27 @@ | @@ -110,6 +112,27 @@ | ||
110 | height: 162px; | 112 | height: 162px; |
111 | margin: 20px 0; | 113 | margin: 20px 0; |
112 | } | 114 | } |
115 | + | ||
116 | + .stu-rights-item .item-content { | ||
117 | + position: absolute; | ||
118 | + top: 0; | ||
119 | + padding: 20px; | ||
120 | + margin-top: 0; | ||
121 | + transition: margin-top 2s linear; | ||
122 | + background: rgba(255,255,255,.95); | ||
123 | + } | ||
124 | + | ||
125 | + .stu-rights-item .item-content .item-title { | ||
126 | + font-weight: bold; | ||
127 | + margin-bottom: 20px; | ||
128 | + margin-top: 20px; | ||
129 | + } | ||
130 | + | ||
131 | + .stu-rights-item .item-content > p:not(.item-title) { | ||
132 | + text-align: left; | ||
133 | + font-size: 13px; | ||
134 | + line-height: 25px; | ||
135 | + } | ||
113 | } | 136 | } |
114 | 137 | ||
115 | .stu-identity { | 138 | .stu-identity { |
-
Please register or login to post a comment