diff --git a/apps/shopping/controllers/cart.js b/apps/shopping/controllers/cart.js index 9dcf521..9301533 100644 --- a/apps/shopping/controllers/cart.js +++ b/apps/shopping/controllers/cart.js @@ -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})); + }); +}; + diff --git a/apps/shopping/helpers/index.js b/apps/shopping/helpers/index.js index a3792da..b885df4 100644 --- a/apps/shopping/helpers/index.js +++ b/apps/shopping/helpers/index.js @@ -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 '库存不足'; + } +}; diff --git a/apps/shopping/models/cart.js b/apps/shopping/models/cart.js index 8a218c8..f4d4599 100644 --- a/apps/shopping/models/cart.js +++ b/apps/shopping/models/cart.js @@ -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 = { diff --git a/apps/shopping/router.js b/apps/shopping/router.js index d0607c8..ba290ea 100644 --- a/apps/shopping/router.js +++ b/apps/shopping/router.js @@ -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); diff --git a/apps/shopping/views/action/cart.hbs b/apps/shopping/views/action/cart.hbs index 9216578..c6abd5f 100644 --- a/apps/shopping/views/action/cart.hbs +++ b/apps/shopping/views/action/cart.hbs @@ -1,5 +1,5 @@ -<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> diff --git a/apps/shopping/views/partial/cart-list.hbs b/apps/shopping/views/partial/cart-list.hbs index 891fd90..37886e9 100644 --- a/apps/shopping/views/partial/cart-list.hbs +++ b/apps/shopping/views/partial/cart-list.hbs @@ -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"></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"></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"></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"></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"></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"></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> diff --git a/apps/shopping/views/partial/cart/statement.hbs b/apps/shopping/views/partial/cart/statement.hbs index 55a4cbf..8be3180 100644 --- a/apps/shopping/views/partial/cart/statement.hbs +++ b/apps/shopping/views/partial/cart/statement.hbs @@ -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> diff --git a/apps/shopping/views/partial/cart/stepper.hbs b/apps/shopping/views/partial/cart/stepper.hbs index 0a6f742..7a94369 100644 --- a/apps/shopping/views/partial/cart/stepper.hbs +++ b/apps/shopping/views/partial/cart/stepper.hbs @@ -1,11 +1,14 @@ <div class="stepper" data-productType={{goods_type}}> - <div class="minus action"> + <div class="minus action {{#isEqual buy_number 1}}disable{{/isEqual}}"> <span class="iconfont"></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"></span> </div> + <div class="warning"> + {{showStorage left_number}} + </div> </div> \ No newline at end of file diff --git a/public/js/shopping/cart.page.js b/public/js/shopping/cart.page.js index ecc5c14..9231672 100644 --- a/public/js/shopping/cart.page.js +++ b/public/js/shopping/cart.page.js @@ -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'; + } + }); }); // // 全选和单选 diff --git a/public/js/shopping/cart/cart.js b/public/js/shopping/cart/cart.js index e278e74..a8120c9 100644 --- a/public/js/shopping/cart/cart.js +++ b/public/js/shopping/cart/cart.js @@ -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(); + } + } + }); } }; diff --git a/public/js/shopping/cart/stepper.js b/public/js/shopping/cart/stepper.js index 20413c1..a6e93c2 100644 --- a/public/js/shopping/cart/stepper.js +++ b/public/js/shopping/cart/stepper.js @@ -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'); } - }); } }); diff --git a/public/js/shopping/cart/util.js b/public/js/shopping/cart/util.js index e743229..e2e0e08 100644 --- a/public/js/shopping/cart/util.js +++ b/public/js/shopping/cart/util.js @@ -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)); diff --git a/public/scss/shopping/_stepper.css b/public/scss/shopping/_stepper.css index 2dcd536..9226efe 100644 --- a/public/scss/shopping/_stepper.css +++ b/public/scss/shopping/_stepper.css @@ -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; + } }