Showing 98 changed files with 3010 additions and 463 deletions

Too many changes to show.

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

... ... @@ -24,7 +24,8 @@ const favicon = require('serve-favicon');
const uuid = require('uuid');
const pkg = require('./package.json');
const session = require('cookie-session');
const session = require('client-sessions');
const _ = require('lodash');
const app = express();
... ... @@ -58,7 +59,7 @@ app.use(global.yoho.hbs({
layoutsDir: path.join(__dirname, 'doraemon/views'),
partialsDir: path.join(__dirname, 'doraemon/views/partial'),
views: path.join(__dirname, 'doraemon/views'),
helpers: global.yoho.helpers
helpers: _.assign(global.yoho.helpers, require('./utils/helpers'))
}));
app.use(global.yoho.middleware());
... ... @@ -73,14 +74,19 @@ app.use(cookieParser());
app.use(compression());
app.use(session({
name: 'yohobuy_session_cookie',
secret: '82dd7e724f2c6870472c89dfa43cf48d'
requestKey: 'session',
cookieName: 'yohobuy_session_cookie',
secret: '82dd7e724f2c6870472c89dfa43cf48d',
domain: config.cookieDomain
}));
app.use((req, res, next) => {
req.user = {}; // 全局的用户数据
req.yoho = {}; // req和res绑定yoho对象,用于传递全局数据, 如req.yoho.channel等
req.app.locals.wap = app.locals.wap; // zookeper对象赋值
if (!req.session) {
req.session = {};
}
if (!req.session.id) {
req.session.id = uuid.v4();
}
... ... @@ -93,16 +99,19 @@ app.use((req, res, next) => {
// dispatcher
try {
const user = require('./doraemon/middleware/user');
const reqParamsFilter = require('./doraemon/middleware/req-params-filter');
const subDomain = require('./doraemon/middleware/sub-domain');
const itemNameHandler = require('./doraemon/middleware/item-name-handler');
const setYohoData = require('./doraemon/middleware/set-yoho-data');
const errorHanlder = require('./doraemon/middleware/error-handler');
const setPageInfo = require('./doraemon/middleware/set-pageinfo');
const devtools = require('./doraemon/middleware/devtools');
const layoutTools = require('./doraemon/middleware/layout-tools');
const seo = require('./doraemon/middleware/seo');
const pageCache = require('./doraemon/middleware/page-cache');
// YOHO 前置中间件
app.use(reqParamsFilter());
app.use(subDomain());
app.use(itemNameHandler);
app.use(setYohoData());
... ... @@ -114,6 +123,8 @@ try {
app.use(devtools());
}
app.use(layoutTools());
app.use(pageCache());
require('./dispatch')(app);
app.all('*', errorHanlder.notFound()); // 404
... ...
'use strict';
const serviceApi = global.yoho.ServiceAPI;
const api = global.yoho.API;
const helpers = global.yoho.helpers;
const crypto = global.yoho.crypto;
const queryString = require('querystring');
const Promise = require('bluebird');
const co = Promise.coroutine;
const headerModel = require('../../../doraemon/models/header'); // 头部model
const _ = require('lodash');
const productProcess = require(`${utils}/product-process`);
const userAcquireStatus = (uid, couponIds) => {
if (couponIds != '') {
return api.get('', {
method: 'app.coupons.userAcquireStatus',
uid: uid,
couponIds: couponIds
});
}
};
/**
* 查询商品
* @param id
* @returns {*}
*/
const _getRelatedData = (idList) => {
if (idList != '') {
return api.get('', {
productSkn: idList,
method: 'h5.product.batch'
}).then((result) => {
let goods = [];
if (result && result.data && result.data.product_list && result.code === 200) {
_.forEach(result.data.product_list, function(val) {
if (!val.student_price) {
val.student_price = val.vip2_price;
}
});
goods = productProcess.processProductList(result.data.product_list);
return goods;
} else {
return {};
}
});
}
};
exports.index = (req, res, next) => {
let code = 'c9b9639ce2884b768cfbc5cf9e68a53f';
let uid = req.__USER__.uid;
let options;
let noLoginUrl = helpers.urlFormat('/activity/student/register') + '?openby:yohobuy={"action":"go.weblogin","params":{"jumpurl":{"url":"' + req.__USER__.http + '//m.yohobuy.com/activity/student-market"}}}';
return serviceApi.get('operations/api/v5/resource/get', {
content_code: code,
platform: 'iphone'
}).then((result) => {
let coupons = {},
activities,
banner,
icons,
link,
studentGoods,
idList = [],
goodShow,
// url,
// param,
couponids = [];
(result.data || []).forEach((item) => {
switch (item.template_name) {
case 'getCoupon':
coupons = item;
break;
case 'image_list':
activities = item;
break;
case 'focus':
banner = item;
break;
case 'recommend_content_five':
icons = item;
break;
case 'link':
link = item;
break;
case 'goods':
studentGoods = item;
break;
default:
// other = item;
break;
}
});
if (coupons && coupons.data) {
coupons.link = link && link.data ? link.data[0].url + (req.__USER__.isApp ? '&app_version=' + req.__USER__.app_version : '') : '';
coupons.data = (coupons.data || []).map((item) => {
// let url = item.image.url;
couponids.push(item.couponID);
// if (!req.__USER__.isLogin) {
// url = 'http://m.yohobuy.com/activity/student/register?openby:yohobuy={"action":"go.weblogin","params":{"jumpurl":{"url":"http://m.yohobuy.com/activity/student"}}}';
// }
//
// item.image.noLoginUrl=url;
return item;
});
if (coupons.data.length > 2) {
coupons.data = coupons.data.slice(0, 2);
}
}
if (studentGoods && studentGoods.data) {
_.forEach(studentGoods.data, function(obj) {
idList.push(obj.id);
});
}
return Promise.all([userAcquireStatus(uid, couponids.join(',')), _getRelatedData(idList.join(','))]).then(datas => {
coupons.data = _.get(coupons, 'data', []).map((item)=>{
item.status = 1;
(datas[0].data || []).forEach((it) => {
if (+it.couponId === +item.couponID) {
item.hasNum = it.hasNum;
item.status = it.status;
}
});
item.couponID = crypto.encryption('yoho9646abcdefgh', item.couponID);
return item;
});
options = {
isApp: req.__USER__.isApp,
goods: datas[1],
banner: banner,
icons: icons,
coupons: coupons,
activities: activities,
isStudent: req.__USER__.isStudent,
isSupportStudent: req.__USER__.isSupportStudent,
isLogin: req.__USER__.isLogin,
title: '有货学生专享优惠',
http: req.__USER__.http,
uid: req.__USER__.uid,
app_version: req.__USER__.app_version,
isAppNoLogin: req.__USER__.isApp && !req.__USER__.isLogin,
noLoginUrl: noLoginUrl,
page: 'student-market',
showDownloadApp: true
};
if (!req.__USER__.isApp) {
options.pageHeader = headerModel.setNav({
navTitle: options.title,
navBtn: true
});
}
options.loginUrl = '//m.yohobuy.com/activity/student/register';
if (options.isApp) {
if (options.isLogin) {
options.loginUrl = options.loginUrl + '?openby:yohobuy={"action":"go.h5","params":{"islogin":"N","url":"' + req.__USER__.http + '//m.yohobuy.com/activity/student/register"}}';
} else {
// no login
options.loginUrl = options.loginUrl + '?openby:yohobuy={"action":"go.weblogin","params":{"jumpurl":{"url":"' + req.__USER__.http + '//m.yohobuy.com/activity/student/register","antarget":"1"}}}';
}
}
res.render('student-market', options);
}).catch(next);
});
};
... ...
... ... @@ -27,6 +27,8 @@ const shopCollect = require(`${cRoot}/shopCollect`);
const singleDay = require(`${cRoot}/single-day`);
const share = require(`${cRoot}/share`);
const studentMarket = require(`${cRoot}/student-market`);
// routers
router.get('/demo', demo.index);
... ... @@ -120,4 +122,6 @@ router.post('/vip-day1028/isStudent', vipDay1028.beforeIn, vipDay1028.checkIsStu
// 获取活动页传来的参数
router.get('/wechat/1111', wechat.feature);
router.get('/student-market', student.getUser, studentMarket.index);
module.exports = router;
... ...
<div class="mobile-container">
<div class="mobile-wrap yoho-page student student-market">
{{! 头部banner}}
{{#banner}}
{{> resources/banner-top}}
{{/banner}}
{{#icons}}
<section class='s-section clearfix' data-template-id="{{template_id}}">
<h1>学生权益<a class='more s-quan' href='//m.yohobuy.com/activity/student/detail/quanyi?openby:yohobuy={"action":"go.h5","params":{"islogin":"N","url":"{{../http}}//m.yohobuy.com/activity/student/detail/quanyi"}}'>更多权益</a></h1>
<div class='s-content'>
{{#each data.list}}
<div class='s-section s-dialog'>
<a href="javascript:void(0)">
<img src='{{image src 320 149}}' title="{{title}}">
</a>
</div>
{{/each}}
</div>
</section>
{{/icons}}
<div class='sm-layout'>
快来认证吧,认证通过即可享受专属优惠!
<a class='s-renzhen' href='{{loginUrl}}'>立即认证</a>
</div>
{{#coupons}}
<section class='s-section clearfix' data-template-id="{{template_id}}">
<h1>领券中心
<a class='more iconfont' href="{{link}}">&#xe618;</a>
</h1>
<div class='s-coupon-contain'>
<style type="text/css">
.no-bg{
color: #fff!important;
background-image: none!important;
}
</style>
{{#each data}}
<div class="coupon-floor" coupon-id="{{couponID}}">
<div class="floor-main" style="background-image: url({{image image.src 0 0}});">
<a href='{{image.url}}' class="main-left"></a>
{{#isEqual status 1}}
{{#if @root.isAppNoLogin}}
<a href='{{@root.noLoginUrl}}' class="main-right-use" >
<span class="on-receive on-lingqu no-bg">
<p>点击</p>
<p>领取</p>
</span>
</a>
{{else}}
<div class="main-right-use" href='{{../image.url}}'>
<span class="on-receive on-lingqu no-bg">
<p>点击</p>
<p>领取</p>
</span>
</div>
{{/if}}
{{/isEqual}}
{{#isEqual status 2}}
<a href='{{../image.url}}' class="main-right-use" >
<span class="zero"></span>
</a>
{{/isEqual}}
{{#isEqual status 3}}
<a href='{{../image.url}}' class="main-right-use" >
<span class="received"></span>
</a>
{{/isEqual}}
{{#isEqual status 4}}
<a href='{{../image.url}}' class="main-right-use" >
<span class="on-receive no-bg" >
<p>已经</p>
<p>过期</p>
</span>
</a>
{{/isEqual}}
</div>
</div>
{{/each}}
</div>
</section>
{{/coupons}}
{{#activities}}
<section class='s-section clearfix' data-template-id="{{template_id}}">
<h1>学生专属活动</h1>
{{#each data.list}}
<a class='s-activity' href="{{url}}">
<img src='{{image src 640 200}}' title='{{title}}'>
</a>
{{/each}}
</section>
{{/activities}}
<section class='s-section clearfix'>
<h1>学生专享商品<a class="more iconfont" href="//search.m.yohobuy.com/?students=1&title=学生专享商品&uid={{uid}}{{#isApp}}&app_version={{@root.app_version}}{{/isApp}}?openby:yohobuy={'action':'go.h5','params':{'islogin':'N','url':'{{@root.http}}//search.m.yohobuy.com/','param':{'students':'1','title':'学生专享商品','uid':'{{uid}}'}}}">&#xe618;</a></h1>
<div class='goods-list clearfix'>
{{#each goods}}
<div class="good-info">
<div class="tag-container clearfix">
{{# tags}}
{{# isNew}}
<p class="good-tag new-tag">NEW</p>
{{/ isNew}}
{{# isAdvance}}
<p class="good-tag renew-tag">再到着</p>
{{/ isAdvance}}
{{# isDiscount}}
<p class="good-tag sale-tag">SALE</p>
{{/ isDiscount}}
{{# isYohoood}}
<p class="good-tag running-man-tag">跑男同款</p>
{{/ isYohoood}}
{{# isLimited}}
<p class="good-tag limit-tag">限量</p>
{{/ isLimited}}
{{/ tags}}
</div>
<div class="good-detail-img">
<a class="good-thumb" href="{{url}}">
<img class="lazy" data-original="{{image default_images 235 314}}">
</a>
</div>
<div class="good-detail-text">
<div class="name">
<a href="{{url}}">{{product_name}}</a>
</div>
<div class="price">
<span class="sale-price">¥{{round student_price}} <i class='s-biaoqian'></i></span>
<p class="s-price-block">
<span class="market-price">¥{{round sales_price}}</span>
</p>
</div>
</div>
</div>
{{/each}}
</div>
<a class='s-more' href="//search.m.yohobuy.com/?students=1&title=学生专享商品&uid={{uid}}{{#isApp}}&app_version={{@root.app_version}}{{/isApp}}?openby:yohobuy={'action':'go.h5','params':{'islogin':'N','url':'{{@root.http}}//search.m.yohobuy.com/','param':{'students':'1','title':'学生专享商品','uid':'{{uid}}'}}}">查看更多</a>
</section>
<div class="float-layer" id="float-layer-app">
<div class="float-layer-left">
<span class="yoho-icon iconfont">&#xe60d;</span>
<p>快来下载Yoho!buy有货<br>即刻享受学生购物优惠</p>
</div>
<a href="javascript:void(0);" id="float-layer-close" >
<i class="close-icon iconfont">&#xe623;</i>
<div class="circle-rightbottom"></div>
</a>
<a href="javascript:void(0);" id="float-layer-btn">
立即下载
</a>
</div>
<div class="s-replace"></div>
</div>
</div>
... ...
... ... @@ -32,7 +32,8 @@ let _renderData = {
let _channelPage = (req, res, data) => {
return channelModel.getChannelData({
gender: data.gender,
uid: _.toString(req.user.uid)
uid: _.toString(req.user.uid),
limit: 6// 首屏先获取前6个楼层,其余用ajax获取
}).then(result => {
_renderData.homeHeader.defaultTerms = result.defaultTerms;
... ... @@ -51,11 +52,31 @@ let _channelPage = (req, res, data) => {
// }
// }].concat(result.content);
// console.log(result.content[9]);
res.render('channel', Object.assign({}, _renderData, data, result));
res.render('channel', Object.assign({}, _renderData, data, result, {
localCss: true
}));
});
};
/**
* 获取首页频道其余楼层
*/
let getResourceContent = (req, res, next) => {
return channelModel.getChannelResource({
gender: req.query.gender,
uid: _.toString(req.user.uid),
}).then(result => {
if (result.length) {
result = result.slice(6);
}
res.json(result);
}).catch(next);
};
/**
* 频道选择页
*/
let index = (req, res, next) => {
... ... @@ -163,7 +184,7 @@ let shopRecom = (req, res, next) => {
}).then(result => {
res.send(result);
}).catch(next);
}
};
/**
* 获取用户vip信息
... ... @@ -187,12 +208,12 @@ let userVip = (req, res, next) => {
res.json({
code: 500,
msg: '出错了',
})
});
}
});
}).catch(next);
}
}
};
module.exports = {
switchChannel,
... ... @@ -204,4 +225,5 @@ module.exports = {
bottomBanner,
shopRecom,
userVip,
};
\ No newline at end of file
getResourceContent
};
... ...
... ... @@ -194,7 +194,7 @@ const getBrandByChannel = (channel) => {
name: row.brand_name,
isHot: row.is_hot === 'Y' ? true : false,
isNew: row.is_show_new === 'Y' ? true : false,
url: helpers.urlFormat('', null, row.brand_domain)
url: helpers.urlFormat('/product/index/brand?domain=' + row.brand_domain)
});
});
... ... @@ -222,7 +222,7 @@ const getBrandByChannel = (channel) => {
list.push({
brandName: newList[key].brand_name,
url: helpers.urlFormat('', null, newList[key].brand_domain),
url: helpers.urlFormat('/product/index/brand?domain=' + newList[key].brand_domain),
img: helpers.image(newList[key].brand_ico, 186, 115),
});
... ... @@ -249,7 +249,7 @@ const getBrandByChannel = (channel) => {
list.push({
brandName: hotList[key].brand_name,
url: helpers.urlFormat('', null, hotList[key].brand_domain),
url: helpers.urlFormat('/product/index/brand?domain=' + hotList[key].brand_domain),
img: helpers.image(hotList[key].brand_ico, 186, 115),
});
... ... @@ -487,7 +487,7 @@ const branchSearch = (params) => {
name: row.brand_name,
isHot: row.is_hot === 'Y' ? true : false,
isNew: row.is_show_new === 'Y' ? true : false,
url: helpers.urlFormat('', null, row.brand_domain),
url: helpers.urlFormat('/product/index/brand?domain=' + row.brand_domain),
brandId: row.id,
brandDomain: row.brand_domain,
searchName: row.brand_name_en + row.brand_name_cn
... ...
... ... @@ -114,14 +114,14 @@ const _processSideBar = (list, choosed) => {
* @param {[object]} gender
* @return {[type]}
*/
const _getChannelResource = (params) => {
const getChannelResource = (params) => {
params.gender = params.gender || 'boys';
params.limit = params.limit || 30;
params = Object.assign(params, {
gender: genderData[params.gender] || '1,2,3',
content_code: contentCode[params.gender], // eslint-disable-line
page: 1,
limit: 30
page: 1
});
if (!params.uid) {
params.new_device = true; // eslint-disable-line
... ... @@ -269,7 +269,7 @@ let getChannelData = (params) => {
var channelData = {};
let navGender = _.cloneDeep(params.gender);
return Promise.all([_getChannelResource(params), _getLeftNav(navGender), _getSearchIndex()]).then((data) => {
return Promise.all([getChannelResource(params), _getLeftNav(navGender), _getSearchIndex()]).then((data) => {
channelData.content = data[0] || []; // 资源位数据
channelData.sideNav = data[1] || []; // 侧边栏数据
channelData.defaultTerms = (data[2] && data[2].defaultTerms && data[2].defaultTerms.length !== 0) ? data[2].defaultTerms[0].content : '搜索商品、品牌';
... ... @@ -312,6 +312,7 @@ let shopRecom = (params) => {
module.exports = {
getChannelData,
getChannelResource,
getChannelSwitchData,
getBottomBannerData,
shopRecom,
... ...
... ... @@ -19,6 +19,7 @@ router.get('/boys', channel.switchChannel, channel.boys);
router.get('/girls', channel.switchChannel, channel.girls);
router.get('/kids', channel.switchChannel, channel.kids);
router.get('/lifestyle', channel.switchChannel, channel.lifestyle);
router.get('/channel/getResourceContent', channel.getResourceContent);// 获取首页,其余频道楼层
router.get('/(:channel)/bottomBanner', channel.bottomBanner);
... ... @@ -31,5 +32,5 @@ router.get('/brands/delBrandHistory', brandController.delBrandHistory); // 删
// 5.2新楼层功能
router.post('/channel/shopRecom', channel.shopRecom); // 店铺推荐收藏状态
router.post('/channel/userVip', channel.userVip)
router.post('/channel/userVip', channel.userVip);
module.exports = router;
... ...
... ... @@ -6,7 +6,9 @@
{{/homeHeader}}
{{! 资源位}}
{{> channel/content}}
<div class="resource-content">
{{> channel/content}}
</div>
{{! 商品列表}}
{{#if twoColumnGoods}}
... ...
... ... @@ -5,13 +5,13 @@
{{#if @first}}
<li class="swiper-slide buriedpoint" data-bp-id="shop_bannerarea_{{url}}_0">
<a href="{{url}}">
<img src="{{img}}">
<img src="{{image2 img q=60}}">
</a>
</li>
{{^}}
<li class="swiper-slide buriedpoint" data-bp-id="shop_bannerarea_two_0">
<a href="{{url}}">
<img class="swiper-lazy" data-src="{{img}}">
<img class="swiper-lazy" data-src="{{image2 img q=60}}">
</a>
<div class="swiper-lazy-preloader"></div>
</li>
... ... @@ -23,4 +23,4 @@
<div class="pagination-inner">
</div>
</div>
</div>
\ No newline at end of file
</div>
... ...
... ... @@ -5,7 +5,7 @@
{{# list}}
<li class="swiper-slide">
<a href="{{url}}">
<img src="{{img}}" alt="">
<img src="{{image2 img q=60}}" alt="">
<span class="brands-title">{{textCn}}</span>
</a>
</li>
... ...
... ... @@ -69,7 +69,8 @@ const editor = (req, res, next) => {
infos: build,
isApp: isApp,
authorInfo: authorData.data
}
},
localCss: true
}, parameter));
} else {
return next();
... ... @@ -172,7 +173,9 @@ const index = (req, res, next) => {
res.set('Cache-Control', 'no-cache');
}
}
res.render('guang', Object.assign(responseData, result));
res.render('guang', Object.assign(responseData, result, {
localCss: true
}));
}).catch(next);
};
... ...
... ... @@ -357,7 +357,8 @@ const index = (req, res, next) => {
page: 'info-index',
title: '逛',
gender: gender,
wechatShare: true
wechatShare: true,
localCss: true
}, data, parameter));
});
} else {
... ...
... ... @@ -8,7 +8,7 @@
</li>
{{/ navs}}
</ul>
<div id="info-list" class="info-list-container">
{{# infos}}
<div class="info-list{{^show}} hide{{/show}}">
... ... @@ -19,7 +19,7 @@
{{# ../swiper}}
<div class="swiper-slide">
<a href="{{url}}">
<img class="swiper-lazy" data-src="{{img}}">
<img class="swiper-lazy" data-src="{{image2 img width=200 height=100 q=60}}">
</a>
<div class="swiper-lazy-preloader"></div>
</div>
... ... @@ -45,4 +45,4 @@
<input id="gender" type="hidden" value={{gender}}>
{{/ guang}}
</div>
{{> footer-tab}}
\ No newline at end of file
{{> footer-tab}}
... ...
... ... @@ -47,4 +47,4 @@
<p class="info-text">{{text}}</p>
{{> tvls}}
</div>
</div>
\ No newline at end of file
</div>
... ...
... ... @@ -50,6 +50,7 @@ const _repaymentList = (req, res, opt, params) => {
// 开通分期首页
const index = (req, res) => {
let uid = req.query.uid;
Promise.all([
installmentModel.getStauts(uid),
installmentModel.getSearchIntallment({
... ... @@ -98,6 +99,12 @@ const index = (req, res) => {
notice: data[3]
}, data[0], data[1]);
if (installmentOnly.goods.length > 0) {
params.installmentOnly = _.assign({
showMore: true
}, installmentOnly);
}
// status: 1 正常 2 逾期 3 不可用 4 未开通
if (data[0].status === '2') {
params.replayStatus = '逾期';
... ... @@ -117,7 +124,12 @@ const index = (req, res) => {
if (!result) {
return;
}
res.cookie('installmentUid', req.query.uid);
res.cookie('yhChannel', req.query.yh_channel);
res.cookie('udid', req.query.udid);
res.cookie('clientType', req.query.client_type);
res.cookie('appVersion', req.query.app_version);
res.render('installment/open-index', _.assign({
module: 'home',
page: 'installment',
... ... @@ -308,13 +320,15 @@ const getRepayRecord = (req, res) => {
// 账号管理
const account = (req, res) => {
var url = req.yoho.isApp || req.cookies.appVersion ? '/home/installment/account' : '/home/installment/bank-card';
if (req.cookies.appVersion) {
var versions = req.cookies.appVersion.split('.');
if (versions.length >= 2) {
if (versions[0] < 5 || (parseInt(versions[0], 10)===5 && versions[1] <= 1)) {
if (versions[0] < 5 || (parseInt(versions[0], 10) === 5 && versions[1] <= 1)) {
url = '/home/installment/bank-card';
} else {
url = helpers.appUrlFormat(url, 'go.instalmentMyCard')
url = helpers.appUrlFormat(url, 'go.instalmentMyCard');
}
}
}
... ...
... ... @@ -6,7 +6,7 @@ const model = require('../models/myqrcode'),
exports.index = (req, res, next) => {
let params = req.query,
esc = false,
appversion = req.query.app_version;
appversion = req.query.app_version || '';
if (Number(appversion.substr(0, 1) < 5) || (Number(appversion.substr(0, 1)) === 5 && Number(appversion.substr(2, 1)) < 2)) {
esc = true;
... ...
... ... @@ -78,6 +78,12 @@
</div>
{{# installmentOnly}}
{{> installment/installment-only}}
{{#if showMore}}
<div class="see-btn-area">
<a href="{{title.more_url}}" class="see-more">查看更多可分期商品</a>
</div>
{{/if}}
{{/ installmentOnly}}
</div>
{{/if}}
... ...
<div class="installment-page installment-result-page">
<div class="installment-page installment-result-page yoho-page">
{{# review}}
<i class="review-icon"></i>
<p class="font-b">审核中</p>
... ...
<div class="repayment-list-page" data-pos-id="{{posId}}">
<div class="repayment-list-page yoho-page" data-pos-id="{{posId}}">
<ul class="record-list"></ul>
<div class="no-result" style="display: none;">
<i class="result-icon"></i>
... ...
... ... @@ -182,7 +182,7 @@ const local = {
})(req, res, next);
},
logout: (req, res) => {
req.session = null;
req.session.reset();
res.clearCookie('_UID', {
domain: 'yohobuy.com'
... ...
... ... @@ -72,6 +72,8 @@ class Auth {
let encryptionUid = aes.encryptionUid(uid);
if (data) {
data.profile_name = (data.profile_name || '').replace(/::/g, '');
let uidCookie = `${data.profile_name}::${encryptionUid}::${data.vip_info && data.vip_info.title}::${token}`;
res.cookie('_UID', uidCookie, {
... ...
... ... @@ -164,7 +164,8 @@ exports.comments = (req, res, next) => {
res.render('detail/comments', Object.assign({
title: '购买评价',
pageHeader: headerData,
pageFooter: true
pageFooter: true,
localCss: true
}, result));
}).catch(next);
};
... ... @@ -188,7 +189,8 @@ exports.consults = (req, res, next) => {
res.render('detail/consults', Object.assign({
title: '购买咨询',
pageHeader: headerData,
pageFooter: true
pageFooter: true,
localCss: true
}, result));
}).catch(next);
};
... ... @@ -237,7 +239,8 @@ exports.consultform = (req, res, next) => {
pageHeader: headerData,
productId: req.query.product_id,
formUrl: '/product/detail/consultsubmit',
pageFooter: true
pageFooter: true,
localCss: true
});
};
... ... @@ -297,7 +300,8 @@ exports.indexSkn = (req, res, next) => {
result: result,
page: 'detail',
title: result.goodsName,
pageFooter: true
pageFooter: true,
localCss: true
});
}).catch(next);
};
... ... @@ -336,7 +340,8 @@ exports.index = (req, res, next) => {
result: result,
page: 'detail',
title: result.goodsName,
pageFooter: true
pageFooter: true,
localCss: true
});
}).catch(next);
};
... ...
... ... @@ -13,6 +13,7 @@ const _ = require('lodash');
const crypto = global.yoho.crypto;
const helpers = global.yoho.helpers;
const productProcess = require(`${utils}/product-process`);
const searchModel = require(`${mRoot}/search`);
/**
* 从 useragent 获取 uid
... ... @@ -208,20 +209,42 @@ const shopFav = (req, res) => {
};
// 品类落地页
const category = (req, res) => {
const category = (req, res, next) => {
let params = Object.assign({}, req.query);
res.render('search/goods-list', {
module: 'product',
page: 'search-list',
pageHeader: headerModel.setNav({
navTitle: req.query.title || req.query.sort_name
}),
goodList: params,
showDownloadApp: true,
pageFooter: true,
category: true
});
// 获取第一页数据做服务端渲染
let initialData = _.assign({
gender: params.gender,
sort: parseInt(params.sort) || '',
type: 'default',
order: '0',
page: 1,
limit: 12,
}, params);
searchModel.getSearchData(initialData).then((firstScreenGoodsList) => {
if (firstScreenGoodsList && firstScreenGoodsList.list) {
_.forEach(firstScreenGoodsList.list, function(item) {
if (item && item.default_images) {
item.default_images = item.default_images.replace(/quality\/80/g, 'quality/70');
}
});
}
res.render('search/goods-list', {
_noLazy: true, // 首屏不使用lazyload
module: 'product',
page: 'search-list',
pageHeader: headerModel.setNav({
navTitle: req.query.title || req.query.sort_name
}),
goodList: params,
firstPageGoodsList: firstScreenGoodsList.list,
showDownloadApp: true,
pageFooter: true,
category: true,
localCss: true
});
}).catch(next);
};
/**
... ... @@ -399,9 +422,16 @@ const favoriteBrand = (req, res, next) => {
let url = helpers.urlFormat('/signin.html') + '?refer=' + refer;
if (appVersion && appVersion !== 'false') {
uid = req.query.uid ? crypto.decrypt('', req.query.uid) : req.cookies.appUid;
if (req.query.uid) {
try {
uid = crypto.decrypt('', req.query.uid);
} catch (err) {
uid = req.query.uid;
}
} else {
uid = req.cookies.appUid;
}
uid = parseInt(uid, 10);
if (!uid || uid === 'undefined') {
... ...
/**
* 新版商品详情页面
*/
'use strict';
const _ = require('lodash');
const detailModel = require('../models/detail');
const newDetailModel = require('../models/new-detail');
const headerModel = require('../../../doraemon/models/header'); // 头部model
const newDetail = {
index(req, res, next) {
let id = req.params[0],
goodsId = req.params[1];
if (!id || !goodsId) {
return next();
}
let headerData = headerModel.setNav({
navTitle: '商品详情'
});
newDetailModel.getProductData({
id: id,
goodsId: goodsId,
ua: req.get('user-agent') || ''
}).then((result) => {
if (_.isEmpty(result)) {
return next();
}
result.id = id;
result.goodsId = goodsId;
res.render('detail/new/detail', {
pageHeader: headerData,
result: result,
page: 'new-detail',
title: result.goodsName,
pageFooter: true,
localCss: true
});
}).catch(next);
},
/*
* 商品基本信息 SKN 进入 pagecache重构
*/
sknData(req, res, next) {
let brandId = req.query.brandId;
let productId = req.query.productId;
let skn = req.query.skn;
if ([brandId, productId].some(val => !val)) {
return next();
}
newDetailModel.querySknData({
skn,
brandId,
productId
}).then(result => {
if (_.isEmpty(result)) {
return next();
}
res.json(result);
});
},
indexData(req, res, next) {
if (!req.xhr) {
return next();
}
if (!req.body.id) {
return next();
}
let uid = req.user.uid || 0;
let shoppingKey = req.cookies._SPK || '';
detailModel.getNewProductAsyncData(Object.assign({
id: req.body.id,
goodsId: req.body.goodsId,
productSkn: req.body.productSkn,
uid: uid,
shoppingKey: shoppingKey,
ua: req.get('user-agent') || ''
}, req.__User__)).then((result) => {
if (_.isEmpty(result)) {
return res.json({
code: 400,
message: '数据错误'
});
}
result.studentPrice = req.__User__.isStudent && result && result.goodsPrice && result.goodsPrice.studentPrice ? result.goodsPrice.studentPrice : false;
return res.json(result);
}).catch(next);
}
};
module.exports = newDetail;
... ...
/**
* 店铺重构
*/
'use strict';
const mRoot = '../models';
const listModel = require(`${mRoot}/list`);
const searchModel = require(`${mRoot}/search`);
const headerModel = require('../../../doraemon/models/header');
const _ = require('lodash');
const helpers = global.yoho.helpers;
const productProcess = require(`${utils}/product-process`);
const shop = {
index(req, res, next) {
let params = Object.assign({}, req.query);
let domain = req.query.domain;
let brandId = 0;
let brandLogo = {};
let title = '';
if (req.query.shop_id) {
return shop.shop(req, res, next);
}
if (!domain) {
res.redirect('/?go=1');
return;
}
listModel.getBrandLogoByDomain(domain).then(result => {
if (!result) {
return next();
}
brandLogo = result;
title = brandLogo.name;
if (brandLogo && brandLogo.id) {
brandId = brandLogo.id;
}
params.brand = brandId;
let searchParam = {
isApp: req.yoho.isApp,
brand: brandId,
type: 'newest',
order: '1',
page: 1,
limit: 4
};
if (req.query.from !== 'search' && brandLogo.type === '2' && brandLogo.shopId) {
req.query.shop_id = brandLogo.shopId;
shop.shop(req, res, next);
return false;
} else if (req.query.from === 'search') {
return Promise.all([listModel.getBrandShops(brandId, req), searchModel.getSearchData(searchParam)]).then(shopResult => {
let brandShop = shopResult[0];
let newGoods = shopResult[1];
params.newGoods = newGoods.list;
if (brandId === 0) {
params.query = domain;
}
if (brandShop.length > 0) {
params = _.assign({
brandWay: _.isEmpty(brandShop) ? brandLogo : brandShop,
search: {
default: req.query.query,
url: helpers.urlFormat('', null, 'search')
}
}, params);
}
return true;
});
} else {
params.brandHome = {
title: result.name,
id: result.id
};
return Promise.all([listModel.getBrandBanner(brandId), searchModel.getSearchData(searchParam)]).then(brandResult => {
let brandBanner = brandResult[0];
let newGoods = brandResult[1];
if (!brandBanner || !newGoods) {
res.set('Cache-Control', 'no-cache');
}
params.brandHome.banner = brandBanner;
params.newGoods = newGoods.list;
return true;
});
}
}).then((isBrand) => {
if (isBrand) {
res.render('newshop/brand', {
module: 'product',
page: 'brand-index',
pageHeader: headerModel.setNav({
navTitle: title !== '' ? title : domain
}),
goodList: params,
showDownloadApp: true,
pageFooter: true,
title: title + '|' + title + '潮流服装服饰-Yoho!Buy有货',
keywords: title + ',' + title + '服装服饰,' + title + '潮流服装服饰',
description: title + '|Yoho!Buy有货' + title + '潮流服饰官方授权店!100%品牌正品保证,支持货到付款。',
domain: req.query.domain,
shopPage: true,
_noLazy: true
});
}
}).catch(next);
},
shop(req, res, next) {
let isApp = req.query.app_version || req.query.appVersion || false;
let shopId = req.query.shop_id;
let uid = req.user.uid;
let channel = req.yoho.channel || 'boys';
let pageHeader = {};
// pagecache前端判断
if (!isApp) {
pageHeader = {
pageHeader: _.assign({
shopPage: {
text: '分类',
url: helpers.urlFormat('/product/index/category', {
shop_id: shopId
})
}
}, headerModel.setNav({
navTitle: false
}))
};
} else {
uid = req.query.uid;
req.session.appUid = uid;
res.cookie('appUid', uid, {
domain: 'yohobuy.com',
expires: new Date(Date.now() + 2592000000) // 有效期一年
});
}
return listModel.getShopIntro(shopId).then(shopInfoResult => {
let searchParam = {
isApp: req.yoho.isApp,
shop_id: shopId,
type: 'newest',
order: '1',
page: 1,
limit: 4
};
let shopInfo = shopInfoResult;
let seoResult = listModel.getBrandShopSeo(channel, shopInfoResult, req.query);
/* 基础店铺返回程序内的跳转信号,跳转到基础店铺 */
if (shopInfoResult && shopInfoResult.shop_template_type && parseInt(shopInfoResult.shop_template_type, 10) === 1) {
return Promise.all([listModel.getBaseShopData(req.query, shopInfo), searchModel.getSearchData(searchParam)]).then(fResult => {
let baseShop = fResult[0];
let newGoods = fResult[1];
baseShop.newGoods = newGoods.list;
if (baseShop && baseShop.baseShopHome && baseShop.baseShopHome.banner) {
if (baseShop.baseShopHome.banner.indexOf('?') < 0) {
baseShop.baseShopHome.banner += '?imageMogr2/auto-orient/strip/thumbnail/x150/crop/640x150';
}
}
res.render('newshop/shop-base', {
module: 'product',
page: 'shop.base',
pageHeader: headerModel.setNav({
navTitle: baseShop.shopName
}),
goodList: baseShop,
showDownloadApp: true,
pageFooter: true,
title: shopInfo.shop_name + '|' + shopInfo.shop_name + '潮流服装服饰-Yoho!Buy有货',
keywords: shopInfo.shop_name + ',' + shopInfo.shop_name + '服装服饰,' + shopInfo.shop_name + '潮流服装服饰',
description: shopInfo.shop_name + '|Yoho!Buy有货' + shopInfo.shop_name + '潮流服饰官方授权店!100%品牌正品保证,支持货到付款。',
shopId: shopId,
shopPage: true,
_noLazy: true
});
});
} else {
// 经典装修店铺
return Promise.all([listModel.getShopDecorator(shopId).then(), listModel.getShopCategoryApi(shopId, channel)]).then(fResult => {
let shopDeco = fResult[0];
let shopCategory = fResult[1];
let shopData = {
decorator: shopDeco, // 店铺装修资源数据
shopInfo: shopInfo, // 店铺信息
shopCategory: shopCategory
};
let result = listModel.formShopData(shopData, shopId, isApp);
result = _.assign(result, pageHeader, {shopId: shopId, coverChannel: channel, seoResult: seoResult});
res.render('newshop/shop-classics', {
module: 'product',
page: 'shop.classics',
shopIndex: result,
shopHeadHide: true,
gender: req.query.gender,
channel: req.query.channel,
title: result.seoTitle + '|' + result.seoTitle + '潮流服装服饰-Yoho!Buy有货',
keywords: result.seoTitle + ',' + result.seoTitle + '服装服饰,' + result.seoTitle + '潮流服装服饰',
description: result.seoTitle + '|Yoho!Buy有货' + result.seoTitle + '潮流服饰官方授权店!100%品牌正品保证,支持货到付款。',
shopId: shopId,
shopPage: true
});
});
}
}).catch(next);
},
_getUidFromUserAgent(req) {
let userAgent = _.split(req.headers['user-agent'], ';');
let uidString = '';
_.forEach(userAgent, value => {
if (_.startsWith(value, 'uid')) {
uidString = value;
return;
}
});
return _.split(uidString, '=')[1];
},
/**
* TODO TAR 店铺和品牌收藏状态调用新的接口
* 基础模板收藏
*/
baseShopFav(req, res, next) {
let allowOrigin = _.get(req, 'headers.origin', null) ?
req.headers.origin : req.protocol + '://' + req.headers.host;
res.setHeader('Access-Control-Allow-Origin', allowOrigin);
res.setHeader('Access-Control-Allow-Credentials', 'true');
let uid = req.user.uid || req.query.uid || req.cookies.appUid || _getUidFromUserAgent(req);
let shopId = req.query.shopId;
return listModel.getShopIntro(shopId, uid).then(result => {
res.json(Object.assign({code: 200}, result));
}).catch(next);
},
/**
* TODO TAR 店铺和品牌收藏状态调用新的接口
* @param req
* @param res
*/
brandFav(req, res, next) {
let brandId = req.query.brandId;
let uid = req.user.uid;
if (!brandId) {
return res.json({code: 404});
}
return listModel.getBrandIntro(brandId, uid).then(result => {
res.json(result);
}).catch(next);
},
shopHotList(req, res, next) {
let skns = req.query.skns;
let isApp = req.query.app_version || req.query.appVersion || false;
return listModel.searchProductBySkn(skns).then(hotList => {
hotList = productProcess.processProductList(hotList, {isApp: isApp});
_.forEach(hotList, (value, key) => {
hotList[key].tags = {};
hotList[key].is_soon_sold_out = false;
hotList[key].tags.is_hot = true;
});
res.render('newshop/shop-hotlist', {
hotList: hotList,
layout: false,
_noLazy: true
});
}).catch(next);
}
};
/**
* 从 useragent 获取 uid
* @returns {*}
* @private
*/
const _getUidFromUserAgent = (req) => {
let userAgent = _.split(req.headers['user-agent'], ';');
let uidString = '';
_.forEach(userAgent, value => {
if (_.startsWith(value, 'uid')) {
uidString = value;
return;
}
});
return _.split(uidString, '=')[1];
};
module.exports = shop;
... ...
... ... @@ -63,7 +63,7 @@ const selectNewSale = (req, res, next) => {
let params = _.assign({}, req.query);
newModel.getSearchData(params).then((result) => {
if (result.list.length > 0) {
if (result.list && result.list.length > 0) {
res.render('search/page', {
layout: false,
new: result.list,
... ...
'use strict';
const mRoot = '../models';
const headerModel = require('../../../doraemon/models/header'); // 头部model
const mayLikeModel = require('../models/recom');
/**
... ... @@ -41,7 +39,7 @@ const mayLike = (req, res, next) => {
* 你可能喜欢的潮童的商品列表
*/
const mayLikeKids = (req, res, next) => {
let page = req.body.page || 1;
let page = req.query.page || 1;
let limit = 50;
let channel = req.query.channel || 3;
... ...
... ... @@ -29,37 +29,34 @@ const list = (req, res, next) => {
params.shopId = params.shop_id;
}
params.isApp = req.yoho.isApp;
return searchModel.searchKeyActivity(params.query || '').then(activityResult => {
let activity = _.get(activityResult, 'urlobj.appUrl', '');
if (activity) {
return res.redirect(activity);
} else {
// 获取第一页数据做服务端渲染
let initialData = _.assign({
type: 'default',
order: '0',
page: 1,
limit: 12
}, params);
if (query) {
query = query.toLowerCase();
}
/* 判断是不是品牌, 是品牌跳到品牌列表页(显示搜索框),判断是不是品类, 是品类加导航标题(不显示搜索框) */
return Promise.all([
searchModel.getAllBrandNames(),
searchModel.getClassNames()
searchModel.getBrandDomain(query),
searchModel.getClassNames(),
searchModel.getSearchData(initialData)
]).then(result => {
if (query) {
query = query.toLowerCase();
_.forEach(result[0], obj => {
if (query === obj.brandDomain) { // 精确查品牌域名
domain = query;
return false;
}
if (query === obj.brandName || query === obj.brandName || query === obj.brandName) { // 精确查品牌名称
domain = obj.brandDomain;
return false;
}
// if (obj.brandDomain.indexOf(query) > 0) { // 模糊查品牌域名
// domain = obj.brandDomain;
// return false;
// }
});
domain = result[0];
// 跳转到品牌商品列表页
if (domain !== null && !params.shop_id) {
... ... @@ -114,6 +111,7 @@ const list = (req, res, next) => {
title = params.title ? params.title : title;
res.render('search/list', {
_noLazy: true,
module: 'product',
page: 'search-list',
pageHeader: headerModel.setNav({
... ... @@ -121,7 +119,9 @@ const list = (req, res, next) => {
}),
title: title,
goodList: params,
pageFooter: true
firstPageGoodsList: result[2].list || [],
pageFooter: true,
shopId: params.shop_id || ''
});
}).catch(next);
}
... ... @@ -183,17 +183,25 @@ const search = (req, res, next) => {
let params = Object.assign({}, req.query);
params.isApp = req.yoho.isApp;
params.limit = 24;
searchModel.getSearchData(params).then((result) => {
if (result && result.list && result.list.length > params.start &&
parseInt(params.page) === 1 && parseInt(params.start) > 0) {
// 首屏渲染时,使用 'start' 参数裁减已渲染数据
result.list = result.list.slice(params.start || 0);
}
if (result.list && result.list.length > 0) {
res.render('search/page', {
layout: false,
new: result.list,
total: result.total
total: result.total,
_noLazy: params.noLazy || false
});
} else {
res.json(result);
}
}).catch(next);
};
... ...
... ... @@ -247,7 +247,7 @@ exports.consultsubmit = (req, res, next) => {
data: ''
};
// 判断参数是否存在
// 判断参数是否存在
if (!req.body.product_id || !req.body.content) {
return res.json(data);
}
... ... @@ -294,7 +294,8 @@ exports.indexSkn = (req, res, next) => {
result: result,
page: 'seckill-detail',
title: result.goodsName,
pageFooter: true
pageFooter: true,
localCss: true
});
}).catch(next);
};
... ... @@ -333,7 +334,8 @@ exports.index = (req, res, next) => {
result: result,
page: 'seckill-detail',
title: result.goodsName,
pageFooter: true
pageFooter: true,
localCss: true
});
}).catch(next);
};
... ... @@ -344,7 +346,7 @@ exports.index = (req, res, next) => {
* @param {[type]} res [description]
* @return {[type]} [description]
*/
exports.indexData = (req, res, next)=> {
exports.indexData = (req, res, next) => {
if (!req.xhr) {
return next();
}
... ... @@ -361,7 +363,10 @@ exports.indexData = (req, res, next)=> {
ua: req.get('user-agent') || ''
}, req.__User__)).then((result) => {
if (_.isEmpty(result)) {
return res.json({code: 400, message: '数据错误'});
return res.json({
code: 400,
message: '数据错误'
});
}
result.studentPrice = req.__User__.isStudent && result && result.goodsPrice && result.goodsPrice.studentPrice ? result.goodsPrice.studentPrice : false;
return res.json(result);
... ...
... ... @@ -13,7 +13,7 @@ const helpers = global.yoho.helpers;
/**
* 获取默认咨询列表
*/
const _getCommonConsult = () => {
const getCommonConsult = () => {
let params = {
method: 'app.consult.common'
};
... ... @@ -163,7 +163,7 @@ let comments = (params) => {
*/
let consults = (params, uid) => {
return api.all([
_getCommonConsult(),
getCommonConsult(),
getConsults(params.product_id, 1, 60, uid)
]).then(result => {
let data = {
... ... @@ -217,6 +217,7 @@ let addConsult = (uid, productId, content) => {
};
module.exports = {
getCommonConsult, // 默认咨询
getCommentInfo, // 商品详情相关,获取评价,来自晒单
comments, // 商品详情相关-购买评价
consults, // 商品详情相关-购买咨询
... ...
... ... @@ -14,7 +14,7 @@ exports.queryProdPageCoupons = (uid, skn, brandId) => {
brandId
};
return api.get('', param, {cache: true});
return api.get('', param);
};
/**
... ...
... ... @@ -71,7 +71,7 @@ const _processShopsInfo = (data) => {
const _procShowStatus = (data, showStatus, isBeginSale) => {
switch (showStatus) {
case 1: // 开售前/后,立即分享获得限购码(用户未领取限购码)
// 显示获取限购码按钮
// 显示获取限购码按钮
data.canGetLimitCode = true;
if (isBeginSale) { // 开售后
... ... @@ -119,7 +119,7 @@ const _procShowStatus = (data, showStatus, isBeginSale) => {
*/
const _getLimitCodeUrl = (productCode, skn, ua) => {
let url = 'yohoapp://yoho.app/openwith?limit_product_code=' + productCode +
'&product_skn=' + skn;
'&product_skn=' + skn;
let isIphone = String(ua).indexOf('iPhone') >= 0;
let isIpad = ua.indexOf('iPad') >= 0;
... ... @@ -958,7 +958,7 @@ let _getPromotionInfo = (skn) => {
*/
let _getFavorite = (productId, uid) => {
if (!uid) {
return Promise.resolve({});
return Promise.resolve(false);
}
return singleAPI.get('favorite', {
method: 'app.favorite.isFavoriteNew',
... ... @@ -969,7 +969,7 @@ let _getFavorite = (productId, uid) => {
return result.data;
}
return {};
return false;
});
};
... ... @@ -1103,7 +1103,7 @@ let getProductData = (data) => {
Object.assign(finalResult.feedbacks, info[1]);
/* 如果有咨询,显示咨询,否则显示常见问题 */
/* 如果有咨询,显示咨询,否则显示常见问题 */
if (info[3].total) {
finalResult.feedbacks.consultsNum = parseInt(info[3].total, 10);
... ... @@ -1148,7 +1148,7 @@ const _detailDataPkg = (origin, ua) => {
// 是否是虚拟商品
dest.virtualGoods = (origin.attribute * 1 === 3);
// 用户未登录时 pagecache重构
// 用户未登录时 pagecache重构
// if (!uid) {
// dest.loginUrl = helpers.urlFormat('/signin.html', {
// refer: helpers.urlFormat('/product/show_' + origin.product_skn + '.html')
... ... @@ -1158,7 +1158,7 @@ const _detailDataPkg = (origin, ua) => {
// 商品促销短语
origin.sales_phrase && (dest.goodsSubtitle = origin.sales_phrase);
// 促销信息 TODO: 换新接口 pagecache重构
// 促销信息 TODO: 换新接口 pagecache重构
// if (origin.promotionBoList) {
// let discountList = [];
... ... @@ -1223,7 +1223,7 @@ const _detailDataPkg = (origin, ua) => {
// 上市期
origin.expect_arrival_time && (dest.periodOfMarket = origin.expect_arrival_time);
// 商品咨询
// 商品咨询
dest.feedbacks = {
consults: [],
consultsNum: 0
... ... @@ -1245,7 +1245,7 @@ const _detailDataPkg = (origin, ua) => {
product_id: origin.product_id
});
// 品牌信息
// 品牌信息
if (origin.brand_info) {
let extra = `?productSkn=${origin.product_skn}&brandId=${origin.brand_info.brand_id}`;
... ... @@ -1256,17 +1256,17 @@ const _detailDataPkg = (origin, ua) => {
dest.productSkn = origin.product_skn;
dest.isLimitBuy = Number(origin.isLimitBuy); // 1 限购商品, 0 非限购商品
// 商品信息
// 商品信息
if (origin.goods_list.length) {
let goodsGroup = [];
// pagecache重构
// sizeName = '',
// colorList = [],
// sizeList = {},
// allSizeList = {},
// colorStorageGroup = {},
// colorStorageNum = 0;
// sizeName = '',
// colorList = [],
// sizeList = {},
// allSizeList = {},
// colorStorageGroup = {},
// colorStorageNum = 0;
// pagecache重构
_.forEach(origin.goods_list, function(value) {
// 未上架也显示
... ... @@ -1274,7 +1274,7 @@ const _detailDataPkg = (origin, ua) => {
// return;
// }
// colorStorageNum = 0;
// colorStorageNum = 0;
// 商品分组
if (value.images_list) {
... ... @@ -1286,108 +1286,108 @@ const _detailDataPkg = (origin, ua) => {
});
}
// // 商品的尺码列表
// colorStorageGroup[value.product_skc] = {};
// if (value.size_list) {
// sizeList[value.product_skc] = [];
// _.forEach(value.size_list, function(size) {
// sizeList[value.product_skc].push({
// id: size.size_id,
// skuId: size.product_sku,
// goodsId: value.goods_id,
// colorId: value.color_id,
// name: size.size_name,
// sizeNum: size.storage_number
// });
// sizeName = size.size_name;
// // 所有尺码列表,赋值用于前端展示默认尺码的时候
// // 判断出没有库存则显示灰色
// let build = {
// id: size.size_id,
// storage: size.storage_number
// };
// allSizeList[sizeName] = (allSizeList[sizeName] === null ||
// typeof allSizeList[sizeName] === 'undefined') ? build : allSizeList[sizeName];
// colorStorageNum += parseInt(size.storage_number, 10);
// colorStorageGroup[value.product_skc][sizeName] = parseInt(size.storage_number, 10);
// });
// // 颜色分组
// colorList.push({
// id: value.color_id,
// skcId: value.product_skc,
// name: value.color_name,
// colorNum: colorStorageNum
// });
// }
// // 缩略图
// thumbImageList.push({
// img: value.color_image
// });
// // 商品库存总数
// totalStorageNum += _.toNumber(colorStorageNum);
// });
// // 遍历所有尺码,构建颜色显示数据
// let i = 1;
// sizeGroup[0] = {
// size: []
// };
// _.forEach(allSizeList, (value, key) => {
// // 默认尺码
// sizeGroup[0].size.push({
// name: key,
// sizeNum: _.toNumber(value.storage) > 0 ? true : false,
// id: value.id
// });
// colorGroup[i] = {
// color: []
// };
// // 各个颜色的尺码, 每行显示一个尺码对应的颜色
// _.forEach(colorList, (colorArr) => {
// let tempColorArr = _.cloneDeep(colorArr);
// if (colorStorageGroup[tempColorArr.skcId] &&
// colorStorageGroup[tempColorArr.skcId][key]) {
// tempColorArr.colorNum = colorStorageGroup[tempColorArr.skcId][key];
// } else {
// tempColorArr.colorNum = 0;
// }
// colorGroup[i].color.push(Object.assign({}, tempColorArr));
// });
// colorGroup[i].id = value.id;
// ++i;
// });
// colorGroup[0] = {
// color: []
// };
// // 遍历所有颜色, 构建尺码显示数据
// i = 1;
// _.forEach(colorList, function(value) {
// // 各个尺码的颜色, 每行显示一个颜色的对应尺码
// sizeGroup[i] = {
// size: sizeList[value.skcId],
// colorId: value.skcId
// };
// // 默认颜色
// colorGroup[0].color.push(value);
// ++i;
// // 商品的尺码列表
// colorStorageGroup[value.product_skc] = {};
// if (value.size_list) {
// sizeList[value.product_skc] = [];
// _.forEach(value.size_list, function(size) {
// sizeList[value.product_skc].push({
// id: size.size_id,
// skuId: size.product_sku,
// goodsId: value.goods_id,
// colorId: value.color_id,
// name: size.size_name,
// sizeNum: size.storage_number
// });
// sizeName = size.size_name;
// // 所有尺码列表,赋值用于前端展示默认尺码的时候
// // 判断出没有库存则显示灰色
// let build = {
// id: size.size_id,
// storage: size.storage_number
// };
// allSizeList[sizeName] = (allSizeList[sizeName] === null ||
// typeof allSizeList[sizeName] === 'undefined') ? build : allSizeList[sizeName];
// colorStorageNum += parseInt(size.storage_number, 10);
// colorStorageGroup[value.product_skc][sizeName] = parseInt(size.storage_number, 10);
// });
// // 颜色分组
// colorList.push({
// id: value.color_id,
// skcId: value.product_skc,
// name: value.color_name,
// colorNum: colorStorageNum
// });
// }
// // 缩略图
// thumbImageList.push({
// img: value.color_image
// });
// // 商品库存总数
// totalStorageNum += _.toNumber(colorStorageNum);
// });
// // 遍历所有尺码,构建颜色显示数据
// let i = 1;
// sizeGroup[0] = {
// size: []
// };
// _.forEach(allSizeList, (value, key) => {
// // 默认尺码
// sizeGroup[0].size.push({
// name: key,
// sizeNum: _.toNumber(value.storage) > 0 ? true : false,
// id: value.id
// });
// colorGroup[i] = {
// color: []
// };
// // 各个颜色的尺码, 每行显示一个尺码对应的颜色
// _.forEach(colorList, (colorArr) => {
// let tempColorArr = _.cloneDeep(colorArr);
// if (colorStorageGroup[tempColorArr.skcId] &&
// colorStorageGroup[tempColorArr.skcId][key]) {
// tempColorArr.colorNum = colorStorageGroup[tempColorArr.skcId][key];
// } else {
// tempColorArr.colorNum = 0;
// }
// colorGroup[i].color.push(Object.assign({}, tempColorArr));
// });
// colorGroup[i].id = value.id;
// ++i;
// });
// colorGroup[0] = {
// color: []
// };
// // 遍历所有颜色, 构建尺码显示数据
// i = 1;
// _.forEach(colorList, function(value) {
// // 各个尺码的颜色, 每行显示一个颜色的对应尺码
// sizeGroup[i] = {
// size: sizeList[value.skcId],
// colorId: value.skcId
// };
// // 默认颜色
// colorGroup[0].color.push(value);
// ++i;
});
// 商品图:多个
// 商品图:多个
if (goodsGroup.length > 1) {
let bannerList = [];
... ... @@ -1407,7 +1407,7 @@ const _detailDataPkg = (origin, ua) => {
}
}
// 悬浮的购物车信息
// 悬浮的购物车信息
dest.cartInfo = {
cartUrl: helpers.urlFormat('/cart/index/index'),
numInCart: 0,
... ... @@ -1418,53 +1418,53 @@ const _detailDataPkg = (origin, ua) => {
// let soldOut = (origin.storage_sum === 0) || (totalStorageNum === 0); // status
// let notForSale = origin.attribute === 2;
// 显示加入购物车链接 pagecache重构
// if (!soldOut && !notForSale) {
// _.orderBy(colorGroup);
// Object.assign(dest.cartInfo, {
// productId: origin.product_id,
// thumbs: thumbImageList,
// name: dest.goodsName ? dest.goodsName : '',
// price: dest.goodsPrice.previousPrice ? dest.goodsPrice.previousPrice : '',
// salePrice: dest.goodsPrice.currentPrice ? dest.goodsPrice.currentPrice : '',
// totalNum: totalStorageNum,
// colors: _.toArray(colorGroup),
// sizes: sizeGroup
// });
// // 限购商品
// if (origin.isLimitBuy) {
// // 是否开售
// let isBeginSale = (origin.saleStatus === 1);
// // 限购商品有关的展示状态
// let showStatus = 1;
// origin.showStatus && (showStatus = parseInt(origin.showStatus, 10));
// // 处理限购商品有关的按钮状态
// dest = _procShowStatus(dest, showStatus, isBeginSale);
// dest.cartInfo.limitProductCode = origin.limitProductCode;
// dest.cartInfo.limitCodeUrl = _getLimitCodeUrl(origin.limitProductCode, origin.product_skn, ua);
// dest.cartInfo.limitProductPay = helpers.urlFormat('/cart/index/orderEnsure');
// } else {
// dest.cartInfo.addToCartUrl = helpers.urlFormat('/product/buy_' + origin.product_id + '_' +
// origin.goods_list.goods_id + '.html');
// }
// } else if (notForSale) {
// dest.cartInfo.notForSale = true;
// } else if (soldOut) {
// dest.cartInfo.soldOut = true;
// }
// // 是否收藏
// dest.isCollect = false;
// if (origin.is_collect === 'Y') {
// dest.isCollect = true;
// dest.cartInfo.isCollect = true;
// }
// 显示加入购物车链接 pagecache重构
// if (!soldOut && !notForSale) {
// _.orderBy(colorGroup);
// Object.assign(dest.cartInfo, {
// productId: origin.product_id,
// thumbs: thumbImageList,
// name: dest.goodsName ? dest.goodsName : '',
// price: dest.goodsPrice.previousPrice ? dest.goodsPrice.previousPrice : '',
// salePrice: dest.goodsPrice.currentPrice ? dest.goodsPrice.currentPrice : '',
// totalNum: totalStorageNum,
// colors: _.toArray(colorGroup),
// sizes: sizeGroup
// });
// // 限购商品
// if (origin.isLimitBuy) {
// // 是否开售
// let isBeginSale = (origin.saleStatus === 1);
// // 限购商品有关的展示状态
// let showStatus = 1;
// origin.showStatus && (showStatus = parseInt(origin.showStatus, 10));
// // 处理限购商品有关的按钮状态
// dest = _procShowStatus(dest, showStatus, isBeginSale);
// dest.cartInfo.limitProductCode = origin.limitProductCode;
// dest.cartInfo.limitCodeUrl = _getLimitCodeUrl(origin.limitProductCode, origin.product_skn, ua);
// dest.cartInfo.limitProductPay = helpers.urlFormat('/cart/index/orderEnsure');
// } else {
// dest.cartInfo.addToCartUrl = helpers.urlFormat('/product/buy_' + origin.product_id + '_' +
// origin.goods_list.goods_id + '.html');
// }
// } else if (notForSale) {
// dest.cartInfo.notForSale = true;
// } else if (soldOut) {
// dest.cartInfo.soldOut = true;
// }
// // 是否收藏
// dest.isCollect = false;
// if (origin.is_collect === 'Y') {
// dest.isCollect = true;
// dest.cartInfo.isCollect = true;
// }
// 底部简介URL链接
dest.introUrl = '/product/detail/intro/' + origin.product_skn;
... ... @@ -1484,6 +1484,82 @@ const _detailDataPkg = (origin, ua) => {
return dest;
};
const _cartCount = (uid, shoppingKey) => {
return api.get('', {
method: 'app.Shopping.count',
uid: uid,
shopping_key: shoppingKey
}).then((result) => {
if (result.code === 200) {
var count = result.data.cart_goods_count || 0;
if (count > 99) {
count = '99+';
}
return count;
}
return 0;
});
};
/**
* [商品信息的异步数据获取] (优化)
*/
let getNewProductAsyncData = (data) => {
let finalResult;
let params = {
method: 'app.product.data'
};
if (data.id) { // 通过 productId 获取商品详情
Object.assign(params, {
product_id: _.toString(data.id)
});
} else if (data.productSkn) { // 通过 productSkn 获取商品详情
Object.assign(params, {
product_skn: _.toString(data.productSkn)
});
}
if (data.uid) {
params.uid = data.uid;
}
params.is_student = data.isStudent ? 1 : 0;
params.current_vip_level = data.vipLevel;
// if (!params.is_student) {
// params.current_vip_level = data.vipLevel;
// }
return api.get('', params, {
code: 200,
cache: true
}).then(result => {
if (result.code === 500 || !result.data) {
return {};
}
result = result.data;
result.goods_id = data.goodsId;
return Promise.all([_cartCount(data.uid, data.shoppingKey), _detailDataPkgAsync(result, data.uid, data.vipLevel, data.ua), _getFavorite(result.product_id, data.uid)]).then((res) => {
var cartCount = res[0];
var finalResult = res[1];
var isFavorite = res[2];
if (cartCount) {
finalResult.cartCount = cartCount;
}
finalResult.isCollect = isFavorite;
if (finalResult.cartInfo) {
finalResult.cartInfo.isCollect = isFavorite;
}
finalResult.isStudent = data.isStudent;
return finalResult;
});
});
};
/**
* [商品信息的异步数据获取]
*/
... ... @@ -1587,15 +1663,18 @@ let _detailDataPkgAsync = (origin, uid, vipLevel, ua) => {
goodsPrice.previousPrice = origin.format_market_price;
}
if (origin.student_price) {
goodsPrice.studentPrice = origin.student_price;
}
dest.goodsPrice = goodsPrice;
if (origin.is_secKill) {
dest.isSecKill = origin.is_secKill;// 判断秒杀字段
dest.isSecKill = origin.is_secKill; // 判断秒杀字段
}
if (origin.is_secKill) {
dest.isDepositAdvance = origin.isDeposit_advance;// A定金预售字段 = origin.is_deposit_advance === 'Y'; // 是否定金预售
dest.isPresale = Boolean(origin.expect_arrival_time)
dest.isDepositAdvance = origin.is_deposit_advance; // 判断定金预售字段
}
// 商品返回 YOHO 币
... ... @@ -1668,15 +1747,15 @@ let _detailDataPkgAsync = (origin, uid, vipLevel, ua) => {
sizeName = size.size_name;
// 所有尺码列表,赋值用于前端展示默认尺码的时候
// 判断出没有库存则显示灰色
// 所有尺码列表,赋值用于前端展示默认尺码的时候
// 判断出没有库存则显示灰色
let build = {
id: size.size_id,
storage: size.storage_number
};
allSizeList[sizeName] = (allSizeList[sizeName] === null ||
typeof allSizeList[sizeName] === 'undefined') ? build : allSizeList[sizeName];
typeof allSizeList[sizeName] === 'undefined') ? build : allSizeList[sizeName];
colorStorageNum += parseInt(size.storage_number, 10);
colorStorageGroup[value.product_skc][sizeName] = parseInt(size.storage_number, 10);
});
... ... @@ -1722,7 +1801,7 @@ let _detailDataPkgAsync = (origin, uid, vipLevel, ua) => {
let tempColorArr = _.cloneDeep(colorArr);
if (colorStorageGroup[tempColorArr.skcId] &&
colorStorageGroup[tempColorArr.skcId][key]) {
colorStorageGroup[tempColorArr.skcId][key]) {
tempColorArr.colorNum = colorStorageGroup[tempColorArr.skcId][key];
} else {
tempColorArr.colorNum = 0;
... ... @@ -1846,20 +1925,20 @@ let _detailDataPkgAsync = (origin, uid, vipLevel, ua) => {
if (origin.product_skn * 1 === SINGLE_TICKETS_SKN) {
dest.single = true;
} else {
// 套票
// 套票
dest.package = true;
}
// 购票限制
// 购票限制
dest.cartInfo.limit = 4;
// 清空活动
// 清空活动
dest.goodsDiscount = [];
// 来自登录页,自动弹出选择框
// if (isset($_GET['product_type']) && $_GET['product_type'] == 'ticket') {
// $result['showPannel'] = true;
// }
// 来自登录页,自动弹出选择框
// if (isset($_GET['product_type']) && $_GET['product_type'] == 'ticket') {
// $result['showPannel'] = true;
// }
}
dest.id = origin.product_id;
dest.goodsId = origin.goods_id;
... ... @@ -1927,6 +2006,7 @@ let _productInfoBySkns = (skns) => {
module.exports = {
getProductData,
getProductAsyncData,
getNewProductAsyncData,
getUserProfile: _getUserProfile,
productInfoBySkns: _productInfoBySkns
};
... ...
... ... @@ -122,6 +122,20 @@ const _getShopInfo = (shopId, uid) => {
};
/**
* 调取店铺简介数据
* @param {int} shopId
*/
const getShopIntro = (shopId, uid) => {
return api.get('', {
method: 'app.shops.getIntro',
shop_id: shopId,
uid: uid
}, {code: 200}).then(result => {
return result.data;
});
};
/**
* 获取店铺下面的所有分类
* @param {int} shopId 店铺id
* @param {string} channel 频道
... ... @@ -133,7 +147,7 @@ const _getShopCategory = (shopId, channel, gender) => {
yh_channel: yhChannel[channel],
gender: gender || '1,3',
shop_id: shopId
}, {code: 200}).then(result => {
}, {code: 200, cache: true}).then(result => {
return result.data;
});
};
... ... @@ -245,7 +259,7 @@ const getShopBrands = (shopId) => {
return api.get('', {
method: 'app.shops.getShopsBrands',
shop_id: shopId
}, {code: 200}).then((result) => {
}, {code: 200, cache: true}).then((result) => {
if (result[0]) {
return result[0].brand_id;
}
... ... @@ -262,7 +276,7 @@ const searchProductBySkn = (productSkn) => {
return api.get('', {
method: 'h5.product.batch',
productSkn: productSkn
}, {code: 200}).then(result => {
}, {code: 200, cache: true}).then(result => {
return _.get(result, 'data.product_list', []);
});
};
... ... @@ -452,7 +466,7 @@ const _formShopData = (data, shopId, isApp) => {
}, formatData);
} else {
formatData = _.assign({
allGoods: `${helpers.urlFormat('', allGoodsParam, 'search')}&openby:yohobuy={"action":"go.list","params":{"title":"全部商品", "actiontype":"0","shop_id":${shopId},"page":"1"}}`,//eslint-disable-line
allGoods: `${helpers.urlFormat('', allGoodsParam, 'search')}&openby:yohobuy={"action":"go.list","params":{"title":"全部商品", "actiontype":"0","shop_id":${shopId}}}`,//eslint-disable-line
shopIntroHref: helpers.urlFormat('/product/index/intro', {
shop_id: shopId,
app_version: isApp
... ... @@ -517,7 +531,6 @@ const getBaseShopData = (params, shopInfo) => {
_getShopDecorator(shopId),
getShopBrands(shopId)
]).then(result => {
if (result[0] && _.has(result[0], 'list')) {
_.forEach(result[0].list, item => {
if (item.resource_name === 'shopTopBanner_base') {
... ... @@ -610,6 +623,9 @@ const getShopData = (req, shopId, uid, isApp) => {
shopFilterSearchData.goods = productProcess.processProductList(result[0].product_list || [], {isApp: isApp});
}
/* 店铺优惠券 */
let shopCoupons = result[1] || [];
// 店铺分类
return _getShopCategory(shopId, channel).then(shopCategory => {
... ... @@ -797,19 +813,6 @@ const setFavoriteCancel = (id, uid, type) => {
};
/**
* 调取店铺简介数据
* @param {int} shopId
*/
const getShopIntro = (shopId) => {
return api.get('', {
method: 'app.shops.getIntro',
shop_id: shopId
}, {code: 200, cache: true}).then(result => {
return result.data;
});
};
/**
* 处理店铺品类
* @param params
*/
... ... @@ -953,9 +956,13 @@ module.exports = {
getShopBrands,
getShopCategory,
receiveCoupon,
shopCouponsList,
brandCouponsList,
getShopFav,
searchProductBySkn,
getBrandFavStatus,
shopCouponsList,
brandCouponsList
getShopDecorator: _getShopDecorator,
getShopCategoryApi: _getShopCategory,
formShopData: _formShopData,
getBrandShopSeo: _getBrandShopSeo
};
... ...
/**
* [商品获取数据]
*/
'use strict';
const _ = require('lodash');
const commentModel = require('./consult-comment');
const api = global.yoho.API;
const helpers = global.yoho.helpers;
const tool = {
prodessDetailData(origin) {
let dest = {}; // 结果输出
// 商品名称
if (!origin.product_name) {
return dest;
}
dest.goodsName = origin.product_name;
// 是否是虚拟商品
// dest.virtualGoods = (origin.attribute * 1 === 3);
// 商品促销短语
origin.sales_phrase && (dest.goodsSubtitle = origin.sales_phrase);
// 商品标签
if (origin.tags) {
let productTags = {};
_.forEach(origin.tags, function(value) {
productTags[value] = true;
});
dest.tags = productTags;
}
// 商品价格
let goodsPrice = {
currentPrice: origin.format_sales_price === '0' ? origin.format_market_price : origin.format_sales_price
};
if (origin.format_sales_price !== '0' && origin.format_market_price !== origin.format_sales_price) {
goodsPrice.previousPrice = origin.format_market_price;
}
dest.goodsPrice = goodsPrice;
// 商品返回 YOHO 币
// origin.yohoCoinNum && (dest.commodityReturn = origin.yohoCoinNum);
// 上市期
origin.expect_arrival_time && (dest.periodOfMarket = origin.expect_arrival_time);
// 品牌信息
if (origin.brand_info) {
let extra = `?productSkn=${origin.product_skn}&brandId=${origin.brand_info.brand_id}`;
dest.preferenceUrl = `/product/detail/preference${extra}`;
}
dest.brandId = origin.brand_info.brand_id || 0;
dest.productSkn = origin.product_skn;
dest.id = origin.product_id;
dest.goodsId = origin.goods_id;
dest.isDepositAdvance = origin.is_deposit_advance === 'Y'; // 是否定金预售
dest.isSeckill = origin.is_secKill === 'Y'; // 是否秒杀
dest.isLimitBuy = origin.isLimitBuy; // 是否 限购
dest.isPresale = Boolean(origin.expect_arrival_time); // 是否普通预售
// 自定义 属性
dest.showCoupon = !(
dest.isDepositAdvance || dest.isSeckill || dest.isLimitBuy || dest.isPresale
); // 商品有限购、秒杀、定金预售、普通预售 不显示领
// 商品信息
if (origin.goods_list.length) {
let goodsGroup = [];
// pagecache重构
_.forEach(origin.goods_list, function(value) {
// 商品分组
if (value.images_list) {
_.forEach(value.images_list, function(good) {
goodsGroup.push({
goodsId: value.goods_id,
img: good.image_url
});
});
}
});
// 商品图:多个
if (goodsGroup.length > 1) {
let bannerList = [];
_.forEach(goodsGroup, function(value) {
value.img = _.replace(value.img, '/quality/80', '/quality/70');
bannerList.push({
img: value.img
});
});
dest.bannerTop = {
list: bannerList
};
} else if (goodsGroup[0]) {
dest.bannerTop = {
img: goodsGroup[0].img
};
}
}
// 底部简介URL链接
dest.introUrl = '/product/detail/intro/' + origin.product_skn;
return dest;
},
/**
* 处理品牌关联店铺信息
* @param {array}
* @return {array}
*/
processShopsInfo(data) {
let enterStore = [];
_.forEach(data, function(value) {
let shopInfo = {
img: value.brand_ico,
storeName: value.brand_name
};
if (value.shop_id) {
shopInfo.url = helpers.urlFormat('/product/index/brand', {
shop_id: value.shop_id
});
} else {
shopInfo.url = helpers.urlFormat('', null, value.brand_domain);
}
enterStore.push(shopInfo);
});
return enterStore;
},
/**
* 处理商品 feedback
* @param data feedback要处理数据
* {
* comment, defaultConsult, userConsult
* }
* @param productId 商品id
* @return feedback
*/
processFeedback(data, productId) {
// let {comment, defaultConsult, userConsult} = data;
let comment = data.comment;
let defaultConsult = data.defaultConsult;
let userConsult = data.userConsult;
let feedbacks = {consults: [], consultsNum: 0};
Object.assign(feedbacks, comment);
// 商品评价
feedbacks.commentsUrl = helpers.urlFormat('/product/detail/comments', {
product_id: productId
});
/* 如果有用户咨询,显示用户咨询,否则显示常见问题 */
let obj = {};
if (userConsult.total) {
obj = {
commonConsults: false,
consultsNum: parseInt(userConsult.total, 10),
consults: _.take(userConsult.list, 2)
};
} else if (!_.isEmpty(defaultConsult) && !_.get(comment, 'consultsNum', 0)) {
obj = {
commonConsults: true,
consultsNum: true,
consults: _.take(defaultConsult.faq, 2)
};
}
Object.assign(feedbacks, obj);
if (_.get(feedbacks, 'consultsNum')) {
feedbacks.consultsUrl = helpers.urlFormat('/product/detail/consults', {
product_id: productId,
total: feedbacks.consultsNum
});
} else {
feedbacks.consultsUrl = helpers.urlFormat('/product/detail/consultform', {
product_id: productId
});
}
return feedbacks;
}
};
const newDetail = {
getProductData(data) {
let params = {
method: 'app.product.data'
};
if (data.id) { // 通过 productId 获取商品详情
Object.assign(params, {
product_id: data.id
});
} else if (data.productSkn) { // 通过 productSkn 获取商品详情
Object.assign(params, {
product_skn: data.productSkn
});
}
return api.get('', params, {
code: 200,
cache: true
}).then(result => {
if (result.code === 500 || !result.data) {
return {};
}
result.data.goods_id = data.goodsId;
return tool.prodessDetailData(result.data);
});
},
/*
获取 促销,评论,咨询,品牌信息
*/
querySknData(params) {
let brandId = params.brandId;
let productId = params.productId;
let skn = params.skn;
return Promise.all([
this.queryShopsByBrandId(brandId), // 0 品牌信息
commentModel.getCommentInfo({
productId: productId
}), // 1 评论信息
commentModel.getCommonConsult(), // 2 默认咨询信息
commentModel.getConsults(productId, 1, 2), // 3 咨询列表
this.queryPromotion(skn) // 4 促销活动
]).then(info => {
let finalResult = {
promotion: null,
enterStore: null,
feedbacks: {
consults: [],
consultsNum: 0
},
};
finalResult.promotion = info[4];
finalResult.enterStore = info[0];
finalResult.feedbacks = tool.processFeedback({
comment: info[1],
defaultConsult: info[2],
userConsult: info[3]
}, productId);
return finalResult;
});
},
// ------------------------------接口
/*
接口: 根据BrandID, 查询品牌信息
*/
queryShopsByBrandId(brandId) {
let params = {
method: 'app.shop.queryShopsByBrandId',
brand_id: brandId
};
let cacheConf = {
cache: true
};
return api.get('', params, cacheConf)
.then(result => {
if (result.code === 200) {
return tool.processShopsInfo(result.data);
}
return [];
}, () => []);
},
/**
* 接口: 商品 促销活动
*/
queryPromotion(skn) {
let params = {
method: 'app.product.promotion',
product_skn: skn
};
let cacheConf = {
cache: true
};
return api.get('', params, cacheConf)
.then(result => {
if (result && result.code === 200) {
return result.data;
}
return {};
});
}
};
module.exports = newDetail;
... ...
... ... @@ -11,6 +11,8 @@ const _ = require('lodash');
const logger = global.yoho.logger;
const api = global.yoho.API;
const camelCase = global.yoho.camelCase;
const cache = require('memory-cache');
/**
* 封面图
... ... @@ -28,6 +30,8 @@ const _coverChannel = {
*/
const _processBrandNames = (list) => {
const formatData = [];
const brandDomainMap = {}, brandNameMap = {};
const ttl = 60000; // 默认缓存一分钟
list = list || [];
list = camelCase(list);
... ... @@ -38,9 +42,20 @@ const _processBrandNames = (list) => {
brandDomain: obj.brandDomain && obj.brandDomain.toLowerCase(),
brandName: obj.brandDomain && obj.brandName.toLowerCase()
});
if (obj && obj.brandDomain) {
brandDomainMap[obj.brandDomain.toLowerCase()] = obj.brandDomain.toLowerCase();
}
if (obj && obj.brandName && obj.brandDomain) {
brandNameMap[obj.brandName.toLowerCase()] = obj.brandDomain.toLowerCase();
}
});
});
cache.put('brandDomainMap', brandDomainMap, ttl);
cache.put('brandNameMap', brandNameMap, ttl);
return formatData;
};
... ... @@ -303,6 +318,42 @@ const searchKeyActivity = (params) => {
});
};
/**
* 检查字符串是否是品牌域/品牌名称
*
* @param query
* @returns {*|Promise.<TResult>}
*/
const getBrandDomain = (query) => {
let brandDomainMap = cache.get('brandDomainMap');
let brandNameMap = cache.get('brandNameMap');
const fn = () => {
brandDomainMap = cache.get('brandDomainMap');
brandNameMap = cache.get('brandNameMap');
let ret = null;
if (!_.isEmpty(brandDomainMap) && brandDomainMap.hasOwnProperty(query)) {
ret = brandDomainMap[query] || null;
}
if (!_.isEmpty(brandNameMap) && brandNameMap.hasOwnProperty(query)) {
ret = brandNameMap[query] || null;
}
return Promise.resolve(ret);
};
if (brandDomainMap && brandNameMap) {
logger.debug('Using cached brand data.');
return fn();
} else {
logger.debug('Reloading brand data...');
return getAllBrandNames().then(fn);
}
};
module.exports = {
getSearchData,
getFilterData,
... ... @@ -311,5 +362,6 @@ module.exports = {
getClassNames,
getSearchIndex,
getFuzzyDatas,
searchKeyActivity
searchKeyActivity,
getBrandDomain
};
... ...
... ... @@ -14,6 +14,7 @@ const cRoot = './controllers';
// 商品详情controller
const detail = require(`${cRoot}/detail`);
const newDetail = require(`${cRoot}/new-detail`);
// sale controller
const sale = require(`${cRoot}/sale`);
... ... @@ -45,6 +46,8 @@ const seckill = require(`${cRoot}/seckill`);
// 秒杀商品详情controller
const seckillDetail = require(`${cRoot}/seckill-detail`);
const newShop = require(`${cRoot}/new-shop`);
// routers
// /pro_136349_455445/HEARTSOFARMianMaShuJiaoXiuXianKuPS1684.html
... ... @@ -52,17 +55,18 @@ const seckillDetail = require(`${cRoot}/seckill-detail`);
// 因为正则匹配原因,秒杀详情页路由要放在普通详情页前面,待解决
router.get(/^\/seckill\/show_([\d]+)/, seckillDetail.indexSkn); // 秒杀商品详情页 SKN 进入
router.get(/^\/seckill\/pro_([\d]+)_([\d]+)/, seckillDetail.index); // 秒杀商品详情页进入
router.get(/\/pro_([\d]+)_([\d]+)\/(.*)/, detail.index); // 商品详情页
router.get(/^\/pro_([\d]+)_([\d]+)/, newDetail.index); // 商品详情页
// /show_51047967.html
router.get(/\/show_([\d]+)/, detail.indexSkn); // 商品详情页 SKN 进入
router.get(/^\/show_([\d]+)/, detail.indexSkn); // 商品详情页 SKN 进入
router.get('/detail/sknData.json', newDetail.sknData); // 商品咨询,评价,店铺
router.get('/detail/intro/:productskn', detail.intro); // 商品内嵌页
router.get('/detail/preference', detail.preference); // 为你优选
router.get('/detail/consults', detail.consults); // 商品咨询页
router.get('/detail/consultform', auth, detail.consultform); // 商品咨询表单页
router.get('/detail/comments', detail.comments); // 商品评价
router.post('/detail/info', detail.getUser, detail.indexData); // 商品详情页-异步数据
router.post('/detail/newinfo', detail.getUser, newDetail.indexData); // 商品详情页-异步数据 (优化)
router.post('/detail/consultsubmit', auth, detail.consultsubmit); // 商品咨询提交接口
router.get('/detail/coupon.json', detail.brandCoupon); // 品牌券
... ... @@ -123,16 +127,22 @@ router.get('/index/index', list.category);
router.get('/list/index', list.category); // 兼容 PC 的链接
// 品牌 | 店铺
router.get('/index/brand', list.brand);
router.get('/index/brandFav', list.brandFav);
router.get('/index/shopAppCookie', list.shopAppCookie);
router.get('/index/shopFav', list.shopFav);
router.get('/index/baseShopFav', list.baseShopFav);
router.get('/index/category', list.shopCategory);
router.post('/index/userCoupon', list.userCoupon);
router.get('/index/getShopCouponsList', list.getShopCouponsList);
router.get('/index/getBrandCouponsList', list.getBrandCouponsList);
// 店铺重构
router.get('/index/brand', newShop.index);
router.get('/index/baseShopFav', newShop.baseShopFav);
router.get('/index/brandFav', newShop.brandFav);
router.get('/new/shop/hotlist', newShop.shopHotList);
// end- 店铺重构
// 店铺介绍
router.get('/index/intro', list.shopIntro);
... ...
... ... @@ -79,7 +79,7 @@
<ul class="vip-level data-bind clearfix">
<li class="icons-item">
<span class="vip-img" style="background-size:contain;">
<span class="vip-img">
</span>
<span class="vip-price"></span>
</li>
... ... @@ -120,7 +120,7 @@
{{# enterStore}}
<div id="enter-store" class="enter-store page-block tap-hightlight">
<a class="store-logo" href="{{url}}" style="">
<img class="lazy" data-original="{{image img 47 47}}" alt="{{storeName}}">
<img class="lazy" data-original="{{image2 img w=47 h=47 q=60}}" alt="{{storeName}}">
</a>
<a class="store-name" href="{{url}}">{{storeName}}</a>
<a class="store-link" href="{{url}}">进入店铺<span class="iconfont">&#xe604;</span></a>
... ...
... ... @@ -53,7 +53,7 @@
<span class="en-title">{{enTitle}}</span>
</h1>
<div class="detail" style="width:100%">
<img class="lazy" data-original="{{img}}" alt="">
<img class="lazy" data-original="{{image2 img q=60}}" alt="">
</div>
</div>
{{/measurementMethod}}
... ... @@ -110,7 +110,7 @@
{{desc}}
</p>-->
<div class="material-image">
<img src="{{img}}" alt="材质图">
<img src="{{image2 img q=60}}" alt="材质图">
</div>
<div class="material-desc">
{{desc}}
... ... @@ -126,7 +126,7 @@
<div class="detail table clearfix">
{{#list}}
<div class="tip">
<img src="{{img}}" alt="">
<img src="{{image2 img q=60}}" alt="">
<span class="caption">{{caption}}</span>
</div>
{{/list}}
... ... @@ -143,7 +143,7 @@
<div class="pro-detail">
<p>{{{desc}}}</p>
{{#list}}
<img class="lazy" data-original="{{img}}" alt="">
<img class="lazy" data-original="{{image2 img q=60}}" alt="">
{{/list}}
</div>
</div>
... ...
{{# result}}
<div class="good-detail-page yoho-page">
<div class="banner-container">
<div class="tag-container">
{{# tags}}
{{# is_new}}
<p class="good-tag new-tag">NEW</p>
{{/ is_new}}
{{# is_advance}}
<p class="good-tag renew-tag">再到着</p>
{{/ is_advance}}
{{# is_discount}}
<p class="good-tag sale-tag">SALE</p>
{{/ is_discount}}
{{# is_yohood}}
<p class="good-tag new-festival-tag">新品节</p>
{{/ is_yohood}}
{{# is_limited}}
<p class="good-tag limit-tag">限量</p>
{{/ is_limited}}
{{# is_soon_sold_out}}
<p class="good-tag soon-sold-out-tag">即将售罄</p>
{{/ is_soon_sold_out}}
{{# is_presell}}
<p class="good-tag is-presell">预售</p>
{{/ is_presell}}
{{/ tags}}
</div>
{{# bannerTop}}
{{> detail/banner-swiper-arrow}}
{{/ bannerTop}}
</div>
{{# goodsName}}
<h2 class="goods-name"><span>{{.}}</span></h2>
{{/ goodsName}}
{{# goodsSubtitle}}
<h1 class="goods-subtitle"><span>{{.}}</span></h1>
{{/ goodsSubtitle}}
<div class="price-date">
<div class="goods-price">
<h1 class="current-price">{{goodsPrice.currentPrice}}</h1>
<h1 class="previous-price">{{goodsPrice.previousPrice}}</h1>
</div>
<button class="limit-sale data-can-get-limit-code data-bind" id='limit-sale'>获取限购码</button>
<button class="got-limit-sale data-code-empty data-bind">限购码已被抢光</button>
<button class="got-limit-sale data-got-code data-bind">已获取限购码</button>
{{#if periodOfMarket}}
<div class="period-of-market">
<h1>上市期:</h1>
<h1 >{{periodOfMarket}}</h1>
</div>
{{/if}}
</div>
{{!--占位: 学生价/会员价--}}
<div id="placeholder-pricedata"></div>
{{! 品牌优惠券}}
<div class="brand-coupon hide">
<i class="iconfont font-right pull-right">&#xe614;</i>
<i class="iconfont font-quan">&#xe900;</i><span>领取优惠券</span>
</div>
{{!--占位: 促销--}}
<div id="placeholder-promotion" style="height:100px;background-color:#fff;">
</div>
{{!-- 占位: 用户反馈, 店铺入口 --}}
<div id="placeholder-feedback-store"></div>
<div id="productDesc" class="product-desc {{#if limit}}limit{{/if}}"></div>
{{> detail/recommend-for-you}}
{{!--占位: 购物车部分--}}
<div id="placeholder-infodata">
<div class="cart-bar">
<a href="javascript:;" class="num-incart iconfont">&#xe62c;</a>
<a href="javascript:;" class="addto-cart add-to-cart-url">加入购物车</a>
<a href="javascript:;" class="favorite iconfont">&#xe605;</a>
</div>
</div>
{{#if introUrl}}
<input id="introUrl" type="hidden" value="{{introUrl}}">
{{/if}}
{{#if id}}
<input id="productId" type="hidden" value="{{id}}">
{{/if}}
{{#if goodsId}}
<input id="goodsId" type="hidden" value="{{goodsId}}">
{{/if}}
{{#if preferenceUrl}}
<input id="preferenceUrl" type="hidden" value="{{preferenceUrl}}">
{{/if}}
<input id="productSkn" type="hidden" value="{{productSkn}}">
<input id="brand-id" type="hidden" value="{{brandId}}">
<input id="product-limit" type="hidden" value="{{isLimitBuy}}">
<input id="product-coupon-switch" type="hidden" value="{{showCoupon}}">
</div>
{{/ result}}
... ...
<div class="good-list-page yoho-page">
{{# goodList}}
{{# search}}
<div id="search-input" class="search-input">
<form id="search-form" action="{{url}}" method="get">
<i class="search-icon iconfont">&#xe60f;</i>
<input type="text" value="{{default}}" name="query" class="buriedpoint" data-bp-id="shop-search_input_1" autocomplete="off">
<input type="hidden" value="search" name="from">
<i class="clear-input iconfont hide">&#xe626;</i>
<span id="search" class="search buriedpoint" type="submit" data-bp-id="shop-search_btn_0">搜索</span>
</form>
</div>
<ul class="search-associate"></ul>
{{/ search}}
{{# brandWay}}
<div class="brand-way">
<a href={{url}}>
<img class="brand-thumb" src={{image2 thumb q=60}}>
<span class="brand-name">{{name}}</span>
<span class="entry">
进入店铺
<i class="iconfont">&#xe614;</i>
</span>
</a>
</div>
{{/ brandWay}}
<!-- 品牌页面 -->
{{# brandHome}}
<div id="brand-header" class="brand-header" data-id={{id}}>
<img src={{image2 banner q=60}}>
<a class="btn-intro" href="javascript:void(0);">
品牌介绍
</a>
<a class="btn-col" href="javascript:void(0);">
<span class="iconfont">&#xe622;</span>
<span class="txt"></span>
</a>
</div>
<div id="intro-box" class="brand-intro-box hide">
<div id="brand-intro" class="brand-intro">
<h2>品牌介绍</h2>
<div class="con">
{{{intro}}}
</div>
<p class="fo">
<span class="iconfont">&#xe629;</span> 100%品牌授权正品
</p>
<span class="iconfont close-intro">&#xe623;</span>
</div>
</div>
{{/ brandHome}}
<!-- 优惠卷 -->
<div class="coupon-group"></div>
<!-- /品牌页面 -->
<ul id="list-nav" class="list-nav clearfix">
<li class="default active buriedpoint first-li-more" data-bp-id="shop_listnav_default_1">
<a href="javascript:void(0);">
<span class="nav-txt">默认</span>
<span class="iconfont up cur hide">&#xe615;</span>
<span class="iconfont down cur">&#xe616;</span>
</a>
</li>
<li class="price buriedpoint" data-bp-id="shop_listnav_price_1">
<a href="javascript:void(0);">
<span class="nav-txt">价格</span>
<span class="icon">
<i class="iconfont up cur">&#xe615;</i>
<i class="iconfont down">&#xe616;</i>
</span>
</a>
</li>
<li class="discount buriedpoint" data-bp-id="shop_listnav_discount_1">
<a href="javascript:void(0);">
<span class="nav-txt">折扣</span>
<span class="icon">
<i class="iconfont up cur">&#xe615;</i>
<i class="iconfont down">&#xe616;</i>
</span>
</a>
</li>
<li class="filter buriedpoint" data-bp-id="shop_listnav_filter_1">
<a href="javascript:void(0);">
<span class="nav-txt">筛选</span>
<span class="iconfont cur">&#xe613;</span>
</a>
</li>
</ul>
<div class='new-list hide'>
<ul>
<li class='active default' data-bp-id='shop_listnav_default_1'>默认</li>
<li class='new' data-bp-id='shop_listnav_new_1'>最新</li>
</ul>
</div>
<div id="goods-container" class="goods-container">
<div class="default-goods container clearfix">
{{#newGoods}}
{{> common/goods}}
{{/newGoods}}</div>
<div class="new-goods container clearfix hide"></div>
<div class="price-goods container clearfix hide"></div>
<div class="discount-goods container clearfix hide"></div>
{{> common/filter}}
</div>
{{> common/query-param}} {{> common/suspend-cart}} {{/ goodList}}
<input type="text" class="domain" style="display:none" value={{domain}}>
</div>
... ...
<div class="good-list-page yoho-page">
{{# goodList}}
<!-- 基础店铺页面 -->
{{# baseShopHome}}
<div id="brand-header" class="brand-header" data-id={{id}} data-isbaseshop="{{isBaseShop}}">
<img src={{image2 banner q=60}}>
<a class="btn-intro" href="javascript:void(0);">
店铺介绍
</a>
<a class="btn-col" href="javascript:void(0);">
<span class="iconfont">&#xe622;</span>
<span class="txt"></span>
</a>
</div>
<div id="intro-box" class="brand-intro-box hide">
<div id="brand-intro" class="brand-intro">
<h2>店铺介绍</h2>
<div class="con">
{{{intro}}}
</div>
<p class="fo">
<span class="iconfont">&#xe629;</span>
100%品牌授权正品
</p>
<span class="iconfont close-intro">&#xe623;</span>
</div>
</div>
<input type="hidden" name="app_version" value="{{appVersion}}">
{{/ baseShopHome}}
<!-- 优惠卷 -->
<div class="coupon-group"></div>
<!-- /基础店铺页面 -->
<ul id="list-nav" class="list-nav clearfix">
<li class="default active buriedpoint first-li-more" data-bp-id="shop_listnav_default_1">
<a href="javascript:void(0);">
<span class="nav-txt">默认</span>
<span class="iconfont up cur hide">&#xe615;</span>
<span class="iconfont down cur">&#xe616;</span>
</a>
</li>
<li class="price buriedpoint" data-bp-id="shop_listnav_price_1">
<a href="javascript:void(0);">
<span class="nav-txt">价格</span>
<span class="icon">
<i class="iconfont up cur">&#xe615;</i>
<i class="iconfont down">&#xe616;</i>
</span>
</a>
</li>
<li class="discount buriedpoint" data-bp-id="shop_listnav_discount_1">
<a href="javascript:void(0);">
<span class="nav-txt">折扣</span>
<span class="icon">
<i class="iconfont up cur">&#xe615;</i>
<i class="iconfont down">&#xe616;</i>
</span>
</a>
</li>
<li class="filter buriedpoint" data-bp-id="shop_listnav_filter_1">
<a href="javascript:void(0);">
<span class="nav-txt">筛选</span>
<span class="iconfont cur">&#xe613;</span>
</a>
</li>
</ul>
<div class='new-list hide'>
<ul>
<li class='active default' data-bp-id='shop_listnav_default_1'>默认</li>
<li class='new' data-bp-id='shop_listnav_new_1'>最新</li>
</ul>
</div>
<div id="goods-container" class="goods-container">
<div class="default-goods container clearfix">
{{#newGoods}}
{{> common/goods}}
{{/newGoods}}</div>
<div class="new-goods container clearfix hide"></div>
<div class="price-goods container clearfix hide"></div>
<div class="discount-goods container clearfix hide"></div>
{{> common/filter}}
</div>
{{> common/query-param}} {{> common/suspend-cart}} {{/ goodList}}
<input type="text" class="shopId" style="display:none" value={{shopId}}>
</div>
... ...
{{# shopIndex}}
<div class="shop-index yoho-page scroll-wrapper new-shop" id="wrapper">
<div id="scroller">
<div id="nav-top">
{{> header}}
<!-- tar modifield 160826 -->
<input type="hidden" name="app_version" value="{{appVersion}}">
<input type="hidden" name="shop_id" value="{{../shopId}}">
<input type="hidden" name="brand" value="{{brand}}">
<input type="hidden" name="favId" value="{{favId}}">
<input type="hidden" name="coverChannel" value="{{coverChannel}}">
<input type="hidden" name="uid" value="{{uid}}">
{{#unless appVersion}}
<div class="search-area">
<div id="search-input" class="search-input">
<form id="search-form" action={{url}} method="get">
<i class="search-icon iconfont">&#xe60f;</i>
<input type="text" placeholder="搜索店铺内潮品" name="query" class="buriedpoint">
<input type="hidden" name="shop_id" value="{{../shopId}}">
<input type="hidden" name="coverChannel" value="{{coverChannel}}">
<i class="clear-input iconfont hide">&#xe626;</i>
<button id="search" class="search buriedpoint" type="submit"
data-bp-id="shop_search_btn_0">搜索
</button>
</form>
</div>
</div>
{{/unless}}
<!-- /tar modifield 160826 -->
<div class="branner-top">
<img class="shop-back-img" src="{{image2 branerImg w=640 h=200 mode=1 q=60}}">
{{#if logoImg}}
<img class="logo" src="{{image2 logoImg w=500 h=500 q=60}}">
{{/if}}
<p class="store-name">{{storeName}}</p>
<div class="collect">
<div class="not-collect buriedpoint" id="collect" data-bp-id="shop_branner_collect_1"></div>
</div>
</div>
</div>
<ul id="nav" class="nav">
<li class="active color buriedpoint" tab="home-page" data-bp-id="shop_nav_index_1"><div class="text">首页</div></li>
<li tab="new-arrival" data-bp-id="shop_nav_new_1" class="buriedpoint"><div class="text">上新</div></li>
<li tab="popularity" data-bp-id="shop_nav_populary_1" class="buriedpoint"><div class="text">人气</div></li>
<li data-bp-id="shop_nav_all_1" class="all-goods buriedpoint">
<div class="text"><a href="{{allGoods}}" target="_blank">全部商品</a></div>
</li>
</ul>
<div id="home-page" class="main">
<div id="nav-main" class="nav-main">
<!-- 优惠卷 -->
<div class="coupon-group"></div>
<!-- 大导航 -->
{{#if brandList}}
<div class="multi-brands first">
<p>品牌一览</p>
<div class="multi-browse">
<ul class="swiper-wrapper">
{{#each brandList.list}}
<li class="swiper-slide brand-img buriedpoint"
data-bp-id="shop_brand_{{img}}_0">
<a href="{{url}}">
<img src="{{image2 img q=60}}">
</a>
<p>{{brandName}}</p>
</li>
{{/each}}
</ul>
</div>
</div>
{{/if}}
<div class="banner-area first">
{{# bannerTop}}
{{> resources/banner-top}}
{{/ bannerTop}}
</div>
<ul class="spring">
{{#each spring}}
<li class="buriedpoint" data-bp-id="shop_spring_{{url}}_0">
{{#if url}}
<a href="{{url}}">
<img src="{{image2 springType q=60}}">
</a>
{{^}}
<a href="javascript:;">
<img src="{{image2 springType q=60}}">
</a>
{{/if}}
</li>
{{/each}}
</ul>
{{! 热门品类}}
<div class="first">
{{# hotCategory}}
{{> shop/hot-category}}
{{/ hotCategory}}
</div>
<div class="popularity-title" data-skns="{{hotListproductSkn}}">
人气单品
<a class="more buriedpoint" href="{{more_url}}" data-bp-id="shop_popularity_{{more_url}}">
&#xe618;</a>
</div>
<div class="product-warp">
<div class="goods-container clearfix">
</div>
</div>
</div>
<div class="discount-area first" id="navlist2">
<ul id="list-nav" class="home-sub-nav list-nav pos-list clearfix">
<li class="default active buriedpoint first-li-more" data-bp-id="shop_listnav_default_1">
<a href="javascript:void(0);">
<span class="nav-txt">默认</span>
<span class="iconfont up cur hide">&#xe615;</span>
<span class="iconfont down cur">&#xe616;</span>
</a>
</li>
<li class="price buriedpoint" data-bp-id="shop_listnav_price_1">
<a href="javascript:void(0);">
<span class="spanTest">价格</span>
<span class="icon">
<i class="iconfont up cur">&#xe615;</i>
<i class="iconfont down">&#xe616;</i>
</span>
</a>
</li>
<li class="discount buriedpoint" data-bp-id="shop_listnav_discount_1">
<a href="javascript:void(0);">
<span class="spanTest">折扣</span>
<span class="icon">
<i class="iconfont up cur">&#xe615;</i>
<i class="iconfont down">&#xe616;</i>
</span>
</a>
</li>
<li class="filter buriedpoint" data-bp-id="shop_listnav_filter_1">
<a href="javascript:void(0);">
<span class="spanTest">筛选</span>
<span class="iconfont cur">&#xe613;</span>
</a>
</li>
</ul>
<div class='new-list classics hide'>
<ul>
<li class='active default' data-bp-id='shop_listnav_default_1'>默认</li>
<li class='new' data-bp-id='shop_listnav_new_1'>最新</li>
</ul>
</div>
</div>
<div class="discount-area first">
<div id="goods-container" class="goods-container">
<div class="default-goods container clearfix">
{{#newGoods}}
{{> common/goods}}
{{/newGoods}}</div>
<div class="new-goods container clearfix hide"></div>
<div class="price-goods container hide clearfix"></div>
<div class="discount-goods container hide clearfix"></div>
</div>
</div>
</div>
<div id="new-arrival" class="new-arrival main hide"></div>
<div id="popularity" class="popularity main hide"></div>
</div>
{{#unless appVersion}}
{{> shop/shop-footer}}
{{/unless}}
<ul id="pos-nav" class="nav hide">
<li class="active color buriedpoint" tab="home-page" data-bp-id="shop_posnav_index_1"><div class="text">首页</div></li>
<li tab="new-arrival" class="buriedpoint" data-bp-id="shop_posnav_new_1"><div class="text">上新</div></li>
<li tab="popularity" class="buriedpoint" data-bp-id="shop_posnav_populary_1"><div class="text">人气</div></li>
<li class="all-goods buriedpoint" data-bp-id="shop_posnav_all_1">
<div class="text"><a href="{{allGoods}}" target="_blank">全部商品</a></div>
</li>
</ul>
<ul id="pos-list" class="home-sub-nav pos-list hide">
<li class="default active buriedpoint first-li-more" data-bp-id="shop_listnav_default_1">
<a href="javascript:void(0);">
<span class="nav-txt">默认</span>
<span class="iconfont up cur hide">&#xe615;</span>
<span class="iconfont down cur">&#xe616;</span>
</a>
</li>
<li class="price buriedpoint" data-bp-id="shop_poslist_price_1">
<a href="javascript:void(0);">
<span class="spanTest">价格</span>
<span class="icon">
<i class="iconfont up cur">&#xe615;</i>
<i class="iconfont down">&#xe616;</i>
</span>
<b></b>
</a>
</li>
<li class="discount buriedpoint" data-bp-id="shop_poslist_discount_1">
<a href="javascript:void(0);">
<span class="spanTest">折扣</span>
<span class="icon">
<i class="iconfont up cur">&#xe615;</i>
<i class="iconfont down">&#xe616;</i>
</span>
<b></b>
</a>
</li>
<li class="filter buriedpoint" data-bp-id="shop_poslist_filter_1">
<a href="javascript:void(0);">
<span class="spanTest">筛选</span>
<span class="iconfont cur">&#xe613;</span>
</a>
</li>
</ul>
</div>
{{> common/filter}}
{{/ shopIndex}}
{{> common/query-param}}
<input type="text" class="shopId" style="display:none" value={{shopId}}>
... ...
{{# hotList}}
{{> common/goods}}
{{/ hotList}}
\ No newline at end of file
... ...
... ... @@ -5,7 +5,11 @@
{{# list}}
<li class="swiper-slide">
<a href="javascript:;">
<img src="{{image img 450 600}}" alt="">
{{#if @first}}
<img src="{{image2 img w=450 h=600 q=60}}" alt="">
{{else}}
<img class="swiper-lazy" data-src="{{image2 img w=450 h=600 q=60}}" alt="">
{{/if}}
</a>
</li>
{{/ list}}
... ... @@ -22,7 +26,7 @@
{{^}}
<div class="banner-top-single">
<a href={{url}}>
<img class="img" src="{{image img 450 600}}">
<img class="img" src="{{image2 img w=450 h=600 q=60}}">
</a>
</div>
{{/if}}
... ...
... ... @@ -5,6 +5,7 @@
<i class="search-icon iconfont">&#xe60f;</i>
<input type="text" value="{{default}}" name="query" class="buriedpoint" data-bp-id="shop-search_input_1" autocomplete="off">
<input type="hidden" value="search" name="from">
<input type="hidden" name="shop_id" value="{{@root.shopId}}">
<i class="clear-input iconfont hide">&#xe626;</i>
<span id="search" class="search buriedpoint" type="submit" data-bp-id="shop-search_btn_0">搜索</span>
</form>
... ... @@ -133,6 +134,11 @@
</div>
<div id="goods-container" class="goods-container">
<div class="firstscreen-goods container clearfix">
{{#@root.firstPageGoodsList}}
{{> common/goods}}
{{/@root.firstPageGoodsList}}
</div>
<div class="default-goods container clearfix"></div>
<div class="new-goods container clearfix"></div>
<div class="sale-goods container clearfix"></div>
... ...
{{#data}}
<div class="hot-category">
{{> common/floor-header}}
{{# banner}}
<a class="category-banner" href="{{url}}">
<img class="lazy" data-original="{{src}}">
<img class="lazy" data-original="{{image2 src q=60}}">
</a>
{{/ banner}}
<ul class="category-list clearfix">
... ... @@ -12,7 +12,7 @@
<li>
<a href="{{url}}">
<div class="img-box">
<img class="lazy" data-original="{{image src 140 140}}" alt="">
<img class="lazy" data-original="{{image2 src w=140 h=140 q=60}}" alt="">
</div>
</a>
<div class="img-cover">{{name}}</div>
... ... @@ -20,4 +20,4 @@
{{/ list}}
</ul>
</div>
{{/data}}
\ No newline at end of file
{{/data}}
... ...
... ... @@ -18,6 +18,7 @@ const cachePage = {
// 商品详情页
'/product/\\/pro_([\\d]+)_([\\d]+)\\/(.*)/': 30 * MINUTE,
'/product/\\/show_([\\d]+)/': 30 * MINUTE,
// 商品详情ajax
// 逛
'/guang/': 1 * MINUTE,
... ...
... ... @@ -51,11 +51,11 @@ module.exports = {
activity: '//activity.yohobuy.com',
index: '//m.yohobuy.com'
},
useCache: false,
useCache: true,
memcache: {
master: ['192.168.102.168:12111'],
slave: ['192.168.102.168:12111'],
session: ['192.168.102.168:12111'],
master: ['127.0.0.1:11211'],
slave: ['127.0.0.1:11211'],
session: ['127.0.0.1:11211'],
timeout: 1000,
retries: 0
},
... ... @@ -122,7 +122,7 @@ if (isProduction) {
open: false,
url: 'http://123.206.2.55/strategy'
},
zookeeperServer: 'zookeeper.web.yohoops.org:2181'
zookeeperServer: 'web.zookeeper.yohoops.org:2181'
});
} else if (isTest) {
Object.assign(module.exports, {
... ...
// 在这个文件中配置 DNS 预读域名
module.exports = {
hosts: [
'//cdn.yoho.cn',
'//static.yohobuy.com',
'//img10.static.yhbimg.com',
'//img11.static.yhbimg.com',
'//img12.static.yhbimg.com',
'//img13.static.yhbimg.com',
'//analytics.m.yohobuy.com',
'//search.m.yohobuy.com',
'//list.m.yohobuy.com',
'//guang.m.yohobuy.com'
]
};
... ...
... ... @@ -5,8 +5,21 @@
const headerModel = require('../models/header');
const logger = global.yoho.logger;
const forceNoCache = (res) => {
if (res) {
res.set({
'Cache-Control': 'no-cache',
Pragma: 'no-cache',
Expires: (new Date(1900, 0, 1, 0, 0, 0, 0)).toUTCString()
});
}
};
exports.notFound = () => {
return (req, res) => {
forceNoCache(res);
res.status(404);
if (req.xhr) {
... ... @@ -34,6 +47,8 @@ exports.notFound = () => {
*/
exports.serverError = () => {
return (err, req, res, next) => {
forceNoCache(res);
logger.error(`error at path: ${req.url}`);
logger.error(err);
... ...
'use strict';
const dnsPrefetch = require('../../config/dns-prefetch');
module.exports = () => {
return (req, res, next) => {
Object.assign(res.locals, {
dnsPrefetch: dnsPrefetch
});
next();
};
};
... ...
const _ = require('lodash');
// 黑名单参数
const BLACK_LIST = [
'client_secret',
'method'
];
module.exports = () => {
return (req, res, next) => {
if (req.query) {
_.forEach(BLACK_LIST, (key) => {
if (req.query[key]) {
delete req.query[key];
}
});
}
next();
};
};
... ...
... ... @@ -4,8 +4,8 @@ const cookie = global.yoho.cookie;
module.exports = () => {
return (req, res, next) => {
// 从 SESSION 中获取到当前登录用户的 UID
if (req.session && _.isNumber(req.session._LOGIN_UID)) {
req.user.uid = req.session._LOGIN_UID;
if (req.session && _.isNumber(req.session.LOGIN_UID)) {
req.user.uid = req.session.LOGIN_UID;
}
// session 没有读取到的时候,从 cookie 读取 UID
... ...
... ... @@ -10,19 +10,15 @@
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta content="telephone=no" name="format-detection" />
<meta content="email=no" name="format-detection" />
<link rel="dns-prefetch" href="//cdn.yoho.cn">
<link rel="dns-prefetch" href="//static.yohobuy.com">
<link rel="dns-prefetch" href="//img12.static.yhbimg.com">
<link rel="dns-prefetch" href="//img13.static.yhbimg.com">
{{#dnsPrefetch.hosts}}
<link rel="dns-prefetch" href="{{this}}">
{{/dnsPrefetch.hosts}}
<script type="text/javascript">
var isWechat = /micromessenger/i.test(navigator.userAgent || '');
if (isWechat) document.title =document.title.replace(' | Yoho!Buy有货 | 潮流购物逛不停', '');
</script>
<!-- oneapm agent -->
<script type='text/javascript'>window.BWEUM||(BWEUM={});BWEUM.info = {"stand":true,"agentType":"browser","agent":"bi-collector.oneapm.com/static/js/bw-send-411.4.9.js","beaconUrl":"bi-collector.oneapm.com/beacon","licenseKey":"NQVuf~6yrQbvJnqr","applicationID":2283639};</script><script type="text/javascript">/*!OneAPM-v411.4.9 */!function(){window.NREUM||(window.NREUM={}),window.BWEUM||(window.BWEUM=window.NREUM);var a;window.BWEUM.require=a,window.apmFirstbyte=window.apmUserFirstbyte||(new Date).getTime(),a=function b(c,d,e){function f(h,i){if(!d[h]){if(!c[h]){var j="function"==typeof a&&a;if(!i&&j)return j(h,!0);if(g)return g(h,!0);var k=new Error("Cannot find module '"+h+"'");throw k.code="MODULE_NOT_FOUND",k}var l=d[h]={exports:{}};c[h][0].call(l.exports,function(a){var b=c[h][1][a];return f(b?b:a)},l,l.exports,b,c,d,e)}return d[h].exports}for(var g="function"==typeof a&&a,h=0;h<e.length;h++)f(e[h]);return f}({38:[function(a,b){b.exports=function(a){var b=document.createElement("a"),c=window.location,d={};b.href=a,d.port=b.port;var e=b.href.split("://");return!d.port&&e[1]&&(d.port=e[1].split("/")[0].split(":")[1]),d.port&&"0"!==d.port||(d.port="https"===e[0]?"443":"80"),d.hostname=b.hostname||c.hostname,d.pathname=b.pathname,"/"!==d.pathname.charAt(0)&&(d.pathname="/"+d.pathname),d.sameOrigin=!b.hostname||b.hostname===document.domain&&b.port===c.port&&b.protocol===c.protocol,d}},{}],34:[function(a,b){function c(){var a=m.info=window.BWEUM.info;if(a&&a.agent&&a.licenseKey&&a.applicationID&&i&&i.body){m.proto="https"===l.split(":")[0]||a.sslForHttp?"https://":"http://",g("mark",["onload",f()]);var b=i.createElement("script");b.src=0==a.agent.indexOf("//")?a.agent:m.proto+a.agent,b.src+="?v=411.4.9 ",i.body.appendChild(b)}}function d(){o||"complete"===i.readyState&&e()}function e(){g("mark",["domContent",f()])}function f(){return(new Date).getTime()}var g=a("handle"),h=window,i=h.document,j="addEventListener",k="attachEvent",l=(""+location).split("?")[0],m=b.exports={offset:window.apmFirstbyte||f(),origin:l,features:{}};g("mark",["firstbyte",window.apmFirstbyte||f()]),"complete"===document.readyState?(e(),c()):i[j]?(i[j]("DOMContentLoaded",e,!1),h[j]("load",c,!1)):(i[k]("onreadystatechange",d),h[k]("onload",c));var n=!1,o=!1;try{n=null==window.frameElement&&document.documentElement}catch(m){}n&&n.doScroll&&!function p(){if(!o){try{n.doScroll("left")}catch(a){return setTimeout(p,50)}o=!0,e()}}()},{handle:33}],33:[function(a,b){function c(a,b,c){return d.listeners(a).length?d.emit(a,b,c):(e[a]||(e[a]=[]),void e[a].push(b))}var d=a("ee").create(),e={};b.exports=c,c.ee=d,d.q=e},{ee:31}],36:[function(a,b){function c(a,b,c){b||(b=0),"undefined"==typeof c&&(c=a?a.length:0);for(var d=-1,e=c-b||0,f=new Array(0>e?0:e);++d<e;)f[d]=a[b+d];return f}b.exports=c},{}],31:[function(a,b){function c(a){function b(b,c,g){a&&a(b,c,g),g||(g={});var i=h(b),j=i.length,k={};try{k=f(g,e,d)}catch(l){}for(var m=0;j>m;m++)i[m].apply(k,c);return k}function g(a,b){j[a]=h(a).concat(b)}function h(a){return j[a]||[]}function i(){return c(b)}var j={};return{on:g,emit:b,create:i,listeners:h,_events:j}}function d(){return{}}var e="bw@context",f=a("gos");b.exports=c()},{gos:32}],32:[function(a,b){function c(a,b,c){if(d.call(a,b))return a[b];var e=c();if(Object.defineProperty&&Object.keys)try{return Object.defineProperty(a,b,{value:e,writable:!0,enumerable:!1}),e}catch(f){}try{a[b]=e}catch(f){}return e}var d=Object.prototype.hasOwnProperty;b.exports=c},{}]},{},[]),a=function c(b,d,e){function f(h,i){if(!d[h]){if(!b[h]){var j="function"==typeof a&&a;if(!i&&j)return j(h,!0);if(g)return g(h,!0);var k=new Error("Cannot find module '"+h+"'");throw k.code="MODULE_NOT_FOUND",k}var l=d[h]={exports:{}};b[h][0].call(l.exports,function(a){var c=b[h][1][a];return f(c?c:a)},l,l.exports,c,b,d,e)}return d[h].exports}for(var g="function"==typeof a&&a,h=0;h<e.length;h++)f(e[h]);return f}({1:[function(a){a("loader"),a("errorload"),a("xhrload"),a("perfload")},{errorload:5,loader:34,perfload:6,xhrload:7}],7:[function(a){function b(a){if("string"==typeof a&&a.length)return a.length;if("object"!=typeof a)return void 0;if("undefined"!=typeof ArrayBuffer&&a instanceof ArrayBuffer&&a.byteLength)return a.byteLength;if("undefined"!=typeof Blob&&a instanceof Blob&&a.size)return a.size;if("undefined"!=typeof FormData&&a instanceof FormData)return void 0;try{return JSON.stringify(a).length}catch(b){return void 0}}function c(a,b){return b}function d(a){a.send=o.wrapOld(a.send,"send-xhr-",c),a.onreadystatechange=o.wrapOld(a.onreadystatechange,"iexhr-onreadystatechange-",c),a.onerror=o.wrapOld(a.onerror,"iexhr-onerror-",c)}function e(a){var c=this.params,d=this.metrics;if(!this.ended){if(this.ended=!0,a.removeEventListener)for(var e=0;m>e;e++)a.removeEventListener(l[e],this.listener,!1);if(!c.aborted){if(d.duration=(new Date).getTime()-this.startTime,4===a.readyState){c.status=a.status;var f=a.responseType,g="arraybuffer"===f||"blob"===f||"json"===f?a.response:a.responseText,h=b(g);h&&(d.rxSize=h)}else c.status=0;d.cbTime=this.cbTime,c&&c.pathname&&c.pathname.indexOf("beacon/resources")<0&&i("xhr",[c,d,this.startTime,this.creatType])}}}function f(a,b){var c=j(b),d=a.params;d.host=c.hostname+":"+c.port,d.pathname=c.pathname,a.sameOrigin=c.sameOrigin}var g=window,h=(g.performance,window.XMLHttpRequest);if(h&&h.prototype&&!/CriOS/.test(navigator.userAgent)){a("loader").features.xhr=!0;var i=a("handle"),j=a("parse-url"),k=a("ee"),l=["load","error","abort","timeout"],m=l.length,n=a("loader_id"),o=a("wrap-function")(k);a("wrap-events"),a("wrap-xhr"),k.on("new-xhr",function(){this.totalCbs=0,this.called=0,this.cbTime=0,this.end=e,this.ended=!1,this.xhrGuids={}}),k.on("open-xhr-start",function(a){this.params={method:a[0]},f(this,a[1]),this.metrics={}}),k.on("open-xhr-end",function(a,b){b.__oldie&&d(b)}),k.on("send-xhr-start",function(a,c){var d=this.metrics,e=a[0],f=this;if(d&&e){var g=b(e);g&&(d.txSize=g)}if(this.startTime=(new Date).getTime(),this.listener=function(a){try{"abort"===a.type&&(f.params.aborted=!0),("load"!==a.type||f.called===f.totalCbs&&(f.onloadCalled||"function"!=typeof c.onload))&&f.end&&f.end(c)}catch(b){try{k.emit("internal-error",[b])}catch(d){}}},c.addEventListener)for(var h=0;m>h;h++)c.addEventListener(l[h],this.listener,!1)}),k.on("iexhr-onreadystatechange-start",function(a,b){if(1==b.readyState){var d=b.onreadystatechange;setTimeout(function(){b.onreadystatechange!==d&&(b.onreadystatechange=o.wrapOld(b.onreadystatechange,"iexhr-onreadystatechange-",c))},0)}4==b.readyState&&(this.xhrCbStart=(new Date).getTime())}),k.on("iexhr-onreadystatechange-end",function(a,b){var c=this;this.xhrCbStart&&k.emit("xhr-cb-time",[(new Date).getTime()-this.xhrCbStart,this.onload,b],b),4==b.readyState&&c.end(b)}),k.on("xhr-cb-time",function(a,b,c){this.cbTime+=a,b?this.onloadCalled=!0:this.called+=1,this.called!==this.totalCbs||!this.onloadCalled&&"function"==typeof c.onload||this.end(c)}),k.on("xhr-load-added",function(a,b){var c=""+n(a)+!!b;this.xhrGuids&&!this.xhrGuids[c]&&(this.xhrGuids[c]=!0,this.totalCbs+=1)}),k.on("xhr-load-removed",function(a,b){var c=""+n(a)+!!b;this.xhrGuids&&this.xhrGuids[c]&&(delete this.xhrGuids[c],this.totalCbs-=1)}),k.on("addEventListener-end",function(a,b){b instanceof XMLHttpRequest&&"load"===a[0]&&k.emit("xhr-load-added",[a[1],a[2]],b)}),k.on("removeEventListener-end",function(a,b){b instanceof XMLHttpRequest&&"load"===a[0]&&k.emit("xhr-load-removed",[a[1],a[2]],b)}),k.on("fn-start",function(a,b,c){b instanceof XMLHttpRequest&&("onload"===c&&(this.onload=!0),("load"===(a[0]&&a[0].type)||this.onload)&&(this.xhrCbStart=(new Date).getTime()))}),k.on("fn-end",function(a,b){this.xhrCbStart&&k.emit("xhr-cb-time",[(new Date).getTime()-this.xhrCbStart,this.onload,b],b)})}},{ee:31,handle:33,loader:34,loader_id:35,"parse-url":38,"wrap-events":28,"wrap-function":39,"wrap-xhr":30}],35:[function(a,b){function c(a){var b=typeof a;return!a||"object"!==b&&"function"!==b?-1:a===window?0:f(a,e,function(){return d++})}var d=1,e="bw@id",f=a("gos");b.exports=c},{gos:32}],6:[function(a){var b=window.performance;if(b&&b.timing&&b.getEntriesByType){var c=a("ee"),d=a("handle"),e=(a("wrap-timer"),a("loader"));e.features.stn=!0,c.on("fn-start",function(a){var b=a[0];b instanceof Event&&(this.bstStart=Date.now())}),c.on("fn-end",function(a,b){var c=a[0];c instanceof Event&&d("bst",[c,b,this.bstStart,Date.now()])})}},{ee:31,handle:33,loader:34,"wrap-timer":29}],5:[function(a){function b(a,b,d,g,i){try{j?j-=1:e("err",[i||new c(a,b,d)])}catch(k){try{e("ierr",[k,(new Date).getTime(),!0])}catch(l){}}return"function"==typeof h?h.apply(this,f(arguments)):!1}function c(a,b,c){this.message=a||"Uncaught error with no additional information",this.sourceURL=b,this.line=c}function d(a){e("err",[a,(new Date).getTime()])}var e=a("handle"),f=a("lodash._slice"),g=a("ee"),h=window.onerror,i=!1,j=0;a("loader").features.err=!0,window.onerror=b,window.BWEUM.noticeError=d;var k=window.XMLHttpRequest;try{throw new Error}catch(l){"stack"in l&&(a("wrap-timer"),"addEventListener"in window&&a("wrap-events"),k&&k.prototype&&k.prototype.addEventListener&&a("wrap-xhr"),i=!0)}g.on("fn-start",function(){i&&(j+=1)}),g.on("fn-err",function(a,b,c){i&&(this.thrown=!0,d(c))}),g.on("fn-end",function(){i&&!this.thrown&&j>0&&(j-=1)}),g.on("internal-error",function(a){e("ierr",[a,(new Date).getTime(),!0])})},{ee:31,handle:33,loader:34,"lodash._slice":36,"wrap-events":28,"wrap-timer":29,"wrap-xhr":30}],30:[function(a,b){function c(){j.inPlace(this,m,"fn-")}function d(a,b){j.inPlace(b,["onreadystatechange"],"fn-")}function e(a){a.open=j.wrapOld(a.open,"open-xhr-",f)}function f(a,b){return b}var g=a("ee").create(),h=a("wrap-events"),i=a("wrap-function"),j=i(g),k=i(h),l=window.XMLHttpRequest,m=["onload","onerror","onabort","onloadstart","onloadend","onprogress","ontimeout"];b.exports=g,window._ApmXMLHttpRequest=window.XMLHttpRequest,window.XMLHttpRequest=function(a){var b=new l(a);try{g.emit("new-xhr",[],b),l.prototype.addEventListener?(k.inPlace(b,["addEventListener","removeEventListener"],"-",function(a,b){return b}),b.addEventListener("readystatechange",c,!1)):(b.__oldie=!0,e(b))}catch(d){try{g.emit("internal-error",[d])}catch(f){}}return b},window.XMLHttpRequest.prototype=l.prototype,j.inPlace(XMLHttpRequest.prototype,["open","send"],"-xhr-",f),g.on("send-xhr-start",d),g.on("open-xhr-start",d)},{ee:31,"wrap-events":28,"wrap-function":39}],29:[function(a,b){function c(a,b,c){var d=a[0];"string"==typeof d&&(d=new Function(d)),a[0]=e(d,"fn-",null,c)}var d=(a("lodash._slice"),a("ee").create()),e=a("wrap-function")(d);b.exports=d,e.inPlace(window,["setTimeout","setInterval","setImmediate"],"setTimer-"),d.on("setTimer-start",c)},{ee:31,"lodash._slice":36,"wrap-function":39}],28:[function(a,b){function c(a){f.inPlace(a,["addEventListener","removeEventListener"],"-",d)}function d(a){return a[1]}var e=(a("lodash._slice"),a("ee").create()),f=a("wrap-function")(e),g=a("gos");if(b.exports=e,c(window),"getPrototypeOf"in Object){for(var h=document;h&&!h.hasOwnProperty("addEventListener");)h=Object.getPrototypeOf(h);h&&c(h);for(var i=XMLHttpRequest.prototype;i&&!i.hasOwnProperty("addEventListener");)i=Object.getPrototypeOf(i);i&&c(i)}else Object.prototype.hasOwnProperty.call(XMLHttpRequest,"addEventListener")&&c(XMLHttpRequest.prototype);e.on("addEventListener-start",function(a){if(a[1]){var b=a[1];"function"==typeof b?this.wrapped=a[1]=g(b,"bw@wrapped",function(){return f(b,"fn-",null,b.name||"anonymous")}):"function"==typeof b.handleEvent&&f.inPlace(b,["handleEvent"],"fn-")}}),e.on("removeEventListener-start",function(a){var b=this.wrapped;b&&(a[1]=b)})},{ee:31,gos:32,"lodash._slice":36,"wrap-function":39}],39:[function(a,b){function c(a){return!(a&&"function"==typeof a&&a.apply&&!a[f])}var d=a("ee"),e=a("lodash._slice"),f="bw@wrapper",g=Object.prototype.hasOwnProperty;b.exports=function(a){function b(a,b,d,g,i){function j(){var c=this;return h(a,b,c,e(arguments),d,g,i)}if(c(a))return a;b||(b="");try{j[f]=!0}catch(k){}return l(a,j),j}function h(a,b,c,d,e,f){var d,c,g,h;try{g=e&&e(d,c)||{}}catch(i){m([i,"",[d,c,f],g])}_apmfnName=a.name||"",k(b+"start",[d,c,f,_apmfnName],g);try{return h=a.apply(c,d)}catch(j){var l=window.console;throw void 0!=l&&l.error&&l.log&&void 0!=j.stack&&(l.log("OneAPM catch error"),l.error(j.stack)),k(b+"err",[d,c,j],g),j}finally{k(b+"end",[d,c,h,_apmfnName],g)}}function i(a,b,c){var a=a||function(){},b=b||"-";return function(){var d=this;return h(a,b,d,e(arguments),c)}}function j(a,d,e,f){e||(e="");var g,h,i,j="-"===e.charAt(0);for(i=0;i<d.length;i++)h=d[i],g=a[h],c(g)||(a[h]=b(g,j?h+e:e,f,h,a))}function k(b,c,d){try{a.emit(b,c,d)}catch(e){m([e,b,c,d])}}function l(a,b){if(Object.defineProperty&&Object.keys)try{var c=Object.keys(a);return c.forEach(function(c){Object.defineProperty(b,c,{get:function(){return a[c]},set:function(b){return a[c]=b,b}})}),b}catch(d){m([d])}for(var e in a)g.call(a,e)&&(b[e]=a[e]);return b}function m(b){try{a.emit("internal-error",b)}catch(c){}}return a||(a=d),b.inPlace=j,b.flag=f,b.wrapOld=i,b}},{ee:31,"lodash._slice":36}]},{},[1]),window.BWEUM.require=a}();</script>
{{#if width750}}
<script type="text/javascript">
(function(d,c){var e=d.documentElement,a="orientationchange" in window?"orientationchange":"resize",b=function(){var f=e.clientWidth;if(!f){return}if(f>=750){e.style.fontSize="40px"}else{e.style.fontSize=40*(f/750)+"px"}};if(!d.addEventListener){return}b();c.addEventListener(a,b,false);d.addEventListener("DOMContentLoaded",b,false)})(document,window);
... ... @@ -32,26 +28,41 @@
(function(d,c){var e=d.documentElement,a="orientationchange" in window?"orientationchange":"resize",b=function(){var f=e.clientWidth;if(!f){return}if(f>=640){e.style.fontSize="40px"}else{e.style.fontSize=40*(f/640)+"px"}};if(!d.addEventListener){return}b();c.addEventListener(a,b,false);d.addEventListener("DOMContentLoaded",b,false)})(document,window);
</script>
{{/if}}
{{#if devEnv}}
{{#if shopPage}}
<link rel="stylesheet" media="all" href="//{{devHost}}:5001/bundle/shop.css">
{{^}}
<link rel="stylesheet" media="all" href="//{{devHost}}:5001/bundle/index.css">
{{/if}}
{{#if vue}}
<link rel="stylesheet" href="//{{devHost}}:5001/{{module}}.{{page}}.css">
{{#if isWechat}}
{{!--Android机器页面不再受到用户字体缩放强制改变大小 http://m.blog.csdn.net/article/details?id=51275080 --}}
<script type="text/javascript">
(function(){if(typeof(WeixinJSBridge)=="undefined"){document.addEventListener("WeixinJSBridgeReady",function(a){setTimeout(function(){WeixinJSBridge.invoke("setFontSizeCallback",{fontSize:0},function(b){})},0)})}else{setTimeout(function(){WeixinJSBridge.invoke("setFontSizeCallback",{fontSize:0},function(a){})},0)}})();
</script>
{{/if}}
{{#if devEnv}}
{{#if localCss}}
<link rel="stylesheet" media="all" href="//{{devHost}}:5001/bundle/common.css">
{{/if}}
{{^}}
{{#if shopPage}}
<link rel="stylesheet" media="all" href="//cdn.yoho.cn/m-yohobuy-node/{{version}}/shop.css">
{{#ifor localCss vue}}
<link rel="stylesheet" media="all" href="//{{devHost}}:5001/bundle/{{module}}.{{page}}.css">
{{^}}
<link rel="stylesheet" media="all" href="//cdn.yoho.cn/m-yohobuy-node/{{version}}/index.css">
{{/if}}
{{#if shopPage}}
<link rel="stylesheet" media="all" href="//{{devHost}}:5001/bundle/shop.css">
{{^}}
<link rel="stylesheet" media="all" href="//{{devHost}}:5001/bundle/index.css">
{{/if}}
{{/ifor}}
{{^}}
{{#if vue}}
<link rel="stylesheet" href="//cdn.yoho.cn/m-yohobuy-node/{{version}}/{{module}}.{{page}}.css">
{{#if localCss }}
<link rel="stylesheet" media="all" href="//cdn.yoho.cn/m-yohobuy-node/{{version}}/common.css">
{{/if}}
{{#ifor localCss vue}}
<link rel="stylesheet" media="all" href="//cdn.yoho.cn/m-yohobuy-node/{{version}}/{{module}}.{{page}}.css">
{{^}}
{{#if shopPage}}
<link rel="stylesheet" media="all" href="//cdn.yoho.cn/m-yohobuy-node/{{version}}/shop.css">
{{^}}
<link rel="stylesheet" media="all" href="//cdn.yoho.cn/m-yohobuy-node/{{version}}/index.css">
{{/if}}
{{/ifor}}
{{/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" sizes="640x920" href="http://static.yohobuy.com/m/v1/img/startup/startup-retina.png" media="screen and (max-device-width: 480px) and (-webkit-min-device-pixel-ratio: 2)">
... ...
<!-- Google Tag Manager -->
<noscript><iframe src="//www.googletagmanager.com/ns.html?id=GTM-W958MG" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<script>
var _hmt = _hmt || [];
function async_load(){
(function() {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?e5b83a487a4458aa5abca43f5779b764";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-W958MG');
}
window.addEventListener('load', async_load, false);
</script>
<script>
(function(){
var bp = document.createElement('script');
var curProtocol = window.location.protocol.split(':')[0];
if (curProtocol === 'https') {
bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
}
else {
bp.src = 'http://push.zhanzhang.baidu.com/push.js';
}
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(bp, s);
})();
</script>
{{#if this}} {{!-- 剔除值为false的项 --}}
<div class="good-info {{#if @root.sale_vip_login}}sale-vip{{/if}}" data-good-id="{{product_id}}" data-id="{{product_skn}}" data-bp-id="guang_goodList_{{product_name}}_false">
<div class="good-info {{#if @root.sale_vip_login}}sale-vip{{/if}}" data-good-id="{{product_id}}"
data-id="{{product_skn}}" data-bp-id="guang_goodList_{{product_name}}_false">
<div class="tag-container clearfix">
{{# tags}}
{{# is_new}}
... ... @@ -27,7 +28,11 @@
</div>
<div class="good-detail-img">
<a class="good-thumb" href="{{url}}">
<img class="lazy" data-original="{{image default_images 235 314}}">
{{#if @root._noLazy}}
<img src="{{image2 default_images w=235 h=314 q=60}}"/>
{{else}}
<img class="lazy" data-original="{{image2 default_images w=235 h=314 q=60}}"/>
{{/if}}
</a>
{{# is_soon_sold_out}}
<p class="few-tag">即将售罄</p>
... ...
<div class="banner-bottom">
<a href="{{url}}">
<img class="lazy" data-original="{{img}}" alt="">
<img class="lazy" data-original="{{image2 img q=60}}" alt="">
</a>
</div>
\ No newline at end of file
</div>
... ...
... ... @@ -5,13 +5,13 @@
{{#if @first}}
<li class="swiper-slide">
<a href="{{url}}">
<img src="{{image src 640 240}}">
<img src="{{image2 src w=640 h=240 q=60}}">
</a>
</li>
{{^}}
<li class="swiper-slide">
<a href="{{url}}">
<img class="swiper-lazy" data-src="{{image src 640 240}}">
<img class="swiper-lazy" data-src="{{image2 src w=640 h=240 q=60}}">
</a>
<div class="swiper-lazy-preloader"></div>
</li>
... ...
... ... @@ -2,7 +2,7 @@
{{#data}}
<div class="banner-list">
<a href="{{url}}">
<img src="{{image src 640 200}}" alt="">
<img src="{{image2 src w=640 h=200 q=60}}" alt="">
</a>
</div>
{{/data}}
... ... @@ -12,7 +12,7 @@
{{#data}}
<li class="swiper-slide">
<a href="{{url}}">
<img src="{{image src 640 200}}" alt="">
<img src="{{image2 src w=640 h=200 q=60}}" alt="">
</a>
</li>
{{/data}}
... ...
... ... @@ -3,7 +3,7 @@
<div class="creative-life">
{{# big_image}}
<a class="banner" href="{{url}}">
<img class="lazy" data-original="{{image src 640 403}}">
<img class="lazy" data-original="{{image2 src w=640 h=403 q=60}}">
</a>
{{/ big_image}}
<ul class="classify-list clearfix">
... ... @@ -11,7 +11,7 @@
<li class="classify">
<a href="{{url}}">
<div class="classify-logo">
<img class="lazy" data-original="{{image src 191 191}}">
<img class="lazy" data-original="{{image2 src w=191 h=191 q=60}}">
</div>
<p class="classify-name">{{title}}</p>
</a>
... ...
... ... @@ -6,7 +6,7 @@
{{#list}}
<li>
<a href="/product/sale/discount/detail?id={{id}}&channel={{@root.channel}}">
<img class="lazy" data-original="{{image cover_url 640 250}}" />
<img class="lazy" data-original="{{image2 cover_url w=640 h=250 q=60}}" />
<p class="discount-cont">
<span class="discount-title">{{title}}</span>
<span class="discount-time {{#if warn_color}}red-color{{/if}}">{{time}}</span>
... ...
{{#data}}
<div style="background-image:url({{image src 640 26}})" class="divide-image"></div>
{{/data}}
\ No newline at end of file
<div style="background-image:url({{image2 src w=640 h=26 q=60}})" class="divide-image"></div>
{{/data}}
... ...
... ... @@ -2,7 +2,7 @@
<div class="fav-brand-swiper">
<a class="swiper-header" href="{{link}}">
<div class="swiper-logo">
<img src="{{brandImg}}" alt=""/>
<img src="{{image2 brandImg q=60}}" alt=""/>
</div>
<div class="brand-info">
<span class="brand-name">{{brandName}}</span>
... ... @@ -23,7 +23,7 @@
{{# productList}}
<li class="swiper-slide">
<a href="{{link}}">
<img class="swiper-lazy" data-src="{{imgUrl}}" alt=""/>
<img class="swiper-lazy" data-src="{{image2 imgUrl q=60}}" alt=""/>
</a>
<div class="brand-product">
<div class="{{# discount}}price-discount{{/ discount}}">
... ... @@ -38,4 +38,4 @@
</div>
{{/if}}
</div>
{{/ hasFavBrand}}
\ No newline at end of file
{{/ hasFavBrand}}
... ...
... ... @@ -2,7 +2,7 @@
<li data-id="{{fav_id}}" class="{{#if invalidGoods}}invalidGoods{{/if}}">
<a href="{{link}}">
<div class="fav-img-box">
<img src="{{imgUrl}}" alt=""/>
<img src="{{iamge2 imgUrl q=60}}" alt=""/>
</div>
<div class="fav-info-list">
<h2>{{title}}</h2>
... ... @@ -30,4 +30,4 @@
</div>
</a>
</li>
{{/ hasFavProduct}}
\ No newline at end of file
{{/ hasFavProduct}}
... ...
{{> common/floor-header}}
<ul class="fine-brands clearfix">
{{# brands}}
{{# brands}}
<li class="brand">
<a href="{{url}}">
<div class="brand-logo">
<img class="lazy" data-original="{{img}}">
<img class="lazy" data-original="{{images img q=60}}">
</div>
<p class="brand-name">{{name}}</p>
</a>
</li>
{{/ brands}}
</ul>
\ No newline at end of file
</ul>
... ...
... ... @@ -4,7 +4,7 @@
{{# banner_image}}
<div class="fresh-swiper">
<a href="{{url}}">
<img class="lazy" data-original="{{image src 640 200}}">
<img class="lazy" data-original="{{image2 src w=640 h=200 q=60}}">
</a>
</div>
{{/ banner_image}}
... ... @@ -14,7 +14,7 @@
<li class="swiper-slide">
<div class="img-box">
<a href="{{url}}">
<img class="swiper-lazy" data-src="{{image default_images 235 314}}" alt="">
<img class="swiper-lazy" data-src="{{image2 default_images w=235 h=314 q=60}}" alt="">
</a>
<div class="swiper-lazy-preloader"></div>
</div>
... ...
... ... @@ -8,7 +8,7 @@
{{# bigList}}
<li class="swiper-slide">
<a href="{{url}}">
<img class="lazy" data-original="{{image src 640 403}}" alt="{{title}}">
<img class="lazy" data-original="{{image2 src w=640 h=403 q=60}}" alt="{{title}}">
</a>
</li>
{{/ bigList}}
... ... @@ -21,7 +21,7 @@
{{^}}
<div class="category-swiper">
<a href="{{url}}">
<img class="lazy" data-original="{{image src 640 403}}" alt="{{title}}">
<img class="lazy" data-original="{{image2 src w=640 h=403 q=60}}" alt="{{title}}">
</a>
</div>
{{/if}}
... ... @@ -33,9 +33,9 @@
<a href="{{url}}">
<div class="img-box">
{{#if @first}}
<img class="lazy" data-original="{{image src 258 383}}" alt="">
<img class="lazy" data-original="{{image2 src w=258 h=383 q=60}}" alt="">
{{^}}
<img class="lazy" data-original="{{image src 191 191}}" alt="">
<img class="lazy" data-original="{{image2 src w=191 h=191 q=60}}" alt="">
{{/if}}
</div>
<p class="category-name">{{title}}</p>
... ...
... ... @@ -6,7 +6,7 @@
<a href="{{url}}">
<div class="brand-logo">
{{!--此处不使用 Lazyload 是由于安卓 UC 10 版本加载不出来--}}
<img src="{{image src 158 174}}">
<img src="{{image2 src w=158 h=174 q=60}}">
</div>
<p class="brand-name">{{name}}</p>
</a>
... ... @@ -15,7 +15,7 @@
<li class="more">
<a class="{{#unless image.src}}default{{/unless}}" href="{{image.url}}">
<img src="{{image image.src 320 172}}">
<img class="lazy" data-original="{{image2 image.src w=320 h=172 q=60}}">
</a>
</li>
</ul>
... ...
... ... @@ -6,7 +6,7 @@
{{# list}}
<li class="swiper-slide">
<a href="{{url}}">
<img src="{{image src 140 140}}" alt="">
<img src="{{image2 src w=140 h=140 q=60}}" alt="">
<span class="brands-title">{{name}}</span>
</a>
</li>
... ... @@ -14,4 +14,4 @@
</ul>
</div>
</div>
{{/data}}
\ No newline at end of file
{{/data}}
... ...
{{#data}}
<div class="hot-category">
{{> common/floor-header-more}}
{{# banner}}
<a class="category-banner" href="{{url}}">
<img class="lazy" data-original="{{src}}">
<img class="lazy" data-original="{{image2 src q=60}}">
</a>
{{/ banner}}
<ul class="category-list clearfix">
... ... @@ -12,11 +12,11 @@
<li>
<a href="{{url}}">
<div class="img-box">
<img class="lazy" data-original="{{image src 140 140}}" alt="">
<img class="lazy" data-original="{{image2 src w=140 h=140 q=60}}" alt="">
</div>
</a>
</li>
{{/ list}}
</ul>
</div>
{{/data}}
\ No newline at end of file
{{/data}}
... ...
... ... @@ -2,12 +2,12 @@
<div class="hot-single">
{{> common/floor-header-more}}
{{> resources/new-floor-banner}}
<div class="hot-single-goods-list" {{#background}}style="background-image: url({{image src 640 330}})"{{/background}}>
<div class="hot-single-goods-list" {{#background}}style="background-image: url({{image2 src w=640 h=330 q=60}})"{{/background}}>
<ul>
{{#list}}
<li class="hot-single-goods">
<a href="//m.yohobuy.com/product/show_{{product_skn}}">
<img src="{{image default_images 153 206}}" alt="goods" class="goods-pic">
<img src="{{image2 default_images w=153 h=206 q=60}}" alt="goods" class="goods-pic">
<div class="goods-info">
<h3 class="price">&yen; {{sales_price}}</h3>
<p class="view-num">{{view_num}}</p>
... ... @@ -16,49 +16,7 @@
</a>
</li>
{{/list}}
<!--<li class="hot-single-goods">
<img src="" alt="goods" class="goods-pic">
<div class="goods-info">
<h3 class="price">&yen; 188.00</h3>
<p class="view-num">22人</p>
<p class="view-status">已加入收藏</p>
</div>
</li>
<li class="hot-single-goods">
<img src="" alt="goods" class="goods-pic">
<div class="goods-info">
<h3 class="price">&yen; 188.00</h3>
<img src="" alt="little-head-icon" class="head-icon">
<p class="view-num view-margin">大大王</p>
<p class="view-status view-margin">10分钟前购买</p>
</div>
</li>
<li class="hot-single-goods">
<img src="" alt="goods" class="goods-pic">
<div class="goods-info">
<h3 class="price">&yen; 188.00</h3>
<p class="view-num">12人</p>
<p class="view-status">正在浏览</p>
</div>
</li>
<li class="hot-single-goods">
<img src="" alt="goods" class="goods-pic">
<div class="goods-info">
<h3 class="price">&yen; 188.00</h3>
<p class="view-num">22人</p>
<p class="view-status">已加入收藏</p>
</div>
</li>
<li class="hot-single-goods">
<img src="" alt="goods" class="goods-pic">
<div class="goods-info">
<h3 class="price">&yen; 188.00</h3>
<img src="" alt="little-head-icon" class="head-icon">
<p class="view-num view-margin">大大王</p>
<p class="view-status view-margin">10分钟前购买</p>
</div>
</li>-->
</ul>
</div>
</div>
{{/data}}
\ No newline at end of file
{{/data}}
... ...
{{#appIconList}}
<div class="icons-wrapper" style="background-image:url({{image back_image 640 360}})">
<div class="icons-wrapper" {{#if back_image}} style="background-image:url({{image2 back_image w=640 h=360 q=60}})" {{/if}}>
<ul class="icons-list clearfix">
{{#data}}
<li class="icons-item item-{{../number}}"><a href="{{url}}" class="imagebar"><img src="{{image src 98 98}}" alt=""></a><a href="{{url}}" class="linkbar">{{title}}</a></li>
<li class="icons-item item-{{../number}}"><a href="{{url}}" class="imagebar"><img src="{{image2 src w=98 h=98 q=60}}" alt=""></a><a href="{{url}}" class="linkbar">{{title}}</a></li>
{{/data}}
</ul>
</div>
... ...
{
"name": "m-yohobuy-node",
"version": "5.2.5",
"version": "5.2.14",
"private": true,
"description": "A New Yohobuy Project With Express",
"repository": {
... ... @@ -22,6 +22,7 @@
"body-parser": "^1.15.2",
"captchapng": "0.0.1",
"cheerio": "^0.22.0",
"client-sessions": "^0.7.0",
"compression": "^1.6.2",
"connect-multiparty": "^2.0.0",
"cookie-parser": "^1.4.3",
... ... @@ -71,6 +72,7 @@
"postcss-center": "^1.0.0",
"postcss-clearfix": "^1.0.0",
"postcss-crip": "^2.0.1",
"postcss-loader": "^1.1.1",
"postcss-position": "^0.5.0",
"postcss-pxtorem": "^3.3.1",
"postcss-scss": "^0.3.1",
... ... @@ -93,7 +95,7 @@
"yoho-handlebars": "^4.0.5",
"yoho-iscroll": "^5.2.0",
"yoho-jquery": "^2.2.4",
"yoho-jquery-lazyload": "^1.9.7",
"yoho-jquery-lazyload": "^1.9.9",
"yoho-jquery-qrcode": "^0.14.0",
"yoho-mlellipsis": "0.0.3",
"yoho-qs": "^1.0.1",
... ...
... ... @@ -148,7 +148,7 @@ gulp.task('dist', ['ge'], () => {
// postcss compile in dev
gulp.task('postcss-dev', () => {
return gulp.src(['scss/shop.css', 'scss/index.css'])
return gulp.src(['scss/shop.css', 'scss/index.css', 'scss/common.css'])
.pipe(sourcemaps.init())
.pipe(postcss(postcssPlugin(env.dev), {
parser: require('postcss-scss')
... ... @@ -179,7 +179,7 @@ gulp.task('font', () => {
// postcss compile in pro
gulp.task('postcss', ['assets'], () => {
return gulp.src(['scss/shop.css', 'scss/index.css'])
return gulp.src(['scss/shop.css', 'scss/index.css', 'scss/common.css'])
.pipe(postcss(postcssPlugin(env.pro), {
parser: require('postcss-scss')
}))
... ... @@ -204,12 +204,19 @@ gulp.task('webpack-dev-server', () => {
loaders: {
css: ExtractTextPlugin.extract(['css?-url&sourceMap'])
}
},
postcss: {
plugins: postcssPlugin(env.dev),
options: {
parser: scss
}
}
});
devConfig.output.publicPath = 'http://localhost:5001/';
// 开发环境插件
devConfig.plugins[0] = new ExtractTextPlugin('bundle/[name].css');
devConfig.plugins.push(new webpack.HotModuleReplacementPlugin());
devConfig.entry.libs.unshift(`webpack-dev-server/client?${devConfig.output.publicPath}`, 'webpack/hot/dev-server');
... ... @@ -248,6 +255,16 @@ gulp.task('webpack', ['assets'], (done) => {
loaders: {
css: ExtractTextPlugin.extract(['css?-url'])
}
},
postcss: {
plugins: postcssPlugin(env.pro),
options: {
parser: scss
},
autoprefixer: false,
loaders: {
css: ExtractTextPlugin.extract(['css?-url'])
}
}
});
... ...
{{#content}}
{{! 头部banner}}
{{#if focus}}
{{> ../resources/banner-top}}
{{/if}}
{{! 图标入口}}
{{#if appIconList}}
{{> ../resources/icons-enter}}
{{/if}}
{{! 首页公告}}
{{!-- {{#announcement}}
{{> ../resources/notice}}
{{/announcement}} --}}
{{! 中间banner}}
{{#if singleImage}}
<div data-id="{{template_id}}">
{{> ../resources/banner}}
</div>
{{/if}}
{{! 两个小图}}
{{#if smallPic}}
{{> ../resources/thumb-row}}
{{/if}}
{{! 热门品类}}
{{#if recommendContentFive}}
{{> ../resources/hot-category}}
{{/if}}
{{! 热门品牌}}
{{#if appHotBrands}}
{{> ../resources/hot-brands-list}}
{{/if}}
{{! 热门品牌可滑动}}
{{#if customBrands}}
{{> ../resources/hot-brands-swipe}}
{{/if}}
{{! 潮人搭配}}
{{#if trendsetterCollocation}}
{{> ../resources/trendsetter-collocation}}
{{/if}}
{{! 潮流话题}}
{{#if trendgoodsTopic}}
{{> ../resources/trend-topics}}
{{/if}}
{{! 潮流时装/经典裤裙/时尚靴履/潮人配饰/潮流上装}}
{{#if recommendContentOne}}
{{> ../resources/goods-category}}
{{/if}}
{{! 新入住品牌/品味生活/创意生活}}
{{#if recommendContentTwo}}
{{> ../resources/creative-life}}
{{/if}}
{{! PLUS}}
{{#if singleNameImage}}
{{> ../resources/plus-star}}
{{/if}}
{{! 新人专享}}
{{#if oldNewUserFloor}}
{{> ../resources/fresh-only}}
{{/if}}
{{! 秒杀}}
{{#if seckill}}
{{> ../resources/seckill}}
{{/if}}
{{! 标题楼层}}
{{#if titleFloor}}
{{> ../resources/title-floor}}
{{/if}}
{{! 直播楼层}}
{{#if livePicture}}
{{> ../resources/live-picture}}
{{/if}}
{{! 六层图}}
{{#if sixLinesFloor}}
{{> ../resources/six-lines-floor}}
{{/if}}
{{! vip专属}}
{{#if vipUse}}
{{> ../resources/vip-only}}
{{/if}}
{{! 店铺推荐}}
{{#if shopRecommend}}
{{> ../resources/shop-recommand}}
{{/if}}
{{! 新新人专享}}
{{#if newUserFloor}}
{{> ../resources/new-user-floor}}
{{/if}}
{{! 人气单品}}
{{#if popularSingleProduct}}
{{> ../resources/hot-single}}
{{/if}}
{{! SALE}}
{{#if sale1T1L4R}}
{{> ../resources/sale-floor}}
{{/if}}
{{! 新品首发楼层}}
{{#if newProductFloor}}
{{> ../resources/new-first}}
{{/if}}
{{! 分隔楼层}}
{{#if divideImage}}
{{> ../resources/divide-image}}
{{/if}}
{{/content}}
... ...
{{# 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}}">&#xe618;</a>
{{/if}}
</div>
{{/ title}}
... ...
{{#title}}
<div class="floor-header">
<h2>{{title}}</h2>
</div>
{{/title}}
... ...
{{# imgList}}
<li>
{{# imgUrl}}
<img src="{{.}}" />
<span class="upload-img-remove"></span>
{{/ imgUrl}}
</li>
{{/ imgList}}
\ No newline at end of file
... ...
<div id="dialog-wrapper" class="dialog-wrapper">
<div class="dialog-box">
{{# hasHeader}}
<div class="dialog-header">{{.}}</div>
{{/ hasHeader}}
<div class="dialog-content">{{{dialogText}}}</div>
{{# hasFooter}}
<div class="dialog-footer">
{{# leftBtnText}}
<span class="dialog-left-btn tap-hightlight">{{.}}</span>
{{/ leftBtnText}}
{{# rightBtnText}}
<span class="dialog-right-btn tap-hightlight">{{.}}</span>
{{/ rightBtnText}}
</div>
{{/ hasFooter}}
</div>
</div>
\ No newline at end of file
... ...
{{# enterStore}}
<div id="enter-store" class="enter-store page-block tap-hightlight">
<a class="store-logo" href="{{url}}" style="">
<img class="lazy" src="{{image img 47 47}}" alt="{{storeName}}">
</a>
<a class="store-name" href="{{url}}">{{storeName}}</a>
<a class="store-link" href="{{url}}">进入店铺<span class="iconfont">&#xe604;</span></a>
</div>
{{/ enterStore}}
\ No newline at end of file
... ...
<ul id="nav-tab" class="nav-tab clearfix">
<li class="comment-nav tap-hightlight">商品评价(<span class="comments-num">{{commentsNum}}</span>)</li>
{{#if commonConsults}}
<li class="consult-nav tap-hightlight">常见问题</li>
{{^}}
<li class="consult-nav tap-hightlight">购买咨询(<span class="consults-num">{{consultsNum}}</span>)</li>
{{/if}}
</ul>
<div id="feedback-content" >
<div class="comment-content content ">
{{#if commentsNum}}
<div class="comment-content-main content-main">
{{# comments}}
<span class="user-name">
{{userName}}
</span>
<span class="goods-spec">
购买了{{desc}}
</span>
<p class="detail-content">
{{content}}
</p>
<span class="comment-time">
{{time}}
</span>
{{/ comments}}
</div>
<a class="comment-content-footer tap-hightlight" href="{{commentsUrl}}">
查看更多
<span class="iconfont">&#xe604;</span>
</a>
{{^}}
<div class="comment-content-main content-main no-item">
<span class="iconfont">&#xe63d;</span>暂无评论
</div>
{{/if}}
</div>
<div class="consult-content content hide ">
{{#if consultsNum}}
<div class="consult-content-main content-main">
{{# consults}}
<div class="question">
<span class="iconfont">&#xe644;</span>
<p>
{{question}}<br>
<span class="time">{{time}}</span>
</p>
</div>
<div class="answer">
<span class="iconfont">&#xe642;</span>
<p>{{answer}}</p>
</div>
{{/ consults}}
</div>
<a class="consult-content-footer tap-hightlight" href="{{consultsUrl}}">
查看更多
<span class="iconfont">&#xe604;</span>
</a>
{{else}}
<div class="consult-content-main content-main no-item">
<span class="iconfont">&#xe63f;</span>暂无咨询
</div>
<div class="consult-content-footer tap-hightlight">
<a href="{{consultsUrl}}">
我要咨询
<span class="iconfont">&#xe604;</span></a>
</div>
{{/if}}
</div>
</div>
\ No newline at end of file
... ...
{{# feedbacks}}
<div class="feedback-list ">
{{#if commentsNum}}
{{> ./feedback-tab}}
{{else}}
{{#if consultsNum}}
{{> ./feedback-tab}}
{{else}}
<div class="nodata tap-hightlight" id="goto-consult">
<span>暂无商品评价和咨询</span>
<a href="{{consultsUrl}}" class="go-consult">我要咨询<span class="iconfont">&#xe604;</span></a>
</div>
{{/if}}
{{/if}}
</div>
{{/ feedbacks}}
\ No newline at end of file
... ...
{{# cartInfo}}
<div class="chose-panel">
<div class="main">
<div class="infos {{#if @root.tickets}} tickets-info {{/if}}">
<div class="basic-info" >
{{#each thumbs}}
<img class="thumb {{#unless @first}}hide{{/unless}}" src="{{image2 img q=60}}">
{{/each}}
<div class="text-info">
<p class="name">{{name}}</p>
<p class="price">
{{#if price}}
<span class="sale-price">{{salePrice}}</span>
<span class="market-price">{{price}}</span>
{{else}}
{{# isY isSecKill}}
<span class="sale-price">{{salePrice}}</span>
<span class="market-price">{{salePrice}}</span>
{{else}}
<span class="sale-price no-price">{{salePrice}}</span>
{{/ isY}}
{{/if}}
</p>
</div>
</div>
<div class="chose-items">
<div class="color-list block-list">
<span class="name">{{#if @root.tickets}}日期{{else}}颜色{{/if}}</span>
{{#each colors}}
<ul id="{{id}}" data-index="{{@index}}" class="size-row clearfix {{#unless @first}}hide{{/unless}}">
{{#each color}}
<li class="block {{#if chosed}} chosed{{/if}} {{#unless colorNum}} zero-stock{{/unless}}" data-num="{{colorNum}}">{{name}}</li>
{{/each}}
</ul>
{{/each}}
</div>
<div class="size-list block-list {{#if @root.single}} hide{{/if}}">
<span class="name">{{#if @root.tickets}}区域{{else}}尺码{{/if}}</span>
{{#each sizes}}
<ul class="size-row clearfix {{#unless @first}}hide{{/unless}}">
{{#each size}}
<li class="block {{#if chosed}} chosed{{/if}} {{#unless sizeNum}} zero-stock {{/unless}}" data-num="{{sizeNum}}" data-id="{{id}}" data-skuid="{{skuId}}">{{name}}</li>
{{/each}}
</ul>
{{/each}}
</div>
<div class="num">
<span class="name">数量</span>
<div class="clearfix">
<a class="btn btn-minus" href="javascript:void(0);">
<span class="iconfont {{#if promotionId}}disabled{{/if}}">&#xe625;</span>
</a>
<input id="good-num" class="good-num disabled" type="text" value="1" disabled="true">
<a class="btn btn-plus" href="javascript:void(0);">
<span class="iconfont {{#if promotionId}}disabled{{/if}}">&#xe624;</span>
</a>
</div>
<span class="left-num"></span>
<input id="left-num" type="hidden" value="0">
<input id="limitNum" type="hidden" value="{{limit}}">
</div>
</div>
</div>
<div class="btn-wrap">
<button id="chose-btn-sure" class="btn btn-sure">{{#if @root.tickets}}立即购买{{else}}加入购物车{{/if}}</button>
</div>
</div>
<input id="promotionId" type="hidden" value="{{promotionId}}">
<input id="single" type="hidden" value="{{@root.single}}">
</div>
<div class="cart-bar">
{{#unless @root.wap.common.removeCartCount}}
<input type="hidden" id="remove-cart-count" value="1">
{{/unless}}
<a href="{{cartUrl}}" class="num-incart iconfont"><span class="num-tag {{#unless @root.cartCount}}hide{{/unless}}">{{@root.cartCount}}</span>&#xe62c;</a>
{{#if addToCartUrl}}
<a id="addtoCart" href="javascript:;" class="addto-cart add-to-cart-url">{{#if tickets}}立即购买{{else}}加入购物车{{/if}}</a>
{{/if}}
{{#if soldOut}}
<a id="soldOut" href="javascript:;" class="sold-out">已售罄</a>
{{/if}}
{{#if notForSale}}
<a id="notForSale" href="javascript:;" class="sold-out">非卖品</a>
{{/if}}
{{#if limitNotForSale}}
<a id="limitNotForSale" href="javascript:;" class="sold-out limit">即将发售</a>
{{/if}}
{{#if preSale}}
<a id="preSale" href="javascript:;" class="sold-out limit">即将开售</a>
{{/if}}
{{#if canBuyLimit}}
<a href="javascript:;" id="addtoCart" class="addto-cart can-buy-limit">立即购买</a>
{{/if}}
{{#if canNotBuy}}
<a href="javascript:;" class="addto-cart can-not-buy">立即购买</a>
{{/if}}
{{#if noLimitCode}}
<a id="noLimitCode" href="javascript:;" class="sold-out limit">立即购买</a>
{{/if}}
<input type="hidden" id="limitCodeUrl" name="limitCodeUrl" value="{{limitCodeUrl}}">
<input type="hidden" id="limitProductPay" name="limitProductPay" value="{{limitProductPay}}">
{{#if limitProductCode}}
<input type="hidden" id="limitProductCode" name="limitProductCode" value="{{limitProductCode}}">
{{/if}}
<a href="javascript:;" id="likeBtn" class="favorite iconfont {{#if @root.isCollect}}liked{{/if}}">&#xe605;</a>
</div>
{{/ cartInfo}}
{{#if loginUrl}}
<input type="hidden" name="loginUrl" id="loginUrl" value="{{loginUrl}}">
{{/if}}
{{# tickets}}
<form id="buyNowForm" method="post" action="{{ticketsConfirm}}">
<input type="hidden" name="productSku" id="productSku">
<input type="hidden" name="buyNumber" id="buyNumber">
</form>
{{/ tickets}}
... ...
{{#if studentPrice}}
<div class="price-date">
<div class="student-price">
<i class="student-name">学生价</i><span class="student-value">¥{{studentPrice}}</span>
</div>
</div>
{{else if vipLevel}}
<ul class="vip-level clearfix">
{{#each vipLevel.list}}
<li class="icons-item {{#if currentLevel}} current-level {{/if}}">
<span class="vip-img">
</span>
<span class="vip-price">{{text}}</span>
</li>
{{/each}}
</ul>
{{/if}}
\ No newline at end of file
... ...
{{!-- 商品促销 --}}
{{#if promotion}}
<div class="goods-discount" id="goodsDiscount">
{{#each promotion}}
{{#if @first}}
<h1 class="first-item short-text tap-hightlight">{{promotionTitle}}<span class="icon-down iconfont dropdown">&#xe609;</span></h1>
{{else}}
<div class="discount-folder">
<h1 class="folder-item tap-hightlight">{{promotionTitle}}</h1>
</div>
{{/if}}
{{/each}}
</div>
{{/if}}
\ No newline at end of file
... ...
... ... @@ -5,13 +5,13 @@
{{#if @first}}
<li class="swiper-slide">
<a href="{{url}}">
<img src="{{image src 640 240}}">
<img src="{{image2 src w=640 h=240 q=60}}">
</a>
</li>
{{^}}
<li class="swiper-slide">
<a href="{{url}}">
<img class="swiper-lazy" data-src="{{image src 640 240}}">
<img class="swiper-lazy" data-src="{{image2 src w=640 h=240 q=60}}">
</a>
<div class="swiper-lazy-preloader"></div>
</li>
... ...
<div class="banner-center banner-center-swiper">
{{#if singleOne}}
{{#data}}
<div class="banner-list">
<a href="{{url}}">
<img src="{{image2 src w=640 h=200 q=60}}" alt="">
</a>
</div>
{{/data}}
{{else}}
<ul class="banner-list swiper-wrapper clearfix">
{{#data}}
<li class="swiper-slide">
<a href="{{url}}">
<img src="{{image2 src w=640 h=200 q=60}}" alt="">
</a>
</li>
{{/data}}
</ul>
{{/if}}
<div class="swiper-pagination" {{#unless singleOne}}style="display:block"{{/unless}}>
<div class="pagination-inner">
</div>
</div>
</div>
... ...
{{#data}}
{{> ../common/floor-header-more}}
<div class="creative-life">
{{# big_image}}
<a class="banner" href="{{url}}">
<img class="lazy" data-original="{{image2 src w=640 h=403 q=60}}">
</a>
{{/ big_image}}
<ul class="classify-list clearfix">
{{# list}}
<li class="classify">
<a href="{{url}}">
<div class="classify-logo">
<img class="lazy" data-original="{{image2 src w=191 h=191 q=60}}">
</div>
<p class="classify-name">{{title}}</p>
</a>
</li>
{{/ list}}
</ul>
</div>
{{/data}}
... ...
{{#data}}
<div style="background-image:url({{image2 src w=640 h=30 q=60}})" class="divide-image"></div>
{{/data}}
... ...
{{#data}}
{{> ../common/floor-header-more}}
<div class="fresh-only">
{{# banner_image}}
<div class="fresh-swiper">
<a href="{{url}}">
<img class="lazy" data-original="{{image2 src w=640 h=200 q=60}}">
</a>
</div>
{{/ banner_image}}
<div class="fresh-list-swiper">
<ul class="clearfix swiper-wrapper">
{{# list}}
<li class="swiper-slide">
<div class="img-box">
<a href="{{url}}">
<img src="{{image2 default_images w=235 h=314 q=60}}" alt="">
</a>
<div class="swiper-lazy-preloader"></div>
</div>
<div class="fresh-info">
<p class="fresh-name"><a href="{{url}}">{{product_name}}</a></p>
<p class="price">
<span class="cur-price">¥{{sales_price}}</span>
{{# market_price}}
<span class="old-price">¥{{.}}</span>
{{/market_price}}
</p>
<span class="fresh-icon">新人价</span>
</div>
</li>
{{/ list}}
</ul>
</div>
</div>
{{/data}}
... ...
{{#data}}
{{> ../common/floor-header-more}}
<div class="goods-category">
{{# big_image}}
{{#if bigList}}
<div class="category-swiper">
<ul class="swiper-wrapper">
{{# bigList}}
<li class="swiper-slide">
<a href="{{url}}">
<img class="swiper-lazy" data-src="{{image2 src w=640 h=403 q=60}}" alt="{{title}}">
</a>
</li>
{{/ bigList}}
</ul>
<div class="swiper-pagination">
<div class="pagination-inner clearfix">
</div>
</div>
</div>
{{^}}
<div class="category-swiper">
<a href="{{url}}">
<img src="{{image2 src w=640 h=403 q=60}}" alt="{{title}}">
</a>
</div>
{{/if}}
{{/ big_image}}
{{#if list}}
<ul class="category-list clearfix">
{{# list}}
<li>
<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=191 h=191 q=60}}" alt="">
{{/if}}
</div>
<p class="category-name">{{title}}</p>
</a>
</li>
{{/ list}}
</ul>
{{/if}}
</div>
{{/data}}
... ...
{{#data}}
<ul class="hot-brands clearfix">
{{> ../common/floor-header-more}}
{{# list}}
<li class="brand">
<a href="{{url}}">
<div class="brand-logo">
{{!--此处不使用 Lazyload 是由于安卓 UC 10 版本加载不出来--}}
<img src="{{image2 src w=158 h=174 q=60}}">
</div>
<p class="brand-name">{{name}}</p>
</a>
</li>
{{/ list}}
<li class="more">
<a class="{{#unless image.src}}default{{/unless}}" href="{{image.url}}">
<img src="{{image2 image.src w=320 h=172 q=60}}">
</a>
</li>
</ul>
{{/data}}
... ...
{{#data}}
<div class="hot-brands">
{{> ../common/floor-header}}
<div class="brands-swiper">
<ul class="brands-list swiper-wrapper clearfix">
{{# list}}
<li class="swiper-slide">
<a href="{{url}}">
<img src="{{image2 src w=140 h=140 q=60}}" alt="">
<span class="brands-title">{{name}}</span>
</a>
</li>
{{/ list}}
</ul>
</div>
</div>
{{/data}}
... ...
{{#data}}
<div class="hot-category">
{{> ../common/floor-header-more}}
{{# banner}}
<a class="category-banner" href="{{url}}">
<img class="lazy" data-original="{{image2 src q=60}}">
</a>
{{/ banner}}
<ul class="category-list clearfix">
{{# list}}
<li>
<a href="{{url}}">
<div class="img-box">
<img class="lazy" data-original="{{image2 src w=140 h=140 q=60}}" alt="">
</div>
</a>
</li>
{{/ list}}
</ul>
</div>
{{/data}}
... ...
{{#data}}
<div class="hot-single">
{{> ../common/floor-header-more}}
{{> ./new-floor-banner}}
<div class="hot-single-goods-list" {{#background}}style="background-image: url({{image2 src w=640 h=200 q=60}})"{{/background}}>
<ul>
{{#list}}
<li class="hot-single-goods">
<a href="//m.yohobuy.com/product/show_{{product_skn}}">
<img src="{{image2 default_images w=153 h=206 q=60}}" alt="goods" class="goods-pic">
<div class="goods-info">
<h3 class="price">&yen; {{sales_price}}</h3>
<p class="view-num">{{view_num}}</p>
<p class="view-status">正在浏览</p>
</div>
</a>
</li>
{{/list}}
</ul>
</div>
</div>
{{/data}}
... ...
{{#appIconList}}
<div class="icons-wrapper" {{#if back_image}} style="background-image:url({{image2 back_image q=60}})" {{/if}}>
<ul class="icons-list clearfix">
{{#data}}
<li class="icons-item item-{{../number}}"><a href="{{url}}" class="imagebar"><img src="{{image2 src w=98 h=98 q=60}}" alt=""></a><a href="{{url}}" class="linkbar">{{title}}</a></li>
{{/data}}
</ul>
</div>
{{/appIconList}}
... ...
{{> ./title-floor}}
{{> ./three-picture}}
... ...