Authored by yyq

Merge branch 'release/1.0' of git.yoho.cn:fe/yoho-blk into release/1.0

... ... @@ -9,16 +9,14 @@
const _ = require('lodash');
const helpers = global.yoho.helpers;
const PassportHelper = require('../models/passport-helper');
const BindService = require('../models/bind-api');
const loginService = require('../models/login-service');
const BindService = require('../models/bind-service');
const LoginService = require('../models/login-service');
const Sources = {
qq: 'QQ',
sina: '微博',
alipay: '支付宝',
wechat: '微信',
renren: '人人',
douban: '豆瓣'
wechat: '微信'
};
const DEFAULT_URL = 'http://img10.static.yhbimg.com/headimg/2013/11/28/09/01cae078abe5fe320c88cdf4c220212688.gif?imageView/2/w/100/h/100';
... ... @@ -173,7 +171,7 @@ const bind = {
let sourceType = req.body.sourceType;
if (mobile && openId && area && sourceType) {
BindService.bindCheck(mobile, openId, sourceType, area).then(result => {
BindService.bindCheckAsync(mobile, openId, sourceType, area).then(result => {
if (!result || !result.code) {
return {code: 400, message: '', data: ''};
} else if (result.code === 200 && result.data.is_register === 0) {
... ... @@ -210,7 +208,7 @@ const bind = {
let mobile = req.body.mobile;
let area = req.body.area;
BindService.sendBindMsg(area, mobile).then(result => {
BindService.sendBindMsgAsync(area, mobile).then(result => {
if (result && result.code) {
res.json(result);
} else {
... ... @@ -223,7 +221,7 @@ const bind = {
let area = req.body.area;
let code = req.body.code;
BindService.checkBindCode(area, mobile, code).then(result => {
BindService.checkBindCodeAsync(area, mobile, code).then(result => {
if (result && result.code) {
res.json(result);
} else {
... ... @@ -238,14 +236,14 @@ const bind = {
let sourceType = _.trim(req.body.sourceType);
let password = _.trim(req.body.password) || '';
BindService.bindMobile(openId, sourceType, mobile, area, password).then(result => {
BindService.bindMobileAsync(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', {
sourceType: sourceType + '_bind'
});
return loginService.syncUserSession(result.data.uid, req, res).then(() => {
return LoginService.syncUserSession(result.data.uid, req, res).then(() => {
return {code: 200, message: result.message, data: {refer: refer}};
});
} else {
... ... @@ -264,14 +262,14 @@ const bind = {
let areaCode = req.body.areaCode || '86';
let sourceType = req.body.sourceType;
return BindService.relateMobile(openId, sourceType, mobile, areaCode).then(result => {
return BindService.relateMobileAsync(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 loginService.syncUserSession(result.data.uid, req, res).then(() => {
return LoginService.syncUserSession(result.data.uid, req, res).then(() => {
return {code: 200, message: result.message, data: {refer: refer}};
});
} else {
... ...
... ... @@ -17,7 +17,7 @@ const helpers = global.yoho.helpers;
const log = global.yoho.logger;
const config = global.yoho.config;
const cache = global.yoho.cache;
const loginService = require('../models/login-service');
const LoginService = require('../models/login-service');
const PassportHelper = require('../models/passport-helper');
const loginPageURL = `${config.siteUrl}/passport/login`;
... ... @@ -38,7 +38,7 @@ function doPassportCallback(req, res, user) {
}
if (user.openId && user.nickname) {
let signinByOpenID = loginService.signinByOpenID(
let signinByOpenID = LoginService.signinByOpenIDAsync(
user.nickname, user.openId, user.sourceType, shoppingKey, user.unionId);
return signinByOpenID.then((result) => {
... ... @@ -53,7 +53,7 @@ function doPassportCallback(req, res, user) {
refer: refer
});
} else if (result.code === 200 && result.data.uid) {
return loginService.syncUserSession(result.data.uid, req, res).then(() => {
return LoginService.syncUserSession(result.data.uid, req, res).then(() => {
return refer;
});
}
... ... @@ -153,7 +153,7 @@ const local = {
let refer = req.cookies.refer;
if (isRemember) {
yield loginService.rememberAccount({
yield LoginService.rememberAccount({
area: req.body.areaCode || '86',
account: req.body.account,
password: req.body.password
... ... @@ -170,7 +170,7 @@ const local = {
refer = `${config.siteUrl}`;
}
yield loginService.syncUserSession(user.uid, req, res).then(() => {
yield LoginService.syncUserSession(user.uid, req, res).then(() => {
res.json({
code: 200,
data: {
... ...
... ... @@ -5,9 +5,9 @@
const _ = require('lodash');
const Promise = require('bluebird');
const passportHelper = require('../models/passport-helper');
const regService = require('../models/reg-api');
const userService = require('../models/user-service');
const loginService = require('../models/login-service');
const RegService = require('../models/reg-service');
const UserService = require('../models/user-service');
const LoginService = require('../models/login-service');
const config = require('../../../config/common');
let helpers = global.yoho.helpers;
... ... @@ -100,7 +100,7 @@ let checkMobile = (req, res, next) => {
}
// 判断用户是否存在
return userService.findByMobileAsync(area, mobile).then((user) => {
return UserService.findByMobileAsync(area, mobile).then((user) => {
if (!_.isEmpty(user)) {
data.message = '手机号码已经存在';
return res.json(data);
... ... @@ -156,7 +156,7 @@ let sendBindMsg = (req, res, next) => {
}
/* 向手机发送注册验证码 */
let result = yield regService.sendCodeToMobile(area, mobile);
let result = yield RegService.sendCodeToMobileAsync(area, mobile);
return cache.set(sendCodeKey, sendCodeTimes + 1, 3600).then(() => {
if (result.code) {
... ... @@ -182,7 +182,7 @@ let msgCaptcha = (req, res, next) => {
let mobile = req.body.mobile;
let code = req.body.code; // 短信验证码
regService.validMobileCode(area, mobile, code).then((result) => {
RegService.validMobileCodeAsync(area, mobile, code).then((result) => {
if (result.code) {
return res.json(result);
} else {
... ... @@ -232,7 +232,7 @@ let mobileRegister = (req, res, next) => {
let mobile = req.body.mobile;
let code = req.body.code; // 短信验证码
let password = req.body.password;
let result = yield regService.validMobileCode(area, mobile, code); // 验证注册的标识码是否有效
let result = yield RegService.validMobileCodeAsync(area, mobile, code); // 验证注册的标识码是否有效
if (!result.code || result.code !== 200) {
data.message = '验证码错误';
... ... @@ -240,14 +240,14 @@ let mobileRegister = (req, res, next) => {
}
/* 手机注册: 调用注册接口*/
let regResult = yield regService.regMobile(area, mobile, password, cookie.getShoppingKey(req));
let regResult = yield RegService.regMobileAsync(area, mobile, password, cookie.getShoppingKey(req));
if (!regResult.code || regResult.code !== 200) {
data.message = '注册失败';
return res.json(data);
}
return loginService.syncUserSession(regResult.data.uid, req, res).then(() => {
return LoginService.syncUserSession(regResult.data.uid, req, res).then(() => {
return res.json({
code: 200,
message: '注册成功',
... ... @@ -272,7 +272,7 @@ let success = (req, res) => {
title: '注册成功',
passport: {
goUrl: goUrl,
goShoppong: goShoppingUrl,
goShopping: goShoppingUrl,
mobile: mobile
}
});
... ...
... ... @@ -9,7 +9,7 @@
const api = global.yoho.API;
const bindCheck = (mobile, openId, sourceType, area) => {
const bindCheckAsync = (mobile, openId, sourceType, area) => {
let params = {
method: 'app.passport.signCheck',
area: area,
... ... @@ -21,7 +21,7 @@ const bindCheck = (mobile, openId, sourceType, area) => {
return api.get('', params);
};
const sendBindMsg = (area, mobile) => {
const sendBindMsgAsync = (area, mobile) => {
let params = {
method: 'app.passport.smsbind',
mobile: mobile,
... ... @@ -31,7 +31,7 @@ const sendBindMsg = (area, mobile) => {
return api.get('', params);
};
const checkBindCode = (area, mobile, code) => {
const checkBindCodeAsync = (area, mobile, code) => {
return api.get('', {
method: 'app.register.validRegCode',
mobile: mobile,
... ... @@ -40,7 +40,7 @@ const checkBindCode = (area, mobile, code) => {
});
};
const bindMobile = (openId, sourceType, mobile, area, password, nickname) => {
const bindMobileAsync = (openId, sourceType, mobile, area, password, nickname) => {
let params = {
method: 'app.passport.bind',
mobile: mobile,
... ... @@ -60,7 +60,7 @@ const bindMobile = (openId, sourceType, mobile, area, password, nickname) => {
return api.get('', params);
};
const relateMobile = (openId, sourceType, mobile, area) => {
const relateMobileAsync = (openId, sourceType, mobile, area) => {
return api.get('', {
method: 'app.passport.relatedMobile',
mobile: mobile,
... ... @@ -70,7 +70,7 @@ const relateMobile = (openId, sourceType, mobile, area) => {
});
};
const changeCheck = (mobile, area) => {
const changeCheckAsync = (mobile, area) => {
return api.get('', {
method: 'app.passport.changeCheck',
mobile: mobile,
... ... @@ -78,7 +78,7 @@ const changeCheck = (mobile, area) => {
});
};
const changeMobile = (uid, mobile, area, code) => {
const changeMobileAsync = (uid, mobile, area, code) => {
return api.get('', {
method: 'app.passport.changeMobile',
mobile: mobile,
... ... @@ -89,11 +89,11 @@ const changeMobile = (uid, mobile, area, code) => {
};
module.exports = {
bindCheck,
sendBindMsg,
checkBindCode,
bindMobile,
relateMobile,
changeCheck,
changeMobile
bindCheckAsync,
sendBindMsgAsync,
checkBindCodeAsync,
bindMobileAsync,
relateMobileAsync,
changeCheckAsync,
changeMobileAsync
};
... ...
/**
* Created by TaoHuang on 2016/7/26.
*/
'use strict';
const api = require('./bind-api');
module.exports = api;
... ...
... ... @@ -6,7 +6,7 @@
const api = global.yoho.API;
const signin = (area, profile, password, shoppingKey) => {
const signinAsync = (area, profile, password, shoppingKey) => {
let param = {
method: 'app.passport.signin',
area: area,
... ... @@ -21,7 +21,7 @@ const signin = (area, profile, password, shoppingKey) => {
return api.post('', param);
};
const signinByOtherOpenID = (nickname, openId, sourceType, shoppingKey) => {
const signinByOtherOpenIDAsync = (nickname, openId, sourceType, shoppingKey) => {
let param = {
nickname: nickname,
openId: openId,
... ... @@ -36,7 +36,7 @@ const signinByOtherOpenID = (nickname, openId, sourceType, shoppingKey) => {
return api.get('', param);
};
const signinByWechat = (nickname, openId, sourceType, shoppingKey, unionId) => {
const signinByWechatAsync = (nickname, openId, sourceType, shoppingKey, unionId) => {
let param = {
nickname: nickname,
openId: openId,
... ... @@ -53,7 +53,7 @@ const signinByWechat = (nickname, openId, sourceType, shoppingKey, unionId) => {
};
module.exports = {
signin,
signinByOtherOpenID,
signinByWechat
signinAsync,
signinByOtherOpenIDAsync,
signinByWechatAsync
};
... ...
... ... @@ -15,7 +15,7 @@ const AlipayStrategy = require('./passport-alipay').Strategy;
const md5 = require('md5');
const loginService = require('./login-service');
const LoginService = require('./login-service');
const config = global.yoho.config;
const helpers = global.yoho.helpers;
... ... @@ -63,25 +63,20 @@ passport.use(new LocalStrategy({
let shoppingKey = cookie.getShoppingKey(req);
let account = req.body.account;
let ip = req.ip;
let errorLoginKey = 'account_errorlogin_' + account;
let accountKey = 'account_signin_' + account;
let ipKey = 'ip_signin_' + ip;
let cacheGet = [cache.get(errorLoginKey), cache.get(accountKey), cache.get(ipKey)];
let cacheGet = [cache.get(errorLoginKey), cache.get(accountKey)];
Promise.all(cacheGet).then(times => {
let errLoginTimes = _.parseInt(times[0]) || 0;
let accountTimes = _.parseInt(times[1]) || 0;
let ipTimes = _.parseInt(times[2]) || 0;
if (accountTimes >= 10) {
done({message: '您的账号已被暂时锁定,请稍后再试'}, null);
} else if (ipTimes >= 100) {
done({message: '您尝试的次数过多,账号已被暂时锁定,请稍后再试'}, null);
done({message: '您的账号已被暂时锁定,请30分钟后再试'}, null);
} else {
return loginService.signin(area, username, password, shoppingKey).then((result) => {
return LoginService.signinAsync(area, username, password, shoppingKey).then((result) => {
if (result.code && result.code === 200 && result.data.uid) {
cache.del(errorLoginKey);
... ... @@ -89,15 +84,11 @@ passport.use(new LocalStrategy({
} else {
errLoginTimes = errLoginTimes + 1;
accountTimes = accountTimes + 1;
ipTimes = ipTimes + 1;
cache.set(errorLoginKey, errLoginTimes);
cache.set(accountKey, accountTimes, 1800);
cache.set(ipKey, ipTimes, 3600);
// 再次校验
if (ipTimes >= 100) {
done({message: '您尝试的次数过多,账号已被暂时锁定,请稍后再试'}, null);
} else if (accountTimes >= 10) {
if (accountTimes >= 10) {
done({message: '您的账号已被暂时锁定,请稍后再试'}, null);
} else if (errLoginTimes >= 3) {
done({
... ...
... ... @@ -13,10 +13,10 @@ const config = global.yoho.config;
const api = require('./login-api');
const userService = require('./user-service');
const signinByOpenID = (nickname, openId, sourceType, shoppingKey, unionId) => {
const signinByOpenIDAsync = (nickname, openId, sourceType, shoppingKey, unionId) => {
let signinFunc = {
other: api.signinByOtherOpenID,
wechat: api.signinByWechat
other: api.signinByOtherOpenIDAsync,
wechat: api.signinByWechatAsync
};
// PC 的微信登录之前使用了 open_id, 所以需要特别的接口处理
... ... @@ -73,8 +73,8 @@ const rememberAccount = (accountInfo, req, res) => {
};
module.exports = {
signin: api.signin,
signinByOpenID,
signinAsync: api.signinAsync,
signinByOpenIDAsync,
syncUserSession,
rememberAccount
};
... ...
... ... @@ -4,7 +4,7 @@
'use strict';
const api = global.yoho.API;
let sendCodeToMobile = (area, mobile) => {
let sendCodeToMobileAsync = (area, mobile) => {
let params = {
method: 'app.register.sendRegCodeToMobile',
area: area,
... ... @@ -14,7 +14,7 @@ let sendCodeToMobile = (area, mobile) => {
return api.post('', params);
};
let validMobileCode = (area, mobile, code) => {
let validMobileCodeAsync = (area, mobile, code) => {
let params = {
method: 'app.register.validRegCode',
area: area,
... ... @@ -25,7 +25,7 @@ let validMobileCode = (area, mobile, code) => {
return api.post('', params);
};
let regMobile = (area, mobile, password, shoppingKey)=> {
let regMobileAsync = (area, mobile, password, shoppingKey)=> {
let params = {
method: 'app.passport.register',
area: area,
... ... @@ -41,7 +41,7 @@ let regMobile = (area, mobile, password, shoppingKey)=> {
};
module.exports = {
sendCodeToMobile,
validMobileCode,
regMobile
sendCodeToMobileAsync,
validMobileCodeAsync,
regMobileAsync
};
... ...
/**
* Created by TaoHuang on 2016/7/26.
*/
'use strict';
const api = require('./reg-api');
module.exports = api;
... ...
... ... @@ -52,14 +52,12 @@
var count = 5,
countDown = document.getElementById('count-down');
console.log(countDown);
var timer = setInterval(function () {
setInterval(function () {
if (count > 1) {
count--;
countDown.innerHTML = count;
} else {
location.href = '/';
location.href = '/passport/login';
}
}, 1000);
})();
... ...
... ... @@ -48,7 +48,7 @@
<li class="clearfix">
<span class="left login-fail-tip hide">
<!--<span class="'iconfont">&#xe608;</span>-->
<span class="iconfont">&#xe61d;</span>
<em></em>
</span>
... ...
... ... @@ -9,7 +9,7 @@
<div>
尊敬的{{mobile}},恭喜您已经成为YOHO!BLK会员!即刻您可以开启时尚购物之旅!
</div>
<a class="btn btn-fixed-height success-btn" href="{{goShoppong}}" data-url="{{goUrl}}">开始购物</a>
<a class="btn btn-fixed-height success-btn" href="{{goShopping}}" data-url="{{goUrl}}">开始购物</a>
</div>
{{/ passport}}
</div>
... ...
... ... @@ -201,3 +201,22 @@ exports.modifyProduct = (req, res, next) => {
}
}).catch(next);
};
// 获取购物车商品信息
exports.getCartData = (req, res, next) => {
const shoppingKey = req.cookies._SPK || null;
const uid = req.user.uid || null;
cartModel.getCartData(shoppingKey, uid).then((result) => {
if (result.code === 200) {
res.json(
_.merge(
cartModel.filterCartData(result, uid),
{code: result.code, message: result.message}
)
);
} else {
res.send(result);
}
}).catch(next);
};
... ...
... ... @@ -229,7 +229,10 @@ const filterCartData = (result, uid) => {
let invalidGoods = [];
// 库存不足商品
let soldOutGoods = [];
// 售罄商品当作一般商品处理
// sold_out_goods_list
let advancedSoldOutGoods = [];
let ordinarySoldOutGoods = [];
// 商品总数量
let buyNumber;
... ... @@ -248,7 +251,7 @@ const filterCartData = (result, uid) => {
totalAdvanceMoney = advancedCartData.shopping_cart_data.last_order_amount;
advancedGoods = _.concat(advancedGoods, advancedCartData.goods_list);
invalidGoods = _.concat(invalidGoods, advancedCartData.off_shelves_goods_list);
soldOutGoods = _.concat(soldOutGoods, advancedCartData.sold_out_goods_list);
advancedSoldOutGoods = _.concat(advancedSoldOutGoods, advancedCartData.sold_out_goods_list);
_.forEach(advancedGoods, function(good) {
buyNumber = parseInt(good.buy_number, 10);
... ... @@ -272,7 +275,7 @@ const filterCartData = (result, uid) => {
totalOrdinaryMoney = ordinaryCartData.shopping_cart_data.last_order_amount;
ordinaryGoods = _.concat(ordinaryGoods, ordinaryCartData.goods_list);
invalidGoods = _.concat(invalidGoods, ordinaryCartData.off_shelves_goods_list);
soldOutGoods = _.concat(soldOutGoods, ordinaryCartData.sold_out_goods_list);
ordinarySoldOutGoods = _.concat(ordinarySoldOutGoods, ordinaryCartData.sold_out_goods_list);
_.forEach(ordinaryGoods, function(good) {
buyNumber = parseInt(good.buy_number, 10);
... ... @@ -293,8 +296,10 @@ const filterCartData = (result, uid) => {
return _.merge(resData, {
hasGoods: advancedGoods.length || ordinaryGoods.length || invalidGoods.length,
preSalePros: advancedGoods.length ? _.groupBy(advancedGoods, 'brand_id') : [],
commonPros: ordinaryGoods.length ? _.groupBy(ordinaryGoods, 'brand_id') : [],
preSalePros: (advancedSoldOutGoods.length || advancedGoods.length) ?
_.groupBy(_.concat(advancedGoods, advancedSoldOutGoods), 'brand_id') : [],
commonPros: (ordinarySoldOutGoods.length || ordinaryGoods.length) ?
_.groupBy(_.concat(ordinaryGoods, ordinarySoldOutGoods), 'brand_id') : [],
invalidPros: invalidGoods,
selectedNum: selectedAdvanceNum + selectedOrdinaryNum,
checkAll: totalNum === (selectedAdvanceNum + selectedOrdinaryNum),
... ...
... ... @@ -23,6 +23,7 @@ router.post('/cart/add', cartCtrl.addToCart);
router.post('/cart/toggleSelectGoods', cartCtrl.toggleSelectGoods);
router.get('/cart/checkStorage', cartCtrl.checkStorage);
router.put('/cart/updateProduct', cartCtrl.modifyProduct);
router.get('/cart/data', cartCtrl.getCartData);
// 结算
router.get('/order', auth, order.index);
... ...
... ... @@ -9,6 +9,7 @@
{{> cart/empty-cart}}
{{/if}}
</div>
<div id="removed_products"></div>
</div>
<script id="edit-color-size-tpl" type="text/html">
... ... @@ -117,10 +118,14 @@
<li class="pro-info">
\{{!-- <div class="brand-name">\{{brand_name}}</div> --}}
<div class="pro-name"><a href="/product/pro_\{{product_id}}_\{{goods_id}}/\{{cn_alphabet}}.html" target="_blank">\{{product_name}}</a></div>
<div class="size">
<div class="color-size editable" data-product_id=\{{product_id}} id="edit_\{{product_id}}">
\{{#if color_name}}
<span class="mr20">颜色: \{{color_name}}</span>
\{{/if}}
\{{#if size_name}}
<span>尺寸: \{{size_name}}</span>
\{{/if}}
<span class="iconfont">&#xe63c;</span>
</div>
\{{#expect_arrival_time}}
<div class="published-at">上市期: \{{expect_arrival_time}}</div>
... ... @@ -146,7 +151,7 @@
<li class="total-price-action">
<span class="price item-total-price">¥ \{{round (multiple sales_price buy_number) 2}}</span>
<div class="actions">
<div class="remove-item action" data-product_id=\{{product_id}}><span class="iconfont">&#xe614;</span> &nbsp;删&nbsp;&nbsp;&nbsp;&nbsp;除</div>
<div class="remove-item action" data-product_extra_info='{"goodsId": "\{{goods_id}}", "cnAlphabet": "\{{cn_alphabet}}", "productId": "\{{product_id}}", "salesPrice": "\{{round sales_price 2}}", "productName": "\{{product_name}}", "goodType":"ordinary", "selected": "\{{selected}}"}'><span class="iconfont">&#xe614;</span> &nbsp;删&nbsp;&nbsp;&nbsp;&nbsp;除</div>
<div class="send-to-favorite action" data-product_id=\{{product_id}}>移入收藏夹</div>
</div>
</li>
... ... @@ -213,7 +218,7 @@
<li class="total-price-action">
<span class="price item-total-price">¥ \{{round (multiple sales_price buy_number) 2}}</span>
<div class="actions">
<div class="remove-item action" data-product_id=\{{product_id}}><span class="iconfont">&#xe614;</span> &nbsp;删&nbsp;&nbsp;&nbsp;&nbsp;除</div>
<div class="remove-item action" data-product_extra_info='{"goodsId": "\{{goods_id}}", "cnAlphabet": "\{{cn_alphabet}}", "productId": "\{{product_id}}", "salesPrice": "\{{round sales_price 2}}", "productName": "\{{product_name}}", "goodType":"ordinary", "selected": "\{{selected}}"}'><span class="iconfont">&#xe614;</span> &nbsp;删&nbsp;&nbsp;&nbsp;&nbsp;除</div>
<div class="send-to-favorite action" data-product_id=\{{product_id}}>移入收藏夹</div>
</div>
</li>
... ... @@ -290,7 +295,6 @@
</div>
<div id="remove_selected" class="action hoverable">删除选中的商品</div>
<div id="send_favorite" class="action hoverable">移入收藏夹</div>
<div id="warning_invalid" class="action hoverable">清除实效商品</div>
<div class="selected-num">已选<span>\{{selectedNum}}</span>件</div>
<div class="checkout-total">
<div class="total-title">商品金额:</div>
... ... @@ -319,3 +323,28 @@
</a>
</div>
</script>
<script id="removed-products" type="text/html">
<div class="cart-removed-list">
<div class="info-bar">
<p class="info-text">已删除商品,您可以重新购买或移入收藏:</p>
</div>
<div class="removed-products">
<ul>
\{{#each removedProducts}}
<li class="removed-product">
<div class="product-name">
<a href="/product/pro_\{{productId}}_\{{goodsId}}/\{{cnAlphabet}}.html" target="_blank">\{{productName}}</a>
</div>
<div class="product-price">¥ \{{salesPrice}}</div>
<div class="bought-num">\{{buyNumber}}</div>
<div class="actions">
<span class="buy-again" data-rebuy_info='{"buyNumber": \{{buyNumber}}, "productSku": "\{{productSku}}"}'>重新购买</span>
<span class="send-to-favorite" data-product_info='{"goods_type": "\{{goodType}}", "buy_number": \{{buyNumber}}, "selected": "\{{selected}}", "product_sku": "\{{productSku}}", "promotion_id": 0}'>移入收藏夹</span>
</div>
</li>
\{{/each}}
</ul>
</div>
</div>
</script>
... ...
... ... @@ -24,10 +24,14 @@
<li class="pro-info">
{{!-- <div class="brand-name">{{brand_name}}</div> --}}
<div class="pro-name"><a href="/product/pro_{{product_id}}_{{goods_id}}/{{cn_alphabet}}.html" target="_blank">{{product_name}}</a></div>
<div class="size">
<div class="color-size editable" data-productId={{product_id}} id="edit_{{product_id}}" data-productSkn={{product_skn}}>
{{#if color_name}}
<span class="mr20">颜色: <span class="default-color">{{color_name}}</span></span>
{{/if}}
{{#if size_name}}
<span>尺寸: {{size_name}}</span>
<span>尺寸: <span class="default-size">{{size_name}}</span></span>
{{/if}}
<span class="iconfont">&#xe63c;</span>
</div>
{{#expect_arrival_time}}
<div class="published-at">上市期: {{expect_arrival_time}}</div>
... ... @@ -40,7 +44,7 @@
<li class="total-price-action">
<span class="price item-total-price">¥ {{round (multiple sales_price buy_number) 2}}</span>
<div class="actions">
<div class="remove-item action" data-product_id={{product_id}}><span class="iconfont">&#xe614;</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>
<div class="remove-item action" data-product_extra_info='{"goodsId": "{{goods_id}}", "cnAlphabet": "{{cn_alphabet}}", "productId": "{{product_id}}", "salesPrice": "{{round sales_price 2}}", "productName": "{{product_name}}", "goodType":"advance", "selected": "{{selected}}"}'><span class="iconfont">&#xe614;</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>
<div class="send-to-favorite action" data-product_id={{product_id}}>移入收藏夹</div>
</div>
</li>
... ... @@ -94,7 +98,7 @@
<li class="total-price-action">
<span class="price item-total-price">¥ {{round (multiple sales_price buy_number) 2}}</span>
<div class="actions">
<div class="remove-item action" data-product_id={{product_id}}><span class="iconfont">&#xe614;</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>
<div class="remove-item action" data-product_extra_info='{"goodsId": "{{goods_id}}", "cnAlphabet": "{{cn_alphabet}}", "productId": "{{product_id}}", "salesPrice": "{{round sales_price 2}}", "productName": "{{product_name}}", "goodType":"ordinary", "selected": "{{selected}}"}'><span class="iconfont">&#xe614;</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>
<div class="send-to-favorite action" data-product_id={{product_id}}>移入收藏夹</div>
</div>
</li>
... ...
<div class="cart-removed-list">
<div class="info-bar">
<p class="info-text">已删除商品,您可以重新购买或移入收藏:</p>
</div>
<div class="removed-products">
<ul>
<li class="removed-product">
<div class="product-name">TEEBACOO虎头字母短袖T恤</div>
<div class="product-price">¥ 373.00</div>
<div class="bought-num">2</div>
<div class="actions">
<span class="buy-again">重新购买</span>
<span class="send-to-favorite">移入收藏夹</span>
</div>
</li>
<li class="removed-product">
<div class="product-name">NIKIE AIR FORCE1</div>
<div class="product-price">¥ 373.00</div>
<div class="bought-num">2</div>
<div class="actions">
<span class="buy-again">重新购买</span>
<span class="send-to-favorite">移入收藏夹</span>
</div>
</li>
</ul>
</div>
</div>
\ No newline at end of file
... ... @@ -9,7 +9,6 @@
</div>
<div id="remove_selected" class="action hoverable">删除选中的商品</div>
<div id="send_favorite" class="action hoverable">移入收藏夹</div>
<div id="clear_invalid" class="action hoverable">清除失效商品</div>
<div class="selected-num">已选<span>{{selectedNum}}</span></div>
<div class="checkout-total">
<div class="total-title">商品金额:</div>
... ...
... ... @@ -19,7 +19,7 @@ module.exports = {
},
cookieDomain: 'yohobuy.com',
domains: {
api: 'http://devapi.yoho.cn:58078/', // devapi.yoho.cn:58078 testapi.yoho.cn:28078 devapi.yoho.cn:58078
api: 'http://testapi.yoho.cn:28078/', // devapi.yoho.cn:58078 testapi.yoho.cn:28078 devapi.yoho.cn:58078
service: 'http://testservice.yoho.cn:28077/', // testservice.yoho.cn:28077 devservice.yoho.cn:58077
search: 'http://192.168.102.216:8080/yohosearch/'
},
... ...
... ... @@ -15,7 +15,7 @@ exports.notFound = () => {
}
headerModel.requestHeaderData().then((result) => {
return res.render('error/404', {
return res.display('error/404', {
module: 'common',
page: 'error',
title: '页面不存在 | Yoho!Buy有货 | 潮流购物逛不停',
... ... @@ -43,7 +43,7 @@ exports.serverError = () => {
}
const renderErrPage = (result) => {
res.render('error/500', {
res.display('error/500', {
module: 'common',
page: 'error',
err: err,
... ...
... ... @@ -2,7 +2,7 @@
<div class="err-500-img"></div>
<div class="tips">
<span class="tip">哎呀,您访问的页面走丢了...</span>
<span class="tips-english">505 HTTP Version Not Supported</span>
<span class="tips-english">500 HTTP Version Not Supported</span>
<span class="">建议您:<a href="javascript:location.reload()">刷新该网页/ </a> 升级您的Web服务器软件</span>
</div>
</div>
\ No newline at end of file
... ...
... ... @@ -80,7 +80,7 @@ $smsCaptchaInput.on('blur', function() {
if (res.code === 200) {
// 添加验证码正确验证
$next.removeClass('disable').attr('href', res.data);
hideTip();
hideTip($smsCaptchaInput);
} else {
$next.addClass('disable');
errTip($smsCaptchaInput, '验证码不正确');
... ...
... ... @@ -22,8 +22,14 @@ $(function() {
Cart.toggleCheck.call(Cart, this);
}).delegate('.remove-item', 'click', function() {
// 删除商品
// 重构
Cart.removePro([$.parseJSON($(this).parents('ul').children().first().attr('data-product_info'))]);
// 失效商品删除,不用显示在删除模块
var productExtraInfo = $(this).attr('data-product_extra_info'),
productExtraInfoArr = productExtraInfo ? [$.parseJSON(productExtraInfo)] : [];
Cart.removePro(
[$.parseJSON($(this).parents('ul').children().first().attr('data-product_info'))],
productExtraInfoArr
);
}).delegate('#remove_selected', 'click', function(e) {
// 删除多个商品
// 重构
... ... @@ -92,6 +98,31 @@ $(function() {
return false;
});
$('#removed_products').delegate('.send-to-favorite', 'click', function() {
var $removedProduct = $(this).parents('.removed-product');
Cart.sendToFavorite([$.parseJSON($(this).attr('data-product_info'))], function() {
if ($('#removed_products .removed-product').length > 1) {
$removedProduct.remove();
} else {
$('#removed_products').html('');
}
});
}).delegate('.buy-again', 'click', function() {
var productInfo = $.parseJSON($(this).attr('data-rebuy_info')),
$removedProduct = $(this).parents('.removed-product');
Cart.addToCart(productInfo, function() {
Cart.refreshCart(function() {
if ($('#removed_products .removed-product').length > 1) {
$removedProduct.remove();
} else {
$('#removed_products').html('');
}
});
});
});
// 变动商品数量
Stepper.init();
});
... ...
... ... @@ -13,6 +13,10 @@ var Util = require('./util');
var hbs = require('yoho-handlebars');
var Stepper = require('./stepper');
// 删除商品信息
var removedProSkus = [];
var removedProsInfo = [];
var Cart = {
/*
* 添加到购物车
... ... @@ -94,37 +98,20 @@ var Cart = {
/*
* 根据服务端JSON,刷新购物车信息
* @function [refreshCart]
* @params { Object } data 最新购物车数据
* @params { Function } callback 刷新购物车后的回调函数
*/
refreshCart: function(data) {
var template;
hbs.registerHelper('multiple', function(num1, num2) {
num1 = typeof num1 === 'number' ? num1 : parseFloat(num1, 10);
num2 = typeof num2 === 'number' ? num2 : parseFloat(num2, 10);
if (num1 && num2) {
return num1 * num2;
}
});
hbs.registerHelper('isEqual', function(v1, v2, options) {
if (v1 === v2) {
return options.fn(this);
refreshCart: function(callback) {
Util.ajax({
url: '/shopping/cart/data',
success: function(res) {
Util.refreshCart(res, function() {
Stepper.init();
if (callback) {
return callback();
}
});
}
return options.inverse(this);
});
hbs.registerHelper('image', function(url, width, height, mode) {
mode = parseInt(mode, 10) ? mode : 2;
url = url || '';
return url.replace(/{width}/g, width).replace(/{height}/g, height).replace(/{mode}/g, mode);
});
template = hbs.compile($('#cart-content-tpl').html());
$('#cart_content').html(template(data));
Stepper.init();
},
/*
... ... @@ -195,11 +182,14 @@ var Cart = {
* 删除商品
* @function [removePro]
* @params { Array } products 商品列表
* @params { Array } extraInfos 删除商品额外信息
*/
removePro: function(products) {
removePro: function(products, extraInfos) {
var dialog;
if (products.length) {
// Cart.showRemovedProducts(products, extraInfos);
dialog = new _confirm({
content: '您确定要从购物车中删除该商品吗?',
cb: function() {
... ... @@ -211,6 +201,9 @@ var Cart = {
success: function(res) {
Util.refreshCart(res, function() {
Stepper.init();
// 显示或者更新删除商品模块
Cart.showRemovedProducts(products, extraInfos);
});
}
});
... ... @@ -222,11 +215,68 @@ var Cart = {
},
/*
* 显示或者更新删除商品模块
* @function [removePro]
* @params { Array } products 已删除商品列表
*/
showRemovedProducts: function(products, extraInfos) {
var productsLen = products.length,
index = 0,
currentPro,
currentExtraInfo,
currentSku;
var currentRemovedLen = removedProsInfo.length;
var currentItemBuyNumber;
var template;
if (extraInfos.length) {
for (index; index < productsLen; index++) {
currentPro = products[index];
currentExtraInfo = extraInfos[index];
currentSku = currentPro.product_sku;
if (removedProSkus.indexOf(currentPro.product_sku) === -1) {
// 当前删除商品不存在
removedProSkus.push(currentSku);
removedProsInfo.push({
productName: currentExtraInfo.productName,
salesPrice: currentExtraInfo.salesPrice,
buyNumber: currentPro.buy_number,
productSku: currentSku,
productId: currentExtraInfo.productId,
goodsId: currentExtraInfo.goodsId,
cnAlphabet: currentExtraInfo.cnAlphabet,
goodType: currentExtraInfo.goodType,
selected: currentExtraInfo.selected
});
} else {
// 当前删除商品是否已经存在,如果存在就累计数量
while (currentRemovedLen--) {
currentItemBuyNumber = removedProsInfo[currentRemovedLen].buyNumber;
if (removedProsInfo[currentRemovedLen].productSku === currentSku) {
removedProsInfo[currentRemovedLen].buyNumber = currentItemBuyNumber + currentPro.buy_number;
}
}
}
}
}
// 刷新
template = hbs.compile($('#removed-products').html());
$('#removed_products').html(template({
removedProducts: removedProsInfo
}));
},
/*
* 商品移入收藏夹
* @function [sendToFavorite]
* @params { Array } products 商品列表
* @params { Function } callback 移入收藏夹成功后回调
*/
sendToFavorite: function(products) {
sendToFavorite: function(products, callback) {
var msg = '确定要将该商品从购物车中移入收藏吗?<br/>移入收藏后该商品将不在购物车中显示';
var dialog;
... ... @@ -237,22 +287,39 @@ var Cart = {
msg = '确定要将已选中的商品从购物车中移入收藏吗?<br/>移入收藏后已选中的商品将不在购物车中显示';
}
dialog = new _confirm({
content: msg,
cb: function() {
dialog.close();
Util.ajax({
url: '/shopping/cart/product/send_to_favorite',
type: 'POST',
data: {skuList: JSON.stringify(products)},
success: function(res) {
Util.refreshCart(res, function() {
Stepper.init();
});
}
});
}
}).show();
// callback存在说明从删除模块收藏
if (callback) {
Util.ajax({
url: '/shopping/cart/product/send_to_favorite',
type: 'POST',
data: {skuList: JSON.stringify(products)},
success: function(res) {
Util.refreshCart(res, function() {
Stepper.init();
if (callback) {
return callback();
}
});
}
});
} else {
dialog = new _confirm({
content: msg,
cb: function() {
dialog.close();
Util.ajax({
url: '/shopping/cart/product/send_to_favorite',
type: 'POST',
data: {skuList: JSON.stringify(products)},
success: function(res) {
Util.refreshCart(res, function() {
Stepper.init();
});
}
});
}
}).show();
}
}
},
... ...
.error{
.error {
overflow: hidden;
margin: 85px 0 515px 0;
margin: 85px 0 515px;
.err-404-img {
width: 244px;
height: 105px;
background: resolve('404.png') no-repeat center center;
background: resolve('layout/404.png') no-repeat center center;
margin: 0 auto;
}
.tips {
width: 100%;
display: block;
margin: 200px auto;
margin: 400px auto;
text-align: center;
span {
display: block;
/* b {
cursor: pointer;
}*/
}
.tip {
height: 30px;
line-height: 30px;
font-size: 20px;
font-size: 20px;
}
}
... ... @@ -39,7 +35,7 @@
.err-500-img {
width: 244px;
height: 105px;
background: resolve('500.png') no-repeat center center;
background: resolve('layout/500.png') no-repeat center center;
margin: 0 auto;
}
}
... ...
... ... @@ -56,7 +56,7 @@
font-size: 14px;
color: #1b1b1b;
font-weight: bold;
margin: 0 60px 0 140px;
margin: 0 60px 0 224px;
}
.checkout-total {
... ...