Authored by runner

dist update

Showing 35 changed files with 567 additions and 502 deletions
1 **/bundle/**/*.js 1 **/bundle/**/*.js
2 **/dist/**/*.js 2 **/dist/**/*.js
  3 +coverage
@@ -7,7 +7,6 @@ @@ -7,7 +7,6 @@
7 7
8 const config = require('./config/common'); 8 const config = require('./config/common');
9 9
10 -  
11 // use one apm 10 // use one apm
12 if (config.useOneapm) { 11 if (config.useOneapm) {
13 require('oneapm'); 12 require('oneapm');
@@ -20,16 +19,12 @@ const cookieParser = require('cookie-parser'); @@ -20,16 +19,12 @@ const cookieParser = require('cookie-parser');
20 const favicon = require('serve-favicon'); 19 const favicon = require('serve-favicon');
21 const session = require('express-session'); 20 const session = require('express-session');
22 const memcached = require('connect-memcached'); 21 const memcached = require('connect-memcached');
23 -const _ = require('lodash'); 22 +const hbs = require('express-handlebars');
24 const pkg = require('./package.json'); 23 const pkg = require('./package.json');
25 -const cookie = require('./library/cookie');  
26 24
27 const app = express(); 25 const app = express();
28 const MemcachedStore = memcached(session); 26 const MemcachedStore = memcached(session);
29 27
30 -const setChannel = require('./doraemon/middleware/set-channel');  
31 -  
32 -  
33 // 向模板注入变量 28 // 向模板注入变量
34 app.locals.devEnv = app.get('env') === 'development'; 29 app.locals.devEnv = app.get('env') === 'development';
35 app.locals.version = pkg.version; 30 app.locals.version = pkg.version;
@@ -37,8 +32,15 @@ app.locals.version = pkg.version; @@ -37,8 +32,15 @@ app.locals.version = pkg.version;
37 // 指定libray目录 32 // 指定libray目录
38 global.library = path.resolve('./library/'); 33 global.library = path.resolve('./library/');
39 34
40 -  
41 app.set('view engine', '.hbs'); 35 app.set('view engine', '.hbs');
  36 +app.set('views', './doraemon/views');
  37 +app.engine('.hbs', hbs({
  38 + extname: '.hbs',
  39 + defaultLayout: 'layout',
  40 + layoutsDir: './doraemon/views',
  41 + partialsDir: './doraemon/views/partial',
  42 + helpers: require(`${global.library}/helpers`)
  43 +}));
42 44
43 app.use(favicon(path.join(__dirname, '/public/favicon.ico'))); 45 app.use(favicon(path.join(__dirname, '/public/favicon.ico')));
44 app.use(express.static(path.join(__dirname, 'public'))); 46 app.use(express.static(path.join(__dirname, 'public')));
@@ -65,35 +67,35 @@ app.use(session({ @@ -65,35 +67,35 @@ app.use(session({
65 }) 67 })
66 })); 68 }));
67 69
68 -  
69 -// req和res绑定yoho对象,用于传递全局数据, 如req.yoho.channel等  
70 app.use((req, res, next) => { 70 app.use((req, res, next) => {
71 - req.yoho = {};  
72 - res.yoho = {};  
73 - next();  
74 -}); 71 + req.user = {}; // 全局的用户数据
  72 + req.yoho = {}; // req和res绑定yoho对象,用于传递全局数据, 如req.yoho.channel等
75 73
76 -app.use((req, res, next) => {  
77 - req.user = {};  
78 -  
79 - // 从 PHP 写的 SESSION 中获取到当前登录用户的 UID  
80 - if (req.session && _.isNumber(req.session._LOGIN_UID)) {  
81 - req.user.uid = req.session._LOGIN_UID;  
82 - }  
83 -  
84 - // session 没有读取到的时候,从 cookie 读取 UID  
85 - if (!req.user.uid && req.cookies._UID) {  
86 - req.user.uid = cookie.getUid(req);  
87 - }  
88 next(); 74 next();
89 }); 75 });
90 76
  77 +const logger = require('./library/logger');
  78 +const user = require('./doraemon/middleware/user');
  79 +const setChannel = require('./doraemon/middleware/set-channel');
  80 +const errorHanlder = require('./doraemon/middleware/error-hanlder');
  81 +
  82 +// YOHO 前置中间件
  83 +app.use(user());
91 app.use(setChannel()); 84 app.use(setChannel());
92 85
93 // dispatcher 86 // dispatcher
94 -require('./dispatch')(app); 87 +try {
  88 + require('./dispatch')(app);
  89 +
  90 + app.all('*', errorHanlder.notFound()); // 404
  91 +
  92 + // YOHO 后置中间件
  93 + app.use(errorHanlder.serverError());
  94 +} catch (err) {
  95 + logger.error(err);
  96 +}
