Authored by xuqi

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

... ... @@ -12,13 +12,13 @@ const orderModel = require('../models/order');
/**
* 我的订单
*/
const index = (req, res) => {
const index = (req, res, next) => {
const type = req.query.type;
const page = req.query.page;
const uid = global.yoho.uid || '7394907';
orderModel.getOrderData(uid, type, page).then(result => {
res.render('index', {
res.display('index', {
page: 'order',
isMe: true,
content: Object.assign({
... ... @@ -27,15 +27,15 @@ const index = (req, res) => {
banner: 'http://placehold.it/{width}x{height}'
}, result)
});
});
}).catch(next);
};
const detail = (req, res) => {
const detail = (req, res, next) => {
const code = req.query.code;
const uid = global.yoho.uid || '7394907';
orderModel.getOrderDetail(uid, code).then(result => {
res.render('index', {
res.display('index', {
isMe: true,
page: 'order-detail',
content: Object.assign({
... ... @@ -44,26 +44,28 @@ const detail = (req, res) => {
banner: 'http://placehold.it/{width}x{height}'
}, result)
});
});
}).catch(next);
};
const getOrderList = (req, res) => {
const getOrderList = (req, res, next) => {
const type = req.query.type;
const page = req.query.page;
const uid = global.yoho.uid || '7394907';
orderModel.getOrderData(uid, type, page).then(result => {
res.render('order-table', {
res.display('order-table', {
layout: false,
page: 'order',
isMe: true,
orderList: result.order.orderList,
paginationOpts: result.order.paginationOpts
});
paginationOpts: result.order.paginationOpts,
emptyMsg: result.order.emptyMsg,
showEmptyEn: result.order.showEmptyEn
});
}).catch(next);
};
const getOrderTotal = (req, res) => {
const getOrderTotal = (req, res, next) => {
const type = req.query.type;
const uid = global.yoho.uid || '7394907';
... ... @@ -74,40 +76,40 @@ const getOrderTotal = (req, res) => {
total: result.order.total,
type: result.order.type
});
});
}).catch(next);
};
const cancelOrder = (req, res) => {
const cancelOrder = (req, res, next) => {
const uid = global.yoho.uid || '7394907';
const code = req.query.orderCode;
const data = req.query;
orderModel.cancelOrder(uid, code).then(result => {
orderModel.cancelOrder(uid, data).then(result => {
res.json(result);
});
}).catch(next);
};
const deleteOrder = (req, res) => {
const deleteOrder = (req, res, next) => {
const uid = global.yoho.uid || '7394907';
const code = req.query.orderCode;
orderModel.deleteOrder(uid, code).then(result => {
res.json(result);
});
}).catch(next);
};
const getExpressInfo = (req, res) => {
const getExpressInfo = (req, res, next) => {
const uid = global.yoho.uid || '7394907';
const code = req.query.orderCode;
orderModel.getExpressInfo(uid, code).then(result => {
res.json(result);
});
}).catch(next);
};
const getCancelOrderReason = (req, res) => {
const getCancelOrderReason = (req, res, next) => {
orderModel.getCancelOrderReason().then(result => {
res.json(result);
});
}).catch(next);
};
const editOrder = (req, res) => {
... ... @@ -121,6 +123,16 @@ const editOrder = (req, res) => {
});
};
const reAddCart = (req, res) => {
const uid = global.yoho.uid || '7394907';
const code = req.query.orderCode;
orderModel.reAddCart(uid, code).then(result => {
res.json(result);
});
};
module.exports = {
index: index,
detail: detail,
... ... @@ -130,5 +142,6 @@ module.exports = {
deleteOrder: deleteOrder,
editOrder: editOrder,
getExpressInfo: getExpressInfo,
getCancelOrderReason: getCancelOrderReason
getCancelOrderReason: getCancelOrderReason,
reAddCart: reAddCart
};
... ...
... ... @@ -72,6 +72,7 @@ const invoiceText = {
2: '电子'
};
// 订单状态
const statusMap = {
0: {
... ... @@ -100,8 +101,8 @@ const statusMap = {
},
4: {
value: 2,
valueStr: '已发货',
step: 2,
valueStr: '待收货',
step: 3,
showGetBtn: true,
btns: btnMap.complete
},
... ... @@ -282,11 +283,13 @@ const deleteOrder = (uid, code) => {
});
};
const cancelOrder = (uid, code) => {
const cancelOrder = (uid, data) => {
return api.get('', {
method: 'app.SpaceOrders.close',
uid: uid,
order_code: code
order_code: data.orderCode,
reason_id: data.reasonId,
reason: data.reason
}, {
cache: true
});
... ... @@ -328,6 +331,19 @@ const getOrderData = (uid, type, page) => {
]
};
const emptyMsg = {
1: {
text: '您暂时还没有订单',
showEmptyEn: true
},
2: {
text: '您暂时还没有待付款的订单'
},
3: {
text: '您暂时还没有待收货的订单'
}
};
type = parseInt(type, 10);
type = type < 4 ? type : 1;
... ... @@ -342,6 +358,11 @@ const getOrderData = (uid, type, page) => {
type: type
};
const empty = {
showEmptyEn: emptyMsg[type].showEmptyEn,
emptyMsg: emptyMsg[type].text
};
navBar.tabs[typeActiveIndexMap[type]].isActive = true;
const order = Object.assign(basicData, {
... ... @@ -357,7 +378,7 @@ const getOrderData = (uid, type, page) => {
} : false;
return {
order: Object.assign(order, paginationOpts)
order: Object.assign(order, paginationOpts, empty)
};
});
};
... ... @@ -375,6 +396,11 @@ const getOrderDetail = (uid, code) => {
detail.createTime = _convertUnixTime(detail.createTime);
if (detail.isCancel === 'N' &&
st === 0) {
detail.showLeftTime = true;
}
// 需要和接口确认如何获取运费,接口文档和线上数据不一致
// if (detail.shippingCost) {
// detail.shippingCost = _removeRmbIcon(detail.shippingCost);
... ... @@ -433,6 +459,16 @@ const editOrder = data => {
});
};
const reAddCart = (uid, code) => {
return api.get('', {
method: 'app.Shopping.readd',
uid: uid,
order_code: code
}, {
cache: true
});
};
module.exports = {
getOrderData: getOrderData,
getOrderDetail: getOrderDetail,
... ... @@ -440,5 +476,6 @@ module.exports = {
getCancelOrderReason: getCancelOrderReason,
deleteOrder: deleteOrder,
editOrder: editOrder,
getExpressInfo: getExpressInfo
getExpressInfo: getExpressInfo,
reAddCart: reAddCart
};
... ...
... ... @@ -9,6 +9,8 @@
const router = require('express').Router(); // eslint-disable-line
const cRoot = './controllers';
// const auth = require(`${global.middleware}/auth`);
// 订单
const order = require(`${cRoot}/order`);
const address = require(`${cRoot}/address`);
... ... @@ -24,6 +26,7 @@ router.get('/cancelOrder', order.cancelOrder);
router.get('/getCancelOrderReason', order.getCancelOrderReason);
router.get('/getExpressInfo', order.getExpressInfo);
router.get('/editOrder', order.editOrder);
router.get('/reAdd', order.reAddCart);
// 个人中心首页/收货地址
router.get('/address', address.index);
... ...
<div class="goods-list info-box">
<h4 class="status-title">商品清单</h4>
{{#isY isMultiPackage}}
<div class="multi-package-row">
温馨提示:您购买的商品<em class="blue">分属不同仓库</em>,需要调拨,将被拆分成多个包裹送达
<span class="iconfont show-package">&#xe643;</span>
<div class="package-list hide">
<div class="package-up-icon"></div>
{{#each packageList}}
<div class="package-item">
<p class="package-title bold">包裹{{math @index '+' 1}}:{{#if @first}}总仓发货{{^}}异地调拨{{/if}}</p>
<ul class="package-goods clearfix">
{{#each goodsList}}
<li class="left">
<img class="lazy package-goods-img" data-original="{{image goodsImages 100 134}}">
</li>
{{/each}}
</ul>
<p class="package-shipping">运费:¥{{shoppingCost}}元(原价{{shoppingOrigCost}}元,优惠{{shoppingCutCost}}元)</p>
</div>
{{/each}}
</div>
</div>
{{/isY}}
<div class="table">
<ul class="header">
<li class="first">商品信息</li>
... ...
... ... @@ -13,6 +13,15 @@
</div>
</div>
{{#if showLeftTime}}
<div class="time">
<span>剩余支付时间:</span>
<span class="iconfont">&#xe606;</span>
<p class="left-time" data-left={{payLefttime}}></p>
<span class="tip">(逾期订单将自动取消)</span>
</div>
{{/if}}
{{#if steps}}
<div class="time-line">
<ul>
... ...
... ... @@ -6,7 +6,7 @@
<li class="content">下单时间:{{createTime}}</li>
<li class="content">订单编号:{{orderCode}}</li>
{{#if showMobile}}
<li class="content">手机订单</li>
<li class="content"><span class="iconfont">&#xe62f;</span>手机订单</li>
{{/if}}
</ul>
<div class="table-body">
... ... @@ -25,7 +25,7 @@
{{#if showPayButton}}
<div class="pay-operation">
{{#if isOnlinePaid}}
<p class="left-time" data-left="{{payLefttime}}"></p>
<span class="iconfont">&#xe606;</span><p class="left-time" data-left="{{payLefttime}}"></p>
<span class="btn red">立即付款</span>
{{/if}}
<p class="subtext cancel">取消订单</p>
... ... @@ -43,7 +43,7 @@
{{/if}}
<div class="buy-operation{{#unless showBuyBtn}} hide{{/unless}}">
<span class="btn black">再次购买</span>
<span class="btn black buy">再次购买</span>
<p class="subtext delete">删除订单</p>
</div>
... ... @@ -57,8 +57,10 @@
{{^}}
<div class="bg"></div>
<div class="msg">
<p class="msg-zh bold">您暂时还没有订单</p>
<p class="msg-zh bold">{{emptyMsg}}</p>
{{#if showEmptyEn}}
<p class="msg-en">You do not have an order for the time being</p>
{{/if}}
<span class="btn">去购物</span>
</div>
{{/if}}
... ...
... ... @@ -37,6 +37,66 @@ const product = (req, res, next) => {
res.json(resData);
};
const brand = (req, res, next) => {
let uid = req.user.uid;
let pid = req.body.brandId;
let type = (req.body.type === 'add');
let resData = {
code: 400,
message: '操作失败'
};
if (uid) {
if (pid) {
fav.toggleFavBrand(pid, uid, type).then(result => {
res.json(result);
}).catch(next);
return;
}
} else {
Object.assign(resData, {
code: 403,
message: '请登录后执行该操作',
data: {
refer: helpers.urlFormat('/signin')
}
});
}
res.json(resData);
};
const shop = (req, res, next) => {
let uid = req.user.uid;
let pid = req.body.shopId;
let type = (req.body.type === 'add');
let resData = {
code: 400,
message: '操作失败'
};
if (uid) {
if (pid) {
fav.toggleFavShop(pid, uid, type).then(result => {
res.json(result);
}).catch(next);
return;
}
} else {
Object.assign(resData, {
code: 403,
message: '请登录后执行该操作',
data: {
refer: helpers.urlFormat('/signin')
}
});
}
res.json(resData);
};
module.exports = {
product // 组件demo页
product,
brand,
shop
};
... ...
... ... @@ -95,7 +95,6 @@ const shop = {
q.page = parseInt(q.page || 1, 10);
ShopData.getShopHeadData(domain, uid).then(result => {
data.banner = result;
if (data.banner.banner) {
... ...
... ... @@ -19,9 +19,9 @@ const getDomainInfo = domain => {
})();
};
const getBrandInfo = bid => {
const getBrandInfo = (bid, uid) => {
return co(function*() {
let brandInfo = yield api.getBrandInfo(bid);
let brandInfo = yield api.getBrandInfo(bid, uid);
if (!brandInfo.data || brandInfo.code !== 200) {
return {};
... ...
... ... @@ -8,21 +8,21 @@
const api = global.yoho.API;
const addFavAsync = (uid, pid) => {
const addFavAsync = (uid, id, type) => {
return api.get('', {
method: 'app.favorite.add',
id: pid,
id: id,
uid: uid,
type: 'product'
type: type
});
};
const cancelFavAsync = (uid, pid) => {
const cancelFavAsync = (uid, id, type) => {
return api.get('', {
method: 'app.favorite.cancel',
fav_id: pid,
fav_id: id,
uid: uid,
type: 'product'
type: type
});
};
... ...
... ... @@ -10,13 +10,31 @@ const FavAPI = require('./favorite-api');
const toggleFavProduct = (productId, uid, isadd) => {
if (isadd) {
return FavAPI.addFavAsync(uid, productId);
return FavAPI.addFavAsync(uid, productId, 'product');
} else {
return FavAPI.cancelFavAsync(uid, productId);
return FavAPI.cancelFavAsync(uid, productId, 'product');
}
};
const toggleFavBrand = (brandId, uid, isadd) => {
if (isadd) {
return FavAPI.addFavAsync(uid, brandId, 'brand');
} else {
return FavAPI.cancelFavAsync(uid, brandId, 'brand');
}
};
const toggleFavShop = (shopId, uid, isadd) => {
if (isadd) {
return FavAPI.addFavAsync(uid, shopId, 'shop');
} else {
return FavAPI.cancelFavAsync(uid, shopId, 'shop');
}
};
module.exports = {
toggleFavProduct
toggleFavProduct,
toggleFavBrand,
toggleFavShop
};
... ...
... ... @@ -122,6 +122,8 @@ const ShopService = {
let brandId = domainInfo.id;
let brandInfo = yield BrandService.getBrandInfo(brandId, uid);
console.log(brandInfo);
info.name = brandInfo.brandName;
info.info = brandInfo.brandIntro;
info.btnName = '品牌介绍';
... ...
... ... @@ -24,6 +24,8 @@ router.post('/item/togglecollect', fav.product); // 商品详情页
router.get('/shop/query/all', shop.indexQuery);
router.get('/shop/:domain/list', shop.list);
router.get('/shop/:domain', shop.index);
router.post('/shop/togglecollect', fav.shop);
router.post('/brand/togglecollect', fav.brand);
router.get('/query', query.index);
... ...
{{# banner}}
<div class="brand-banner">
<div class="brand-banner" data-brand="{{brandId}}" data-shop="{{shopId}}">
<div class="brand-img" style="height:150px; background: url('{{image banner 1150 150}}')"></div>
<p class="opts">
<a id="brand-info">
... ...
... ... @@ -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) {
// 预售商品
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) {
// 普通商品
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
// };
// }
}
return api.get('', params);
});
// 增加
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
... ...
module.exports = {
success: 200,
notModified: 304,
notFound: 404,
badRequest: 400,
internalError: 500
};
... ...
var cancelOrder = require('./order/cancel-order');
var editOrder = require('./order/edit-order');
var countDown = require('./order/countdown');
function reload() {
... ... @@ -35,3 +36,14 @@ $('.order .edit-btn').on('click', function() {
}
}, reload);
});
if ($('.left-time').length) {
countDown.intervalValue = 1000;
countDown.showSec = true;
countDown.start();
}
$('.show-package').on('click', function() {
$(this).next('.package-list').toggleClass('hide');
});
... ...
... ... @@ -11,6 +11,11 @@ var expressTpl = require('../../tpl/me/express.hbs');
var cancelOrder = require('./order/cancel-order');
var reOrder = require('./order/readd-order');
// 订单剩余时间显示及倒计时
var countDown = require('./order/countdown');
// 更新表格
var tableOperation = {
$header: $('.table.column-category'),
... ... @@ -24,60 +29,6 @@ var tableOperation = {
}
};
// 订单剩余时间显示及倒计时
var countDown = {
count: null,
intervalTimer: null,
intervalValue: 60000,
$element: null,
selector: '.left-time',
setTime: function() {
var that = this;
this.$element.each(function(index, item) {
var $item = $(item);
var leftTime = $item.data('left');
$item.text(that.convertLeftTime(leftTime - that.count * 60));
});
this.count += 1;
},
convertLeftTime: function(src) {
var min = parseInt(src / 60, 10) % 60;
var hour = parseInt(src / 3600, 10);
var timeStr = min + '分';
if (src <= 0) {
timeStr = '已失效';
return timeStr;
}
if (hour > 0) {
timeStr = hour + '时' + timeStr;
}
timeStr = '剩余' + timeStr;
return timeStr;
},
getLeftTime: function() {
var that = this;
if (this.$element.length) {
this.setTime();
this.intervalTimer = setInterval(this.setTime.bind(that), that.intervalValue);
}
},
start: function() {
this.count = 0;
this.$element = $(this.selector);
if (this.intervalTimer) {
clearInterval(this.intervalTimer);
}
this.getLeftTime();
}
};
// 订单类型
var typeMap = {
all: 1,
... ... @@ -168,6 +119,14 @@ function getCurrentPage() {
return page;
}
function bindBuyEvent() {
$('.buy-operation .buy').off('click').on('click', function() {
var code = $(this).closest('.order').data('code');
reOrder(code);
});
}
function updateTableContent($el) {
var type = getCurrentTabType();
var page = getCurrentPage();
... ... @@ -177,6 +136,7 @@ function updateTableContent($el) {
$el.find('.pay-operation').remove();
$el.find('.buy-operation').removeClass('hide');
setOrderTotal();
bindBuyEvent();
} else {
type = typeMap[type];
getOrderList(type, page);
... ... @@ -334,11 +294,13 @@ function bindExpressEvent() {
});
}
function bindEvent() {
bindPaginationClick();
bindDeleteEvent();
bindCancelEvent();
bindExpressEvent();
bindBuyEvent();
}
bindEvent();
... ...
... ... @@ -26,10 +26,16 @@ function getTpl(data) {
// 取消订单
function cancelOrder(code, onCancel) {
var $checked = $('.reason .row .checked');
var reason = $checked.next('.reason-text').text();
var reasonId = $checked.parent().data('value');
$.ajax({
url: '/me/cancelOrder',
data: {
orderCode: code
orderCode: code,
reasonId: reasonId,
reason: reason
}
}).done(function() {
var tip = new _dialog({
... ...
// 订单剩余时间显示及倒计时
module.exports = {
count: null,
intervalTimer: null,
intervalValue: 60000,
$element: null,
selector: '.left-time',
addtionalMsg: '',
showSec: false,
setTime: function() {
var that = this;
this.$element.each(function(index, item) {
var $item = $(item);
var leftTime = $item.data('left');
var i = that.intervalValue / 1000;
$item.text(that.convertLeftTime(leftTime - that.count * i));
});
this.count += 1;
},
convertLeftTime: function(src) {
var sec = parseInt(src, 10) % 60;
var min = parseInt(src / 60, 10) % 60;
var hour = parseInt(src / 3600, 10);
var timeStr = min + '分';
if (src <= 0) {
timeStr = '已失效';
return timeStr;
}
if (this.showSec) {
timeStr += sec + '秒';
}
if (hour > 0) {
timeStr = hour + '时' + timeStr;
}
timeStr = '剩余' + timeStr;
if (this.addtionalMsg.length > 0) {
timeStr += this.addtionalMsg;
}
return timeStr;
},
getLeftTime: function() {
var that = this;
if (this.$element.length) {
this.setTime();
this.intervalTimer = setInterval(this.setTime.bind(that), that.intervalValue);
}
},
start: function() {
this.count = 0;
this.$element = $(this.selector);
if (this.intervalTimer) {
clearInterval(this.intervalTimer);
}
this.getLeftTime();
}
};
... ...
var dialog = require('../../plugins/dialog');
var _alert = dialog.Alert;
module.exports = function(code) {
$.ajax({
url: '/me/reAdd',
data: {
orderCode: code
}
}).done(function(result) {
if (result.code === 200) {
location.href = '/shopping/cart';
} else {
new _alert('出错了,请重试!').show();
}
});
};
... ...
require('./list/list-search');
require('./list/favorite');
... ...
/**
* 品牌或店铺收藏
* @author: jiangfeng<jeff.jiang@yoho.cn>
* @date: 16/7/19
*/
function _favBack(data) {
if (data && data.code === 200) {
$('#brand-fav').toggleClass('coled');
}
}
function _favShop(shopId, isAdd) {
$.post('/product/shop/togglecollect', {shopId: shopId, type: isAdd ? '' : 'add'}, function(data) {
_favBack(data);
});
}
function _favBrand(brandId, isAdd) {
$.post('/product/brand/togglecollect', {brandId: brandId, type: isAdd ? '' : 'add'}, function(data) {
_favBack(data);
});
}
$('#brand-fav').click(function() {
var shopId = $(this).parents('.brand-banner').data('shop');
var brandId = $(this).parents('.brand-banner').data('brand');
var isAdd = $(this).hasClass('coled');
if (shopId) {
_favShop(shopId, isAdd);
} else if (brandId) {
_favBrand(brandId, isAdd);
}
});
... ...
... ... @@ -8,7 +8,7 @@ var Dialog = require('../plugins/dialog').Dialog;
var Shop = {
init: function() {
require('./list/list-search');
require('./list/favorite');
$('#brand-info').click(function() {
Shop.brandInfoDialog().show();
... ...
... ... @@ -16,7 +16,7 @@ var tpl = '{{#each products}}' +
var tplFn = Handlebars.compile(tpl);
require('../common/header');
require('./list/favorite');
lazyload();
$(function() {
... ... @@ -100,3 +100,4 @@ $(function() {
});
});
});
... ...
... ... @@ -55,10 +55,12 @@ $(function() {
Cart.editColorOrSize($(this).attr('data-productId'));
}).delegate('#checkout_btn', 'click', function(e) {
e.preventDefault();
Cart.checkStorage(function() {
if (!$(this).hasClass('disable')) {
window.location.href = '/shopping/order';
}
});
});
// // 全选和单选
// $('.toggle-chk, .toggle-chk-item').on('click', function() {
... ...
... ... @@ -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));
... ...
.multi-package-row {
position: relative;
height: 40px;
font-size: 14px;
line-height: 40px;
text-align: center;
background: #f4fbff;
margin-bottom: $space;
border: 1px solid $borderColor;
.show-package {
font-size: 16px;
cursor: pointer;
}
.package-up-icon {
position: absolute;
width: 10px;
height: 7px;
background: url(/shopping/package-up.png);
top: -7px;
left: 282px;
+ .package-item .package-title {
border-top: none;
}
}
.package-list {
position: absolute;
background: #fff;
border: 2px solid #bbb;
width: 586px;
right: 36px;
padding: 0 50px;
}
.package-title,
.package-shipping {
text-align: left;
margin-left: 10px;
}
.package-title {
border-top: 1px solid #eee;
line-height: 55px;
}
.package-shipping {
color: #595959;
margin-top: 20px;
margin-bottom: 30px;
}
.package-goods li {
width: 120px;
}
.package-goods-img {
display: block;
width: 100px;
height: 134px;
margin: 0 auto;
}
}
.order-status {
$basicHeight: 90px;
border-top: 1px solid $borderColor;
border-bottom: 1px solid $borderColor;
position: relative;
.time {
width: 330px;
height: 42px;
margin-top: -$space;
font-size: $smallSize;
font-weight: normal;
.iconfont {
font-size: $smallSize;
margin-right: 5px;
}
.left-time {
display: inline-block;
}
.tip {
float: right;
}
}
.basic {
height: $basicHeight;
... ...
... ... @@ -38,6 +38,10 @@
&.content {
margin-right: 25px;
.iconfont {
font-size: 16px;
}
}
}
}
... ... @@ -161,6 +165,18 @@
margin-bottom: $space;
}
.pay-operation {
.iconfont {
font-size: $normalSize;
}
.left-time {
display: inline-block;
height: $normalSize;
margin-left: 5px;
}
}
.subtext {
font-size: 12px;
cursor: pointer;
... ...
... ... @@ -28,6 +28,14 @@
display: inline-block;
}
.brand-info {
cursor: pointer;
}
.brand-fav {
cursor: pointer;
}
.iconfont {
font-size: 12px;
}
... ...
... ... @@ -20,11 +20,17 @@
border: 1px solid #fff;
padding: 10px;
margin-left: 10px;
cursor: pointer;
.iconfont {
font-size: 14px;
}
}
.brand-fav.coled .iconfont {
color: #000;
}
}
}
... ...
... ... @@ -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;
}
}
... ...
... ... @@ -6,7 +6,7 @@
{{# subReasons}}
<p data-value="{{id}}">
<span class="iconfont raido {{#if checked}}checked{{/if}}">{{#if checked}}&#xe603;{{^}}&#xe604;{{/if}}</span>
{{reason}}
<span class="reason-text">{{reason}}</span>
</p>
{{/ subReasons}}
</div>
... ...