Authored by 沈志敏

Merge branch 'develop' of git.yoho.cn:fe/yohoblk-wap into develop

@@ -5,10 +5,12 @@ Name | Path | Note @@ -5,10 +5,12 @@ Name | Path | Note
5 品牌列表 | /brands | 5 品牌列表 | /brands |
6 品类 | /cate | 6 品类 | /cate |
7 全部分类 | /cate-all | 7 全部分类 | /cate-all |
  8 +商品列表 | /product/list?sort=1 |
8 品牌店铺 | /product/shop?domain=sctest1 | 9 品牌店铺 | /product/shop?domain=sctest1 |
9 品牌店铺分享页面 | /product/shop-share?domain=colormad | 10 品牌店铺分享页面 | /product/shop-share?domain=colormad |
10 商品详情 | /product/{productId} | 11 商品详情 | /product/{productId} |
11 新品抢先看 | /product/new | 12 新品抢先看 | /product/new |
  13 +搜索页 | /product/search?query=xxx |
12 资讯列表 | /news | 14 资讯列表 | /news |
13 资讯详情 | /news/{newsId} | 15 资讯详情 | /news/{newsId} |
14 个人中心 | /home | 16 个人中心 | /home |
@@ -19,6 +21,7 @@ Name | Path | Note @@ -19,6 +21,7 @@ Name | Path | Note
19 待收货 | /home/orders?type=4 | 21 待收货 | /home/orders?type=4 |
20 订单详情 | /home/order-detail?orderCode=xxx | 22 订单详情 | /home/order-detail?orderCode=xxx |
21 退货申请 | /home/refund?orderId=160181661 | 23 退货申请 | /home/refund?orderId=160181661 |
  24 +换货申请 | /home/exchange?orderId=160181661 |
22 收藏商品 | /home/favorite | 25 收藏商品 | /home/favorite |
23 收藏品牌 | /home/favorite?tab=brand | 26 收藏品牌 | /home/favorite?tab=brand |
24 yoho币 | /home/mycurrency | 27 yoho币 | /home/mycurrency |
  1 +/**
  2 + * 微信分享签名
  3 + * Bi Kai <kai.bi@yoho.cn>
  4 + */
  5 +'use strict';
  6 +const wechatModel = require('../models/wechat');
  7 +
  8 +exports.shareToken = (req, res, next) => {
  9 + wechatModel.calcSignature({
  10 + url: req.query.url || 'http://www.yohoblk.com/'
  11 + }).then((result) => {
  12 + res.jsonp(result);
  13 + }).catch(next);
  14 +};
  1 +'use strict';
  2 +
  3 +/*
  4 + * 生成微信分享所需的签名
  5 + * bikai <kai.bi@yoho.cn>
  6 + * 2016.6.15
  7 + */
  8 +const request = require('request-promise');
  9 +const Promise = require('bluebird');
  10 +const crypto = require('crypto');
  11 +const logger = global.yoho.logger;
  12 +const cache = global.yoho.cache;
  13 +
  14 +// 此处请勿使用有货公众号的 appId, 此处使用的是 女生志 的appId
  15 +const appId = 'wxb52ec6a352f0b090';
  16 +const secret = '9fe6bedb0b7f30986a168c7fc44f34c0';
  17 +
  18 +const sha1 = (str) => {
  19 + const generator = crypto.createHash('sha1');
  20 +
  21 + generator.update(str);
  22 + return generator.digest('hex');
  23 +};
  24 +
  25 +const accessTokenCacheKey = 'wechatShare:accessToken';
  26 +const ticketCacheKey = 'wechatShare:ticket';
  27 +
  28 +// 微信 JS 接口签名校验工具 http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign
  29 +
  30 +let _getAccessToken = Promise.coroutine(function* () {
  31 + let accessToken = yield cache.get(accessTokenCacheKey);
  32 +
  33 + if (accessToken) {
  34 + return accessToken;
  35 + }
  36 +
  37 + logger.info('get accessToken from wechat API');
  38 + return request({
  39 + url: 'https://api.weixin.qq.com/cgi-bin/token',
  40 + qs: {
  41 + grant_type: 'client_credential',
  42 + appid: appId,
  43 + secret: secret
  44 + },
  45 + json: true
  46 + }).then((res) => {
  47 +
  48 + // accessToken 有效期 7200s,缓存 7100s
  49 + cache.set(accessTokenCacheKey, res.access_token, 7100).catch((err) => {
  50 + logger.error('set wechat accessToken cache error', JSON.stringify(err));
  51 + });
  52 + return res.access_token;
  53 + }).catch((err) => {
  54 + logger.error('get accessToken from wechat API error', JSON.stringify(err));
  55 + });
  56 +});
  57 +
  58 +let _getTicket = Promise.coroutine(function* () {
  59 + let ticket = yield cache.get(ticketCacheKey);
  60 +
  61 + if (ticket) {
  62 + return ticket;
  63 + }
  64 +
  65 + logger.info('get ticket from wechat API');
  66 + return request({
  67 + url: 'https://api.weixin.qq.com/cgi-bin/ticket/getticket',
  68 + qs: {
  69 + access_token: yield _getAccessToken(),
  70 + type: 'jsapi'
  71 + },
  72 + json: true
  73 + }).then(res => {
  74 +
  75 + // ticket 有效期 7200s,缓存 7100s
  76 + cache.set(ticketCacheKey, res.ticket, 7100).catch((err) => {
  77 + logger.error('set wechat Token cache error', JSON.stringify(err));
  78 + });
  79 + return res.ticket;
  80 + }).catch((err) => {
  81 + logger.error('get ticket from wechat API error', JSON.stringify(err));
  82 + });
  83 +});
  84 +
  85 +let calcSignature = Promise.coroutine(function* (data) {
  86 + data = Object.assign({
  87 + nonceStr: Math.random().toString(36).substr(2, 15),
  88 + timestamp: Math.floor(Date.now() / 1000) + '',
  89 + ticket: yield _getTicket(),
  90 + appId: appId
  91 + }, data);
  92 +
  93 + const str = `jsapi_ticket=${data.ticket}&noncestr=${data.nonceStr}&timestamp=${data.timestamp}&url=${data.url}`;
  94 +
  95 + data.signature = sha1(str);
  96 + return data;
  97 +});
  98 +
  99 +// 测试
  100 +// calcSignature({
  101 +// url: 'http://www.yohobuy.com/'
  102 +// }).then(console.log);
  103 +
  104 +module.exports = {
  105 + calcSignature
  106 +};
@@ -11,8 +11,11 @@ const router = require('express').Router(); // eslint-disable-line @@ -11,8 +11,11 @@ const router = require('express').Router(); // eslint-disable-line
11 var multipart = require('connect-multiparty'); 11 var multipart = require('connect-multiparty');
12 var multipartMiddleware = multipart(); 12 var multipartMiddleware = multipart();
13 13
14 -const uploadApi = require('./upload/upload.js'); 14 +const uploadApi = require('./controllers/upload.js');
  15 +const wechat = require('./controllers/wechat.js');
15 16
16 router.post('/upload/image', multipartMiddleware, uploadApi.uploadImg); 17 router.post('/upload/image', multipartMiddleware, uploadApi.uploadImg);
17 18
  19 +router.get('/wechat/share/token', wechat.shareToken);
  20 +
