Authored by jinhu.tung

Merge branch 'feature/shopping' into release/1.0

... ... @@ -14,12 +14,13 @@ exports.index = (req, res) => {
const uid = req.user.uid || null;
cartModel.getCartData(shoppingKey, uid).then((result) => {
// console.log(JSON.stringify(result, '', 4))
// console.log('Cart current Data:', JSON.stringify(result, '', 4))
if (result.code === 200) {
res.display('cart', _.merge({
module: 'shopping',
page: 'cart',
bcNavFocus: 1
bcNavFocus: 1,
defaultHeader: false
}, {
helpers: require('../helpers')
}, cartModel.filterCartData(result, uid)));
... ... @@ -64,11 +65,6 @@ exports.changeProductNum = (req, res) => {
}
});
// res.json({
// code: '1000',
// num: parseInt(changeTo, 10) - 1,
// changed: false
// });
} else if (changeType === 'DECREASE') {
cartModel.modifyProductNum({
decreaseNum: 1, // 默认是1
... ... @@ -77,7 +73,7 @@ exports.changeProductNum = (req, res) => {
sku,
goodTpye
}).then(result => {
console.log('changeProductNum-DECREASE-result:', result);
console.log('changeProductNum-DECREASE-result:', JSON.stringify(result));
if (result.code === 200) {
cartModel.getCartData(shoppingKey, uid).then(cartData => {
res.json(_.merge(
... ... @@ -172,7 +168,7 @@ exports.addToCart = (req, res) => {
shoppingKey: req.cookies._SPK || null,
uid: req.user.uid
}).then((result) => {
res.cookie('_SPK', result.data.shopping_key);
res.cookie('_SPK', result.data.shopping_key, { maxAge: 1000 * 60 * 60 * 24 * 365, httpOnly: true, path: '/'});
res.json(result);
});
};
... ... @@ -209,4 +205,15 @@ exports.toggleSelectGoods = (req, res) => {
};
// 去结算检查库存
exports.checkStorage = (req, res) => {
const shoppingKey = req.cookies._SPK || null;
const uid = req.user.uid || null;
cartModel.getCartData(shoppingKey, uid).then((result) => {
// console.log('Cart current Data:', JSON.stringify(result, '', 4))
res.json(_.merge(cartModel.filterCartData(result, uid), {code: result.code, message: result.message}));
});
};
... ...
... ... @@ -10,7 +10,6 @@
* 乘法
* @param {[Number]} num1
* @param {[Number]} num2
* @param {[object]} options 上下文环境,一般不手动传
* @return {[boolen]}
*/
exports.multiple = (num1, num2) => {
... ... @@ -23,3 +22,35 @@ exports.multiple = (num1, num2) => {
console.error('multiplication needs two number parameters');
}
};
/**
* 小于等于
* @param {[Number]} num1
* @param {[Number]} num2
* @param {[object]} options 上下文环境,一般不手动传
* @return {[boolen]}
*/
exports.lte = (num1, num2, options) => {
num1 = typeof num1 === 'number' ? num1 : parseFloat(num1, 10);
num2 = typeof num2 === 'number' ? num2 : parseFloat(num2, 10);
if (num1 <= num2) {
return options.fn(this);
}
return options.inverse(this);
};
/**
* 显示剩余库存
* @param {[Number]} leftNumber
* @return {[boolen]}
*/
exports.showStorage = (leftNumber) => {
leftNumber = typeof num1 === 'number' ? leftNumber : parseFloat(leftNumber, 10);
if (leftNumber <= 3 && leftNumber >= 0) {
return `仅剩${leftNumber}件`;
} else if (leftNumber < 0) {
return '库存不足';
}
};
... ...
... ... @@ -83,8 +83,8 @@ const addToCart = (options) => {
* }
*/
const getCartData = (shoppingKey, uid) => {
console.log('SPK:', shoppingKey);
console.log('uid:', uid);
// console.log('SPK:', shoppingKey);
// console.log('uid:', uid);
let params = {
method: 'app.Shopping.cart'
};
... ... @@ -132,12 +132,49 @@ const toggleSelectGoods = (params) => {
let method = 'app.Shopping.selectedAndCart';
_.merge(params, {method});
/*
let resultData;
let skus = JSON.parse(params.product_sku_list).map(sku => return sku.product_sku);
const skusLen = skus.length;
_.merge(params, {method});
return getCartData(params.shopping_key, params.uid).then(function(result) {
// 检查库存量
resultData = result.data;
_.find(
_.concat(resultData.ordinary_cart_data.goods_list, resultData.advance_cart_data.goods_list),
(goodItem) => {
if (skusLen == 1 && goodItem.product_sku === skus[0] &&
(parseInt(goodItem.buy_number, 10) > parseInt(goodItem.storage_number, 10))) {
// 单个商品
return {
code: '1000',
message: '您勾选的商品库存不足'
};
} else {
if((parseInt(goodItem.buy_number, 10) > parseInt(goodItem.storage_number, 10))) {
// 全选
return api.get('', params).then(result => {
return _.merge(result, {
code: '1001',
message: '您全选的商品中存在库存不足商品,已帮您自动取消勾选'
})
});
}
}
});
});
*/
return api.get('', params);
};
/*
* 商品选择与取消选择
* @function toggleSelectGoods
* 删除商品
* @function removeGoods
* @param { Number } uid 用户UID
* @param { String } sku 商品sku列表
* @param { String } shoppingKey 未登录用户唯一识别码,可以不传
... ... @@ -153,7 +190,7 @@ const removeGoods = (params) => {
/*
* 每次操作处理购物车数据
* @function toggleSelectGoods
* @function filterCartData
* @param { Object } result 购物车数据
* {
* advance_cart_data: { // 预售商品
... ... @@ -199,17 +236,20 @@ const filterCartData = (result, uid) => {
// 商品总数量
let buyNumber;
let storageNumber;
let totalNum = 0;
let noStorage = [];
// 返回值
let resData = {
loggedIn: uid
};
// 预售商品
if (result.data && result.data.advance_cart_data) {
// 预售商品
advancedCartData = result.data.advance_cart_data;
console.log('---------------advance------:', advancedCartData.goods_list.length);
// console.log('---------------advance------:', advancedCartData.goods_list.length);
totalAdvanceMoney = advancedCartData.shopping_cart_data.last_order_amount;
advancedGoods = _.concat(advancedGoods, advancedCartData.goods_list);
invalidGoods = _.concat(invalidGoods, advancedCartData.off_shelves_goods_list);
... ... @@ -217,17 +257,25 @@ const filterCartData = (result, uid) => {
_.forEach(advancedGoods, function(good) {
buyNumber = parseInt(good.buy_number, 10);
storageNumber = parseInt(good.storage_number, 10);
totalNum += buyNumber;
_.merge(good, {
left_number: storageNumber - buyNumber
});
if (good.selected === 'Y') {
selectedAdvanceNum += buyNumber;
if (storageNumber < buyNumber) {
noStorage.push(good.product_name);
}
}
});
}
// 普通商品
if (result.data && result.data.ordinary_cart_data) {
// 普通商品
ordinaryCartData = result.data.ordinary_cart_data;
console.log('---------------ordinary------:', ordinaryCartData.goods_list.length);
// console.log('---------------ordinary------:', ordinaryCartData.goods_list.length);
totalOrdinaryMoney = ordinaryCartData.shopping_cart_data.last_order_amount;
ordinaryGoods = _.concat(ordinaryGoods, ordinaryCartData.goods_list);
invalidGoods = _.concat(invalidGoods, ordinaryCartData.off_shelves_goods_list);
... ... @@ -235,9 +283,17 @@ const filterCartData = (result, uid) => {
_.forEach(ordinaryGoods, function(good) {
buyNumber = parseInt(good.buy_number, 10);
storageNumber = parseInt(good.storage_number, 10);
totalNum += buyNumber;
_.merge(good, {
left_number: storageNumber - buyNumber
});
if (good.selected === 'Y') {
selectedOrdinaryNum += buyNumber;
if (storageNumber < buyNumber) {
noStorage.push(good.product_name);
}
}
});
}
... ... @@ -252,8 +308,8 @@ const filterCartData = (result, uid) => {
invalidPros: invalidGoods,
selectedNum: selectedAdvanceNum + selectedOrdinaryNum,
checkAll: totalNum === (selectedAdvanceNum + selectedOrdinaryNum),
totalMoney: totalAdvanceMoney + totalOrdinaryMoney
totalMoney: totalAdvanceMoney + totalOrdinaryMoney,
noStorage
});
};
... ... @@ -273,12 +329,18 @@ const modifyProductNum = (options) => {
const uid = options.uid;
const shoppingKey = options.shoppingKey;
const sku = options.sku;
const goodType = options.goodType;
const goodType = options.goodTpye;
let buyNumber,
storageNumber;
let params = {
product_sku: options.sku
};
// 减少到库存范围内,自动勾选
// let selectedParams;
// 增加
if (increaseNum) {
_.merge(params, {
... ... @@ -310,17 +372,88 @@ const modifyProductNum = (options) => {
});
return getCartData(shoppingKey, uid).then(function(result) {
console.log('getCartData--pre-callback-result:', result);
console.log('modifyProductNum---params:', params);
// console.log('getCartData--pre-callback-result:', JSON.stringify(result, '', 4));
// console.log('modifyProductNum---params:', params);
if (goodType === 'advance') {
// 检查库存量
// 同步
_.find(result.data.advance_cart_data.goods_list, (goodItem) => {
if (goodItem.product_sku === sku) {
buyNumber = parseInt(goodItem.buy_number, 10);
storageNumber = parseInt(goodItem.storage_number, 10);
// 计算剩余多少
_.merge(goodItem, {
left_number: storageNumber - buyNumber
});
// 减少到库存范围内,自动勾选
// if(decreaseNum && buyNumber <= storageNumber) {
// selectedParams = {
// product_sku_list: JSON.stringify([{
// "goods_type": "ordinary",
// "buy_number": buyNumber,
// "selected": "Y",
// "product_sku": sku,
// "promotion_id": 0
// }]),
// uid: uid,
// shopping_key: shoppingKey
// };
// }
}
});
// 增加
if (increaseNum && (buyNumber + increaseNum) > storageNumber) {
return {
code: '1000',
message: '商品库存不足'
};
}
} else if (goodType === 'ordinary') {
// 检查库存量
// 同步
_.find(result.data.ordinary_cart_data.goods_list, (goodItem) => {
if (goodItem.product_sku === sku) {
buyNumber = parseInt(goodItem.buy_number, 10);
storageNumber = parseInt(goodItem.storage_number, 10);
// 计算剩余多少
_.merge(goodItem, {
left_number: storageNumber - buyNumber
});
// 减少到库存范围内,自动勾选
// if(decreaseNum && buyNumber <= storageNumber) {
// selectedParams = {
// product_sku_list: JSON.stringify([{
// "goods_type": "ordinary",
// "buy_number": buyNumber,
// "selected": "Y",
// "product_sku": sku,
// "promotion_id": 0
// }]),
// uid: uid,
// shopping_key: shoppingKey
// };
// }
}
});
// 增加
if (increaseNum && (buyNumber + increaseNum) > storageNumber) {
return {
code: '1000',
message: '商品库存不足'
};
}
}
// 异步
return api.get('', params);
});
};
module.exports = {
... ...
... ... @@ -21,6 +21,7 @@ router.post('/cart/product/send_to_favorite', cartCtrl.sendToFavorite);
router.get('/cart/product/:productId/edit', cartCtrl.editProduct);
router.post('/cart/add', cartCtrl.addToCart);
router.post('/cart/toggleSelectGoods', cartCtrl.toggleSelectGoods);
router.get('/cart/checkStorage', cartCtrl.checkStorage);
// 结算
router.get('/order', auth, order.index);
... ...
<div class="home-page">
<div class="blk-page center-content">
{{> sign-header}}
<div class="blk-page center-content">
{{> bc-nav}}
{{> cart/info}}
{{#if hasGoods}}
... ... @@ -8,8 +8,8 @@
{{> cart/empty-cart}}
{{/if}}
{{!-- <button id="add_to_cart1">添加到购物车 1413600 number 1</button> --}}
</div>
</div>
<script id="edit-color-size-tpl" type="text/html">
<div class="edit-color-size">
<div class="indicator"><i></i></div>
... ...
... ... @@ -58,16 +58,19 @@
</li>
<li class="price-num">
<span class="price sale-price">¥\{{sales_price}}</span>
<div class="stepper" data-productId=\{{productId}}>
<div class="minus action">
<div class="stepper" data-productType=\{{goods_type}}>
<div class="minus action \{{#isEqual buy_number 1}}disable\{{/isEqual}}">
<span class="iconfont">&#xe621;</span>
</div>
<div class="num">
<input type="text" class="input" value=\{{buy_number}} />
</div>
<div class="plus action">
<div class="plus action \{{#isEqual left_number 0}}disable\{{/isEqual}}">
<span class="iconfont">&#xe61f;</span>
</div>
<div class="warning">
\{{showStorage left_number}}
</div>
</div>
</li>
<li class="total-price-action">
... ... @@ -122,16 +125,19 @@
</li>
<li class="price-num">
<span class="price sale-price">¥\{{sales_price}}</span>
<div class="stepper" data-productId=\{{productId}}>
<div class="minus action">
<div class="stepper" data-productType=\{{goods_type}}>
<div class="minus action \{{#isEqual buy_number 1}}disable\{{/isEqual}}">
<span class="iconfont">&#xe621;</span>
</div>
<div class="num">
<input type="text" class="input" value=\{{buy_number}} />
</div>
<div class="plus action">
<div class="plus action \{{#isEqual left_number 0}}disable\{{/isEqual}}">
<span class="iconfont">&#xe61f;</span>
</div>
<div class="warning">
\{{showStorage left_number}}
</div>
</div>
</li>
<li class="total-price-action">
... ... @@ -175,16 +181,19 @@
</li>
<li class="price-num">
<span class="price sale-price">¥\{{salesPrice}}</span>
<div class="stepper" data-productId=\{{productId}}>
<div class="minus action">
<div class="stepper" data-productType=\{{goods_type}}>
<div class="minus action \{{#isEqual buy_number 1}}disable\{{/isEqual}}">
<span class="iconfont">&#xe621;</span>
</div>
<div class="num">
<input type="text" class="input" value=\{{buy_number}} />
</div>
<div class="plus action">
<div class="plus action \{{#isEqual left_number 0}}disable\{{/isEqual}}">
<span class="iconfont">&#xe61f;</span>
</div>
<div class="warning">
\{{showStorage left_number}}
</div>
</div>
</li>
<li class="total-price-action">
... ... @@ -211,7 +220,7 @@
</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 id="warning_invalid" class="action hoverable">清除实效商品</div>
<div class="selected-num">已选<span>\{{selectedNum}}</span>件</div>
<div class="checkout-total">
<div class="total-title">商品金额:</div>
... ...
... ... @@ -9,7 +9,7 @@
</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 id="clear_invalid" class="action hoverable">清除效商品</div>
<div class="selected-num">已选<span>{{selectedNum}}</span></div>
<div class="checkout-total">
<div class="total-title">商品金额:</div>
... ...
<div class="stepper" data-productType={{goods_type}}>
<div class="minus action">
<div class="minus action {{#isEqual buy_number 1}}disable{{/isEqual}}">
<span class="iconfont">&#xe621;</span>
</div>
<div class="num">
<input type="text" class="input" value={{buy_number}} />
</div>
<div class="plus action">
<div class="plus action {{#isEqual left_number 0}}disable{{/isEqual}}">
<span class="iconfont">&#xe61f;</span>
</div>
<div class="warning">
{{showStorage left_number}}
</div>
</div>
\ No newline at end of file
... ...
... ... @@ -55,9 +55,11 @@ $(function() {
Cart.editColorOrSize($(this).attr('data-productId'));
}).delegate('#checkout_btn', 'click', function(e) {
e.preventDefault();
if (!$(this).hasClass('disable')) {
window.location.href = '/shopping/order';
}
Cart.checkStorage(function() {
if (!$(this).hasClass('disable')) {
window.location.href = '/shopping/order';
}
});
});
// // 全选和单选
... ...
... ... @@ -40,14 +40,14 @@ var Cart = {
* 显示商品库存不足提示
* @function [toggleNotEnough]
* @params { Object } target 提示显示在目标DOM对象
* @params { String } type 显示全选提示还是单个商品提示
* @params { Object } bCheckAll 显示全选提示还是单个商品提示
*/
toggleNotEnough: function(target, type) {
toggleNotEnough: function(target, bCheckAll) {
var msg = '您勾选的商品库存不足',
allKlass = '',
tooltip;
if (type === 'ALL') {
if (bCheckAll) {
msg = '您全选的商品中存在库存不足商品,已帮您自动取消勾选';
allKlass = 'all';
}
... ... @@ -139,9 +139,11 @@ var Cart = {
dataType: 'json'
}).done(function(res) {
if (res.code === 200) {
Cart.refreshCart(res);
Util.refreshCart(res, function() {
Stepper.init();
});
} else {
_alert(res.message);
new _alert(res.message).show();
}
}).fail(function() {
... ... @@ -202,7 +204,9 @@ var Cart = {
data: {skuList: JSON.stringify(products)},
type: 'DELETE',
success: function(res) {
Cart.refreshCart(res);
Util.refreshCart(res, function() {
Stepper.init();
});
}
});
}
... ... @@ -231,7 +235,9 @@ var Cart = {
type: 'POST',
data: {skuList: JSON.stringify(products)},
success: function(res) {
Cart.refreshCart(res);
Util.refreshCart(res, function() {
Stepper.init();
});
}
});
}
... ... @@ -246,6 +252,17 @@ var Cart = {
url: '/shopping/cart/product/' + productId + '/edit',
success: function(res) {
if (res.code === '0') {
// helpers start
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;
} else {
console.error('multiplication needs two number parameters');
}
});
hbs.registerHelper('isEqual', function(v1, v2, options) {
if (v1 === v2) {
... ... @@ -254,12 +271,24 @@ var Cart = {
return options.inverse(this);
});
hbs.registerHelper('showStorage', function(leftNumber) {
leftNumber = typeof num1 === 'number' ? leftNumber : parseFloat(leftNumber, 10);
if (leftNumber <= 3 && leftNumber >= 0) {
return '仅剩' + leftNumber + '件';
} else if (leftNumber < 0) {
return '库存不足';
}
});
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);
});
// helpers end
template = hbs.compile($('#edit-color-size-tpl').html());
$('#edit_' + productId).append(
... ... @@ -274,10 +303,25 @@ var Cart = {
}
},
fail: function() {
_alert('此商品无法编辑颜色和尺寸').show();
new _alert('此商品无法编辑颜色和尺寸').show();
}
});
},
checkStorage: function(callback) {
Util.ajax({
url: '/shopping/cart/checkStorage',
success: function(res) {
if (!res.noStorage.length) {
if (callback) {
return callback();
}
} else {
new _alert(res.noStorage.join('<br/>') + '<br/>库存不足').show();
}
}
});
}
};
... ...
... ... @@ -21,8 +21,6 @@ var Stepper = {
changeType: 'DECREASE',
sku: sku,
goodType: goodType
// changeTo: parseInt(currNum, 10) - 1
},
success: function(res) {
Util.refreshCart(res, function() {
... ... @@ -43,15 +41,8 @@ var Stepper = {
changeType: 'INCREASE',
sku: sku,
goodType: goodType
// changeTo: parseInt(currNum, 10) + 1
},
success: function(res) {
// if (res.code === '0') {
// return callback(res.num, res.changed);
// } else {
// return callback(res.num, res.changed, res.code === '1000');
// }
Util.refreshCart(res, function() {
Stepper.init();
});
... ... @@ -101,7 +92,6 @@ var Stepper = {
if (changed && plus.hasClass('disable')) {
plus.removeClass('disable');
}
});
}
});
... ...
... ... @@ -37,6 +37,7 @@ var Util = {
refreshCart: function(data, callback) {
var template;
// helpers start
hbs.registerHelper('multiple', function(num1, num2) {
num1 = typeof num1 === 'number' ? num1 : parseFloat(num1, 10);
num2 = typeof num2 === 'number' ? num2 : parseFloat(num2, 10);
... ... @@ -55,12 +56,24 @@ var Util = {
return options.inverse(this);
});
hbs.registerHelper('showStorage', function(leftNumber) {
leftNumber = typeof num1 === 'number' ? leftNumber : parseFloat(leftNumber, 10);
if (leftNumber <= 3 && leftNumber >= 0) {
return '仅剩' + leftNumber + '件';
} else if (leftNumber < 0) {
return '库存不足';
}
});
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);
});
// helpers end
template = hbs.compile($('#cart-content-tpl').html());
$('#cart_content').html(template(data));
... ...
... ... @@ -39,4 +39,14 @@
height: 28px;
text-align: center;
}
.warning {
clear: both;
text-align: center;
width: 100%;
margin-top: 5px;
color: #e8044f;
font-size: 13px;
font-weight: bold;
}
}
... ...