Authored by 陈轩

save

... ... @@ -2,47 +2,140 @@
* 秒杀结算
*/
'use strict';
const co = require('bluebird').coroutine;
const seckillModel = require('../models/seckill');
const buyNowModel = require('../models/buynow');
exports.ensure = (req, res, next) => {
/* ----- mock ---------- */
req.body.sku = 51047967;
req.body.skn = 1;
/* ----- end mock ------ */
const BAD_REQUEST = '非法请求';
const sku = req.body.sku;
const skn = req.body.skn;
exports.ensure = (req, res, next) => {
const sku = Number.parseInt(req.query.sku, 10);
const skn = Number.parseInt(req.query.skn, 10);
const uid = req.user.uid;
// require skn, sku;
if (!(sku && skn)) {
return next('error');
}
// 判断 sku 是否与skn 对应
let skillData = seckillModel.skillData(skn);
co(function*() {
let paymentOption = {
product_sku: sku,
sku_type: 'S',
uid
};
let skillData = yield seckillModel.skillData(skn); // 根据skn查活动信息
skillData = skillData.data;
if (!(
skillData &&
skillData.status &&
skillData.secKillSku.some(obj => obj.productSku === sku) // skn has sku;
)) {
return Promise.reject('活动不存在');
}
paymentOption.activity_id = skillData.activityId;
// 获取结算 数据
let paymentInfo = yield buyNowModel.payment(paymentOption);
if (paymentInfo.code !== 200) {
return Promise.reject('结算请求失败');
}
// 渲染
let view = Object.assign({
seckill: skillData,
orderEnsure: true,
sku,
}, paymentInfo.data);
// console.log(view);
res.locals.title = '确认订单';
res.render('order-ensure', view);
})().catch(next);
};
exports.compute = (req, res, next) => {
const uid = req.user.uid,
sku = req.body.sku,
activityId = req.body.activityId;
if (!req.xhr) {
return next(400);
}
// 获取 sku商品信息
let paymentInfo = buyNowModel.payment({
product_sku: skn,
sku_type: 'S'
});
// 必填字段
if ([uid, sku, activityId].some(field => !field)) {
return res.status(400).json({
code: 400,
msg: BAD_REQUEST
});
}
const options = {
sku_type: 'S', // 秒杀
buy_number: 1,
yoho_coin_mode: 1,
payment_type: 1,
uid: req.user.uid,
product_sku: sku,
delivery_way: req.body.deliveryId || 1,
use_yoho_coin: req.body.use_yoho_coin || 0,
activity_id: activityId
};
Promise.all([skillData, paymentInfo])
return buyNowModel.compute(options)
.then(result => {
let r1 = result[0];
let r2 = result[1];
res.json(result.data);
})
.catch(next);
};
exports.submit = (req, res, next) => {
const uid = req.user.uid,
sku = req.body.sku,
activityId = req.body.activityId,
addressId = Number.parseInt(req.body.addressId, 10),
deliveryTime = Number.parseInt(req.body.deliveryTime, 10),
deliveryWay = Number.parseInt(req.body.deliveryWay, 10),
paymentId = Number.parseInt(req.body.paymentId, 10),
paymentType = Number.parseInt(req.body.paymentType, 10);
if (r2.code !== 200) {
return Promise.reject('error');
}
if (!req.xhr) {
return next(404);
}
if ([uid, sku, activityId, addressId, deliveryTime,
deliveryWay, paymentId, paymentType
].some(field => !field)) {
return res.status(400).json({
code: 400,
msg: BAD_REQUEST
});
}
const options = {
sku_type: 'S',
buy_number: 1,
invoices_title: req.body.invoicesTitle || '',
invoices_type_id: req.body.invoicesTypeId || '',
use_yoho_coin: Number.parseFloat(req.body.useYohoCoin) || 0,
remark: req.body.remark || '',
let view = Object.assign({orderEnsure: true}, r2.data);
address_id: addressId,
delivery_time: deliveryTime,
delivery_way: deliveryWay,
payment_id: paymentId,
payment_type: paymentType
};
res.locals.title = '确认订单';
res.render('order-ensure', view);
return buyNowModel.submit(options)
.then(result => {
res.clearCookie('order-info');
res.json(result);
})
.catch(next);
};
... ...
/* eslint-disable */
module.exports = {
exports.payment = {
"alg": "SALT_MD5",
"code": 200,
"data": {
... ... @@ -210,4 +210,120 @@ module.exports = {
},
"md5": "3c89d2af5917a0f12070df8281b39fe8",
"message": "payment data."
}
\ No newline at end of file
};
exports.compute = {
"alg": "SALT_MD5",
"code": 200,
"data": {
"coupon_amount": 0,
"delivery_way": [{
"default": "Y",
"delivery_way_cost": 0,
"delivery_way_id": 1,
"delivery_way_name": "普通快递",
"is_delivery": "Y",
"is_support": "Y"
}, {
"default": "N",
"delivery_way_cost": 5,
"delivery_way_id": 2,
"delivery_way_name": "顺丰速运",
"is_delivery": "Y",
"is_support": "Y"
}],
"discount_amount": 0,
"fast_shopping_cost": 5,
"gain_yoho_coin": 0,
"goods_count": 4,
"last_order_amount": 340,
"order_amount": 335,
"payment_way": [{
"default": "Y",
"is_support": "Y",
"is_support_message": "",
"payment_id": 15,
"payment_name": "支付宝",
"payment_type": 1,
"payment_type_name": "在线支付(推荐)"
}, {
"default": "N",
"is_support": "Y",
"is_support_message": "送货上门后再付款",
"payment_id": 0,
"payment_name": "货到付款",
"payment_type": 2,
"payment_type_name": "货到付款"
}],
"promotion_formula": "总计¥340.00=商品金额¥335.00+运费¥5.00",
"promotion_formula_list": [{
"promotion": "商品金额",
"promotion_amount": "¥335.00"
}, {
"promotion": "运费",
"promotion_amount": "+¥5.00"
}],
"selected_goods_count": 2,
"shipping_cost": 0,
"str_discount_amount": "¥0.00",
"str_order_amount": "¥335.00",
"use_red_envelopes": 0,
"use_yoho_coin": 0,
"instalment": {//不支持或者用户没有选择分期时,不返回
"is_support": "Y",//是否支持
"plan_amount_per": 326.66,//每期应还金额
"plan_amount_per_name": "分3期(¥326.66*3)",
"plan_int_amount_per_name": "免手续费",
"term": 3 //期数
},
"is_multi_package":"Y",
"package_list":[{
"supplier_id":"0",
"goods_list":[{
"buy_number": "1",
"goods_images": "http://img11.static.yhbimg.com/goodsimg/2015/12/23/07/0115f6f0e2ca345d2b413396202f97c8b5.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80",
"goods_type": "ordinary",
"product_id": 329795,
"product_name": "Blackbird 黑鸟锥形香-Ai香型",
"product_skc": "320280",
"product_skn": "51184595",
"product_sku": "1003938"
}],
"shopping_cost":3,
"shopping_cut_cost": 7,
"shopping_orig_cost":10
},
{
"supplier_id":"23",
"goods_list":[{
"buy_number": "1",
"goods_images": "http://img11.static.yhbimg.com/goodsimg/2015/12/23/07/0115f6f0e2ca345d2b413396202f97c8b5.jpg?imageMogr2/thumbnail/{width}x{height}/extent/{width}x{height}/background/d2hpdGU=/position/center/quality/80",
"goods_type": "gift",
"product_id": 329795,
"product_name": "Blackbird 黑鸟锥形香-Ai香型",
"product_skc": "320280",
"product_skn": "51184595",
"product_sku": "1003938"
}],
"shopping_cost":3,
"shopping_cut_cost": 7,
"shopping_orig_cost":10
}]
},
"md5": "c743135bb9ee4afe3c522c59e64604ea",
"message": "compute list."
};
exports.submit = {
"alg": "SALT_MD5",
"code": 200,
"data": {
"create_time": "2016-07-14 15:57:48",//订单创建时间
"order_amount": 1965,//订单金额
"order_code": 1613291832,//订单号
"pay_expire": "2016-07-14 17:57:48",//支付失效时间
"payment_status": 0//0 未支付,1已支付,只有0元订单才为1
},
"md5": "62723a6f81151e880b04a8480df4d2f9",
"message": "submit order ."
};
\ No newline at end of file
... ...
/* eslint-disable */
exports.seckillData = {
'alg': 'SALT_MD5',
'code': 200,
'data': {
'activityId': 4,
'endTime': 1478758971,
'formatSecKillPrice': '¥50.00',
'id': 4,
'orderBy': 0,
'productSkn': 512581470,
'secKillPrice': 50,
'secKillSku': [
{
'activityId': 4,
'id': 1,
'productSkn': 512581470,
'productSku': 1384138,
'storageNum': 10
},
{
'activityId': 4,
'id': 2,
'productSkn': 512581470,
'productSku': 1384140,
'storageNum': 5
}
],
'secKillStatus': 0,
'startTime': 1474192655,
'status': 1, // ---0:作废 1:秒杀前 2:秒杀中 3:秒杀结束
'storageSum': 0
},
'md5': 'c3d6dfc778e4dc5e078191f7873980de',
'message': 'query secKillProduct info'
};
... ...
/**
* doc: http://git.yoho.cn/yoho-documents/api-interfaces/blob/master/%E8%AE%A2%E5%8D%95/%E7%AB%8B%E5%8D%B3%E8%B4%AD%E4%B9%B0.md
*/
'use strict';
const API = global.yoho.API;
... ... @@ -20,11 +23,47 @@ exports.payment = options => {
// mock
.catch()
.then(() => {
let mockData = require('./_buynow-mock');
let mockData = require('./_buynow-mock').payment;
return {
code: 200,
data: paymentProcess.tranformPayment(mockData.data)
data: paymentProcess.tranformPayment(mockData.data)
};
});
};
exports.compute = options => {
let url = '';
let queryData = Object.assign({
method: 'app.Buynow.compute',
}, options);
return API.post(url, queryData)
// mock
.catch()
.then(() => {
let mockData = require('./_buynow-mock').compute;
return mockData;
});
};
exports.submit = options => {
let url = '';
let queryData = Object.assign({
method: 'app.Buynow.submit'
}, options);
return API.post(url, queryData)
// mock
.catch()
.then(()=> {
let mockData = require('./_buynow-mock').submit;
return mockData;
});
};
... ...
... ... @@ -12,5 +12,14 @@ exports.skillData = product_skn => {
product_skn
};
return API.post('', queryData);
return API.post('', queryData)
// mock
.catch()
.then(()=> {
let mock = require('./_seckill-mock').seckillData;
return mock;
});
};
... ...
... ... @@ -14,5 +14,7 @@ const seckill = require(cRoot + '/seckill');
// Your controller here
router.get('/seckill/', seckill.ensure);
router.post('/seckill/compute', seckill.compute);
router.post('/seckill/submit', seckill.submit);
module.exports = router;
... ...
... ... @@ -188,5 +188,10 @@
您需要支付:<span>¥{{price}}</span>
<a href="javascript:;">提交订单</a>
</div>
<input type="hidden" id="product-sku" name="product-sku" value="{{sku}}">
{{#with seckill}}
<input type="hidden" id="activity-id" name="activity-id" value="{{activityId}}">
{{/with}}
{{/ orderEnsure}}
</div>
... ...
... ... @@ -113,7 +113,7 @@ const index = (req, res, next) => {
return seckillModel.queryProductList(focusActivity.activityId).then((resultProducts) => {
result.products = _productAddFlag(resultProducts.data, req.yoho.isApp);
console.log(result);
// console.log(result);
res.render('seckill', Object.assign({
pageHeader: headerData,
pageFooter: true,
... ... @@ -148,7 +148,10 @@ const getProductList = (req, res, next) => {
});
};
const remind = (req, res, next) => {};
module.exports = {
index,
getProductList
getProductList,
remind
};
... ...
... ... @@ -22,10 +22,10 @@ const queryActivity = () => {
})
// TODO: REMOVE follow
.catch()
.then(() => {
return _.cloneDeep(mock.activities);
});
// .catch()
// .then(() => {
// return _.cloneDeep(mock.activities);
// });
};
/**
... ... @@ -42,24 +42,24 @@ const queryProductList = (activityId) => {
})
// TODO: remove follow
.catch()
.then(() => {
let result;
// .catch()
// .then(() => {
// let result;
switch (activityId) { // eslint-disable-line
case 1:
result = mock.inActivityData;
break;
case 2:
result = mock.inActivityData;
break;
case 3:
result = mock.waitData;
break;
}
// switch (activityId) { // eslint-disable-line
// case 1:
// result = mock.inActivityData;
// break;
// case 2:
// result = mock.inActivityData;
// break;
// case 3:
// result = mock.waitData;
// break;
// }
return _.cloneDeep(result);
});
// return _.cloneDeep(result);
// });
};
module.exports = {
... ...
... ... @@ -62,6 +62,7 @@ router.get('/recommend-for-you/userCenter', recommendForYou.userCenter);
router.get('/recommend-for-you/cart', recommendForYou.cart);
router.get('/seckill', seckill.index); // 秒杀列表页
router.post('/seckill/remind', seckill.remind); // only app; 秒杀提醒
router.get(/\/seckill\/detail\/pro_([\d]+)_([\d]+)\/(.*)/, detail.getUser, detail.index); // 秒杀详情页
router.get(/\/seckill\/detail\/show_([\d]+)/, detail.getUser, detail.indexSkn); // 秒杀详情页 SKN 进入
router.get('/seckill/get-product-list', seckill.getProductList); // 秒杀列表根据活动id获取商品列表
... ...
<a href="#" class="item" data-activity="{{activityId}}" data-skn="{{productSkn}}">
<div class="item" data-activity="{{activityId}}" data-skn="{{productSkn}}">
<div class="item-img">
<img src="{{image defaultImages 235 314}}" alt="">
</div>
... ... @@ -24,14 +24,14 @@
<div class="item-button">
{{#if over}}
<span class="old-price">还可以原价购买</span>
<button class="btn btn-over">已抢光</button>
<a href='/product/show_{{{productSkn}}}{{#if isApp}}?openby:yohobuy={"action":"go.productDetail","params":{"product_skn":"{{productSkn}}"}}{{/if}}' class="btn btn-over">已抢光</a>
{{else if wait}}
<button class="btn btn-remind-off" data-remind data-action="cancel" {{#unless remindFlag}}style="display: none;"{{/unless}}>取消提醒</button>
<button class="btn btn-remind-on" data-remind data-action="add" {{#if remindFlag}}style="display: none;"{{/if}}>提醒我</button>
{{else}}
<button class="btn btn-buy">去抢购</button>
<a href='/product/seckill/detail/show_{{productSkn}}.html?{{#if isApp}}?openby:yohobuy={"action":"go.productDetail","params":{"product_skn":"{{productSkn}}"}}{{/if}}' class="btn btn-buy">去抢购</a>
{{/if}}
</div>
</div>
</div>
</a>
\ No newline at end of file
</div>
\ No newline at end of file
... ...
... ... @@ -17,8 +17,8 @@ module.exports = {
assetUrl: '//localhost:5001',
domains: {
// service: 'http://devservice.yoho.cn:58077/'
api: 'http://dev-service.yohops.com:9999/',
service: 'http://dev-api.yohops.com:9999/',
api: 'http://dev-api.yohops.com:9999/',
service: 'http://dev-service.yohops.com:9999/',
liveApi: 'http://testapi.live.yohops.com:9999/'
},
subDomains: {
... ...
... ... @@ -14,6 +14,7 @@ module.exports = () => {
Object.assign(res.locals, {
devHost: devHost
});
req.user.uid = '8039759';
next();
};
... ...
'use strict';
require('./order-ensure');
require('./seckill/order-ensure');
... ...
/* eslint-disable vars-on-top */
/**
* 订单确认
* @author: xuqi<qi.xu@yoho.cn>
* @date: 2015/11/12
*/
require('common.js');
var lazyLoad = require('yoho-jquery-lazyload'),
tip = require('plugin/tip'),
loading = require('plugin/loading'),
order = require('./order-info');
order = require('../order-info');
var $invoice = $('.invoice'),
$couponUse = $('.coupon-use.used'),
... ... @@ -22,9 +25,8 @@ var $invoice = $('.invoice'),
isSubmiting,
dispatchInfo,
total,
isTickets = $('#ticketsPage').val(),
productSku = $('#productSku').val(),
buyNumber = $('#buyNumber').val();
activityId = $('#activity-id').val(),
productSku = $('#product-sku').val();
var orderCont = window.cookie('order-info') && JSON.parse(window.cookie('order-info'));
var invoiceCont = {
... ... @@ -41,7 +43,6 @@ var invoiceCont = {
2: '电子'
};
require('../common');
lazyLoad();
... ... @@ -180,25 +181,15 @@ function orderCompute() {
cartType: orderInfo('cartType') || 'ordinary',
deliveryId: orderInfo('deliveryId'),
paymentTypeId: orderInfo('paymentTypeId'),
couponCode: orderInfo('couponCode'),
yohoCoin: yohoCoin,
skuList: isLimitGood() ? orderInfo('skuList') : undefined
};
// 门票
if (isTickets) {
data = {
type: 'tickets',
productSku: productSku,
buyNumber: buyNumber,
yohoCoin: yohoCoin
sku: productSku,
activityId: activityId
};
}
loading.showLoadingMask();
$.ajax({
method: 'POST',
url: '/cart/index/orderCompute',
url: '/cart/seckill/compute',
data: data
}).then(function(res) {
if ($.type(res) !== 'object') {
... ... @@ -264,22 +255,21 @@ function submitOrder() {
isSubmiting = true;
$.ajax({
method: 'POST',
url: '/cart/index/orderSub',
url: '/cart/seckill/submit',
data: {
activityId: activityId,
sku: productSku,
addressId: orderInfo('addressId'),
cartType: orderInfo('cartType') || 'ordinary',
deliveryId: orderInfo('deliveryId'),
deliveryTimeId: orderInfo('deliveryTimeId'),
invoiceText: orderInfo('invoice') ? invoiceText : null,
invoiceType: orderInfo('invoice') ? ($invoice.find('.invoice-type').val() ||
deliveryWay: orderInfo('deliveryId'),
deliveryTime: orderInfo('deliveryTimeId'),
invoiceTitle: orderInfo('invoice') ? invoiceText : null,
invoiceTypeId: orderInfo('invoice') ? ($invoice.find('.invoice-type').val() ||
orderInfo('invoiceType')) : null,
msg: msg,
paymentTypeId: orderInfo('paymentTypeId'),
remark: msg,
paymentId: orderInfo('paymentTypeId'),
paymentType: orderInfo('paymentType'), // 支付方式
couponCode: orderInfo('couponCode'),
yohoCoin: orderInfo('yohoCoin'),
skuList: isLimitGood() ? orderInfo('skuList') : undefined
useYohoCoin: orderInfo('yohoCoin')
}
}).then(function(res) {
var url;
... ... @@ -314,6 +304,7 @@ if (!orderInfo('addressId')) {
orderInfo('addressId', $addressWrap.data('id'));
}
// 配送方式 发生改变
$('.delivery-id').on('touchend', 'li', function() {
orderInfo('deliveryId', $(this).data('id'));
orderCompute();
... ... @@ -410,10 +401,6 @@ $subBlock.on('touchstart', 'li', function() {
$('.bill a').on('touchstart', function() {
if (isTickets) {
ticketsConfirm();
return;
}
orderInfo('paymentTypeId', $('.delivery-id .icon-cb-radio').data('id'));
orderInfo('paymentType', $('.payment-type .icon-cb-radio').data('id'));
... ... @@ -433,40 +420,6 @@ if (orderInfo('address') && orderInfo('address').is_support === 'N') {
orderCompute();
}
// 电子票下单
function ticketsConfirm() {
if (!$ticketsMobile.val()) {
tip.show('手机号必填');
return;
}
var data = {
productSku: productSku,
buyNumber: buyNumber,
mobile: $ticketsMobile.val(),
useYohoCoin: orderInfo('yohoCoin')
};
$.ajax({
url: '/cart/index/submitTicket',
type: 'POST',
dataType: 'json',
data: data,
success: function(ticket) {
// 下单成功调整支付页面
if (ticket.code === 200) {
window.location.href = '/home/orders/pay?order_code=' + ticket.data.order_code;
} else {
tip.show(ticket.message);
}
},
error: function() {
tip.show('网络异常~');
}
});
}
// 校验手机号
$ticketsMobile.blur(function function_name(e) {
var reg = /^[0123456789]{1,30}$/;
... ...
... ... @@ -260,6 +260,7 @@ seckillObj = {
},
/*
only app
添加/删除提醒
*/
toggleRemind: function(event) {
... ... @@ -268,7 +269,8 @@ seckillObj = {
var actionName,
action,
params;
params,
on_off;
var okTip,
failTip,
... ... @@ -285,6 +287,7 @@ seckillObj = {
actionName = $remindBtn.data('data-action');
// default
on_off = true;
action = 'go.addSecKil';
params = {
skn: $product.data('skn'),
... ... @@ -298,6 +301,7 @@ seckillObj = {
if (actionName === 'cancel') {
on_off = false;
action = 'go.delSecKill';
okTip = '取消成功';
failTip = '取消失败';
... ... @@ -307,6 +311,7 @@ seckillObj = {
$.post('/product/seckill/remind?app_version=1', {
type: actionName,
data: {
on_off: on_off,
activity_id: $product.data('activity'),
product_skn: $product.data('skn'),
uid: yoho.isLogin(),
... ...
... ... @@ -199,7 +199,7 @@
background:#fff;
left: 0;
bottom: 0;
width: 96%;
right: 0;
height: 100px;
overflow: hidden;
line-height: 100px;
... ...
... ... @@ -66,8 +66,11 @@
width: 200px;
text-align: right;
.btn {
display: inline-block;
width: 155px;
height: 60px;
line-height: 60px;
text-align: center;
color: #fff;
background-color: #d0021b;
border-radius: 3PX;
... ...
... ... @@ -49,7 +49,8 @@ module.exports = {
common: path.join(__dirname, 'js/common'),
plugin: path.join(__dirname, 'js/plugin'),
js: path.join(__dirname, 'js/'),
template: path.join(__dirname, './template')
template: path.join(__dirname, './template'),
'common.js': path.join(__dirname, 'js/common.js')
}
},
plugins: [
... ...
... ... @@ -152,11 +152,13 @@ function tranformPayment(data, orderInfo) {
// 拆单逻辑 not here
// you can add to here , if you need
// 这块数据处理, 要改写,请参照Cart.php @cartPay
// -----------------------
result.cartPayData = cartData.promotion_formula_list;
result.num = cartData.goods_count;
result.goodsPrice = cartData.str_order_amount;
result.price = cartData.last_order_amount;
if (cartData.gain_yoho_coin > 0) {
result.yohoCoinNum = cartData.gain_yoho_coin;
... ...