Showing
7 changed files
with
344 additions
and
27 deletions
@@ -35,16 +35,16 @@ exports.index = (req, res) => { | @@ -35,16 +35,16 @@ exports.index = (req, res) => { | ||
35 | responseData.devEnv = true; | 35 | responseData.devEnv = true; |
36 | 36 | ||
37 | // 假数据输出 | 37 | // 假数据输出 |
38 | - res.render('sale/index', Object.assign(responseData, simulation.saleIndex())); | 38 | + // res.render('sale/index', Object.assign(responseData, simulation.saleIndex())); |
39 | 39 | ||
40 | // 真实数据输出 | 40 | // 真实数据输出 |
41 | - /* return sale.getSaleIndexDate().then(result => { | 41 | + sale.getSaleIndexData().then(result => { |
42 | 42 | ||
43 | responseData.result = result; | 43 | responseData.result = result; |
44 | responseData.resultShow = JSON.stringify(result, null, 4); | 44 | responseData.resultShow = JSON.stringify(result, null, 4); |
45 | 45 | ||
46 | res.render('sale/index', responseData); | 46 | res.render('sale/index', responseData); |
47 | - });*/ | 47 | + }); |
48 | }) | 48 | }) |
49 | .catch(() => { | 49 | .catch(() => { |
50 | res.render('error', { devEnv: true, pageErr: true }); | 50 | res.render('error', { devEnv: true, pageErr: true }); |
@@ -175,3 +175,21 @@ exports.newSale = (req, res) => { | @@ -175,3 +175,21 @@ exports.newSale = (req, res) => { | ||
175 | res.render('error', { devEnv: true, pageErr: true }); | 175 | res.render('error', { devEnv: true, pageErr: true }); |
176 | }); | 176 | }); |
177 | }; | 177 | }; |
178 | + | ||
179 | +/** | ||
180 | + * 获取商品列表 | ||
181 | + * @param {[type]} req [description] | ||
182 | + * @param {[type]} res [description] | ||
183 | + * @return {[type]} [description] | ||
184 | + */ | ||
185 | +exports.getGoodsList = (req, res) => { | ||
186 | + return sale.getSaleGoodsData().then(result => { | ||
187 | + let responseData = {}; | ||
188 | + | ||
189 | + responseData.devEnv = true; | ||
190 | + responseData.result = result; | ||
191 | + responseData.footerTop = false; | ||
192 | + | ||
193 | + res.render('goods', responseData); | ||
194 | + }); | ||
195 | +}; |
@@ -19,7 +19,7 @@ app.engine('.hbs', hbs({ | @@ -19,7 +19,7 @@ app.engine('.hbs', hbs({ | ||
19 | defaultLayout: 'layout', | 19 | defaultLayout: 'layout', |
20 | layoutsDir: doraemon, | 20 | layoutsDir: doraemon, |
21 | partialsDir: [path.join(__dirname, 'views/partial'), `${doraemon}/partial`], | 21 | partialsDir: [path.join(__dirname, 'views/partial'), `${doraemon}/partial`], |
22 | - helpers: 'helpers' | 22 | + helpers: require('../../library/helpers') |
23 | })); | 23 | })); |
24 | 24 | ||
25 | // router | 25 | // router |
@@ -2,29 +2,19 @@ | @@ -2,29 +2,19 @@ | ||
2 | * @Author: Targaryen | 2 | * @Author: Targaryen |
3 | * @Date: 2016-05-19 10:20:08 | 3 | * @Date: 2016-05-19 10:20:08 |
4 | * @Last Modified by: Targaryen | 4 | * @Last Modified by: Targaryen |
5 | - * @Last Modified time: 2016-05-21 14:39:36 | 5 | + * @Last Modified time: 2016-05-23 16:39:03 |
6 | */ | 6 | */ |
7 | 7 | ||
8 | 'use strict'; | 8 | 'use strict'; |
9 | const library = '../../../library'; | 9 | const library = '../../../library'; |
10 | const API = require(`${library}/api`).API; | 10 | const API = require(`${library}/api`).API; |
11 | +const TARAPI = require(`${library}/tar-api`).TARAPI; | ||
11 | const sign = require(`${library}/sign`); | 12 | const sign = require(`${library}/sign`); |
12 | const api = new API(); | 13 | const api = new API(); |
14 | +const tarApi = new TARAPI(); | ||
13 | const _ = require('lodash'); | 15 | const _ = require('lodash'); |
14 | 16 | ||
15 | /** | 17 | /** |
16 | - * 处理 sale 首页原始数据 | ||
17 | - * @param {Object} origin [原始数据] | ||
18 | - * @return {Object} [结果] | ||
19 | - */ | ||
20 | -const handleSaleIndexData = (origin) => { | ||
21 | - var dest = {}; | ||
22 | - | ||
23 | - dest = origin; | ||
24 | - return dest; | ||
25 | -}; | ||
26 | - | ||
27 | -/** | ||
28 | * 处理商品列表数据 | 18 | * 处理商品列表数据 |
29 | * @param {[type]} origin [description] | 19 | * @param {[type]} origin [description] |
30 | * @return {[type]} [description] | 20 | * @return {[type]} [description] |
@@ -131,7 +121,7 @@ const handleSaleFilterData = (origin) => { | @@ -131,7 +121,7 @@ const handleSaleFilterData = (origin) => { | ||
131 | }; | 121 | }; |
132 | 122 | ||
133 | /** | 123 | /** |
134 | - * 处理分类筛选数据 | 124 | + * 处理页面左侧分类筛选数据 |
135 | * @return {[type]} [description] | 125 | * @return {[type]} [description] |
136 | */ | 126 | */ |
137 | const handleSaleSortData = (origin) => { | 127 | const handleSaleSortData = (origin) => { |
@@ -152,7 +142,19 @@ const handleSaleSortData = (origin) => { | @@ -152,7 +142,19 @@ const handleSaleSortData = (origin) => { | ||
152 | }; | 142 | }; |
153 | 143 | ||
154 | /** | 144 | /** |
155 | - * 返回商品列表 promise 对象 | 145 | + * 处理折扣专区活动数据 |
146 | + * @param {[type]} origin [description] | ||
147 | + * @return {[type]} [description] | ||
148 | + */ | ||
149 | +const handleSaleActivityData = (origin) => { | ||
150 | + var dest = {}; | ||
151 | + | ||
152 | + dest = origin; | ||
153 | + return dest; | ||
154 | +}; | ||
155 | + | ||
156 | +/** | ||
157 | + * 获取商品列表 promise 对象 | ||
156 | * @return {[type]} [description] | 158 | * @return {[type]} [description] |
157 | */ | 159 | */ |
158 | const getSaleGoodsList = () => { | 160 | const getSaleGoodsList = () => { |
@@ -167,7 +169,7 @@ const getSaleGoodsList = () => { | @@ -167,7 +169,7 @@ const getSaleGoodsList = () => { | ||
167 | }; | 169 | }; |
168 | 170 | ||
169 | /** | 171 | /** |
170 | - * 获取分类信息 promise 对象 | 172 | + * 获取左侧分类信息数据 promise 对象 |
171 | * @return {[type]} [description] | 173 | * @return {[type]} [description] |
172 | */ | 174 | */ |
173 | const getSortList = () => { | 175 | const getSortList = () => { |
@@ -178,22 +180,60 @@ const getSortList = () => { | @@ -178,22 +180,60 @@ const getSortList = () => { | ||
178 | }; | 180 | }; |
179 | 181 | ||
180 | /** | 182 | /** |
181 | - * 获取 Sale 首页数据 | 183 | + * 获取折扣专区活动列表 promise 对象 |
182 | * @return {[type]} [description] | 184 | * @return {[type]} [description] |
183 | */ | 185 | */ |
184 | -exports.getSaleIndexDate = () => { | ||
185 | - return api.get('', sign.apiSign({ | 186 | +const getSaleActivityList = () => { |
187 | + return tarApi.getActivity('', sign.apiSign({ | ||
186 | method: 'app.activity.get', | 188 | method: 'app.activity.get', |
187 | sort: 2, | 189 | sort: 2, |
188 | plateform: 2 | 190 | plateform: 2 |
189 | - })).then(result => { | 191 | + })); |
192 | +}; | ||
193 | + | ||
194 | +/** | ||
195 | + * 获取 Sale 首页数据 | ||
196 | + * @return {[type]} [description] | ||
197 | + */ | ||
198 | +exports.getSaleIndexData = () => { | ||
199 | + | ||
200 | + return api.all([getSaleActivityList(), getSaleGoodsList()]).then(result => { | ||
201 | + var finalResult = {}; | ||
202 | + | ||
203 | + if (result[0].code === 200) { | ||
204 | + finalResult.activity = handleSaleActivityData(result[0].data); | ||
205 | + } | ||
206 | + | ||
207 | + if (result[1].code === 200) { | ||
208 | + | ||
209 | + if (!_.isEmpty(result[1].data.product_list)) { // 处理商品列表数据 | ||
210 | + finalResult.saleCategory = {}; | ||
211 | + finalResult.saleCategory.saleImage = []; | ||
212 | + finalResult.saleCategory.saleImage.push(handleSaleGoodsListData(result[1].data.product_list)); | ||
213 | + } | ||
214 | + } | ||
215 | + return finalResult; | ||
216 | + }); | ||
217 | +}; | ||
218 | + | ||
219 | +/** | ||
220 | + * 获取商品列表数据 | ||
221 | + * @return {[type]} [description] | ||
222 | + */ | ||
223 | +exports.getSaleGoodsData = () => { | ||
224 | + | ||
225 | + return getSaleGoodsList().then(result => { | ||
226 | + let finalResult = {}; | ||
190 | 227 | ||
191 | - return handleSaleIndexData(result); | 228 | + if (result.code === 200) { |
229 | + finalResult.goods = handleSaleGoodsListData(result.data.product_list); | ||
230 | + } | ||
231 | + return finalResult; | ||
192 | }); | 232 | }); |
193 | }; | 233 | }; |
194 | 234 | ||
195 | /** | 235 | /** |
196 | - * 获取页面全部信息 | 236 | + * 获取其他三个页面全部数据 |
197 | * @return {[type]} [description] | 237 | * @return {[type]} [description] |
198 | */ | 238 | */ |
199 | exports.getSaleData = () => { | 239 | exports.getSaleData = () => { |
@@ -24,6 +24,7 @@ router.get('/sale/discount', sale.discount); | @@ -24,6 +24,7 @@ router.get('/sale/discount', sale.discount); | ||
24 | router.get('/sale/vip', sale.vip); | 24 | router.get('/sale/vip', sale.vip); |
25 | router.get('/sale/breakingYards', sale.breakingYards); | 25 | router.get('/sale/breakingYards', sale.breakingYards); |
26 | router.get('/sale/newSale', sale.newSale); | 26 | router.get('/sale/newSale', sale.newSale); |
27 | +router.get('/sale/goods', sale.getGoodsList); | ||
27 | 28 | ||
28 | // 奥特莱斯routers | 29 | // 奥特莱斯routers |
29 | router.get('/outlets/index', outlets.index); | 30 | router.get('/outlets/index', outlets.index); |
apps/product/views/action/goods.hbs
0 → 100644
1 | +{{# result}} | ||
2 | +{{#each goods}} | ||
3 | + <div class="good-info" data-skn="{{skn}}" data-from="{{from}}"> | ||
4 | + <div class="tag-container clearfix"> | ||
5 | + {{# tags}} | ||
6 | + {{# isNew}} | ||
7 | + <span class="good-tag new-tag">NEW</span> | ||
8 | + {{/ isNew}} | ||
9 | + {{# isReNew}} | ||
10 | + <span class="good-tag renew-tag">再到着</span> | ||
11 | + {{/ isReNew}} | ||
12 | + {{# isSale}} | ||
13 | + <span class="good-tag sale-tag">SALE</span> | ||
14 | + {{/ isSale}} | ||
15 | + {{# isNewFestival}} | ||
16 | + <span class="good-tag new-festival-tag">新品节</span> | ||
17 | + {{/ isNewFestival}} | ||
18 | + {{# isLimit}} | ||
19 | + <span class="good-tag limit-tag">限量商品</span> | ||
20 | + {{/ isLimit}} | ||
21 | + {{# isYearEndPromotion}} | ||
22 | + <span class="good-tag yep-tag">年终大促</span> | ||
23 | + {{/ isYearEndPromotion}} | ||
24 | + {{# isYearMidPromotion}} | ||
25 | + <span class="good-tag ymp-tag">年中热促</span> | ||
26 | + {{/ isYearMidPromotion}} | ||
27 | + {{/ tags}} | ||
28 | + </div> | ||
29 | + <div class="good-detail-img"> | ||
30 | + <a class="good-thumb" href="{{url}}" target="_blank"> | ||
31 | + <img class="lazy" data-original="{{image thumb 235 315}}"> | ||
32 | + </a> | ||
33 | + {{# isFew}} | ||
34 | + <p class="few-tag">即将售罄</p> | ||
35 | + {{/ isFew}} | ||
36 | + | ||
37 | + {{#if showColBtn}} | ||
38 | + <span class="col-btn iconfont{{#if coled}} coled{{/if}}"></span> | ||
39 | + {{/if}} | ||
40 | + </div> | ||
41 | + <div class="good-detail-text"> | ||
42 | + <a href="{{url}}" target="_blank">{{{name}}}</a> | ||
43 | + {{#brand}} | ||
44 | + <p class="brand"> | ||
45 | + <a href="{{url}}">{{name}}</a> | ||
46 | + </p> | ||
47 | + {{/brand}} | ||
48 | + <p class="price"> | ||
49 | + {{# marketPrice}} | ||
50 | + <span class="market-price">¥{{.}}</span> | ||
51 | + {{/ marketPrice}} | ||
52 | + <span class="sale-price{{#unless marketPrice}}prime-cost{{/unless}}"> | ||
53 | + ¥{{salePrice}} | ||
54 | + </span> | ||
55 | + </p> | ||
56 | + </div> | ||
57 | + </div> | ||
58 | +{{/each}} | ||
59 | +{{/ result}} |
@@ -12,7 +12,7 @@ const isTest = process.env.NODE_ENV === 'test'; | @@ -12,7 +12,7 @@ const isTest = process.env.NODE_ENV === 'test'; | ||
12 | module.exports = { | 12 | module.exports = { |
13 | port: 6002, | 13 | port: 6002, |
14 | domains: { | 14 | domains: { |
15 | - api: 'http://192.168.102.205:8080/gateway', | 15 | + api: 'http://192.168.102.205:8080/gateway', // 192.168.102.205:8080 testapi.yoho.cn:28078 |
16 | service: 'http://testservice.yoho.cn:28077', | 16 | service: 'http://testservice.yoho.cn:28077', |
17 | search: 'http://192.168.10.64:8080/yohosearch/' | 17 | search: 'http://192.168.10.64:8080/yohosearch/' |
18 | }, | 18 | }, |
library/tar-api.js
0 → 100644
1 | +/* | ||
2 | +* @Author: Targaryen | ||
3 | +* @Date: 2016-05-23 15:27:46 | ||
4 | +* @Last Modified by: Targaryen | ||
5 | +* @Last Modified time: 2016-05-23 16:40:48 | ||
6 | +*/ | ||
7 | + | ||
8 | +'use strict'; | ||
9 | + | ||
10 | +const rp = require('request-promise'); | ||
11 | +const qs = require('querystring'); | ||
12 | +const md5 = require('md5'); | ||
13 | +const _ = require('lodash'); | ||
14 | +const log = require('./logger'); | ||
15 | +const cache = require('./cache'); | ||
16 | +const Timer = require('./timer'); | ||
17 | +const config = require('../config/common'); | ||
18 | +const api = config.domains.api; | ||
19 | +const serviceApi = config.domains.service; | ||
20 | +const searchApi = config.domains.search; | ||
21 | + | ||
22 | + | ||
23 | +let ApiUrl; | ||
24 | + | ||
25 | +class TARAPI { | ||
26 | + | ||
27 | + constructor() { | ||
28 | + ApiUrl = api; | ||
29 | + } | ||
30 | + | ||
31 | + /** | ||
32 | + * 获取请求 ID | ||
33 | + */ | ||
34 | + _getReqId(options) { | ||
35 | + return md5(`${options.url}?${qs.stringify(options.qs || options.form)}`); | ||
36 | + } | ||
37 | + | ||
38 | + /** | ||
39 | + * 调用接口 | ||
40 | + */ | ||
41 | + _requestFromAPI(options, cacheOption, reqId) { | ||
42 | + let timer = new Timer(); | ||
43 | + | ||
44 | + timer.put('getApi');// 统计时间开始 | ||
45 | + | ||
46 | + log.info(`get api: ${options.url}?${qs.stringify(options.qs)}`); | ||
47 | + return rp(options).then((result) => { | ||
48 | + let duration = timer.put('getApi');// 统计时间结束 | ||
49 | + | ||
50 | + log.info(`get api success: use: ${duration}ms`); | ||
51 | + if (config.useCache && cacheOption) { | ||
52 | + reqId = reqId || this._getReqId(options); | ||
53 | + | ||
54 | + // 数据校验无误,写缓存, 否则返回 Slave 缓存服务器的数据 | ||
55 | + if (result && result.code) { | ||
56 | + let cacheTime = _.isNumber(cacheOption) ? cacheOption : 60; | ||
57 | + | ||
58 | + cache.set(`apiCache:${reqId}`, result, cacheTime); | ||
59 | + cache.setSlave(`apiCache:${reqId}`, result, cacheTime); | ||
60 | + } else { | ||
61 | + return this._requestFromCache(options, true); | ||
62 | + } | ||
63 | + } | ||
64 | + return result; | ||
65 | + }).catch((error)=>{ | ||
66 | + let duration = timer.put('getApi');// 统计时间结束 | ||
67 | + | ||
68 | + log.error(`get api fail: use: ${duration}ms, statusCode: ${error.statusCode}, error: ${error.message}`); | ||
69 | + | ||
70 | + // 使用缓存的时候,读取二级缓存 | ||
71 | + if (config.useCache) { | ||
72 | + return this._requestFromCache(options, true); | ||
73 | + } | ||
74 | + return Promise.reject({ | ||
75 | + error: '接口调用失败' | ||
76 | + }); | ||
77 | + }); | ||
78 | + } | ||
79 | + | ||
80 | + /** | ||
81 | + * 读取缓存 | ||
82 | + * @param {[object]} options | ||
83 | + * @param {[boolean]} slave true: 读取二级缓存 | ||
84 | + * @return {[type]} | ||
85 | + */ | ||
86 | + _requestFromCache(options, slave) { | ||
87 | + let reqId = this._getReqId(options); | ||
88 | + let getCache = slave ? cache.getFromSlave : cache.get; | ||
89 | + | ||
90 | + log.info(`get cache: ${reqId}, url: ${options.url}?${qs.stringify(options.qs)}`); | ||
91 | + return getCache(`apiCache:${reqId}`).then((result) => { | ||
92 | + if (!_.isNil(result)) { | ||
93 | + try { | ||
94 | + result = JSON.parse(result); | ||
95 | + } finally { | ||
96 | + log.info(slave ? 'get slave cache success' : 'get master cache success'); | ||
97 | + return result; | ||
98 | + } | ||
99 | + } | ||
100 | + | ||
101 | + if (!slave) { | ||
102 | + return this._requestFromAPI(options, true, reqId); | ||
103 | + } | ||
104 | + }).catch(() => { | ||
105 | + log.error(slave ? 'get slave cache fail' : 'get master cache fail'); | ||
106 | + if (!slave) { | ||
107 | + return this._requestFromAPI(options, true, reqId); | ||
108 | + } | ||
109 | + }); | ||
110 | + } | ||
111 | + | ||
112 | + /** | ||
113 | + * 使用 get 请求获取接口 | ||
114 | + * @param {[string]} url | ||
115 | + * @param {[object]} data | ||
116 | + * @param {[bool or number]} cacheOption 使用数字时,数字表示缓存时间 | ||
117 | + * @return {[type]} | ||
118 | + */ | ||
119 | + get(url, data, cacheOption) { | ||
120 | + let options = { | ||
121 | + url: `${ApiUrl}${url}`, | ||
122 | + qs: data, | ||
123 | + json: true, | ||
124 | + timeout: 3000 | ||
125 | + }; | ||
126 | + | ||
127 | + // 从缓存获取数据 | ||
128 | + if (config.useCache && cacheOption) { | ||
129 | + return this._requestFromCache(options); | ||
130 | + } | ||
131 | + | ||
132 | + return this._requestFromAPI(options, cacheOption); | ||
133 | + } | ||
134 | + | ||
135 | + /** | ||
136 | + * 使用 get 请求获取接口 | ||
137 | + * @param {[string]} url | ||
138 | + * @param {[object]} data | ||
139 | + * @param {[bool or number]} cacheOption 使用数字时,数字表示缓存时间 | ||
140 | + * @return {[type]} | ||
141 | + */ | ||
142 | + getActivity(url, data, cacheOption) { | ||
143 | + let options = { | ||
144 | + url: `http://testapi.yoho.cn:28078/gateway${url}`, | ||
145 | + qs: data, | ||
146 | + json: true, | ||
147 | + timeout: 3000 | ||
148 | + }; | ||
149 | + | ||
150 | + // 从缓存获取数据 | ||
151 | + if (config.useCache && cacheOption) { | ||
152 | + return this._requestFromCache(options); | ||
153 | + } | ||
154 | + | ||
155 | + return this._requestFromAPI(options, cacheOption); | ||
156 | + } | ||
157 | + | ||
158 | + /** | ||
159 | + * post | ||
160 | + * @param url String | ||
161 | + * @param data Obejct | ||
162 | + */ | ||
163 | + post(url, data) { | ||
164 | + let options = { | ||
165 | + url: `${ApiUrl}${url}`, | ||
166 | + form: data, | ||
167 | + method: 'post', | ||
168 | + json: true, | ||
169 | + timeout: 3000 | ||
170 | + }; | ||
171 | + | ||
172 | + return this._requestFromAPI(options); | ||
173 | + } | ||
174 | + | ||
175 | + all(list) { | ||
176 | + if (_.isArray(list)) { | ||
177 | + return Promise.all(list); | ||
178 | + } | ||
179 | + throw Error('the parameters of api all method should be Array!'); | ||
180 | + } | ||
181 | +} | ||
182 | + | ||
183 | +class ServiceAPI extends TARAPI { | ||
184 | + constructor() { | ||
185 | + super(); | ||
186 | + ApiUrl = serviceApi; | ||
187 | + } | ||
188 | +} | ||
189 | + | ||
190 | +class SearchAPI extends TARAPI { | ||
191 | + constructor() { | ||
192 | + super(); | ||
193 | + ApiUrl = searchApi; | ||
194 | + } | ||
195 | +} | ||
196 | + | ||
197 | +exports.TARAPI = TARAPI; | ||
198 | +exports.ServiceAPI = ServiceAPI; | ||
199 | +exports.SearchAPI = SearchAPI; |
-
Please register or login to post a comment