Authored by 陈轩

Merge remote-tracking branch 'origin/feature/seckill' into feature/seckill

... ... @@ -259,3 +259,17 @@ exports.consultsubmit = (req, res, next) => {
return res.json(data);
}).catch(next);
};
exports.getSeckillData = (req, res) => {
detailModel.getSeckillData({
productskn: req.params.productskn
}, req).then(result => {
return res.json(result);
});
};
... ...
... ... @@ -975,6 +975,72 @@ const _getCommonConsult = () => {
});
};
/**
* 获取秒杀列表
*/
const getSeckillData = (productSkn) => {
let params = {
method: 'app.seckill.data',
product_skn: productSkn
};
return api.get('', params, {
code: 200
}).then(result => {
let data = {};
if (result.data) {
data = result.data;
}
data = {
activityId: 4,
startTime: 1465194254,
endTime: 1475294254,
formatSecKillPrice: '¥133.00',
id: 4,
orderBy: 0,
productSkn: 512581470,
secKillPrice: 50,
secKillSku: [
{
activityId: 4,
id: 1,
productSkn: 512581470,
productSku: 1381111,
storageNum: 1
},
{
activityId: 4,
id: 2,
productSkn: 512581470,
productSku: 1382222,
storageNum: 2
},
{
activityId: 4,
id: 2,
productSkn: 512581470,
productSku: 1383333,
storageNum: 3
},
{
activityId: 4,
id: 2,
productSkn: 512581470,
productSku: 1384444,
storageNum: 0
}
],
secKillStatus: 0,
status: 2,
storageSum: 0
};
return data;
});
};
let getProductData = (data) => {
let finalResult;
let params = {
... ... @@ -996,6 +1062,7 @@ let getProductData = (data) => {
}
return _getUserProfile(params.uid).then((user) => {
data.vipLevel = (user.data && user.data.vip_info && user.data.vip_info.cur_level) || '0';
data.isStudent = (user.data && user.data.vip_info && user.data.vip_info.is_student) ? true : false;
params.is_student = data.isStudent ? 1 : 0;
... ... @@ -1015,8 +1082,50 @@ let getProductData = (data) => {
productId: result.productId
}),
_getCommonConsult(),
comment.getConsults(result.productId, 1, 2)
comment.getConsults(result.productId, 1, 2),
getSeckillData(result.productSkn)
]).then((info) => {
// 根据app.product.data接口是否返回isSecKill,判断是否是秒杀
// let isSecKills = result.isSecKill === 'Y' ? true : false;
let isSecKills = true;// TODO
let gList = result.goodsList;
// 统计非秒杀库存数
let commonNum = 0;
gList.forEach(row => {
row.sizeList.forEach(val => {
commonNum = commonNum + val.storageNumber;
});
});
// 统计秒杀库存数
let leftCount = 0;
info[5].secKillSku.forEach(val => {
leftCount = leftCount + val.storageNum;
});
// 如果秒杀库存不为0,将商品库存链接至秒杀库存
let i = 0;
if (isSecKills && info[5] && leftCount) {
gList.forEach(row => {
row.sizeList.forEach(val => {
val.storageNumber = info[5].secKillSku[i].storageNum;
val.productSku = info[5].secKillSku[i].productSku;
i++;
});
});
}
// 秒杀详情页弹出层价格
if (isSecKills && leftCount && info[5]) {
result.formatMarketPrice = info[5].formatSecKillPrice;
}
result.promotionBoList = info[1];
finalResult = _detailDataPkg(result, data.uid, data.vipLevel, data.ua);
finalResult.enterStore = info[0];
... ... @@ -1024,7 +1133,35 @@ let getProductData = (data) => {
Object.assign(finalResult.feedbacks, info[2]);
/* 如果有咨询,显示咨询,否则显示常见问题 */
// 秒杀详情页
if (isSecKills && leftCount && info[5]) {
let end = info[5].status === 3 ? true : false;
if (!end) {
let notStart = info[5].status === 1 ? true : false;
let startIng = info[5].status === 2 ? true : false;
Object.assign(finalResult, {
isSecKill: {
notStart: notStart,
startIng: startIng,
end: end,
productSkn: data.productSkn,
secKillPrice: info[5].formatSecKillPrice,
noneLeft: leftCount === 0 && commonNum === 0 ? true : false
}
});
}
}
/* 如果有咨询,显示咨询,否则显示常见问题 */
if (info[4].total) {
finalResult.feedbacks.consultsNum = parseInt(info[4].total, 10);
... ... @@ -1040,6 +1177,7 @@ let getProductData = (data) => {
consults: _.take(info[3], 2)
});
}
return finalResult;
});
... ... @@ -1049,5 +1187,6 @@ let getProductData = (data) => {
module.exports = {
getProductData,
getUserProfile: _getUserProfile
getUserProfile: _getUserProfile,
getSeckillData
};
... ...
... ... @@ -39,6 +39,7 @@ router.get('/detail/consults', detail.consults); // 商品咨询页
router.get('/detail/consultform', auth, detail.consultform); // 商品咨询表单页
router.get('/detail/comments', detail.comments); // 商品评价
router.post('/detail/consultsubmit', auth, detail.consultsubmit); // 商品咨询提交接口
router.get('/detail/seckillData/:productskn', detail.getSeckillData); // 秒杀数据接口
router.post('/detail/consultupvote', detail.consultUpvoteOrUseful); // 商品咨询提交接口
router.post('/detail/consultuseful', detail.consultUpvoteOrUseful); // 商品咨询提交接口
... ... @@ -61,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.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获取商品列表
module.exports = router;
... ...
... ... @@ -38,7 +38,11 @@
<div class="price-date">
{{# goodsPrice}}
<div class="goods-price">
{{#if ../isSecKill}}
<h1 class="current-price">{{../isSecKill/secKillPrice}}</h1>
{{else}}
<h1 class="current-price">{{currentPrice}}</h1>
{{/if}}
<h1 class="previous-price">{{previousPrice}}</h1>
</div>
{{/ goodsPrice}}
... ... @@ -63,6 +67,24 @@
<h1 >{{periodOfMarket}}</h1>
</div>
{{/if}}
{{#isSecKill}}
{{#if startIng}}
<div class="seckill-time seckill-time-border">
<span>距结束 </span>
<span class="end-time">
<i class="tick hour">00</i>:
<i class="tick minute">00</i>:
<i class="tick second">00</i>
</span>
</div>
{{/if}}
{{#if notStart}}
<div class="seckill-time notStart">
<span class="seckill-time-pic">秒杀预告</span>
<span class="seckill-time-c">月日</span>
</div>
{{/if}}
{{/isSecKill}}
</div>
{{#if studentPrice}}
... ... @@ -158,40 +180,61 @@
<div id="productDesc"> </div>
{{> detail/recommend-for-you}}
{{> cart/chose-panel}}
{{# isSecKill}}
{{# notStart}}
<div class="seckill-count">
<div class="seckill-count-bg"></div>
<div class="seckill-count-num">距秒杀开始:
<i class="tick hour">00</i>
<i class="tick minute">00</i>
<i class="tick second">00</i>
</div>
</div>
{{/notStart}}
{{/isSecKill}}
{{#cartInfo}}
<div class="cart-bar">
<a href="{{cartUrl}}" class="num-incart iconfont"><span class="num-tag hide"></span>&#xe62c;</a>
{{#if ../isSecKill/noneLeft}}
<a href="javascript:;" class="sold-out">已售罄</a>
{{else if ../isSecKill/startIng}}
<a href="javascript:;" id="addtoCart" class="addto-cart">立即购买</a>
{{else if ../isSecKill/notStart}}
<a href="javascript:;" class="sold-out">即将开抢</a>
{{else}}
{{#if addToCartUrl}}
<a id="addtoCart" href="javascript:;" class="addto-cart">{{#if ../tickets}}立即购买{{else}}加入购物车{{/if}}</a>
{{/if}}
{{#if addToCartUrl}}
<a id="addtoCart" href="javascript:;" class="addto-cart">{{#if ../tickets}}立即购买{{else}}加入购物车{{/if}}</a>
{{/if}}
{{#if soldOut}}
<a href="javascript:;" class="sold-out">已售罄</a>
{{/if}}
{{#if soldOut}}
<a href="javascript:;" class="sold-out">已售罄</a>
{{/if}}
{{#if notForSale}}
<a href="javascript:;" class="sold-out">非卖品</a>
{{/if}}
{{#if notForSale}}
<a href="javascript:;" class="sold-out">非卖品</a>
{{/if}}
{{#if limitNotForSale}}
<a href="javascript:;" class="sold-out limit">即将发售</a>
{{/if}}
{{#if limitNotForSale}}
<a href="javascript:;" class="sold-out limit">即将发售</a>
{{/if}}
{{#if canBuyLimit}}
<a href="javascript:;" id="addtoCart" class="addto-cart">立即购买</a>
{{/if}}
{{#if canBuyLimit}}
<a href="javascript:;" id="addtoCart" class="addto-cart">立即购买</a>
{{/if}}
{{#if noLimitCode}}
<a href="javascript:;" class="sold-out limit">立即购买</a>
{{/if}}
{{#if noLimitCode}}
<a href="javascript:;" class="sold-out limit">立即购买</a>
{{/if}}
<input type="hidden" id="limitCodeUrl" name="limitCodeUrl" value="{{limitCodeUrl}}">
<input type="hidden" id="limitProductPay" name="limitProductPay" value="{{limitProductPay}}">
{{#limitProductCode}}
<input type="hidden" id="limitProductCode" name="limitProductCode" value="{{.}}">
{{/limitProductCode}}
<input type="hidden" id="limitCodeUrl" name="limitCodeUrl" value="{{limitCodeUrl}}">
<input type="hidden" id="limitProductPay" name="limitProductPay" value="{{limitProductPay}}">
{{#limitProductCode}}
<input type="hidden" id="limitProductCode" name="limitProductCode" value="{{.}}">
{{/limitProductCode}}
{{/if}}
<a href="javascript:;" id="likeBtn" class="favorite iconfont {{#isCollect}}liked{{/isCollect}}">&#xe605;</a>
</div>
{{/cartInfo}}
... ... @@ -223,4 +266,7 @@
{{/if}}
</div>
{{# isSecKill}}
<input type="hidden" class="productSkn-text" value={{productSkn}} />
{{/isSecKill}}
{{/ result}}
... ...
... ... @@ -14,6 +14,16 @@
<span class="market-price">{{price}}</span>
{{/if}}
</p>
{{#if ../isSecKill/startIng}}
<div class="seckill-time seckill-time-border seckill-chose">
<span>距结束 </span>
<span class="end-time">
<i class="tick hour">00</i>:
<i class="tick minute">00</i>:
<i class="tick second">00</i>
</span>
</div>
{{/if}}
</div>
</div>
<div class="chose-items">
... ... @@ -45,15 +55,26 @@
<div class="num">
<span>数量</span>
<div class="clearfix">
<a class="btn btn-minus" href="javascript:void(0);">
<span class="iconfont {{#if promotionId}}disabled{{/if}}">&#xe625;</span>
</a>
<input id="good-num" class="good-num disabled" type="text" value="1" disabled="true">
<a class="btn btn-plus" href="javascript:void(0);">
<span class="iconfont {{#if promotionId}}disabled{{/if}}">&#xe624;</span>
</a>
{{#if ../isSecKill/startIng}}
<a class="btn" href="javascript:void(0);">
<span class="iconfont {{#if promotionId}}disabled{{/if}}">&#xe625;</span>
</a>
<input id="good-num" class="good-num disabled" type="text" value="1" disabled="true">
<a class="btn" href="javascript:void(0);">
<span class="iconfont {{#if promotionId}}disabled{{/if}}">&#xe624;</span>
</a>
<span class="limit-num-text">限购1件</span>
{{else}}
<a class="btn btn-minus" href="javascript:void(0);">
<span class="iconfont {{#if promotionId}}disabled{{/if}}">&#xe625;</span>
</a>
<input id="good-num" class="good-num disabled" type="text" value="1" disabled="true">
<a class="btn btn-plus" href="javascript:void(0);">
<span class="iconfont {{#if promotionId}}disabled{{/if}}">&#xe624;</span>
</a>
{{/if}}
</div>
<span class="left-num"></span>
<span class="left-num {{#if ../isSecKill}}hide{{/if}}"></span>
<input id="left-num" type="hidden" value="0">
<input id="limitNum" type="hidden" value="{{limit}}">
</div>
... ... @@ -61,7 +82,20 @@
</div>
</div>
<div class="btn-wrap">
<button id="chose-btn-sure" class="btn btn-sure">{{#if ../tickets}}立即购买{{else}}加入购物车{{/if}}</button>
{{#if ../isSecKill/startIng}}
<button id="chose-btn-sure" class="btn btn-sure go-pay isSecKill">
立即抢购
</button>
{{else}}
<button id="chose-btn-sure" class="btn btn-sure go-pay">
{{#if ../tickets}}
立即购买
{{else}}
加入购物车
{{/if}}
</button>
{{/if}}
</div>
</div>
</div>
... ...
... ... @@ -58,6 +58,8 @@ var limitProductCode,
// 限购商品的skn。只有限购商品时才会设置。
skn;
var isSecKills = $('.isSecKill').length;// 秒杀标记
// 禁用数字编辑
function disableNumEdit() {
var $numBtn = $('.chose-panel').find('.num .btn>.iconfont');
... ... @@ -203,15 +205,30 @@ function hide() {
}
// 修改加入购物车的文字和背景
var isSeckill = $('.limit-num-text').length;
function updateConformButtonClassAndText() {
$chosed = $allChoseItems.find('.chosed');
if ($chosed.closest('.zero-stock').length === 2) {
$('#chose-btn-sure').css('background-color', '#c0c0c0').html('已售罄');
} else if (limitProductCode || ticketsLimit) {
$('#chose-btn-sure').css('background-color', '#eb0313').html('立即购买');
if (isSeckill > 0) {
$chosed = $allChoseItems.find('.chosed');
if ($chosed.closest('.zero-stock').length === 2) {
$('#chose-btn-sure').css('background-color', '#c0c0c0').html('已售罄');
} else if (limitProductCode || ticketsLimit) {
$('#chose-btn-sure').css('background-color', '#eb0313').html('立即购买');
} else {
$('#chose-btn-sure').css('background-color', '#eb0313').html(isEdit ? '确认' : '立即结算');
}
} else {
$('#chose-btn-sure').css('background-color', '#eb0313').html(isEdit ? '确认' : '加入购物车');
$chosed = $allChoseItems.find('.chosed');
if ($chosed.closest('.zero-stock').length === 2) {
$('#chose-btn-sure').css('background-color', '#c0c0c0').html('已售罄');
} else if (limitProductCode || ticketsLimit) {
$('#chose-btn-sure').css('background-color', '#eb0313').html('立即购买');
} else {
$('#chose-btn-sure').css('background-color', '#eb0313').html(isEdit ? '确认' : '加入购物车');
}
}
}
// 显示剩余件数
... ... @@ -549,8 +566,9 @@ $yohoPage.on('touchstart', '.btn-minus', function() {
if (!ticketsLimit) {
confirming = true;
}
loading.showLoadingMask();
if (!isSecKills) {
loading.showLoadingMask();
}
// 立即购买门票
if (ticketsLimit) {
... ... @@ -578,7 +596,10 @@ $yohoPage.on('touchstart', '.btn-minus', function() {
productSku + '&skn=' + skn + '&buy_number=' + buyNumber;
removePannel();
loading.showLoadingMask();
if (!isSecKills) {
loading.showLoadingMask();
}
// 调用接口判断商品是否可以购买
$.ajax({
... ... @@ -615,47 +636,70 @@ $yohoPage.on('touchstart', '.btn-minus', function() {
url = '/cart/index/add';
}
$.ajax({
method: 'POST',
url: url,
data: cartGoodData
}).done(function(res) {
var cartNum;
loading.hideLoadingMask();
if (res.code === 200 && !isEdit) {
cartNum = res.data.goods_count;
if (cartNum > 99) {
cartNum = '99+';
if (!isSecKills) {
$.ajax({
method: 'POST',
url: url,
data: cartGoodData
}).done(function(res) {
var cartNum;
loading.hideLoadingMask();
if (res.code === 200 && !isEdit) {
cartNum = res.data.goods_count;
if (cartNum > 99) {
cartNum = '99+';
}
$('.num-tag').html(cartNum).removeClass('hide');
confirming = false;
if (cbFn) {
cbFn();
}
}
$('.num-tag').html(cartNum).removeClass('hide');
confirming = false;
if (cbFn) {
cbFn();
if (res.message && !isEdit) {
tip.show(res.message);
}
}
if (res.message && !isEdit) {
tip.show(res.message);
}
hide();
hide();
if (isEdit) {
loading.showLoadingMask();
if (isEdit) {
loading.showLoadingMask();
// 延迟刷新,否则面板可能无法隐藏
setTimeout(function() {
// 延迟刷新,否则面板可能无法隐藏
setTimeout(function() {
// 获取当前页面商品类型:普通商品/预售商品
window.location.href = '/cart/index/index?cartType=' + $('#cartType').val();
}, 1);
}
}).fail(function() {
tip.show('网络出了点问题~');
}).always(function() {
confirming = false;
});
} else {
$('#chose-btn-sure').click(
function() {
var thisSkn = $('#productSkn').val();
var thisSku = '';
$('.size-row').each(
function() {
if ($(this).hasClass('hide')) {
return false;
} else {
thisSku = $(this).find('.chosed').attr('data-skuid');
}
}
);
window.location.href = '/cart/seckill?skn=' + thisSkn + '&sku=' + thisSku;
}
);
}
// 获取当前页面商品类型:普通商品/预售商品
window.location.href = '/cart/index/index?cartType=' + $('#cartType').val();
}, 1);
}
}).fail(function() {
tip.show('网络出了点问题~');
}).always(function() {
confirming = false;
});
}
});
... ...
... ... @@ -23,6 +23,8 @@ var dialog = require('../plugin/dialog');
require('../common');
require('./tick');
// add extra marign-bottom for footer to show the yoho copyright
function showFooter() {
var $cartBar = $('.cart-bar');
... ...
... ... @@ -146,6 +146,7 @@ seckillObj = {
// 初始化倒计时并开始计时
that.initTick(elem);
}
// 刷新商品列表
that.refreshProductList($(elem).find('input.activityId').val());
},
... ... @@ -178,12 +179,14 @@ seckillObj = {
$(this).addClass('wait');
}
});
// 刷新商品列表
var focusElem = $el.$navUl.find('>li.focus');
if (focusElem.length) {
that.refreshProductList(focusElem.find('input.activityId').val());
}
},
/**
* [异步加载商品列表]
*/
... ... @@ -205,7 +208,7 @@ seckillObj = {
error: function(data) {
tip.show('网络断开连接了~');
}
})
});
},
/**
... ...
/**
* [秒抢页面js]
* author: 陈峰<feng.chen@yoho.cn>
* date: 2016/09/08
*/
var $ = require('yoho-jquery'),
seckillObj = {};
var timeObj = '';
var offsetTime = 0;
var nowTime = Date.parse(new Date()) / 1000;
var startTime = 0;
var endTime = 0;
var dateText = 0,
newDate = 0,
newMonth = 0,
newDay = 0,
newHour = 0,
newMinus = 0;
require('../common');
seckillObj = {
el: {
iScroll: null,
currentTick: null
},
startTick: function(elem, offsetTime) {
var that = this,
$el = this.el,
hour = parseInt(offsetTime / (60 * 60), 10),
minute = parseInt(offsetTime % (60 * 60) / 60, 10),
second = offsetTime % 60;
if (offsetTime) {
$(elem).find('.tick.hour').text(hour < 0 ? '00' : (hour < 10 ? ('0' + hour) : hour));
$(elem).find('.tick.minute').text(minute < 0 ? '00' : (minute < 10 ? ('0' + minute) : minute));
$(elem).find('.tick.second').text(second < 0 ? '00' : (second < 10 ? ('0' + second) : second));
if (offsetTime <= 0) { // 结束倒计时刷新状态
// that.refreshList(elem);
} else {
$el.currentTick = setTimeout(function() {
that.startTick(elem, --offsetTime);
}, 1000);
}
}
}
};
$(
function() {
var ajaxUrl = '/product/detail/seckillData/' + $('.productSkn-text').val();
$.ajax({
type: 'GET',
url: ajaxUrl,
success: function(data) {
startTime = data.startTime;
endTime = data.endTime;
if (startTime > nowTime) {
offsetTime = startTime - nowTime;
timeObj = $('.seckill-count-num');
} else if (nowTime > startTime && nowTime < endTime) {
offsetTime = endTime - nowTime;
timeObj = $('.end-time');
}
dateText = Number(data.startTime * 1000);
newDate = new Date(dateText);
newMonth = newDate.getMonth() + 1;
newDay = newDate.getDate();
newHour = newDate.getHours();
newMinus = newDate.getMinutes();
$('.notStart').find('.seckill-time-c').text(newMonth + '月' + newDay + '日' + newHour + ':' + newMinus);
seckillObj.startTick(timeObj, offsetTime);
},
error: function() {
// alert('err');
}
});
}
);
... ...
... ... @@ -371,6 +371,52 @@ $basicBtnC: #eb0313;
}
}
.seckill-time {
float: right;
color: #d0021b;
font-size: 24px;
span {
display: inline-block;
line-height: 88px;
}
.seckill-time-pic {
background-color: #d0021b;
color: #fff;
line-height: 35px;
font-size: 18px;
padding: 0 10px;
border-radius: 5px;
}
}
.seckill-chose {
position: absolute;
bottom: 0px;
right: 0px;
}
.limit-num-text {
color: #d0021b;
font-size: 30px;
line-height: 80px;
position: absolute;
left: 380px;
bottom: 0;
}
.seckill-time-border {
border: solid 1px #d0021b;
margin-top: 26px;
border-radius: 19px;
padding: 0 10px;
span {
line-height: 34px;
}
}
.vip-level {
box-sizing: box-border;
padding-right: 28px;
... ... @@ -711,7 +757,41 @@ $basicBtnC: #eb0313;
}
}
}
/*
秒杀倒计时栏
*/
.seckill-count {
position: relative;
position: fixed;
bottom: 120px;
left: 50%;
margin-left: -320px;
z-index: 2;
box-sizing: border-box;
width: 640px;
height: 70px;
text-align: left;
.seckill-count-bg {
background-color: #000;
opacity: 0.7;
width: 640px;
height: 70px;
}
.seckill-count-num {
position: absolute;
top: 0;
left: 0;
padding: 0 30px;
color: white;
width: 640px;
height: 70px;
line-height: 70px;
box-sizing: border-box;
font-size: 28px;
}
}
/*
底部固定栏
*/
... ...