Authored by ccbikai

Merge branch 'develop' into feature/home

/**
* 商品列表页
* @author chen xuan <xuan.chen@yoho.cn>
*/
const listModel = require('../models/list');
exports.index = (req, res) =>{
res.render('list');
};
/*
* 获取 商品列表
*/
exports.getProducts = (req, res, next)=>{
listModel.search()
.then(data=>{
res.json(data);
})
.catch(next);
};
// 进入某分类下的商品列表 页
exports.entryProducts = (req, res, next) => {
// TODO
};
/**
* 产品搜索 controller
* @author 陈轩 <xuan.chen@yoho.cn>
*/
'use strict';
const path = require('path');
const _ = require('lodash');
const api = global.yoho.API;
const camelCase = global.yoho.camelCase;
const prettyFilter = require(path.join(global.utils, '/beautify/filters'));
const processProductList = require(path.join(global.utils, '/beautify/product')).processProductList;
/* 搜索 页面 */
exports.index = (req, res) => {
const view = {
module: 'product',
page: 'search'
};
res.render('search', view);
};
/* 获取 筛选配置 */
exports.fetchFilters = (req, res, next) => {
const params = {
page: req.body.page || 1,
order: req.body.order || 1,
yh_channel: req.body.yh_channel || 'all',
channel: req.body.channel || 'all',
};
const data = _.merge({
method: 'app.search.sales',
}, params);
api.post('', data, {
cache: true,
code: 200
})
.then(result => {
let filterConfig = {};
prettyFilter(result.data.filter);
filterConfig = camelCase(result.data.filter);
res.json(filterConfig);
})
.catch(next);
};
/* 查询 产品列表 */
exports.fetchProducts = (req, res, next) => {
const params = {
page: req.body.page || 1,
order: req.body.order || 1,
yh_channel: req.body.yh_channel || 'all',
channel: req.body.channel || 'all',
};
const data = _.merge({
method: 'app.search.sales',
}, params);
api.post('', data, {
cache: true,
code: 200
})
.then(result => {
result.data.productList = processProductList(result.data.productList);
result = camelCase(result);
res.json(result);
})
.catch(next);
};
... ...
/**
* product list Model
*/
'use strict';
const path = require('path');
const api = global.yoho.API;
const camelCase = global.yoho.camelCase;
const prettyFilter = require(path.join(global.utils, '/beautify/filters'));
const processProductList = require(path.join(global.utils, '/beautify/product')).processProductList;
let list = {
/**
* 商品搜索
* @param {[type]} params [description]
* @return {[type]} [description]
*/
search(params) {
return api.post('', {
method: 'app.search.sales',
limit: 4,
saleType: 2,
yh_channel: 3
}, {
cache: true,
code: 200
})
.then(result => {
prettyFilter(result.data.filter);
result.data.productList = processProductList(result.data.productList);
result = camelCase(result);
return result;
});
},
getFilters(params) {
return api.post('', {
method: 'app.search.sales'
}, {
cache: true,
code: 200
})
.then(result => {
});
}
};
module.exports = list;
... ... @@ -9,18 +9,14 @@
const expressRouter = require('express').Router;
const cRoot = './controllers';
const productList = require(`${cRoot}/list`);
const router = expressRouter();
// 商品列表
router.use('/list', (req, res, next) => {
req.module = 'product';
req.page = 'list';
next();
});
router.get('/list', productList.index);
router.post('/list', productList.getProducts);
// 产品 搜索 页面
const search = require(`${cRoot}/search`);
router.get('/search', search.index);
router.post('/search', search.fetchProducts);
router.get('/filters.json', search.fetchFilters);
// 商品详情controller
const detail = require(`${cRoot}/detail`);
... ...
<div id="product-list">
<filter-sub :data="brand" :value="3" type="brand"></filter-sub>
<Sort :config.once="sortConfig" :val="sort">
</Sort>
<List :data="productList"></List>
<Drawer v-ref:drawer>
<Filter :config.once="filterConfig"></Filter>
</Drawer>
</div>
<script>
var sortConfig = [{
txt: '默认',
val: 1
}, {
txt: '最新',
val: 2
}, {
type: 'updown',
txt: '价格',
val: [3, 4]
}, //[up, down]
{
type: 'updown',
txt: '折扣',
val: [5, 6]
}
];
var filterConfig = {
"color": [{
"id": 11,
"name": "红色",
"value": "",
"code": "ee0000"
}, {
"id": 3,
"name": "灰色",
"value": "",
"code": "b9b7af"
}, {
"id": 7,
"name": "蓝色",
"value": "",
"code": "0000fe"
}],
"gender": [{
name: 'BOYS',
id: '1,3'
}, {
name: 'GIRLS',
id: '2,3'
}],
"size": [{
"name": "110",
"id": 326
}, {
"name": "120",
"id": 327
}, {
"name": "90",
"id": 186
}, {
"name": "100",
"id": 255
}, {
"name": "130",
"id": 333
}],
"discount": [{
count: 2,
name: '7~9',
id: '0.7,0.999'
}, {
count: 3,
name: '4~6',
id: '0.4,0.699'
}],
"brand": [{
"hotKeyword": "",
"domain": "smileyworldkids",
"dlif": "S",
"isHot": "Y",
"dco": "http://img10.static.yhbimg.com/brandLogo/2015/12/23/17/01088824d9ca36f91bb9265a3cc0cc25eb.jpg",
"name": "Smiley World Kids",
"keyword": "童装",
"id": 1069,
"nameEn": "Smiley World kids",
"nameCn": "Smiley World Kids"
},
{
"hotKeyword": "",
"domain": "smileyworldkids",
"alif": "S",
"isHot": "Y",
"ico": "http://img10.static.yhbimg.com/brandLogo/2015/12/23/17/01088824d9ca36f91bb9265a3cc0cc25eb.jpg",
"name": "Smiley World Kids",
"keyword": "童装",
"id": 1069,
"nameEn": "Smiley World kids",
"nameCn": "Smiley World Kids"
}
]
};
</script>
<div id="product-list"></div>
... ...
const Vue = require('yoho-vue');
const $ = require('yoho-jquery');
const qs = require('yoho-qs');
const search = require('product/search.vue');
$(function() {
const buildFilters = function() {
return $.get('filters.json', qs);
};
const buildSort = function() {
return [
{
txt: '默认',
val: 1
}, {
txt: '最新',
val: 2
}, {
type: 'updown',
txt: '价格',
val: [3, 4] // [up, down]
},
{
type: 'updown',
txt: '折扣',
val: [5, 6]
}
];
};
let app = new Vue(search);
buildFilters()
.then(filterConfig => {
app.filterConfig = filterConfig;
});
app.sortConfig = buildSort();
});
... ...
const Vue = require('yoho-vue');
const lazyload = require('yoho-vue-lazyload');
const infinitScroll = require('yoho-vue-infinite-scroll');
const bus = require('common/vue-bus');
const sort = require('product/sort.vue');
const list = require('product/list.vue');
const drawer = require('product/drawer.vue');
const filter = require('product/filter.vue');
const filterSub = require('product/filter/filter-detail.vue');
Vue.use(lazyload);
Vue.use(infinitScroll);
require('common/vue-filter');
const app = new Vue({
el: '#product-list',
data: function() {
return {
sortConfig: global.sortConfig,
filterConfig: global.filterConfig,
// query
url: 'list',
sort: 3,
filter: {},
page: 0, // page= 0 未搜索, 1 并且productList.length =0 没有数据, page = page_total 全部加载完
totalPage: 3,
// 产品列表
productList: [],
// state:
inSearching: false,
brand: require('product/filter/brand-group-mock')
};
},
components: {
list,
sort,
filter,
filterSub,
drawer
},
methods: {
search: function() {
const self = this;
if (this.inSearching) {
return;
}
if (this.page && this.page + 1 > this.totalPage) {
return;
}
this.inSearching = true;
this.page++;
$.post(this.url, {
sort: this.sort,
filter: this.filter,
page: this.page
})
<template>
<div>
<filter-sub :data="brand" :value="3" type="brand"></filter-sub>
<Sort :config="sortConfig" :val="sort">
</Sort>
<List :data="productList"></List>
<Drawer v-ref:drawer>
<Filter :config="filterConfig"></Filter>
</Drawer>
</div>
</template>
<script>
const Vue = require('yoho-vue');
const lazyload = require('yoho-vue-lazyload');
const infinitScroll = require('yoho-vue-infinite-scroll');
const bus = require('common/vue-bus');
const tip = require('common/tip');
const sort = require('product/sort.vue');
const list = require('product/list.vue');
const drawer = require('product/drawer.vue');
const filter = require('product/filter.vue');
const filterSub = require('product/filter/filter-detail.vue');
Vue.use(lazyload);
Vue.use(infinitScroll);
require('common/vue-filter');
module.exports = {
el: '#product-list',
data: function() {
return {
sortConfig: global.sortConfig,
filterConfig: global.filterConfig,
// query
url: 'search',
sort: null,
filter: {},
page: 0, // 未搜索 page=0; 全部加载完 page = totalPage; 无数据: page !=0 && productList.length=0
totalPage: null,
// 产品列表
productList: [],
// state
inSearching: false, // 请求中
brand: require('product/filter/brand-group-mock')
};
},
components: {
list,
sort,
filter,
filterSub,
drawer
},
methods: {
search: function() {
const self = this;
const nextPage = this.page + 1;
if (this.inSearching) {
return;
}
// page = 0, 始终执行搜索
if (this.page && nextPage > this.totalPage) {
return;
}
this.inSearching = true;
console.log(nextPage);
$.post(this.url, {
sort: this.sort,
filter: this.filter,
page: nextPage
})
.done(res => {
self.page = res.data.page;
self.totalPage = res.data.pageTotal;
self.$set('productList', self.productList.concat(res.data.productList));
})
.fail(error => {
self.page--;
console.log(error);
tip('网络出错~');
})
.always(() => {
self.inSearching = false;
});
},
openFilterSub: function() {
console.log('TODO: open filter sub');
},
/**
* 清空数据(page=0) 重新搜索
*/
research: function() {
this.page = 0;
this.$set('productList', []);
this.search();
}
},
openFilterSub: function() {
console.log('TODO: open filter sub');
watch: {
/* sort 和 filter 改变 都会触发 重新搜索 */
sort: function() {
this.research();
},
filter: function() {
this.research();
}
},
/**
*
*/
research: function() {
this.page = 0;
this.$set('productList', []);
created: function() {
const self = this;
bus.$on('list.paging', function() {
self.search();
});
bus.$on('sort.change', function({
val
}) {
console.log(val);
self.sort = val;
});
/**
* 筛选组件 筛选值变更,触发 filter.change事件
* 1. 重新搜索
* 2. 关闭 drawer 组件
*/
bus.$on('filter.change', function({
val
}) {
console.log(val);
self.filter = val;
self.$refs.drawer.on = false;
});
/**
* 筛选组件 打开二级晒寻,通过bridge 打开APP view
* 1. 打开view
* 2. 监听 router.back ,重新设置 筛选值
*/
bus.$on('filter.sub.show', function({
val
}) {
self.openFilterSub(val);
});
this.search();
}
},
watch: {
/* sort 和 filter 改变 都会触发 重新搜索 (想象成清空所有分页) */
sort: function() {
this.research();
},
filter: function() {
this.research();
}
},
created: function() {
this.search();
}
});
bus.$on('list.paging', function() {
app.search();
});
bus.$on('sort.change', function({ val }) {
console.log(val);
app.sort = val;
});
/**
* 筛选组件 筛选值变更,触发 filter.change事件
* 1. 重新搜索
* 2. 关闭 drawer 组件
*/
bus.$on('filter.change', function({ val }) {
console.log(val);
app.filter = val;
app.$refs.drawer.on = false;
});
/**
* 筛选组件 打开二级晒寻,通过bridge 打开APP view
* 1. 打开view
* 2. 监听 router.back ,重新设置 筛选值
*/
bus.$on('filter.sub.show', function({val}) {
app.openFilterSub(val);
});
};
</script>
<style>
</style>
... ...
... ... @@ -110,3 +110,17 @@ function prettyFilter(filters) {
module.exports = prettyFilter;
/*
filter Object经过 prettyFilter, camelCase 后的 数据格式:
{
color: [{id,name,value, code}],
gender: [{id,name}],
size: [id,name],
discount: [{id,name,count}],
priceRange: [{id, name}],
ageLevel: [{id,name, productCount}]
brand: [{id, name,domain,alif,ico,keyword,hotKeyword,isHot, nameEn, nameCn}]
groupSort,
}
*/
... ...