Authored by 毕凯

Merge branch 'gray'

Showing 100 changed files with 1285 additions and 753 deletions

Too many changes to show.

To preserve performance only 100 of 100+ files are displayed.

**/css/**/*.css
**/dist/**/*.css
**/build/**/*.css
**/scss/activity/_aslider.css
**/scss/layout/_swiper.css
**/scss/activity/trend/_map.css
... ...
... ... @@ -5,10 +5,6 @@
*/
'use strict';
// if (process.env.USE_APM === '1' && process.env.NODE_ENV === 'production') {
// require('oneapm');
// }
const config = require('./config/common');
global.Promise = require('bluebird');
... ...
... ... @@ -22,7 +22,7 @@ const _getPname = (req) => {
};
exports.index = function(req, res, next) {
model.index({
req.ctx(model).index({
code: req.params.code,
type: stringProcess.paramsFilter(req.query.type),
from_page_name: _getPname(req),
... ... @@ -53,7 +53,7 @@ exports.index = function(req, res, next) {
};
exports.sidebar = function(req, res, next) {
model.index({
req.ctx(model).index({
code: req.params.code
}).then((result) => {
if (!result) {
... ... @@ -68,7 +68,7 @@ exports.sidebar = function(req, res, next) {
exports.bottombar = function(req, res, next) {
model.index({
req.ctx(model).index({
code: req.params.code
}).then((result) => {
if (!result) {
... ... @@ -117,7 +117,7 @@ exports.couponSend = (req, res, next) => {
return res.jsonp(resultData);
}
model.couponSend(uid, token).then(result => {
req.ctx(model).couponSend(uid, token).then(result => {
res.set({
'Cache-Control': 'no-cache',
Pragma: 'no-cache',
... ...
... ... @@ -15,7 +15,7 @@ exports.productLst = function(req, res, next) {
let getProductList;
if (req.query.maybeLike) {
getProductList = model.maybeLikeList(Object.assign({
getProductList = req.ctx(model).maybeLikeList(Object.assign({
uid: uid,
udid: udid,
yh_channel: req.query.yh_channel || (req.cookies._Channel && channels[req.cookies._Channel]) || 1,
... ... @@ -58,7 +58,7 @@ exports.productLst = function(req, res, next) {
}
}
getProductList = model.productLst(params);
getProductList = req.ctx(model).productLst(params);
}
getProductList.then((result) => {
... ... @@ -93,7 +93,7 @@ exports.coupon = function(req, res, next) {
});
}
model.getCoupon({
req.ctx(model).getCoupon({
activity_template_id,
uid
}).then((result) => {
... ...
... ... @@ -3,9 +3,8 @@
* Created by yoho on 2016/10/19.
*/
'use strict';
const mRoot = '../models';
const share = require(`${mRoot}/share`);
const _ = require('lodash');
const shareModel = require('../models/share');
exports.getShareContent = (req, res, next) => {
if (!req.query.shareId) {
... ... @@ -22,7 +21,7 @@ exports.getShareContent = (req, res, next) => {
});
}
share.getShareContent({
req.ctx(shareModel).getShareContent({
shareId: req.query.shareId
}).then(result => {
res.jsonp(result);
... ...
'use strict';
const TideModel = require('../models/tide');
const headerModel = require('../../../doraemon/models/header');
/**
* 潮品推介
*/
exports.category = (req, res, next) => {
let uid = req.user.uid || req.query.uid;
let params = {
uid: uid,
isApp: req.yoho.isApp,
scene: req.query.scene || 1
};
let renders = {};
if (!req.yoho.isApp) {
renders = {
title: req.query.title || '潮流推荐 | Yoho!Buy有货 | 潮流购物逛不停',
pageHeader: headerModel.setNav({
navTitle: req.query.title || '潮流推荐'
}),
pageFooter: true,
};
}
return req.ctx(TideModel).tideCategory(params).then(result => {
res.render('tide/category', Object.assign(renders, {
module: 'tide',
page: 'category',
width750: true,
localCss: true,
result: result
}));
}).catch(next);
};
/**
* 潮牌推介
*/
exports.shop = (req, res, next) => {
let uid = req.user.uid || req.query.uid;
let params = {
uid: uid,
isApp: req.yoho.isApp,
scene: req.query.scene || 1
};
let renders = {};
if (!req.yoho.isApp) {
renders = {
title: req.query.title || '潮流推荐 | Yoho!Buy有货 | 潮流购物逛不停',
pageHeader: headerModel.setNav({
navTitle: req.query.title || '潮流推荐'
}),
pageFooter: true,
};
}
return req.ctx(TideModel).tideShop(params).then((result) => {
res.render('tide/shop', Object.assign(renders, {
module: 'tide',
page: 'shop',
width750: true,
localCss: true,
result: result
}));
}).catch(next);
};
... ...
... ... @@ -31,7 +31,7 @@ function droitHtml(contents) {
banner: `http://img12.static.yhbimg.com/sort/2018/03/26/13/02ae523f4c97e2c8d184932c3c846a59f9.jpg${imageView2}`,
intros: [
{title: '特权介绍', data: ['会员在有货平台上购买符合活动规则的商品时,可享受对应等级的折扣。会员等级越高,享受的折扣力度越大。']},
{title: '折扣说明', data: ['银卡会员享9.5折优惠,金卡会员享9折优惠,白金卡会员享8.8折优惠。']},
{title: '折扣说明', data: ['银卡会员最高可享9.5优惠,金卡会员最高可享9折优惠,白金卡会员最高可享8.8折优惠。']},
],
interlocution: []
};
... ... @@ -39,13 +39,14 @@ function droitHtml(contents) {
item.content = {
banner: `http://img12.static.yhbimg.com/sort/2018/03/26/13/02402b95df5f0f0f5ef4d4b79edd515577.jpg${imageView2}`,
intros: [
{title: '特权介绍', data: ['会员专享生日福利,等级越高,优惠力度越大,具体以实际领取为准。']},
{title: '权益对象', data: ['银卡及以上会员、且已完善个人生日信息才可领取生日福利券。']},
{title: '特权介绍', data: ['会员专享生日礼包,等级越高,礼包价值越高,具体以实际发放为准。']},
{title: '权益对象', data: ['银卡及以上会员、且已完善个人生日信息才可领取生日礼包。']},
{title: '领取说明', data: [
'生日福利券在生日当月可领,领取后有效期15天。',
'生日福利券可在“我的-生日券”页面领取。',
'生日福利券一年内(365天)仅限领取一次。',
'若在上述时间段内未领取,将无法补发生日福利。'
'生日礼包在生日前7天至生日后7天可领,领取后生日福利券有效期15天。',
'生日礼包可在会员中心-我的礼包页面领取。',
'生日礼包一年内(365天)仅发放一次。',
'若在上述时间段内未领取,将无法补发生日礼包。',
'老版本用户需更新至新版本app才可领取生日礼包。'
]},
]
};
... ... @@ -64,21 +65,69 @@ function droitHtml(contents) {
item.content = {
banner: `http://img11.static.yhbimg.com/sort/2018/03/26/13/0160bd2c93e5730608a7921181eb826ab2.jpg${imageView2}`,
intros: [
{title: 'Dear:', data: ['近期将针对有货的VIP会员推出购物返有货币服务,成功购物之后自动到账,服务即将开启请随时关注最新APP会员权益动态!']},
{ title: '特权介绍', data: ['会员在有货平台上购买符合活动规则的商品后,可获得商品实付金额一定比例的有货币。'] },
{ title: '领取说明', data: [
'在线支付订单订单完成后可获得该等级对应的有货币奖励,货到付款发货15天后发放有货币,有货币按照该等级对应的比例发放。',
'有货币可抵现,抵现比例100:1。',
'退货后会扣除返还的有货币,若有货币不足,将会从原订单退款金额中扣除相应的退款。'
]
},
{
title: '返币比例', data: [
`
<table class="return-coin-table">
<tr>
<th>会员等级</th>
<th>购物实付金额</th>
<th style="color: red">返币比例</th>
<th>返币个数</th>
</tr>
<tr>
<td>银卡会员</td>
<td>100</td>
<td style="color: red">30%</td>
<td>30</td>
</tr>
<tr>
<td>金卡会员</td>
<td>100</td>
<td style="color: red">30%</td>
<td>30</td>
</tr>
<tr>
<td>白金会员</td>
<td>100</td>
<td style="color: red">50%</td>
<td>50</td>
</tr>
</table>
`,
'提示:小数点后不计入返币数量,例如:白金会员商品实付金额299,则返149(299*50%=149.5)个有货币。'
]
},
]
};
} else if (item.displayName === '升级礼包') {
item.content = {
banner: `http://img11.static.yhbimg.com/sort/2018/03/26/13/0100d72b57f8c364e69cdfeb708b5d852a.jpg${imageView2}`,
intros: [
{title: 'Dear:', data: ['近期将针对有货的VIP会员推出专享升级礼包服务,等级提升后即可领取,服务即将开启请随时关注最新APP会员权益动态!']},
{ title: '特权介绍', data: ['会员专享升级礼包,具体以实际发放为准。'] },
{ title: '领取说明', data: [
'升级礼包在升级当日7天内可领取,领取后优惠券有效期7天。',
'升级礼包可在会员中心-我的礼包页面领取。',
'每个等级的礼包365天仅发放一次。',
'若在上述时间段内未领取,将无法补发升级礼包。',
'老版本用户需更新至新版本app才可领取生日礼包。'
]
}
]
};
} else if (item.displayName === '优享客服') {
item.content = {
banner: `http://img11.static.yhbimg.com/sort/2018/03/26/13/01ded1925ced60db1a63937bcd3afbbb1d.jpg${imageView2}`,
intros: [
{title: 'Dear:', data: ['近期将针对有货的VIP会员推出优享客服服务,感受更优质的客服体验,服务即将开启请随时关注最新APP会员权益动态!']},
{ title: '特权介绍', data: ['白金会员将由在线客服提供更优质的服务,并享受优先接入的特权,减少等待时间。'] },
{title: '使用说明', data: ['在线客服:<a href=//m.yohobuy.com/service/chatQaList?openby:yohobuy={"action":"go.sfhome"} style="text-decoration: underline;color: red;">app我的->服务与反馈->在线客服->人工客服</a>']}
]
};
}
... ...
... ... @@ -57,8 +57,11 @@ const _getShopGroup = (shopRawData) => {
});
};
module.exports = {
index: function(params) {
class featureModel extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
}
index(params) {
return Promise.coroutine(function*() {
if (!params.code) {
return Promise.resolve({});
... ... @@ -134,7 +137,7 @@ module.exports = {
return data;
})();
},
}
/**
* 领取优惠券
... ... @@ -157,7 +160,7 @@ module.exports = {
};
}
return api.get('', data).then(result => {
return this.get({data}).then(result => {
if (!result) {
result.code = 404;
... ... @@ -167,4 +170,7 @@ module.exports = {
return result;
});
}
};
}
module.exports = featureModel;
... ...
'use strict';
const api = global.yoho.API;
let _getProduct = function(o) {
return {
small_sort_id: o.small_sort_id,
... ... @@ -30,12 +28,16 @@ const gender = {
2: '2,3'
};
module.exports = {
productLst: function(params) {
return api.get('', Object.assign({
method: 'app.search.newPromotion'
}, params), {
cache: true
class individuationModel extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
}
productLst(params) {
return this.get({
data: Object.assign({
method: 'app.search.newPromotion'
}, params),
param: {cache: true}
}).then(res => {
var data = [],
lst = (res && res.data && res.data.product_list) || [];
... ... @@ -45,19 +47,20 @@ module.exports = {
});
return data;
});
},
maybeLikeList: function(params) {
return api.get('', {
method: 'app.home.newPreference',
uid: params.uid || 0,
udid: params.udid || 0,
yh_channel: params.yh_channel,
limit: params.limit || 60,
need_filter: 'null',
rec_pos: '100053',
gender: params.gender || gender[params.yh_channel]
}, {
cache: true
}
maybeLikeList(params) {
return this.get({
data: {
method: 'app.home.newPreference',
uid: params.uid || 0,
udid: params.udid || 0,
yh_channel: params.yh_channel,
limit: params.limit || 60,
need_filter: 'null',
rec_pos: '100053',
gender: params.gender || gender[params.yh_channel]
},
param: {cache: true}
}).then(res => {
var data = [],
lst = (res && res.data && res.data.product_list) || [];
... ... @@ -67,12 +70,16 @@ module.exports = {
});
return data;
});
},
getCoupon: function(params) {
return api.get('', Object.assign({
method: 'app.coupons.personalCoupons'
}, params), {
cache: true
}
getCoupon(params) {
return this.get({
data: Object.assign({
method: 'app.coupons.personalCoupons'
}, params),
param: {cache: true}
});
}
};
}
module.exports = individuationModel;
... ...
/**
* Created by yoho on 2016/10/19.
*/
'use strict';
const serviceApi = global.yoho.ServiceAPI;
/**
* 从接口获取 share 内容
* @returns {*|Promise.<TResult>}
*/
const getShareContent = (params) => {
return serviceApi.get('operations/api/v5/webshare/getShare', {
share_id: params.shareId
}).then(result => {
return result;
});
};
class shareModel extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
}
module.exports = {
getShareContent
};
/**
* 从接口获取 share 内容
* @returns {*|Promise.<TResult>}
*/
getShareContent(params) {
return this.get({
url: 'operations/api/v5/webshare/getShare',
data: {share_id: params.shareId},
api: global.yoho.ServiceAPI,
}).then(result => {
return result;
});
}
}
module.exports = shareModel;
... ...
'use strict';
const _ = require('lodash');
const helpers = global.yoho.helpers;
const ROOTPATH = '../../../';
const contentCodeConfig = require(`${ROOTPATH}config/content-code`);
const productProcess = require(`${ROOTPATH}utils/product-process`);
class TideModel extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
}
tideCategory(params) {
return Promise.all([
this.getResource(Object.assign({
content_code: contentCodeConfig.tide.category
}, params)),
this.crmRecommendSort(params)
]).then(res => {
let tide = {
resource: _.get(res[0], 'data', []),
contents: []
};
let sindex = _.findIndex(tide.resource, {template_name: 'image_list'});
if (sindex > -1) {
tide.resource[sindex].title = '# 精彩活动 #';
}
_.each(_.get(res[1], 'data', []), (item, index) => {
item.sortInfo = item.sortInfo || {};
let goods = productProcess.processProductList(item.productList || [], {
isApp: params.isApp,
showSimilar: false
});
let tdata = {
sortInfo: Object.assign({}, item.sortInfo, {
url: helpers.urlFormat(`/list/mi${item.sortInfo.itemId}`, {
'openby:yohobuy': `{"action":"go.list","params":{"misort":"${item.sortInfo.itemId}"}}`
})
}),
goods: goods
};
if (index === 0) {
tdata.title = '# 潮品推介 #';
} else {
tdata.borderTop = true;
}
tide.contents.push(tdata);
});
return tide;
});
}
// 促购个性化3个品类商品推荐
crmRecommendSort(params) {
return this.get({
data: Object.assign({
method: 'app.product.crmRecommend.sort'
}, params)
});
}
// 促购个性化店铺商品推荐(1个店铺+店铺下6个商品)
crmRecommendShopSix(params) {
return this.get({
data: Object.assign({
method: 'app.product.crmRecommend.shopSix'
}, params)
});
}
// 促购个性化店铺推荐(9个店铺)
crmRecommendShop(params) {
return this.get({
data: Object.assign({
method: 'app.product.crmRecommend.shop'
}, params)
});
}
// 促购个性化店铺推荐(30个商品)
crmRecommendProduct(params) {
return this.get({
data: Object.assign({
method: 'app.product.crmRecommend.product'
}, params)
});
}
tideShop(params) {
return Promise.all([
this.getResource(Object.assign({
content_code: contentCodeConfig.tide.brand
}, params)),
this.crmRecommendShopSix(params),
this.crmRecommendShop(params),
this.crmRecommendProduct(params)
]).then(res => {
let tide = {
resource: _.get(res[0], 'data', []),
brands: [],
shopInfo: [],
contents: []
};
let sindex = _.findIndex(tide.resource, {template_name: 'image_list'});
if (sindex > -1) {
tide.resource[sindex].title = '# 精彩活动 #';
}
let shopInfo = _.get(res[1], 'data.shopInfo', {});
if (shopInfo.shopId) {
shopInfo.url = helpers.urlFormat(`/shop/${shopInfo.shopDomain}-${shopInfo.shopId}.html`, {
'openby:yohobuy': `{"action":"go.shop","params":{"shop_id":"${shopInfo.shopId}","shop_template_type":"${shopInfo.shopTemplateType}","shop_name":"${shopInfo.shopName}"}}` //eslint-disable-line
});
}
if (shopInfo.shopId || _.get(res[1], 'data.productList', []).length) {
tide.shopInfo.push({
title: '# 为你精选 #',
shopInfo: shopInfo,
goods: productProcess.processProductList(_.get(res[1], 'data.productList', []), {
isApp: params.isApp,
showSimilar: false
})
});
}
_.each(_.get(res[2], 'data', []), (item) => {
tide.brands.push(Object.assign({}, item, {
url: helpers.urlFormat(`/shop/${item.shopDomain}-${item.shopId}.html`, {
'openby:yohobuy': `{"action":"go.shop","params":{"shop_id":"${item.shopId}","shop_template_type":"${item.shopTemplateType}","shop_name":"${item.shopName}"}}` //eslint-disable-line
})
}));
});
if (_.get(res[3], 'data', []).length) {
tide.contents.push({
title: '# 潮品推介 #',
goods: productProcess.processProductList(_.get(res[3], 'data', []), {
isApp: params.isApp,
showSimilar: false
})
});
}
return tide;
});
}
getResource(params) {
return this.get({
url: 'operations/api/v5/resource/get',
data: Object.assign({
platform: 'iphone'
}, params),
api: global.yoho.ServiceAPI,
param: {cache: true}
}).then(result => {
return result;
});
}
}
module.exports = TideModel;
... ...
... ... @@ -38,6 +38,8 @@ const individuation = require(`${cRoot}/individuation`);
const feature = require(`${cRoot}/feature`);
const tide = require(`${cRoot}/tide`);
const appDownloads = require(`${cRoot}/app-downloads`);
const redbag = require(`${cRoot}/redbag`);
... ... @@ -268,6 +270,8 @@ router.get('/feature/:code.html', feature.index);
router.get('/featuresidebar/:code.html', feature.sidebar);
router.get('/featurebottombar/:code.html', feature.bottombar);
router.get('/feature/couponSend', feature.couponSend); // 获取优惠券
router.get('/tide/category', auth, tide.category); // 潮品推介
router.get('/tide/shop', auth, tide.shop); // 潮牌推介
// 2016 年度账单
router.get('/annual-account', annualAccount.index);
... ...
<div class="activity-cate-page">
<div class="brand-block"></div>
<div class="tide-promotion-container">
<div class="tide-title"># 潮品推介 #</div>
<div class="tide-goods">
<div class="goods">
<div class="goods-img"><img src="//img11.static.yhbimg.com/goodsimg/2018/03/30/14/01a5f5036a8829c4c01aa8d02b1f9f9ac7.png?imageMogr2/thumbnail/235x314/background/d2hpdGU=/position/center/quality/60" /></div>
<div class="goods-name">adidas Originals </div>
<div class="goods-footer">
<div class="goods-price">¥249 <span class="old-price">¥249</span></div>
<div class="cart-icon"></div>
</div>
</div>
</div>
</div>
</div>
... ...
... ... @@ -4,7 +4,7 @@
<div class="swiper-container droit-nav">
<div class="swiper-wrapper">
{{#vipNav}}
<div class="swiper-slide droit-nav-item {{#if active}}active1{{/if}}">
<div class="swiper-slide droit-nav-item{{#if active}} active1{{/if}} {{#isEqualOr light 'N'}} no-light{{/isEqualOr}}">
<img class="droit-nav-icon" src="{{image iosSmallImage 100 100}}" />
<span class="name">{{displayName}}</span>
</div>
... ...
<div class="activity-tide-page">
{{> tide/resource-top resource=result.resource}}
{{#result.contents}}
{{#if title}}
<div class="tide-title">{{title}}</div>
{{/if}}
{{#if borderTop}}
<div class="tide-border-top"></div>
{{/if}}
<div class="tide-goods">
{{#if sortInfo.imageUrl}}
<div class="cate-block">
<a href="{{sortInfo.url}}">
<img class="lazy" data-original="{{image sortInfo.imageUrl 217 300 1}}" />
</a>
</div><!--/cate-block-->
{{/if}}
{{> tide/goods}}
</div><!--/tide-goods-->
{{/result.contents}}
{{> tide/resource-bottom resource=result.resource}}
</div>
... ...
<div class="activity-tide-page">
{{> tide/resource-top resource=result.resource}}
{{#result.shopInfo}}
{{#if title}}
<div class="tide-title">{{title}}</div>
{{/if}}
<div class="tide-goods">
{{> tide/shop-info}}
{{> tide/goods}}
</div><!--/tide-goods-->
{{/result.shopInfo}}
{{#if result.brands}}
<div class="tide-title"># 潮牌推介 #</div>
<div class="tide-brand">
{{> tide/brands brands=result.brands}}
</div>
{{/if}}
{{#result.contents}}
{{#if title}}
<div class="tide-title">{{title}}</div>
{{/if}}
{{#if borderTop}}
<div class="tide-border-top"></div>
{{/if}}
<div class="tide-goods">
{{> tide/shop-info}}
{{#if sorts.sortImg}}
<div class="cate-block">
<img class="lazy" data-original="{{image sorts.sortImg 216 300 1}}">
</div><!--/cate-block-->
{{/if}}
{{> tide/goods}}
</div><!--/tide-goods-->
{{/result.contents}}
{{> tide/resource-bottom resource=result.resource}}
</div>
... ...
{{#brands}}
<div class="brand">
<a href="{{url}}">
<div class="brand-block">
<img class="brand-img lazy" data-original="{{image imageUrl 216 270 2}}" alt="{{name}}">
<div class="goods-name ellipsis">{{shopName}}</div>
</div>
<div class="entry-brand">
进入店铺&nbsp;&nbsp;<span class="iconfont">&#xe614;</span>
</div>
</a>
</div>
{{/brands}}
... ...
{{#goods}}
<div class="goods">
<a class="good-thumb" href="{{url}}">
<div class="goods-img">
<img class="lazy" data-original="{{image default_images 217 288 1}}" alt="{{imgAlt}}">
</div>
<div class="goods-footer">
<div class="goods-name ellipsis">{{brand_name}}</div>
<div class="goods-bottom">
<div class="sales-price">
¥{{round sales_price 0}}{{#if market_price}}&nbsp;&nbsp;<span class="market-price">¥{{round market_price 0}}</span>{{/if}}
</div>
<div class="cart-icon"></div>
</div>
</div>
</a>
</div>
{{/goods}}
... ...
{{#resource}}
{{#isEqualOr template_name 'image_list'}}
{{#if title}}<div class="tide-title">{{title}}</div>{{/if}}
<div class="wonderful-container">
{{#isEqualOr data.title.column_num '1'}}
{{#each data.list}}
<div class="wonderful-big">
<a href="{{url}}">
<img class="lazy" data-original="{{image src 670 330 1}}" />
<div class="see-block">点击查看&nbsp;&nbsp;<span class="iconfont">&#xe614;</span></div>
</a>
</div>
{{/each}}
{{/isEqualOr}}
{{#isEqualOr data.title.column_num '2'}}
{{#each data.list}}
<div class="wonderful-small">
<a href="{{url}}">
<img class="lazy" data-original="{{image src 320 220 1}}" />
<div class="see-block">点击查看&nbsp;&nbsp;<span class="iconfont">&#xe614;</span></div>
</a>
</div>
{{/each}}
{{/isEqualOr}}
</div>
{{/isEqualOr}}
{{#isEqualOr template_name 'divideImage'}}
{{#each data}}
<div class="footer-banner">
<a href="{{url}}">
<img class="lazy" data-original="{{image src 750 500 1}}" />
</a>
</div>
{{/each}}
{{/isEqualOr}}
{{/resource}}
... ...
{{#resource}}
{{#isEqualOr template_name 'single_image'}}
{{#each data}}
<div class="brand-banner">
<img src="{{image src 750 360 1}}" />
</div>
{{/each}}
{{/isEqualOr}}
{{/resource}}
... ...
{{#if shopInfo.imageUrl}}
<div class="brand-block-big">
<a href="{{shopInfo.url}}">
<img class="brand-img" src="{{image shopInfo.imageUrl 314 352 2}}" alt="{{shopInfo.shopName}}" />
</a>
<a href="{{shopInfo.url}}">
<div class="brand-info">
<div class="brand-logo">
<img src="{{image shopInfo.logoUrl 130 130 2}}" />
</div>
<div class="name">{{shopInfo.shopName}}</div>
<div class="promotion-title ellipsis">{{shopInfo.promotionTitle}}</div>
<div class="entry-brand">进入店铺&nbsp;&nbsp;<span class="iconfont">&#xe614;</span></div>
</div>
</a>
</div>
{{/if}}
... ...
... ... @@ -47,14 +47,14 @@ class BuyNowController {
return next();
}
if (product_sku !== orderInfo.product_sku) {
if (orderInfo.product_sku && product_sku !== orderInfo.product_sku) {
orderInfo = {};
res.clearCookie('buynow_info', actCkOpthn);
}
// 是否需要重新计算
let needReComputer = orderInfo && !_.isEmpty(orderInfo) &&
(orderInfo.yohoCoin || orderInfo.coupon_code);
(orderInfo.yohoCoin || orderInfo.coupon_code || orderInfo.gift_card_code);
let computerPromise = null;
if (needReComputer) {
... ...
... ... @@ -280,7 +280,7 @@ const payAli = (req, res, next) => {
// 支付宝支付校验
if (!verifyResult.payResult) {
return res.render('pay/pay-failure', responseFailure);
return res.render('pay/pay-failure', _.assign(responseData, responseFailure));
}
req.ctx(payModel).getPayAli(param).then(result => {
... ...
... ... @@ -37,7 +37,7 @@ class cartModel extends global.yoho.BaseModel {
// 是否需要重新计算
let needReComputer = orderInfoCookie && !_.isEmpty(orderInfoCookie) &&
(orderInfoCookie.yohoCoin || orderInfoCookie.user_check_coupon === 'Y');
(orderInfoCookie.yohoCoin || orderInfoCookie.user_check_coupon === 'Y' || orderInfoCookie.gift_card_code);
if (needReComputer) {
orderInfoCookie.paymentType = orderInfoCookie.paymentType ? orderInfoCookie.paymentType : '';
... ...
... ... @@ -10,7 +10,7 @@ class orderModel extends global.yoho.BaseModel {
let invoices_title = false;
let invoices_title_personal = false;
let invoices_type = '2';
let addressId = orderInfo.addressId;
let addressId = orderInfo.address_id;
// 用户手机号处理
if (orderInfo.receiverMobile && orderInfo.isModifyTel) {
... ...
... ... @@ -374,6 +374,10 @@ class payModel extends global.yoho.BaseModel {
alipayResultVerify(params) {
let checkResult = {};
if (params.uid) {
delete params.uid;
}
if (params.q) {
delete params.q;
}
... ... @@ -428,6 +432,9 @@ class payModel extends global.yoho.BaseModel {
if (result && result[2] && result[2].data && result[2].data.payment_amount) {
resu.packageTitle = _.get(result[3], 'data.notice', '');
resu.gain_yoho_coin = _.get(result[3], 'data.gain_yoho_coin', 0);
resu.growth_value = _.get(result[3], 'data.growth_value', 0);
resu.msg = _.get(result[3], 'data.msg', '');
resu.payment = result[2].data.payment_amount;
... ...
... ... @@ -173,13 +173,6 @@
实付金额
<span>¥{{round price 2}}</span>
</div>
{{#if returnYohoCoin}}
<div class="yoho-coin">
共返有货币: {{yohoCoinNum}}
</div>
{{/if}}
</section>
{{#if addressInfo}}
<div class="address-bottom">
... ...
... ... @@ -178,13 +178,6 @@
实付金额
<span>¥{{round price 2}}</span>
</div>
{{#if returnYohoCoin}}
<div class="yoho-coin">
共返有货币: {{yohoCoinNum}}
</div>
{{/if}}
</section>
{{#if addressInfo}}
<div class="address-bottom">
... ...
... ... @@ -28,7 +28,22 @@
<td>支付宝</td>
</tr>
{{/if}}
{{#if gain_yoho_coin}}
<tr>
<td>返有货币</td>
<td>{{gain_yoho_coin}}</td>
</tr>
{{/if}}
{{#if growth_value}}
<tr>
<td>返成长值</td>
<td>{{growth_value}}</td>
</tr>
{{/if}}
</table>
{{#if msg}}
<div class="growth-tip"><span class="iconfont icon-tan"></span>{{msg}}</div>
{{/if}}
</div>
<div class="btn-c">
<a href="/">随便逛逛</a>
... ... @@ -52,4 +67,3 @@
</div>
{{> home/maybe-like}}
</div>
... ...
... ... @@ -100,7 +100,6 @@ exports.index = (req, res, next) => {
res.render('channel-index', {
module: 'channel',
page: 'index',
title: 'Yoho!Buy 有货',
searchUrl: helpers.urlFormat('/', null, 'search'),
pageFooter: true,
channelList: result[0].channelList,
... ...
... ... @@ -6,9 +6,6 @@
'use strict';
const _ = require('lodash');
// const helpers = global.yoho.helpers;
// const utils = require('../../../utils');
const genderMap = {
boys: '1,3',
girls: '2,3',
... ... @@ -39,34 +36,17 @@ module.exports = class extends global.yoho.BaseModel {
// 如果有二级菜单,二级菜单跳转,否则一级菜单跳转
if (firstItem.sub && firstItem.sub.length) {
_.map(firstItem.sub, function(secondItem) {
// secondItem.url = helpers.urlFormat('/', utils.mapSort({
// sort: _.get(secondItem, 'relation_parameter.sort'),
// sort_name: secondItem.category_name,
// gender: genderMap[key] || ''
// }), 'list');
secondItem.url =
`//m.yohobuy.com/list/gd${genderMap[key] || ''}-ci${_.get(secondItem, 'category_id')}`;
`//m.yohobuy.com/list/gd${genderMap[key] || ''}-ci${_.get(secondItem, 'category_id')}.html`;
});
firstItem.sub.unshift({
category_name: `全部${firstItem.category_name}`,
// url: helpers.urlFormat('/', utils.mapSort({
// sort: _.get(firstItem, 'relation_parameter.sort'),
// sort_name: firstItem.category_name,
// gender: genderMap[key] || ''
// }), 'list'),
url: `//m.yohobuy.com/list/gd${genderMap[key] || ''}-ci${_.get(firstItem, 'category_id')}?title=${firstItem.category_name}` // eslint-disable-line
url: `//m.yohobuy.com/list/gd${genderMap[key] || ''}-ci${_.get(firstItem, 'category_id')}.html?title=${firstItem.category_name}` // eslint-disable-line
});
} else {
// firstItem.url = helpers.urlFormat('/', utils.mapSort({
// sort: _.get(firstItem, 'relation_parameter.sort'),
// sort_name: firstItem.category_name,
// gender: genderMap[key] || ''
// }), 'list');
firstItem.url =
`//m.yohobuy.com/list/gd${genderMap[key] || ''}-ci${_.get(firstItem, 'category_id')}`;
`//m.yohobuy.com/list/gd${genderMap[key] || ''}-ci${_.get(firstItem, 'category_id')}.html`;
}
});
});
... ...
... ... @@ -5,13 +5,13 @@
{{#if @first}}
<li class="swiper-slide buriedpoint" data-bp-id="shop_bannerarea_{{url}}_0">
<a href="{{url}}">
<img src="{{image2 img q=60}}">
<img src="{{image2 img q=60}}" alt="banner轮播图">
</a>
</li>
{{^}}
<li class="swiper-slide buriedpoint" data-bp-id="shop_bannerarea_two_0">
<a href="{{url}}">
<img class="swiper-lazy" data-src="{{image2 img q=60}}">
<img class="swiper-lazy" data-src="{{image2 img q=60}}" alt="banner轮播图">
</a>
</li>
{{/if}}
... ...
... ... @@ -274,19 +274,20 @@ const index = (req, res, next) => {
let shareInfo = _shareInfo(id, detail.getArticle);
Object.assign(guang, shareInfo);
data.title = detail.getArticle.article_title + '-YOHO!BUY 有货网';
data.title = detail.getArticle.article_title + '_潮流资讯-YOHO!BUY 有货';
data.title_more = true;
data.description = detail.getArticle.descriptionText;
data.description = detail.getArticle.descriptionText && detail.getArticle.descriptionText.slice(0, 100);
data.description_more = true;
}
if (detail.getArticle.article_title) {
parameter.tltle = detail.getArticle.article_title + '-YOHO!BUY 有货网';
parameter.tltle = detail.getArticle.article_title + '_潮流资讯-YOHO!BUY 有货';
parameter.keywords = detail.getArticle.article_title;
}
if (detail.getArticle.descriptionText) {
parameter.description = detail.getArticle.descriptionText;
parameter.description =
detail.getArticle.descriptionText && detail.getArticle.descriptionText.slice(0, 100);
}
// 标识有微信分享
... ...
... ... @@ -25,8 +25,8 @@ exports.index = (req, res, next) => {
pageHeader: headerModel.setNav({
navTitle: '有货逛不停'
}),
title: '逛潮流,最新原创潮流资讯 | YOHO!BUY有货',
keywords: '潮流资讯,潮流文章,有货潮流分享',
title: '潮流资讯,最新原创潮流时尚资讯-YOHO!BUY 有货',
keywords: '潮流资讯,时尚潮流资讯',
description: '来有货玩潮流,潮流资讯大分享!年轻人潮流购物中心,了解潮流趋势、掌握潮流文化知识信息,尽在有货逛潮流!',
module: 'guang',
page: 'guang-new',
... ...
... ... @@ -23,27 +23,27 @@ const channels = {
const listTDK = {
0: {
title: '最新潮流文章,逛最新潮流资讯-YOHO!BUY 有货网',
title: '最新潮流资讯-YOHO!BUY 有货',
keywords: '最新潮流文章,潮流资讯,逛潮流',
description: '有货网每天提供全球最新最潮的潮流文章资讯,宣传潮流商品,潮流文化,潮流品牌等信息,想更多了解潮流最新资讯就来有货网!'
}, // 最新
1001: {
title: '高人气潮流文章,逛人气潮流资讯-YOHO!BUY 有货网',
title: '人气潮流资讯-YOHO!BUY 有货',
keywords: '人气潮流文章,潮流人气,逛潮流人气',
description: '有货网每天提供全球人气最高的潮流文章资讯,宣传潮流商品,潮流文化,潮流品牌等信息,想更多了解高人气潮流资讯就来有货网!'
}, // 人气
2: {
title: '各种潮流搭配,逛潮流搭配资讯-YOHO!BUY 有货网',
title: '潮流搭配_潮流资讯-YOHO!BUY 有货',
keywords: '搭配潮流文章,潮流搭配',
description: '有货网每天提供全球最新最潮的潮流搭配文章资讯,宣传潮流商品,潮流文化,潮流品牌等信息,想更多了解学习潮流搭配资讯就来有货网!'
}, // 搭配
4: {
title: '潮流品牌,逛各种潮流品牌资讯-YOHO!BUY 有货网',
title: '潮流品牌_潮流资讯-YOHO!BUY 有货',
keywords: '逛潮品,潮流潮品,潮品资讯',
description: '有货网每天提供全球最新最潮的潮流潮品文章资讯,宣传潮流商品,潮流文化,潮流品牌等信息,想更多了解学习潮流潮品资讯就来有货网!'
}, // 潮品
22: {
title: '潮流视频,欣赏最新最好玩的潮流视频-YOHO!BUY 有货网',
title: 'Buy TV潮流视频_潮流资讯-YOHO!BUY 有货',
keywords: '潮流视频,看潮流',
description: '有货网每天提供全球最新最潮最精彩的潮流视频,宣传潮流商品,潮流文化,潮流品牌等信息,想更多欣赏潮流视频就来有货网!'
} // 视频
... ...
... ... @@ -201,6 +201,9 @@ class DetailModel extends global.yoho.BaseModel {
method: 'app.resources.getSingleTemplate',
module: 'wechat',
key: 'guang_detail_wechat'
},
param: {
cache: true
}
});
}
... ... @@ -433,6 +436,9 @@ class DetailModel extends global.yoho.BaseModel {
page: params.page,
limit: params.limit || 20,
udid: params.udid
},
param: {
cache: true
}
}).then(result => {
return _.get(result, 'data.list', []);
... ... @@ -452,6 +458,9 @@ class DetailModel extends global.yoho.BaseModel {
page: 1,
limit: 1,
udid: params.udid
},
param: {
cache: true
}
}).then(result => {
return _.get(result, 'data.total', 0);
... ... @@ -470,6 +479,9 @@ class DetailModel extends global.yoho.BaseModel {
uid: params.uid,
id: params.id,
udid: params.udid
},
param: {
cache: true
}
}).then(result => {
return _.get(result, 'data', {});
... ...
... ... @@ -61,6 +61,8 @@ exports.addressJson = (req, res, next) => {
* @param next
*/
exports.addressAct = (req, res, next) => {
let saveAndUse = req.query.refer === 'shopping' || req.query.refer === 'buynow';
req.ctx(addressModel).address({
id: req.query.id ? req.query.id : null,
uid: req.user.uid
... ... @@ -75,7 +77,8 @@ exports.addressAct = (req, res, next) => {
navBtn: false,
backUrl: false
}),
title: result && result.navTitle
title: result && result.navTitle,
saveAndUse: saveAndUse
};
res.render('address/address-act', Object.assign(responseData, result));
... ... @@ -100,8 +103,6 @@ exports.newGetAddress = (req, res, next) => {
* @param next
*/
exports.saveAddress = (req, res, next) => {
/* 没有用户,返回 */
if (!req.user.uid) {
return res.json({
code: 400,
... ... @@ -109,7 +110,6 @@ exports.saveAddress = (req, res, next) => {
});
}
/* 没有地址信息,返回 */
if (!req.body.address) {
return res.json({
code: 401,
... ... @@ -117,7 +117,6 @@ exports.saveAddress = (req, res, next) => {
});
}
/* 没有地区码,返回 */
if (!req.body.area_code) {
return res.json({
code: 402,
... ... @@ -125,7 +124,6 @@ exports.saveAddress = (req, res, next) => {
});
}
/* 没有收件人姓名,返回 */
if (!req.body.consignee) {
return res.json({
code: 403,
... ... @@ -133,14 +131,6 @@ exports.saveAddress = (req, res, next) => {
});
}
/* 邮箱地址校验不通过,返回 */
// if (!req.body.email || !helpers.verifyEmail(req.body.email)) {
// return res.json({
// code: 404,
// message: '输入的邮箱地址格式不正确'
// });
// }
req.ctx(addressModel).saveAddress({
uid: req.user.uid,
address: req.body.address,
... ... @@ -255,4 +245,3 @@ exports.chooseAddress = (req, res, next) => {
res.json(result);
}).catch(next);
};
... ...
... ... @@ -443,7 +443,7 @@ class familyModel extends global.yoho.BaseModel {
integralCharts(uid) {
let options = {
data: {
method: 'app.family.usercoin',
method: 'app.passport.yohofamilyCoin',
uid: uid
},
param: {
... ... @@ -463,9 +463,7 @@ class familyModel extends global.yoho.BaseModel {
return b.proportion - a.proportion;
});
if (integralData.total) {
chartsData.total = parseInt(result.data.total, 10) < 99999 ? result.data.total : '99999+';
}
chartsData.total = parseInt(result.data.total, 10) < 99999 ? result.data.total : '99999+';
_.forEach(integralData.data, function(data) {
list.push({
... ... @@ -550,12 +548,12 @@ class familyModel extends global.yoho.BaseModel {
getCoinData(params) {
let options = {
data: {
method: 'app.family.coinlog',
method: 'app.yohocoin.lists',
uid: params.uid,
source: params.source || -1,
queryType: params.queryType || 0,
beginTime: params.beginTime ? this.formatDay(parseInt(params.beginTime, 10)) : '',
endTime: params.endTime ? this.formatDay(parseInt(params.endTime, 10)) : '',
endTime: params.endTime ? this.formatDay(parseInt(params.endTime, 10) + 86400 * 1000) : '',
page: params.page || 1,
limit: params.limit || 10
},
... ... @@ -570,14 +568,15 @@ class familyModel extends global.yoho.BaseModel {
};
let _this = this;
if (_.get(result, 'data.data')) {
_.forEach(result.data.data, function(val) {
if (_.has(result, 'data.coinlist')) {
_.forEach(_.get(result, 'data.coinlist', []), function(val) {
Object.assign(val, {
typeName: _this.checkType(val.iconType),
minus: parseInt(val.num, 10) < 0
});
});
resu.coinList = result.data.data;
resu.coinList = _.get(result, 'data.coinlist', []);
}
return resu;
... ... @@ -790,7 +789,7 @@ class familyModel extends global.yoho.BaseModel {
}
if (parseInt(val.exchangeEndTime, 10) !== 0 && parseInt(val.exchangeStartTime, 10) !== 0) {
if (parseInt(Date.now(), 10) > parseInt(val.exchangeEndTime, 10) || parseInt(Date.now(), 10) < parseInt(val.exchangeStartTime, 10)) { // eslint-disable-line
if (parseInt(Date.now(), 10)/1000 > parseInt(val.exchangeEndTime, 10) || parseInt(Date.now(), 10)/1000 < parseInt(val.exchangeStartTime, 10)) { // eslint-disable-line
val.noStore = true;
}
}
... ... @@ -805,7 +804,7 @@ class familyModel extends global.yoho.BaseModel {
coinMall(params) {
let options = {
data: {
method: 'app.family.totalcoin',
method: 'app.yohocoin.total',
uid: params.uid
},
param: {
... ...
// 消息 by acgpiano
'use strict';
const _ = require('lodash');
const moment = require('moment');
const helpers = global.yoho.helpers;
... ... @@ -40,7 +41,7 @@ class messageModel extends global.yoho.BaseModel {
// name: item.body.name,
// collarTime: item.body.collar_time,
// useTime: item.body.use_time,
content: _.get(item, 'body.content', ''),
isCollar: item.body.is_collar === 'Y' ? true : false,
isOverTime: item.body.is_over_time === 'Y' ? true : false
});
... ...
... ... @@ -21,11 +21,9 @@
详细地址:
<textarea name="address" maxlength="255">{{address.address}}</textarea>
</label>
</form>
<div class="submit">
确认
保存{{#if saveAndUse}}并使用{{/if}}
</div>
</div>
<div class="my-address-list-page page-wrap hide">
... ...
<div class="coin-mall-c">
<div class="coin{{#if isNowApp}} now{{/if}}">
<span>{{coinNum}}</span>
<span>{{total}}</span>
</div>
<div class="btn-c">
<a class="acquiring-help" href='https://m.yohobuy.com/activity/feature/905.html?share_id=3111&title=YOHO!FAMILY积分说明&openby:yohobuy={"action":"go.h5","params":{"url":"https://m.yohobuy.com/activity/feature/905.html?share_id=3111&title=YOHO!FAMILY积分说明"}}'>如何获取积分</a>
... ... @@ -24,4 +24,4 @@
</div>
<div class="tip-app hide">
</div>
</div>
\ No newline at end of file
</div>
... ...
... ... @@ -7,7 +7,7 @@
{{/if}}
<p>
{{#if birthType}}
<a>亲爱的,这是我给您的生日专属礼</a>
<a>{{title}}</a>
{{else}}
<a href="//m.yohobuy.com/home/messageDetail?id={{id}}">{{title}}</a>
{{/if}}
... ... @@ -15,19 +15,7 @@
{{#if birthType}}
<div class="ticket-pic">
<img src="{{imgSrc 'img/home/employ/birth-card.png'}}" />
</div>
<div class="ticket-btn">
<div class="ticket-btn-c">
<div>
{{#if isOverTime}}
<a class="disable">已过期</a>
{{else if isCollar}}
<a class="disable">已领取</a>
{{else}}
<a href="//m.yohobuy.com/home/birthCoupon">立即领取</a>
{{/if}}
</div>
</div>
<div class="content">{{content}}</div>
</div>
{{/if}}
<span>{{time}}</span>
... ...
... ... @@ -68,11 +68,11 @@
{{/realAmount}}
</ul>
{{/orderAmountInfo}}
{{#if yohoGiveCoin}}
{{#if orderExtInfo.yohoGiveCoin}}
<p class="dollar">
<span class="bg-dollar"></span>
共返YOHO币:
<span>{{yohoGiveCoin}}</span>
<span>{{orderExtInfo.yohoGiveCoin}}</span>
</p>
{{/if}}
... ... @@ -117,7 +117,7 @@
{{> order-detail/refund-change-mask}}
{{#if orderBasicInfo}}
<div class="info-table">
{{#orderBasicInfo}}
<div class="table-item">{{key}}{{value}}</div>
... ...
... ... @@ -26,6 +26,10 @@ exports.index = (req, res, next) => {
fuzzyWord: list.fuzzyWord
};
if (!list || !list.fuzzyWord.length) {
return next();
}
return res.render('chanpin', Object.assign({
css: yield css('chanpin.css'),
title: `${goodsList.name}价格_图片_品牌_怎么样-YOHO!BUY有货`,
... ...
'use strict';
const css = require('../css');
const mRoot = '../models';
const listModel = require(`${mRoot}/hot`);
const co = require('bluebird').coroutine;
exports.index = (req, res, next) => {
co(function* () {
let params = {
page: 1,
limit: 100,
sales: 'Y',
outlets: 2,
stocknumber: 1,
need_filter: 'no',
type: 'default',
order: 's_t_desc',
id: req.params.id
};
let list = yield req.ctx(listModel).index(params);
let goodsList = {
name: list.name || '',
list: list.list,
fuzzyWord: list.fuzzyWord
};
if (!list || !list.fuzzyWord.length) {
return next();
}
return res.render('hot', Object.assign({
css: yield css('chanpin.css'),
title: `${goodsList.name}价格_图片_品牌_怎么样-YOHO!BUY有货`,
mipUrl: `https://m.yohobuy.com${req.originalUrl}`,
mipFooter: true,
canonical: {
currentHref: `https://www.yohobuy.com/hot/${req.params.id}.html`
}
}, goodsList));
})().catch(next);
};
... ...
... ... @@ -167,6 +167,8 @@ class DetailModel extends global.yoho.BaseModel {
method: 'app.resources.getSingleTemplate',
module: 'wechat',
key: 'guang_detail_wechat'
}, {
cache: true
});
}
... ...
'use strict';
const utils = '../../../utils';
const redis = require(`${utils}/redis`);
const _ = require('lodash');
const helpers = global.yoho.helpers;
const camelCase = global.yoho.camelCase;
class Hot extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
}
list(params) {
let options = {
data: {
method: 'web.search.forseo',
sales: params.sales,
outlets: params.outlets,
stocknumber: params.stocknumber,
need_filter: params.need_filter,
query: params.query,
type: params.type,
page: params.page || 1,
limit: params.limit || 24,
order: params.order || 0
},
param: {
code: 200
}
};
return this.get(options).then(result => {
return result;
});
}
getSearchKeywordDataById(params) {
return redis.all([
['get', `global:yoho:seo:hot:keywords:id:${params.id}`]
]).then(redisData => {
return redisData;
});
}
index(params) {
return Promise.all([
this.getSearchKeywordDataById(params),
]).then(result => {
let resu = {
list: [],
fuzzyWord: []
};
if (_.get(result, '[0][0]')) {
let build = [];
let redisData = JSON.parse(result[0][0]);
return this.list(Object.assign(params, {query: redisData.name})).then(listData => {
_.forEach(_.slice(redisData.data, 0, 12), value => {
build.push({
name: value.keyword,
link: helpers.urlFormat(`/mip/hot/${value.id}.html`, null)
});
});
resu.name = redisData.name;
resu.fuzzyWord = build;
if (_.get(listData, 'data.product_list')) {
resu.list = camelCase(listData.data.product_list);
_.forEach(resu.list, value => {
value.isSoonSoldOut = value.isSoonSoldOut === 'Y';
});
}
return resu;
});
} else {
return resu;
}
});
}
}
module.exports = Hot;
... ...
... ... @@ -13,6 +13,7 @@ const rewrite = require('../../doraemon/middleware/rewrite');
const mip = require('../../doraemon/middleware/mip');
const guang = require(`${cRoot}/guang`);
const chanpin = require(`${cRoot}/chanpin`);
const hot = require(`${cRoot}/hot`);
const productDetail = require(`${cRoot}/product-detail`);
router.use(mip);
... ... @@ -25,4 +26,6 @@ router.get('/list/:id.html', chanpin.redirect);
router.get('/product/:skn.html', productDetail.index);
router.get('/hot/:id.html', hot.index);
module.exports = router;
... ...
<div class="good-list-page search-page yoho-page">
{{> chanpin}}
{{> mip-product-list}}
{{> mip-footer}}
</div>
... ...
<div class="good-list-page search-page yoho-page">
{{> mip-product-list}}
{{> mip-footer}}
</div>
... ...
... ... @@ -19,7 +19,7 @@ exports.index = (req, res, next) => {
}
return res.render('news-index', Object.assign({
title: '资讯 | ' + (res.locals.title || ''),
title: '资讯_潮流资讯-YOHO!BUY 有货',
pageHeader: headerModel.setNav({
navTitle: '资讯'
}),
... ...
... ... @@ -11,7 +11,6 @@ const passport = require('passport');
const uuid = require('uuid');
const url = require('url');
const moment = require('moment');
const co = Promise.coroutine;
const cookie = global.yoho.cookie;
const helpers = global.yoho.helpers;
const log = global.yoho.logger;
... ... @@ -547,46 +546,6 @@ exports.user = function(req, res, next) {
res.jsonp(result);
};
/**
* 中间件
* 根据用户登录是否成功决定是否展示验证码
*/
exports.loginShowCaptchaByIp = function(req, res, next) {
// 总开关状态
req.yoho.captchaShow = !_.get(req.app.locals.wap, 'close.loginValidation', false);
// 开关打开,不走任何验证逻辑
if (!req.yoho.captchaShow) {
return next();
} else {
req.yoho.captchaShow = false;
}
// 第一次登录要不要展示验证码:后台开关勾选,首次登录不需要展示
let firstLoginShowCaptcha = !_.get(req.app.locals.wap, 'close.firstLoginShowCaptcha', false);
log.info(`firstLoginShowCaptcha status is ${firstLoginShowCaptcha}`);
if (firstLoginShowCaptcha) {
req.yoho.captchaShow = true;
return next();
} else {
co(function* () {
let hasErrorLog = yield cache.get(`loginErrorIp:${req.yoho.clientIp}`);
log.info(`Pagerender clientip ${req.yoho.clientIp} status is ` + hasErrorLog);
if (hasErrorLog) {
req.yoho.captchaShow = true;
}
next();
})().catch(function(e) {
req.yoho.captchaShow = true;
next();
});
}
};
exports.common = common;
exports.local = local;
exports.wechat = wechat;
... ...
... ... @@ -184,7 +184,6 @@ router.get('/login.html',
login.common.clearCookie,
validateCode.load,
login.common.beforeLogin,
login.loginShowCaptchaByIp,
loginNew.international); // 国际账号登录
router.get('/passport/back/mobile', validateCode.load, back.backByMobile); // 通过手机找回密码
... ...
<div class="back-email-new-page">
<div class="top-operation-bar">
<button class="back iconfont" onclick="javascript:history.go(-1);">&#xe72e;</button>
<button class="back iconfont" onclick="javascript:history.go(-1);" type="button">&#xe72e;</button>
<span class="page-title">邮箱找回密码</span>
</div>
<div class="back-email-form">
<form class="back-email-form">
<div class="form-group email">
<label for="email" class="iconfont">&#xe724;</label><input type="text" name="email" placeholder="请输入邮箱"><i id="clearEmail" class="iconfont clear hide">&#xe72a;</i>
</div>
<button id="backEmailResetBtn" class="back-email-reset-btn">确 认</button>
</div>
<button id="backEmailResetBtn" class="back-email-reset-btn" type="button">确 认</button>
</form>
</div>
... ...
<div class="back-mobile-new-page">
<div class="top-operation-bar">
<button class="back iconfont" onclick="javascript:history.go(-1);">&#xe72e;</button>
<button class="back iconfont" onclick="javascript:history.go(-1);" type="button">&#xe72e;</button>
<span class="page-title">手机找回密码</span>
</div>
<div class="back-mobile-form">
<form class="back-mobile-form">
<div class="form-group mobile">
<label for="mobile" class="iconfont">&#xe727;</label>
<select name="" id="countryCodeSelector" class="country-select">
... ... @@ -16,12 +16,12 @@
class="iconfont clear hide">&#xe72a;</i>
</div>
<div class="form-group verify-code">
<label for="verifyCode" class="iconfont">&#xe71c;</label><input type="text" name="verifyCode" placeholder="请输入验证码" class="verify-code-input"><button id="getVerifyCodeBtn" class="get-verify-code">获取验证码</button>
<label for="verifyCode" class="iconfont">&#xe71c;</label><input type="text" name="verifyCode" placeholder="请输入验证码" class="verify-code-input"><button id="getVerifyCodeBtn" class="get-verify-code" type="button">获取验证码</button>
</div>
<div class="form-group password">
<label for="password" class="iconfont">&#xe723;</label><input type="password" name="password" placeholder="请重置新密码"><span id="passwordEyeIcon" class="eye"><i class="iconfont eye-close">&#xe716;</i><i class="iconfont eye-open hide">&#xe714;</i></span>
</div>
<div data-userverify="{{captchaShow}}" data-geetest="{{useGeetest}}" id="js-img-check" {{#unless useGeetest}} class="full-img-verify" {{/unless}}></div>
<button id="backMobileResetBtn" class="back-mobile-reset-btn">重置登录密码</button>
</div>
</div>
\ No newline at end of file
<button id="backMobileResetBtn" class="back-mobile-reset-btn" type="button">重置登录密码</button>
</form>
</div>
... ...
<div class="international-new-page">
<div class="top-operation-bar">
<button class="back iconfont" onclick="javascript:history.go(-1);">&#xe72e;</button>
<button class="back iconfont" onclick="javascript:history.go(-1);" type="button">&#xe72e;</button>
<span class="page-title">海外账号登录</span>
</div>
<div class="international-form">
<form class="international-form">
<div class="form-group mobile">
<label for="mobile" class="iconfont">&#xe727;</label>
<select name="" id="countryCodeSelector" class="country-select">
... ... @@ -21,6 +21,6 @@
id="passwordEyeIcon" class="eye"><i class="iconfont eye-close">&#xe716;</i><i class="iconfont eye-open hide">&#xe714;</i></span>
</div>
<div data-userverify="{{captchaShow}}" data-geetest="{{useGeetest}}" id="js-img-check" {{#unless useGeetest}} class="full-img-verify" {{/unless}}></div>
<button id="internationalLoginBtn" class="international-login-btn">登录</button>
</div>
</div>
\ No newline at end of file
<button id="internationalLoginBtn" class="international-login-btn" type="button">登录</button>
</form>
</div>
... ...
... ... @@ -3,13 +3,13 @@
<img src="{{image2 banner w=750 h=290}}">
<div class="banner-info">
<div class="top-operation-bar">
<button class="close iconfont" onclick="location.href='{{backUrl}}'">&#xe72e;</button>
<button class="close iconfont" onclick="location.href='{{backUrl}}'" type="button">&#xe72e;</button>
<a href="{{registerUrl}}" class="register">注册</a>
</div>
<div class="tip">Yoho!Family账号可登录Yoho!Buy有货 <i id="showYohoFamilyTip" class="iconfont">&#xe639;</i></div>
</div>
</div>
<div class="login-form">
<form class="login-form">
<div class="form-group username">
<label for="username" class="iconfont">&#xe727;</label><input type="text" name="username" placeholder="请输入手机号/邮箱">
<i id="clearUsrname" class="iconfont clear hide">&#xe72a;</i>
... ... @@ -19,13 +19,13 @@
<span id="passwordEyeIcon" class="eye"><i class="iconfont eye-close">&#xe716;</i><i class="iconfont eye-open hide">&#xe714;</i></span>
</div>
<div data-userverify="{{captchaShow}}" data-geetest="{{useGeetest}}" id="js-img-check" {{#unless useGeetest}} class="full-img-verify" {{/unless}}></div>
<button id="loginBtn" class="login-btn disable">登录</button>
<button id="loginBtn" class="login-btn disable" type="button">登录</button>
<div class="other-info">
<a href="{{internationalUrl}}">海外账号登录</a>
<a href="{{smsLoginUrl}}">手机验证码登录</a>
<a id="getPswrdBtn" href="javascript:void(0);">忘记密码?</a>
</div>
</div>
</form>
{{!-- <div class="third-party-login">
<div class="tip-box">
<span class="left-line"></span>
... ...
<div class="reg-new-page">
<div class="top-operation-bar">
<button class="back iconfont" onclick="javascript:history.go(-1);">&#xe72e;</button>
<button class="back iconfont" onclick="javascript:history.go(-1);" type="button">&#xe72e;</button>
<span class="page-title">注册</span>
</div>
<div class="reg-form">
<form class="reg-form">
<div class="form-group mobile">
<label for="mobile" class="iconfont">&#xe727;</label>
<select name="" id="countryCodeSelector" class="country-select">
... ... @@ -17,7 +17,7 @@
</div>
<div class="form-group verify-code">
<label for="verifyCode" class="iconfont">&#xe71c;</label><input type="text" name="verifyCode" placeholder="请输入验证码"
class="verify-code-input" autocomplete="off"><button id="getVerifyCodeBtn" class="get-verify-code">获取验证码</button>
class="verify-code-input" autocomplete="off"><button id="getVerifyCodeBtn" class="get-verify-code" type="button">获取验证码</button>
</div>
<div class="form-group password">
<label for="password" class="iconfont">&#xe723;</label><input type="password" name="password" placeholder="请输入密码" autocomplete="off">
... ... @@ -29,10 +29,10 @@
</div>
<input name="token" type="hidden" value="{{token}}">
<div data-userverify="{{captchaShow}}" data-geetest="{{useGeetest}}" id="js-img-check"{{#unless useGeetest}} class="full-img-verify"{{/unless}}></div>
<button id="regBtn" class="reg-btn">注册</button>
<button id="regBtn" class="reg-btn" type="button">注册</button>
<div class="protocol">
<span class="iconfont checkbox icon-cb-radio"></span>
我已阅读并同意遵守<a href="/service/qaDetail?keyword=服务条款&sonId=197" title="Yoho!Buy有货服务条款" target="_blank">Yoho!Buy有货服务条款</a>
</div>
</div>
</div>
\ No newline at end of file
</form>
</div>
... ...
... ... @@ -3,13 +3,13 @@
<img src="{{image2 banner w=750 h=290}}">
<div class="banner-info">
<div class="top-operation-bar">
<button class="close iconfont" onclick="location.href='{{backUrl}}'">&#xe72e;</button>
<button class="close iconfont" onclick="location.href='{{backUrl}}'" type="button">&#xe72e;</button>
<a href="{{registerUrl}}" class="register">注册</a>
</div>
<div class="tip">Yoho!Family账号可登录Yoho!Buy有货 <i id="showYohoFamilyTip" class="iconfont">&#xe639;</i></div>
</div>
</div>
<div class="sms-login-form">
<form class="sms-login-form">
<div class="form-group mobile">
<label for="mobile" class="iconfont">&#xe727;</label>
<select name="" id="countryCodeSelector" class="country-select">
... ... @@ -23,10 +23,10 @@
</div>
<div class="form-group verify-code">
<label for="verifyCode" class="iconfont">&#xe71c;</label><input type="text" name="verifyCode" placeholder="请输入验证码"
class="verify-code-input"><button id="getVerifyCodeBtn" class="get-verify-code">获取验证码</button>
class="verify-code-input"><button id="getVerifyCodeBtn" class="get-verify-code" type="button">获取验证码</button>
</div>
<div data-userverify="{{captchaShow}}" data-geetest="{{useGeetest}}" id="js-img-check" {{#unless useGeetest}} class="full-img-verify" {{/unless}}></div>
<button id="smsLoginBtn" class="sms-login-btn">登录</button>
<button id="smsLoginBtn" class="sms-login-btn" type="button">登录</button>
<div class="other-info">
{{#if openPassword}}
<a href="{{internationalUrl}}">海外账号登录</a>
... ... @@ -34,7 +34,7 @@
{{/if}}
<a id="getPswrdBtn" href="javascript:void(0);">忘记密码?</a>
</div>
</div>
</form>
{{!-- <div class="third-party-login">
<div class="tip-box">
<span class="left-line"></span>
... ...
... ... @@ -15,7 +15,7 @@ const bundleModel = require(`${mRoot}/bundle`);
* @param next
*/
exports.detail = (req, res, next) => {
bundleModel.detail(req.query, req.yoho.isApp).then(result => {
req.ctx(bundleModel).detail(req.query, req.yoho.isApp).then(result => {
if (!result.bundleDatas) {
return next();
}
... ... @@ -40,7 +40,7 @@ exports.detail = (req, res, next) => {
exports.addToCart = (req, res, next) => {
let shoppingKey = req.cookies._SPK || '';
bundleModel.addToCart({
req.ctx(bundleModel).addToCart({
uid: req.user.uid,
activity_id: req.body.activity_id,
product_sku_list: req.body.product_sku_list,
... ...
... ... @@ -217,82 +217,6 @@ const shopFav = (req, res) => {
};
/**
* 旧版品类落地页
* TODO 已重构为 listNew 待删除
*/
const category = (req, res, next) => {
if (req.query) {
_.forEach(req.query, (perParam, index) => {
req.query[index] = stringProcess.paramsFilter(perParam);
});
}
let params = Object.assign({}, req.query);
let seoTitle;
if (req.query.title || req.query.sort_name) {
seoTitle = stringProcess.decodeURIComponent(req.query.title || req.query.sort_name);
}
/* 勿修改,唤起 APP 使用 */
let appParams = Object.assign({}, req.query, {
title: req.query.title || req.query.sort_name || '',
productPool: req.query.filter_poolId,
actiontype: req.query.actiontype || '1'
});
delete appParams.filter_poolId;
let appPath = 'yohobuy://yohobuy.com/goapp?openby:yohobuy={"action":"go.list","params":' +
JSON.stringify(appParams) +
'}';
let uid = req.user.uid || 0;
// 获取第一页数据做服务端渲染
let initialData = _.assign({
gender: params.gender,
sort: parseInt(params.sort, 10) || '',
type: 'default',
order: '0',
page: 1,
limit: 24,
isApp: params.app_version
}, params);
if (uid) {
initialData.uid = uid;
}
req.ctx(searchModel).getSearchData(initialData).then((firstPageGoods) => {
res.render('search/goods-list', Object.assign({
_noLazy: true, // 首屏不使用lazyload
module: 'product',
page: 'search-list',
// canonical: {
// currentHref: 'https://www.yohobuy.com/list?' // TODO
// },
pageHeader: headerModel.setNav({
navTitle: seoTitle || '商品列表'
}),
goodList: params,
firstPageGoods: firstPageGoods || [],
suggestion: firstPageGoods.suggestion || [],
showDownloadApp: true,
pageFooter: true,
category: true,
localCss: true,
appPath: appPath,
introText: req.query.intro_text
}, searchProcess.getListSeoData({
gender: req.query.gender,
sort_name: seoTitle
})));
}).catch(next);
};
/**
* 品类落地页 SEO 友好的新路由
*/
const listNew = (req, res, next) => {
... ... @@ -670,7 +594,6 @@ const getBrandCouponsList = (req, res, next) => {
};
module.exports = {
category,
brand,
favoriteBrand,
shopIntro,
... ...
... ... @@ -58,7 +58,7 @@ const newDetail = {
JSON.stringify(appParams) +
'}';
let title = `${result.brandName}${result.sortName}${result.goodsName}|YOHO!BUY 有货`;
let title = `${result.goodsName}_${result.brandName}${result.sortName}--YOHO!BUY 有货`;
let description = result.goodsName + ' 有货网仅售' + result.goodsPrice.currentPrice + '元,购买' +
result.brandName + result.sortName + ',了解' + result.brandName + result.sortName + '商品信息就上有货网!';
... ...
... ... @@ -5,6 +5,7 @@
*/
'use strict';
const co = Promise.coroutine;
const mRoot = '../models';
const utils = '../../../utils';
const headerModel = require('../../../doraemon/models/header');
... ... @@ -24,15 +25,6 @@ const channelToAppChannel = (channel) => {
}[channel] || '1';
};
const channelSeo = (channel) => {
return {
boys: '男生',
girls: '女生',
kids: '潮童',
lifestyle: '创意生活'
}[channel] || '男生';
};
// 新品到着(blk)
const blkNewGoods = (req, res, next) => {
let params = Object.assign({
... ... @@ -81,13 +73,37 @@ const newGoods = (req, res, next) => {
// 唤起 APP 的路径
res.locals.appPath = `yohobuy://yohobuy.com/goapp?openby:yohobuy={"action":"go.new","params":${JSON.stringify(appParams)}}`;
newModel.getNewFocus(channel).then((result) => {
let seoTitle = '【潮流新品】_引领潮流_2018时尚潮流新品-YOHO!BUY 有货';
co(function* () {
let apiRequest = [
newModel.getNewFocus(channel)
];
let paramsForSeo = _.assign({}, req.query);
delete paramsForSeo.pathParams;
delete paramsForSeo[0];
delete paramsForSeo.channel;
if (!_.isEmpty(paramsForSeo)) {
apiRequest.push(newModel.filterDataApi(paramsForSeo));
}
let [result, filterResultApi] = yield Promise.all(apiRequest);
if (filterResultApi) {
let seoParams = searchProcess.getFilterValueForSeo(paramsForSeo, _.get(filterResultApi, 'data', {}));
let seoRenderData = searchProcess.getListSeoData(seoParams, true);
seoTitle = seoRenderData.title;
}
res.render('new/new', {
module: 'product',
page: 'new',
title: channelSeo(req.yoho.channel) + '新品上架,全场正品保证-YOHO!BUY 有货',
keywords: channelSeo(req.yoho.channel) + '新品,潮流新品,潮流正品',
description: channelSeo(req.yoho.channel) + '新品上架,正品网购,官方授权!全场品牌正品保证,支持货到付款。 想购买潮流商品就来YOHO! 有货中国大型潮流商品购物网站。', // eslint-disable-line
title: seoTitle,
keywords: '潮流新品.引领潮流,2018时尚潮流新品',
description: '【潮流新品】,2018时尚潮流新品,潮流网购就上YOHO!BUY有货,有货网销售正品新款,全场低至4折,★全场品牌正品保证,支持货到付款!★', // eslint-disable-line
pageHeader: headerModel.setNav({
navTitle: '新品到着'
}),
... ... @@ -104,7 +120,7 @@ const newGoods = (req, res, next) => {
pageFooter: true,
showDownloadApp: true
});
}).catch(next);
})().catch(next);
};
// 301到新路由
... ...
... ... @@ -4,95 +4,103 @@
'use strict';
const utils = '../../../utils';
const _ = require('lodash');
const api = global.yoho.API;
const helpers = global.yoho.helpers;
const productProcess = require(`${utils}/product-process`);
/**
* 从接口获取套装数据
* @private
*/
const getBundleBySkn = (productSkn) => {
return api.get('', {
method: 'app.query.bundleSkn',
product_skn: productSkn
}, {cache: false}).then(result => {
return result;
});
};
/**
* 套装详情页数据
* @param params
* @returns {*}
*/
const detail = (params, isApp) => {
if (!params.skn && !params.bundle_skn) {
return Promise.resolve({});
class bundleModel extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
}
let bundleIndex = (params.index || 1);
--bundleIndex;
return getBundleBySkn(params.skn || params.bundle_skn).then(result => {
if (_.has(result, `data[${bundleIndex}]`)) {
let shareInfo = _.get(result, 'data[0].shareInfo', {});
return {
bundleDatas: _.map(result.data, (bundle, index) => {
let query = {bundle_skn: params.skn ||
params.bundle_skn, productId: params.productId, index: index + 1};
/**
* 从接口获取套装数据
* @private
*/
getBundleBySkn(productSkn) {
return this.get({
data: {
method: 'app.query.bundleSkn',
product_skn: productSkn
},
param: {cache: false}
}).then(result => {
return result;
});
}
if (isApp) {
query.app_version = isApp;
}
return {
selected: index === bundleIndex,
title: _.get(bundle, 'bundleInfo.tabName') || '',
href: helpers.urlFormat('/product/bundle/detail', query),
};
}),
shareInfo: {
imgUrl: `http:${helpers.image(shareInfo.imgUrl, 300, 300)}`,
subTitle: encodeURIComponent(shareInfo.subTitle),
title: encodeURIComponent(shareInfo.title),
url: shareInfo.url
},
bundleInfo: _.get(result, `data[${bundleIndex}].bundleInfo`, {}),
productList: productProcess.processProductList(_.get(result, `data[${bundleIndex}].productList`, []))
};
/**
* 套装详情页数据
* @param params
* @returns {*}
*/
detail(params, isApp) {
if (!params.skn && !params.bundle_skn) {
return Promise.resolve({});
}
return {};
});
};
let bundleIndex = (params.index || 1);
/**
* 套餐加入购物车
* @param {*} params
*/
const addToCart = (params) => {
let skuList = params.product_sku_list;
let finalParams = {
method: 'app.Shopping.addBundle',
shopping_key: params.shopping_key,
activity_id: params.activity_id,
product_sku_list: skuList
};
--bundleIndex;
return this.getBundleBySkn(params.skn || params.bundle_skn).then(result => {
if (_.has(result, `data[${bundleIndex}]`)) {
let shareInfo = _.get(result, 'data[0].shareInfo', {});
if (params.uid) {
Object.assign(finalParams, {
uid: params.uid
return {
bundleDatas: _.map(result.data, (bundle, index) => {
let query = {bundle_skn: params.skn ||
params.bundle_skn, productId: params.productId, index: index + 1};
if (isApp) {
query.app_version = isApp;
}
return {
selected: index === bundleIndex,
title: _.get(bundle, 'bundleInfo.tabName') || '',
href: helpers.urlFormat('/product/bundle/detail', query),
};
}),
shareInfo: {
imgUrl: `http:${helpers.image(shareInfo.imgUrl, 300, 300)}`,
subTitle: encodeURIComponent(shareInfo.subTitle),
title: encodeURIComponent(shareInfo.title),
url: shareInfo.url
},
bundleInfo: _.get(result, `data[${bundleIndex}].bundleInfo`, {}),
productList: productProcess.processProductList(
_.get(result, `data[${bundleIndex}].productList`, []))
};
}
return {};
});
}
return api.post('', finalParams, {
headers: {
'User-Agent': params.userAgent
/**
* 套餐加入购物车
* @param {*} params
*/
addToCart(params) {
let skuList = params.product_sku_list;
let finalParams = {
method: 'app.Shopping.addBundle',
shopping_key: params.shopping_key,
activity_id: params.activity_id,
product_sku_list: skuList
};
if (params.uid) {
Object.assign(finalParams, {
uid: params.uid
});
}
});
};
module.exports = {
getBundleBySkn,
detail,
addToCart
};
return this.post({
data: finalParams,
param: {
headers: {
'User-Agent': params.userAgent
}
}
});
}
}
module.exports = bundleModel;
... ...
... ... @@ -241,7 +241,7 @@ module.exports = class extends global.yoho.BaseModel {
}),
this._getCommonConsult(), // eslint-disable-line
comment.getConsults(result.product_id, 1, 2),
bundle.getBundleBySkn(result.product_skn)
this.ctx.req.ctx(bundle).getBundleBySkn(result.product_skn)
]).then((info) => {
finalResult = _detailDataPkg(result, data.ua); // eslint-disable-line
finalResult.enterStore = info[0];
... ... @@ -256,7 +256,7 @@ module.exports = class extends global.yoho.BaseModel {
href: helpers.urlFormat('/product/bundle/detail',
{skn: result.product_skn, id: result.product_id}),
description: '立省¥' + (parseInt(_.get(bundleData, 'bundleInfo.salesPrice', 0), 10) -
parseInt(_.get(bundleData, 'bundleInfo.discountPrice', 0), 10)) + '元',
parseInt(_.get(bundleData, 'bundleInfo.discountPrice', 0), 10)) + '元',
productList: productProcess.processProductList(bundleData && bundleData.productList)
};
}
... ... @@ -614,7 +614,7 @@ module.exports = class extends global.yoho.BaseModel {
dest = this._procShowStatus(dest, showStatus, isBeginSale);
dest.cartInfo.limitProductCode = origin.limitProductCode;
dest.cartInfo.limitCodeUrl = this._getLimitCodeUrl(origin.limitProductCode, origin.product_skn, ua); // eslint-disable-line
dest.cartInfo.limitCodeUrl = this._getLimitCodeUrl(origin.limitProductCode, origin.product_skn, ua); // eslint-disable-line
dest.cartInfo.limitProductPay = helpers.urlFormat('/cart/index/orderEnsure');
return resolve(dest);
} else {
... ... @@ -631,14 +631,14 @@ module.exports = class extends global.yoho.BaseModel {
});
dest.showBuyNow = true;
dest.cartInfo.addToCartUrl = helpers.urlFormat('/product/buy_' + origin.product_id + '_' +
origin.goods_id + '.html');
origin.goods_id + '.html');
} else { // 除了上面商品之外的普通商品
Object.assign(dest.cartInfo, cartInfo, {
price: dest.goodsPrice.previousPrice ? dest.goodsPrice.previousPrice : '',
salePrice: dest.goodsPrice.currentPrice ? dest.goodsPrice.currentPrice : '',
});
dest.cartInfo.addToCartUrl = helpers.urlFormat('/product/buy_' + origin.product_id + '_' +
origin.goods_id + '.html');
origin.goods_id + '.html');
}
return resolve(dest);
}).then(result => {
... ... @@ -728,7 +728,7 @@ module.exports = class extends global.yoho.BaseModel {
];
if (data.bundleType) {
apiArray.push(bundle.getBundleBySkn(data.productSkn));
apiArray.push(this.ctx.req.ctx(bundle).getBundleBySkn(data.productSkn));
}
return Promise.all(apiArray).then((res) => {
... ... @@ -775,6 +775,11 @@ module.exports = class extends global.yoho.BaseModel {
};
}
finalResult.promYohoCoinText =
productProcess.procPromYohoCoin(_.get(result,
'vip_return_coin.max_return_coin_info', []),
params.current_vip_level);
// 2017电子门票不显示区域
// let ticketsProps = finalResult.cartInfo.props;
... ...
... ... @@ -78,6 +78,8 @@ module.exports = class extends global.yoho.BaseModel {
});
finalResult.recommendKeywords = recomdKeywords;
finalResult.vip_return_coin_info =
detailProcess.processPromYohoCoin(_.get(result, 'data.vip_return_coin.vip_return_coin_info', []));
return finalResult;
});
... ... @@ -91,8 +93,8 @@ module.exports = class extends global.yoho.BaseModel {
}
/*
获取 促销,评论,咨询,品牌信息
*/
获取 促销,评论,咨询,品牌信息
*/
querySknData(params) {
let brandId = params.brandId;
let shopId = params.shopId;
... ... @@ -110,11 +112,10 @@ module.exports = class extends global.yoho.BaseModel {
];
if (params.bundleType) {
apiArray.push(bundle.getBundleBySkn(skn));
apiArray.push(this.ctx.req.ctx(bundle).getBundleBySkn(skn));
}
return Promise.all(apiArray).then(info => {
// console.log(info);
let finalResult = {
promotion: null,
enterStore: null,
... ... @@ -152,8 +153,8 @@ module.exports = class extends global.yoho.BaseModel {
// ------------------------------接口
/*
接口: 根据BrandID, 查询品牌信息
*/
接口: 根据BrandID, 查询品牌信息
*/
queryShopsByBrandId(brandId, shopId) {
let params = {
method: 'app.product.queryShopsInfoById',
... ... @@ -168,14 +169,12 @@ module.exports = class extends global.yoho.BaseModel {
return this.get({
data: params,
param: cacheConf
})
.then(result => {
// console.log(result);
if (result && result.code === 200) {
return detailProcess.processShopsInfo(result.data);
}
return [];
}, () => []);
}).then(result => {
if (result && result.code === 200) {
return detailProcess.processShopsInfo(result.data);
}
return [];
}, () => []);
}
/**
... ... @@ -194,14 +193,12 @@ module.exports = class extends global.yoho.BaseModel {
return this.get({
data: params,
param: cacheConf
})
.then(result => {
// console.log(result);
if (result && result.code === 200) {
return result.data;
}
}).then(result => {
if (result && result.code === 200) {
return result.data;
}
return {};
});
return {};
});
}
};
... ...
... ... @@ -239,5 +239,6 @@ module.exports = {
indexData,
recbrand,
reclist,
reclistFilter
reclistFilter,
filterDataApi: _searchGoods
};
... ...
... ... @@ -155,9 +155,6 @@ router.get('/search/shop/goods', search.searchShopGoods); // 搜索店铺下的
router.get('/list/global(/:pathParams)?', rewrite.resolvePathParams, globalPro.list); // 全球购路由重写 全球购列表页
router.get('/index/index', rewrite.sortParams, list.category); // 旧 品类首页
router.get('/list/index', rewrite.sortParams, list.category); // 旧 兼容 PC 的链接
router.get('/list(/:pathParams)?', rewrite.resolvePathParams, list.listNew); // 列表新的 URL
router.get('/search/category',
cors,
... ...
... ... @@ -74,6 +74,9 @@
<div id="placeholder-promotion" style="height:100px;background-color:#fff;">
</div>
{{!--占位: 有货币促销--}}
<div id="placeholder-promotion-yohocoin"></div>
{{!-- 占位: 用户反馈, 店铺入口 --}}
<div id="placeholder-feedback-store"></div>
... ... @@ -139,4 +142,17 @@
{{> common/suspend-home}}
</div>
{{#if vip_return_coin_info}}
<div class="coin-intro-box hide">
<div class="coin-intro">
<ul class="coin-ul">
{{#vip_return_coin_info}}
<li class="coin-li"><span class="vip-img">
</span>{{{title}}}</li>
{{/vip_return_coin_info}}
</ul>
<div class="tip">页面展示有货币为预计结果,因为页面缓存等原因可能有出入,最终返还结果以结算提示为准</div>
</div>
</div>
{{/if}}
{{/ result}}
... ...
... ... @@ -13,21 +13,22 @@ const isTest = process.env.NODE_ENV === 'test';
const domains = {
api: 'http://api.yoho.cn/',
service: 'http://service.yoho.cn/',
liveApi: 'http://testapi.live.yohops.com:9999/',
singleApi: 'http://api-test3.yohops.com:9999/',
// api: 'http://api.yoho.cn/',
// service: 'http://service.yoho.cn/',
// liveApi: 'http://testapi.live.yohops.com:9999/',
// singleApi: 'http://api-test3.yohops.com:9999/',
// gray
// api: 'http://apigray.yoho.cn/',
// service: 'http://apigray.yoho.cn/',
// platformApi: 'http://172.16.6.210:8088/',
// api: 'http://api-test3.yohops.com:9999/',
// service: 'http://service-test3.yohops.com:9999/',
// liveApi: 'http://testapi.live.yohops.com:9999/',
// singleApi: 'http://api-test3.yohops.com:9999/',
api: 'http://api-test3.yohops.com:9999/',
service: 'http://service-test3.yohops.com:9999/',
liveApi: 'http://testapi.live.yohops.com:9999/',
singleApi: 'http://api-test3.yohops.com:9999/',
imSocket: 'ws://socket.yohobuy.com:10240',
imCs: 'http://im.yohobuy.com/api',
... ...
... ... @@ -68,6 +68,12 @@ const liveContentCode = {
index: '345c80537dca15611f37ae4863004bfe'
};
// 个性化推荐
const tideContentCode = {
category: 'f5fccd93c21f740d7dd4a39aa938ee01', // 潮品类推介
brand: 'cfae8d475468b3109115d1c45596e155', // 潮品牌推介
};
module.exports = {
sale: saleContentCode,
outlet: outletContentCode,
... ... @@ -76,5 +82,6 @@ module.exports = {
guang: guangContentCode,
new: newContentCode, // TODO: remove
newV2: newContentCodeV2,
live: liveContentCode
live: liveContentCode,
tide: tideContentCode
};
... ...
... ... @@ -8,4 +8,4 @@ yarn build
else
npm i --production
fi
tar -czvf yoho-yohobuy-wap.tar.gz *
tar -czf yoho-yohobuy-wap.tar.gz *
... ...
... ... @@ -106,6 +106,11 @@ exports.serverError = () => {
err.code = err.code || err.statusCode || 500;
if (!err.type === 'entity.parse.failed') { // json 解析失败不上报错误
logger.error(`error at path: ${req.url}`);
logger.error(err);
}
if (req.isApmReport && err.code !== 401) {
// 上报服务端错误
sender.addMessage({
... ... @@ -186,9 +191,6 @@ exports.serverError = () => {
return _err510(req, res, 510, err);
}
logger.error(`error at path: ${req.url}`);
logger.error(err);
if (!res.headersSent) {
return _err500(req, res, err.code, err);
}
... ...
... ... @@ -4,7 +4,9 @@ const _ = require('lodash');
const logger = global.yoho.logger;
const ip = require('./rules/ip-list');
const userAgent = require('./rules/useragent');
const ipWhiteList = require('./rules/ip-white-list');
const qpsLimiter = require('./rules/qps-limit');
const co = Promise.coroutine;
// const asynchronous = require('./rules/asynchronous');
// const fakerLimiter = require('./rules/faker-limit');
... ... @@ -13,16 +15,23 @@ const captchaPolicy = require('./policies/captcha');
// const reporterPolicy = require('./policies/reporter');
const IP_WHITE_LIST = [
'106.38.38.146',
'106.38.38.147',
'106.39.86.227',
'218.94.75.58',
'218.94.75.50',
'218.94.77.166',
'10.66.70.21', // 联盟 生产 IP
'222.73.196.18' // B站合作方单击次数快加白名单
'106.38.38.146', // 北京办公区域
'106.38.38.147', // 北京办公区域
'106.39.86.227', // 北京办公区域
'218.94.75.58', // 南京办公区域
'218.94.75.50', // 南京办公区域
'218.94.77.166', // 南京办公区域
// '222.73.196.18', // B站合作方单击次数快加白名单
'123.206.73.107', // 腾讯云出口IP
'139.199.35.21', // 腾讯云出口IP
'139.199.29.44', // 腾讯云出口IP
'123.206.21.19' // 腾讯云出口IP
];
const IP_WHITE_SEGMENT = [
'10.66.', // 内网IP段
'192.168.' // 内网IP段
];
const PATH_WHITE_LIST = [
'/3party/check',
'/3party/check/submit',
... ... @@ -53,18 +62,44 @@ const limiter = (rule, policy, context) => {
return rule(context, policy);
};
module.exports = (req, res, next) => {
// 排除条件:ip白名单/路径白名单/异步请求/登录用户
const _excluded = (req) => {
let remoteIp = req.yoho.clientIp || '';
let remoteIpSegment = `${remoteIp.split('.').slice(0, 2).join('.')}.`;
return co(function* () {
let atWhiteList = yield ipWhiteList(remoteIp);
return Boolean(
atWhiteList ||
_.includes(IP_WHITE_LIST, remoteIp) ||
_.includes(IP_WHITE_SEGMENT, remoteIpSegment) ||
_.includes(PATH_WHITE_LIST, req.path) ||
req.xhr ||
!_.isEmpty(_.get(req, 'user.uid'))
);
})();
};
// 排除条件:ip白名单/路径白名单/异步请求/登录用户
const excluded = _.includes(IP_WHITE_LIST, remoteIp) ||
_.includes(PATH_WHITE_LIST, req.path) || req.xhr || !_.isEmpty(_.get(req, 'user.uid'));
module.exports = (req, res, next) => {
const remoteIp = req.yoho.clientIp || '';
const enabled = !_.get(req.app.locals, 'wap.sys.noLimiter');
logger.debug(`request remote ip: ${remoteIp}; excluded: ${excluded}; enabled: ${enabled}`);
// 开关为关或者未获取到remoteIp,放行
if (!enabled || !remoteIp) {
logger.debug(`request remote ip: ${remoteIp}; enabled: ${enabled}`);
return next();
}
co(function* () {
let excluded = yield _excluded(req);
// 判断获取remoteIp成功,并且开关未关闭
if (enabled && remoteIp && !excluded) {
logger.debug(`request remote ip: ${remoteIp}; excluded: ${excluded}; enabled: ${enabled}`);
// 白名单,放行
if (excluded) {
return next();
}
const context = {
req: req,
res: res,
... ... @@ -72,42 +107,39 @@ module.exports = (req, res, next) => {
remoteIp: remoteIp
};
Promise.all([
let results = yield Promise.all([
limiter(userAgent, captchaPolicy, context),
limiter(ip, captchaPolicy, context),
limiter(qpsLimiter, captchaPolicy, context)
// limiter(asynchronous, captchaPolicy, context)
// limiter(fakerLimiter, reporterPolicy, context)
]).then((results) => {
let allPass = true, exclusion = false, policy = null;
logger.debug('limiter result: ' + JSON.stringify(results));
_.forEach(results, (result) => {
if (typeof result === 'object' && !exclusion) {
exclusion = result.exclusion;
}
if (typeof result === 'function') {
allPass = false;
policy = result;
}
});
if (exclusion) {
return next();
} else if (!allPass && policy) {
policy(req, res, next);
} else {
return next();
]);
let allPass = true, exclusion = false, policy = null;
logger.debug('limiter result: ' + JSON.stringify(results));
_.forEach(results, (result) => {
if (typeof result === 'object' && !exclusion) {
exclusion = result.exclusion;
}
}).catch((err) => {
logger.error(err);
return next();
if (typeof result === 'function') {
allPass = false;
policy = result;
}
});
} else {
if (exclusion) {
return next();
} else if (!allPass && policy) {
policy(req, res, next);
} else {
return next();
}
})().catch(err => {
logger.error(err);
return next();
}
});
};
... ...
const co = Promise.coroutine;
const logger = global.yoho.logger;
const cache = global.yoho.cache.master;
const WHITE_LIST_KEY = 'whitelist:ip:';
module.exports = (remoteIp) => {
let key = `${WHITE_LIST_KEY}${remoteIp}`;
return co(function* () {
let result = Boolean(yield cache.getAsync(key));
logger.debug(key, result);
return result;
})();
};
... ...
... ... @@ -15,8 +15,15 @@ module.exports = (limiter, policy) => {
cache.getAsync(blackKey),
cache.getAsync(whiteKey)
]).then((args) => {
const blacklist = args[0] || [],
whitelist = args[1] || [];
let blacklist = [];
let whitelist = [];
try {
blacklist = JSON.parse(args[0]);
whitelist = JSON.parse(args[1]);
} catch (error) {
logger.error(error);
}
if (blacklist.length === 0 && whitelist.length === 0) {
return Promise.resolve(true);
... ...
... ... @@ -122,6 +122,8 @@ const resolvePathParams = (req, res, next) => {
let queryParams = req.query;
let pathParams = req.params.pathParams;
pathParams = _.replace(pathParams, '.html', '');
// 1. 取 path 的参数
req.query = listParamsProcess.getParams(pathParams);
... ... @@ -149,6 +151,9 @@ const resolvePathParams = (req, res, next) => {
*/
const resolvePathParamsAjax = (req, res, next) => {
let pathParams = _.last(_.split(req.query.currentUrl, '/'));
pathParams = _.replace(pathParams, '.html', '');
let currentUrlParams = listParamsProcess.getParams(pathParams);
let queryParams = {};
... ... @@ -158,6 +163,10 @@ const resolvePathParamsAjax = (req, res, next) => {
req.query.order = currentUrlParams.order;
}
if (currentUrlParams.brand && req.query.brand === '0') {
req.query.brand = currentUrlParams.brand;
}
req.query = _.assign(queryParams, currentUrlParams, req.query);
return next();
... ...
const seoMap = {
/* eslint-disable */
'/': {
title: 'Yoho!Buy有货|年轻人潮流购物中心,中国潮流购物风向标',
keywords: 'Yoho!Buy有货 有货官网,潮流志,潮流男装,潮牌,美国潮牌,日本潮牌,香港潮牌,潮牌店,新品首发,欧美潮流,全球购,代购,时尚,流行,特卖,B2C,正品,购物网站,网上购物,货到付款',
description: 'Yoho!Buy有货,年轻人潮流购物中心,中国大型潮流商品购物网站。全场品牌正品保证,支持货到付款。'
title: 'YOHO!BUY 有货-年轻人潮流购物中心,时尚潮流购物网站',
keywords: '潮流,时尚潮流,潮流服饰,潮流购物网,潮流网站',
description: '【YOHO!BUY有货】,年轻人潮流购物中心,中国潮流商品购物网站。作为YOHO!旗下的购物平台,汇集了全球潮流时尚商品和国内流行商品,★全场品牌正品保证,支持货到付款★'
},
'/boys': {
title: '男式服饰|男装,休闲男装,时尚男装品牌|Yoho!Buy有货',
keywords: '男装,休闲男装,时尚男装品牌,男式服饰,Yoho!Buy有货',
description: 'Yoho!Buy有货男装汇集国内国际各大男装品牌,提供品牌男装、休闲男装、商务男装、外套,全场正品保证!'
title: '【潮流男装】_品牌,价格,图片,新款-YOHO!BUY 有货',
keywords: '潮流男装',
description: '潮流网购就上YOHO!BUY有货,有货网潮流男装提供潮流男装品牌、潮流男装图片等信息。销售正品新款潮流男装,全场低至4折,★全场品牌正品保证,支持货到付款!★'
},
'/girls': {
title: '潮流女装|时尚女装,日韩女装,潮牌女装全球购|Yoho!BUY有货',
keywords: '潮流女装,女生服饰,时尚潮流女装,日韩女装,女装正品购物网站,女装全球购',
description: 'Yoho!BUY有货官网女生频道汇集了全球女装潮流时尚,提供时尚潮流女装,日版女装,韩版女装,潮牌女装正品全球购,全场正品保证!'
title: '【潮流女装】_品牌,价格,图片,新款-YOHO!BUY 有货',
keywords: '潮流女装',
description: '潮流网购就上YOHO!BUY有货,有货网潮流女装提供潮流女装品牌、潮流女装图片等信息。销售正品新款潮流女装,全场低至4折,★全场品牌正品保证,支持货到付款!★'
},
'/kids': {
title: '潮童|男童装,女童装,韩版儿童服装服饰|Yoho!BUY有货',
keywords: '潮童,男童装,女童装,韩版童装,儿童服装服饰',
description: 'Yoho!BUY有货官网潮童频道汇集了全球潮童潮流时尚,提供新款男童装,女童装,韩版童装,儿童服装服饰正品全球购。'
title: '【潮流童装】_品牌,价格,图片,新款-YOHO!BUY 有货',
keywords: '潮流童装',
description: '潮流网购就上YOHO!BUY有货,有货网潮流童装提供潮流童装品牌、潮流童装图片等信息。销售正品新款潮流童装,全场低至4折,★全场品牌正品保证,支持货到付款!★'
},
'/lifestyle': {
title: '创意生活|创意生活馆,潮流创意家居,家居生活用品|Yoho!BUY有货',
keywords: '创意生活,创意生活馆,潮流家居,潮流创意家居,家居生活用品,Yoho!Buy有货',
description: 'Yoho!BUY有货官网创意生活频道提供了潮流创意家居,家居生活用品等正品网购,给您的生活带来更多创意。'
title: '【潮流生活商品】_品牌,价格,图片,新款-YOHO!BUY 有货',
keywords: '潮流创意生活商品',
description: '潮流网购就上YOHO!BUY有货,有货网潮流生活商品专卖店提供商品品牌、图片等信息。销售正品新款潮流生活商品,全场低至4折,★全场品牌正品保证,支持货到付款!★'
},
'/product/boys-sale/': {
title: '折扣男装专区|男装SALE折扣,男款鞋包配饰特卖|Yoho!Buy有货 全场正品保证',
... ...
... ... @@ -8,11 +8,11 @@
const helpers = global.yoho.helpers;
exports.getUrlData = function(type, gender) {
exports.getUrlData = function(type) {
const urlData = {
indexUrl: helpers.urlFormat('/?go=1'), // 首页
categoryUrl: helpers.urlFormat('/cate'), // 分类
guangUrl: helpers.urlFormat('/guang', gender ? {gender: gender} : null), // 逛首页
guangUrl: helpers.urlFormat('/guang'), // 逛首页
shoppingCartUrl: helpers.urlFormat('/cart/index/index'), // 购物车
mineUrl: helpers.urlFormat('/home') // 个人中心
};
... ...
... ... @@ -55,48 +55,34 @@
{{#if devEnv}}
{{#if localCss }}
<link rel="preload" as="style" href="//{{devHost}}:{{port}}/common.css?t={{startTime}}">
<link rel="stylesheet" media="all" href="//{{devHost}}:{{port}}/common.css?t={{startTime}}">
{{/if}}
{{#if isFeature}}
<link rel="preload" as="style" href="//{{devHost}}:{{port}}/feature.css?t={{startTime}}">
<link rel="stylesheet" media="all" href="//{{devHost}}:{{port}}/feature.css?t={{startTime}}">
{{else}}
{{#ifor localCss vue}}
<link rel="preload" as="style" href="//{{devHost}}:{{port}}/{{module}}.{{page}}.css?t={{startTime}}">
<link rel="stylesheet" media="all" href="//{{devHost}}:{{port}}/{{module}}.{{page}}.css?t={{startTime}}">
{{^}}
<link rel="preload" as="style" href="//{{devHost}}:{{port}}/index.css?t={{startTime}}">
<link rel="stylesheet" media="all" href="//{{devHost}}:{{port}}/index.css?t={{startTime}}">
{{/ifor}}
{{/if}}
{{else}}
{{#if localCss }}
<link rel="preload" as="style" href="//cdn.yoho.cn/yohobuywap-node/{{version}}/common.css?t={{startTime}}">
<link rel="stylesheet" media="all" href="//cdn.yoho.cn/yohobuywap-node/{{version}}/common.css?t={{startTime}}">
{{/if}}
{{#if isFeature}}
<link rel="preload" as="style" href="//cdn.yoho.cn/yohobuywap-node/{{version}}/feature.css?t={{startTime}}">
<link rel="stylesheet" media="all" href="//cdn.yoho.cn/yohobuywap-node/{{version}}/feature.css?t={{startTime}}">
{{else}}
{{#ifor localCss vue}}
<link rel="preload" as="style" href="//cdn.yoho.cn/yohobuywap-node/{{version}}/{{module}}.{{page}}.css?t={{startTime}}">
<link rel="stylesheet" media="all" href="//cdn.yoho.cn/yohobuywap-node/{{version}}/{{module}}.{{page}}.css?t={{startTime}}">
{{^}}
<link rel="preload" as="style" href="//cdn.yoho.cn/yohobuywap-node/{{version}}/index.css?t={{startTime}}">
<link rel="stylesheet" media="all" href="//cdn.yoho.cn/yohobuywap-node/{{version}}/index.css?t={{startTime}}">
{{/ifor}}
{{/if}}
{{/if}}
{{#if devEnv}}
<link rel="preload" as="script" href="//{{devHost}}:{{port}}/libs.js?t={{startTime}}"/>
<link rel="preload" as="script" href="//{{devHost}}:{{port}}/{{module}}.{{page}}.js?t={{startTime}}"/>
{{else}}
<link rel="preload" as="script" href="//cdn.yoho.cn/yohobuywap-node/{{version}}/libs.js?t={{startTime}}"/>
<link rel="preload" as="script" href="//cdn.yoho.cn/yohobuywap-node/{{version}}/{{module}}.{{page}}.js?t={{startTime}}"/>
{{/if}}
<link rel="apple-touch-icon-precomposed" href="http://static.yohobuy.com/m/v1/img/touch/apple-touch-icon-144x144-precomposed-new.png">
<link rel="apple-touch-startup-image" href="https://cdn.yoho.cn/h5/forios/startup/startup-orange-6p.png" media="screen and (min-device-width: 1126px) and (max-device-width: 1242px)">
<link rel="apple-touch-startup-image" href="https://cdn.yoho.cn/h5/forios/startup/startup-orange-x.png" media="screen and (min-device-width: 751px) and (max-device-width: 1125px)">
... ... @@ -127,93 +113,27 @@
{{#wechatShare}}
<script type="text/javascript" src="//res.wx.qq.com/open/js/jweixin-1.3.2.js"></script>
{{/wechatShare}}
{{#loadJsBefore}}
<script src="{{src}}"></script>
{{/loadJsBefore}}
{{#if devEnv}}
<script>
<script>
var STATIC_RESOURCE_HASH = '{{startTime}}';
var STATIC_RESOURCE_PATH = '//{{devHost}}:{{port}}';
window.jsFiles = [
{{#loadJsBefore}}
'{{src}}',
{{/loadJsBefore}}
'//{{devHost}}:{{port}}/libs.js?t={{startTime}}',
'//{{devHost}}:{{port}}/{{module}}.{{page}}.js?t={{startTime}}'
{{#loadJs}}
,'{{src}}'
{{/loadJs}}
];
</script>
<script src="//{{devHost}}:{{port}}/libs.js?t={{startTime}}" crossorigin="anonymous"></script>
<script src="//{{devHost}}:{{port}}/{{module}}.{{page}}.js?t={{startTime}}" crossorigin="anonymous"></script>
{{^}}
<script>
var STATIC_RESOURCE_HASH = '{{startTime}}';
var STATIC_RESOURCE_PATH = '//cdn.yoho.cn/yohobuywap-node/{{version}}';
window.jsFiles = [
{{#loadJsBefore}}
'{{src}}',
{{/loadJsBefore}}
'//cdn.yoho.cn/yohobuywap-node/{{version}}/libs.js?t={{startTime}}',
'//cdn.yoho.cn/yohobuywap-node/{{version}}/{{module}}.{{page}}.js?t={{startTime}}'
{{#loadJs}}
,'{{src}}'
{{/loadJs}}
];
</script>
<script src="//cdn.yoho.cn/yohobuywap-node/{{version}}/libs.js?t={{startTime}}" crossorigin="anonymous"></script>
<script src="//cdn.yoho.cn/yohobuywap-node/{{version}}/{{module}}.{{page}}.js?t={{startTime}}" crossorigin="anonymous"></script>
{{/if}}
<script>
(function() {
function addOnload(node, callback) {
var supportOnload = 'onload' in node;
if (supportOnload) {
node.onload = callback;
} else {
node.onreadystatechange = function() {
if (/loaded|complete/.test(node.readyState)) {
return callback();
}
};
}
}
function loadJS(src, retryMode) {
var ref = document.getElementsByTagName('script')[ 0 ];
var script = document.createElement('script');
var scriptSrc;
if (retryMode) {
scriptSrc = src;
} else {
scriptSrc = window.jsFiles.shift();
}
if (!scriptSrc) {
return;
}
script.src = scriptSrc;
script.crossorigin = 'anonymous';
if (!retryMode) {
script.onerror = function() {
if (script.parentNode) {
script.parentNode.removeChild(script);
}
script.onerror = script.onreadystatechange = null;
loadJS(script.src, true);
};
}
addOnload(script, function() {
script.onload = script.onreadystatechange = null;
loadJS();
});
ref.parentNode.insertBefore(script, ref);
return script;
}
loadJS();
}());
</script>
{{#loadJs}}
<script src="{{src}}"></script>
{{/loadJs}}
{{#unless devEnv}}
{{> analysis}}
{{/unless}}
... ...
... ... @@ -12,11 +12,11 @@
<p class="iconfont tab-icon">&#xe627;</p>
<p class="tab-name"></p>
</a>
<a class="tab-item {{#if shoppingCartPage}}current{{/if}}" href="{{shoppingCartUrl}}">
<a class="tab-item {{#if shoppingCartPage}}current{{/if}}" href="{{shoppingCartUrl}}" rel="nofollow">
<p class="iconfont tab-icon">&#xe62c;</p>
<p class="tab-name">购物车</p>
</a>
<a class="tab-item {{#if minePage}}current{{/if}}" href="{{mineUrl}}">
<a class="tab-item {{#if minePage}}current{{/if}}" href="{{mineUrl}}" rel="nofollow">
<p class="iconfont tab-icon">&#xe62b;</p>
<p class="tab-name">我的</p>
</a>
... ...
... ... @@ -4,14 +4,14 @@
{{#each data}}
{{#if @first}}
<li class="swiper-slide">
<a href="{{url}}">
<img src="{{image2 src w=640 h=240 q=60}}">
<a href="{{url}}" rel="nofollow">
<img src="{{image2 src w=640 h=240 q=60}}" alt="banner轮播图">
</a>
</li>
{{^}}
<li class="swiper-slide">
<a href="{{url}}">
<img class="swiper-lazy" data-src="{{image2 src w=640 h=240 q=60}}">
<a href="{{url}}" rel="nofollow">
<img class="swiper-lazy" data-src="{{image2 src w=640 h=240 q=60}}" alt="banner轮播图">
</a>
</li>
{{/if}}
... ...
{{#if singleOne}}
{{#data}}
<div class="banner-list">
<a href="{{url}}" id="{{../template_id}}" name="{{../template_intro}}">
<img src="{{image2 src w=640 h=200 q=60 mode=3}}" alt="">
<a href="{{url}}" id="{{../template_id}}" name="{{../template_intro}}" rel="nofollow">
<img src="{{image2 src w=640 h=200 q=60 mode=3}}" alt="活动图片">
</a>
</div>
{{/data}}
... ... @@ -11,8 +11,8 @@
<ul class="banner-list swiper-wrapper clearfix">
{{#data}}
<li class="swiper-slide">
<a href="{{url}}" id="{{../template_id}}" name="{{../template_intro}}">
<img src="{{image2 src w=640 h=200 q=60 mode=3}}" alt="">
<a href="{{url}}" id="{{../template_id}}" name="{{../template_intro}}" rel="nofollow">
<img src="{{image2 src w=640 h=200 q=60 mode=3}}" alt="活动图片">
</a>
</li>
{{/data}}
... ...
... ... @@ -33,9 +33,9 @@
<a href="{{url}}">
<div class="img-box">
{{#if @first}}
<img class="lazy" data-original="{{image2 src w=258 h=383 q=60}}" alt="">
<img class="lazy" data-original="{{image2 src w=258 h=383 q=60}}" alt="{{title}}">
{{^}}
<img class="lazy" data-original="{{image2 src w=191 h=191 q=60}}" alt="">
<img class="lazy" data-original="{{image2 src w=191 h=191 q=60}}" alt="{{title}}">
{{/if}}
</div>
<p class="category-name">{{title}}</p>
... ...
... ... @@ -6,7 +6,7 @@
<a href="{{url}}">
<div class="brand-logo">
{{!--此处不使用 Lazyload 是由于安卓 UC 10 版本加载不出来--}}
<img src="{{image2 src w=158 h=174 q=60}}">
<img src="{{image2 src w=158 h=174 q=60}}" alt="{{title}}">
</div>
{{!--<p class="brand-name">{{name}}</p>--}}
</a>
... ...
... ... @@ -12,7 +12,7 @@
<li>
<a href="{{url}}">
<div class="img-box">
<img src="{{image2 src w=140 h=140 q=60}}" alt="">
<img src="{{image2 src w=140 h=140 q=60}}" alt="{{title}}">
</div>
</a>
</li>
... ...
{{#data}}
<div class="hot-single">
{{> common/floor-header-more}}
{{# title}}
<div class="floor-header-more">
<h2>
{{#if title}}{{title}}{{else}}{{name}}{{/if}}
</h2>
{{#if more_url}}
<a class="more-btn iconfont" href="{{more_url}}" rel="nofollow">&#xe618;</a>
{{/if}}
</div>
{{/ title}}
{{> resources/new-floor-banner}}
<div class="hot-single-goods-list" {{#background}}style="background-image: url({{image2 src w=640 h=330 q=60}})"{{/background}}>
<ul>
... ...
{
"name": "yohobuywap-node",
"version": "6.5.53",
"version": "6.6.1",
"private": true,
"description": "A New Yohobuy Project With Express",
"repository": {
... ... @@ -57,18 +57,18 @@
"body-parser": "^1.18.0",
"cheerio": "^0.22.0",
"client-sessions": "^0.8.0",
"compression": "^1.7.0",
"compression": "^1.7.2",
"connect-multiparty": "^2.0.0",
"connect-redis": "^3.3.3",
"cookie-parser": "^1.4.3",
"cssnano": "^3.10.0",
"express": "^4.15.4",
"express": "^4.16.3",
"feed": "^1.1.0",
"geetest": "^4.1.2",
"lodash": "^4.17.4",
"handlebars": "^4.0.11",
"lodash": "^4.17.5",
"memory-cache": "^0.2.0",
"moment": "^2.20.1",
"oneapm": "^1.2.20",
"moment": "^2.22.1",
"passport": "^0.4.0",
"passport-local": "^1.0.0",
"passport-qq": "^0.1.0",
... ... @@ -77,81 +77,81 @@
"passport-weixin": "^0.2.0",
"path-to-regexp": "^2.1.0",
"redis": "^2.8.0",
"request": "^2.81.0",
"request": "^2.85.0",
"request-promise": "^4.2.1",
"semver": "^5.4.1",
"semver": "^5.5.0",
"sitemap": "^1.13.0",
"urlencode": "^1.1.0",
"uuid": "^3.1.0",
"uuid": "^3.2.1",
"xml2js": "^0.4.19",
"yoho-express-session": "^2.0.0",
"yoho-md5": "^2.0.0",
"yoho-node-lib": "=0.6.12",
"yoho-node-lib": "=0.6.13",
"yoho-zookeeper": "^1.0.9"
},
"devDependencies": {
"@mapbox/stylelint-processor-arbitrary-tags": "^0.2.0",
"autoprefixer": "^7.2.4",
"autoprefixer": "^8.3.0",
"babel-core": "^6.26.0",
"babel-eslint": "^8.2.2",
"babel-loader": "^7.1.2",
"babel-eslint": "^8.2.3",
"babel-loader": "^7.1.4",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.6.0",
"babel-runtime": "^6.26.0",
"css-loader": "^0.28.8",
"echarts": "^3.7.1",
"eslint": "^4.15.0",
"css-loader": "^0.28.11",
"echarts": "^4.0.4",
"eslint": "^4.19.1",
"eslint-config-yoho": "^1.0.9",
"eslint-plugin-html": "^4.0.1",
"extract-text-webpack-plugin": "^3.0.0",
"friendly-errors-webpack-plugin": "^1.6.1",
"handlebars-loader": "^1.6.0",
"happypack": "^4.0.0",
"eslint-plugin-html": "^4.0.3",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"friendly-errors-webpack-plugin": "^1.7.0",
"handlebars-loader": "^1.7.0",
"husky": "^0.14.3",
"intersection-observer": "^0.5.0",
"jquery-lazyload": "^1.9.7",
"lint-staged": "^7.0.4",
"lozad": "^1.0.9",
"nodemon": "^1.14.10",
"postcss": "^6.0.16",
"lozad": "^1.4.0",
"nodemon": "^1.17.3",
"postcss": "^6.0.21",
"postcss-assets": "^5.0.0",
"postcss-calc": "^6.0.0",
"postcss-center": "^1.0.0",
"postcss-clearfix": "^2.0.1",
"postcss-crip": "^2.0.1",
"postcss-import": "^11.0.0",
"postcss-loader": "^2.0.10",
"postcss-import": "^11.1.0",
"postcss-loader": "^2.1.4",
"postcss-position": "^1.0.0",
"postcss-pxtorem": "^4.0.1",
"postcss-scss": "^1.0.3",
"postcss-scss": "^1.0.5",
"postcss-short": "^4.1.0",
"postcss-sprites": "^4.2.1",
"postcss-use": "^2.3.0",
"postcss-use": "^3.0.0",
"precss": "^2.0.0",
"shelljs": "^0.7.8",
"shelljs": "^0.8.1",
"store": "^2.0.12",
"style-loader": "^0.19.1",
"stylelint": "^8.1.1",
"stylelint-config-yoho": "^1.2.12",
"style-loader": "^0.21.0",
"stylelint": "^9.2.0",
"stylelint-config-yoho": "^1.3.0",
"stylelint-formatter-table": "^1.0.2",
"vue": "^2.5.13",
"vue": "^2.5.16",
"vue-infinite-scroll": "^2.0.1",
"vue-lazyload": "^1.1.3",
"vue-loader": "^13.7.0",
"vue-template-compiler": "^2.5.13",
"webpack": "^3.5.6",
"webpack-dev-middleware": "^2.0.4",
"webpack-dev-server": "^2.10.1",
"webpack-hot-middleware": "^2.19.1",
"webpack-merge": "^4.1.0",
"whatwg-fetch": "^2.0.3",
"vue-lazyload": "^1.2.3",
"vue-loader": "^14.2.2",
"vue-template-compiler": "^2.5.16",
"webpack": "^4.6.0",
"webpack-cli": "^2.0.15",
"webpack-dev-middleware": "^3.1.2",
"webpack-dev-server": "^3.1.3",
"webpack-hot-middleware": "^2.22.1",
"webpack-merge": "^4.1.2",
"whatwg-fetch": "^2.0.4",
"workbox-sw": "^2.1.2",
"yoho-cookie": "^1.2.0",
"yoho-fastclick": "^1.0.6",
"yoho-hammer": "^2.0.8",
"yoho-iscroll": "^5.2.1",
"yoho-jquery": "^2.2.4",
"yoho-jquery-lazyload": "^1.9.12",
"yoho-jquery-lazyload": "^1.9.13",
"yoho-jquery-qrcode": "^0.14.0",
"yoho-qs": "^1.0.1",
"yoho-swiper": "^3.3.2",
... ...
... ... @@ -111,7 +111,9 @@ exports.postcssPlugin = (et) => {
selectorBlackList: [], // 选择器黑名单,可以使用正则
propWhiteList: [] // 属性名称为空,表示替换所有属性的值
}),
autoprefixer(),
autoprefixer({
remove: false
}),
postUse({
modules: ['postcss-clearfix', 'postcss-crip', 'postcss-short', 'postcss-center', 'postcss-position']
})
... ...
... ... @@ -6,23 +6,16 @@
'use strict';
const os = require('os');
const path = require('path');
const shelljs = require('shelljs');
const _ = require('lodash');
const webpack = require('webpack');
const HappyPack = require('happypack');
const { cssLoader, hbsLoader } = require('./utils.js');
const postcssConfig = require('./postcss.config.js');
const happyThreadPool = HappyPack.ThreadPool({ // eslint-disable-line
size: os.cpus().length
});
const getEntries = () => {
const entries = {
libs: ['yoho-jquery', path.join(__dirname, '../js/global.js')],
common: path.join(__dirname, '../scss/common.css'),
feature: path.join(__dirname, '../scss/feature.css')
};
... ... @@ -34,7 +27,10 @@ const getEntries = () => {
// Important
// 生成规则:module.page: './js/module/page/index.js'
entries[`${dir[0]}.${dir[1]}`] = path.join(__dirname, `../js/${dir.join('/')}`);
entries[`${dir[0]}.${dir[1]}`] = [
path.join(__dirname, '../js/global.js'),
path.join(__dirname, `../js/${dir.join('/')}`)
];
});
// 老的生成规则module.page.js
... ... @@ -43,7 +39,10 @@ const getEntries = () => {
// Important
// 生成规则:module.page: './js/module/xx.page.js'
entries[`${dir[0]}.${dir[1].match(/(.*).page.js/)[1]}`] = path.join(__dirname, `../js/${dir.join('/')}`);
entries[`${dir[0]}.${dir[1].match(/(.*).page.js/)[1]}`] = [
path.join(__dirname, '../js/global.js'),
path.join(__dirname, `../js/${dir.join('/')}`)
];
});
return entries;
... ... @@ -78,16 +77,14 @@ module.exports = (env) => {
test: /\.js$/,
exclude: [/node_modules/],
use: [{
loader: 'happypack/loader?id=js'
loader: 'babel-loader'
}]
}, {
test: /\.css$/,
use: cssLoader(env, 'css')
}, {
test: /\.hbs$/,
use: [{
loader: 'happypack/loader?id=hbs'
}]
use: [hbsLoader]
}]
},
resolve: {
... ... @@ -105,21 +102,34 @@ module.exports = (env) => {
stats: {
children: false
},
optimization: {
splitChunks: {
cacheGroups: {
default: false,
libs: {
test: (file) => {
if (file.rawRequest === 'yoho-jquery') {
return true;
}
if (file.rawRequest === path.join(__dirname, '../js/global.js')) {
return true;
}
return false;
},
name: 'libs',
chunks: 'initial',
enforce: true
}
}
}
},
performance: {
maxEntrypointSize: 512000,
maxAssetSize: 512000
},
plugins: [
new HappyPack({
id: 'js',
threadPool: happyThreadPool,
loaders: ['babel-loader'],
}),
new HappyPack({
id: 'hbs',
threadPool: happyThreadPool,
loaders: [hbsLoader]
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'libs',
filename: 'libs.js'
}),
new webpack.ProvidePlugin({
$: 'yoho-jquery',
jQuery: 'yoho-jquery',
... ...
... ... @@ -17,10 +17,15 @@ if (devInfo.publicPath.indexOf('https')) {
}
module.exports = merge(baseConfig, {
mode: 'development',
output: {
publicPath: devInfo.publicPath
},
devtool: 'source-map',
devtool: 'eval',
performance: {
maxEntrypointSize: 2048000,
maxAssetSize: 2048000
},
plugins: [
new ExtractTextPlugin('[name].css'),
new webpack.HotModuleReplacementPlugin(),
... ...
const webpack = require('webpack');
const path = require('path');
const shelljs = require('shelljs');
const {cssLoader} = require('./utils.js');
... ... @@ -12,6 +11,7 @@ shelljs.cp('-R', path.join(__dirname, '../img/'), distDir);
shelljs.cp('-R', path.join(__dirname, '../font/'), distDir);
let webpackConfig = {
mode: 'production',
entry: {
index: [path.join(__dirname, '../scss/index.css')]
},
... ... @@ -25,13 +25,15 @@ let webpackConfig = {
use: cssLoader('pro', 'css')
}]
},
stats: {
children: false
},
performance: {
maxEntrypointSize: 5120000,
maxAssetSize: 5120000
},
plugins: [
new ExtractTextPlugin('[name].css'),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
})
new ExtractTextPlugin('[name].css')
]
};
... ...
... ... @@ -2,7 +2,6 @@
const path = require('path');
const shelljs = require('shelljs');
const webpack = require('webpack');
const merge = require('webpack-merge');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const config = require('../../package.json');
... ... @@ -18,25 +17,11 @@ shelljs.cp('-R', path.join(__dirname, './dll/*'), distDir);
baseConfig = baseConfig('pro');
module.exports = merge(baseConfig, {
mode: 'production',
output: {
path: distDir
},
plugins: [
new ExtractTextPlugin('[name].css'),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
parallel: true,
sourceMap: true,
uglifyOptions: {
compress: {
warnings: false
},
comments: false
}
})
new ExtractTextPlugin('[name].css')
]
});
... ...
const webpack = require('webpack');
const path = require('path');
module.exports = {
mode: 'production',
entry: {
sw: path.join(__dirname, '../js/pwa/sw.js')
},
... ... @@ -16,13 +17,5 @@ module.exports = {
include: [path.join(__dirname, '../../node_modules/workbox-sw'), path.join(__dirname, '../js')],
use: 'babel-loader'
}]
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin()
]
}
};
... ...
... ... @@ -16,8 +16,8 @@
<div class="name eps">{{name}}</div>
<div class="num">
<span class="coin-pic-s"></span>
<span>{{#if points}}{{points}}{{/if}}{{#if point}}{{point}}{{/if}}</span>
<span class="old-price">{{discountPoints}}</span>
<span>{{#if point}}{{point}}{{/if}}{{#if discountPoints}}{{discountPoints}}{{/if}}</span>
<span class="old-price">{{#if points}}{{points}}{{/if}}</span>
{{#if vipDesc}}<span class="discount">{{vipDesc}}</span>{{/if}}
</div>
<div class="remain">仅剩{{#if stock}}{{stock}}{{/if}}{{#if num}}{{num}}{{/if}}</div>
... ... @@ -28,4 +28,4 @@
</div>
</div>
{{/ list}}
</div>
\ No newline at end of file
</div>
... ...
{{#if promYohoCoinText}}
<div class="goods-discount" id="goodsDiscountYohoCoin">
<h2 class="coin-item short-text tap-hightlight">
<span class="promotion-icon"></span>{{promYohoCoinText}}
<span class="icon-down iconfont">&#xe609;</span>
</h2>
</div>
{{/if}}
... ...
... ... @@ -11,4 +11,4 @@
{{/if}}
{{/each}}
</div>
{{/if}}
\ No newline at end of file
{{/if}}
... ...