Authored by biao

Merge branch 'develop' into feature/my-order

Showing 65 changed files with 2774 additions and 1085 deletions

Too many changes to show.

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

const model = require('../models');
exports.index = (req, res) => {
res.render('index', Object.assign({
res.display('index', Object.assign({
module: 'channel',
page: 'home'
}, model.getContent()));
... ...
... ... @@ -8,15 +8,32 @@
const mcHandler = require('../models/menu-crumb-handler');
const addressModel = require('../models/address');
const _ = require('lodash');
/**
* 默认地址
*/
const _setDefault = (id, uid) => {
return addressModel.setDefaultAddress(id, uid).then(result => result);
};
/**
* 收货地址页面加载
*/
const index = (req, res) => {
addressModel.getAddressDataAsync('123456', 20).then(result => {
for (let i = 0; i < result.data.length; i++) {
result.data[i].default = result.data[i].is_default === 'Y';
const index = (req, res, next) => {
let uid = req.user.uid || '123456';
addressModel.getAddressDataAsync(uid, 20).then(result => {
let resultData = result.data;
let length = resultData.length ? resultData.length : 0;
for (let i = 0; i < length; i++) {
resultData[i].default = resultData[i].is_default === 'Y';
resultData[i].mobile = resultData[i].mobile.substring(0, 3) + '****' +
resultData[i].mobile.substring(7, 11);
}
result.data.leftLength = 20 - result.data.length;
resultData.leftLength = 20 - length;
resultData.length = length;
res.render('index', {
module: 'me',
page: 'address',
... ... @@ -27,9 +44,20 @@ const index = (req, res) => {
banner: 'http://placehold.it/150x120',
address: true,
title: '收货地址',
data: result.data
data: resultData
}
});
}).catch(next);
};
const getAddressList = (req, res) => {
addressModel.getAddressDataAsync('7566245', 20).then(result => {
if (result.data) {
let defaultAd = _.find(result.data, o => o.is_default === 'Y');
defaultAd && (defaultAd.focus = true);
}
res.send(result);
});
};
... ... @@ -37,15 +65,29 @@ const index = (req, res) => {
* 添加地址
*/
const addAddressData = (req, res) => {
let uid = req.body.uid;
let uid = req.user.uid || '123456';
let address = req.body.address;
let areaCode = req.body.area_code;
let consignee = req.body.consignee;
let mobile = req.body.mobile;
let phone = req.body.phone;
let isInit = req.body.init; // 是否是初始地址
addressModel.addAddressData(uid, address, areaCode, consignee, mobile, phone).then(result => {
res.send(result);
if (isInit) {
_setDefault(uid, result.data.id).then(defaultResult => {
if (defaultResult.code === 200) {
Object.assign(result.data, {
is_default: 'Y'
});
res.send(result);
}
});
} else {
res.send(result);
}
});
};
... ... @@ -54,7 +96,7 @@ const addAddressData = (req, res) => {
*/
const updateAddressData = (req, res) => {
let id = req.body.id;
let uid = req.body.uid;
let uid = req.user.uid || '123456';
let address = req.body.address;
let areaCode = req.body.area_code;
let consignee = req.body.consignee;
... ... @@ -71,7 +113,7 @@ const updateAddressData = (req, res) => {
*/
const delAddressData = (req, res) => {
let id = req.body.id;
let uid = req.body.uid;
let uid = req.user.uid || '123456';
addressModel.delAddressData(id, uid).then(result => {
res.send(result);
... ... @@ -83,9 +125,9 @@ const delAddressData = (req, res) => {
*/
const setDefaultAddress = (req, res) => {
let id = req.body.id;
let uid = req.body.uid;
let uid = req.user.uid || '123456';
addressModel.setDefaultAddress(id, uid).then(result => {
_setDefault(id, uid).then(result => {
res.send(result);
});
};
... ... @@ -114,6 +156,7 @@ const getAddressData = (req, res) => {
module.exports = {
index,
getAddressList,
addAddressData,
updateAddressData,
delAddressData,
... ...
/**
* [个人中心]yoho币
* @author: jiangmin
* @date: 2016/07/11
*/
'use strict';
const mcHandler = require('../models/menu-crumb-handler');
const currencyModel = require('../models/currency');
const moment = require('moment');
const convertUnitTime = (src) => {
return moment.unix(src).format('YYYY-MM-DD');
};
/**
* yoho币页面加载
*/
const index = (req, res) => {
let uid = req.user.uid || '8041246';
var page = parseInt(req.query.page) || 1;
var queryType = parseInt(req.query.queryType) || 0;
var beginTime = req.query.beginTime || convertUnitTime(new Date() / 1000 - 3600 * 24 * 90);
var date1 = new Date().getTime() / 1000;
var date2 = new Date(beginTime).getTime() / 1000;
var selectIndex = parseInt((date1 - date2) / (3600 * 24 * 30 * 6));
console.log('请求参数:', 'page:' + page, 'queryType:' + queryType, 'beginTime:' + beginTime);
currencyModel.getIndexData(uid, page, queryType, beginTime).then(result=> {
result.list.tabs[queryType].isActive = true;
result.list.coinList.forEach(function(x) {
x.date = x.date.replace(/\-/g, '.');
});
result.list.selects[selectIndex].isSelected = 'selected';
if (result.list.paginationOpts) {
result.list.paginationOpts.queryParams = {
queryType: queryType,
beginTime: beginTime
};
}
console.log('返回个数:' + result.list.total);
res.render('index', {
module: 'me',
page: 'currency',
isMe: true,
content: {
nav: mcHandler.getMeCrumb(),
navigation: mcHandler.getSideMenu('YOHO币'),
banner: 'http://placehold.it/150x120',
currency: true,
tabs: result.list.tabs,
title: '我的YOHO币',
currentYear: new Date().getFullYear(),
data: result.list.coinList,
paginationOpts: result.list.paginationOpts,
num: result.num.data,
selects: result.list.selects,
total: result.list.total
}
});
});
};
module.exports = {
index
};
... ...
... ... @@ -20,13 +20,7 @@ const getAddressDataAsync = (uid, limit) => {
method: 'app.address.gethidden',
uid: uid,
limit: limit
}).then(result => {
// console.log('列表结果result', result);
if (result.code === '200') {
return result.data;
}
return result;
});
}).then(result => result);
};
/**
... ... @@ -137,10 +131,10 @@ const getAddressData = (areaId) => {
};
module.exports = {
getAddressDataAsync: getAddressDataAsync,
addAddressData: addAddressData,
updateAddressData: updateAddressData,
delAddressData: delAddressData,
setDefaultAddress: setDefaultAddress,
getAddressDataAsync,
addAddressData,
updateAddressData,
delAddressData,
setDefaultAddress,
getAddressData
};
... ...
/**
* [个人中心]YOHO币
* @author: jiangmin
* @date: 2016/07/11
*/
'use strict';
const api = global.yoho.API;
const camelCase = global.yoho.camelCase;
/**
* yoho币列表数据
* @param uid
* @param page
* @param queryType
* @param beginTime
* @returns {*}
*/
const yohoCoinList = (uid, page, queryType, beginTime) => {
var pageSize = 15;
return api.get('', {
method: 'app.yohocoin.lists',
uid: uid,
page: page,
limit: pageSize,
queryType: queryType,
beginTime: beginTime
}).then(result => {
// console.log("列表接口",result);
let coinList = [];
let total = false;
let curPage = 1;
if (result && result.data) {
coinList = camelCase(result.data.coinlist);
total = result.data.total;
curPage = result.data.page;
}
const paginationOpts = total > 15 ? {
paginationOpts: {
total: total,
page: curPage,
limit: pageSize,
queryParams: {}
}
} : false;
const tabs = [
{
text: '全部明细',
type: 'all'
},
{
text: '全部收入',
type: 'paying'
},
{
text: '全部支出',
type: 'delivering'
}
];
const selects = [
{
text: '近三个月的明细',
value: 3
},
{
text: '近半年的明细',
value: 6
},
{
text: '近一年的明细',
value: 12
}
];
return {
coinList: coinList,
total: total,
curPage: curPage,
paginationOpts: paginationOpts.paginationOpts,
tabs: tabs,
selects: selects
};
});
};
/**
* yoho币总数
* @returns {*}
*/
const yohoCoinTotal = (uid)=> {
return api.get('', {
method: 'app.yoho.yohocoin',
uid: uid
}).then(result => {
// console.log("总数接口",result);
return result;
});
};
const getIndexData = (uid, page, queryType, beginTime) => {
let getData = [yohoCoinList(uid, page, queryType, beginTime), yohoCoinTotal(uid)];
return Promise.all(getData).then(result => {
// console.log("合并接口", result);
return {
list: result[0],
num: result[1]
};
});
};
module.exports = {
getIndexData: getIndexData
};
... ...
... ... @@ -12,6 +12,7 @@ const cRoot = './controllers';
// 订单
const order = require(`${cRoot}/order`);
const address = require(`${cRoot}/address`);
const currency = require(`${cRoot}/currency`);
// 个人中心首页/订单
router.get(['/', '/order'], order.index);
... ... @@ -29,6 +30,10 @@ router.post('/address/add', address.addAddressData);
router.post('/address/update', address.updateAddressData);
router.post('/address/del', address.delAddressData);
router.post('/address/default', address.setDefaultAddress);
router.get('/address/list', address.getAddressList); // 获取地址列表
router.get('/address/areas/:areaId', address.getAddressData);
// 个人中心首页/YOHO币
router.get('/currency', currency.index);
module.exports = router;
... ...
... ... @@ -48,7 +48,7 @@
{{!-- 我的YOHO币 --}}
{{#if currency}}
{{> curency}}
{{> currency}}
{{/if}}
{{!-- 个人设置 --}}
... ...
... ... @@ -5,32 +5,27 @@
<div class="form-group">
<label class="label-name">&nbsp;&nbsp;收货人:</label>
<input id="address_id" type="hidden" value="">
<input id="consignee" class="input width-190" type="text" placeholder="请输入您的姓名" maxlength="10">
<input id="consignee" class="input" type="text" placeholder="请输入您的姓名" maxlength="10">
<span class="blue error-tips">{{> icon/error-round}}收件人不能为空</span>
</div>
<div class="form-group">
<div class="form-group-address">
<label class="label-name">所在区域:</label>
<div id="address"></div>
<span class="blue error-tips">{{> icon/error-round}}所在区域不能为空</span>
</div>
<div class="form-group">
<label class="label-name">详细地址:</label>
<input id="addressDetail" class="input width-275" type="text" placeholder="街道名称或小区名称" maxlength="60">
<input id="addressDetail" class="input address-detail" type="text" placeholder="街道名称或小区名称" maxlength="60">
<span class="blue error-tips">{{> icon/error-round}}详细地址不能为空</span>
</div>
<div class="form-group">
<label class="label-name">手机号码:</label>
<input id="mobile" class="input width-190" type="text" placeholder="请输入手机号码(重要必填)" maxlength="11">
<input id="mobile" class="input" type="text" placeholder="请输入手机号码(重要必填)" maxlength="11">
<span class="blue error-tips">{{> icon/error-round}}手机号码不能为空</span>
</div>
<div class="form-group">
<label class="label-name">电话号码:</label>
<input id="phone" class="input width-190" type="text" placeholder="请输入电话号码(选填)">
</div>
<div class="form-group ">
<label class="label-name"></label>
<span class="iconfont radio default-address opreation">&#xe604;</span>
<label class="radio-lable">设置为默认收货地址</label>
<input id="phone" class="input" type="text" placeholder="请输入电话号码(选填)">
</div>
<div class="form-group">
<span class="btn opreation" id="save-address">保存</span>
... ...
... ... @@ -3,16 +3,17 @@
<span class="blue table-title">已保存了{{data.length}}条地址,还能保存{{data.leftLength}}条地址</span>
<table class="a-table">
<tr class="table-head">
<th class="width-80">收货人</th>
<th class="width-70">收货人</th>
<th class="width-195">所在区域</th>
<th class="width-280">详细地址</th>
<th class="width-255">详细地址</th>
<th class="width-120">手机/电话</th>
<th class="width-260">操作</th>
</tr>
{{#each data}}
<tr class="table-body">
<input type="hidden" id="tr_{{address_id}}" value="{{address_id}}">
<td class="width-80">{{consignee}}</td>
<input type="hidden" id="tr_{{area_code}}" value="{{area_code}}">
<td class="width-70">{{consignee}}</td>
<td class="width-195">{{area}}</td>
<td class="width-255">{{address}}</td>
<td class="width-120"><p>{{mobile}}</p><p>{{phone}}</p></td>
... ...
<div class="user-currency">
{{> common/subtitle}}
<div class="currency-title">
<div class="inline-block yohocoin-icon">
</div>
<div class="inline-block total-yohocoin">
<div class="current-yohocoin">目前可用YOHO币:<span class="blue">{{num.yohocoin_num}}</span></div>
<div class="left-yohocoin">{{currentYear}}年12月31日即将过期:<span class="blue">{{num.nearExpCoinNum}}</span></div>
</div>
</div>
{{> currency/nav}}
{{> currency/table-body}}
</div>
... ...
<div class="order-nav">
<ul class="tabs clearfix">
{{#tabs}}
<li class="{{#if isActive}}active{{/if}}" data-type="{{type}}">{{text}}</li>
{{/tabs}}
</ul>
<div class="search-bar">
<select id="begin-time" >
{{#each selects}}
{{#if isSelected}}
<option value="{{value}}" selected={{isSelected}}>{{text}}</option>
{{else}}
<option value="{{value}}" >{{text}}</option>
{{/if}}
{{/each}}
</select>
<span class="blue">{{> icon/doubt}}什么是YOHO币</span>
</div>
</div>
... ...
<br>
<table class="currency-table">
<tr class="currency-header">
<th class="td-time">日期</th>
<th class="td-coin">收入/支出</th>
<th class="td-detail">详细说明</th>
</tr>
{{#each data}}
<tr class="currency-body">
<td class="td-time">{{date}}</td>
<td class="td-coin">{{num}}</td>
<td class="td-detail">{{message}}</td>
<input type="hidden" value="{{type}}">
</tr>
{{/each}}
</table>
<div class="currency-footer">
<div class="inline-block total">总共{{total}}条消息</div>
<div class="inline-block coin-pagination">
{{#if paginationOpts}}
{{{ pagination paginationOpts }}}
{{/if}}
</div>
</div>
... ...
... ... @@ -78,9 +78,9 @@ passport.use(new LocalStrategy({
let accountTimes = _.parseInt(times[1]) || 0;
let ipTimes = _.parseInt(times[2]) || 0;
if (accountTimes >= Infinity) {
if (accountTimes >= 10) {
done({message: '您的账号已被暂时锁定,请稍后再试'}, null);
} else if (ipTimes >= Infinity) {
} else if (ipTimes >= 100) {
done({message: '您尝试的次数过多,账号已被暂时锁定,请稍后再试'}, null);
} else {
return AuthHelper.signin(area, username, password, shoppingKey).then((result) => {
... ...
... ... @@ -185,45 +185,33 @@ const validateCodeByEmailPage = (req, res, next) => {
.catch(next);
};
const resetPasswordPage = (req, res, next) => {
const resetPasswordPage = (req, res) => {
let code = req.query.code || '';
passportHelper.getLeftBannerAsync()
.then(result => {
res.render('back/reset-pwd', Object.assign({
module: 'passport',
page: 'back-reset-pwd',
title: '重置密码'
}, {
resetPwd: Object.assign({
coverHref: result.url,
coverImg: result.img,
code: code
}, req.mobileAuth)
}));
})
.catch(next);
res.render('back/reset-pwd', Object.assign({
module: 'passport',
page: 'back-reset-pwd',
title: '重置密码'
}, {
resetPwd: Object.assign({
code: code
}, req.mobileAuth)
}));
};
const verifyCodeByMobilePage = (req, res, next) => {
passportHelper.getLeftBannerAsync()
.then(result => {
res.render('back/verification', Object.assign({
module: 'passport',
page: 'back-verify-mobile-code',
title: '手机验证'
}, {
verification: {
coverHref: result.url,
coverImg: result.img,
mobile: req.body.mobile,
area: req.body.area,
verifyCode: req.body.verifyCode
}
}));
})
.catch(next);
const verifyCodeByMobilePage = (req, res) => {
res.render('back/verification', Object.assign({
module: 'passport',
page: 'back-verify-mobile-code',
title: '手机验证'
}, {
verification: {
mobile: req.body.mobile,
area: req.body.area,
verifyCode: req.body.verifyCode
}
}));
};
const validateSuccessStatusPage = (req, res, next) => {
... ...
... ... @@ -11,7 +11,6 @@ const helpers = global.yoho.helpers;
const PassportHelper = require('../models/passport-helper');
const BindService = require('../models/bind-service');
const AuthHelper = require('../models/auth-helper');
const UserService = require('../models/user-service');
const Sources = {
qq: 'QQ',
... ... @@ -27,84 +26,119 @@ const bind = {
let openId = req.query.openId;
let sourceType = req.query.sourceType;
res.render('bind', {
thirdLogin: true,
openId: openId,
sourceType: sourceType,
region: PassportHelper.getCountry(),
serviceUrl: helpers.urlFormat('/help', {
category_id: 9
}),
res.render('bind/index', Object.assign({
module: 'passport',
page: 'bind',
title: '联合登录补全信息'
});
}, {
openId: openId,
sourceType: sourceType,
region: PassportHelper.getCountry(),
local: '+86',
imgCaptcha: helpers.urlFormat('/passport/images', {t: Date.now()})
}));
},
noregist: (req, res) => {
bindSetPwdPage: (req, res) => {
let mobile = req.body.mobile;
let sourceType = req.body.sourceType;
let openId = req.body.openId;
let area = req.body.area;
res.render('bind/noregist', {
enablePerfectInformation: true,
res.render('bind/bind-set-pwd', Object.assign({
module: 'passport',
page: 'bind-set-pwd',
title: '登录绑定'
}, {
mobile: mobile,
sourceType: sourceType,
openId: openId,
area: area,
module: 'passport',
page: 'noregist',
title: '登录绑定'
});
area: area
}));
},
relate: (req, res, next) => {
let mobile = req.body.mobile;
let sourceType = req.body.sourceType;
let openId = req.body.openId;
let area = req.body.area;
bindConfirmPage: (req, res) => {
let thirdPart = req.body.thirdPart;
let user = req.body.user;
UserService.findByMobileAsync(area, mobile).then(user => {
if (user) {
return {
thumb: user.headImg,
userName: user.username,
loginHref: user.bindLogin
};
} else {
return {};
}
}).then(user => {
let data = _.assign(user, {
phoneNum: mobile,
areaCode: area,
openId: openId,
sourceType: sourceType,
changeHref: helpers.urlFormat('/passport/thirdlogin/index', {openId: openId, sourceType: sourceType}),
module: 'passport',
page: 'noregist',
title: '账号关联'
});
res.render('bind/relate', data);
}).catch(next);
const DEFAULT_URL = 'http://img10.static.yhbimg.com/headimg/2013/11/28/09/01cae078abe5fe320c88cdf4c220212688.gif?imageView/2/w/100/h/100';
let avatar = user.headImg || DEFAULT_URL;
res.render('bind/bind-confirm', Object.assign({
module: 'passport',
page: 'bind-confirm',
title: '绑定确认'
}, {
avatar: avatar,
name: user.username || '咸鸭蛋',
bindSuccess: helpers.urlFormat('/thirdlogin/bindSuccess', {
sourceType: thirdPart.sourceType
}),
bindUrl: helpers.urlFormat('/passport/thirdlogin/index', {
openId: thirdPart.openId,
sourceType: thirdPart.sourceType
}),
loginUrl: helpers.urlFormat('/passport/login'),
uid: user.uid,
mobile: thirdPart.mobile,
area: thirdPart.area,
code: thirdPart.code,
sourceType: thirdPart.sourceType
}));
},
bindSuccess: (req, res) => {
bindSuccessPage: (req, res) => {
let sourceType = _.trim(req.query.sourceType);
let sourceInfo = sourceType.split('_');
let sourceName = Sources[sourceInfo[0]];
let isRelate = (sourceInfo[1] === 'relate');
let data = {
thirdLogin: true,
goShopping: helpers.urlFormat('/'),
sourceName: sourceName,
relate: isRelate,
res.render('bind/bind-success', Object.assign({
module: 'passport',
page: 'bind-success',
title: '绑定手机号'
};
}, {
goShopping: helpers.urlFormat('/'),
sourceName: sourceName
}));
},
relateSuccessPage: (req, res) => {
let sourceType = _.trim(req.query.sourceType);
let sourceInfo = sourceType.split('_');
let sourceName = Sources[sourceInfo[0]];
res.render('bind/relate-success', Object.assign({
module: 'passport',
page: 'relate-success',
title: '关联手机号'
}, {
goShopping: helpers.urlFormat('/'),
sourceName: sourceName
}));
},
relateConfirmPage: (req, res) => {
let thirdPart = req.body.thirdPart;
let user = req.body.user;
const DEFAULT_URL = 'http://img10.static.yhbimg.com/headimg/2013/11/28/09/01cae078abe5fe320c88cdf4c220212688.gif?imageView/2/w/100/h/100';
let avatar = user.headImg || DEFAULT_URL;
res.render('bind/success', data);
res.render('bind/relate-confirm', Object.assign({
module: 'passport',
page: 'bind-confirm',
title: '关联确认'
}, {
avatar: avatar,
name: user.username || '咸鸭蛋',
relateUrl: helpers.urlFormat('/passport/thirdlogin/index', {
openId: thirdPart.openId,
sourceType: thirdPart.sourceType
}),
signinUrl: helpers.urlFprmat('/passport/login'),
mobile: thirdPart.mobile,
area: thirdPart.area,
sourceType: thirdPart.sourceType,
openId: thirdPart.openId
}));
},
bindCheck: (req, res, next) => {
let mobile = req.body.mobile;
... ... @@ -115,35 +149,35 @@ const bind = {
if (mobile && openId && area && sourceType) {
BindService.bindCheck(mobile, openId, sourceType, area).then(result => {
if (!result || !result.code) {
return { code: 400, message: '', data: '' };
return {code: 400, message: '', data: ''};
} else if (result.code === 200 && result.data.is_register === 0) {
let nextUrl = helpers.urlFormat('/passport/thirdlogin/noregist');
let nextUrl = helpers.urlFormat('/passport/thirdlogin/bindSetPwd');
// 绑定流程:code=200 未注册,可绑定
return { code: 200, message: result.message, data: { next: nextUrl } };
return {code: 200, message: result.message, data: {next: nextUrl}};
} else if (result.code === 200 && result.data.is_register === 1) {
return PassportHelper.getUserInfo(area, mobile).then(user => {
// 绑定流程:code=201 已注册 绑定过其他第三方
return {code: 201, message: result.message, data: { user: user } };
return {code: 201, message: result.message, data: {user: user}};
});
} else if (result.code === 200 && result.data.is_register === 3) {
let nextUrl = helpers.urlFormat('/passport/thirdlogin/relate');
// 关联流程
return { code: 203, message: result.message, data: { next: nextUrl } };
return {code: 203, message: result.message, data: {next: nextUrl}};
} else if (result.code === 506 || result.code === 505) {
return PassportHelper.getUserInfo(area, mobile).then(user => {
// 绑定流程:code=201 已注册 绑定过其他第三方
return { code: 205, message: result.message, data: { user: user } };
return {code: 205, message: result.message, data: {user: user}};
});
} else {
return { code: result.code, message: result.message, data: result.data ? result.data : '' };
return {code: result.code, message: result.message, data: result.data ? result.data : ''};
}
}).then(result => {
res.json(result);
}).catch(next);
} else {
res.json({ code: 400, message: '', data: '' });
res.json({code: 400, message: '', data: ''});
}
},
sendBindMsg: (req, res, next) => {
... ... @@ -154,7 +188,7 @@ const bind = {
if (result && result.code) {
res.json(result);
} else {
res.json({ code: 400, message: '', data: '' });
res.json({code: 400, message: '', data: ''});
}
}).catch(next);
},
... ... @@ -167,7 +201,7 @@ const bind = {
if (result && result.code) {
res.json(result);
} else {
res.json({ code: 400, message: '', data: '' });
res.json({code: 400, message: '', data: ''});
}
}).catch(next);
},
... ... @@ -176,16 +210,9 @@ const bind = {
let area = _.trim(req.body.area) || '86';
let openId = _.trim(req.body.openId);
let sourceType = _.trim(req.body.sourceType);
let code = _.trim(req.body.code);
let password = _.trim(req.body.password) || '';
BindService.checkBindCode(area, mobile, code).then(result => {
if (result && result.code !== 200) {
return { code: 402, message: '短信验证码不正确', data: '' };
} else {
return BindService.bindMobile(openId, sourceType, mobile, area, password);
}
}).then(result => {
BindService.bindMobile(openId, sourceType, mobile, area, password).then(result => {
if (result && result.code) {
if (result.code === 200 && result.data && result.data.uid) {
let refer = helpers.urlFormat('/passport/thirdlogin/bindsuccess', {
... ... @@ -193,10 +220,10 @@ const bind = {
});
return AuthHelper.syncUserSession(result.data.uid, req, res).then(() => {
return { code: 200, message: result.message, data: {refer: refer }};
return {code: 200, message: result.message, data: {refer: refer}};
});
} else {
return { code: result.code, message: result.message, data: { refer: ''} };
return {code: result.code, message: result.message, data: {refer: ''}};
}
} else {
return {code: 400, message: '', data: ''};
... ... @@ -210,37 +237,26 @@ const bind = {
let openId = req.body.openId;
let areaCode = req.body.areaCode || '86';
let sourceType = req.body.sourceType;
let code = req.body.code;
if (_.isNumber(parseInt(mobile, 0)) && openId && areaCode && sourceType && code) {
BindService.checkBindCode(areaCode, mobile, code).then(result => {
if (result && result.code && result.code === 200) {
return BindService.relateMobile(openId, sourceType, mobile, code);
} else {
return { code: 402, message: '短信验证码错误', data: '' };
}
}).then(result => {
if (result && result.code) {
if (result.code === 200 && result.data && result.data.uid) {
let refer = helpers.urlFormat('/passport/thirdlogin/bindsuccess', {
sourceType: sourceType + '_bind'
});
return AuthHelper.syncUserSession(result.data.uid, req, res).then(() => {
return { code: 200, message: result.message, data: {refer: refer }};
});
} else {
return { code: result.code, message: result.message, data: { refer: ''} };
}
return BindService.relateMobile(openId, sourceType, mobile, areaCode).then(result => {
if (result && result.code) {
if (result.code === 200 && result.data && result.data.uid) {
let refer = helpers.urlFormat('/passport/thirdlogin/relatesuccess', {
sourceType: sourceType + '_bind'
});
return AuthHelper.syncUserSession(result.data.uid, req, res).then(() => {
return {code: 200, message: result.message, data: {refer: refer}};
});
} else {
return {code: 400, message: '', data: ''};
return {code: result.code, message: result.message, data: {refer: ''}};
}
}).then(result => {
res.json(result);
}).catch(next);
} else {
res.json({ code: 400, message: '', data: '' });
}
} else {
return {code: 400, message: '', data: ''};
}
}).then(result => {
res.json(result);
}).catch(next);
}
};
... ...
... ... @@ -45,8 +45,25 @@ const generate = (req, res) => {
res.end(captcha.image);
};
const requiredPost = (req, res) => {
let captchaToken = req.body.verifyCode || '';
if (captchaToken === req.session.captcha) {
return res.json({
code: 200,
data: {}
});
} else {
return res.json({
code: 400,
message: '您输入的验证码不正确!'
});
}
};
module.exports = {
requiredAPI,
requiredPage,
generate
generate,
requiredPost
};
... ...
... ... @@ -16,7 +16,7 @@ const config = global.yoho.config;
const cache = global.yoho.cache;
const AuthHelper = require('../models/auth-helper');
const PassportHelper = require('../models/passport-helper');
const loginPage = `${config.siteUrl}/signin.html`;
const loginPageURL = `${config.siteUrl}/passport/login`;
// 第三方登录回调
function doPassportCallback(req, res, user) {
... ... @@ -32,23 +32,16 @@ function doPassportCallback(req, res, user) {
if (/sign|login/.test(refer)) {
refer = config.siteUrl;
}
if (user.openId && user.nickname) {
let signinByOpenID;
if (user.sourceType === 'wechat') {
// PC 的微信登录之前使用了 open_id, 所以需要特别的接口处理
signinByOpenID = AuthHelper.signinByWechat(
user.nickname, user.openId, user.unionId, user.sourceType, shoppingKey);
} else {
signinByOpenID = AuthHelper.signinByOpenID(
user.nickname, user.openId, user.sourceType, shoppingKey);
}
if (user.openId && user.nickname) {
let signinByOpenID = AuthHelper.signinByOpenID(
user.nickname, user.openId, user.sourceType, shoppingKey, user.unionId);
return signinByOpenID.then((result) => {
if (result.code !== 200) {
return Promise.reject(result);
}
if (result.data['is_bind'] && result.data['is_bind'] === 'N') { //eslint-disable-line
return helpers.urlFormat('/passport/thirdlogin/index', {
openId: user.unionId || user.openId,
... ... @@ -64,7 +57,7 @@ function doPassportCallback(req, res, user) {
return res.redirect(redirectTo);
});
} else {
res.redirect(loginPage);
res.redirect(loginPageURL);
}
}
... ... @@ -130,8 +123,6 @@ const local = {
qqLogin: helpers.urlFormat('/passport/autosign/qq'),
weiboLogin: helpers.urlFormat('/passport/autosign/sina'),
alipayLogin: helpers.urlFormat('/passport/autosign/alipay'),
doubanLogin: helpers.urlFormat('/passport/autosign/douban'),
renrenLogin: helpers.urlFormat('/passport/autosign/renren'),
bindMobile: bindMobile
},
module: 'passport',
... ... @@ -164,11 +155,11 @@ const local = {
if (refer) {
refer = decodeURI(req.cookies.refer);
} else {
refer = `${config.siteUrl}/home`;
refer = `${config.siteUrl}`;
}
if (/sign|login/.test(refer)) {
refer = `${config.siteUrl}/home`;
refer = `${config.siteUrl}`;
}
user.session = refer;
user.href = refer;
... ... @@ -213,7 +204,7 @@ const wechat = {
passport.authenticate('wechat', (err, user) => {
if (err) {
log.error(`wechat authenticate error : ${JSON.stringify(err)}`);
return res.redirect(loginPage);
return res.redirect(loginPageURL);
} else {
doPassportCallback(req, res, {
openId: user._json.openid,
... ... @@ -243,7 +234,7 @@ const sina = {
passport.authenticate('sina', (err, user) => {
if (err) {
log.error(`sina authenticate error : ${JSON.stringify(err)}`);
return res.redirect(loginPage);
return res.redirect(loginPageURL);
}
let nickname = user.screen_name;
let openId = user.id;
... ... @@ -273,7 +264,7 @@ const qq = {
passport.authenticate('qq', (err, user) => {
if (err) {
log.error(`qq authenticate error : ${JSON.stringify(err)}`);
return res.redirect(loginPage);
return res.redirect(loginPageURL);
}
let nickname = user.nickname;
let openId = user.id;
... ... @@ -298,7 +289,7 @@ const alipay = {
passport.authenticate('alipay', (err, user) => {
if (err) {
log.error(`alipay authenticate error : ${JSON.stringify(err)}`);
return res.redirect(loginPage);
return res.redirect(loginPageURL);
}
let nickname = user.realName;
let openId = user.userId;
... ... @@ -312,67 +303,11 @@ const alipay = {
}
};
const douban = {
login: (req, res, next) => {
req.session = req.session || {};
req.session.authState = uuid.v4();
return passport.authenticate('douban', {
state: req.session.authState
})(req, res, next);
},
callback: (req, res, next) => {
passport.authenticate('douban', (err, user) => {
if (err) {
log.error(`douban authenticate error : ${JSON.stringify(err)}`);
return res.redirect(loginPage);
}
let nickname = user.displayName;
let openId = user.id;
doPassportCallback(req, res, {
openId: openId,
nickname: nickname,
sourceType: 'douban'
}).catch(next);
})(req, res, next);
}
};
const renren = {
login: (req, res, next) => {
req.session = req.session || {};
req.session.authState = uuid.v4();
return passport.authenticate('renren', {
state: req.session.authState
})(req, res, next);
},
callback: (req, res, next) => {
passport.authenticate('renren', (err, user) => {
if (err) {
log.error(`renren authenticate error : ${JSON.stringify(err)}`);
return res.redirect(loginPage);
}
let nickname = user.displayName;
let openId = user.id;
doPassportCallback(req, res, {
openId: openId,
nickname: nickname,
sourceType: 'renren'
}).catch(next);
})(req, res, next);
}
};
module.exports = {
common: common,
wechat: wechat,
local: local,
sina: sina,
wechat: wechat,
qq: qq,
alipay: alipay,
douban: douban,
renren: renren
sina: sina,
alipay: alipay
};
... ...
... ... @@ -82,7 +82,7 @@ let index = (req, res) => {
captchaUrl: helpers.urlFormat('/passport/images', {t: Date.now()}),
itemUrl: helpers.urlFormat('/help/', {category_id: 9}),
referUrl: refer,
loginUrl: helpers.urlFormat('/signin', {refer: refer}),
loginUrl: helpers.urlFormat('/passport/login', {refer: refer}),
regBtnText: '立即注册'
}
});
... ...
... ... @@ -22,12 +22,12 @@ const Auth = {
return api.post('', param);
},
signinByOpenID(nickname, openId, sourceType, shoppingKey) {
signinByOtherOpenID(nickname, openId, sourceType, shoppingKey) {
let param = {
nickname: nickname,
openId: openId,
source_type: sourceType,
method: 'app.passport.signinByOpenID'
method: 'app.passport.signinByOtherOpenID'
};
if (shoppingKey) {
... ... @@ -36,7 +36,7 @@ const Auth = {
return api.get('', param);
},
signinByWechat(nickname, openId, unionId, sourceType, shoppingKey) {
signinByWechat(nickname, openId, sourceType, shoppingKey, unionId) {
let param = {
nickname: nickname,
openId: openId,
... ... @@ -51,6 +51,17 @@ const Auth = {
return api.get('', param);
},
signinByOpenID(nickname, openId, sourceType, shoppingKey, unionId) {
let signinFunc = {
other: this.signinByOtherOpenID,
wechat: this.signinByWechat
};
// PC 的微信登录之前使用了 open_id, 所以需要特别的接口处理
let type = sourceType !== 'wechat' ? 'other' : sourceType;
return signinFunc[type](nickname, openId, sourceType, shoppingKey, unionId);
},
profile(uid) {
let param = {
uid: uid,
... ... @@ -62,10 +73,10 @@ const Auth = {
syncUserSession(uid, req, res) {
return Auth.profile(uid).then((userInfo) => {
let token = sign.makeToken(uid);
let data = userInfo.data;
let user = userInfo.data;
if (data) {
let uidCookie = `{data.profile_name}::${data.uid}::${data.vip_info.title}::${token}`;
if (user) {
let uidCookie = `{data.profile_name}::${user.uid}::${user.vip_info.title}::${token}`;
req.session._TOKEN = token;
req.session._LOGIN_UID = uid;
... ...
... ... @@ -16,12 +16,7 @@ const getAreaDataAsync = () => {
}).then(result => {
result.data = result.data.map(value => {
value.areaCode = `+${value.area}`;
if (value.areaCode === '+86') {
value.selected = true;
} else {
value.selected = false;
}
value.areaCode = value.areaCode === '+86';
delete value.area;
return value;
... ...
... ... @@ -15,8 +15,6 @@ const userService = require('./user-service');
const passportHelper = require('./passport-helper');
const backHelper = require('./back-helper');
const BACK_LEFT_BANNER_CODE = '3bbaf502c447a2ddad60879042e286d8'; // 找回密码左边的banner
/**
* 验证手机和邮箱输入正确性
*/
... ... @@ -99,17 +97,13 @@ const sendCodeToMobileAsync = (areaCode, mobile) => {
*/
const indexPageDataAsync = () => {
return co(function *() {
let banner = yield passportHelper.getLeftBannerAsync(BACK_LEFT_BANNER_CODE);
let countryList = passportHelper.getCountry();
return {
back: {
coverHref: banner.url,
coverImg: banner.img,
countryCode: 86,
countryName: '中国',
captchaUrl: helpers.urlFormat('/passport/images', {t: moment().unix()}),
countryList: countryList
region: countryList,
captchaUrl: helpers.urlFormat('/passport/images'),
location: '+86'
}
};
})();
... ...
... ... @@ -23,7 +23,7 @@ const getLeftBannerAsync = (resourceCode) => {
url: ''
};
return co(function* () {
return co(function * () {
let resource = yield indexService.getResourceAsync(resourceCode);
if (_.isEmpty(resource)) {
... ... @@ -257,7 +257,7 @@ const getUserInfo = (area, mobile) => {
return {
username: profile,
headImg: user.head_ico ? helpers.image(user.head_ico, 100, 100, 2) : DEFAULT_HEAD_IMG_ICO,
bindLogin: helpers.urlFormat('/signin.html', { bindMobile: mobile, bindArea: area })
bindLogin: helpers.urlFormat('/signin', { bindMobile: mobile, bindArea: area })
};
});
};
... ...
... ... @@ -34,18 +34,16 @@ const findByEmailAsync = (email) => {
return api.get('', {
email: email,
method: 'app.passport.getProfileByEmail'
})
.then(result => {
if (!result.code || result.code !== 200 || !result.data || _.isEmpty(result.data)) {
return EMPTY;
}
}).then(result => {
if (!result.code || result.code !== 200 || !result.data || _.isEmpty(result.data)) {
return EMPTY;
}
return result.data;
return result.data;
})
.catch(() => {
return EMPTY;
});
}).catch(() => {
return EMPTY;
});
};
module.exports = {
... ...
... ... @@ -39,25 +39,26 @@ router.get('/login/qq/callback', login.qq.callback);
router.get('/autosign/alipay', login.common.beforeLogin, login.alipay.login);
router.get('/login/alipay/callback', login.alipay.callback);
// douban登录
router.get('/autosign/douban', login.common.beforeLogin, login.douban.login);
router.get('/autosign/doubanback', login.douban.callback);
// renren登录
router.get('/autosign/renren', login.common.beforeLogin, login.renren.login);
router.get('/login/renren/callback', login.renren.callback);
router.get('/login/account', login.common.needCaptcha);
// 第三方登录后绑定
router.get('/thirdlogin/index', bind.indexPage);
router.get('/thirdlogin/bindsuccess', bind.bindSuccess);
router.post('/thirdlogin/noregist', bind.noregist);
router.post('/thirdlogin/bindsetpwd', bind.bindSetPwdPage);
// 第三方登录后绑定确认
router.post('/thirdlogin/bindConfirm', bind.bindConfirmPage);
router.get('/thirdlogin/bindSuccess', bind.bindSuccessPage);
// 第三方登录后关联确认
router.post('/thirdlogin/relateConfirm', bind.relateConfirmPage);
router.get('/thirdlogin/relateSuccess', bind.relateSuccessPage);
// 第三方登录api
router.post('/autouserinfo/bindMobile', bind.bindMobile);
router.post('/autouserinfo/bindCheck', bind.bindCheck);
router.post('/autouserinfo/sendBindMsg', bind.sendBindMsg);
router.post('/autouserinfo/checkBindMsg', bind.checkBindMsg);
router.post('/autouserinfo/bindMobile', bind.bindMobile);
router.post('/autouserinfo/relatemobile', bind.relateMobile);
/**
* 注册页面路由
... ... @@ -78,7 +79,6 @@ router.get('/back/index', back.index);
// 实时验证输入是否正确
router.post('/back/authcode',
captcha.requiredAPI,
back.validateInputAPI,
back.getUserInfoAPI);
... ... @@ -147,5 +147,6 @@ router.get('/back/resetSuccess',
back.resetPwdSuccessPage);
router.get('/images', captcha.generate);
router.post('/images/check', captcha.requiredPost);
module.exports = router;
... ...
<div class="back-page passport-page yoho-page clearfix">
{{> sign-header}}
<div class="back-page passport-page clearfix">
{{# back}}
{{> back/cover}}
<div class="content">
<div class="back-header clearfix">
<h2 class="title">找回密码</h2>
<span id="country-code" class="country-code">
<em>{{countryName}} +{{countryCode}}</em>
<i class="iconfont">&#xe61d;</i>
</span>
<ul id="country-code-list" class="country-code-list">
{{# countryList}}
<li data-cc="{{areaCode}}">{{name}} {{areaCode}}</li>
{{/ countryList}}
</ul>
<ul>
<li class="clearfix">
<div class="title">密码重置</div>
</li>
<div class="indicator">
<li class="clearfix small">
<div class="draw">
<div class="step first cur-step">
<div class="circle"></div>
</div>
<div class="step">
<div class="line"></div>
</div>
<div class="step second">
<div class="circle ring"></div>
</div>
<div class="step">
<div class="line"></div>
</div>
<div class="step third cur-step">
<div class="circle ring"></div>
</div>
</div>
</li>
<li class="clearfix small">
<div class="text">
<div class="step first cur-step">验证身份</div>
<div class="step second">重置密码</div>
<div class="step third">重置成功</div>
</div>
</li>
</div>
<li style="margin-bottom: 0">
</li>
<form id="back-form" class="back-form" action="/passport/back/email" method="post">
<input id="country-code-hide" type="hidden" name="area" value="+86">
<ul>
<li class="input-container-li clearfix">
<input id="phone-num" class="input va phone-num" type="text" name="phoneNum" placeholder="邮箱/手机号码" autocomplete="off">
<span id="account-err" class="err-tip hide">
<i></i>
<em>账户名不能为空</em>
</span>
</li>
<li class="input-container-li clearfix">
<input id="captcha" class="input va captcha" type="text" name="verifyCode" placeholder="验证码" autocomplete="off" maxlength="4">
<li class="clearfix">
<select id="area" class="country-list" name="region">
{{#each region}}
<option {{#if selected}}selected="selected"{{/if}} value="{{areaCode}}">{{name}}</option>
{{/each}}
</select>
<div id="phone" class="phone">
<span id="country-code" class="country-code">{{location}}</span>
<input value="" id="phoneNum" class="input va phone-num" type="text" name="phoneNum"
placeholder="Phone Number" autocomplete="off">
</div>
</li>
<li class="clearfix">
<input id="verifyCode" class="input va captcha" type="text" name="verifyCode" placeholder="图形验证码"
autocomplete="off" maxlength="4">
<div class="left captcha-component">
<img id="captcha-img" class="captcha-img" src="{{captchaUrl}}" alt="">
<a id="change-captcha" class="link change-captcha">换一张</a>
<span id="captcha-err" class="err-tip captcha-err hide">
<i></i>
<em>验证码不能为空</em>
</span>
</li>
<li class="input-container-li clearfix">
<input name="refer" id="refer" type="hidden" value="http%3A%2F%2Fwww.yohobuy.com%2F">
<input id="find-btn" class="btn find-btn disable" type="submit" value="下一步" disabled="">
</li>
</ul>
<a class="left link change-captcha"><span class="iconfont gray">&#xe613;</span></a>
</div>
</li>
<li class="clearfix">
<input name="refer" id="refer" type="hidden" value="http%3A%2F%2Fwww.yohoblk.com%2F">
<div class="center">
<a id="find-btn" class="find-btn disable" >下一步</a>
</div>
</li>
</form>
</ul>
<div class="tips hide">
<div class="triangle"></div>
<div class="rectangle"></div>
</div>
{{/ back}}
</div>
... ...
{{> sign-header}}
<div class="reset-pwd-page back-page passport-page yoho-page clearfix">
{{# resetPwd}}
{{> back/cover}}
<div class="content">
<h2 class="title2">重置密码</h2>
<form id="reset-pwd-form" class="reset-pwd-form" method="POST" action="/passport/back/update">
<ul>
<li class="input-container-li po-re">
<input id="pwd" class="input va pwd" type="password" name="pwd" placeholder="新密码"
maxlength="20">
<div class="pwd-intensity-container">
<span class="pwd-intensity low"></span>
<span class="pwd-intensity mid"></span>
<span class="pwd-intensity high"></span>
<ul>
<li class="clearfix">
<div class="title">密码重置</div>
</li>
<div class="indicator">
<li class="clearfix small">
<div class="draw">
<div class="step first cur-step">
<div class="circle"></div>
</div>
<div class="step">
<div class="line cur-step"></div>
</div>
<div class="step second">
<div class="circle"></div>
</div>
<div id="pwd-tips" class="pwd-tips hide">
<div class="default" id="pwd-tip1">
<i></i>
密码只支持6-20位字符
</div>
<div class="default" id="pwd-tip2">
<i></i>
由字母、 数字组合,不能包含特殊符号
</div>
<div class="step">
<div class="line cur-step"></div>
</div>
<span id="pwd-err" class="err-tip hide">
<i></i>
<em>请输入密码</em>
</span>
</li>
<li class="input-container-li clearfix po-re">
<input id="re-input" class="input va re-input repwd" type="password" name="re-input"
placeholder="再次输入" maxlength="20">
<span id="repwd-err" class="err-tip hide">
<i></i>
<em>请输入密码确认</em>
</span>
</li>
<li class="input-container-li clearfix">
<input type="hidden" name="code" value="{{code}}">
<input type="hidden" name="mobile" value="{{mobile}}">
<input type="hidden" name="area" value="{{area}}">
<input type="hidden" name="token" value="{{token}}">
<input type="hidden" name="createdAt" value="{{createdAt}}">
<input id="reset-pwd-btn" class="btn reset-pwd-btn" type="submit" value="提交" disabled="">
</li>
</ul>
<div class="step third cur-step">
<div class="circle ring"></div>
</div>
</div>
</li>
<li class="clearfix small">
<div class="text">
<div class="step first cur-step">验证身份</div>
<div class="step second cur-step">重置密码</div>
<div class="step third">重置成功</div>
</div>
</li>
</div>
<li style="margin-bottom: 0">
</li>
<form id="reset-pwd-form" class="reset-pwd-form" method="POST" action="/passport/back/update">
<li class="input-container-li po-re">
<input id="pwd" class="input va pwd" type="password" name="pwd" placeholder="新的登录密码"
maxlength="20">
</li>
<li class="clearfix">
<input id="re-input" class="input va re-input repwd" type="password" name="re-input"
placeholder="确认登录密码" maxlength="20">
</li>
<li class="clearfix blank">
<input type="hidden" name="code" value="{{code}}">
<input type="hidden" name="mobile" value="{{mobile}}">
<input type="hidden" name="area" value="{{area}}">
<input type="hidden" name="token" value="{{token}}">
<input type="hidden" name="createdAt" value="{{createdAt}}">
</li>
<li>
<div>
<input id="reset-pwd-btn" class="reset-pwd-btn disable" type="submit" value="下一步">
</div>
</li>
</form>
</ul>
<div class="tips hide">
<div class="triangle"></div>
<div class="rectangle"></div>
</div>
{{/ resetPwd}}
</div>
... ...
{{> sign-header}}
<div class="reset-success-page back-page passport-page yoho-page clearfix">
{{# resetSuccess}}
{{> back/cover}}
<div class="content">
<ul>
<li class="clearfix">
<div class="title">密码重置</div>
</li>
<div class="indicator">
<li class="clearfix small">
<div class="draw">
<div class="step first cur-step">
<div class="circle"></div>
</div>
<div class="step">
<div class="line cur-step"></div>
</div>
<div class="step second">
<div class="circle"></div>
</div>
<div class="step">
<div class="line cur-step"></div>
</div>
<div class="step third cur-step">
<div class="circle"></div>
</div>
</div>
</li>
<li class="clearfix small">
<div class="text">
<div class="step first cur-step">验证身份</div>
<div class="step second cur-step">重置密码</div>
<div class="step third cur-step">重置成功</div>
</div>
</li>
</div>
<li style="margin-bottom: 0">
</li>
<div class="success-text">
<i class="iconfont">&#xe620;</i><span>恭喜!</span>密码修改成功,&nbsp;<span id="count-down">5</span>&nbsp;&nbsp;秒后将跳转至首页
<div class="title">恭喜您设置完成,请妥善保存您的密码!</div>
<div class="time">页面将在&nbsp;<span id="count-down" class="blue">5</span>&nbsp;秒后将跳转至首页</div>
</div>
<a class="success-btn" href="/">随便逛逛</a>
</div>
</ul>
{{/ resetSuccess}}
</div>
<script type="text/javascript">
(function() {
(function () {
var count = 5,
countDown = document.getElementById('count-down');
console.log(countDown);
var timer = setInterval(function(){
var timer = setInterval(function () {
if (count > 1) {
count--;
countDown.innerHTML = count;
... ...
<div class="send-email-page passport-page yoho-page clearfix">
{{> sign-header}}
<div class="send-email-page back-page passport-page clearfix">
{{# sendEmail}}
{{> back/cover}}
<div class="content">
<div class="send-tips"><i class="iconfont">&#xe61e;</i>我们已经把验证邮件发送至您的邮箱,请在24小时内通过邮件内的<br>链接继续设置新的密码。</div>
<div class="no-find">没有收到?到您邮箱的垃圾邮件里找找。</div>
<div class="to-my-email">
<a href="{{email}}" target="_blank" class="btn_b_ar_r">去我的邮箱&gt;</a>
<ul>
<li class="clearfix">
<div class="title">密码重置</div>
</li>
<div class="indicator">
<li class="clearfix small">
<div class="draw">
<div class="step first cur-step">
<div class="circle"></div>
</div>
<div class="step">
<div class="line cur-step"></div>
</div>
<div class="step second">
<div class="circle ring"></div>
</div>
<div class="step">
<div class="line"></div>
</div>
<div class="step third cur-step">
<div class="circle ring"></div>
</div>
</div>
</li>
<li class="clearfix small">
<div class="text">
<div class="step first cur-step">验证身份</div>
<div class="step second cur-step">重置密码</div>
<div class="step third">重置成功</div>
</div>
</li>
</div>
</div>
<li style="margin-bottom: 0">
</li>
<li>
<div class="center">我们已经把验证邮件发送至您的邮箱
</div>
<br>
<div class="center">请在24小时内通过邮件内的链接继续设置新的密码
</div>
</li>
<li class="small">
</li>
<div class="no-find">没有收到?到您邮箱的垃圾邮件里找找。</div>
<br>
<li class="clearfix">
<div>
<a class="btn to-my-email" href="{{email}}" target="_blank" class="btn_b_ar_r">去我的邮箱</a>
</div>
</li>
</ul>
{{/ sendEmail}}
</div>
... ...
<div class="verification-page back-page passport-page yoho-page clearfix">
{{> sign-header}}
<div class="verification-page back-page passport-page clearfix">
{{# verification}}
{{> back/cover}}
<div class="content">
<ul>
<li class="clearfix">
<div class="title">密码重置</div>
</li>
<div class="indicator">
<li class="clearfix small">
<div class="draw">
<div class="step first cur-step">
<div class="circle"></div>
</div>
<div class="step">
<div class="line cur-step"></div>
</div>
<div class="step second">
<div class="circle ring"></div>
</div>
<div class="step">
<div class="line"></div>
</div>
<div class="step third cur-step">
<div class="circle ring"></div>
</div>
</div>
</li>
<li class="clearfix small">
<div class="text">
<div class="step first cur-step">验证身份</div>
<div class="step second cur-step">重置密码</div>
<div class="step third">重置成功</div>
</div>
</li>
</div>
<li style="margin-bottom: 0">
</li>
<li class="clearfix">
<div class="desc">
<span>手机验证码已经发送至{{mobile}}</span><br>
<span>请在有效时间内输入验证码点击下一步来重置密码</span>
</div>
</li>
<form id="verification-form" class="verification-form" method="POST" action="/passport/back/backmobile">
<ul>
<li class="head-title">验证身份</li>
<li class="po-re">
<label class="pn-label">手机号码</label>
<span class="country-code">+{{area}}</span>
<span class="phone-num">{{mobile}}</span>
</li>
<li class="po-re">
<input id="captcha" class="input va captcha" type="text" name="code" maxlength="4">
<input id="send-captcha" class="btn send-captcha" type="button" value="发送验证码" disabled="">
<div id="captcha-tip" class="captcha-tips"><i class="iconfont">&#xe61f;</i>验证码已发送至您的手机,请查收</div>
<span id="err-tip" class="err-tip hide">
<i></i>
<em>请输入验证码</em>
</span>
</li>
<li>
<input name="area" id="area" type="hidden" value="{{area}}">
<input name="mobile" id="mobile" type="hidden" value="{{mobile}}">
<input name="verifyCode" id="captchaPic" type="hidden" value="{{verifyCode}}">
<input name="refer" id="refer" type="hidden" value="">
<a id="next-step" class="btn next-step disable" href="javascript:;">下一步</a>
<!-- <input id="next-step" class="btn next-step disable" type="submit" value="下一步" disabled=""> -->
</li>
</ul>
<li>
<input id="captcha" class="input va captcha left" type="text" name="code" maxlength="4"
placeholder="请输入短信验证码">
<a id="send-captcha" class="btn send-captcha left">获取短信验证码</a>
</li>
<li class="blank">
<input name="area" id="area" type="hidden" value="{{area}}">
<input name="mobile" id="mobile" type="hidden" value="{{mobile}}">
<input name="verifyCode" id="captchaPic" type="hidden" value="{{verifyCode}}">
<input name="refer" id="refer" type="hidden" value="">
</li>
<li>
<a id="next-step" class="next-step disable" href="javascript:;">下一步</a>
</li>
</form>
</ul>
<div class="tips hide">
<div class="triangle"></div>
<div class="rectangle"></div>
</div>
{{/ verification}}
</div>
... ...
{{> sign-header}}
<div class="bind-wrapper">
<div id="bindConfirmPage" class="bind-confirm-page">
<ul>
<li class="clearfix big-width">
<div class="center">
{{#if avatar}}
<img id="avatar" class="avatar" src="{{avatar}}">
{{^}}
<img id="avatar" class="avatar"
src="http://img10.static.yhbimg.com/headimg/2013/11/28/09/01cae078abe5fe320c88cdf4c220212688.gif?imageView/2/w/100/h/100">
{{/if}}
</div>
</li>
<li>
<div id="name" class="title center small">
{{#if name}}
<span>{{name}}</span>
{{^}}
<span>咸鸭蛋</span>
{{/if}}
</div>
</li>
<li class="clearfix">
<div id="confirmInfo">
<div class="desc center">手机号{{mobile}}已经被以上用户注册,请确认是否归您本人所有</div>
<div class="desc center"></div>
<div class="desc center">您可以绑定该手机号或者更换一个新的手机号绑定该帐号,也可以使用该手机直接登录</div>
</div>
</li>
<li style="margin: -10px 0">
</li>
<li>
<div>
<a id="next" class="btn btn-fixed-height" href="{{bindSuccess}}">是朕的,绑定该手机号</a>
</div>
</li>
<li>
<div class="quick-link">
<a class="blue left" href="{{bindUrl}}">绑定其他手机号</a>
<a class="blue right" href="{{loginUrl}}">使用手机号登录</a>
</div>
</li>
</ul>
</div>
<input type="hidden" value="{{uid}}">
<input type="hidden" value="{{mobile}}">
<input type="hidden" value="{{area}}">
<input type="hidden" value="{{code}}">
<input type="hidden" value="{{sourceType}}">
</div>
... ...
{{> sign-header}}
<div class="bind-wrapper">
<div id="pwdPage" class="pwd-page">
<ul>
<li class="clearfix">
<div class="title center">欢迎加入 YOHO!BLK</div>
</li>
<li class="clearfix small">
<div class="prompt desc center">为了您的购物安全,请完善账户信息哦!</div>
</li>
<li>
<div>
<input id="pwd" class="input" type="password" placeholder="新的登录密码">
</div>
</li>
<li>
<div>
<input id="repwd" class="input" type="password" placeholder="确认登录密码">
</div>
</li>
<li>
<div>
<a id="next" class="btn btn-fixed-height disable" href="">确认</a>
</div>
</li>
</ul>
</div>
<div class="tips hide">
<div class="triangle"></div>
<div class="rectangle"></div>
</div>
<input type="hidden" id="sourceType" value="{{sourceType}}">
<input type="hidden" id="openId" value="{{openId}}">
<input type="hidden" id="mobile" value="{{mobile}}">
<input type="hidden" id="area" value="{{area}}">
</div>
\ No newline at end of file
... ...
{{> sign-header}}
<div class="bind-wrapper">
<div id="bindSuccessPage" class="bind-success-page">
<ul>
<li>
<div class="title center">
恭喜您,手机绑定成功啦!
</div>
</li>
<li>
<div class="desc center">
尊敬的会员,今后您可以选择{{sourceName}}或者手机号+密码的方式登录YOHO!BLK!即刻您可以开启时尚购物之旅!
</div>
</li>
<li>
<div>
<a class="btn btn-fixed-height" href="{{goShopping}}">开始购物</a>
</div>
</li>
</ul>
</div>
</div>
\ No newline at end of file
... ...
<div class="bindwrapper">
<h3 class="welcomeword">
欢迎加入
<span class="yoho">YOHO!FAMILY</span>
</h3>
<p class="safeword">为了您的账户安全,请您完善账户信息,以便为您提供更优质的服务</p>
<form action="" id="bindmobileform" method="post">
<input type="hidden" value="{{openId}}" id="openId" name="openId"/>
<input type="hidden" value="{{sourceType}}" id="sourceType" name="sourceType"/>
<input type="hidden" value="86" id="areacode" name="area"/>
<div class="yohobindrow">
<div class="name areatag">地区</div>
<div class="content">
<div class="yohoselectarea">
<div class="optionshow">
<span class="areaname" id="areaname">中国</span>
<span class="righttag"></span>
</div>
<div class="optionslist hide">
{{> sign-header}}
<div class="bind-wrapper">
<div id="authPage" class="auth-page">
<ul>
<li class="clearfix">
<div class="title center">欢迎加入 YOHO!BLK</div>
</li>
<li class="clearfix small">
<div class="prompt desc center">为了您的购物安全,请完善账户信息哦!</div>
</li>
<li class="clearfix">
<div id="mobile-input-component" class="mobile-input-component">
<select id="region" name="select" class="region left">
{{#each region}}
<div class="optionitem" areanum="{{areaCode}}">{{name}}</div>
<option {{#if selected}}selected="selected"{{/if}}
value="{{areaCode}}">{{name}}</option>
{{/each}}
</select>
<div id="phone" class="ctrl left">
<div id="region-code" class="code left">{{local}}</div>
<div >
<input id="phone-num" class="phone-num" type="text" placeholder="Phone Number">
</div>
</div>
</div>
</div>
</div>
<div class="yohobindrow">
<div class="name phonetag">手机号码</div>
<div class="content">
<div class="yohophonewrapper">
<div class="areanum" >
+
<span id="areanum">86</span>
</li>
<li class="clearfix">
<div id="img-captcha-component" class="img-captcha-component">
<input id="verifyCode" class="input left" name="code" type="text" placeholder="图形验证码">
<div class="refresh left">
<img class="left img-captcha" src="{{imgCaptcha}}">
<span class="img-captcha-refresh iconfont left ctrl">&#xe613;</span>
</div>
<input type="text" class="phonenum" name="mobile" id="mobile"/>
<span class="err-tip phone-err-tip hide">
<i></i>
<em></em>
</span>
</div>
</div>
</div>
</form>
<div class="protoctolwrapper">
<div class="choosewrapper">
<input type="checkbox" class="choosetag" checked='checked'></div>
<span>
我已阅读并同意遵守
<a target="_blank" href="{{serviceUrl}}" class="protoctol">YOHO!BUY 有货服务条款</a>
</span>
</div>
<div class="btnwrapper">
<a href="javascript:void(0)" class="yohobindbtn" id="bindfirststep">下一步</a>
</div>
</div>
<div id="bindconfirm" style="display:none">
<div class="mask">
<div class="bindconfrimwrapper">
<div class="topwrapper">
<img src="" alt="" class="userphoto" id="userphoto1">
<span class="username">
用户名: <i id="username1"></span>
</div>
<h2 class="usertaginfo">
手机号
<span id="registphonetwo"></span>
已经被以上账户注册,请确认是否归您本人所有
</h2>
<h1 class="usertagremind">您可以使用该手机号码直接登录或更换一个新的手机号码绑定该账号</h1>
<a href="javascript:;" class="yohobindbtn otherphone" id="yohobindbtn">绑定其他手机号</a>
<a href="" class="logindirectly" id="logindirectly">使用手机号直接登录</a>
</div>
</div>
</div>
<div class="backdrop" style="display:none"></div>
</div>
<div id="alreayregist" style="display:none">
<div class="mask">
<div class="bindconfrimwrapper">
<div class="topwrapper">
<img src="" alt="" class="userphoto" id="userphoto">
<span class="username">
用户名: <i id="username"></i>
</span>
</div>
<h2 class="usertaginfo">
手机号
<span id="registphone"></span>
已经被以上账户注册,请确认是否归您本人所有
</h2>
<h1 class="usertagremind">您可以绑定该手机号码或更换一个新的手机号码绑定该账号,也可以使用该手机号码直接登录</h1>
<form id="gobindform" action="/passport/autouserinfo/bindMobile" method="post">
<div class="gobindwrapper">
<div class="validaterow">
<div class="content">
<input type="text" class="validatacode" placeholder="验证码" maxlength="4" id="validatenum"/>
</div>
<div class="validatewrapper">
<a href="javascript:void(0)" class="yohobindbtn" id="sendmessage">免费获取短信验证码</a>
</div>
<div class="hide" id="nopermissionmessage">
<span class="second">60</span>
秒后可重新操作
</div>
</li>
<li class="clearfix">
<div id="sms-captcha-component" class="sms-captcha-component">
<input id="sms-captcha-input" class="input left sms-captcha-input" type="text" placeholder="短信验证码">
<div class="left">
<a class="btn send disable sms-captcha-send">获取短信验证码</a>
</div>
<input type="hidden" name="area" value="" id="inarea"/>
<input type="hidden" name="mobile" value="" id="inmobile"/>
<input type="hidden" name="openId" value="{{openId}}"/>
<input type="hidden" name="sourceType" value="{{sourceType}}"/>
<a href="javascript:;" class="yohobindbtn myphone" id="gotobindphone">是的我绑定该手机号</a>
</div>
<div class="gobindbottomwrapper">
<a href="javascript:;" class="logindirectly" id="yohobindbtn2">绑定其他手机号</a>
<a href="javascript:;" class="logindirectly" id="logindirectly2">使用手机号直接登录</a>
</li>
<li class="clearfix">
<div>
<a id="validate-phone-next" class="btn btn-fixed-height disable">下一步</a>
</div>
</form>
</div>
</li>
</ul>
</div>
<div class="tips hide">
<div class="triangle"></div>
<div class="rectangle"></div>
</div>
<div class="backdrop" style="display:none"></div>
<div>
<input id="openId" type="hidden" value="{{openId}}">
<input id="sourceType" type="hidden" value="{{sourceType}}">
<input id="refer" type="hidden" value="{{refer}}">
</div>
</div>
\ No newline at end of file
... ...
<div class="bindwrapper">
<h3 class="welcomeword">
欢迎加入
<span class="yoho">YOHO!FAMILY</span>
</h3>
<p class="safeword">为了您的账户安全,请您完善账户信息,以便为您提供更优质的服务</p>
<p class="sendnotify">
验证码已发送至
<span class="sendphone">{{mobile}}</span>
</p>
<form action="infoform" method="post">
<div class="validaterow">
<div class="name phonetag">短信验证码</div>
<div class="content">
<div class="yohophonewrapper">
<input type="text" class="validatenum phonenum" value="" id="validatenum" maxlength="4"/>
<span class="err-tip code-err-tip hide">
<i></i>
<em></em>
</span>
</div>
</div>
<div class="validatewrapper">
<a href="javascript:void(0)" class="yohobindbtn" id="sendmessage">免费获取短信验证码</a>
</div>
<div class="hide" id="nopermissionmessage">
<span class="second">60</span>
秒后可重新操作
</div>
</div>
<div class="setpwdcontent">
<div class="yohobindrow setpwdwrapper">
<div class="name setpwdtag">设置密码</div>
<div class="content">
<div class="yohophonewrapper">
<input type="password" class="phonenum pwdcontent" maxlength="20" id="pwd" name="password" />
<span class="err-tip pwd-err-tip hide">
<i></i>
<em></em>
</span>
<div id="pwd-tips" class="hide pwd-tips">
<div class="default" id="pwd-tip1"> <i></i>
密码只支持6-20位字符
</div>
<div class="default" id="pwd-tip2"> <i></i>
由字母、 数字组合,不能包含特殊符号
</div>
</div>
</div>
</div>
</div>
<div class="safelevel clearfix">
安全程度: &nbsp;
<span class="low pwd-intensity"></span>
<span class="mid pwd-intensity"></span>
<span class="high pwd-intensity"></span>
</div>
</div>
<div class="btnwrapper confirmwrapper">
<a href="javascript:void(0)" class="yohobindbtn" id="confirmsubmit" >确定</a>
</div>
<input type="hidden" value="{{openId}}" name="openId" id="openId">
<input type="hidden" value="{{sourceType}}" name="sourceType" id="sourceType">
<input type="hidden" value="{{mobile}}" id="mobile" name="mobile"/>
<input type="hidden" value="{{area}}" id="area"/>
</form>
</div>
{{> sign-header}}
<div class="bind-wrapper">
<div id="relateConfirmPage" class="relate-confirm-page">
<ul>
<li class="clearfix big-width">
<div id="avatar" class="center">
<img class="avatar"
src="http://img10.static.yhbimg.com/headimg/2013/11/28/09/01cae078abe5fe320c88cdf4c220212688.gif?imageView/2/w/100/h/100">
</div>
</li>
<li>
<div id="name" class="title center">
<span>咸鸭蛋</span>
</div>
</li>
<li class="clearfix">
<div id="confirmInfo" class="confirmInfo">
<div class="desc center">手机号{{mobile}}已经被以上用户注册,点击<a class="blue underline" href="{{signinUrl}}">登录该帐号</a>
</div>
<div class="desc"></div>
<div class="desc center">您可以使用此号码进行帐户关联或者更换一个新的手机号码</div>
</div>
</li>
<li style="margin: -10px 0">
</li>
<li>
<div class="quick-btn">
<a id="relate-btn" class="btn btn-fixed-height left" href="">关联此手机号</a>
<a class="btn btn-fixed-height right" href="">更换新手机号</a>
</div>
</li>
<li>
<div class="desc center">
注:关联的手机号码不能用来登录此帐号
</div>
</li>
</ul>
</div>
<input id="mobile" type="hidden" value="{{mobile}}">
<input id="area" type="hidden" value="{{area}}">
<input id="sourceType" type="hidden" value="{{sourceType}}">
<input id="openId" type="hidden" value="{{openId}}">
</div>
\ No newline at end of file
... ...
{{> sign-header}}
<div class="bind-wrapper">
<div id="relateSuccessPage" class="relate-success-page">
<ul>
<li>
<div class="title center">
恭喜您,手机关联成功啦!
</div>
</li>
<li>
<div class="desc center">
该手机号不能用来登录帐号,您可以选择继续使用{{sourceName}}登录
</div>
</li>
<li>
<div>
<a class="btn btn-fixed-height" href="{{goShopping}}">开始购物</a>
</div>
</li>
</ul>
</div>
</div>
\ No newline at end of file
... ...
{{> layout/header}}
<div class="third-relate-page passport-page yoho-page clearfix">
{{# relate}}
<div id="relate-main" class="relate-main">
<div class="user-wrapper">
<div class="user-thumb">
<img src="{{thumb}}">
</div>
<label>用户名: {{userName}}</label>
</div>
<div class="remind-info">
<h3>手机号
<span>{{phoneNum}}</span>
已经被以上账户注册,点击
<a href="{{loginHref}}" target="_blank">登录该账号</a>
</h3>
<p>您可以使用此号码进行账户关联或更换一个新的手机号码</p>
</div>
<div class="option-btn">
<a id="next-step-btn">关联此手机号</a>
<a href="{{changeHref}}">更换新手机号</a>
</div>
<p class="remind-tips">注:关联的手机号码不能用来登录此账户</p>
</div>
<div id="code-validate" class="code-validate hide">
<div class="action-link">短信验证码已发送至<span>{{phoneNum}}</span></div>
<div class="validate-wrapper action-link">
<div class="code-name">短信验证码</div>
<input type="text" class="msg-code">
<label class="get-code">免费获取短信验证码</label>
<label class="count-down"><span>60</span>秒后可重新操作</label>
<div class="code-error hide">
<i></i>
验证码错误
</div>
</div>
<div class="action-link">
<button id="relate-btn" class="relate-btn">确定</button>
</div>
<p class="remind-tips">
<span class="left">注:关联的手机号码不能用来登录此账户</span>
<a class="perv-step right">返回上一步</a>
</p>
</div>
<div id="hide-info" data-mobile="{{phoneNum}}" data-area="{{areaCode}}" data-openid="{{openId}}" data-source="{{sourceType}}"></div>
{{/ relate}}
</div>
{{> layout/footer}}
\ No newline at end of file
<div class="bindsuccesswrapper">
<div class="successwrapper">
<span class="successtag"></span>
<span class="congratulation">恭喜!</span>
{{#if relate}}
<span class="successnotify">您的手机号码已经关联成功</span>
{{^}}
<span class="successnotify">您的号码已经绑定成功</span>
{{/if}}
</div>
{{#if relate}}
<h3 class="info">该手机号码不能用来登录此账户,您可以选择继续使用{{sourceName}}登录</h3>
{{^}}
<h3 class="info">今后您可以选择{{sourceName}}或绑定的手机号码+密码的方式登录此账户</h3>
{{/if}}
<a href="{{goShopping}}" class="yohobindbtn gobuynow">立即购物</a>
</div>
\ No newline at end of file
{{> sign-header}}
<div class="login-page passport-page yoho-page clearfix center-content">
<div class="login-page passport-page">
{{# passport}}
<ul>
<li class="clearfix">
<h2 class="title">登录 SIGN IN</h2>
<div class="title">登录 SIGN IN</div>
</li>
<li class="clearfix">
<select id="country-list" class="country-list">
... ... @@ -12,57 +12,38 @@
{{/each}}
</select>
<div id="phone" class="left phone">
<div id="phone" class="left phone needTip">
<span id="country-code" class="country-code">{{countryCode}}</span>
<input id="account" class="account input phone-num va" name="account" value="{{bindMobile}}"
type="text"
placeholder="Phone Number" autocomplete="off">
</div>
<span class="err-tip hide">
<span class="iconfont">&#xe60c;</span>
<em></em>
</span>
</li>
<li class="clearfix">
<input id="password" class="input password va" name="password" type="password" placeholder="Password"
<input id="password" class="input password va needTip" name="password" type="password"
placeholder="Password"
autocomplete="off" maxlength="20">
<span id="caps-lock" class="caps-lock hide">大写状态开启</span>
<span class="err-tip hide">
<span class="iconfont">&#xe60c;</span>
<em>请输入密码</em>
</span>
</li>
<li class="clearfix captcha-wrap hide">
<input id="captcha" class="input va captcha" type="text" name="captcha" placeholder="图形验证码"
<input id="captcha" class="input va captcha needTip" type="text" name="captcha" placeholder="图形验证码"
autocomplete="off" maxlength="4">
<div class="left captcha-component">
<img id="captcha-img" class="left captcha-img" alt="">
<a class="left link change-captcha"><span class="iconfont gray">&#xe613;</span></a>
</div>
<span class="err-tip hide">
<span class="iconfont">&#xe60c;</span>
<em></em>
</span>
</li>
<li class="clearfix relative">
<li class="clearfix">
<span class="left login-fail-tip hide">
<span class="iconfont">&#xe608;</span>
<span class="'iconfont">&#xe608;</span>
<em></em>
</span>
<span id="login-btn" class="btn login-btn">登录</span>
<a id="login-btn" class="btn login-btn">登录</a>
</li>
<li class="clearfix">
... ... @@ -76,24 +57,19 @@
</span>
</li>
<li class="third-party-login">
<li class="clearfix third-party-login">
<a href="{{weixinLogin}}">
<span class="icon weixin"></span>
<span class="iconfont weixin">&#xe642;</span>
</a>
<a href="{{qqLogin}}">
<span class="icon qq"></span>
<span class="iconfont qq">&#xe641;</span>
</a>
<a href="{{weiboLogin}}">
<span class="icon weibo"></span>
<span class="iconfont weibo">&#xe640;</span>
</a>
<a href="{{alipayLogin}}">
<span class="icon alipay"></span>
</a>
<a href="{{doubanLogin}}">
<span class="icon douban"></span>
</a>
<a href="{{renrenLogin}}">
<span class="icon renren"></span>
<span class="iconfont alipay">&#xe63f;</span>
</a>
</li>
... ... @@ -107,6 +83,11 @@
</span>
</li>
<div class="tips hide">
<div class="triangle"></div>
<div class="rectangle"></div>
</div>
</ul>
<input id="country-code-hide" name="countryCode" type="hidden" value="{{countryCode}}">
{{/ passport}}
... ...
... ... @@ -9,7 +9,7 @@
<div>
尊敬的{{mobile}},恭喜您已经成为YOHO!BLK会员!即刻您可以开启时尚购物之旅!
</div>
<a class="success-btn" href="{{goShoppong}}" data-url="{{goUrl}}">开始购物</a>
<a class="btn btn-fixed-height success-btn" href="{{goShoppong}}" data-url="{{goUrl}}">开始购物</a>
</div>
{{/ passport}}
</div>
... ...
... ... @@ -13,14 +13,14 @@
</select>
<div id="phone" class="left phone relative">
<span id="country-code" class="country-code">{{location}}</span>
<input value="" id="phone-num" class="input va phone-num" type="text" name="phoneNum"
<input value="" id="phone-num" class="input phone-num" type="text" name="phoneNum"
placeholder="Phone Number" autocomplete="off">
</div>
</li>
<li class="clearfix" data-index="1">
<input id="captcha" class="input va captcha" type="text" name="captcha" placeholder="图形验证码"
<input id="captcha" class="input captcha" type="text" name="captcha" placeholder="图形验证码"
autocomplete="off" maxlength="4">
<div class="left captcha-component">
... ... @@ -31,10 +31,9 @@
</li>
<li class="clearfix" data-index="2">
<input id="msg-captcha" class="input va msg-captcha" type="text" name="msgCaptcha" placeholder="短信验证码"
<input id="msg-captcha" class="input msg-captcha" type="text" name="msgCaptcha" placeholder="短信验证码"
autocomplete="off" maxlength="4">
<input id="send-captcha" class="btn send-captcha disable" type="button" value="获取短信验证码">
<span id="msg-tip" class="hide msg-tip">短信验证码已发送至您的手机,请查收</span>
<a id="send-captcha" class="btn send-captcha disable">获取短信验证码</a>
</li>
<li class="clearfix" data-index="3">
... ... @@ -46,13 +45,8 @@
</li>
<li class="clearfix">
<input id="pwd" class="input va pwd" name="pwd" placeholder="Password" autocomplete="off" maxlength="20"
<input id="pwd" class="input pwd" name="pwd" placeholder="Password" autocomplete="off" maxlength="20"
type="password">
<div id="pwd-tips" class="hide pwd-tips">
<div class="default" id="pwd-tip1"><i></i>密码只支持6-20位字符</div>
<div class="default" id="pwd-tip2"><i></i>由字母、 数字组合,不能包含特殊符号</div>
</div>
</li>
<li class="clearfix">
... ... @@ -67,14 +61,14 @@
<li class="clearfix">
<input name="refer" id="refer" type="hidden" value="{{referUrl}}">
<div style="width: 100%;text-align: center">
<input id="register-btn" class="btn register-btn disable" type="submit" value="{{regBtnText}}"
disabled="">
<input id="register-btn" class="btn btn-fixed-height disable" type="submit" value="{{regBtnText}}"
>
</div>
</li>
<li class="clearfix quick-login-container">
<div style="width: 100%;text-align: center">
已注册YOHO!BLK账号
<a class="blue go-login" href="">快速登录</a>
<a class="blue go-login" href="{{loginUrl}}">快速登录</a>
</div>
</li>
</ul>
... ...
... ... @@ -5,240 +5,248 @@
*/
'use strict';
const index = (req, res) => {
let data = {
brandBanner: {
bgColor: '#93897d',
brandLogo: {
link: '#',
img: 'http://placehold.it/{width}x{height}'
},
brandHome: {
link: '#'
}
},
nav: [
{
link: '#',
name: 'MEN首页'
},
{
link: '#',
name: '上衣'
},
{
link: '#',
name: '卫衣'
},
{
name: 'Spring 2016NEWT-Shirt 2016迷彩蝴蝶夹克'
}
],
goodInfo: {
name: 'Spring 2016NEWT-Shirt 2016迷彩蝴蝶夹克',
brandName: 'Supreme',
intro: '2016最新发布',
img: 'http://placehold.it/{width}x{height}',
sellPrice: 3199,
marketPrice: 4009,
colors: [
{
name: '黑色',
title: '黑色',
focus: true,
thumbs: [
'http://placehold.it/{width}x{height}',
'http://placehold.it/{width}x{height}',
'http://placehold.it/{width}x{height}',
'http://placehold.it/{width}x{height}',
'http://placehold.it/{width}x{height}'
],
sizes: [
{
name: 'S',
title: 'S',
sku: '12313',
num: 10
},
{
name: 'M',
title: 'M',
sku: '12314',
num: 14
},
{
name: 'L',
title: 'L',
sku: '12315',
num: 0
},
{
name: 'XL',
title: 'XL',
sku: '12316',
num: 0
}
],
rgb: '#000'
},
{
name: '黄色',
title: '黄色',
thumbs: [
'http://placehold.it/{width}x{height}',
'http://placehold.it/{width}x{height}'
],
rgb: '#efdc0e',
sizes: [
{
name: 'S',
title: 'S',
sku: '12313',
num: 0
},
{
name: 'M',
title: 'M',
sku: '12314',
num: 14
},
{
name: 'L',
title: 'L',
sku: '12315',
num: 0
},
{
name: 'XL',
title: 'XL',
sku: '12316',
num: 23
}
]
},
{
name: '蓝色',
title: '蓝色',
thumbs: [
'http://placehold.it/{width}x{height}',
'http://placehold.it/{width}x{height}',
'http://placehold.it/{width}x{height}',
'http://placehold.it/{width}x{height}'
],
rgb: '#2ea8e6'
},
{
name: '绿色',
title: '绿色',
thumbs: [
'http://placehold.it/{width}x{height}',
'http://placehold.it/{width}x{height}',
'http://placehold.it/{width}x{height}',
'http://placehold.it/{width}x{height}'
],
rgb: '#85b2ef'
}
]
},
description: {
titleEn: 'DESCRIPTION',
titleCn: '商品信息',
basic: [
{
key: '编号',
value: '51144694'
},
{
key: '颜色',
value: '灰色'
},
{
key: '性别',
value: '男款'
},
{
key: '经典款型',
value: '灰色'
}
]
},
material: {
titleEn: 'MATERIALS',
titleCn: '材料洗涤',
detail: [
{
img: 'http://placehold.it/{width}x{height}',
name: '皮革',
nameEn: 'Leather',
text: '不适宜沾水,避免硬物划花,使用专用清洁膏擦拭。长时间不着用,可用软毛巾抹掉表面尘土,上一层皮革保养油。建议几双鞋交替穿着,不穿时放置通风处保持鞋内干爽。'
}
],
wash: [
{
img: 'http://placehold.it/{width}x{height}',
name: '分色洗涤'
}
]
},
sizeInfo: {
titleEn: 'SIZEINFO',
titleCn: '尺码信息',
param: {
thead: [
{
width: 126,
name: '吊牌尺码'
},
{
width: 126,
name: '后衣长'
},
{
width: 126,
name: '前衣长'
}
],
tbody: [
['XS', 66, 66],
['S', 66, 66],
['L', 66, 66]
]
},
taste: {
thead: [
{
width: 170,
name: '模特'
},
{
width: 126,
name: '身高'
},
{
width: 126,
name: '体重'
}
],
tbody: [
[{
img: 'http://placehold.it/{width}x{height}',
name: 'Steven'
}, 187, 66],
[{
img: 'http://placehold.it/{width}x{height}',
name: 'Oliver'
}, 183, 66]
]
}
},
details: {
titleEn: 'DETAILS',
titleCn: '商品详情',
content: 'aaaa'
}
};
const _ = require('lodash');
const Item = require('../models/item');
const index = (req, res, next) => {
// let data = {
// brandBanner: {
// bgColor: '#93897d',
// brandLogo: {
// link: '#',
// img: 'http://placehold.it/{width}x{height}'
// },
// brandHome: {
// link: '#'
// }
// },
// nav: [
// {
// link: '#',
// name: 'MEN首页'
// },
// {
// link: '#',
// name: '上衣'
// },
// {
// link: '#',
// name: '卫衣'
// },
// {
// name: 'Spring 2016NEWT-Shirt 2016迷彩蝴蝶夹克'
// }
// ],
// goodInfo: {
// name: 'Spring 2016NEWT-Shirt 2016迷彩蝴蝶夹克',
// brandName: 'Supreme',
// intro: '2016最新发布',
// img: 'http://placehold.it/{width}x{height}',
// sellPrice: 3199,
// marketPrice: 4009,
// colors: [
// {
// name: '黑色',
// title: '黑色',
// focus: true,
// thumbs: [
// 'http://placehold.it/{width}x{height}',
// 'http://placehold.it/{width}x{height}',
// 'http://placehold.it/{width}x{height}',
// 'http://placehold.it/{width}x{height}',
// 'http://placehold.it/{width}x{height}'
// ],
// sizes: [
// {
// name: 'S',
// title: 'S',
// sku: '12313',
// num: 10
// },
// {
// name: 'M',
// title: 'M',
// sku: '12314',
// num: 14
// },
// {
// name: 'L',
// title: 'L',
// sku: '12315',
// num: 0
// },
// {
// name: 'XL',
// title: 'XL',
// sku: '12316',
// num: 0
// }
// ],
// rgb: '#000'
// },
// {
// name: '黄色',
// title: '黄色',
// thumbs: [
// 'http://placehold.it/{width}x{height}',
// 'http://placehold.it/{width}x{height}'
// ],
// rgb: '#efdc0e',
// sizes: [
// {
// name: 'S',
// title: 'S',
// sku: '12313',
// num: 0
// },
// {
// name: 'M',
// title: 'M',
// sku: '12314',
// num: 14
// },
// {
// name: 'L',
// title: 'L',
// sku: '12315',
// num: 0
// },
// {
// name: 'XL',
// title: 'XL',
// sku: '12316',
// num: 23
// }
// ]
// },
// {
// name: '蓝色',
// title: '蓝色',
// thumbs: [
// 'http://placehold.it/{width}x{height}',
// 'http://placehold.it/{width}x{height}',
// 'http://placehold.it/{width}x{height}',
// 'http://placehold.it/{width}x{height}'
// ],
// rgb: '#2ea8e6'
// },
// {
// name: '绿色',
// title: '绿色',
// thumbs: [
// 'http://placehold.it/{width}x{height}',
// 'http://placehold.it/{width}x{height}',
// 'http://placehold.it/{width}x{height}',
// 'http://placehold.it/{width}x{height}'
// ],
// rgb: '#85b2ef'
// }
// ]
// },
// description: {
// titleEn: 'DESCRIPTION',
// titleCn: '商品信息',
// basic: [
// {
// key: '编号',
// value: '51144694'
// },
// {
// key: '颜色',
// value: '灰色'
// },
// {
// key: '性别',
// value: '男款'
// },
// {
// key: '经典款型',
// value: '灰色'
// }
// ]
// },
// material: {
// titleEn: 'MATERIALS',
// titleCn: '材料洗涤',
// detail: [
// {
// img: 'http://placehold.it/{width}x{height}',
// name: '皮革',
// nameEn: 'Leather',
// text: '不适宜沾水,避免硬物划花,使用专用清洁膏擦拭。长时间不着用,可用软毛巾抹掉表面尘土,上一层皮革保养油。建议几双鞋交替穿着,不穿时放置通风处保持鞋内干爽。'
// }
// ],
// wash: [
// {
// img: 'http://placehold.it/{width}x{height}',
// name: '分色洗涤'
// }
// ]
// },
// sizeInfo: {
// titleEn: 'SIZEINFO',
// titleCn: '尺码信息',
// param: {
// thead: [
// {
// width: 126,
// name: '吊牌尺码'
// },
// {
// width: 126,
// name: '后衣长'
// },
// {
// width: 126,
// name: '前衣长'
// }
// ],
// tbody: [
// ['XS', 66, 66],
// ['S', 66, 66],
// ['L', 66, 66]
// ]
// },
// taste: {
// thead: [
// {
// width: 170,
// name: '模特'
// },
// {
// width: 126,
// name: '身高'
// },
// {
// width: 126,
// name: '体重'
// }
// ],
// tbody: [
// [{
// img: 'http://placehold.it/{width}x{height}',
// name: 'Steven'
// }, 187, 66],
// [{
// img: 'http://placehold.it/{width}x{height}',
// name: 'Oliver'
// }, 183, 66]
// ]
// }
// },
// details: {
// titleEn: 'DETAILS',
// titleCn: '商品详情',
// content: 'aaaa'
// }
// };
res.display('item', data);
Item.getProductItemData(req.params).then(result => {
if (_.isEmpty(result)) {
return next();
}
res.display('item', result);
}).catch(next);
};
module.exports = {
... ...
... ... @@ -3,7 +3,8 @@
const _ = require('lodash');
const Search = require('../models/search');
const camelCase = global.yoho.camelCase;
const DateHelper = require('../models/helpers');
const DataHelper = require('../models/helpers');
const Resouces = require('../models/resouces');
const list = {
index: (req, res, next) => {
... ... @@ -11,7 +12,7 @@ const list = {
q.page = q.page || 1;
let retDate = {
let retData = {
module: 'product',
page: 'list',
title: '列表'
... ... @@ -21,20 +22,26 @@ const list = {
if (result && result.code === 200 && result.data) {
let data = camelCase(result.data);
let nav = [DataHelper.getChannelNav()];
if (data.filter) {
retDate.filter = DateHelper.filterHandle(data.filter, q);
retData.filter = DataHelper.filterHandle(data.filter, q);
nav = _.concat(nav, retData.filter.nav);
}
retDate.paginationData = {
retData.navPath = {
nav: nav
};
retData.paginationData = {
page: q.page,
limit: data.limit || 45,
total: data.total,
pageTotal: data.pageTotal,
queryParams: q
};
res.display('list', _.assign(retDate, {
products: data.productList,
res.display('list', _.assign(retData, {
products: DataHelper.handleProductList(data.productList),
order: q.order
}));
} else {
... ... @@ -49,36 +56,48 @@ const list = {
q.page = q.page || 1;
let retDate = {
let retData = {
module: 'product',
page: 'list',
title: '列表'
};
Search.queryProduct(q).then(result => {
Promise.all([Resouces.newProductBanner(), Search.queryNewProduct(q)]).then(result => {
let banner = result[0];
let listData = result[1];
let nav = [DataHelper.getChannelNav(), {
name: '新品'
}];
if (result && result.code === 200 && result.data) {
let data = camelCase(result.data);
retData.banner = banner;
if (listData && listData.code === 200 && listData.data) {
let data = camelCase(listData.data);
if (data.filter) {
retDate.filter = DateHelper.filterHandle(data.filter, q);
retData.filter = DataHelper.filterHandle(data.filter, q);
}
retDate.paginationData = {
retData.navPath = {
nav: nav
};
retData.paginationData = {
page: q.page,
limit: data.limit || 45,
total: data.total,
pageTotal: data.pageTotal,
queryParams: q
};
res.display('newList', _.assign(retDate, {
products: data.productList,
res.display('newList', _.assign(retData, {
products: DataHelper.handleProductList(data.productList),
order: q.order
}));
} else {
return Promise.reject('query product error');
}
}).catch(next);
}
};
... ...
/**
* 搜索页
*
* @author: jiangfeng<jeff.jiang@yoho.cn>
* @date: 2016/7/12
*/
'use strict';
const _ = require('lodash');
const Search = require('../models/search');
const camelCase = global.yoho.camelCase;
const DataHelper = require('../models/helpers');
const Query = {
index: (req, res, next) => {
let q = req.query;
q.page = q.page || 1;
let retData = {
module: 'product',
page: 'list',
title: '列表'
};
Search.queryProduct(q).then(result => {
if (result && result.code === 200 && result.data) {
let data = camelCase(result.data);
let nav = [DataHelper.getChannelNav()];
nav.push({
name: `"${q.query}" ${data.total}个结果`
});
if (data.filter) {
retData.filter = DataHelper.filterHandle(data.filter, q);
}
retData.navPath = {
nav: nav
};
retData.paginationData = {
page: q.page,
limit: data.limit || 45,
total: data.total,
pageTotal: data.pageTotal,
queryParams: q
};
res.display('list', _.assign(retData, {
products: DataHelper.handleProductList(data.productList),
order: q.order
}));
} else {
return Promise.reject('query product error');
}
}).catch(next);
}
};
module.exports = Query;
... ...
... ... @@ -10,59 +10,76 @@
const _ = require('lodash');
const camelCase = global.yoho.camelCase;
const BrandData = require('../models/brand-service');
const cookie = global.yoho.cookie;
const Search = require('../models/search');
const DateHelper = require('../models/helpers');
function bannerFormat(banner) {
return {
bgImg: banner.brandBanner,
brandIntro: {
text: '品牌介绍'
},
height: 150
};
}
function shopMenu() {
let menus = [
{name: '店铺首页', href: '/'},
{name: '全部商品', href: '/shop', icon: '&#xe60a;'},
{name: '人气单品', href: '/list?order=xxx'},
{name: '新品上架', href: '/list?order=s_t_desc'}
];
return menus;
}
const DataHelper = require('../models/helpers');
const ShopData = require('../models/shop-service');
const shop = {
index(req, res, next) {
let domain = req.params.domain;
let uid = cookie.getUid(req);
let data = {
module: 'product',
page: 'shop',
title: domain
};
ShopData.getShopHeadData(domain, uid).then(result => {
if (result.shopId) {
let nav = [DataHelper.getChannelNav()];
nav.push({
name: result.name
});
data.navPath = {
nav: nav
};
data.banner = result;
res.display('shop-index', data);
} else {
shop.list(req, res, next);
}
});
},
list(req, res, next) {
let data = {
module: 'product',
page: 'shop-list',
title: '店铺列表'
};
let nav = [DataHelper.getChannelNav()];
let domain = req.params.domain;
let uid = cookie.getUid(req);
let q = req.query;
q.page = q.page || 1;
data.shopMenu = shopMenu();
BrandData.getBrandByDomainAsync(domain).then(result => {
data.brandBanner = bannerFormat(result);
q.brand = result.id;
q.shop_id = q.shopId || '';
ShopData.getShopHeadData(domain, uid).then(result => {
data.banner = result;
if (result.brandId) {
q.brand = result.brandId;
q.shop_id = result.shopId;
nav.push({
name: result.name
});
} else {
res.status(404);
return Promise.reject('brand not found');
}
}).then(() => {
return Search.queryProductOfBrand(q).then(result => {
if (result && result.code === 200 && result.data) {
let ret = camelCase(result.data);
if (ret.filter) {
delete q.brand;
data.filter = DateHelper.filterHandle(ret.filter, req.query);
data.filter = DataHelper.filterHandle(ret.filter, req.query);
}
data.paginationData = {
... ... @@ -73,12 +90,16 @@ const shop = {
queryParams: req.query
};
data.navPath = {
nav: nav
};
res.display('shop-list', _.assign(data, {
products: ret.productList,
products: DataHelper.handleProductList(ret.productList),
order: q.order
}));
} else {
return Promise.reject('query product error');
return Promise.reject('query shop index error');
}
});
}).catch(next);
... ...
... ... @@ -6,22 +6,25 @@
const api = global.yoho.API;
const getBannerInfoAsync = bid => {
return api.get('', {
method: 'web.brand.banner',
brand_id: bid
});
const BrandApi = {
getBrandInfo(bid, uid) {
let params = {
method: 'app.brand.getBrandIntro',
brand_id: bid
};
};
if (uid) {
params.uid = uid;
}
return api.get('', params);
},
const getBrandLogoByDomainAsync = domain => {
return api.get('', {
domain: domain,
method: 'web.brand.byDomain'
});
getDomainInfo(domain) {
return api.get('', {
domain: domain,
method: 'web.brand.byDomain'
});
}
};
module.exports = {
getBannerInfoAsync,
getBrandLogoByDomainAsync
};
module.exports = BrandApi;
... ...
... ... @@ -8,21 +8,20 @@ const co = Promise.coroutine;
const api = require('./brand-api');
const camelCase = global.yoho.camelCase;
const getBrandByDomainAsync = domain => {
const getDomainInfo = domain => {
return co(function*() {
let brandInfo = yield api.getBrandLogoByDomainAsync(domain);
let brandInfo = yield api.getDomainInfo(domain);
if (!brandInfo.data || brandInfo.code !== 200) {
return {};
}
return camelCase(brandInfo.data);
})();
};
const getBannerInfoAsync = bid => {
const getBrandInfo = bid => {
return co(function*() {
let brandInfo = yield api.getBannerInfoAsync(bid);
let brandInfo = yield api.getBrandInfo(bid);
if (!brandInfo.data || brandInfo.code !== 200) {
return {};
... ... @@ -33,6 +32,6 @@ const getBannerInfoAsync = bid => {
};
module.exports = {
getBrandByDomainAsync,
getBannerInfoAsync: getBannerInfoAsync
getDomainInfo,
getBrandInfo
};
... ...
'use strict';
const _ = require('lodash');
const config = global.yoho.config;
const helpers = {
brandLetters(numberIndex) {
... ... @@ -51,12 +52,15 @@ const helpers = {
});
},
getNav(channel, sort, sorts) {
let nav = [{
getChannelNav() {
return {
link: '#',
pathTitle: '',
name: 'MEN首页'
}];
};
},
getSortNav(sort, sorts) {
let nav = [];
if (sort && sorts) {
sorts.forEach(s => {
... ... @@ -140,7 +144,6 @@ const helpers = {
}
if (!_.isArray(sizeInfo)) {
sizeInfo.checked = true;
sizeInfo = [sizeInfo];
... ... @@ -189,12 +192,31 @@ const helpers = {
filters: filters,
showFilters: filters.length > 0,
letters: this.brandLetters(),
navPath: {
nav: this.getNav('', q.sort, sorts)
},
customPriceLow: customPriceLow,
customPriceHigh: customPriceHigh
customPriceHigh: customPriceHigh,
showSize: !!q.sort,
nav: this.getSortNav(q.sort, sorts)
};
},
handleProductList(list) {
if (_.isArray(list)) {
list.forEach(g => {
let goodsList = g.goodsList;
let goodsId;
if (goodsList && goodsList.length > 0) {
goodsId = goodsList[0].goodsId;
goodsList.forEach(o => {
o.url = `${config.siteUrl}/product/item/${g.productId}_${o.goodsId}.html`;
});
}
g.url = `${config.siteUrl}/product/item/${g.productId}_${goodsId}.html`;
});
}
return list;
}
};
... ...
/**
* 商品基本信息
* @author: yyq<yanqing.yang@yoho.cn>
* @date: 2016/7/11
*/
'use strict';
const api = global.yoho.API;
const getProductBaseAsync = (pid, uid, skn) => {
let params = {
method: 'h5.product.data',
productId: pid
};
if (uid) {
params.uid = uid;
}
if (skn) {
params.product_skn = skn;
}
return api.get('', params, { cache: true });
};
const getsizeInfoAsync = (skn) => {
return api.get('', {
method: 'h5.product.intro',
productskn: skn
}, { cache: true });
};
const getComfortAsync = productId => {
return api.get('', {
method: 'web.productComfort.data',
product_id: productId
}, {
cache: true,
code: 200
});
};
const getModelTryAsync = skn => {
return api.get('', {
method: 'web.productModelTry.data',
product_skn: skn
}, {
cache: true,
code: 200
});
};
module.exports = {
getProductBaseAsync,
getsizeInfoAsync,
getComfortAsync,
getModelTryAsync
};
... ...
/**
* 商品详情页model
* @author: yyq<yanqing.yang@yoho.cn>
* @date: 2016/7/11
*/
'use strict';
const _ = require('lodash');
const helpers = global.yoho.helpers;
/**
* 使sizeBoList id以 sizeAttributeBos id顺序一样
* @param sizeInfoBo
*/
const _sizeInfoBoSort = sizeInfoBo => {
if (!sizeInfoBo.sizeBoList || !sizeInfoBo.sizeAttributeBos) {
return {};
}
// TODO: 这里的排序代码很乱
_.forEach(sizeInfoBo.sizeBoList, (sizeBoList, sizek)=> {
let sortAttr = {};
_.forEach(sizeBoList.sortAttributes, sortAttributes => {
sortAttr[sortAttributes.id] = sortAttributes;
});
sizeInfoBo.sizeBoList[sizek].sortAttributes = sortAttr;
});
_.forEach(sizeInfoBo.sizeBoList, (sizeBoList, sizek)=> {
let sortAttr = [];
_.forEach(sizeInfoBo.sizeAttributeBos, val => {
sortAttr.push(sizeBoList.sortAttributes[val.id]);
});
sizeInfoBo.sizeBoList[sizek].sortAttributes = sortAttr;
});
return sizeInfoBo;
};
const setPathNav = (data, name) => {
let resData = {};
if (!_.isEmpty(data)) {
let navs = [];
let sort = data.sort[0];
navs.push({
link: helpers.urlFormat('/list', {
msort: sort.sort_id
// gender: '' // 待处理
}),
name: sort.sort_name,
pathTitle: sort.sort_name
});
// 二级分类
if (!_.isEmpty(sort.sub)) {
navs.push({
link: helpers.urlFormat('/list', {
msort: sort.sort_id,
misort: sort.sub.sort_id
// gender: '' // 待处理
}),
name: sort.sub[0].sort_name,
pathTitle: sort.sub[0].sort_name
});
}
navs.push({
name: name,
pathTitle: name
});
resData.nav = navs;
}
return resData;
};
/**
* 设置品牌banner数据
* @param brand 品牌相关数据
* @return Object
*/
const setBrandBanner = brand => {
let data = {
bgColor: '#000',
brandLogo: {
link: `#${brand.brandDomain}`, // 品牌跳转链接 -- 待处理
img: brand.brandIco
},
brandHome: {
link: `#${brand.brandDomain}` // 品牌跳转链接 -- 待处理
}
};
return {
brandBanner: data
};
};
/**
* 设置商品数据
* @param base 商品基础数据
* @return Object
*/
const setProductData = base => {
let data = {
name: base.productName,
brandName: _.has(base, 'brand.brandName') ? base.brand.brandName : '',
intro: base.salesPhrase,
sellPrice: base.productPriceBo.salesPrice,
marketPrice: base.productPriceBo.marketPrice,
total: 0
};
let chooseSkuFlag;
if (_.toNumber(data.sellPrice) >= _.toNumber(data.marketPrice)) {
// 售价与吊牌价相同,只显示售价
_.unset(data, 'marketPrice');
}
// 遍历颜色尺寸
if (base.goodsList) {
let goods = [];
// 处理商品数据
_.forEach(base.goodsList, function(value) {
let group = {},
thumbs = [],
sizes = [];
// 如果status为0,即skc下架时就跳过该商品
if (!value.status) {
return;
}
if (value.goodsImagesList) {
group = {
name: value.colorName,
title: `${data.name} ${value.colorName}`,
color: value.colorName,
total: 0
};
// 目前没有RGB值先以背景图方式实现
group.rgb = `url('${helpers.image(value.colorImage, 30, 30)}')`;
// 商品颜色列表
_.forEach(value.goodsImagesList, function(subValue) {
thumbs.push(subValue.imageUrl);
});
group.thumbs = thumbs;
// 缩略图空,不显示
if (!thumbs.length) {
return;
}
// 默认第一张图片
if (!_.has(data, 'img')) {
data.img = value.colorImage;
}
// 商品尺码列表
_.forEach(value.goodsSizeBoList, function(subValue) {
let size = {
name: subValue.sizeName,
title: subValue.sizeName,
sku: subValue.goodsSizeSkuId,
num: _.toInteger(subValue.goodsSizeStorageNum),
goodsId: subValue.goodsId
};
// 虚拟商品,增加为一件
if (subValue.attribute === 3) {
size.num = size.num > 1 ? 1 : 0;
}
// 如果status为0,即skc下架时,则库存设为0
if (subValue.status === 0) {
size.num = 0;
}
// 单个sku商品的总数累加
group.total += size.num;
// 默认选中该sku商品
if (group.total > 0 && !chooseSkuFlag) {
data.colorName = group.name;
group.cur = true; // 选中sku商品
chooseSkuFlag = true;
}
// 商品的总数累加
data.total += size.num;
sizes.push(size);
});
group.sizes = sizes;
}
goods.push(group);
});
if (goods.length && !chooseSkuFlag) {
goods[0].focus = true;
}
data.colors = goods;
}
return data;
};
/**
* 设置品牌介绍
* @param brand 品牌相关数据
* @return Object
*/
const setBrandIntro = brand => {
let barndIntro = {};
if (brand) {
barndIntro = {
brand: {
titleEn: 'BRAND',
titleCn: '品牌介绍',
logo: brand.brandIco,
intro: brand.brandIntro
}
};
}
return barndIntro;
};
/**
* 设置商品描述
* @param sizeInfo
* @param comfortInfo
* @return Object
*/
const setDescriptionData = (sizeInfo, comfortInfo) => {
let resData = {};
if (_.has(sizeInfo, 'productDescBo.erpProductId')) {
let description = {
titleEn: 'DESCRIPTION',
titleCn: '商品信息'
};
let sex;
switch (sizeInfo.productDescBo.gender) {
case 1:
sex = '男款';
break;
case 2:
sex = '女款';
break;
default:
sex = '通用';
break;
}
let basic = [
{ key: '编号', value: sizeInfo.productDescBo.erpProductId },
{ key: '颜色', value: sizeInfo.productDescBo.colorName },
{ key: '性别', value: sex }
];
if (_.isArray(sizeInfo.productDescBo.standardBos)) {
_.forEach(sizeInfo.productDescBo.standardBos, value => {
basic.push({
key: value.standardName,
value: value.standardVal
});
});
}
description.basic = basic;
if (comfortInfo) {
let comfort = [];
_.forEach(comfortInfo, value => {
let i = 1;
let blocks = [];
let flag = false;
do {
if (i === +value.wearSense.value) {
flag = true;
blocks.push({
cur: true
});
} else {
blocks.push({});
}
i++;
} while (i <= 5);
if (flag) {
comfort.push({
name: value.caption.caption,
minDes: value.caption.low,
blocks: blocks,
maxDes: value.caption.high
});
}
});
description.comfort = comfort;
}
resData = {
description: description
};
}
return resData;
};
/**
* 设置洗涤材质信息
* @param sizeInfo
* @return Object
*/
const setMaterialData = sizeInfo => {
let resData = {};
let material = {};
// 洗涤提示
if (sizeInfo.washTipsBoList) {
let wash = [];
_.forEach(sizeInfo.washTipsBoList, value => {
wash.push({
name: value.caption,
img: value.img
});
});
if (!_.isEmpty(wash)) {
material.wash = wash;
}
}
// 商品材质[洗涤说明]
if (sizeInfo.productMaterialList) {
let detail = [];
_.forEach(sizeInfo.productMaterialList, value => {
detail.push({
img: value.imageUrl,
name: value.caption,
enName: value.encaption,
text: value.remark
});
});
if (!_.isEmpty(detail)) {
material.detail = detail;
}
}
if (!_.isEmpty(material)) {
Object.assign(material, {
titleEn: 'MATERIALS',
titleCn: '材料洗涤'
});
resData.material = material;
}
return resData;
};
/**
* 设置尺寸信息
* @param sizeInfo
* @return Object
*/
const setSizeData = (sizeInfo) => {
let resData = {};
if (sizeInfo.sizeInfoBo) {
let referenceName,
boyReference,
girlReference,
gender;
let size = {
titleEn: 'SIZEINFO',
titleCn: '尺码信息'
};
sizeInfo.sizeInfoBo = _sizeInfoBoSort(sizeInfo.sizeInfoBo);
// 参考尺码
if (_.has(sizeInfo, 'productExtra')) {
boyReference = sizeInfo.productExtra.boyReference;
girlReference = sizeInfo.productExtra.girlReference;
}
gender = _.has(sizeInfo, 'productDescBo.gender') ? sizeInfo.productDescBo.gender : 3;
if (gender === 3 && boyReference) {
referenceName = '参考尺码(男)';
} else if (gender === 3 && girlReference) {
referenceName = '参考尺码(女)';
} else {
referenceName = '参考尺码';
}
// 判断是否显示参考尺码
let showReference = (boyReference && _.get(sizeInfo.sizeInfoBo, 'sizeBoList[0].boyReferSize', false)) ||
(girlReference && _.get(sizeInfo.sizeInfoBo, 'sizeBoList[0].girlReferSize', false));
if (sizeInfo.sizeInfoBo.sizeAttributeBos) {
let sizeTable = {};
// 尺码信息头部
sizeTable.thead = [{name: '吊牌尺码', id: '', width: 126}];
// 显示参考尺码
if (showReference) {
sizeTable.thead.push({name: referenceName, id: '', width: 126});
}
_.forEach(sizeInfo.sizeInfoBo.sizeAttributeBos, value => {
sizeTable.thead.push({
name: value.attributeName || ' ',
id: value.id,
width: 126
});
});
sizeTable.tbody = [];
_.forEach(sizeInfo.sizeInfoBo.sizeBoList, value => {
let sizes = [];
// 吊牌尺码
sizes.push(value.sizeName);
// 判断是否显示参考尺码
if (boyReference && (gender === 1 || gender === 3) && showReference) {
sizes.push(value.boyReferSize.referenceName || ' ');
} else if (girlReference && (gender === 2 || gender === 3) && showReference) {
sizes.push(value.girlReferSize.referenceName || ' ');
} else {
if (sizeTable.thead[1] && showReference) {
sizeTable.thead[1] = {};
}
}
// 其他尺码信息
value.sortAttributes.forEach(attr => {
sizes.push((attr.sizeValue || ' '));
});
// 尺码信息
sizeTable.tbody.push(sizes);
});
// 参考尺码为空
if (_.isEmpty(sizeTable.thead[1]) && showReference) {
// 移除这个值
sizeTable.thead.splice(1, 1);
}
size.param = sizeTable;
}
if (!_.isEmpty(sizeInfo.modelBos)) {
let tasteTable = {};
tasteTable.thead = [
{name: '模特', width: 170},
{name: '身高', width: 126},
{name: '体重', width: 126},
{name: '三围', width: 126},
{name: '吊牌尺码', width: 126},
{name: '试穿描述', width: 126}
];
tasteTable.tbody = [];
_.forEach(sizeInfo.modelBos, value => {
let modelInfo = [
value.avatar, value.modelName, value.height,
value.weight, value.vitalStatistics, value.fitModelBo.fit_size,
value.fitModelBo.feel
];
// 是否有备注
if (_.get(value, 'fitModelBo.fit_remark', false)) {
modelInfo.push(value.fitModelBo.fit_remark);
tasteTable.thead[7] = {name: '备注', width: 170};
}
tasteTable.tbody.push(modelInfo);
});
size.taste = tasteTable;
}
resData.sizeInfo = size;
}
return resData;
};
/**
* 设置商品详情页介绍
*
* @param array sizeInfo
* @return string
*/
const setDetailData = sizeInfo => {
let resData = {};
// 详情配图
if (_.has(sizeInfo, 'productIntroBo.productIntro')) {
let details = {
titleEn: 'DETAILS',
titleCn: '商品详情'
};
if (sizeInfo.productDescBo && sizeInfo.productDescBo.phrase) {
details.content = `${sizeInfo.productDescBo.phrase}<br/>`;
}
// 图片换规则
const replacePairs = [
{
reg: /<img src=/g,
str: '<img class="lazy" src="data:image/gif;base64,R0lGODlhAQABAJEAAAAAAP///93d3f' +
'///yH5BAEAAAMALAAAAAABAAEAAAICVAEAOw==" data-original='
},
{
reg: /<img border="0" src=/g,
str: '<img border="0" class="lazy" src="data:image/gif;base64,R0lGODlhAQABAJEAAAAAAP' +
'///93d3f///yH5BAEAAAMALAAAAAABAAEAAAICVAEAOw==" data-original='
}
];
let content = sizeInfo.productIntroBo.productIntro;
// 图片换成懒加载方式
_.forEach(replacePairs, value => {
content = _.replace(content, value.reg, value.str);
});
details.content += content;
resData.details = details;
}
return resData;
};
module.exports = {
setBrandBanner,
setPathNav,
setProductData,
setBrandIntro,
setDescriptionData,
setMaterialData,
setSizeData,
setDetailData
};
... ...
/**
* 商品详情页model
* @author: yyq<yanqing.yang@yoho.cn>
* @date: 2016/7/11
*/
'use strict';
const itemAPI = require('./item-api');
const itemFUN = require('./item-handler');
const search = require('./search-api');
const _getMultiResourceByBaseInfo = (base, uid) => {
let productId = base.id;
let skn = base.erpProductId;
// let brandId = base.brand.id ? base.brand.id : 0;
// 获取相关数据
let promiseData = [
itemAPI.getsizeInfoAsync(skn),
itemAPI.getComfortAsync(productId),
itemAPI.getModelTryAsync(skn),
search.getSortAsync({sort: base.smallSortId})
];
if (uid) {
console.log(uid);
// promiseData.push(favoriteBrandService.isFavoriteAsync(uid, productId));
}
return Promise.all(promiseData).then(result => {
return {
sizeInfo: result[0],
comfort: result[1].data,
modelTry: result[2].data,
sort: result[3].data
};
});
};
let getProductItemData = (params) => {
let pid = params[0];
// let gid = params[1];
return itemAPI.getProductBaseAsync(pid).then(result => {
let data = {};
if (!result.productName &&
!result.erpProductId &&
!result.productPriceBo) {
return data;
}
// 商品基本信息
data.goodInfo = itemFUN.setProductData(result);
if (result.brand) {
Object.assign(data, itemFUN.setBrandBanner(result.brand));
// BRAND品牌简介
Object.assign(data, itemFUN.setBrandIntro(result.brand));
}
return _getMultiResourceByBaseInfo(result).then(mulRes => {
// 面包屑导航
Object.assign(data, itemFUN.setPathNav(mulRes.sort, result.productName));
// DESCRIPTION商品描述
Object.assign(data, itemFUN.setDescriptionData(mulRes.sizeInfo, mulRes.comfort));
// MATERIALS材料洗涤
Object.assign(data, itemFUN.setMaterialData(mulRes.sizeInfo));
// SIZEINFO尺码信息
Object.assign(data, itemFUN.setSizeData(mulRes.sizeInfo, mulRes.modelTry));
// DETAILS商品详情
Object.assign(data, itemFUN.setDetailData(mulRes.sizeInfo));
return data;
});
});
};
module.exports = {
getProductItemData
};
... ...
/**
* 资源位查询
*/
'use strict';
const api = global.yoho.ServiceAPI;
const logger = global.yoho.logger;
const Resources = {
/**
* 获取新品到着-列表页-banner 资源位
* @returns {Promise.<T>}
*/
newProductBanner() {
let params = {
content_code: 'a7989369aa86681c678bc40f171b8f1d'
};
return api.get('/operations/api/v5/resource/get', params).then(result => {
if (result && result.code === 200 && result.data) {
let data = result.data;
if (data.length > 0) {
let d = data[0].data;
return d ? d[0] : {};
}
}
return {};
}).catch(e => {
logger.error('get new product list banner error', e);
return {};
});
}
};
module.exports = Resources;
... ...
// 由于目前没有相关java接口,暂时调search
'use strict';
const api = global.yoho.SearchAPI;
const getSortAsync = (condition) => {
return api.get('sortgroup.json', condition, {
code: 200
});
};
module.exports = {
getSortAsync
};
... ...
... ... @@ -17,9 +17,7 @@ const Search = {
let finalParams = {
method: 'app.search.li',
limit: 45,
productSize: '384x511',
yh_channel: 1
limit: 45
};
Object.assign(finalParams, clearEmptyVal(params));
... ... @@ -28,15 +26,28 @@ const Search = {
},
queryProductOfBrand(params) {
let finalParams = {
method: 'app.search.li',
limit: 45,
productSize: '384x511',
yh_channel: 1
method: 'app.search.brand',
limit: 45
};
Object.assign(finalParams, clearEmptyVal(params));
return api.get('', finalParams);
},
queryNewProduct(params) {
let finalParams = {
method: 'app.search.newProduct',
limit: 45
};
Object.assign(finalParams, clearEmptyVal(params));
return api.get('', finalParams);
},
queryAllSort() {
return api.get('', {
method: 'app.sort.get'
});
}
};
... ...
/**
* 店铺相关api调用
*
* @author: jiangfeng<jeff.jiang@yoho.cn>
* @date: 2016/07/14
**/
'use strict';
const Api = global.yoho.API;
const ShopApi = {
getShopIntro(shopId, uid) {
let param = {
method: 'app.shops.getIntro',
shop_id: shopId
};
if (uid) {
param.uid = uid;
}
return Api.get('', param);
},
getShopDecorator(shopId) {
let param = {
method: 'app.shopsdecorator.getList',
shop_id: shopId
};
return Api.get('', param);
},
getShopSorts(shopId, channel, gender) {
let param = {
method: 'app.shop.getSortInfo',
shop_id: shopId
};
if (channel) {
param.yh_channel = channel;
}
if (gender) {
param.gender = gender;
}
return Api.get('', param);
}
};
module.exports = ShopApi;
... ...
/**
* 店铺相关数据处理
*
* @author: jiangfeng<jeff.jiang@yoho.cn>
* @date: 2016/07/14
**/
'use strict';
const Promise = require('bluebird');
const co = Promise.coroutine;
const camelCase = global.yoho.camelCase;
const BrandService = require('./brand-service');
const ShopApi = require('./shop-api');
const _ = require('lodash');
/**
* 处理店铺默认菜单
* @param domain
* @returns {*[]}
*/
function shopMenu(domain) {
let menus = [
{name: '店铺首页', href: `/product/shop/${domain}`},
{name: '全部商品', href: `/product/shop/${domain}/list`, icon: '&#xe60a;'},
{name: '人气单品', href: `/product/shop/${domain}/list?order=xxx`},
{name: '新品上架', href: `/product/shop/${domain}/list?order=s_t_desc`}
];
return menus;
}
/**
* 处理店铺首页资源位数据
* @param data
* @returns {{}}
*/
function resourceDataHandle(data) {
let resource = {};
if (data && _.isArray(data)) {
data.forEach(d => {
resource[d.resourceName] = JSON.parse(d.resourceData);
});
}
return resource;
}
const ShopService = {
getShopIntro(shopId, uid) {
return co(function*() {
let shopIntro = yield ShopApi.getShopIntro(shopId, uid);
if (shopIntro && shopIntro.code === 200) {
return camelCase(shopIntro.data);
} else {
return {};
}
})();
},
getShopDecorator(shopId) {
return co(function*() {
let data = yield ShopApi.getShopDecorator(shopId);
if (data && data.code === 200) {
return camelCase(data.data);
} else {
return {};
}
})();
},
getShopSecondSorts(shopId) {
return co(function*() {
let data = yield ShopApi.getShopSorts(shopId);
if (data && data.code === 200) {
let sorts = camelCase(data.data);
return sorts.sort((a, b) => {
return a.sub.length >= b.sub.length;
});
} else {
return [];
}
})();
},
getShopHeadData(domain, uid) {
return co(function*() {
let domainInfo = yield BrandService.getDomainInfo(domain);
let info = {
brandId: domainInfo.id,
shopId: ''
};
if (domainInfo.shopId) {
let shopId = domainInfo.shopId;
let shopIntro = yield ShopService.getShopIntro(shopId, uid);
info.shopId = shopId;
info.name = shopIntro.shopName;
info.info = shopIntro.shopIntro;
info.btnName = '店铺介绍';
info.isFavorite = shopIntro.isFavorite === 'Y';
let shopData = yield Promise.all([ShopService.getShopDecorator(shopId),
ShopService.getShopSecondSorts(shopId)]);
let shopList = shopData[0];
let sorts = shopData[1];
let resources = resourceDataHandle(shopList.list);
info.sorts = sorts;
if (resources.shopTopBanner_base && resources.shopTopBanner_base.length > 0) { // eslint-disable-line
info.banner = resources.shopTopBanner_base[0].shopSrc; // eslint-disable-line
}
info.resources = resources;
info.menus = shopMenu(domain);
} else {
let brandId = domainInfo.id;
let brandInfo = yield BrandService.getBrandInfo(brandId, uid);
info.name = brandInfo.brandName;
info.info = brandInfo.brandIntro;
info.btnName = '品牌介绍';
info.isFavorite = brandInfo.isFavorite === 'Y';
info.banner = domainInfo.brandBanner;
}
return info;
})();
}
};
module.exports = ShopService;
... ...
... ... @@ -11,6 +11,7 @@ const cRoot = './controllers';
const list = require(cRoot + '/list');
const item = require(cRoot + '/item');
const shop = require(cRoot + '/shop');
const query = require(cRoot + '/query');
// Your controller here
router.get('/list', list.index); // 列表页面
... ... @@ -18,6 +19,9 @@ router.get('/list/new', list.newPage); // 新品列表页
router.get(/\/item\/([\d]+)_([\d]+).html/, item.index); // 商品详情页
router.get('/shop/:domain', shop.list);
router.get('/shop/:domain/list', shop.list);
router.get('/shop/:domain', shop.index);
router.get('/query', query.index);
module.exports = router;
... ...
... ... @@ -10,8 +10,8 @@
<div class="thumbs left clearfix">
<div class="thumb-list">
{{# colors}}
<div class="thumb-wrap{{#unless focus}} hide{{/unless}}">
{{#if focus}}
<div class="thumb-wrap{{#unless cur}} hide{{/unless}}">
{{#if cur}}
{{# thumbs}}
<img class="thumb" src="{{image . 75 100}}" data-shower="{{image . 482 643}}">
{{/ thumbs}}
... ... @@ -40,22 +40,24 @@
<div class="option-content">
<p class="choose-color">
<label class="title">Color:</label>
<span class="color">蓝色</span>
<span class="color">{{colorName}}</span>
</p>
<div class="color-list">
<div class="color-list clearfix">
{{# colors}}
{{> round-color}}
<div class="color-item" data-color="{{color}}" data-total="{{total}}" >
{{> round-color}}
</div>
{{/ colors}}
</div>
<p class="choose-size">
<label class="title">Size:</label>
<span class="size">M</span>
<span class="size"></span>
</p>
<div class="sizes">
{{# colors}}
<ul class="size-list {{#unless focus}}hide{{/unless}} clearfix">
<ul class="size-list{{#unless cur}} hide{{/unless}} clearfix">
{{# sizes}}
<li {{#unless num}}class="disable"{{/unless}} data-title="{{title}}" data-sku="{{sku}}" data-num="{{num}}">{{name}}</li>
<li {{#unless num}}class="disable"{{/unless}} title="{{title}}" data-sku="{{sku}}" data-num="{{num}}" data-name="{{name}}">{{name}}</li>
{{/ sizes}}
</ul>
{{/ colors}}
... ... @@ -94,15 +96,21 @@
{{/ goodInfo}}
<div class="other-info">
<div class="info-block">
<div class="block-title">
<label class="title-wrapper">
<span class="en">BRAND</span><br>
<span class="cn">品牌介绍</span>
</label>
{{# brand}}
<div class="info-block">
<div class="block-title">
<label class="title-wrapper">
<span class="en">{{titleEn}}</span><br>
<span class="cn">{{titleCn}}</span>
</label>
</div>
<div class="intro-block">
<img src="{{image logo 250 84}}">
<div class="intro-text">{{{intro}}}</div>
</div>
</div>
品牌介绍
</div>
{{/ brand}}
{{# description}}
<div class="info-block">
<div class="block-title">
... ... @@ -119,13 +127,13 @@
{{/ basic}}
</ul>
{{#if comfort}}
<ul class="comfort clearfix">
<ul class="des-comfort clearfix">
{{# comfort}}
<li class="pull-left">
<span class="comfort-title">{{name}}</span>
<li>
{{name}}:
<span class="min-des">{{minDes}}</span>
{{# blocks}}
<span class="comfort-block {{#if cur}}cur{{/if}}"></span>
<span class="comfort-block{{#if cur}} cur{{/if}}"></span>
{{/ blocks}}
<span class="max-des">{{maxDes}}</span>
</li>
... ...
<div class="blk-page yoho-product-list">
<div class="center-content">
{{# filter.navPath}}
{{# navPath}}
{{> path-nav}}
{{/ filter.navPath}}
{{/ navPath}}
</div>
<div class="center-content clearfix">
<div class="left">
... ... @@ -24,4 +24,4 @@
{{{ pagination paginationData }}}
</div>
</div>
</div>
\ No newline at end of file
</div>
... ...
{{!-- 新品 列表页 --}}
<div class="blk-page yoho-product-list">
<div class="center-content">
{{# filter.navPath}}
{{# navPath}}
{{> path-nav}}
{{/ filter.navPath}}
{{/ navPath}}
</div>
<div class="center-content clearfix">
<div class="left">
... ... @@ -14,7 +14,9 @@
</div>
<div class="right">
{{!-- 新品banner --}}
<div class="banner-img" style="height: 200px;margin-bottom:30px; background:url(//img12.static.yhbimg.com/couponImg/2016/07/06/10/025f07ba2e91648de11e5c054471323920.jpg) no-repeat top center;"></div>
{{# banner}}
<div class="banner-img" style="height: 200px;margin-bottom:30px; background:url({{image src 850 200 2}}) no-repeat top center;"></div>
{{/banner}}
{{!-- 已选中条件 --}}
{{#filter}}
{{> list/filter-area}}
... ...
<div class="blk-page yoho-shop-index">
<div class="center-content">
{{# navPath}}
{{> path-nav}}
{{/ navPath}}
</div>
<div class="center-content clearfix">
{{> brand-banner-list }}
{{> list/shop-menu }}
{{> list/banner-info }}
</div>
{{# banner.resources}}
{{#if newProducts}}
<div class="center-content clearfix slide-warp">
{{#each largeSlideImg}}
{{#each data}}
<div class="slide-left">
<a href="{{url}}">
<img src="{{src}}" alt="">
</a>
</div>
{{/each}}
{{/each}}
<div class="slide-right">
{{#each oneRowTwoColImages}}
{{#each data}}
<a href="{{url}}">
<img src="{{src}}" alt="">
</a>
{{/each}}
{{/each}}
</div>
</div>
{{/if}}
{{#if newProducts}}
<div class="center-content clearfix new-arrival-warp">
<div class="floor-header clearfix">
<h2 class="floor-title en-size">NEW ARRIVALS</h2>
<p class="floor-title zh-size">最新上架</p>
<a class="floor-more" href="#">MORE</a>
</div>
<div class="goods-wrap">
{{#each newProducts}}
<div class="goods-info" data-skn="{{productSkn}}">
<a href="" target="_blank">
<img class="lazy thumb" data-original="{{src}}" style="display: block;">
</a>
<div class="desc">
<a class="name" href="" target="_blank">{{productName}}</a>
<p class="price">{{round salesPrice 2}}</p>
</div>
</div>
{{/each}}
</div>
</div>
{{/if}}
{{#if hotProducts}}
<div class="center-content clearfix hot-product-warp">
<div class="floor-header clearfix">
<h2 class="floor-title en-size">HOT</h2>
<p class="floor-title zh-size">人气单品</p>
<a class="floor-more" href="#">MORE</a>
</div>
<div class="goods-wrap">
{{#each hotProducts}}
<div class="goods-info" data-skn="{{productSkn}}">
<a href="" target="_blank">
<img class="lazy thumb" data-original="{{src}}" style="display: block;">
</a>
<div class="desc">
<a class="name" href="" target="_blank">{{productName}}</a>
<p class="price">{{round salesPrice 2}}</p>
</div>
</div>
{{/each}}
</div>
</div>
{{/if}}
{{/ banner.resources}}
<div class="center-content clearfix all-product-warp">
<div class="floor-header clearfix">
<h2 class="floor-title en-size">ALL</h2>
<p class="floor-title zh-size">全部商品</p>
</div>
{{> list/shop-sort}}
{{> list/order-area}}
<div class="goods-wrap">
</div>
</div>
</div>
... ...
<div class="blk-page yoho-product-list">
<div class="center-content">
{{# filter.navPath}}
{{# navPath}}
{{> path-nav}}
{{/ filter.navPath}}
{{/ navPath}}
</div>
<div class="center-content clearfix">
{{> brand-banner-list }}
{{> list/shop-menu }}
{{> list/banner-info }}
</div>
<div class="center-content clearfix">
<div class="left">
... ...
{{# brandBanner}}
<div class="brand-banner" style="background-image: url('{{image bgImg 1150 150}}')">
{{# banner}}
<div class="brand-banner">
<div class="brand-img" style="height:150px; background: url('{{image banner 1150 150}}')"></div>
<p class="opts">
{{# brandIntro}}
<a href="{{link}}">
<i class="iconfont">&#xe631;</i>
{{text}}
</a>
{{/ brandIntro}}
<a id="brand-info">
<i class="iconfont">&#xe631;</i>
{{btnName}}
</a>
<span id="brand-fav" class="brand-fav{{#if coled}} coled{{/if}}">
<span id="brand-fav" class="brand-fav{{#if isFavorite}} coled{{/if}}">
{{> icon/collection}}
</span>
</p>
</div>
{{/brandBanner}}
{{/banner}}
... ...
{{# banner}}
<div class="brand-info-wrapper">
<div class="brand-info">
<div class="nano-content">
<div class="brand-info-title">
<h2>{{name}}</h2>
<h5>品牌介绍</h5>
</div>
<div class="brand-info-content">
{{{info}}}
</div>
</div>
</div>
</div>
{{/banner}}
... ...
... ... @@ -16,11 +16,11 @@
<div class="yoho-ui-accordion no-active">
{{#each sortData}}
<h3>{{categoryName}}</h3>
<div class="body" data-value="{{relationParameter.sort}}">
<div class="body" data-value="{{categoryId}}">
<div class="list-body nano">
<div class="nano-content">
{{#each sub}}
<div class="input-radio" data-value="{{relationParameter.sort}}">
<div class="input-radio" data-value="{{relationParameter.sort}}" data-category="{{categoryId}}">
{{> icon/radio }}
<label>{{categoryName}}</label>
</div>
... ... @@ -33,6 +33,7 @@
<div class="blank-div"></div>
{{#if brandData}}
<div class="yoho-ui-accordion">
<h3>品牌</h3>
<div class="body">
... ... @@ -68,6 +69,7 @@
</div>
</div>
</div>
{{/if}}
<div class="yoho-ui-accordion">
<h3>价格</h3>
... ... @@ -93,6 +95,7 @@
</div>
</div>
{{#if showSize}}
<div class="yoho-ui-accordion">
<h3>尺码</h3>
<div class="body">
... ... @@ -108,6 +111,7 @@
</div>
</div>
</div>
{{/if}}
<div class="yoho-ui-accordion">
<h3>颜色</h3>
... ...