18 module.exports = router; 21 module.exports = router;
@@ -101,11 +101,11 @@ const getCateListData = params => { @@ -101,11 +101,11 @@ const getCateListData = params => {
101 sub: [] 101 sub: []
102 }; 102 };
103 if (_.isEmpty(cate.sub)) { 103 if (_.isEmpty(cate.sub)) {
104 - item.url = helpers.urlFormat('/', { 104 + item.url = helpers.urlFormat('/product/list', {
105 sort: item.sort, 105 sort: item.sort,
106 sort_name: item.name, 106 sort_name: item.name,
107 gender: genderArr[categorykey] 107 gender: genderArr[categorykey]
108 - }, 'list'); 108 + });
109 oneClass.ca.push(item); 109 oneClass.ca.push(item);
110 return true;// equal continue; 110 return true;// equal continue;
111 } 111 }
@@ -115,11 +115,11 @@ const getCateListData = params => { @@ -115,11 +115,11 @@ const getCateListData = params => {
115 id: item.id, 115 id: item.id,
116 name: '全部' + item.name, 116 name: '全部' + item.name,
117 sort: item.sort, 117 sort: item.sort,
118 - url: helpers.urlFormat('/', { 118 + url: helpers.urlFormat('/product/list', {
119 sort: item.sort, 119 sort: item.sort,
120 sort_name: item.name, 120 sort_name: item.name,
121 gender: genderArr[categorykey] 121 gender: genderArr[categorykey]
122 - }, 'list'), 122 + }),
123 sub: [] 123 sub: []
124 }); 124 });
125 125
@@ -130,11 +130,11 @@ const getCateListData = params => { @@ -130,11 +130,11 @@ const getCateListData = params => {
130 sort: sub.relation_parameter.sort, 130 sort: sub.relation_parameter.sort,
131 url: '' 131 url: ''
132 }; 132 };
133 - subitem.url = helpers.urlFormat('/', { 133 + subitem.url = helpers.urlFormat('/product/list', {
134 sort: subitem.sort, 134 sort: subitem.sort,
135 sort_name: subitem.name, 135 sort_name: subitem.name,
136 gender: genderArr[categorykey] 136 gender: genderArr[categorykey]
137 - }, 'list'); 137 + });
138 item.sub.push(subitem); 138 item.sub.push(subitem);
139 }); 139 });
140 140
@@ -45,9 +45,9 @@ const component = { @@ -45,9 +45,9 @@ const component = {
45 var gender = ''; 45 var gender = '';
46 46
47 if (data.gender === '1') { 47 if (data.gender === '1') {
48 - gender = 'men' 48 + gender = 'men';
49 } else if (data.gender === '2') { 49 } else if (data.gender === '2') {
50 - gender = 'women' 50 + gender = 'women';
51 } 51 }
52 52
53 res.render('mydetails', { 53 res.render('mydetails', {
@@ -19,7 +19,7 @@ exports.index = (req, res) => { @@ -19,7 +19,7 @@ exports.index = (req, res) => {
19 /* 获取 筛选配置 */ 19 /* 获取 筛选配置 */
20 exports.fetchFilters = (req, res, next) => { 20 exports.fetchFilters = (req, res, next) => {
21 const params = Object.assign({ 21 const params = Object.assign({
22 - uid: req.user.uid, 22 + uid: req.user.uid || 0,
23 page: 1, 23 page: 1,
24 order: 1, 24 order: 1,
25 yh_channel: 'all', 25 yh_channel: 'all',
@@ -34,10 +34,12 @@ exports.fetchFilters = (req, res, next) => { @@ -34,10 +34,12 @@ exports.fetchFilters = (req, res, next) => {
34 /* 查询 产品列表 */ 34 /* 查询 产品列表 */
35 exports.fetchProducts = (req, res, next) => { 35 exports.fetchProducts = (req, res, next) => {
36 const params = Object.assign({ 36 const params = Object.assign({
37 - uid: req.user.uid,  
38 - page: 1,  
39 - order: 1 37 + uid: req.user.uid || 0
40 }, req.query); 38 }, req.query);
41 39
42 - newModel.getNewData(params).catch(next); 40 + newModel.getNewData(params)
  41 + .then(result => {
  42 + res.json(result);
  43 + })
  44 + .catch(next);
43 }; 45 };
@@ -17,25 +17,6 @@ exports.index = (req, res) => { @@ -17,25 +17,6 @@ exports.index = (req, res) => {
17 res.render('product-list', view); 17 res.render('product-list', view);
18 }; 18 };
19 19
20 -/* 筛选的二级页面 */  
21 -exports.subFilter = (req, res) => {  
22 - const view = {  
23 - module: 'product',  
24 - page: 'filter-sub'  
25 - };  
26 -  
27 - res.render('filter-sub', view);  
28 -};  
29 -  
30 -/* 获取 筛选配置 */  
31 -exports.fetchFilters = (req, res, next) => {  
32 - const params = req.query;  
33 -  
34 - searchModel.products(params)  
35 - .then(result => res.json(result))  
36 - .catch(next);  
37 -};  
38 -  
39 /* 查询 产品列表 method:GET */ 20 /* 查询 产品列表 method:GET */
40 exports.fetchProducts = (req, res, next) => { 21 exports.fetchProducts = (req, res, next) => {
41 const params = req.query; 22 const params = req.query;
1 -/* 筛选的二级页面 */  
2 -exports.page = (req, res) => {  
3 - const view = {  
4 - module: 'product',  
5 - page: 'filter-sub'  
6 - };  
7 -  
8 - res.render('filter-sub', view);  
9 -};  
@@ -11,11 +11,9 @@ exports.getNewData = (params) => { @@ -11,11 +11,9 @@ exports.getNewData = (params) => {
11 method: 'app.search.newProduct', 11 method: 'app.search.newProduct',
12 }, params); 12 }, params);
13 13
14 - api.post('', params, {  
15 - cache: true,  
16 - code: 200  
17 - }).then(result => { 14 + return api.get('', params).then(result => {
18 if (result.data) { 15 if (result.data) {
  16 + prettyFilter(result.data.filter);
19 result.data.productList = processProductList(result.data.productList); 17 result.data.productList = processProductList(result.data.productList);
20 result = camelCase(result); 18 result = camelCase(result);
21 } 19 }
@@ -30,7 +28,7 @@ exports.getNewFilterData = (params) => { @@ -30,7 +28,7 @@ exports.getNewFilterData = (params) => {
30 method: 'app.search.newProduct', 28 method: 'app.search.newProduct',
31 }, params); 29 }, params);
32 30
33 - api.post('', params, { 31 + return api.post('', params, {
34 cache: true, 32 cache: true,
35 code: 200 33 code: 200
36 }).then(result => { 34 }).then(result => {
@@ -13,11 +13,13 @@ const router = expressRouter(); @@ -13,11 +13,13 @@ const router = expressRouter();
13 13
14 // 产品 搜索 页面 14 // 产品 搜索 页面
15 const search = require(`${cRoot}/search`); 15 const search = require(`${cRoot}/search`);
16 -const newProduct = require(`${cRoot}/new`);  
17 16
18 router.get('/search', search.index); 17 router.get('/search', search.index);
19 router.get('/search.json', search.fetchProducts); // ajax 18 router.get('/search.json', search.fetchProducts); // ajax
20 19
  20 +// 新品页
  21 +const newProduct = require(`${cRoot}/new`);
  22 +
21 router.get('/new', newProduct.index); 23 router.get('/new', newProduct.index);
22 router.get('/new.json', newProduct.fetchProducts); 24 router.get('/new.json', newProduct.fetchProducts);
23 25
@@ -26,12 +28,6 @@ const productList = require(`${cRoot}/product-list`); @@ -26,12 +28,6 @@ const productList = require(`${cRoot}/product-list`);
26 28
27 router.get('/list', productList.index); 29 router.get('/list', productList.index);
28 router.get('/list.json', productList.fetchProducts); 30 router.get('/list.json', productList.fetchProducts);
29 -router.get('/list/filter', productList.subFilter);  
30 -  
31 -// sub filter  
32 -const subFilter = require(`${cRoot}/sub-filter`);  
33 -  
34 -router.get('/sub-filter', subFilter.page);  
35 31
36 // 品牌店铺页面 32 // 品牌店铺页面
37 const shop = require(`${cRoot}/shop`); 33 const shop = require(`${cRoot}/shop`);
1 -{{! 筛选的 二级菜单}}  
2 -<div id="filter-sub">  
3 - <filter-sub><filter-sub>  
4 -</div>  
@@ -6,11 +6,11 @@ @@ -6,11 +6,11 @@
6 */ 6 */
7 7
8 module.exports = app => { 8 module.exports = app => {
9 - app.use('/', require('./apps/channel'));  
10 - app.use('/api', require('./apps/api'));  
11 - app.use('/product', require('./apps/product'));  
12 - app.use('/home', require('./apps/home'));  
13 - app.use('/news', require('./apps/news')); 9 + app.use('/', require('./apps/channel')); // 一级频道模块
  10 + app.use('/api', require('./apps/api')); // 各模块公有 API
  11 + app.use('/product', require('./apps/product')); // 商品模块
  12 + app.use('/home', require('./apps/home')); // 个人中心
  13 + app.use('/news', require('./apps/news')); // 资讯
14 14
15 // 组件示例 15 // 组件示例
16 if (!app.locals.proEnv) { 16 if (!app.locals.proEnv) {
@@ -19,7 +19,7 @@ const titleMap = { @@ -19,7 +19,7 @@ const titleMap = {
19 action: '' 19 action: ''
20 }, 20 },
21 title: { 21 title: {
22 - des: '标题1', 22 + des: 'BLK',
23 action: '' 23 action: ''
24 } 24 }
25 }, 25 },
@@ -29,11 +29,11 @@ const titleMap = { @@ -29,11 +29,11 @@ const titleMap = {
29 action: '' 29 action: ''
30 }, 30 },
31 title: { 31 title: {
32 - des: '标题2', 32 + des: 'BLK',
33 action: '' 33 action: ''
34 }, 34 },
35 right: { 35 right: {
36 - action: '' 36 + action: origin + '/home'
37 } 37 }
38 }, 38 },
39 3: { 39 3: {
@@ -42,12 +42,12 @@ const titleMap = { @@ -42,12 +42,12 @@ const titleMap = {
42 action: '' 42 action: ''
43 }, 43 },
44 title: { 44 title: {
45 - des: '标题3', 45 + des: 'BLK',
46 action: '' 46 action: ''
47 }, 47 },
48 right: { 48 right: {
49 des: '提交', 49 des: '提交',
50 - action: '' 50 + action: 'submitForm'
51 } 51 }
52 }, 52 },
53 4: { 53 4: {
@@ -67,16 +67,16 @@ const titleMap = { @@ -67,16 +67,16 @@ const titleMap = {
67 action: '' 67 action: ''
68 }, 68 },
69 ltitle: { 69 ltitle: {
70 - des: '商品5',  
71 - action: '' 70 + des: '商品',
  71 + action: origin + '/favorite'
72 }, 72 },
73 rtitle: { 73 rtitle: {
74 - des: '品牌5',  
75 - action: '' 74 + des: '品牌',
  75 + action: origin + '/favorite?tab=brand'
76 }, 76 },
77 right: { 77 right: {
78 - des: '编辑5',  
79 - action: '' 78 + des: '编辑',
  79 + action: 'editModel'
80 } 80 }
81 }, 81 },
82 6: { 82 6: {
@@ -92,26 +92,15 @@ const matchHeader = (url) => { @@ -92,26 +92,15 @@ const matchHeader = (url) => {
92 let header = { 92 let header = {
93 headerid: '-1' // 默认不显示头部 93 headerid: '-1' // 默认不显示头部
94 }; 94 };
  95 + let path = url.split('?')[0];
95 96
96 - if (/\/product\/new/.test(url)) {  
97 - header = titleMap[1];  
98 -  
99 - // header.xxx = '111';// 匹配到头类型以后,可修改里边的内容  
100 - return header;  
101 - }  
102 -  
103 - if (/\/brands/.test(url) || /\/cate/.test(url)) {  
104 - header = titleMap[4];  
105 - return header;  
106 - }  
107 -  
108 - if (/\/home\/mydetails$/.test(url)) { 97 + if (/\/home\/mydetails$/.test(path)) {
109 header = titleMap[1]; 98 header = titleMap[1];
110 header.title.des = '个人信息'; 99 header.title.des = '个人信息';
111 return header; 100 return header;
112 } 101 }
113 102
114 - if (/\/home\/orders/.test(url)) { 103 + if (/\/home\/orders$/.test(path)) {
115 let des = ''; 104 let des = '';
116 let u = url.split('?')[1]; 105 let u = url.split('?')[1];
117 106
@@ -130,65 +119,48 @@ const matchHeader = (url) => { @@ -130,65 +119,48 @@ const matchHeader = (url) => {
130 return header; 119 return header;
131 } 120 }
132 121
133 - if (/\/home\/order-detail/.test(url)) { 122 + if (/\/home\/order-detail$/.test(path)) {
134 header = titleMap[2]; 123 header = titleMap[2];
135 header.title.des = '订单详情'; 124 header.title.des = '订单详情';
136 header.title.right.action = origin + '/home/service'; 125 header.title.right.action = origin + '/home/service';
137 return header; 126 return header;
138 } 127 }
139 128
140 - if (/\/home\/refund\/orders/.test(url)) { 129 + if (/\/home\/refund\/orders$/.test(path)) {
141 header = titleMap[1]; 130 header = titleMap[1];
142 header.title.des = '退/换货'; 131 header.title.des = '退/换货';
143 return header; 132 return header;
144 } 133 }
145 134
146 - if (/\/home\/favorite/.test(url)) {  
147 - header = titleMap[5];  
148 - header.ltitle = {  
149 - des: '商品',  
150 - action: origin + '/home/favorite'  
151 - }  
152 - header.rtitle = {  
153 - des: '品牌',  
154 - action: origin + '/home/favorite?tab=brand'  
155 - }  
156 - header.right = {  
157 - des: '编辑',  
158 - action: 'editModel'  
159 - }  
160 - return header;  
161 - }  
162 -  
163 - if (/\/home\/mycurrency/.test(url)) { 135 + if (/\/home\/mycurrency$/.test(path)) {
164 header = titleMap[1]; 136 header = titleMap[1];
165 header.title.des = '有货币'; 137 header.title.des = '有货币';
166 return header; 138 return header;
167 } 139 }
168 140
169 - if (/\/home\/help$/.test(url)) { 141 + if (/\/home\/help$/.test(path)) {
170 header = titleMap[1]; 142 header = titleMap[1];
171 header.title.des = '帮助中心'; 143 header.title.des = '帮助中心';
172 return header; 144 return header;
173 } 145 }
174 146
175 - if (/\/home\/service$/.test(url)) { 147 + if (/\/home\/service$/.test(path)) {
176 header = titleMap[1]; 148 header = titleMap[1];
177 header.title.des = 'Yoho!Blk在线客服'; 149 header.title.des = 'Yoho!Blk在线客服';
178 return header; 150 return header;
179 } 151 }
180 152
181 - if (/\/home\/feedback/.test(url)) { 153 + if (/\/home\/feedback$/.test(path)) {
182 header = titleMap[3]; 154 header = titleMap[3];
183 header.title.des = '意见反馈'; 155 header.title.des = '意见反馈';
184 header.right = { 156 header.right = {
185 des: '提交', 157 des: '提交',
186 action: 'saveFeedback' 158 action: 'saveFeedback'
187 - } 159 + };
188 return header; 160 return header;
189 } 161 }
190 162
191 - if (/\/home\/about/.test(url)) { 163 + if (/\/home\/about$/.test(path)) {
192 header = titleMap[1]; 164 header = titleMap[1];
193 header.title.des = '关于'; 165 header.title.des = '关于';
194 return header; 166 return header;
@@ -200,13 +172,34 @@ const matchHeader = (url) => { @@ -200,13 +172,34 @@ const matchHeader = (url) => {
200 172
201 module.exports = (url) => { 173 module.exports = (url) => {
202 if (yoho.isApp) { 174 if (yoho.isApp) {
203 - let data = { 175 + let path = url.split('?')[0];
  176 +
  177 + // 个人中心收藏
  178 + if (/\/home\/favorite$/.test(path)) {
  179 + return yoho.goPageView({
  180 + header: titleMap[5]
  181 + });
  182 + }
  183 +
  184 + // 个人中心首页
  185 + if (/\/home$/.test(path)) {
  186 + return yoho.goTab({index: 4});
  187 + }
  188 +
  189 + // 资讯
  190 + if (/\/news$/.test(path)) {
  191 + return yoho.goTab({index: 3});
  192 + }
  193 +
  194 + // 品牌 品类
  195 + if (/\/brands$/.test(path) || /\/cate$/.test(path)) {
  196 + return yoho.goTab({index: 1});
  197 + }
  198 +
  199 + yoho.goNewPage({
204 header: matchHeader(url), 200 header: matchHeader(url),
205 url: /^(https?:)?\/\//i.test(url) ? url : origin + url 201 url: /^(https?:)?\/\//i.test(url) ? url : origin + url
206 - };  
207 -  
208 - // console.log(data);  
209 - yoho.goNewPage(data); 202 + });
210 } else { 203 } else {
211 location.href = url; 204 location.href = url;
212 } 205 }
  1 +/**
  2 + * Created by PhpStorm.
  3 + * User: Targaryen
  4 + * Date: 2016/7/29
  5 + * Time: 16:55
  6 + */
  7 +
  8 +const $ = require('yoho-jquery');
  9 +
  10 +$.ajax({
  11 + url: '//res.wx.qq.com/open/js/jweixin-1.1.0.js',
  12 + dataType: 'script',
  13 + cache: true,
  14 + success: function() {
  15 + $.ajax({
  16 + url: '/api/wechat/share/token',
  17 + data: {
  18 + url: location.href
  19 + },
  20 + success: function(res) {
  21 + if (window.wx) {
  22 + window.wx.config({
  23 + debug: false,
  24 + appId: res.appId,
  25 + timestamp: res.timestamp,
  26 + nonceStr: res.nonceStr,
  27 + signature: res.signature,
  28 + jsApiList: [
  29 + 'checkJsApi',
  30 + 'onMenuShareTimeline',
  31 + 'onMenuShareAppMessage',
  32 + 'onMenuShareQQ',
  33 + 'onMenuShareWeibo',
  34 + 'hideMenuItems',
  35 + 'showMenuItems',
  36 + 'hideAllNonBaseMenuItem',
  37 + 'showAllNonBaseMenuItem',
  38 + 'translateVoice',
  39 + 'startRecord',
  40 + 'stopRecord',
  41 + 'onRecordEnd',
  42 + 'playVoice',
  43 + 'pauseVoice',
  44 + 'stopVoice',
  45 + 'uploadVoice',
  46 + 'downloadVoice',
  47 + 'chooseImage',
  48 + 'previewImage',
  49 + 'uploadImage',
  50 + 'downloadImage',
  51 + 'getNetworkType',
  52 + 'openLocation',
  53 + 'getLocation',
  54 + 'hideOptionMenu',
  55 + 'showOptionMenu',
  56 + 'closeWindow',
  57 + 'scanQRCode',
  58 + 'chooseWXPay',
  59 + 'openProductSpecificView',
  60 + 'addCard',
  61 + 'chooseCard',
  62 + 'openCard'
  63 + ]
  64 + });
  65 + }
  66 + }
  67 + });
  68 + }
  69 +});
  70 +
  71 +module.exports = (shareData) => {
  72 + if (window.wx) {
  73 + window.wx.ready(function() {
  74 + window.wx.onMenuShareAppMessage(shareData);
  75 + window.wx.onMenuShareTimeline(shareData);
  76 + window.wx.onMenuShareQQ(shareData);
  77 + window.wx.onMenuShareWeibo(shareData);
  78 + });
  79 + }
  80 +};
@@ -18,9 +18,11 @@ const $ = require('yoho-jquery'); @@ -18,9 +18,11 @@ const $ = require('yoho-jquery');
18 const interceptClick = require('common/intercept-click'); 18 const interceptClick = require('common/intercept-click');
19 19
20 $(() => { 20 $(() => {
21 - $('body').on('click', 'a[href]:not(".no-intercept")', function() { 21 + $('body').on('click', 'a[href]', function() {
22 // 拦截跳转 22 // 拦截跳转
23 - interceptClick($(this).attr('href'));  
24 - return false; 23 + if (!$(this).hasClass('no-intercept')) {
  24 + interceptClick($(this).attr('href'));
  25 + return false;
  26 + }
25 }); 27 });
26 }); 28 });
1 -const Vue = require('yoho-vue');  
2 -const filterSub = require('component/product/filter/filter-sub.vue');  
3 -  
4 -// TODO: 该mock数据 应该有 上级页面传过来  
5 -// const page = {  
6 -  
7 - // 二级筛选的 类型  
8 - // type: 'brand',  
9 -  
10 - // data: [ // 二级筛选的 数据  
11 - // { id: 1, name: '红色' },  
12 - // { id: 2, name: '红色' },  
13 - // { id: 3, name: '红色' }  
14 - // ],  
15 -// data: [{  
16 -// domain: 'converse',  
17 -// alif: 'C',  
18 -// ico: 'http://img12.static.yhbimg.com/brandLogo/2015/12/09/14/02752d2839e7001a09ecf71dcc9a996387.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',  
19 -// name: 'converse',  
20 -// keyword: 'converse,街头,摇滚,百搭,朋克,简约,个性,自然,潮流,环保',  
21 -// id: 27,  
22 -// hotKeyword: 'converse',  
23 -// isHot: 'Y',  
24 -// nameEn: 'converse',  
25 -// nameCn: '匡威'  
26 -// }, {  
27 -// domain: 'eightguys',  
28 -// alif: 'E',  
29 -// ico: 'http://img11.static.yhbimg.com/brandLogo/2013/07/02/19/01959c3b33245e16e786bda6b1e91234be.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',  
30 -// name: 'Eight Guys',  
31 -// keyword: '8Guys,八个男人',  
32 -// id: 396,  
33 -// hotKeyword: '',  
34 -// isHot: 'Y',  
35 -// nameEn: 'eight guys',  
36 -// nameCn: 'Eight Guys'  
37 -// }, {  
38 -// domain: 'soulandsole',  
39 -// alif: 'S',  
40 -// ico: 'http://img13.static.yhbimg.com/brandLogo/2014/01/27/11/02cfe4044dfb82230c1868211b814d6192.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',  
41 -// name: 'SOUL&SOLE',  
42 -// keyword: '',  
43 -// id: 335,  
44 -// hotKeyword: '',  
45 -// isHot: '',  
46 -// nameEn: 'SOUL&SOLE ',  
47 -// nameCn: 'SOUL&SOLE '  
48 -// }, {  
49 -// domain: 'thething',  
50 -// alif: 'T',  
51 -// ico: 'http://img11.static.yhbimg.com/brandLogo/2015/12/09/16/018d25bf4481ed2998bf33b294673a8535.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',  
52 -// name: 'THETHING',  
53 -// keyword: 'thething,tee,polo,衬衫,裤类,包类,配件类',  
54 -// id: 138,  
55 -// hotKeyword: 'thething',  
56 -// isHot: 'Y',  
57 -// nameEn: 'THETHING',  
58 -// nameCn: 'THETHING'  
59 -// }, {  
60 -// domain: 'roxy',  
61 -// alif: 'R',  
62 -// ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',  
63 -// name: 'Roxy',  
64 -// keyword: 'roxy',  
65 -// id: 273,  
66 -// hotKeyword: '',  
67 -// isHot: '',  
68 -// nameEn: 'Roxy',  
69 -// nameCn: 'Roxy'  
70 -// }, {  
71 -// domain: 'roxy',  
72 -// alif: 'R',  
73 -// ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',  
74 -// name: 'Roxy',  
75 -// keyword: 'roxy',  
76 -// id: 273,  
77 -// hotKeyword: '',  
78 -// isHot: '',  
79 -// nameEn: 'Roxy',  
80 -// nameCn: 'Roxy'  
81 -// }, {  
82 -// domain: 'roxy',  
83 -// alif: 'R',  
84 -// ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',  
85 -// name: 'Roxy',  
86 -// keyword: 'roxy',  
87 -// id: 273,  
88 -// hotKeyword: '',  
89 -// isHot: '',  
90 -// nameEn: 'Roxy',  
91 -// nameCn: 'Roxy'  
92 -// }, {  
93 -// domain: 'roxy',  
94 -// alif: 'R',  
95 -// ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',  
96 -// name: 'Roxy',  
97 -// keyword: 'roxy',  
98 -// id: 273,  
99 -// hotKeyword: '',  
100 -// isHot: '',  
101 -// nameEn: 'Roxy',  
102 -// nameCn: 'Roxy'  
103 -// }, {  
104 -// domain: 'roxy',  
105 -// alif: 'R',  
106 -// ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',  
107 -// name: 'Roxy',  
108 -// keyword: 'roxy',  
109 -// id: 273,  
110 -// hotKeyword: '',  
111 -// isHot: '',  
112 -// nameEn: 'Roxy',  
113 -// nameCn: 'Roxy'  
114 -// }, {  
115 -// domain: 'roxy',  
116 -// alif: 'R',  
117 -// ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',  
118 -// name: 'Roxy',  
119 -// keyword: 'roxy',  
120 -// id: 273,  
121 -// hotKeyword: '',  
122 -// isHot: '',  
123 -// nameEn: 'Roxy',  
124 -// nameCn: 'Roxy'  
125 -// }, {  
126 -// domain: 'roxy',  
127 -// alif: 'R',  
128 -// ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',  
129 -// name: 'Roxy',  
130 -// keyword: 'roxy',  
131 -// id: 273,  
132 -// hotKeyword: '',  
133 -// isHot: '',  
134 -// nameEn: 'Roxy',  
135 -// nameCn: 'Roxy'  
136 -// }, {  
137 -// domain: 'roxy',  
138 -// alif: 'R',  
139 -// ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',  
140 -// name: 'Roxy',  
141 -// keyword: 'roxy',  
142 -// id: 273,  
143 -// hotKeyword: '',  
144 -// isHot: '',  
145 -// nameEn: 'Roxy',  
146 -// nameCn: 'Roxy'  
147 -// }, {  
148 -// domain: 'roxy',  
149 -// alif: 'R',  
150 -// ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',  
151 -// name: 'Roxy',  
152 -// keyword: 'roxy',  
153 -// id: 273,  
154 -// hotKeyword: '',  
155 -// isHot: '',  
156 -// nameEn: 'Roxy',  
157 -// nameCn: 'Roxy'  
158 -// }, {  
159 -// domain: 'roxy',  
160 -// alif: 'R',  
161 -// ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',  
162 -// name: 'Roxy',  
163 -// keyword: 'roxy',  
164 -// id: 273,  
165 -// hotKeyword: '',  
166 -// isHot: '',  
167 -// nameEn: 'Roxy',  
168 -// nameCn: 'Roxy'  
169 -// }, {  
170 -// domain: 'roxy',  
171 -// alif: 'R',  
172 -// ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',  
173 -// name: 'Roxy',  
174 -// keyword: 'roxy',  
175 -// id: 273,  
176 -// hotKeyword: '',  
177 -// isHot: '',  
178 -// nameEn: 'Roxy',  
179 -// nameCn: 'Roxy'  
180 -// }, {  
181 -// domain: 'roxy',  
182 -// alif: 'R',  
183 -// ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',  
184 -// name: 'Roxy',  
185 -// keyword: 'roxy',  
186 -// id: 273,  
187 -// hotKeyword: '',  
188 -// isHot: '',  
189 -// nameEn: 'Roxy',  
190 -// nameCn: 'Roxy'  
191 -// }, {  
192 -// domain: 'roxy',  
193 -// alif: 'R',  
194 -// ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',  
195 -// name: 'Roxy',  
196 -// keyword: 'roxy',  
197 -// id: 273,  
198 -// hotKeyword: '',  
199 -// isHot: '',  
200 -// nameEn: 'Roxy',  
201 -// nameCn: 'Roxy'  
202 -// }, {  
203 -// domain: 'roxy',  
204 -// alif: 'R',  
205 -// ico: 'http://img12.static.yhbimg.com/brandLogo/2012/05/28/13/0242bc746fa4ddbc9519c14c3b769b6774.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',  
206 -// name: 'Roxy',  
207 -// keyword: 'roxy',  
208 -// id: 273,  
209 -// hotKeyword: '',  
210 -// isHot: '',  
211 -// nameEn: 'Roxy',  
212 -// nameCn: 'Roxy'  
213 -// }, {  
214 -// domain: 'natkiel',  
215 -// alif: 'N',  
216 -// ico: 'http://img11.static.yhbimg.com/brandLogo/2015/11/17/10/01032e9fba6bc0770077f2c645bad46127.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',  
217 -// name: 'Natkiel',  
218 -// keyword: '奈凯儿',  
219 -// id: 393,  
220 -// hotKeyword: '',  
221 -// isHot: 'N',  
222 -// nameEn: 'Natkiel',  
223 -// nameCn: 'Natkiel'  
224 -// }, {  
225 -// domain: 'natkiel',  
226 -// alif: 'N',  
227 -// ico: 'http://img11.static.yhbimg.com/brandLogo/2015/11/17/10/01032e9fba6bc0770077f2c645bad46127.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',  
228 -// name: 'Natkiel',  
229 -// keyword: '奈凯儿',  
230 -// id: 393,  
231 -// hotKeyword: '',  
232 -// isHot: 'N',  
233 -// nameEn: 'Natkiel',  
234 -// nameCn: 'Natkiel'  
235 -// }, {  
236 -// domain: 'natkiel',  
237 -// alif: 'N',  
238 -// ico: 'http://img11.static.yhbimg.com/brandLogo/2015/11/17/10/01032e9fba6bc0770077f2c645bad46127.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',  
239 -// name: 'Natkiel',  
240 -// keyword: '奈凯儿',  
241 -// id: 393,  
242 -// hotKeyword: '',  
243 -// isHot: 'N',  
244 -// nameEn: 'Natkiel',  
245 -// nameCn: 'Natkiel'  
246 -// }, {  
247 -// domain: 'natkiel',  
248 -// alif: 'N',  
249 -// ico: 'http://img11.static.yhbimg.com/brandLogo/2015/11/17/10/01032e9fba6bc0770077f2c645bad46127.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',  
250 -// name: 'Natkiel',  
251 -// keyword: '奈凯儿',  
252 -// id: 393,  
253 -// hotKeyword: '',  
254 -// isHot: 'N',  
255 -// nameEn: 'Natkiel',  
256 -// nameCn: 'Natkiel'  
257 -// }, {  
258 -// domain: 'natkiel',  
259 -// alif: 'N',  
260 -// ico: 'http://img11.static.yhbimg.com/brandLogo/2015/11/17/10/01032e9fba6bc0770077f2c645bad46127.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',  
261 -// name: 'Natkiel',  
262 -// keyword: '奈凯儿',  
263 -// id: 393,  
264 -// hotKeyword: '',  
265 -// isHot: 'N',  
266 -// nameEn: 'Natkiel',  
267 -// nameCn: 'Natkiel'  
268 -// }, {  
269 -// domain: 'natkiel',  
270 -// alif: 'N',  
271 -// ico: 'http://img11.static.yhbimg.com/brandLogo/2015/11/17/10/01032e9fba6bc0770077f2c645bad46127.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',  
272 -// name: 'Natkiel',  
273 -// keyword: '奈凯儿',  
274 -// id: 393,  
275 -// hotKeyword: '',  
276 -// isHot: 'N',  
277 -// nameEn: 'Natkiel',  
278 -// nameCn: 'Natkiel'  
279 -// }, {  
280 -// domain: 'natkiel',  
281 -// alif: 'N',  
282 -// ico: 'http://img11.static.yhbimg.com/brandLogo/2015/11/17/10/01032e9fba6bc0770077f2c645bad46127.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',  
283 -// name: 'Natkiel',  
284 -// keyword: '奈凯儿',  
285 -// id: 393,  
286 -// hotKeyword: '',  
287 -// isHot: 'N',  
288 -// nameEn: 'Natkiel',  
289 -// nameCn: 'Natkiel'  
290 -// }],  
291 -// val: 3 // 二级筛选 的值  
292 -// };  
293 -  
294 -new Vue({  
295 - el: '#filter-sub',  
296 - data: function() {  
297 - return {};  
298 - },  
299 - components: {  
300 - filterSub  
301 - }  
302 -});  
@@ -34,7 +34,7 @@ const yoho = { @@ -34,7 +34,7 @@ const yoho = {
34 * @param success 调用成功的回调方法 34 * @param success 调用成功的回调方法
35 * @param fail 调用失败的回调方法 35 * @param fail 调用失败的回调方法
36 */ 36 */
37 - goTap(args, success, fail) { 37 + goTab(args, success, fail) {
38 if (this.isApp) { 38 if (this.isApp) {
39 window.yohoInterface.triggerEvent(success || nullFun, fail || nullFun, { 39 window.yohoInterface.triggerEvent(success || nullFun, fail || nullFun, {
40 method: 'go.tab', 40 method: 'go.tab',
@@ -277,9 +277,12 @@ const yoho = { @@ -277,9 +277,12 @@ const yoho = {
277 * @param callback 回调 277 * @param callback 回调
278 */ 278 */
279 addNativeMethod(name, callback) { 279 addNativeMethod(name, callback) {
280 - if (window.yohoInterface) {  
281 - window.yohoInterface[name] = callback;  
282 - } 280 + // 延迟 500ms 注入
  281 + setTimeout(function() {
  282 + if (window.yohoInterface) {
  283 + window.yohoInterface[name] = callback;
  284 + }
  285 + }, 500);
283 } 286 }
284 }; 287 };
285 288
1 <template> 1 <template>
2 - <div class="cate-tab-fixed">  
3 - <tab v-bind:page="page"></tab>  
4 - </div>  
5 <div class="cate-page" id='cate-page'> 2 <div class="cate-page" id='cate-page'>
6 <div class="cate-nav clearfix"> 3 <div class="cate-nav clearfix">
7 <ul> 4 <ul>
@@ -29,12 +26,6 @@ @@ -29,12 +26,6 @@
29 </div> 26 </div>
30 </template> 27 </template>
31 <style> 28 <style>
32 -.cate-tab-fixed {  
33 - position: fixed;  
34 - top: 0;  
35 - left: 0;  
36 -}  
37 -  
38 .cate-page { 29 .cate-page {
39 font-size: 36px; 30 font-size: 36px;
40 font-family: helvetica, Arial, "黑体"; 31 font-family: helvetica, Arial, "黑体";
1 <template> 1 <template>
2 <tab v-bind:page="page"></tab> 2 <tab v-bind:page="page"></tab>
  3 + <brand-search></brand-search>
3 <resources v-bind:content-code.sync="contentCode"></resources> 4 <resources v-bind:content-code.sync="contentCode"></resources>
4 <brand-list v-bind:channel="channel"></brand-list> 5 <brand-list v-bind:channel="channel"></brand-list>
5 </template> 6 </template>
@@ -10,6 +11,7 @@ @@ -10,6 +11,7 @@
10 const tab = require('channel/tab.vue'); 11 const tab = require('channel/tab.vue');
11 const resources = require('component/resources/index.vue'); 12 const resources = require('component/resources/index.vue');
12 const brandList = require('channel/brand-list.vue'); 13 const brandList = require('channel/brand-list.vue');
  14 + const brandSearch = require('channel/brand-search.vue');
13 15
14 16
15 module.exports = { 17 module.exports = {
@@ -21,6 +23,7 @@ @@ -21,6 +23,7 @@
21 }, 23 },
22 components: { 24 components: {
23 tab, 25 tab,
  26 + brandSearch,
24 resources, 27 resources,
25 brandList 28 brandList
26 } 29 }
  1 +<template>
  2 + <div class="search">
  3 + <div v-else class="input" @click='yoho.goSearch()'>
  4 + <span class="icon icon-search"></span> Search
  5 + </div>
  6 + </div>
  7 +</template>
  8 +<style>
  9 + .search {
  10 + width: 100%;
  11 + height: 85px;
  12 + padding: 15px 0;
  13 + background-color: #f6f6f6;
  14 + text-align: center;
  15 +
  16 + .input {
  17 + margin-left: auto;
  18 + margin-right: auto;
  19 + background-color: #fff;
  20 + text-align: center;
  21 + color: #b0b0b0;
  22 + height: 55px;
  23 + width: 92%;
  24 + font-size: 28px;
  25 + padding: 5px 0;
  26 + }
  27 +
  28 + }
  29 +</style>
  30 +<script>
  31 + const yoho = require('yoho');
  32 +
  33 + module.exports = {
  34 + data() {
  35 + return {
  36 + yoho
  37 + };
  38 + }
  39 + };
  40 +</script>
1 <template> 1 <template>
2 - <tab v-bind:page="page"></tab>  
3 - <resources v-bind:content-code.sync="contentCode"></resources> 2 + <div class="tab-top-fixed">
  3 + <tab v-bind:page="page"></tab>
  4 + </div>
  5 + <div class="resources">
  6 + <resources v-bind:content-code.sync="contentCode"></resources>
  7 + </div>
4 </template> 8 </template>
  9 +<style>
  10 + .tab-top-fixed {
  11 + position: fixed;
  12 + top: 0;
  13 + left: 0;
  14 + width: 100%;
  15 + z-index: 99;
  16 + }
  17 +
  18 + .resources {
  19 + margin-top: 100px;
  20 + }
  21 +</style>
5 <script> 22 <script>
6 const contentCode = require('content-code'); 23 const contentCode = require('content-code');
7 const qs = require('yoho-qs'); 24 const qs = require('yoho-qs');
@@ -33,8 +33,13 @@ @@ -33,8 +33,13 @@
33 <style> 33 <style>
34 @import "../../scss/common/color"; 34 @import "../../scss/common/color";
35 35
  36 + html {
  37 + font-size: 60px !important;
  38 + }
  39 +
36 .sidebar { 40 .sidebar {
37 width: 100%; 41 width: 100%;
  42 + margin-top: 40px;
38 background: $white; 43 background: $white;
39 overflow-x: hidden; 44 overflow-x: hidden;
40 45
@@ -37,10 +37,10 @@ @@ -37,10 +37,10 @@
37 padding-left: 30px; 37 padding-left: 30px;
38 padding-right: 30px; 38 padding-right: 30px;
39 width: 100%; 39 width: 100%;
40 - height: 60px; 40 + height: 120px;
41 line-height: 60px; 41 line-height: 60px;
42 font-size: 48px; 42 font-size: 48px;
43 - background-color: #fff; 43 + background-color: transparent;
44 .icon, 44 .icon,
45 .header-title { 45 .header-title {
46 vertical-align: middle; 46 vertical-align: middle;
@@ -66,6 +66,7 @@ @@ -66,6 +66,7 @@
66 } 66 }
67 67
68 .header-gap { 68 .header-gap {
69 - height: 60px; 69 + height: 120px;
  70 + background-color: #fff;
70 } 71 }
71 </style> 72 </style>
@@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
10 <li class="filter-cate" v-for="classify in config" @click="entrySub($key)"> 10 <li class="filter-cate" v-for="classify in config" @click="entrySub($key)">
11 <i class="icon icon-right right"></i> 11 <i class="icon icon-right right"></i>
12 <span class="filter-cate-label">{{$key | filter-en-cn }}</span> 12 <span class="filter-cate-label">{{$key | filter-en-cn }}</span>
13 - <span class="filter-cate-val">{{params[$key] && params[$key].name }}</span> 13 + <span class="filter-cate-val">{{showLabel($key)}}</span>
14 </li> 14 </li>
15 </ul> 15 </ul>
16 </div> 16 </div>
@@ -50,26 +50,21 @@ @@ -50,26 +50,21 @@
50 this.overlay.show(); 50 this.overlay.show();
51 } else { 51 } else {
52 this.overlay.hide(); 52 this.overlay.hide();
  53 + this.$set('params', {});
53 } 54 }
54 } 55 }
55 }, 56 },
56 methods: { 57 methods: {
57 clearVals: function() { 58 clearVals: function() {
58 // remove all value 59 // remove all value
  60 + this.$set('selected', {});
59 this.$set('params', {}); 61 this.$set('params', {});
60 }, 62 },
61 63
62 - /**  
63 - * 当二级筛选, 返回数据时, 调用该方法  
64 - * @param {[type]} cate [description]  
65 - * @param {[type]} val [description]  
66 - */  
67 - setCateParams: function(cate, val) {  
68 - this.$set(`params.${cate}`, val);  
69 - },  
70 okAction: function() { 64 okAction: function() {
  65 + this.$set('selected', Object.assign({}, this.selected,this.params));
71 bus.$emit('filter.change', { 66 bus.$emit('filter.change', {
72 - val: this.params, 67 + val: this.selected,
73 ref: this._uid 68 ref: this._uid
74 }); 69 });
75 }, 70 },
@@ -78,8 +73,24 @@ @@ -78,8 +73,24 @@
78 this.$refs.filterSub.isVisible = true; 73 this.$refs.filterSub.isVisible = true;
79 }, 74 },
80 75
  76 + /**
  77 + * 当二级筛选, 返回数据时, 调用该方法
  78 + * @param {[type]} cate [description]
  79 + * @param {[type]} val [description]
  80 + */
81 setParams: function(item) { 81 setParams: function(item) {
82 this.$set(`params.${this.subType}`, item); 82 this.$set(`params.${this.subType}`, item);
  83 + },
  84 +
  85 + showLabel: function(key){
  86 + const newSelected = this.params[key];
  87 + const oldSelected = this.selected[key];
  88 +
  89 + if(newSelected) {
  90 + return newSelected.name || '';
  91 + } else {
  92 + return oldSelected && oldSelected.name || '';
  93 + }
83 } 94 }
84 }, 95 },
85 filters: { 96 filters: {
@@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
10 <button class="button" @click='yoho.goNewPage({"url":"http://m.yohoblk.com"})'>新页面</button> 10 <button class="button" @click='yoho.goNewPage({"url":"http://m.yohoblk.com"})'>新页面</button>
11 <button class="button" @click="yoho.goPay()">支付</button> 11 <button class="button" @click="yoho.goPay()">支付</button>
12 <button class="button" @click="yoho.goBack()">返回</button> 12 <button class="button" @click="yoho.goBack()">返回</button>
13 - <button class="button" @click='yoho.goShare({"title":"标题","des":"描述","img":"http://7xwj52.com1.z0.glb.clouddn.com/brandbg.jpg","url":"http://m.yohoblk.com"})'>分享</button> 13 + <button class="button" @click='yoho.goShare({"title":"标题","des":"描述","img":"http://7xwj52.com1.z0.glb.clouddn.com/brandbg.jpg","url":"http://m.yohoblk.com/product/shop/share?domain=sctest1"})'>分享</button>
14 <button class="button" @click='yoho.goSearch()'>搜索</button> 14 <button class="button" @click='yoho.goSearch()'>搜索</button>
15 <button class="button" @click='yoho.goSetting()'>设置</button> 15 <button class="button" @click='yoho.goSetting()'>设置</button>
16 <button class="button" @click='yoho.goSetAvatar()'>设置头像</button> 16 <button class="button" @click='yoho.goSetAvatar()'>设置头像</button>
@@ -73,6 +73,8 @@ @@ -73,6 +73,8 @@
73 this.queryProductFeature(msg.pid); 73 this.queryProductFeature(msg.pid);
74 }); 74 });
75 75
  76 + yoho.addNativeMethod('submitForm', this.submit.bind(this));
  77 +
76 // 获取 换货商品 78 // 获取 换货商品
77 $.ajax({ 79 $.ajax({
78 url: '/home/exchange/order', 80 url: '/home/exchange/order',
@@ -111,6 +113,11 @@ @@ -111,6 +113,11 @@
111 } 113 }
112 }); 114 });
113 }, 115 },
  116 + computed: {
  117 + selectedGoods() {
  118 + return this.goodsArr.filter(goods => goods.checked);
  119 + }
  120 + },
114 methods: { 121 methods: {
115 changeAddress() { 122 changeAddress() {
116 yoho.goAddress({ 123 yoho.goAddress({
@@ -15,7 +15,7 @@ @@ -15,7 +15,7 @@
15 <div class="bottom clearfix"> 15 <div class="bottom clearfix">
16 <span class="icon time-icon">&#xe612;</span> 16 <span class="icon time-icon">&#xe612;</span>
17 <span class="time">{{news.publishTime}}</span> 17 <span class="time">{{news.publishTime}}</span>
18 - <span class="icon share" @click="share(news.title, news.intro, news.src, news.share.url)">&#xe611;</span> 18 + <span class="icon icon-share share" @click="share(news.title, news.intro, news.src, news.share.url)"></span>
19 </div> 19 </div>
20 </div> 20 </div>
21 </div> 21 </div>
@@ -61,9 +61,9 @@ @@ -61,9 +61,9 @@
61 methods: { 61 methods: {
62 showcase: function() { 62 showcase: function() {
63 const opts = { 63 const opts = {
64 - images: this.goods.map((item)=> { 64 + images: this.goods.map((item) => {
65 return item.colorImage; 65 return item.colorImage;
66 - }), 66 + }).filter(image => image),
67 index: this.$refs.swipe.index 67 index: this.$refs.swipe.index
68 }; 68 };
69 69
@@ -168,7 +168,7 @@ @@ -168,7 +168,7 @@
168 168
169 </show-box> 169 </show-box>
170 170
171 - <div class="control-box"> 171 + <div class="control-box" v-if="isApp">
172 <button class="button control-button"> 172 <button class="button control-button">
173 <span @click="yoho.goShopingCart()" style="position: relative;"> 173 <span @click="yoho.goShopingCart()" style="position: relative;">
174 <i class="icon icon-bag"></i> 174 <i class="icon icon-bag"></i>
@@ -191,6 +191,10 @@ @@ -191,6 +191,10 @@
191 </button> 191 </button>
192 </div> 192 </div>
193 193
  194 + <div v-if="!isApp">
  195 + <share-bottom></share-bottom>
  196 + </div>
  197 +
194 <feature-selector :is-visible="showFeatureSelector" :entity="entity" 198 <feature-selector :is-visible="showFeatureSelector" :entity="entity"
195 :on-add-to-cart="onAddToCart"></feature-selector> 199 :on-add-to-cart="onAddToCart"></feature-selector>
196 </template> 200 </template>
@@ -293,7 +297,7 @@ @@ -293,7 +297,7 @@
293 justify-content: space-around; 297 justify-content: space-around;
294 align-items: stretch; 298 align-items: stretch;
295 position: fixed; 299 position: fixed;
296 - width: 100%; 300 + width: 750px;
297 height: 99px; 301 height: 99px;
298 bottom: 0; 302 bottom: 0;
299 303
@@ -392,6 +396,7 @@ @@ -392,6 +396,7 @@
392 const app = $('#app'); 396 const app = $('#app');
393 const tip = require('common/tip'); 397 const tip = require('common/tip');
394 const yoho = require('yoho'); 398 const yoho = require('yoho');
  399 + const share = require('common/share');
395 400
396 require('yoho-vue-swipe/dist/vue-swipe.css'); 401 require('yoho-vue-swipe/dist/vue-swipe.css');
397 402
@@ -453,6 +458,7 @@ @@ -453,6 +458,7 @@
453 featureSelector: require('component/product/feature-selector.vue'), 458 featureSelector: require('component/product/feature-selector.vue'),
454 showBox: require('./show-box.vue'), 459 showBox: require('./show-box.vue'),
455 topNav: require('./top-nav.vue'), 460 topNav: require('./top-nav.vue'),
  461 + shareBottom: require('component/tool/share-bottom.vue'),
456 }, 462 },
457 methods: { 463 methods: {
458 /** 464 /**
@@ -476,7 +482,11 @@ @@ -476,7 +482,11 @@
476 this.entity.isCollect = 'N'; 482 this.entity.isCollect = 'N';
477 } else if (result.code === 403) { 483 } else if (result.code === 403) {
478 // 未登陆 484 // 未登陆
479 - yoho.goLogin(); 485 + yoho.goLogin('', function() {
  486 +
  487 + }, function() {
  488 +
  489 + });
480 } 490 }
481 }); 491 });
482 } else { 492 } else {
@@ -516,6 +526,21 @@ @@ -516,6 +526,21 @@
516 } 526 }
517 }); 527 });
518 528
  529 + share({
  530 + title: this.entity.productName,
  531 + link: location.href,
  532 + desc: '我在BLK发现了一个不错的商品,快来看看吧!',
  533 + imgUrl: this.firstImage.replace(/(\{width}|\{height}|\{mode})/g, function($0) {
  534 + const dict = {
  535 + '{width}': 300,
  536 + '{height}': 300,
  537 + '{mode}': 2
  538 + };
  539 +
  540 + return dict[$0];
  541 + })
  542 + });
  543 +
519 return result; 544 return result;
520 }).then((result)=> { 545 }).then((result)=> {
521 loadIntroDeferred = () => { 546 loadIntroDeferred = () => {
@@ -13,9 +13,10 @@ @@ -13,9 +13,10 @@
13 .top-nav { 13 .top-nav {
14 position: fixed; 14 position: fixed;
15 z-index: 10; 15 z-index: 10;
16 - font-size: 40px; 16 + font-size: 50px;
17 padding: 30px; 17 padding: 30px;
18 width: 100%; 18 width: 100%;
  19 + top: 40px;
19 20
20 .left { 21 .left {
21 float: left; 22 float: left;
1 <template> 1 <template>
2 <div> 2 <div>
3 - <template v-if="productList.length">  
4 - <order :config="orderConfig" :val="order">  
5 - </Sort>  
6 - <List :data="productList"></List>  
7 - </template>  
8 - <div class="empty-tip" v-if="empty">  
9 - <i class="icon icon-search"></i>  
10 - <p class="empty-tip-cn">未找到相关商品</p>  
11 - <p class="empty-tip-en">Did not find the relevant goods</p>  
12 - </div> 3 + <cheader title="新品抢先看">
  4 + <i class="icon icon-filter" slot="right" @click="openFilter"></i>
  5 + </cheader>
  6 + <order :config="orderConfig" :val="order"></order>
  7 + <List :data="productList"></List>
  8 + <Filter :config="filterConfig" action="/product/list.json" v-ref:filter></Filter>
13 </div> 9 </div>
14 </template> 10 </template>
15 <script> 11 <script>
  12 + const $ = require('yoho-jquery');
16 const Vue = require('yoho-vue'); 13 const Vue = require('yoho-vue');
17 const lazyload = require('yoho-vue-lazyload'); 14 const lazyload = require('yoho-vue-lazyload');
18 const infinitScroll = require('yoho-vue-infinite-scroll'); 15 const infinitScroll = require('yoho-vue-infinite-scroll');
19 -  
20 - const qs = require('yoho-qs'); 16 + const qs = require('yoho-qs/parse');
21 const bus = require('common/vue-bus'); 17 const bus = require('common/vue-bus');
22 const tip = require('common/tip'); 18 const tip = require('common/tip');
23 -  
24 - const sort = require('component/product/order.vue'); 19 + const cheader = require('component/header.vue');
  20 + const order = require('component/product/order.vue');
25 const list = require('component/product/list.vue'); 21 const list = require('component/product/list.vue');
  22 + const filter = require('component/product/filter.vue');
  23 +
  24 + let locationQuery = qs(decodeURIComponent(location.search.replace(/^\?/, '')));
26 25
27 Vue.use(lazyload); 26 Vue.use(lazyload);
28 Vue.use(infinitScroll); 27 Vue.use(infinitScroll);
29 -  
30 require('common/vue-filter'); 28 require('common/vue-filter');
31 29
32 module.exports = { 30 module.exports = {
33 el: '#product-new', 31 el: '#product-new',
34 data: function() { 32 data: function() {
35 return { 33 return {
36 - orderConfig: global.orderConfig,  
37 - filterConfig: global.filterConfig, 34 + sortName: locationQuery.sort_name,
  35 + orderConfig: [],
  36 + filterConfig: null,
38 37
39 // query 38 // query
40 - url: '/product/search.json',  
41 - order: null,  
42 - query: qs.query, 39 + url: '/product/new.json',
  40 + order: '',
  41 + filter: {},
43 page: 0, // 未搜索 page=0; 全部加载完 page = totalPage; 无数据: page !=0 && productList.length=0 42 page: 0, // 未搜索 page=0; 全部加载完 page = totalPage; 无数据: page !=0 && productList.length=0
44 totalPage: null, 43 totalPage: null,
45 44
@@ -50,21 +49,18 @@ @@ -50,21 +49,18 @@
50 inSearching: false // 请求中 49 inSearching: false // 请求中
51 }; 50 };
52 }, 51 },
53 - computed: {  
54 - // 无数据  
55 - empty: function() {  
56 - return this.page !== 0 && !this.productList.length;  
57 - }  
58 - },  
59 components: { 52 components: {
  53 + cheader,
60 list, 54 list,
61 - order 55 + order,
  56 + filter
62 }, 57 },
63 methods: { 58 methods: {
64 search: function() { 59 search: function() {
65 const self = this; 60 const self = this;
66 const nextPage = this.page + 1; 61 const nextPage = this.page + 1;
67 62
  63 + console.log(nextPage);
68 if (this.inSearching) { 64 if (this.inSearching) {
69 return; 65 return;
70 } 66 }
@@ -75,20 +71,22 @@ @@ -75,20 +71,22 @@
75 } 71 }
76 72
77 this.inSearching = true; 73 this.inSearching = true;
78 - console.log(nextPage);  
79 - $.get(this.url, {  
80 - order: this.order, // 排序 信息  
81 - query: this.query, 74 + $.get(this.url, Object.assign({
  75 + order: this.order,
82 page: nextPage 76 page: nextPage
83 - }) 77 + }, this.filter, locationQuery))
84 .done(res => { 78 .done(res => {
85 if (res.code === 200) { 79 if (res.code === 200) {
86 self.page = res.data.page; 80 self.page = res.data.page;
87 self.totalPage = res.data.pageTotal; 81 self.totalPage = res.data.pageTotal;
88 self.$set('productList', self.productList.concat(res.data.productList)); 82 self.$set('productList', self.productList.concat(res.data.productList));
  83 +
  84 + if (!self.filterConfig) {
  85 + self.$set('filterConfig', res.data.filter);
  86 + }
89 } 87 }
90 }) 88 })
91 - .fail(() => { 89 + .fail(error => {
92 tip('网络出错~'); 90 tip('网络出错~');
93 }) 91 })
94 .always(() => { 92 .always(() => {
@@ -96,6 +94,14 @@ @@ -96,6 +94,14 @@
96 }); 94 });
97 }, 95 },
98 96
  97 + openFilter() {
  98 + this.$refs.filter.isVisible = true;
  99 + },
  100 +
  101 + // openFilterSub: function(classify) {
  102 + // console.log('TODO: open filter sub', classify);
  103 + // },
  104 +
99 /** 105 /**
100 * 清空数据(page=0) 重新搜索 106 * 清空数据(page=0) 重新搜索
101 */ 107 */
@@ -106,9 +112,12 @@ @@ -106,9 +112,12 @@
106 } 112 }
107 }, 113 },
108 watch: { 114 watch: {
109 - /* order 改变 都会触发 重新搜索 */ 115 + /* order 和 filter 改变 都会触发 重新搜索 */
110 order: function() { 116 order: function() {
111 this.research(); 117 this.research();
  118 + },
  119 + filter: function() {
  120 + this.research();
112 } 121 }
113 }, 122 },
114 123
@@ -120,36 +129,33 @@ @@ -120,36 +129,33 @@
120 self.search(); 129 self.search();
121 }); 130 });
122 131
123 - bus.$on('order.change', function({  
124 - val  
125 - }) { 132 + bus.$on('order.change', function({val}) {
  133 + console.log(val);
126 self.order = val; 134 self.order = val;
127 }); 135 });
128 136
  137 + /**
  138 + * 筛选组件 筛选值变更,触发 filter.change事件
  139 + * 1. 重新搜索
  140 + * 2. 关闭 drawer 组件
  141 + */
  142 + bus.$on('filter.change', function({val}) {
  143 + console.log(val);
  144 + let filter = {};
  145 +
  146 + $.each(val, (type, item) => {
  147 + if (item.id) {
  148 + filter[type] = item.id;
  149 + }
  150 + });
  151 + self.$set('filter', filter);
  152 + self.$refs.filter.isVisible = false;
  153 + });
  154 +
129 this.search(); 155 this.search();
130 } 156 }
131 }; 157 };
132 158
133 </script> 159 </script>
134 <style> 160 <style>
135 - .empty-tip {  
136 - margin-top: 380px;  
137 - color: #b0b0b0;  
138 - text-align: center;  
139 - .icon-search {  
140 - display: inline-block;  
141 - font-size: 200px;  
142 - margin-bottom: 56px;  
143 - }  
144 - }  
145 -  
146 - .empty-tip-cn {  
147 - font-size: 34px;  
148 - margin-bottom: 30px;  
149 - }  
150 -  
151 - .empty-tip-en {  
152 - font-size: 20px;  
153 - }  
154 -  
155 </style> 161 </style>
1 <template> 1 <template>
2 <div class="brand-share"> 2 <div class="brand-share">
3 - <div class="brand-top-box" v-bind:style="{ 'background-image': `url(${shopInfo.brandBg})` }"></div> 3 + <img class="brand-top-box" v-bind:src="shopInfo.brandBg | resize 750 478">
4 <div class="brand-title">{{ shopInfo.brandName }}</div> 4 <div class="brand-title">{{ shopInfo.brandName }}</div>
5 <div class="brand-intro">{{ shopInfo.brandIntro }}</div> 5 <div class="brand-intro">{{ shopInfo.brandIntro }}</div>
6 <div class="tip">进入 BLK 选购潮品</div> 6 <div class="tip">进入 BLK 选购潮品</div>
@@ -13,10 +13,6 @@ @@ -13,10 +13,6 @@
13 .brand-share { 13 .brand-share {
14 .brand-top-box { 14 .brand-top-box {
15 width: 100%; 15 width: 100%;
16 - height: 468px;  
17 - color: #fff;  
18 - background-color: #ccc;  
19 - position: relative;  
20 } 16 }
21 17
22 .brand-title { 18 .brand-title {
@@ -56,6 +52,7 @@ @@ -56,6 +52,7 @@
56 const shareBottom = require('component/tool/share-bottom.vue'); 52 const shareBottom = require('component/tool/share-bottom.vue');
57 const qs = require('yoho-qs'); 53 const qs = require('yoho-qs');
58 const tip = require('common/tip'); 54 const tip = require('common/tip');
  55 + const share = require('common/share');
59 56
60 module.exports = { 57 module.exports = {
61 58
@@ -64,6 +61,16 @@ @@ -64,6 +61,16 @@
64 shopInfo: {} 61 shopInfo: {}
65 }; 62 };
66 }, 63 },
  64 + watch: {
  65 + shopInfo() {
  66 + share({
  67 + title: this.shopInfo.brandName,
  68 + link: location.href,
  69 + desc: this.shopInfo.shareSubTitle,
  70 + imgUrl: this.shopInfo.brandBg
  71 + });
  72 + }
  73 + },
67 methods: { 74 methods: {
68 75
69 /* 获取店铺简介相关数据 */ 76 /* 获取店铺简介相关数据 */
@@ -51,7 +51,7 @@ @@ -51,7 +51,7 @@
51 color: #000; 51 color: #000;
52 height: 120px; 52 height: 120px;
53 top: 0; 53 top: 0;
54 - padding: 70px 20px 10px; 54 + padding: 55px 20px 10px;
55 } 55 }
56 </style> 56 </style>
57 57