Authored by 陈轩

new arrival done

... ... @@ -33,7 +33,7 @@ const blkNewGoods = (req, res) => {
// 新品到着
const newGoods = (req, res, next) => {
let channel = req.cookies._Channel;
let channel = req.yoho.channel;
newModel.getNewFocus(channel).then((result) => {
res.render('new/new', {
... ... @@ -61,36 +61,53 @@ const newGoods = (req, res, next) => {
};
const _newGoods = (req, res, next) => {
const channel = req.cookies._Channel;
const channel = req.yoho.channel;
const uid = req.user.uid;
res.render('new/index', {
module: 'product',
page: 'new-arrival',
width750: true,
localCss: true,
pageHeader: headerModel.setNav({
navTitle: '新品到着'
}),
newModel.indexData(uid, channel).then(result => {
let shopList = _.get(result, 'shop_list', []);
let banner = _.get(result, 'ads[0]', {});
let handPick = _.get(result, 'ads[1]', {});
// console.log(handPick)
res.render('new/index', {
module: 'product',
page: 'new-arrival',
width750: true,
localCss: true,
pageHeader: headerModel.setNav({
navTitle: '新品到着'
}),
cartUrl: helpers.urlFormat('/cart/index/index', null),
pageFooter: true,
showDownloadApp: true,
// 资源位
shopList,
banner,
handPick,
// 搜索参数,貌似没用到
brand: '0',
sort: '0',
gender: req.query.gender || searchProcess.getGenderByChannel(channel),
channel,
price: '0',
size: '0',
dayLimit: 1,
discount: ''
});
}).catch(next);
brand: '0',
sort: '0',
gender: req.query.gender || searchProcess.getGenderByChannel(channel),
channel,
price: '0',
size: '0',
dayLimit: 1,
discount: '',
cartUrl: helpers.urlFormat('/cart/index/index', null),
pageFooter: true,
showDownloadApp: true
});
};
/**
* 新品到着 落地页: 为您推荐
*/
const brands = (req, res, next) => {
const channel = req.cookies._Channel;
const channel = req.yoho.channel;
const uid = req.user.uid;
newModel.recbrand(uid, channel).then(data => {
... ... @@ -132,9 +149,11 @@ const selectNewSale = (req, res, next) => {
* Router: /product/new/recommend-shop.json
*/
const recommendShop = (req, res, next) => {
const channel = req.cookies._Channel;
const channel = req.yoho.channel;
const uid = req.user.uid;
console.log(channel)
newModel.recommendShops(uid, channel).then(data => {
res.json(data);
});
... ... @@ -146,7 +165,7 @@ const recommendShop = (req, res, next) => {
*/
const fetchNew = (req, res, next) => {
const uid = req.user.uid;
const channel = req.cookies._Channel;
const channel = req.yoho.channel;
delete req.query.uid;
delete req.query.channel;
... ... @@ -158,7 +177,7 @@ const fetchNew = (req, res, next) => {
const goodsFilter = (req, res, next) => {
const uid = req.user.uid;
const channel = req.cookies._Channel;
const channel = req.yoho.channel;
newModel.reclistFilter(uid, channel).then(result => {
res.render('search/filter', {
... ...
{{!--新品到着--}}
<div>
{{!--top banner--}}
{{#if banner}}
<div class="banner-top">
<div class="banner-swiper swiper-container">
<!-- Additional required wrapper -->
<div class="swiper-wrapper">
<!-- Slides -->
<div class="swiper-slide">
<a href="">
<img class="banner-top-pic" src="//img12.static.yhbimg.com/yhb-img01/2016/03/21/05/02c8856b64157f6fe018e76d1d5dbe6a92.jpg?imageView2/2/w/640/h/240/q/60" alt="">
{{#each banner.data}}
<a href="{{url}}">
<img class="banner-top-pic swiper-lazy" data-src="{{image2 src w=750 h=234 q=60}}" alt="">
</a>
{{/each}}
</div>
</div>
<div class="swiper-pagination"></div>
<div class="swiper-pagination-s1">
<div id="banner-pagination" class="pagination-inner"></div>
</div>
</div>
</div>
{{/if}}
{{!--为您推荐--}}
{{#if shopList}}
<div id="new-recommend" class="new-recommend panel">
<header class="panel-header">
<h3>为您推荐</h3>
... ... @@ -24,11 +31,16 @@
<i class="iconfont more">&#xe606;</i>
</a>
</header>
<div class="panel-body"></div>
<div class="panel-body">
{{> product/brands shops=shopList}}
</div>
</div>
{{/if}}
{{!--精选抢先看--}}
{{> 'new/handpick'}}
{{#if handPick.data}}
{{> 'new/handpick' swiper=handPick.data}}
{{/if}}
{{!--最新上架--}}
{{> 'new/goods'}}
... ...
{{!-- 新品到着: 最新上架--}}
<div id="new-goods">
<div>
<div class="filter-nav-wrap" data-sticky>
{{> common/filter-nav}}
<div id="js-filter"></div>
</div>
<div class="goods-container">
<div class="goods-box"></div>
{{!--
<div class="container" data-rel="new-0"></div>
<div class="container" data-rel="price-0"></div>
<div class="container" data-rel="price-1"></div>
<div class="container" data-rel="discount-0"></div>
<div class="container" data-rel="discount-1"></div>
<div class="container" data-rel="filter"></div>
<div id="js-filter"></div>
--}}
</div>
{{> common/query-param}}
... ...
... ... @@ -2,9 +2,9 @@
<div id="handpick" class="panel handpick">
<header class="panel-header">
<h4>精选抢先看</h4>
<a href="#javascript" class="panel-header-r more">
{{!--<a href="#javascript" class="panel-header-r more">
<i class="iconfont">&#xe606;</i>
</a>
</a>--}}
</header>
<main class="panel-body">
<!-- Slider main container -->
... ... @@ -12,9 +12,13 @@
<!-- Additional required wrapper -->
<div class="swiper-wrapper">
<!-- Slides -->
<div class="swiper-slide">Slide 1</div>
<div class="swiper-slide">Slide 2</div>
<div class="swiper-slide">Slide 3</div>
{{#each swiper}}
<div class="swiper-slide">
<a href="{{url}}">
<img class="swiper-lazy" data-src="{{image2 src w=332 h=194 q=60}}" alt="">
</a>
</div>
{{/each}}
</div>
</div>
</main>
... ...
... ... @@ -49,6 +49,7 @@ const bottomBannerContentCode = {
const outletContentCode = 'c19ffa03f053f4cac3690b22c8da26b7';
// TODO: remove
const newContentCode = {
boys: '3cf2c1be5217fbab6009ce83959e1e12',
girls: '1cf7f9f10e2a2670e73d05c568793ad9',
... ... @@ -56,6 +57,13 @@ const newContentCode = {
lifestyle: '04953a61cbf1db426a681e55d496d2fe'
};
const newContentCodeV2 = {
boys: '1f2e07cb63811680154ba693c954dd62',
girls: '375f201d1ec56f7515509249c9c66959',
kids: '74c62151673e7dde9fb154c90dcff3f0',
lifestyle: 'b9b4bd0de670f982e1f8e7dc23980e81'
};
const liveContentCode = {
index: '345c80537dca15611f37ae4863004bfe'
};
... ... @@ -66,6 +74,7 @@ module.exports = {
channel: channelContentCode,
bottom: bottomBannerContentCode,
guang: guangContentCode,
new: newContentCode,
new: newContentCode, // TODO: remove
newV2: newContentCodeV2,
live: liveContentCode
};
... ...
<ul id="list-nav" class="list-nav filter-nav clearfix">
<li class="new active">
<li class="new active" data-order="s_t_desc">
<a href="javascript:void(0);">
<span class="span-test">最新</span>
</a>
... ... @@ -8,8 +8,8 @@
<a href="javascript:void(0);">
<span class="span-test">价格</span>
<span class="icon">
<i class="iconfont up cur">&#xe615;</i>
<i class="iconfont down">&#xe616;</i>
<i class="iconfont up cur" data-order="s_p_asc">&#xe615;</i>
<i class="iconfont down" data-order="s_p_desc">&#xe616;</i>
</span>
</a>
</li>
... ... @@ -17,8 +17,8 @@
<a href="javascript:void(0);">
<span class="span-test">折扣</span>
<span class="icon">
<i class="iconfont up cur">&#xe615;</i>
<i class="iconfont down">&#xe616;</i>
<i class="iconfont up" data-order="p_d_asc">&#xe615;</i>
<i class="iconfont down cur" data-order="s_p_desc">&#xe616;</i>
</span>
</a>
</li>
... ...
... ... @@ -2,13 +2,17 @@
require('product/new-arrival.page.css');
require('common');
require('common/suspend-cart');
require('plugin/sticky');
let Swiper = require('yoho-swiper');
let lazyLoad = require('yoho-jquery-lazyload');
let filter = require('plugin/filter');
let mySwiper = new Swiper('.handpick-swiper', {
new Swiper('.handpick-swiper', {
// Optional parameters
lazyLoading: true,
lazyLoadingInPrevNext: true,
loop: true,
// If we need pagination
... ... @@ -16,62 +20,157 @@ let mySwiper = new Swiper('.handpick-swiper', {
centeredSlides: true,
paginationClickable: true,
spaceBetween: 30,
pagination: '.swiper-pagination',
});
// ==============================================
// function: 为您推荐
let recommendShops = function() {
let $container = $('#new-recommend');
let fetchURI = '/product/new/recommend-shop.json';
let template = require('product/new/brands.hbs');
// 渲染模版并插入
function render(shops) {
let html = template({shops});
new Swiper('.banner-swiper', {
lazyLoading: true,
$container.find('.panel-body').append(html);
}
// If we need pagination
centeredSlides: true,
paginationClickable: true,
pagination: (function() {
if ($('.banner-swiper').find('.swiper-slide').length > 1) {
return '#banner-pagination';
} else {
$('#banner-pagination').hide();
return null;
}
}()),
});
$.get(fetchURI).done(shopData => {
render(shopData.shop_list || []);
});
};
recommendShops();
// ==============================================
// 1 滚动: 搜索参数不变, 追加数据
// 2 筛选,切换排序: 重新搜索
//
// ==============================================
let searchView = function() {
let body = document.body;
let $c = $('#new-goods');
let $nav = $c.find('filter-nav');
let $goodsBox = $c.find('.goods-container');
let $navBox = $c.find('.filter-nav');
let $goodsWraper = $c.find('.goods-container');
let $prevNav = null;
let goodsT = require('product/new/goods.hbs');
// 给nav 设置 数据属性
$nav.children('.new').data('order', ['new', '0']); // 从新到旧
$nav.children('.price').data('order', ['price', '1']); // 从低到高
$nav.children('.discount').data('order', ['discount', '0']); // 折扣从大到小
let $loading = $('<div class="yo-loading"></div>');
let $prevNav = $navBox.children('.new');
let $goodBox = $goodsWraper.children('.goods-box');
let fetchXhr = null;
/**
* 搜索 参数
* Note:filter 没有重置功能
* see: search-process.js
*/
let searchParams = {
order: 's_t_desc',
filter: {
},
page: {
cur: 0,
total: null
}
};
function initFilter() {
$.get('/product/new/goods-filter').done(filterHtml => {
$('#js-filter').replaceWith(filterHtml);
return $.get('/product/new/goods-filter').done(filterHtml => {
$('#js-filter').html(filterHtml);
filter.initFilter({
fCbFn: $.noop,
hCbFn: $.noop
/**
* filterObj:
* {filtering, id, type}
*/
fCbFn: function(filterObj) {
let filterKey = filterObj.type;
// 字段正规化
let normalizeKey = ({
ageLevel: 'age_level'
// TODO: 哪些字段不正规,添加再这里
})[filterKey];
normalizeKey && (filterKey = normalizeKey);
// 放入查询参数
searchParams.filter[filterKey] = filterObj.id;
console.log(searchParams);
fetchNew({ // eslint-disable-line
$box: $goodBox,
before: $box => {
fetchXhr.abort();
$box.html('');
}
});
},
hCbFn: function() {
// hide filter ,switch prev nav;
$navBox.children('.filter').removeClass('active');
$prevNav.addClass('active');
}
});
});
}
/**
* 切换nav
*/
function switchNav($nextNav) {
let _$prevNav = $navBox.children('.active'); // 当前active nav
// active 不是filter, 都暂存起来,filter hide的时候用到
if (!_$prevNav.hasClass('filter')) {
$prevNav = _$prevNav;
}
// 点击的nav 是filter nav
if ($nextNav.hasClass('filter')) {
let filterActived = $nextNav.hasClass('active');
filterActived ? filter.hideFilter() : filter.showFilter();
$prevNav.toggleClass('active', filterActived);
$nextNav.toggleClass('active', !filterActived);
return;
}
// 以下都是 order nav的情况, $prevNav始终是order nav;
filter.hideFilter();
if (!$prevNav.is($nextNav)) {
$prevNav.removeClass('active');
} else if ($nextNav.is('.price,.discount')) { // same && is price, discount
let $cur = $nextNav.find('.cur');
$cur.removeClass('cur').siblings().addClass('cur');
}
$nextNav.toggleClass('active', true);
return $nextNav;
}
/**
* order是否改变
* Note: filter的改变,有filter的回调处理
*/
function checkOrderChange($activeNav, changeAction) {
if (!$activeNav) {
return;
}
let order = $activeNav.data('order') || $activeNav.find('.cur').data('order');
searchParams.order = order;
changeAction();
}
function renderGoods($container, data) {
... ... @@ -80,26 +179,98 @@ let searchView = function() {
});
$container.append(html);
lazyLoad($container.find('.lazy'));
lazyLoad(html);
}
// search state
function fetchNew(searchParams) {
return $.get('/product/new/goods.json', searchParams)
.then(data => {
console.log(data);
renderGoods($('.goods-container'), data.list);
/**
* 搜索
* @param conf
* {
* $box: 数据塞入的容器,
* nextPage: true // 有该字段,且为true, 会去fetch 下一页数据
* before: 搜索之前的动作,第一个参数为 $box
* }
*/
function fetchNew(conf) {
let $box = conf.$box;
let page = {
cur: 0,
total: null
};
if (conf.nextPage) {
page = searchParams.page;
if (page.cur === page.total) { // no nore next
return;
}
}
conf.before && conf.before.apply(null, [$box]);
// search params
let data = {};
data.page = page.cur + 1; // fetch one page
data.order = searchParams.order;
$.extend(data, searchParams.filter);
$loading.appendTo($box);
return (fetchXhr = $.get('/product/new/goods.json', data))
.done(res => {
searchParams.page.total = res.pageTotal;
searchParams.page.cur = page.cur + 1;
renderGoods($box, res.list);
})
.always(() => {
$loading.remove();
});
}
/**
* 滚动到底部一定距离时, 加载下一页
*/
function fetchNextPage() {
fetchNew({
$box: $goodBox,
nextPage: true
});
}
$nav.on('click', 'li', function(event) {
let $curNav = $(event.target);
initFilter()
.done(function() {
$navBox.on('click', 'li', function(event) {
let $curNav = $(event.currentTarget);
let $activeNav = switchNav($curNav);
checkOrderChange($activeNav, function() {
fetchNew({ // eslint-disable-line
$box: $goodBox,
before: $box => {
fetchXhr.abort();
$box.html('');
}
});
});
});
});
switchNav($curNav);
$(window).scroll(function() {
setTimeout(() => {
if (body.scrollHeight - (body.scrollTop + body.scrollWidth) < 300 && fetchXhr.readyState === 4) {
fetchNextPage();
}
}, 0);
});
initFilter();
fetchNew({
$box: $goodBox
});
return {
fetchNew,
... ... @@ -109,6 +280,7 @@ let searchView = function() {
window.search = searchView();
window.filter = filter;
window.$ = $;
... ...
... ... @@ -50,6 +50,7 @@
top: 0;
right: 0;
left: 0;
z-index: 2;
}
.filter-mask {
... ...
.sticky {
position: fixed;
top: 0;
}
\ No newline at end of file
... ... @@ -523,4 +523,36 @@
}
}
.swiper-pagination-s1 {
position: absolute;
left: 0;
right: 0;
bottom: 0.5rem;
text-align: center;
z-index: 1;
.pagination-inner {
display: inline-block;
padding: 0 0.2rem 0.1rem;
background: rgba(0, 0, 0, 0.2);
border-radius: 1.25rem;
}
.pagination-inner span {
display: inline-block;
width: 0.35rem;
height: 0.35rem;
background: #fff;
opacity: 0.5;
margin: 0 0.225rem;
border-radius: 50%
}
.pagination-inner span.swiper-pagination-bullet-active {
background: #fff;
opacity: 1;
}
}
/* stylelint-enable */
... ...
.yo-loading {
height: 80px;
background: resolve('loading.gif') #fff no-repeat center center;
background-size: 50px 20px;
}
.goods-container .yo-loading {
float: left;
width: 100%;
}
\ No newline at end of file
... ...
... ... @@ -2,6 +2,7 @@
@import '../layout/panel';
@import '../layout/swiper';
@import '../layout/yo-loading';
@import '../common/filter';
@import '../common/good';
@import 'new/recommend';
... ... @@ -15,6 +16,16 @@ body {
background-color: #f0f0f0;
}
.banner-swiper .swiper-slide {
height: 234px;
}
.swiper-slide img {
height: 100%;
width: 100%;
}
.goods-container {
overflow: hidden;
}
... ... @@ -35,11 +46,30 @@ body {
min-height: 193px;
}
#js-filter {
position: relative;
}
.filter-nav-wrap.sticky {
position: fixed;
top: 0;
width: 100%;
z-index: 2;
}
.filter-nav {
border-top: 1PX solid #dededf;
border-bottom: 1PX solid #dededf;
}
.filter-nav .iconfont {
color: #999;
}
.filter-nav .iconfont.cur {
color: inherit;
}
.banner-top {
border-bottom: 1PX solid #dededf;
margin-bottom: 30px;
... ...
... ... @@ -12,6 +12,7 @@
height: 176px;
background-color: #444;
border-radius: 8px;
overflow: hidden;
}
.swiper-slide-active {
... ...