Authored by xuqi

Merge remote-tracking branch 'origin/feature/shopping' into develop

... ... @@ -10,44 +10,23 @@ const cartModel = require('../models/cart');
const _ = require('lodash');
exports.index = (req, res) => {
// cartModel.getCartData('9f0ab721c2d47879e2a2126a1f284106').then((result) => {
// console.log('get cart data:', result);
// }).catch((err) => {
// });
cartModel.getCartInfo().then((result) => {
const mock = {
loggedIn: true,
prosNum: result[0].preSalePros.length && result[1].commonPros.length && result[2].invalidPros.length
};
if (result[0].preSalePros) {
_.merge(mock, {
preSalePros: _.groupBy(result[0].preSalePros, 'brandName')
});
}
if (result[1].commonPros) {
_.merge(mock, {
commonPros: _.groupBy(result[1].commonPros, 'brandName')
});
}
if (result[2].invalidPros) {
console.log(result[2].invalidPros);
_.merge(mock, {
invalidPros: result[2].invalidPros
});
const shoppingKey = req.cookies._SPK || null;
const uid = req.cookies.uid || null;
cartModel.getCartData(shoppingKey, uid).then((result) => {
console.log('get cart data:', result);
if (result.code === 200) {
res.display('cart', _.merge({
module: 'shopping',
page: 'cart',
bcNavFocus: 1
}, {
helpers: require('../helpers')
}, cartModel.filterCartData(result, uid)));
} else {
// code 500
res.send(result);
}
res.display('cart', _.merge({
module: 'shopping',
page: 'cart'
}, mock));
}).catch((err) => {
res.send(err);
});
... ... @@ -117,9 +96,25 @@ exports.changeProductNum = (req, res) => {
// 删除商品
exports.removeProduct = (req, res) => {
// TODO
res.json({
code: '0'
const params = {};
const uid = req.cookies.uid;
const shoppingKey = req.cookies._SPK;
const productSkuList = req.body.skuList;
if (uid) {
_.merge(params, {uid});
}
if (shoppingKey) {
_.merge(params, {shopping_key: shoppingKey});
}
if (productSkuList) {
_.merge(params, {product_sku_list: productSkuList});
}
cartModel.removeGoods(params).then(result => {
res.json(_.merge(cartModel.filterCartData(result, uid), {code: result.code, message: result.message}));
});
};
... ... @@ -152,8 +147,6 @@ exports.editProduct = (req, res) => {
};
// 添加商品到购物车
// productSku:1329776
// buyNumber:1
exports.addToCart = (req, res) => {
const productSku = req.body.productSku;
const buyNumber = req.body.buyNumber;
... ... @@ -167,3 +160,69 @@ exports.addToCart = (req, res) => {
res.json(result);
});
};
// 购物车商品选择与取消选择
exports.toggleSelectGoods = (req, res) => {
const params = {};
const uid = req.cookies.uid;
const shoppingKey = req.cookies._SPK;
// 商品sku列表
// skuList:
// [{"goods_type":"advance","buy_number":1,"selected":"Y","product_sku":"1006277","promotion_id":0}, {...}]
// [{"goods_type":"ordinary","buy_number":1,"selected":"Y","product_sku":"1006277","promotion_id":0}, {...}]
const productSkuList = req.body.skuList;
if (uid) {
_.merge(params, {uid});
}
if (shoppingKey) {
_.merge(params, {shopping_key: shoppingKey});
}
if (productSkuList) {
_.merge(params, {product_sku_list: productSkuList});
}
cartModel.toggleSelectGoods(params).then(result => {
res.json(_.merge(cartModel.filterCartData(result, uid), {code: result.code, message: result.message}));
});
};
// 购物车商品选择与取消选择
exports.modifyProductNum = (req, res) => {
const uid = req.cookies.uid;
const shoppingKey = req.cookies._SPK;
const changeType = req.body.changeType;
const changeNum = req.body.changeNum;
const sku = req.body.sku;
let params = {
uid,
shoppingKey,
sku
};
if (changeType === 'INCREASE') {
_.merge(params, {
increaseNum: changeNum
});
} else if (changeType === 'DECREASE') {
_.merge(params, {
decreaseNum: changeNum
});
} else {
// TODO
// CHANGE
}
cartModel.modifyProductNum(params).then(result => {
res.json(_.merge(cartModel.filterCartData(result, uid), {code: result.code, message: result.message}));
});
};
... ...
/**
* Handlebars helpers
* dongjinhu jinhu.dong@yoho.cn
* 2016-07-14
*/
'use strict';
/**
* 乘法
* @param {[Number]} num1
* @param {[Number]} num2
* @param {[object]} options 上下文环境,一般不手动传
* @return {[boolen]}
*/
exports.multiple = (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');
}
};
... ...
... ... @@ -5,267 +5,10 @@
*/
'use strict';
var Promise = require('bluebird');
var _ = require('lodash');
const api = global.yoho.API;
// const ServiceAPI = require(`${global.library}/api`).ServiceAPI;
// const sign = require(`${global.library}/sign`);
// const logger = require(`${global.library}/logger`);
// const headerModel = require('../../../doraemon/models/header');
// var api = new ServiceAPI();
// 获取预售商品
const getPreSaleProducts = () => {
return Promise.resolve({
preSalePros: [{
gender: '1',
tags: '[Object]',
status: 1,
smallSortId: 115,
vip1Price: 379.04999999999995,
isGlobal: 'N',
vip3Price: 351.12,
isOutlets: 2,
isDiscount: 'Y',
brandDomain: 'allenove',
isSpecial: 'N',
goodsList: '[Object]',
isAdvance: 'N',
productId: 286135,
vipDiscountType: 1,
salesNum: 0,
cnAlphabet: 'ALLENOVE95S11GeBenHaGen',
productSkn: 51160998,
shelveTime: 1455616165,
vip2Price: 359.1,
editTime: 1455616165,
isNew: 'N',
isLimited: 'N',
brandName: 'Alle nove',
maxSortId: 1,
productName: 'Alle nove 小方领长袖衬衫【哥本哈根】',
brandId: 1007,
defaultImages: 'http://img13.static.yhbimg.com/goodsimg/2015/10/21/05/0279bf8ab67a6c962b08e37b3a13ce3401.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
stockNumber: 29,
storageNum: 29,
isSoonSoldOut: false,
middleSortId: 12,
salesPrice: 399,
isPromotion: 101,
marketPrice: 1299,
vipPrice: 0,
id: 51160998,
thumb: 'http://img13.static.yhbimg.com/goodsimg/2015/10/21/05/0279bf8ab67a6c962b08e37b3a13ce3401.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
url: 'http://www.yohobuy.com/product/pro_286135_367985/ALLENOVE95S11GeBenHaGen.html',
brandUrl: '//allenove.yohobuy.com',
orderNum: 1, // 购买数量
numIsValid: true, // 库存是否正常
isValid: true // 是否没有实效
}]
});
};
// 获取普通商品
const getNormalProducts = () => {
return Promise.resolve({
commonPros: [{ gender: '1',
tags: '[Object]',
status: 1,
smallSortId: 115,
vip1Price: 284.05,
isGlobal: 'N',
vip3Price: 263.12,
isOutlets: 2,
isDiscount: 'Y',
brandDomain: 'allenove',
isSpecial: 'N',
goodsList: [Object],
isAdvance: 'N',
productId: 286141,
vipDiscountType: 1,
salesNum: 0,
cnAlphabet: 'ALLENOVE95S14WeiYeNa',
productSkn: 51161001,
shelveTime: 1455616165,
vip2Price: 269.1,
editTime: 1455616165,
isNew: 'N',
isLimited: 'N',
brandName: 'Alle nove',
maxSortId: 1,
productName: 'Alle nove 翼型领长袖衬衫【维也纳】',
brandId: 1007,
defaultImages: 'http://img10.static.yhbimg.com/goodsimg/2015/10/21/02/0128dc014524ccf208b4f6f7760c9b9cf2.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
stockNumber: 21,
storageNum: 21,
isSoonSoldOut: false,
middleSortId: 12,
salesPrice: 299,
isPromotion: 101,
marketPrice: 1299,
vipPrice: 0,
id: 51161001,
thumb: 'http://img10.static.yhbimg.com/goodsimg/2015/10/21/02/0128dc014524ccf208b4f6f7760c9b9cf2.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
url: 'http://www.yohobuy.com/product/pro_286141_367991/ALLENOVE95S14WeiYeNa.html',
brandUrl: '//allenove.yohobuy.com',
orderNum: 2, // 购买数量
numIsValid: true, // 库存是否正常
isValid: true, // 是否没有实效
selectColor: '蓝',
selectSize: 'M'
}, { gender: '1',
tags: '[Object]',
status: 1,
smallSortId: 115,
vip1Price: 379.04999999999995,
isGlobal: 'N',
vip3Price: 351.12,
isOutlets: 2,
isDiscount: 'Y',
brandDomain: 'allenove',
isSpecial: 'N',
goodsList: '[Object]',
isAdvance: 'N',
productId: 286143,
vipDiscountType: 1,
salesNum: 0,
cnAlphabet: 'ALLENOVE95S20BaSaiLuoNa',
productSkn: 51161002,
shelveTime: 1455616165,
vip2Price: 359.1,
editTime: 1455616165,
isNew: 'N',
isLimited: 'N',
brandName: 'Foobar',
maxSortId: 1,
productName: 'Foobar 纽扣领绅士长袖衬衫【巴塞罗那】',
brandId: 1007,
defaultImages: 'http://img12.static.yhbimg.com/goodsimg/2015/10/21/05/024f60a070ab61981c139684f147d41f17.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
stockNumber: 25,
storageNum: 25,
isSoonSoldOut: false,
middleSortId: 12,
salesPrice: 399,
isPromotion: 101,
marketPrice: 1299,
vipPrice: 0,
id: 51161002,
thumb: 'http://img12.static.yhbimg.com/goodsimg/2015/10/21/05/024f60a070ab61981c139684f147d41f17.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
url: 'http://www.yohobuy.com/product/pro_286143_367993/ALLENOVE95S20BaSaiLuoNa.html',
brandUrl: '//allenove.yohobuy.com',
orderNum: 1, // 购买数量
numIsValid: false, // 库存是否正常
isValid: true // 是否没有实效
},
{ gender: '1',
tags: [Object],
status: 1,
smallSortId: 115,
vip1Price: 379.04999999999995,
isGlobal: 'N',
vip3Price: 351.12,
isOutlets: 2,
isDiscount: 'Y',
brandDomain: 'allenove',
isSpecial: 'N',
goodsList: [Object],
isAdvance: 'N',
productId: 286169,
vipDiscountType: 1,
salesNum: 0,
cnAlphabet: 'ALLENOVE95S09BiSa',
productSkn: 51161015,
shelveTime: 1455616145,
vip2Price: 359.1,
editTime: 1455616145,
isNew: 'N',
isLimited: 'N',
brandName: 'Alle nove',
maxSortId: 1,
productName: 'Alle nove 高支牛津休闲长袖衬衫【比萨】',
brandId: 1007,
defaultImages: 'http://img13.static.yhbimg.com/goodsimg/2015/10/21/05/027f47db67ca5cdb9fa996c8300947b975.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
stockNumber: 27,
storageNum: 27,
isSoonSoldOut: false,
middleSortId: 12,
salesPrice: 399,
isPromotion: 101,
marketPrice: 1299,
vipPrice: 0,
id: 51161015,
thumb: 'http://img13.static.yhbimg.com/goodsimg/2015/10/21/05/027f47db67ca5cdb9fa996c8300947b975.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
url: 'http://www.yohobuy.com/product/pro_286169_368019/ALLENOVE95S09BiSa.html',
brandUrl: '//allenove.yohobuy.com',
orderNum: 2, // 购买数量
numIsValid: true, // 库存是否正常
isValid: true // 是否没有实效
}]
});
};
// 获取失效商品
const getInvalidProducts = () => {
return Promise.resolve({
invalidPros: [{ gender: '1',
tags: ['Object'],
status: 1,
smallSortId: 115,
vip1Price: 379.04999999999995,
isGlobal: 'N',
vip3Price: 351.12,
isOutlets: 2,
isDiscount: 'Y',
brandDomain: 'allenove',
isSpecial: 'N',
goodsList: ['Object'],
isAdvance: 'N',
productId: 286139,
vipDiscountType: 1,
salesNum: 0,
cnAlphabet: 'ALLENOVE95S13PuLuoWangSi',
productSkn: 51161000,
shelveTime: 1455616165,
vip2Price: 359.1,
editTime: 1455616165,
isNew: 'N',
isLimited: 'N',
brandName: 'Alle nove',
maxSortId: 1,
productName: 'Alle nove 复古圆领长袖衬衫【普罗旺斯】',
brandId: 1007,
defaultImages: 'http://img12.static.yhbimg.com/goodsimg/2015/10/21/03/02705334cacca0a06edec049918290f7b3.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
stockNumber: 12,
storageNum: 12,
isSoonSoldOut: false,
middleSortId: 12,
salesPrice: 399,
isPromotion: 101,
marketPrice: 1299,
vipPrice: 0,
id: 51161000,
thumb: 'http://img12.static.yhbimg.com/goodsimg/2015/10/21/03/02705334cacca0a06edec049918290f7b3.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80',
url: 'http://www.yohobuy.com/product/pro_286139_367989/ALLENOVE95S13PuLuoWangSi.html',
brandUrl: '//allenove.yohobuy.com',
orderNum: 1, // 购买数量
numIsValid: true, // 库存是否正常
isValid: false // 是否没有实效
}]
});
};
// 获取购物车信息
const getCartInfo = () => {
return Promise.all([
getPreSaleProducts(),
getNormalProducts(),
getInvalidProducts()
]);
};
/*
* 加入购物车
* @function addToCart
... ... @@ -340,6 +83,8 @@ const addToCart = (options) => {
* }
*/
const getCartData = (shoppingKey, uid) => {
console.log('SPK:', shoppingKey);
console.log('uid:', uid);
let params = {
method: 'app.Shopping.cart'
};
... ... @@ -380,9 +125,206 @@ const transferToFavorite = (uid, sku, hasPromotion) => {
return api.get('', params);
};
/*
* 商品选择与取消选择
* @function toggleSelectGoods
* @param { Number } uid 用户UID
* @param { String } sku 商品sku列表
* @param { String } shoppingKey 未登录用户唯一识别码,可以不传
* @return { Array }
*/
const toggleSelectGoods = (params) => {
// BLK 没有促销, 新接口
let method = 'app.Shopping.selectedAndCart';
_.merge(params, {method});
return api.get('', params);
};
/*
* 商品选择与取消选择
* @function toggleSelectGoods
* @param { Number } uid 用户UID
* @param { String } sku 商品sku列表
* @param { String } shoppingKey 未登录用户唯一识别码,可以不传
* @return { Array }
*/
const removeGoods = (params) => {
// BLK 没有促销, 新接口
let method = 'app.Shopping.removeAndCart';
_.merge(params, {method});
return api.get('', params);
};
/*
* 每次操作处理购物车数据
* @function toggleSelectGoods
* @param { Object } result 购物车数据
* {
* advance_cart_data: { // 预售商品
* gift_list: [], // 赠品
* goods_list: [] // 商品列表
* off_shelves_goods_list: [], // 下架商品, 失效商品
* price_gift: [], // 加价购商品
* promotion_info: [], // 促销信息
* shopping_cart_data: [], // 商品价格计算相关信息
* sold_out_goods_list: [] // 售罄商品
* },
* ordinary_cart_data: { // 普通商品
* gift_list: [],
* goods_list: [],
* off_shelves_goods_list: [],
* price_gift: [],
* promotion_info: [],
* shopping_cart_data: [],
* sold_out_goods_list: []
* },
* md5: '...',
* message: '...'
* }
*/
const filterCartData = (result, uid) => {
// 预售商品
let advancedGoods = [],
selectedAdvanceNum = 0,
totalAdvanceMoney,
advancedCartData;
// 普通商品
let ordinaryGoods = [],
selectedOrdinaryNum = 0,
totalOrdinaryMoney,
ordinaryCartData;
// skn=0或者已下架的商品,定义为失效商品
let invalidGoods = [];
// 库存不足商品
let soldOutGoods = [];
// 商品总数量
let buyNumber;
let totalNum = 0;
// 返回值
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);
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);
_.forEach(advancedGoods, function(good) {
buyNumber = parseInt(good.buy_number, 10);
totalNum += buyNumber;
if (good.selected === 'Y') {
selectedAdvanceNum += buyNumber;
}
});
}
if (result.data && result.data.ordinary_cart_data) {
// 普通商品
ordinaryCartData = result.data.ordinary_cart_data;
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);
soldOutGoods = _.concat(soldOutGoods, ordinaryCartData.sold_out_goods_list);
_.forEach(ordinaryGoods, function(good) {
buyNumber = parseInt(good.buy_number, 10);
totalNum += buyNumber;
if (good.selected === 'Y') {
selectedOrdinaryNum += buyNumber;
}
});
}
// console.log('ordinaryGoods:', ordinaryGoods);
return _.merge(resData, {
hasGoods: advancedGoods.length || ordinaryGoods.length || invalidGoods.length,
preSalePros: advancedGoods.length ? _.groupBy(advancedGoods, 'brand_id') : [],
commonPros: ordinaryGoods.length ? _.groupBy(ordinaryGoods, 'brand_id') : [],
invalidPros: invalidGoods,
selectedNum: selectedAdvanceNum + selectedOrdinaryNum,
checkAll: totalNum === (selectedAdvanceNum + selectedOrdinaryNum),
totalMoney: totalAdvanceMoney + totalOrdinaryMoney
});
};
/**
* 增减购物车商品数量
* @function modifyProductNum
* @param { Number } uid 用户ID
* @param { String } sku 商品SKU
* @param { Number } increaseNum 增加的数目
* @param { Number } decreaseNum 减少的数目
* @param { String } shoppingKey 未登录用户唯一识别码
* @return { Array } 接口返回的数据
*/
const modifyProductNum = (options) => {
const increaseNum = options.increaseNum;
const decreaseNum = options.decreaseNum;
const uid = options.uid;
const shoppingKey = options.shoppingKey;
const sku = options.sku;
let params = {
product_sku: options.sku
};
// 增加
if (increaseNum) {
_.merge(params, {
method: 'app.Shopping.increase',
increase_number: parseInt(increaseNum, 10)
});
}
// 减少
if (decreaseNum) {
_.merge(params, {
method: 'app.Shopping.decrease',
decrease_number: parseInt(decreaseNum, 10)
});
}
if (uid) {
_.merge(params, {uid});
}
if (shoppingKey) {
_.merge(params, {
shopping_key: shoppingKey
});
}
if (sku) {
_.merge(params, {
product_sku: sku
});
}
return api.get('', params);
};
module.exports = {
addToCart,
getCartData,
getCartInfo,
transferToFavorite
transferToFavorite,
toggleSelectGoods,
removeGoods,
filterCartData,
modifyProductNum
};
... ...
... ... @@ -17,10 +17,11 @@ const order = require(`${cRoot}/order`); // 下单
router.get('/cart', cartCtrl.index);
router.get('/cart/product/check_inventory', cartCtrl.checkInventory);
router.post('/cart/product/:productId/change_num', cartCtrl.changeProductNum);
router.delete('/cart/product/:productId', cartCtrl.removeProduct);
router.delete('/cart/product/remove', cartCtrl.removeProduct);
router.post('/cart/product/:productId/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('/order', auth, order.index);
... ...
<div class="home-page">
<div class="blk-page center-content">
{{> common/bc-nav}}
{{> common/info}}
{{ selectedGoods.length }}
{{#if prosNum}}
{{> bc-nav}}
{{> cart/info}}
{{#if hasGoods}}
{{> cart-list}}
{{^}}
{{> common/empty-cart}}
{{> cart/empty-cart}}
{{/if}}
{{!-- <button id="add_to_cart1">添加到购物车 980874 number 1</button>
<button id="add_to_cart2">添加到购物车 980870 number 2</button> --}}
</div>
</div>
<script id="edit-color-size-tpl" type="text/html">
... ...
... ... @@ -2,7 +2,7 @@
<div class="shopping-order-page blk-page">
{{# content}}
<div class="center-content">
{{> common/bc-nav}}
{{> bc-nav}}
<div class="address-info order-block">
<p class="title">
... ...
{{> common/cart-list-header}}
{{> common/cart-list-body}}
{{> common/statement}}
\ No newline at end of file
<div id="cart_content">
{{> cart/cart-list-header}}
{{> cart/cart-list-body}}
{{> cart/statement}}
</div>
<script id="cart-content-tpl" type="text/html">
<div class="cart-header">
<div class="titles">
<div class="item">
<label id="toggle_check" class="toggle-chk chk-all \{{#if checkAll}}chk-group\{{/if}}">
<span class="iconfont checkbox not-checked">&#xe601;</span>
<span class="iconfont checkbox checked">&#xe602;</span>
全选
</label>
</div>
<div class="item product">货品</div>
<div class="item price">价格</div>
<div class="item num">数量</div>
<div class="item pro-total-price">总价</div>
<div class="item actions">操作</div>
</div>
</div>
\{{# if preSalePros}}
<div class="cart-pro-list pre-pros">
<div class="title">
<span class="main">预售商品</span>
<span class="note">不同上市期的商品我们将为您先到先发</span>
</div>
<div class="pro-list">
\{{#each preSalePros}}
<div class="pros-group">
\{{# each this}}
<ul>
<li class="chk" data-product_info='{"goods_type": "advance", "buy_number": \{{buy_number}}, "selected": "\{{selected}}", "product_sku": "\{{product_sku}}", "promotion_id": 0}'>
<label class="toggle-chk-item \{{#isEqual selected 'Y'}}chk-group\{{/isEqual}}">
<span class="iconfont checkbox not-checked">&#xe601;</span>
<span class="iconfont checkbox checked">&#xe602;</span>
</label>
<input type="hidden" name="product_ids[]"/>
</li>
<li>
<img src="\{{image goods_images 100 134}}" alt="\{{product_name}}">
</li>
<li class="pro-info">
\{{!-- <div class="brand-name">\{{brand_name}}</div> --}}
<div class="pro-name">\{{product_name}}</div>
<div class="size">
\{{#if size_name}}
<span>尺寸: \{{size_name}}</span>
\{{/if}}
</div>
\{{#expect_arrival_time}}
<div class="published-at">上市期: \{{expect_arrival_time}}</div>
\{{/expect_arrival_time}}
</li>
<li class="price-num">
<span class="price sale-price">¥\{{sales_price}}</span>
<div class="stepper" data-productId=\{{productId}}>
<div class="minus action">
<span class="iconfont">&#xe621;</span>
</div>
<div class="num">
<input type="text" class="input" value=\{{buy_number}} />
</div>
<div class="plus action">
<span class="iconfont">&#xe61f;</span>
</div>
</div>
</li>
<li class="total-price-action">
<span class="price item-total-price">¥\{{multiple sales_price buy_number}}</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="send-to-favorite action" data-product_id=\{{product_id}}>移入收藏夹</div>
</div>
</li>
</ul>
\{{/each}}
</div>
\{{/each}}
</div>
</div>
\{{/ if}}
\{{# if commonPros }}
<div class="cart-pro-list cart-pros">
<div class="title">
<span class="main">普通商品</span>
</div>
<div class="pro-list">
\{{#each commonPros}}
<div class="pros-group">
\{{# each this}}
<ul>
<li class="chk" data-product_info='{"goods_type": "ordinary", "buy_number": \{{buy_number}}, "selected": "\{{selected}}", "product_sku": "\{{product_sku}}", "promotion_id": 0}'>
<label class="toggle-chk-item \{{#isEqual selected 'Y'}}chk-group\{{/isEqual}}">
<span class="iconfont checkbox not-checked">&#xe601;</span>
<span class="iconfont checkbox checked">&#xe602;</span>
</label>
<input type="hidden" name="product_ids[]"/>
</li>
<li>
<img src="\{{image goods_images 100 134}}" alt="\{{product_name}}">
</li>
<li class="pro-info">
\{{!-- <div class="brand-name">\{{brandName}}</div> --}}
<div class="pro-name">\{{product_name}}</div>
<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>
</li>
<li class="price-num">
<span class="price sale-price">¥\{{sales_price}}</span>
<div class="stepper" data-productId=\{{productId}}>
<div class="minus action">
<span class="iconfont">&#xe621;</span>
</div>
<div class="num">
<input type="text" class="input" value=\{{buy_number}} />
</div>
<div class="plus action">
<span class="iconfont">&#xe61f;</span>
</div>
</div>
</li>
<li class="total-price-action">
<span class="price item-total-price">¥\{{multiple sales_price buy_number}}</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="send-to-favorite action" data-product_id=\{{product_id}}>移入收藏夹</div>
</div>
</li>
</ul>
\{{/each}}
</div>
\{{/each}}
</div>
</div>
\{{/ if}}
\{{# if invalidPros}}
<div class="cart-pro-list invalid-pros">
<div class="pro-list">
\{{#each invalidPros}}
<ul>
<li class="chk">
<span class="iconfont warning">&#xe625;</span>
</li>
<li>
<img src="\{{image defaultImages 100 134}}" alt="\{{productName}}">
</li>
<li class="pro-info">
<div class="brand-name">\{{brandName}}</div>
<div class="pro-name">\{{productName}}</div>
<div class="size">尺寸: USB</div>
<div class="published-at">上市期: 2016年8月</div>
</li>
<li class="price-num">
<span class="price sale-price">¥\{{salesPrice}}</span>
<div class="stepper" data-productId=\{{productId}}>
<div class="minus action">
<span class="iconfont">&#xe621;</span>
</div>
<div class="num">
<input type="text" class="input" value=\{{buy_number}} />
</div>
<div class="plus action">
<span class="iconfont">&#xe61f;</span>
</div>
</div>
</li>
<li class="total-price-action">
<span class="price item-total-price">¥1289.00</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="send-to-favorite action" data-product_id=\{{product_id}}>移入收藏夹</div>
</div>
</li>
</ul>
\{{/each}}
</div>
</div>
\{{/ if}}
<div class="cart-statement">
<div class="actions">
<div class="action">
<label id="toggle_check" class="toggle-chk chk-all \{{#if checkAll}}chk-group\{{/if}}">
<span class="iconfont checkbox not-checked">&#xe601;</span>
<span class="iconfont checkbox checked">&#xe602;</span>
<span>全选</span>
</label>
</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>
<div class="total-money">¥<span>\{{totalMoney}}</span></div>
</div>
</div>
<div class="calculate">
<div class="checkout-total pay-total">
<div class="pay-title">应付金额(不含运费):</div>
<div class="total-money">¥<span>\{{totalMoney}}</span></div>
</div>
</div>
<div class="checkout">
<a href="/" class="go-to-checkout">
<span class="btn \{{#unless selectedNum}}disable\{{/unless}}" id="checkout_btn">去结算</span>
</a>
</div>
</div>
</script>
\ No newline at end of file
... ...
... ... @@ -9,31 +9,37 @@
<div class="pros-group">
{{# each this}}
<ul>
<li class="chk" data-productId={{productId}}>
<label class="toggle-chk-item {{#if numIsValid}}chk-group{{/if}}">
<li class="chk" data-product_info='{"goods_type": "advance", "buy_number": {{buy_number}}, "selected": "{{selected}}", "product_sku": "{{product_sku}}", "promotion_id": 0}'>
<label class="toggle-chk-item {{#isEqual selected 'Y'}}chk-group{{/isEqual}}">
<span class="iconfont checkbox not-checked">&#xe601;</span>
<span class="iconfont checkbox checked">&#xe602;</span>
</label>
<input type="hidden" name="productIds[]"/>
<input type="hidden" name="product_ids[]"/>
</li>
<li>
<img src="{{image defaultImages 100 134}}" alt="{{productName}}">
<img src="{{image goods_images 100 134}}" alt="{{product_name}}">
</li>
<li class="pro-info">
<div class="brand-name">{{brandName}}</div>
<div class="pro-name">{{productName}}</div>
<div class="size">尺寸: USB</div>
<div class="published-at">上市期: 2016年8月1日</div>
{{!-- <div class="brand-name">{{brand_name}}</div> --}}
<div class="pro-name">{{product_name}}</div>
<div class="size">
{{#if size_name}}
<span>尺寸: {{size_name}}</span>
{{/if}}
</div>
{{#expect_arrival_time}}
<div class="published-at">上市期: {{expect_arrival_time}}</div>
{{/expect_arrival_time}}
</li>
<li class="price-num">
<span class="price sale-price">¥{{salesPrice}}</span>
{{> common/stepper }}
<span class="price sale-price">¥{{sales_price}}</span>
{{> cart/stepper }}
</li>
<li class="total-price-action">
<span class="price item-total-price">¥1289.00</span>
<span class="price item-total-price">¥{{multiple sales_price buy_number}}</span>
<div class="actions">
<div class="remove-item action" data-productId={{productId}}><span class="iconfont">&#xe614;</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>
<div class="send-to-favorite action" data-productId={{productId}}>移入收藏夹</div>
<div class="remove-item action" data-product_id={{product_id}}><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>
</ul>
... ... @@ -45,7 +51,7 @@
{{/ if}}
{{# if commonPros }}
<div class="cart-pro-list common-pros">
<div class="cart-pro-list cart-pros">
<div class="title">
<span class="main">普通商品</span>
</div>
... ... @@ -54,38 +60,38 @@
<div class="pros-group">
{{# each this}}
<ul>
<li class="chk" data-productId={{productId}}>
<label class="toggle-chk-item {{#if numIsValid}}chk-group{{/if}}">
<li class="chk" data-product_info='{"goods_type": "ordinary", "buy_number": {{buy_number}}, "selected": "{{selected}}", "product_sku": "{{product_sku}}", "promotion_id": 0}'>
<label class="toggle-chk-item {{#isEqual selected 'Y'}}chk-group{{/isEqual}}">
<span class="iconfont checkbox not-checked">&#xe601;</span>
<span class="iconfont checkbox checked">&#xe602;</span>
</label>
<input type="hidden" name="productIds[]"/>
<input type="hidden" name="product_ids[]"/>
</li>
<li>
<img src="{{image defaultImages 100 134}}" alt="{{productName}}">
<img src="{{image goods_images 100 134}}" alt="{{product_name}}">
</li>
<li class="pro-info">
<div class="brand-name">{{brandName}}</div>
<div class="pro-name">{{productName}}</div>
<div class="color-size editable" data-productId={{productId}} id="edit_{{productId}}">
{{#if selectColor}}
<span class="mr20">颜色: {{selectColor}}</span>
{{!-- <div class="brand-name">{{brandName}}</div> --}}
<div class="pro-name">{{product_name}}</div>
<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 selectSize}}
<span>尺寸: {{selectSize}}</span>
{{#if size_name}}
<span>尺寸: {{size_name}}</span>
{{/if}}
<span class="iconfont">&#xe63c;</span>
</div>
</li>
<li class="price-num">
<span class="price sale-price">¥{{salesPrice}}</span>
{{> common/stepper }}
<span class="price sale-price">¥{{sales_price}}</span>
{{> cart/stepper }}
</li>
<li class="total-price-action">
<span class="price item-total-price">¥1289.00</span>
<span class="price item-total-price">¥{{multiple sales_price buy_number}}</span>
<div class="actions">
<div class="remove-item action" data-productId={{productId}}><span class="iconfont">&#xe614;</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>
<div class="send-to-favorite action" data-productId={{productId}}>移入收藏夹</div>
<div class="remove-item action" data-product_id={{product_id}}><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>
</ul>
... ... @@ -115,13 +121,13 @@
</li>
<li class="price-num">
<span class="price sale-price">¥{{salesPrice}}</span>
{{> common/stepper }}
{{> cart/stepper }}
</li>
<li class="total-price-action">
<span class="price item-total-price">¥1289.00</span>
<span class="price item-total-price">¥{{multiple sales_price buy_number}}</span>
<div class="actions">
<div class="remove-item action" data-productId={{productId}}><span class="iconfont">&#xe614;</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>
<div class="send-to-favorite action" data-productId={{productId}}>移入收藏夹</div>
<div class="remove-item action" data-product_id={{product_id}}><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>
</ul>
... ...
<div class="cart-header">
<div class="titles">
<div class="item">
<label id="toggle_check" class="toggle-chk chk-all chk-group">
<label id="toggle_check" class="toggle-chk chk-all {{#if checkAll}}chk-group{{/if}}">
<span class="iconfont checkbox not-checked">&#xe601;</span>
<span class="iconfont checkbox checked">&#xe602;</span>
全选
... ...
<div class="cart-statement">
<div class="actions">
<div class="action">
<label id="toggle_check" class="toggle-chk chk-all chk-group">
<label id="toggle_check" class="toggle-chk chk-all {{#if checkAll}}chk-group{{/if}}">
<span class="iconfont checkbox not-checked">&#xe601;</span>
<span class="iconfont checkbox checked">&#xe602;</span>
<span>全选</span>
... ... @@ -10,21 +10,21 @@
<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>4</span></div>
<div class="selected-num">已选<span>{{selectedNum}}</span></div>
<div class="checkout-total">
<div class="total-title">商品金额:</div>
<div class="total-money">¥<span>58999.00</span></div>
<div class="total-money">¥<span>{{totalMoney}}</span></div>
</div>
</div>
<div class="calculate">
<div class="checkout-total pay-total">
<div class="pay-title">应付金额(不含运费):</div>
<div class="total-money">¥<span>58999.00</span></div>
<div class="total-money">¥<span>{{totalMoney}}</span></div>
</div>
</div>
<div class="checkout">
<a href="/" class="go-to-checkout">
<span class="btn disable" id="checkout_btn">去结算</span>
<span class="btn {{#unless selectedNum}}disable{{/unless}}" id="checkout_btn">去结算</span>
</a>
</div>
</div>
\ No newline at end of file
... ...
... ... @@ -3,7 +3,7 @@
<span class="iconfont">&#xe621;</span>
</div>
<div class="num">
<input type="text" class="input" value={{orderNum}} />
<input type="text" class="input" value={{buy_number}} />
</div>
<div class="plus action">
<span class="iconfont">&#xe61f;</span>
... ...
... ... @@ -105,6 +105,7 @@
"yoho-jquery-nanoscroller": "0.0.1",
"yoho-jquery-placeholder": "^2.3.1",
"yoho-jquery-qrcode": "0.0.3",
"yoho-json2": "^1.0.0",
"yoho-slider": "0.0.2"
}
}
... ...
... ... @@ -12,11 +12,7 @@
API使用:
var address = cascadingAddress({
el: '#address',
url: 'http://localhost:3000/areas/0',
resource: 'areas'
});
var address = cascadingAddress({el: '#address'});
获取选择地址文本:
... ...
var $ = require('yoho-jquery');
var Cart = require('./cart');
var Stepper = require('./stepper');
var Cart = require('./cart/cart');
var Stepper = require('./cart/stepper');
$(function() {
... ... @@ -9,91 +9,61 @@ $(function() {
$('.info-bar').hide();
});
// 全选和单选
$('.toggle-chk, .toggle-chk-item').on('click', function() {
var $this = $(this),
$checkoutBtn = $('#checkout_btn'),
checkAll = $this.hasClass('chk-all'),
checkProId = [];
var data;
if ($this.hasClass('chk-group')) {
// 取消选择
$this.removeClass('chk-group');
$checkoutBtn.addClass('disable');
if (checkAll) {
Cart.unCheckAllPros();
} else {
Cart.resetCheckAllStyle();
$this.next().val('');
}
} else {
if (checkAll) {
data = { productId: 'ALL' };
} else {
checkProId = $this.parent().attr('data-productId');
data = { productId: checkProId};
}
// 检查库存
$.ajax({
type: 'GET',
url: '/shopping/cart/product/check_inventory',
data: data,
dataType: 'json'
}).done(function(res) {
if (res.valid) {
$this.addClass('chk-group');
$checkoutBtn.removeClass('disable');
if (checkAll) {
Cart.checkAllPros(res.invalidProIds);
} else {
$this.next().val(checkProId);
// 判断是否需要全选
Cart.toggleCheckAll();
}
} else {
if (checkAll) {
// 全选商品中存在库存不足
// 如果有有效商品
if ($('.toggle-chk-item').length) {
$this.addClass('chk-group');
Cart.checkAllPros(res.invalidProIds);
}
Cart.toggleNotEnough($this, 'ALL');
} else {
// 单选商品库存不足
Cart.toggleNotEnough($this);
}
}
}).fail(function() {
// 通用处理错误
// TODO
});
$('#cart_content').delegate('.toggle-chk, .toggle-chk-item', 'click', function() {
// 全选和单选
Cart.toggleCheck.call(Cart, this);
}).delegate('.remove-item', 'click', function() {
// 删除商品
Cart.removePro($(this).parents('ul').children().first().attr('data-product_info'));
}).delegate('.send-to-favorite', 'click', function() {
// 移入收藏夹
Cart.sendToFavorite($(this).attr('data-productId'));
}).delegate('.editable', 'click', function() {
// 编辑商品颜色和属性
Cart.editColorOrSize($(this).attr('data-productId'));
}).delegate('#checkout_btn', 'click', function(e) {
e.preventDefault();
if(!$(this).hasClass('disable')) {
window.location.href = "/shopping/order";
}
});
// // 全选和单选
// $('.toggle-chk, .toggle-chk-item').on('click', function() {
// Cart.toggleCheck.call(Cart, this);
// });
// 变动商品数量
Stepper.init();
// 删除商品
$('.remove-item').on('click', function() {
Cart.removePro($(this).attr('data-productId'));
});
// // 删除商品
// $('.remove-item').on('click', function() {
// Cart.removePro($(this).attr('data-productId'));
// });
// 移入收藏夹
$('.send-to-favorite').on('click', function() {
Cart.sendToFavorite($(this).attr('data-productId'));
});
// // 移入收藏夹
// $('.send-to-favorite').on('click', function() {
// Cart.sendToFavorite($(this).attr('data-productId'));
// });
// 编辑商品颜色和属性
$('.editable').on('click', function() {
Cart.editColorOrSize($(this).attr('data-productId'));
});
// // 编辑商品颜色和属性
// $('.editable').on('click', function() {
// Cart.editColorOrSize($(this).attr('data-productId'));
// });
// TODO=>
// $('#add_to_cart1').on('click', function() {
// Cart.addToCart({
// productSku: '870896',
// buyNumber: 1
// });
// });
// $('#add_to_cart2').on('click', function() {
// Cart.addToCart({
// productSku: '972201',
// buyNumber: 2
// });
// });
// TODO=>
});
... ...
... ... @@ -5,11 +5,14 @@
* @module shopping/cart
*/
var Dialog = require('../plugins/dialog');
var Dialog = require('../../plugins/dialog');
var JSON = require('yoho-json2');
var _confirm = Dialog.Confirm;
var _alert = Dialog.Alert;
var Util = require('./util');
var hbs = require('yoho-handlebars');
var common = require('../../common');
var Stepper = require('./stepper');
var Cart = {
/*
... ... @@ -20,12 +23,19 @@ var Cart = {
* @params { Function } callback 购买结果回调
*/
addToCart: function(params, callback) {
// TODO
// common.setCookie('uid', '20000058');
Util.ajax({
url: '/shopping/cart/add',
type: 'POST',
data: params,
success: function(res) {
callback(res);
if (res.code === 200) {
common.setCookie('_SPK', res.data.shopping_key);
if (callback) {
return callback(res);
}
}
},
fail: function() {
// TODO
... ... @@ -63,34 +73,21 @@ var Cart = {
},
/*
* 全选
* @function [checkAllPros]
* @params {Array} invalidIds 失效商品ID
*/
checkAllPros: function(invalidIds) {
var proId,
target;
$('.toggle-chk-item').each(function() {
target = $(this);
proId = target.parent().attr('data-productId');
if (invalidIds.indexOf(proId) === -1) {
target.addClass('chk-group').next().val(proId);
}
});
},
/*
* 取消全选
* @function [unCheckAllPros]
* @function [toggleCheckAllPros]
*/
unCheckAllPros: function() {
var target;
toggleCheckAllPros: function(checked) {
var data = [],
goodInfo;
$('.toggle-chk-item').each(function() {
target = $(this);
target.next().val('');
$('#cart_content').find('li.chk').each(function() {
goodInfo = $.parseJSON($(this).attr('data-product_info'));
goodInfo.selected = checked;
data.push(goodInfo);
});
Cart.resetCheckAllStyle();
Cart.toggleSelectGoods(data);
},
/*
... ... @@ -102,33 +99,125 @@ var Cart = {
},
/*
* 根据服务端JSON,刷新购物车信息
* @function [refreshCart]
*/
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;
} else {
console.error('multiplication needs two number parameters');
}
});
hbs.registerHelper('isEqual', function(v1, v2, options) {
if (v1 === v2) {
return options.fn(this);
}
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();
},
/*
* 选择与取消选择
* @function [toggleSelectGoods]
*/
toggleSelectGoods: function(data) {
$.ajax({
type: 'POST',
url: '/shopping/cart/toggleSelectGoods',
data: {skuList: JSON.stringify(data)},
dataType: 'json'
}).done(function(res) {
if (res.code === 200) {
Cart.refreshCart(res);
} else {
_alert(res.message);
}
}).fail(function() {
});
},
/*
* 单选每一个商品判断是否需要全选
* @function [toggleCheckAll]
*/
toggleCheckAll: function() {
toggleCheck: function(target) {
var $this = $(target),
$checkoutBtn = $('#checkout_btn'),
checkAll = $this.hasClass('chk-all');
var goodInfo;
var data = [];
if ($this.hasClass('chk-group')) {
// 取消选择
$this.removeClass('chk-group');
$checkoutBtn.addClass('disable');
if (checkAll) {
Cart.toggleCheckAllPros('N');
} else {
Cart.resetCheckAllStyle();
goodInfo = $.parseJSON($this.parent().attr('data-product_info'));
goodInfo.selected = 'N';
data.push(goodInfo);
Cart.toggleSelectGoods(data);
}
} else {
// 选择
if (checkAll) {
Cart.toggleCheckAllPros('Y');
} else {
goodInfo = $.parseJSON($this.parent().attr('data-product_info'));
goodInfo.selected = 'Y';
data.push(goodInfo);
Cart.toggleSelectGoods(data);
}
}
},
/*
* 删除商品
* @function [removePro]
* @params { String } productId 商品ID
* @params { Array } products 商品列表
*/
removePro: function(productId) {
removePro: function(products) {
var dialog = new _confirm({
content: '您确定要从购物车中删除该商品吗?',
cb: function() {
console.log('confirm:', productId);
Util.ajax({
url: '/shopping/cart/product/' + productId,
url: '/shopping/cart/product/remove',
data: {skuList: JSON.stringify(products)},
type: 'DELETE',
success: function(res) {
if (res.code === '0') {
if (res.code === 200) {
dialog.close();
Cart.refreshCart(res);
} else {
_alert(res.message);
}
},
fail: function() {
// TODO
//TODO
}
});
}
... ...
... ... @@ -4,7 +4,7 @@
* @date: 2016/07/11
* @module shopping/util
*/
var dialog = require('../plugins/dialog');
var dialog = require('../../plugins/dialog');
var _alert = dialog.Alert;
var Util = {
... ...