95 97
96 // listener 98 // listener
97 app.listen(config.port, function() { 99 app.listen(config.port, function() {
98 - console.log('yohobuy start'); 100 + logger.info('yohobuy start');
99 }); 101 });
@@ -23,242 +23,246 @@ const contentCode = { @@ -23,242 +23,246 @@ const contentCode = {
23 special: '89cc20483ee2cbc8a716dcfe2b6c7603' 23 special: '89cc20483ee2cbc8a716dcfe2b6c7603'
24 }; 24 };
25 25
26 -class Star {  
27 - /**  
28 - * 获取资源位数据  
29 - * @param {[string]} page  
30 - * @return {[array]}  
31 - */  
32 - static getResources(page) {  
33 - return serviceAPI.get('operations/api/v5/resource/get', sign.apiSign({  
34 - content_code: contentCode[page]  
35 - })).then((result) => {  
36 - if (result && result.code === 200) {  
37 - return resourcesProcess(result.data);  
38 - } else {  
39 - logger.error('星潮教室页面资源位返回 code 不是 200');  
40 - return [];  
41 - } 26 +/**
  27 + * 获取资源位数据
  28 + * @param {[string]} page
  29 + * @return {[array]}
  30 + */
  31 +const _getResources = (page) => {
  32 + return serviceAPI.get('operations/api/v5/resource/get', sign.apiSign({
  33 + content_code: contentCode[page]
  34 + })).then((result) => {
  35 + if (result && result.code === 200) {
  36 + return resourcesProcess(result.data);
  37 + } else {
  38 + logger.error('星潮教室页面资源位返回 code 不是 200');
  39 + return [];
  40 + }
  41 + });
  42 +};
  43 +
  44 +/**
  45 + * 星潮教室首页数据处理
  46 + * @param {[array]} list
  47 + * @return {[array]}
  48 + */
  49 +const _processIndexData = (list) => {
  50 + const formatData = {
  51 + ads: [],
  52 + starAvatar: [],
  53 + articles: []
  54 + };
  55 +
  56 + list = list || {};
  57 + list = camelCase(list);
  58 +
  59 + // 首页资源位数据处理
  60 + if (list.ads) {
  61 + _.forEach(list.ads.data, (data) => {
  62 + formatData.ads.push({
  63 + src: data.src,
  64 + url: data.url
  65 + });
42 }); 66 });
43 } 67 }
44 68
45 - /**  
46 - * 星潮教室首页数据处理  
47 - * @param {[array]} list  
48 - * @return {[array]}  
49 - */  
50 - static processIndexData(list) {  
51 - const formatData = {  
52 - ads: [],  
53 - starAvatar: [],  
54 - articles: []  
55 - };  
56 -  
57 - list = list || {};  
58 - list = camelCase(list);  
59 -  
60 - // 首页资源位数据处理  
61 - if (list.ads) {  
62 - _.forEach(list.ads.data, (data) => {  
63 - formatData.ads.push({  
64 - src: data.src,  
65 - url: data.url 69 + // 首页明星文章数据处理
  70 + if (list.list) {
  71 + _.forEach(list.list, (data) => {
  72 + const avatar = {
  73 + tags: []
  74 + };
  75 +
  76 + if (data.ext.tags.length > 1) {
  77 + avatar.isSwiper = true;
  78 + }
  79 +
  80 + _.forEach(data.ext.tags, (tags) => {
  81 + avatar.tags.push({
  82 + avatarUrl: `/guang/star/detail?tag=${tags.tagName}&openby:yohobuy{"action":"go.h5","params":{"id":"","share":"","shareparam":{},"islogin":"N","type":0,"updateflag":"N","url":"http:\/\/m.yohobuy.com\/guang\/star\/detail","param":{"tag":"${tags.tagName}"}}}`, // eslint-disable-line
  83 + cover: tags.cover,
  84 + tagName: tags.tagName
66 }); 85 });
67 }); 86 });
68 - }  
69 87
70 - // 首页明星文章数据处理  
71 - if (list.list) {  
72 - _.forEach(list.list, (data) => {  
73 - const avatar = {  
74 - tags: []  
75 - };  
76 -  
77 - if (data.ext.tags.length > 1) {  
78 - avatar.isSwiper = true;  
79 - }  
80 -  
81 - _.forEach(data.ext.tags, (tags) => {  
82 - avatar.tags.push({  
83 - avatarUrl: `/guang/star/detail?tag=${tags.tagName}&openby:yohobuy{"action":"go.h5","params":{"id":"","share":"","shareparam":{},"islogin":"N","type":0,"updateflag":"N","url":"http:\/\/m.yohobuy.com\/guang\/star\/detail","param":{"tag":"${tags.tagName}"}}}`, // eslint-disable-line  
84 - cover: tags.cover,  
85 - tagName: tags.tagName  
86 - });  
87 - }); 88 + let urlObj = url.parse(data.url);
  89 + let appUrl = `&openby:yohobuy{"action":"go.h5","params":{"id":"","share":"","shareparam":{},"islogin":"N","type":0,"updateflag":"N","url":"${ urlObj.protocol + '//' + urlObj.host + urlObj.pathname}","param":${JSON.stringify(qs.parse(urlObj.query))}}}`.replace(/\//g, '\/'); // eslint-disable-line
  90 +
  91 + formatData.articles.push(_.merge({
  92 + id: data.id,
  93 + url: data.url + appUrl,
  94 + title: data.title,
  95 + articeTxt: data.intro,
  96 + src: data.src,
  97 + publishTime: helpers.dateFormat('MM月DD日 hh:mm', data.publishTime),
  98 + viewsNum: data.viewsNum
  99 + }, avatar));
  100 + });
  101 + }
88 102
89 - let urlObj = url.parse(data.url);  
90 - let appUrl = `&openby:yohobuy{"action":"go.h5","params":{"id":"","share":"","shareparam":{},"islogin":"N","type":0,"updateflag":"N","url":"${ urlObj.protocol + '//' + urlObj.host + urlObj.pathname}","param":${JSON.stringify(qs.parse(urlObj.query))}}}`.replace(/\//g, '\/'); // eslint-disable-line  
91 103
92 - formatData.articles.push(_.merge({  
93 - id: data.id,  
94 - url: data.url + appUrl,  
95 - title: data.title,  
96 - articeTxt: data.intro,  
97 - src: data.src,  
98 - publishTime: helpers.dateFormat('MM月DD日 hh:mm', data.publishTime),  
99 - viewsNum: data.viewsNum  
100 - }, avatar));  
101 - });  
102 - } 104 + // 首页明星头像数据处理
  105 + if (list.tags) {
  106 + _.forEach(list.tags, (data) => {
  107 + let url = `/guang/star/detail?tag=${data.tagName}&openby:yohobuy{"action":"go.h5","params":{"id":"","share":"","shareparam":{},"islogin":"N","type":0,"updateflag":"N","url":"http:\/\/m.yohobuy.com\/guang\/star\/detail","param":{"tag":"${data.tagName}"}}}`; // eslint-disable-line
103 108
  109 + formatData.starAvatar.push({
  110 + url: url,
  111 + cover: data.cover
  112 + });
  113 + });
  114 + }
104 115
105 - // 首页明星头像数据处理  
106 - if (list.tags) {  
107 - _.forEach(list.tags, (data) => {  
108 - let url = `/guang/star/detail?tag=${data.tagName}&openby:yohobuy{"action":"go.h5","params":{"id":"","share":"","shareparam":{},"islogin":"N","type":0,"updateflag":"N","url":"http:\/\/m.yohobuy.com\/guang\/star\/detail","param":{"tag":"${data.tagName}"}}}`; // eslint-disable-line 116 + return formatData;
  117 +};
109 118
110 - formatData.starAvatar.push({  
111 - url: url,  
112 - cover: data.cover  
113 - });  
114 - });  
115 - } 119 +const _processShareUrl = (post) => {
  120 + return `${post.share.url}&openby:yohobuy={"action":"go.share","params":{"pic":"${helpers.image(post.src, 640, 640)}","title":"${post.title}","url":"${post.share.url}","content":"潮流资讯,新鲜贩售,YOHO!Buy有货【逛】不停"}}`; // eslint-disable-line
  121 +};
116 122
117 - return formatData;  
118 - } 123 +/**
  124 + * 明星专题列表数据处理
  125 + * @param {[array]} list
  126 + * @return {[array]}
  127 + */
  128 +const _processDetailData = (list) => {
  129 + const formatData = [];
119 130
120 - static processShareUrl(post) {  
121 - return `${post.share.url}&openby:yohobuy={"action":"go.share","params":{"pic":"${helpers.image(post.src, 640, 640)}","title":"${post.title}","url":"${post.share.url}","content":"潮流资讯,新鲜贩售,YOHO!Buy有货【逛】不停"}}`; // eslint-disable-line  
122 - } 131 + list = list || [];
  132 + list = camelCase(list);
123 133
124 - /**  
125 - * 明星专题列表数据处理  
126 - * @param {[array]} list  
127 - * @return {[array]}  
128 - */  
129 - static processDetailData(list) {  
130 - const formatData = [];  
131 -  
132 - list = list || [];  
133 - list = camelCase(list);  
134 -  
135 - _.forEach(list, (data) => {  
136 - data.publishTime = helpers.dateFormat('MM月DD日 hh:mm', data.publishTime);  
137 - if (data.share && data.share.url) {  
138 - data.share.url = Star.processShareUrl(data);  
139 - }  
140 - formatData.push(data);  
141 - }); 134 + _.forEach(list, (data) => {
  135 + data.publishTime = helpers.dateFormat('MM月DD日 hh:mm', data.publishTime);
  136 + if (data.share && data.share.url) {
  137 + data.share.url = _processShareUrl(data);
  138 + }
  139 + formatData.push(data);
  140 + });
142 141
143 - return formatData;  
144 - } 142 + return formatData;
  143 +};
145 144
146 145
147 - /**  
148 - * 星搭配文章列表数据处理  
149 - */  
150 - static processCollocationData(list) {  
151 - const formatData = []; 146 +/**
  147 + * 星搭配文章列表数据处理
  148 + */
  149 +const _processCollocationData = (list) => {
  150 + const formatData = [];
152 151
153 - list = list || [];  
154 - list = camelCase(list); 152 + list = list || [];
  153 + list = camelCase(list);
155 154
156 - _.forEach(list, (data) => {  
157 - if (data.isFavor === 'N') {  
158 - data.isCollected = false;  
159 - } else {  
160 - data.isCollected = true;  
161 - }  
162 - formatData.push(data);  
163 - }); 155 + _.forEach(list, (data) => {
  156 + if (data.isFavor === 'N') {
  157 + data.isCollected = false;
  158 + } else {
  159 + data.isCollected = true;
  160 + }
  161 + formatData.push(data);
  162 + });
164 163
165 - return formatData;  
166 - } 164 + return formatData;
  165 +};
167 166
168 - /**  
169 - * 星潮首页  
170 - */  
171 - static getIndexData() {  
172 - return api.get('', sign.apiSign({  
173 - method: 'app.starClass.index',  
174 - code: '8adc27fcf5676f356602889afcfd2a8e'  
175 - })).then((result) => {  
176 - if (result && result.code === 200) {  
177 - return Star.processIndexData(result.data);  
178 - } else {  
179 - logger.error('星潮教室首页数据返回 code 不是 200');  
180 - return {};  
181 - }  
182 - });  
183 - } 167 +/**
  168 + * 星潮首页
  169 + */
  170 +const getIndexData = () => {
  171 + return api.get('', sign.apiSign({
  172 + method: 'app.starClass.index',
  173 + code: '8adc27fcf5676f356602889afcfd2a8e'
  174 + })).then((result) => {
  175 + if (result && result.code === 200) {
  176 + return _processIndexData(result.data);
  177 + } else {
  178 + logger.error('星潮教室首页数据返回 code 不是 200');
  179 + return {};
  180 + }
  181 + });
  182 +};
184 183
185 - /**  
186 - * 明星专题  
187 - */  
188 - static getDetailData(params) {  
189 - return api.get('', sign.apiSign({  
190 - method: 'app.starClass.lastTagArticle',  
191 - tag: params.tag,  
192 - page: params.page || 1,  
193 - size: 10  
194 - })).then((result) => {  
195 - if (result && result.code === 200) {  
196 - if (params.page > result.data.totalPage) {  
197 - return '';  
198 - } else {  
199 - return Star.processDetailData(result.data.list);  
200 - } 184 +/**
  185 + * 明星专题
  186 + */
  187 +const getDetailData = (params) => {
  188 + return api.get('', sign.apiSign({
  189 + method: 'app.starClass.lastTagArticle',
  190 + tag: params.tag,
  191 + page: params.page || 1,
  192 + size: 10
  193 + })).then((result) => {
  194 + if (result && result.code === 200) {
  195 + if (params.page > result.data.totalPage) {
  196 + return '';
201 } else { 197 } else {
202 - logger.error('明星专题文章数据返回 code 不是 200');  
203 - return []; 198 + return _processDetailData(result.data.list);
204 } 199 }
205 - });  
206 - } 200 + } else {
  201 + logger.error('明星专题文章数据返回 code 不是 200');
  202 + return [];
  203 + }
  204 + });
  205 +};
207 206
208 207
209 - /**  
210 - * 星专题  
211 - */  
212 - static getSpecialData() {  
213 - return Star.getResources('special').then((result) => { 208 +/**
  209 + * 星专题
  210 + */
  211 +const getSpecialData = () => {
  212 + return _getResources('special').then((result) => {
214 213
215 - // 数据结构嵌套太深  
216 - _.forEach(result, (data) => {  
217 - _.map(data.data, (item) => {  
218 - let urlObj = url.parse(item.url);  
219 - let appUrl = `&openby:yohobuy{"action":"go.h5","params":{"id":"","share":"","shareparam":{},"islogin":"N","type":0,"updateflag":"N","url":"${ urlObj.protocol + '//' + urlObj.host + urlObj.pathname}","param":${JSON.stringify(qs.parse(urlObj.query))}}}`.replace(/\//g, '\/'); // eslint-disable-line 214 + // 数据结构嵌套太深
  215 + _.forEach(result, (data) => {
  216 + _.map(data.data, (item) => {
  217 + let urlObj = url.parse(item.url);
  218 + let appUrl = `&openby:yohobuy{"action":"go.h5","params":{"id":"","share":"","shareparam":{},"islogin":"N","type":0,"updateflag":"N","url":"${ urlObj.protocol + '//' + urlObj.host + urlObj.pathname}","param":${JSON.stringify(qs.parse(urlObj.query))}}}`.replace(/\//g, '\/'); // eslint-disable-line
220 219
221 - item.url += appUrl;  
222 - return item;  
223 - }); 220 + item.url += appUrl;
  221 + return item;
224 }); 222 });
225 - return result;  
226 - });  
227 - }  
228 -  
229 - /**  
230 - * 星搭配  
231 - */  
232 - static getCollocationListData(params, uid) {  
233 -  
234 - return serviceAPI.get('guang/api/v5/article/getStarClassroomArticleList', sign.apiSign(Object.assign({  
235 - limit: '20',  
236 - uid: uid  
237 - }, params))).then((result) => {  
238 - if (result && result.code === 200) {  
239 - return Star.processCollocationData(result.data.list.artList);  
240 - } else {  
241 - logger.error('获取星搭配文章列表返回 code 不是 200');  
242 - return [];  
243 - }  
244 }); 223 });
245 - } 224 + return result;
  225 + });
  226 +};
246 227
247 - static setFavorite(params, uid) {  
248 - if (!uid) {  
249 - return Promise.resolve({  
250 - code: 401,  
251 - message: '未登录'  
252 - }); 228 +/**
  229 + * 星搭配
  230 + */
  231 +const getCollocationListData = (params, uid) => {
  232 +
  233 + return serviceAPI.get('guang/api/v5/article/getStarClassroomArticleList', sign.apiSign(Object.assign({
  234 + limit: '20',
  235 + uid: uid
  236 + }, params))).then((result) => {
  237 + if (result && result.code === 200) {
  238 + return _processCollocationData(result.data.list.artList);
  239 + } else {
  240 + logger.error('获取星搭配文章列表返回 code 不是 200');
  241 + return [];
253 } 242 }
  243 + });
  244 +};
254 245
255 - return api.get('', sign.apiSign({  
256 - method: params.type === 'del' ? 'app.sns.cancelFavorBackCount' : 'app.sns.setFavorBackCount',  
257 - client_type: 'h5',  
258 - article_id: params.articleId,  
259 - uid: uid  
260 - })); 246 +const setFavorite = (params, uid) => {
  247 + if (!uid) {
  248 + return Promise.resolve({
  249 + code: 401,
  250 + message: '未登录'
  251 + });
261 } 252 }
262 -}  
263 253
264 -module.exports = Star; 254 + return api.get('', sign.apiSign({
  255 + method: params.type === 'del' ? 'app.sns.cancelFavorBackCount' : 'app.sns.setFavorBackCount',
  256 + client_type: 'h5',
  257 + article_id: params.articleId,
  258 + uid: uid
  259 + }));
  260 +};
  261 +
  262 +module.exports = {
  263 + getIndexData: getIndexData,
  264 + getSpecialData: getSpecialData,
  265 + getCollocationListData: getCollocationListData,
  266 + setFavorite: setFavorite,
  267 + getDetailData: getDetailData
  268 +};
@@ -69,308 +69,313 @@ const contentCode = { @@ -69,308 +69,313 @@ const contentCode = {
69 } 69 }
70 }; 70 };
71 71
72 -class Sale {  
73 -  
74 - /**  
75 - * 折扣专场列表数据处理  
76 - * @param {[array]} list  
77 - * @return {[array]}  
78 - */  
79 - static processDiscount(list, channel) {  
80 - const formatData = [];  
81 - let flag = true;  
82 -  
83 - list = list || [];  
84 - list = camelCase(list);  
85 -  
86 - if (list.length === 1) {  
87 - flag = false;  
88 - }  
89 -  
90 - _.forEach(list, (data) => {  
91 - if (flag === true) {  
92 - data.specialUrl = `/product/sale/discount/detail?id=${data.id}&channel=${channel}`;  
93 - _.merge(data, processTime(data.leftTime));  
94 - } 72 +/**
  73 + * 折扣专场列表数据处理
  74 + * @param {[array]} list
  75 + * @return {[array]}
  76 + */
  77 +const _processDiscount = (list, channel) => {
  78 + const formatData = [];
  79 + let flag = true;
95 80
96 - formatData.push(data);  
97 - }); 81 + list = list || [];
  82 + list = camelCase(list);
98 83
99 - return formatData; 84 + if (list.length === 1) {
  85 + flag = false;
100 } 86 }
101 87
102 - /**  
103 - * 折扣专场接口调用  
104 - * @param {[object]} params  
105 - * @return {[array]}  
106 - */  
107 - static discount(params) {  
108 - params = params || {};  
109 -  
110 - return api.get('', sign.apiSign(Object.assign({  
111 - method: 'app.activity.get',  
112 - sort: 2,  
113 - plateform: 2  
114 - }, params)));  
115 - } 88 + _.forEach(list, (data) => {
  89 + if (flag === true) {
  90 + data.specialUrl = `/product/sale/discount/detail?id=${data.id}&channel=${channel}`;
  91 + _.merge(data, processTime(data.leftTime));
  92 + }
116 93
117 - /**  
118 - * 断码区分类数据处理  
119 - * @param {[array]} list  
120 - * @return {[array]}  
121 - */  
122 - static processBreakingSort(list) {  
123 - const formatData = {};  
124 - const sort = [];  
125 - const sub = []; 94 + formatData.push(data);
  95 + });
126 96
127 - list = list || [];  
128 - list = camelCase(list); 97 + return formatData;
  98 +};
129 99
130 - _.forEach(list, (data, index) => {  
131 - const allSub = []; 100 +/**
  101 + * 折扣专场接口调用
  102 + * @param {[object]} params
  103 + * @return {[array]}
  104 + */
  105 +const _discount = (params) => {
  106 + params = params || {};
  107 +
  108 + return api.get('', sign.apiSign(Object.assign({
  109 + method: 'app.activity.get',
  110 + sort: 2,
  111 + plateform: 2
  112 + }, params)));
  113 +};
132 114
133 - data.sub.key = index;  
134 - sub.push(data.sub); 115 +/**
  116 + * 断码区分类数据处理
  117 + * @param {[array]} list
  118 + * @return {[array]}
  119 + */
  120 +const _processBreakingSort = (list) => {
  121 + const formatData = {};
  122 + const sort = [];
  123 + const sub = [];
135 124
136 - _.forEach(data.sub, (dataSub) => {  
137 - allSub.push(dataSub.sizeId);  
138 - }); 125 + list = list || [];
  126 + list = camelCase(list);
139 127
140 - sort.push({  
141 - sortName: data.sortName,  
142 - sortId: data.sortId,  
143 - allSub: allSub  
144 - }); 128 + _.forEach(list, (data, index) => {
  129 + const allSub = [];
  130 +
  131 + data.sub.key = index;
  132 + sub.push(data.sub);
  133 +
  134 + _.forEach(data.sub, (dataSub) => {
  135 + allSub.push(dataSub.sizeId);
145 }); 136 });
146 137
147 - formatData.sortData = sort;  
148 - formatData.sub = sub; 138 + sort.push({
  139 + sortName: data.sortName,
  140 + sortId: data.sortId,
  141 + allSub: allSub
  142 + });
  143 + });
149 144
150 - return formatData;  
151 - } 145 + formatData.sortData = sort;
  146 + formatData.sub = sub;
  147 +
  148 + return formatData;
  149 +};
152 150
153 - /**  
154 - * 商品搜索接口请求  
155 - * @param {[object]} params  
156 - * @return {[array]}  
157 - */  
158 - static searchSales(params) { 151 +/**
  152 + * 商品搜索接口请求
  153 + * @param {[object]} params
  154 + * @return {[array]}
  155 + */
  156 +const _searchSales = (params) => {
159 157
160 - let method = 'app.search.sales'; 158 + let method = 'app.search.sales';
161 159
162 - // 排除基本筛选项默认值为0的对象  
163 - for (let str in params) {  
164 - if (str !== 'order' && params[str] === '0' || params[str] === null) {  
165 - delete params[str];  
166 - } 160 + // 排除基本筛选项默认值为0的对象
  161 + for (let str in params) {
  162 + if (str !== 'order' && params[str] === '0' || params[str] === null) {
  163 + delete params[str];
167 } 164 }
  165 + }
168 166
169 - params.yh_channel = channelType[params.yh_channel]; 167 + params.yh_channel = channelType[params.yh_channel];
170 168
171 - if (params.outlets) {  
172 - method = 'app.search.category';  
173 - } 169 + if (params.outlets) {
  170 + method = 'app.search.category';
  171 + }
174 172
175 - params = Object.assign({  
176 - limit: '50'  
177 - }, params); 173 + params = Object.assign({
  174 + limit: '50'
  175 + }, params);
178 176
179 - if (typeCont[params.type]) {  
180 - params.order = typeCont[params.type][params.order];  
181 - } 177 + if (typeCont[params.type]) {
  178 + params.order = typeCont[params.type][params.order];
  179 + }
  180 +
  181 + return api.get('', sign.apiSign(Object.assign({
  182 + method: method
  183 + }, params)), true);
  184 +};
182 185
183 - return api.get('', sign.apiSign(Object.assign({  
184 - method: method  
185 - }, params)), true); 186 +/**
  187 + * 获取用户数据信息
  188 + * @param {[string]} uid
  189 + * @return {[array]}
  190 + */
  191 +const _getUserProfile = (uid) => {
  192 + if (!uid) {
  193 + return Promise.resolve({
  194 + code: 200,
  195 + data: {}
  196 + });
186 } 197 }
  198 + return api.get('', sign.apiSign({
  199 + method: 'app.passport.profile',
  200 + uid: uid
  201 + }), true);
  202 +};
187 203
188 - /**  
189 - * 获取用户数据信息  
190 - * @param {[string]} uid  
191 - * @return {[array]}  
192 - */  
193 - static getUserProfile(uid) {  
194 - if (!uid) {  
195 - return Promise.resolve({  
196 - code: 200,  
197 - data: {}  
198 - }); 204 +/**
  205 + * 获取资源位数据
  206 + * @param {[string]} page
  207 + * @return {[array]}
  208 + */
  209 +const _getResources = (page, channel) => {
  210 + return serviceAPI.get('operations/api/v5/resource/get', sign.apiSign({
  211 + content_code: contentCode[channel][page]
  212 + })).then((result) => {
  213 + if (result && result.code === 200) {
  214 + return resourcesProcess(result.data);
  215 + } else {
  216 + logger.error('SALE 页面资源位返回 code 不是 200');
  217 + return [];
199 } 218 }
200 - return api.get('', sign.apiSign({  
201 - method: 'app.passport.profile',  
202 - uid: uid  
203 - }), true);  
204 - } 219 + });
  220 +};
  221 +
  222 +/**
  223 + * 获取断码区分类数据
  224 + * @param {[string]} yhChannel
  225 + * @return {[object]}
  226 + */
  227 +const _getBreakingSort = (yhChannel) => {
  228 + return api.get('', sign.apiSign({
  229 + method: 'app.sale.getBreakingSort',
  230 + yh_channel: channelType[yhChannel] || '1'
  231 + })).then((result) => {
  232 + if (result && result.code === 200) {
  233 + return _processBreakingSort(result.data);
  234 + } else {
  235 + logger.error('断码区分类接口返回 code 不是 200');
  236 + return {};
  237 + }
  238 + });
  239 +};
205 240
206 - /**  
207 - * 获取资源位数据  
208 - * @param {[string]} page  
209 - * @return {[array]}  
210 - */  
211 - static getResources(page, channel) {  
212 - return serviceAPI.get('operations/api/v5/resource/get', sign.apiSign({  
213 - content_code: contentCode[channel][page]  
214 - })).then((result) => { 241 +/**
  242 + * 获取商品数据
  243 + */
  244 +const getSearchData = (params, uid) => {
  245 + return Promise.all([
  246 + _searchSales(params).then((result) => {
215 if (result && result.code === 200) { 247 if (result && result.code === 200) {
216 - return resourcesProcess(result.data); 248 + return productProcess.processProductList(result.data.product_list || [], {
  249 + yh_channel: params.yh_channel,
  250 + showSale: false
  251 + });
217 } else { 252 } else {
218 - logger.error('SALE 页面资源位返回 code 不是 200'); 253 + logger.error('SALE 商品搜索返回 code 不是 200');
219 return []; 254 return [];
220 } 255 }
221 - });  
222 - }  
223 -  
224 - /**  
225 - * 获取断码区分类数据  
226 - * @param {[string]} yhChannel  
227 - * @return {[object]}  
228 - */  
229 - static getBreakingSort(yhChannel) {  
230 - return api.get('', sign.apiSign({  
231 - method: 'app.sale.getBreakingSort',  
232 - yh_channel: channelType[yhChannel] || '1'  
233 - })).then((result) => { 256 + }),
  257 + _getUserProfile(uid).then((result) => {
234 if (result && result.code === 200) { 258 if (result && result.code === 200) {
235 - return Sale.processBreakingSort(result.data); 259 + return result.data.vip_info ? camelCase(result.data.vip_info) : {};
236 } else { 260 } else {
237 - logger.error('断码区分类接口返回 code 不是 200'); 261 + logger.error('获取用户信息返回 code 不是 200');
238 return {}; 262 return {};
239 } 263 }
240 - });  
241 - } 264 + })
  265 + ]);
  266 +};
242 267
243 - /**  
244 - * 获取商品数据  
245 - */  
246 - static getSearchData(params, uid) {  
247 - return Promise.all([  
248 - Sale.searchSales(params).then((result) => {  
249 - if (result && result.code === 200) {  
250 - return productProcess.processProductList(result.data.product_list || [], {  
251 - yh_channel: params.yh_channel,  
252 - showSale: false  
253 - });  
254 - } else {  
255 - logger.error('SALE 商品搜索返回 code 不是 200');  
256 - return [];  
257 - }  
258 - }),  
259 - Sale.getUserProfile(uid).then((result) => {  
260 - if (result && result.code === 200) {  
261 - return result.data.vip_info ? camelCase(result.data.vip_info) : {};  
262 - } else {  
263 - logger.error('获取用户信息返回 code 不是 200');  
264 - return {};  
265 - }  
266 - })  
267 - ]);  
268 - } 268 +/**
  269 + * 获取筛选数据
  270 + * @param {[object]} params
  271 + * @return {[array]}
  272 + */
  273 +const getFilterData = (params) => {
  274 + return _searchSales(params).then((result) => {
  275 + if (result && result.code === 200) {
  276 + return productProcess.processFilter(result.data.filter || [], {
  277 + hideSize: params.saleType === '1',
  278 + hideSort: params.saleType === '1'
  279 + });
  280 + } else {
  281 + logger.error('SALE 商品搜索返回 code 不是 200');
  282 + return [];
  283 + }
  284 + });
  285 +};
269 286
270 - /**  
271 - * 获取筛选数据  
272 - * @param {[object]} params  
273 - * @return {[array]}  
274 - */  
275 - static getFilterData(params) {  
276 - return Sale.searchSales(params).then((result) => {  
277 - if (result && result.code === 200) {  
278 - return productProcess.processFilter(result.data.filter || [], {  
279 - hideSize: params.saleType === '1',  
280 - hideSort: params.saleType === '1'  
281 - });  
282 - } else {  
283 - logger.error('SALE 商品搜索返回 code 不是 200');  
284 - return [];  
285 - }  
286 - });  
287 - } 287 +/**
  288 + * 获取sale首页数据
  289 + * @return {[array]}
  290 + */
  291 +const getSaleData = (channel) => {
  292 + return _getResources('sale', channel);
  293 +};
288 294
289 - /**  
290 - * 获取sale首页数据  
291 - * @return {[array]}  
292 - */  
293 - static getSaleData(channel) {  
294 - return Sale.getResources('sale', channel);  
295 - }  
296 295
  296 +/**
  297 + * 获取会员享数据
  298 + * @return {[array]}
  299 + */
  300 +const getVipData = (channel) => {
  301 + return _getResources('vip', channel);
  302 +};
297 303
298 - /**  
299 - * 获取会员享数据  
300 - * @return {[array]}  
301 - */  
302 - static getVipData(channel) {  
303 - return Sale.getResources('vip', channel);  
304 - }  
305 304
  305 +/**
  306 + * 获取断码区数据
  307 + * @param {[object]} params
  308 + * @return {[object]}
  309 + */
  310 +const getBreakCodeData = (params) => {
  311 + params = params || {};
  312 + return Promise.all([_getResources('breakCode', params.yhChannel), _getBreakingSort(params.yhChannel)])
  313 + .then((result) => {
  314 + return {
  315 + content: result[0],
  316 + nav: result[1]
  317 + };
  318 + });
  319 +};
306 320
307 - /**  
308 - * 获取断码区数据  
309 - * @param {[object]} params  
310 - * @return {[object]}  
311 - */  
312 - static getBreakCodeData(params) {  
313 - params = params || {};  
314 - return Promise.all([Sale.getResources('breakCode', params.yhChannel), Sale.getBreakingSort(params.yhChannel)])  
315 - .then((result) => {  
316 - return {  
317 - content: result[0],  
318 - nav: result[1]  
319 - };  
320 - });  
321 - } 321 +/**
  322 + * 获取折扣专场专题列表数据
  323 + * @param {[object]} params
  324 + * @return {[object]}
  325 + */
  326 +const getDiscountData = (yhChannel) => {
  327 + const discountData = {};
  328 +
  329 + return _discount({
  330 + yh_channel: channelType[yhChannel] || '1'
  331 + }).then((result) => {
  332 + if (result && result.code === 200) {
  333 + discountData.data = _processDiscount(result.data, yhChannel);
  334 + return discountData;
  335 + } else {
  336 + logger.error('折扣专场专题列表返回 code 不是 200');
  337 + return {};
  338 + }
  339 + });
  340 +};
322 341
323 - /**  
324 - * 获取折扣专场专题列表数据  
325 - * @param {[object]} params  
326 - * @return {[object]}  
327 - */  
328 - static getDiscountData(yhChannel) {  
329 - const discountData = {};  
330 -  
331 - return Sale.discount({  
332 - yh_channel: channelType[yhChannel] || '1'  
333 - }).then((result) => {  
334 - if (result && result.code === 200) {  
335 - discountData.data = Sale.processDiscount(result.data, yhChannel);  
336 - return discountData;  
337 - } else {  
338 - logger.error('折扣专场专题列表返回 code 不是 200');  
339 - return {};  
340 - }  
341 - });  
342 - } 342 +/**
  343 + * 获取折扣专场专题详情数据
  344 + * @param {[string]} id
  345 + * @return {[object]}
  346 + */
  347 +const getDiscountDetailData = (id, yhChannel) => {
  348 + let res = {};
  349 + let param = {
  350 + id: id,
  351 + yh_channel: channelType[yhChannel] || '1'
  352 + };
343 353
344 - /**  
345 - * 获取折扣专场专题详情数据  
346 - * @param {[string]} id  
347 - * @return {[object]}  
348 - */  
349 - static getDiscountDetailData(id, yhChannel) {  
350 - let res = {};  
351 - let param = {  
352 - id: id,  
353 - yh_channel: channelType[yhChannel] || '1'  
354 - }; 354 + return _discount(param).then((result) => {
  355 + if (result && result.code === 200) {
  356 + res = _processDiscount(result.data);
355 357
356 - return Sale.discount(param).then((result) => {  
357 - if (result && result.code === 200) {  
358 - res = Sale.processDiscount(result.data);  
359 -  
360 - return {  
361 - title: res[0].title,  
362 - productPool: res[0].productPool,  
363 - activity: {  
364 - coverUrl: res[0].coverUrl,  
365 - leftTime: res[0].leftTime  
366 - }  
367 - };  
368 - } else {  
369 - logger.error('折扣专场专题详情返回 code 不是 200');  
370 - return {};  
371 - }  
372 - });  
373 - }  
374 -} 358 + return {
  359 + title: res[0].title,
  360 + productPool: res[0].productPool,
  361 + activity: {
  362 + coverUrl: res[0].coverUrl,
  363 + leftTime: res[0].leftTime
  364 + }
  365 + };
  366 + } else {
  367 + logger.error('折扣专场专题详情返回 code 不是 200');
  368 + return {};
  369 + }
  370 + });
  371 +};
375 372
376 -module.exports = Sale; 373 +module.exports = {
  374 + getSaleData: getSaleData,
  375 + getBreakCodeData: getBreakCodeData,
  376 + getDiscountData: getDiscountData,
  377 + getDiscountDetailData: getDiscountDetailData,
  378 + getVipData: getVipData,
  379 + getFilterData: getFilterData,
  380 + getSearchData: getSearchData
  381 +};
  1 +/**
  2 + * 404 错误
  3 + * @return {[type]}
  4 + */
  5 +exports.notFound = () => {
  6 + return (req, res) => {
  7 + if (req.xhr) {
  8 + return res.status(404).json({
  9 + code: 404,
  10 + message: '页面不存在'
  11 + });
  12 + }
  13 + return res.render('error/404');
  14 + };
  15 +};
  16 +
  17 +/**
  18 + * 服务器错误
  19 + * @return {[type]}
  20 + */
  21 +exports.serverError = () => {
  22 + return (err, req, res, next) => {
  23 + if (!res.headersSent) {
  24 + if (req.xhr) {
  25 + return res.status(500).json({
  26 + code: 500,
  27 + message: '服务器错误'
  28 + });
  29 + }
  30 +
  31 + return res.render('error/500', err);
  32 + }
  33 + next(err);
  34 + };
  35 +};
@@ -19,7 +19,6 @@ module.exports = () => { @@ -19,7 +19,6 @@ module.exports = () => {
19 }); 19 });
20 20
21 req.yoho.channel = channel; 21 req.yoho.channel = channel;
22 - res.yoho.channel = channel;  
23 } 22 }
24 23
25 next(); 24 next();
  1 +const _ = require('lodash');
  2 +const cookie = require('../../library/cookie');
  3 +
  4 +module.exports = () => {
  5 + return (req, res, next) => {
  6 + // 从 SESSION 中获取到当前登录用户的 UID
  7 + if (req.session && _.isNumber(req.session._LOGIN_UID)) {
  8 + req.user.uid = req.session._LOGIN_UID;
  9 + }
  10 +
  11 + // session 没有读取到的时候,从 cookie 读取 UID
  12 + if (!req.user.uid && req.cookies._UID) {
  13 + req.user.uid = cookie.getUid(req);
  14 + }
  15 +
  16 + next();
  17 + };
  18 +};
