Authored by huangyCode

Merge branch 'feature/group-buy' of http://git.yoho.cn/fe/yohobuywap-node into feature/group-buy

... ... @@ -58,6 +58,7 @@ function groupList(req, res, next) {
});
}).catch(next);
}
function filter(req, res, next) {
let params = Object.assign({}, req.query);
... ... @@ -69,12 +70,34 @@ function filter(req, res, next) {
});
}).catch(next);
}
function searchList(req, res, next) {
let params = Object.assign({}, req.query);
req.ctx(GroupService).filterGroupList(params)
.then(result => {
return res.render('group/search-list', {
page: 'group',
layout: false,
localCss: true,
nodownload: true,
width750: true,
wechatShare: true,
filterList: result
});
}).catch(next);
}
function progress(req, res, next) {
const uid = req.user.uid;
const groupNo = req.query.groupNo;
const activityId = req.query.activityId;
req.ctx(GroupService).groupResult({groupNo, activityId, uid})
req.ctx(GroupService).groupResult({
groupNo,
activityId,
uid
})
.then(renderData => {
return res.render('group/progress', {
title: '拼团详情',
... ... @@ -82,6 +105,7 @@ function progress(req, res, next) {
localCss: true,
nodownload: true,
width750: true,
wechatShare: true,
data: renderData
});
}).catch(next);
... ... @@ -124,7 +148,10 @@ function goodsDetail(req, res, next) {
function order(req, res, next) {
const uid = req.user.uid;
const { type, selectIndex } = req.query;
const {
type,
selectIndex
} = req.query;
const param = {
page: 1,
limit: 50,
... ... @@ -142,15 +169,14 @@ function order(req, res, next) {
width750: true,
wechatShare: true,
result,
navs: [
{
title: '进行中',
src: '/activity/group/order?type=2&selectIndex=0'
},
{
title: '全部',
src: '/activity/group/order?type=1&selectIndex=1'
}
navs: [{
title: '进行中',
src: '/activity/group/order?type=2&selectIndex=0'
},
{
title: '全部',
src: '/activity/group/order?type=1&selectIndex=1'
}
],
selectIndex: Number(selectIndex) || 0
});
... ... @@ -164,5 +190,6 @@ module.exports = {
progress,
goodsDetail,
order,
filter
filter,
searchList
};
... ...
... ... @@ -116,13 +116,15 @@ class GroupService extends global.yoho.BaseModel {
async filterGroupList(params) {
const initParams = {
page: 1,
limit: 20,
limit: 15,
joinLimit: 1
};
let newParams = {
...initParams,
...params
};
console.log(newParams);
const result = await this.api._getPromoteList(newParams);
let finalResult = {};
... ... @@ -137,6 +139,7 @@ class GroupService extends global.yoho.BaseModel {
}
return finalResult;
}
async groupList(params) {
const initParams = {
page: 1,
... ...
... ... @@ -369,7 +369,8 @@ router.post('/yoluck/detail/mylist.html', yoluck.getActivityCodeList);
router.get('/group', group.index); // 拼团首页
router.get('/group/list', group.groupListIndex); // 拼团列表页
router.get('/group/goods-list', group.groupList); // 拼团列表
router.get('/group/filter', group.filter); // 首页筛选结果
router.get('/group/filter', group.filter); // 首页筛选结果页
router.get('/group/search', group.searchList); // 首页筛选列表
router.get('/group/progress', auth, group.progress); // 拼团状态详情页
router.get('/group/goodsDetail', group.goodsDetail);
router.get('/group/order', auth, group.order); // 我的拼团
... ...
... ... @@ -37,14 +37,15 @@
{{> group/resources/filter-tab}}
</div>
{{#if filterList.length}}
<div class="group-list">
{{#each filterList}}
{{> group/resources/filter-list-item}}
{{/each}}
<div id="goodsContainer">
{{#if filterList.length}}
<div class="goods-list">
{{#each filterList}}
{{> group/resources/filter-list-item}}
{{/each}}
</div>
{{/if}}
</div>
{{/if}}
{{!-- {{> group/resources/filter-page}} --}}
</div>
<a class="bottom" href="/activity/group/order">我的拼团</a>
... ...
{{#data}}
<div class="group-progress" data-page-go="{{pageGo}}" data-left-time="{{leftTime}}">
<div class="group-progress" data-page-go="{{pageGo}}"
data-activity-id="{{activityId}}"
data-left-time="{{leftTime}}"
data-lack-num="{{lackNum}}"
data-group-no="{{groupNo}}"
data-product-name="{{yourJoinItem.productName}}"
data-group-price="{{yourJoinItem.productGroupPrice}}"
data-share-img="{{image2 yourJoinItem.productIcon w=200 h=282}}">
<div class="card">
<div class="inner-card go-join" data-product-skn="{{yourJoinItem.productSkn}}"
data-activity-id="{{activityId}}" data-group-no="{{groupNo}}" data-page-go="{{pageGo}}">
... ...
{{#each filterList}}
{{> group/resources/filter-list-item}}
{{/each}}
\ No newline at end of file
... ...
<div class="group-product-cell-bg" data-group-product="{{group_product}}" data-item-idx="{{itemIdx}}">
<div class="group-product-cell" data-group-product="{{group_product}}" data-item-idx="{{itemIdx}}">
<div class="group-product-header">
<div class="group-product-left-icon">
<span class="group-product-left-icon-number">{{people_num}}人团</span>
... ...
{{# cartInfo}}
<div class="chose-panel" data-skn="{{productSkn}}">
<div class="main">
<div class="close iconfont">&#xe626;</div>
<div class="infos {{#if @root.tickets}} tickets-info {{/if}}">
<div class="basic-info">
<div class="thumb-img">
<img class="thumb" src="{{defaultThumb}}">
</div>
<div class="text-info">
<p class="price">
{{#if price}}
<span class="sale-price">{{salePrice}}</span>
<span class="market-price">{{price}}</span> {{else}} {{# isY isSecKill}}
<span class="sale-price">{{salePrice}}</span>
<span class="market-price">{{salePrice}}</span> {{else}}
<span class="sale-price no-price">{{salePrice}}</span> {{/ isY}} {{/if}}
</p>
<p class="not-choose">{{@root.noChoseText}}</p>
<p class="choosed-info hide"></p>
<p class="size-info hide"></p>
<p class="size-rec hide"></p>
</div>
</div>
<div class="chose-items">
{{#each props}}
<div class="block-list">
<span class="name">{{name}}</span>
<ul class="size-row clearfix">
{{#each values}}
<li class="block{{#if chosed}} chosed{{/if}}" data-prop-id="{{../type}}" data-value-id="{{id}}">{{name}}</li>
{{/each}}
</ul>
</div>
{{/each}}
<div class="num">
<span class="name">数量</span>
<div class="clearfix">
<a class="btn btn-minus {{#if @root.discountBuy}}discount-gray{{/if}}" href="javascript:void(0);">
<span class="iconfont {{#if @root.disableNum}}disabled{{/if}}">&#xe625;</span>
{{!--TODO promotionId => disabled--}}
</a>
<input id="good-num" class="good-num disabled" type="text" value="{{@root.buyNum}}" disabled="true">
<a class="btn btn-plus" href="javascript:void(0);">
<span class="iconfont {{#if @root.disableNum}}disabled{{/if}}">&#xe624;</span>
</a>
</div>
{{#if @root.discountBuy}}
<input id="mnum" type="hidden" value="{{@root.discountBuy.num}}">
{{#if @root.discountBuy.discount}}
<span class="left-num-discount">{{@root.discountBuy.num}}件起购享{{@root.discountBuy.discount}}</span>
{{^}}
<span class="left-num-discount">{{@root.discountBuy.num}}件起购</span>
{{/if}}
{{^}}
<span class="left-num"></span>
{{/if}}
<input id="left-num" type="hidden" value="0">
<input id="limitNum" type="hidden" value="{{limit}}">
</div>
</div>
</div>
<div class="btn-wrap">
{{#if @root.buttonText.double}}
<button id="chose-btn-buynow" class="btn btn-sure-buynow">立即购买</button>
<button id="chose-btn-sure" class="btn btn-sure-addtocart">加入购物车</button>
{{^}}
<button id="chose-btn-sure" class="btn btn-sure">{{@root.buttonText.text}}</button>
{{/if}}
</div>
</div>
</div>
{{/ cartInfo}}
<input id="promotionId" type="hidden" value="{{promotionId}}">
<input id="single" type="hidden" value="{{@root.single}}">
... ...
... ... @@ -22,16 +22,40 @@ class GroupProgress extends Page {
$countdown: $('.count-down')
};
this.timer = '';
this.data = {
groupNo: '',
lackNum: '',
productName: '',
groupPrice: '',
shareImgUrl: ''
};
this.init();
}
init() {
lazyLoad(this.selector.$page.find('img.lazy'));
this.initData();
this.bindEvents();
this.shareInfo();
this.countdown();
}
initData() {
let activityId = this.selector.$page.data('activity-id');
let groupNo = this.selector.$page.data('group-no');
let lackNum = this.selector.$page.data('lack-num');
let productName = this.selector.$page.data('product-name');
let groupPrice = this.selector.$page.data('group-price');
let shareImgUrl = this.selector.$page.data('share-img');
this.data.groupNo = groupNo;
this.data.lackNum = lackNum;
this.data.productName = productName;
this.data.groupPrice = groupPrice;
this.data.activityId = activityId;
this.data.shareImgUrl = shareImgUrl;
}
bindEvents() {
this.selector.$productItem.on('click', this.goDetail.bind(this));
this.selector.$goJoin.on('click', this.goJoin.bind(this));
... ... @@ -40,17 +64,23 @@ class GroupProgress extends Page {
}
shareInfo() {
let _this = this;
let link = '';
let [domain] = location.href.split('?');
link = `${domain}?activityId=${this.data.activityId}&groupNo=${this.data.groupNo}`;
_this.data.shareImgUrl = _this.data.shareImgUrl.replace(/(http:)?\/\//, 'https://');
sharePlugin({
title: '有货福利团xx元包邮xxx商品',
imgUrl: '',
link: '',
desc: 'x人团更优惠,正品保证,全场包邮',
copyDeac: '【有货福利团 】x人团,xx元包邮xxx商品>>'
title: `【还差${_this.data.lackNum}人】${_this.data.groupPrice}金额 ${_this.data.productName}`,
imgUrl: _this.data.shareImgUrl,
link: link
});
let clipboardShare = new Clipboard('.h5-share-clipboard', {
text: function() {
return '【有货福利团 】x人团,xx元包邮xxx商品>>';
return `【还差${_this.data.lackNum}人】${_this.data.groupPrice}金额 ${_this.data.productName}>>${link}`;
}
});
... ...
... ... @@ -7,7 +7,8 @@ let innerScroll = require('js/plugin/inner-scroll');
// import lazyLoad from 'yoho-jquery-lazyload';
// import tip from 'js/plugin/tip';
// import loading from 'js/plugin/loading';
import loading from 'js/plugin/loading';
class Group extends Page {
constructor() {
... ... @@ -18,32 +19,33 @@ class Group extends Page {
floorsContentHeight: $('.floors').height(),
groupTab: $('.group-tab'),
filterTab: $('.filter-nav'),
groupListContent: $('.group-list')
groupListContent: $('.goods-list')
};
this.navInfo = {
new: {
order: 's_t_desc',
reload: true,
page: 1,
end: false
reload: true, // 是否重新加载
isScrollLoad: false, // 是否是滚动加载
page: 0,
end: false // 是否继续请求数据
},
popularity: {
order: 'h_v_desc',
reload: true,
isScrollLoad: false,
page: 0,
end: false
},
price: {
order: 's_p_asc',
reload: true,
isScrollLoad: false,
page: 0,
end: false
}
};
this.noResult = '<p class="no-result">未找到相关搜索结果</p>';
this.defaultLimit = 15;
this.selectedChannel = 'newGroup';
this.filterTab = {
newGroup: {
... ... @@ -64,10 +66,22 @@ class Group extends Page {
this.bindEvents();
this.swiperTop();
this.filterInit();
$(window).scroll(() => {
window.requestAnimationFrame(this.scrollHandler.bind(this));
let self = this;
$(window).scroll(function() {
window.requestAnimationFrame(() => {
self.scrollHandler();
});
setTimeout(function() {
window.requestAnimationFrame(() => {
self.scrollListHandler();
});
}, 5);
});
}
scrollHandler() {
// 滚动固定tab
let floorsContentHeight = this.selector.floorsContentHeight + 5;
... ... @@ -80,6 +94,22 @@ class Group extends Page {
this.selector.groupListContent.removeClass('mrt');
}
}
scrollListHandler() {
// 当scroll到1/2$goodsContainer高度后继续请求下一页数据
let floorsContentHeight = this.selector.floorsContentHeight + 5;
let goodsContainerHeight = this.selector.groupListContent.height();
let navType = this.judgeType(this.filterTab[this.selectedChannel].$pre);
let nav = this.navInfo[navType];
if (($(window).scrollTop() - floorsContentHeight) > goodsContainerHeight * 0.6) {
nav.reload = false;
nav.isScrollLoad = true;
console.log('load');
if (!nav.end) {
this.search();
}
}
}
bindEvents() {
this.selector.tabSection.on('click', this.fixedTab.bind(this));
this.selector.groupTab.on('click', this.groupTabChange.bind(this));
... ... @@ -126,6 +156,9 @@ class Group extends Page {
return;
}
nav.reload = true;
nav.end = false;
nav.isScrollLoad = false;
nav.page = 0;
nav.order = $this.data('order');
this.filterTab[currentChannel].order = nav.order;
}
... ... @@ -134,6 +167,9 @@ class Group extends Page {
if ($this.hasClass('price')) {
$this.find('.icon > .iconfont').toggleClass('cur');
nav.reload = true;
nav.end = false;
nav.isScrollLoad = false;
nav.page = 0;
nav.order = nav.order === 's_p_asc' ? 's_p_desc' : 's_p_asc'; // 切换排序
this.filterTab[currentChannel].order = nav.order;
}
... ... @@ -167,8 +203,9 @@ class Group extends Page {
for (let i in navInfo) {
if (navInfo.hasOwnProperty(i)) {
navInfo[i].reload = true;
navInfo[i].isScrollLoad = false;
navInfo[i].end = false;
navInfo[i].page = 0;
if (i === 'price') {
navInfo[i].order = 's_p_asc';
}
... ... @@ -189,6 +226,10 @@ class Group extends Page {
}
}
// 清除筛选页存储的数据
this.filterPage.newGroup = {};
this.filterPage.normalGroup = {};
// 根据条件重置筛选页面及商品列表
this.filterInit();
this.search();
... ... @@ -210,6 +251,23 @@ class Group extends Page {
}
}
// 判断导航类型
judgeType(dom) {
let navType;
if (dom.hasClass('new')) {
navType = 'new';
} else if (dom.hasClass('popularity')) {
navType = 'popularity';
} else if (dom.hasClass('price')) {
navType = 'price';
} else {
navType = 'other';
}
return navType;
}
//
/**
* 筛选注册的回调,筛选子项点击后逻辑
... ... @@ -217,35 +275,108 @@ class Group extends Page {
* @param opt
*/
search() {
let params = this.filterTab[this.selectedChannel];
let groupListContent = this.selector.groupListContent;
let params = {
...this.filterTab[this.selectedChannel]
};
let pageParams = this.filterPage[this.selectedChannel];
let nav;
let navType;
let page;
let that = this;
delete params.$pre;
console.log('searchParam', params);
console.log('pageParams', this.filterPage[this.selectedChannel]);
// 导航类别
navType = this.judgeType(this.filterTab[this.selectedChannel].$pre);
nav = this.navInfo[navType];
page = nav.page + 1;
if (nav.reload) {
page = 1;
}
nav.page = page;
console.log('nav', nav);
if (nav.end) {
// 不需要重新加载并且数据请求结束
return false;
}
loading.showLoadingMask();
$.ajax({
type: 'GET',
url: '/activity/group/search',
data: {
...params,
...pageParams,
page
},
beforeSend: () => {
if ($('.search-divide').length > 0) {
$('.search-divide').remove();
}
groupListContent.after(() => {
return '<div class="search-divide">正在加载...</div>';
});
},
success: (data) => {
that.dataRender(data, nav);
},
error: () => {
let $divide = $('.search-divide');
// let setting;
$divide.text('加载失败,点击重试');
$divide.one('click', () => {
$divide.text('正在加载...');
this.search();
});
}
});
}
dataRender(result, curNav) {
// 去掉正在加载
$('.search-divide').remove();
let isResult = !result || !result.length ||
result.length < 1 ||
(result.list && result.list.length < 1);
// loading.showLoadingMask();
let groupListContent = this.selector.groupListContent;
// $.ajax({
// type: 'GET',
// url: '/product/sale/search',
// data: setting,
// success: function() {
// },
// error: function() {
// tip.show('网络断开连接了~');
// loading.hideLoadingMask();
// }
// });
// 没有结果输出没有结果页面
if (isResult) {
if (curNav.isScrollLoad && !curNav.reload) {
groupListContent.after(() => {
return '<div class="search-divide">没有更多内容了...</div>';
});
} else {
groupListContent.html('<div>未查询到数据!</div>');
}
curNav.end = true;
console.log('curNav', curNav);
return false;
} else {
if (curNav.isScrollLoad && !curNav.reload) {
groupListContent.append(result);
} else {
groupListContent.html(result);
}
}
}
// 筛选初始化
filterInit() {
let selectedChannel = this.selectedChannel;
let requestParams = {
...this.filterTab[this.selectedChannel]
...this.filterTab[selectedChannel]
};
let filterTab = this.selector.filterTab;
let filterPage = this.filterPage;
let search = this.search.bind(this);
delete requestParams.$pre;
... ... @@ -260,7 +391,13 @@ class Group extends Page {
// 初始化filter&注册filter回调
filter.initFilter({
fCbFn: search,
fCbFn: function(params) {
console.log(params);
// 存储筛选页数据
filterPage[selectedChannel][params.type] = params.id;
search();
},
hCbFn: function() {
filterTab.children('.filter').removeClass('active');
innerScroll.enableScroll($('body'));
... ...
... ... @@ -101,6 +101,7 @@ class ProductListLoader {
}
let catchKey = this.url + '?' + $.param(this.defaultOpt);
console.log(this.defaultOpt);
if (!this.isLoadMore) {
return false;
}
... ...
.group-list {
.goods-list {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
margin-left: 20px;
margin-right: 20px;
margin-bottom: 100px;
}
.group-product-image {
... ... @@ -13,7 +12,7 @@
height: 430px;
}
.group-product-cell-bg {
.group-product-cell {
margin-top: 20px;
}
... ...
... ... @@ -79,4 +79,12 @@
z-index: 998;
background-color: #fff;
}
.search-divide {
height: 50px;
width: 100%;
padding: 10px 0;
color: #ccc;
text-align: center;
}
}
... ...