Authored by jinhu.tung

Merge branch 'feature/shopping' into release/1.0

... ... @@ -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>
... ...
... ... @@ -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();
}
}
},
... ...
... ... @@ -56,7 +56,7 @@
font-size: 14px;
color: #1b1b1b;
font-weight: bold;
margin: 0 60px 0 140px;
margin: 0 60px 0 224px;
}
.checkout-total {
... ...