@@ -9,14 +9,14 @@ @@ -9,14 +9,14 @@
9 }, 9 },
10 "scripts": { 10 "scripts": {
11 "start": "node app.js", 11 "start": "node app.js",
12 - "dev": "node_modules/.bin/nodemon -e js,hbs -i public/ app.js", 12 + "dev": "nodemon -e js,hbs -i public/ app.js",
13 "online": "NODE_ENV=\"production\" node app.js", 13 "online": "NODE_ENV=\"production\" node app.js",
14 - "debug": "DEBUG=\"express:*\" node_modules/.bin/nodemon -e js,hbs -i public/ app.js",  
15 - "lint-js": "./node_modules/.bin/eslint -c .eslintrc --cache --fix .",  
16 - "lint-css": "./node_modules/.bin/stylelint --config .stylelintrc public/scss/**/*.css", 14 + "debug": "DEBUG=\"express:*\" nodemon -e js,hbs -i public/ app.js",
  15 + "lint-js": "eslint -c .eslintrc --cache --fix .",
  16 + "lint-css": "stylelint --config .stylelintrc public/scss/**/*.css",
17 "precommit": "node lint.js", 17 "precommit": "node lint.js",
18 - "test": "NODE_ENV=test ./node_modules/.bin/nyc ./node_modules/.bin/ava",  
19 - "posttest": "./node_modules/.bin/nyc report --reporter=html" 18 + "test": "NODE_ENV=test nyc ./node_modules/.bin/ava",
  19 + "posttest": "nyc report --reporter=html"
20 }, 20 },
21 "ava": { 21 "ava": {
22 "tap": true, 22 "tap": true,
@@ -68,14 +68,13 @@ @@ -68,14 +68,13 @@
68 "gulp-util": "^3.0.7", 68 "gulp-util": "^3.0.7",
69 "husky": "^0.11.4", 69 "husky": "^0.11.4",
70 "nodemon": "1.9.2", 70 "nodemon": "1.9.2",
71 - "nyc": "^6.4.4", 71 + "nyc": "^6.6.1",
72 "postcss-assets": "^4.0.1", 72 "postcss-assets": "^4.0.1",
73 "postcss-cachebuster": "^0.1.3", 73 "postcss-cachebuster": "^0.1.3",
74 "postcss-calc": "^5.2.1", 74 "postcss-calc": "^5.2.1",
75 "postcss-center": "^1.0.0", 75 "postcss-center": "^1.0.0",
76 "postcss-clearfix": "^1.0.0", 76 "postcss-clearfix": "^1.0.0",
77 "postcss-crip": "^2.0.0", 77 "postcss-crip": "^2.0.0",
78 - "postcss-opacity": "^3.0.0",  
79 "postcss-position": "^0.5.0", 78 "postcss-position": "^0.5.0",
80 "postcss-pxtorem": "^3.3.1", 79 "postcss-pxtorem": "^3.3.1",
81 "postcss-short": "^1.4.0", 80 "postcss-short": "^1.4.0",
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
@@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@
9 &:link, 9 &:link,
10 &:visited, 10 &:visited,
11 &:hover, 11 &:hover,
12 - &:actived { 12 + &:active {
13 color: #000; 13 color: #000;
14 } 14 }
15 } 15 }
@@ -259,7 +259,7 @@ @@ -259,7 +259,7 @@
259 position: relative; 259 position: relative;
260 } 260 }
261 261
262 - li:first { 262 + li:first-child {
263 margin-left: 0; 263 margin-left: 0;
264 } 264 }
265 265