Authored by 周少峰

Merge branch 'feature/channel-op' into gray

Too many changes to show.

To preserve performance only 18 of 18+ files are displayed.

... ... @@ -8,14 +8,14 @@
const _ = require('lodash');
const channelModel = require('../models/index');
const ChannelModel = require('../models/index');
exports.index = (req, res, next) => {
let channelType = req.path.split('/')[1] || 'boys';
let poolId = req.query.template_id;
let isJKChannel = req.query.mChannel === 'japanKorean';
channelModel.getContent(channelType, isJKChannel, poolId).then(data => {
req.ctx(ChannelModel).getContent(channelType, isJKChannel, poolId).then(data => {
// channel为空不缓存
if (_.isEmpty(data.channel)) {
... ... @@ -28,7 +28,7 @@ exports.index = (req, res, next) => {
// 日韩馆频道页
exports.japanKorean = (req, res, next) => {
channelModel.getJKContent(req).then(data => {
req.ctx(ChannelModel).getJKContent(req).then(data => {
// channel为空不缓存
if (_.isEmpty(data.channel)) {
... ... @@ -55,7 +55,7 @@ exports.getNewArrival = (req, res, next) => {
pageCount = 20;
}
channelModel.getNewArrival(channel, isJKChannel, poolId).then(data => {
req.ctx(ChannelModel).getNewArrival(channel, isJKChannel, poolId).then(data => {
goods = _.slice(data, pageIndex, pageIndex + pageCount);
if (goods.length !== 0) {
... ... @@ -69,15 +69,15 @@ exports.getNewArrival = (req, res, next) => {
};
exports.getIndexGuide = (req, res, next) => {
channelModel.getIndexGuideData().then(data => {
req.ctx(ChannelModel).getIndexGuideData().then(data => {
if (data.code !== 200) {
const err = new Error('异常');
throw err;
}
return channelModel.formatIndexGuideData(data.data);
return req.ctx(ChannelModel).formatIndexGuideData(data.data);
}).then(data => {
return channelModel.getResourceData(data);
return req.ctx(ChannelModel).getResourceData(data);
}).then(data => {
let result = {list: data, layout: false};
... ... @@ -87,7 +87,7 @@ exports.getIndexGuide = (req, res, next) => {
exports.hasNewUserFloor = (req, res, next) => {
channelModel.hasNewUserFloor(req.yoho.channel, req.user.uid).then(data => {
req.ctx(ChannelModel).hasNewUserFloor(req.yoho.channel, req.user.uid).then(data => {
res.send(data);
}).catch(next);
};
... ...
... ... @@ -13,1332 +13,1338 @@ const helpers = global.yoho.helpers;
const config = global.yoho.config;
const processProduct = require(`${global.utils}/product-process`).processProduct;
const searchApi = require('./search-api');
const api = global.yoho.API;
const serviceApi = global.yoho.ServiceAPI;
const SearchApi = require('./search-api');
const headerModel = require('../../../doraemon/models/header');
// 获取可用的标题
const _getText = data => {
let text = data.split(' ')[0];
const regResult = /\w+/.exec(text);
const titleWithoutChinese = /^(?=.*[A-Za-z0-9])[A-Za-z0-9 _]*$/;
// 对于不含中文的标题,直接返回
if (titleWithoutChinese.test(data)) {
return data;
}
if (regResult) {
// 去掉标题中的英文部分
text = text.replace(regResult[0], '');
}
return text;
const needQuery = {
'GIRL KIDS': true,
'BOY KIDS': true,
人气单品: true,
ACCESSORIES: true
};
const channelMap = dataMap.channel;
const sortMap = dataMap.sort;
/**
* 新人专享
* @param {[Object]} data 原始数据
* @return {[Object]} 转换后的数据
*/
const _getNewUserFloorData = data => {
let floorData = {
newUserFloor: {
name: _getText(data.title.name),
navs: {},
bannerImage: {
url: data.banner_image[0].url,
src: helpers.image(data.banner_image[0].src, 1150, 368),
title: data.banner_image[0].title
}
}
};
if (data.title.more_name) {
floorData.newUserFloor.navs.name = data.title.more_name;
}
if (data.title.more_url) {
floorData.newUserFloor.navs.url = data.title.more_url;
module.exports = class extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
this.searchApi = new SearchApi(ctx);
this.floorMap = {
slide: this._getSlideData.bind(this),
hot: this._getHotGoodsFloorData.bind(this),
最新速报: this._getNewReportFloorData.bind(this),
人气单品: this._getSingleHotFloorData.bind(this),
'GIRL KIDS': this._getSingleHotFloorData.bind(this),
'BOY KIDS': this._getSingleHotFloorData.bind(this),
ACCESSORIES: this._getSingleHotFloorData.bind(this),
优选品牌: this._getPreBrandTopData.bind(this),
最新上架: this._getNewGoodsFloorData.bind(this),
ad: this._getadbannerData.bind(this),
category: this._getCategoryFloorData.bind(this),
accordion: this._getAccordionFloorData.bind(this),
debrisSlide: this._getDebrisSlide.bind(this),
jacket: this._getJacketData.bind(this),
sevenCategory: this._getClothesCategory.bind(this),
floorTitle: this._getFloorTitleData.bind(this),
newuser: this._getNewUserFloorData.bind(this)
};
}
if (data.list) {
let proList = [];
// 大于15就取前15个产品数
proList = data.list.length > 15 ? data.list.slice(0, 15) : data.list;
// 5个以内为false
floorData.newUserFloor.hasSwitch = proList.length > 5 ? true : false;
_.forEach(proList, value => {
value.thumb = helpers.image(value.goods_list[0].images_url, 185, 247);
value.for_newuser = true;
value.url = helpers.getUrlBySkc(value.product_skn);
});
floorData.newUserFloor.list = proList;
}
// 获取可用的标题
_getText(data) {
let text = data.split(' ')[0];
const regResult = /\w+/.exec(text);
const titleWithoutChinese = /^(?=.*[A-Za-z0-9])[A-Za-z0-9 _]*$/;
// 对于不含中文的标题,直接返回
if (titleWithoutChinese.test(data)) {
return data;
}
return floorData;
};
if (regResult) {
/**
* 获取带小图的banner
* @param {[Object]} data 原始数据
* @return {[Object]} 转换后的数据
*/
const _getDebrisSlide = data => {
let floorData = {
debrisSlider: {
left: [],
center: [],
right: []
// 去掉标题中的英文部分
text = text.replace(regResult[0], '');
}
};
_.mapKeys(data, (value, key) => {
_.forEach(value, slideData => {
floorData.debrisSlider[key].push(slideData);
});
});
return text;
}
return floorData;
};
/**
* 新人专享
* @param {[Object]} data 原始数据
* @return {[Object]} 转换后的数据
*/
_getNewUserFloorData(data) {
let floorData = {
newUserFloor: {
name: this._getText(data.title.name),
navs: {},
bannerImage: {
url: data.banner_image[0].url,
src: helpers.image(data.banner_image[0].src, 1150, 368),
title: data.banner_image[0].title
}
}
};
if (data.title.more_name) {
floorData.newUserFloor.navs.name = data.title.more_name;
}
if (data.title.more_url) {
floorData.newUserFloor.navs.url = data.title.more_url;
}
if (data.list) {
let proList = [];
/**
* 获取广告位
* @param {Object} data 原始数据
* @return {Object} 转换后的数据
*/
const _getadbannerData = data => {
// 大于15就取前15个产品数
proList = data.list.length > 15 ? data.list.slice(0, 15) : data.list;
return {
adbanner: data
};
};
// 5个以内为false
floorData.newUserFloor.hasSwitch = proList.length > 5 ? true : false;
/**
* 生成banner模板数据
* @param {Object} srcData 原始数据
* @return {Object} 转换后的数据
*/
const _getSlideData = srcData => {
const slideData = {
slide: {
list: [],
pagination: []
_.forEach(proList, value => {
value.thumb = helpers.image(value.goods_list[0].images_url, 185, 247);
value.for_newuser = true;
value.url = helpers.getUrlBySkc(value.product_skn);
});
floorData.newUserFloor.list = proList;
}
};
if (srcData.big_image) {
slideData.slide.list = srcData.big_image;
return floorData;
}
if (srcData.list) {
slideData.slide.pagination = srcData.list;
}
/**
* 获取带小图的banner
* @param {[Object]} data 原始数据
* @return {[Object]} 转换后的数据
*/
_getDebrisSlide(data) {
let floorData = {
debrisSlider: {
left: [],
center: [],
right: []
}
};
if (_.isArray(srcData)) {
slideData.slide.list = srcData;
_.mapKeys(data, (value, key) => {
_.forEach(value, slideData => {
floorData.debrisSlider[key].push(slideData);
});
});
return floorData;
}
return slideData;
};
/**
* 获取品牌列表数据
* @param {[Object]} args 参数列表
* @param {String} type 频道类型
* @return {Object}
*/
const _getBrandLogosData = (args, showNum) => {
let items = [],
brandLogos = [],
i = 0,
fillNum = 0;
// 品牌数据
_.forEach(args, (floorData) => {
items.push({
href: floorData.url,
img: helpers.image(floorData.src, 185, 86, 2)
});
});
/**
* 获取广告位
* @param {Object} data 原始数据
* @return {Object} 转换后的数据
*/
_getadbannerData(data) {
// 不是每页显示个数的倍数,填充数据
if (items.length % showNum !== 0) {
fillNum = showNum - (items.length % showNum);
for (i = 0; i < fillNum; i++) {
items.push({
href: 'javascript:;', // eslint-disable-line
img: ''
});
}
return {
adbanner: data
};
}
for (i = 0; i < items.length; i++) {
let item = items[i];
let brandLogo = {
pageNum: Math.floor(i / showNum),
href: item.href,
img: item.img
/**
* 生成banner模板数据
* @param {Object} srcData 原始数据
* @return {Object} 转换后的数据
*/
_getSlideData(srcData) {
const slideData = {
slide: {
list: [],
pagination: []
}
};
if (i % showNum === 5 || i === 5) {
if (srcData.big_image) {
slideData.slide.list = srcData.big_image;
}
// 插入切换按钮的位置
brandLogo.isSwitch = true;
} else if (i !== 0 && i % showNum === 0) {
if (srcData.list) {
slideData.slide.pagination = srcData.list;
}
// 插入more的位置,more占的是下一页第一个brand的位置,所以page是i/17
brandLogo.morePageNum = Math.floor(i / (showNum + 1));
brandLogo.isMore = true;
brandLogo.hasNext = true;
} else {
brandLogo.isBrand = true;
if (_.isArray(srcData)) {
slideData.slide.list = srcData;
}
brandLogos.push(brandLogo);
return slideData;
}
brandLogos.push({
morePageNum: Math.floor(i / (showNum + 1)),
isMore: true
});
return brandLogos;
};
/**
* 获取最新速报模板数据 : 大图+小图+大图+single_image(广告位)/+floor(logo列表)
* @param {Object} srcData 原始数据
* @return {Object} 转换后的数据
*/
const _getNewReportFloorData = (args) => {
const title = args[0].data.text;
let floorId = args[0].template_id;
let item = args[1].data;
let secondItem = args[2].data;
let thirdItem = args[3].data;
let forthItem = args[4] || {};
let brandLogoObj = {showNum: 10};
let list = [];
const data = {
newReport: {
name: title,
floorId: floorId,
list: []
}
};
/**
* 获取品牌列表数据
* @param {[Object]} args 参数列表
* @param {String} type 频道类型
* @return {Object}
*/
_getBrandLogosData(args, showNum) {
let items = [],
brandLogos = [],
i = 0,
fillNum = 0;
// 品牌数据
_.forEach(args, (floorData) => {
items.push({
href: floorData.url,
img: helpers.image(floorData.src, 185, 86, 2)
});
});
let adData;
let floorDatas = [];
list.push(item[0]);
// 不是每页显示个数的倍数,填充数据
if (items.length % showNum !== 0) {
fillNum = showNum - (items.length % showNum);
for (i = 0; i < fillNum; i++) {
items.push({
href: 'javascript:;', // eslint-disable-line
img: ''
});
}
}
_.forEach(secondItem, (floorData) => {
list.push(floorData);
});
for (i = 0; i < items.length; i++) {
let item = items[i];
list.push(thirdItem[0]);
let brandLogo = {
pageNum: Math.floor(i / showNum),
href: item.href,
img: item.img
};
data.newReport.list = list;
if (i % showNum === 5 || i === 5) {
floorDatas.push(data);
// 插入切换按钮的位置
brandLogo.isSwitch = true;
} else if (i !== 0 && i % showNum === 0) {
// 广告位
if (forthItem.template_name && forthItem.template_name === 'single_image') {
adData = _getadbannerData(forthItem.data[0]);
floorDatas.push(adData);
}
// 插入more的位置,more占的是下一页第一个brand的位置,所以page是i/17
brandLogo.morePageNum = Math.floor(i / (showNum + 1));
brandLogo.isMore = true;
brandLogo.hasNext = true;
} else {
brandLogo.isBrand = true;
}
// logo列表
if (forthItem.template_name && forthItem.template_name === 'floor') {
// 品牌数据
if (_.get(args[5], 'data[0].url', '')) {
brandLogoObj.moreBrand = args[5].data[0].url || '';
brandLogos.push(brandLogo);
}
brandLogoObj.brandLogos = _getBrandLogosData(forthItem.data, brandLogoObj.showNum);
data.newReport.brandLogoObj = brandLogoObj;
brandLogos.push({
morePageNum: Math.floor(i / (showNum + 1)),
isMore: true
});
return brandLogos;
}
return floorDatas;
};
/**
* 获取最新速报模板数据 : 大图+小图+大图+single_image(广告位)/+floor(logo列表)
* @param {Object} srcData 原始数据
* @return {Object} 转换后的数据
*/
_getNewReportFloorData(args) {
const title = args[0].data.text;
let floorId = args[0].template_id;
let item = args[1].data;
let secondItem = args[2].data;
let thirdItem = args[3].data;
let forthItem = args[4] || {};
let brandLogoObj = {showNum: 10};
let list = [];
const data = {
newReport: {
name: title,
floorId: floorId,
list: []
}
};
/**
* 给目标对象绑定频道属性
* @param {Object} obj 需要绑定频道属性的对象
* @param {String} type 需要设置的频道类型
* @return undefined
*/
const _setChannelType = (obj, type) => {
obj[type + 'Channel'] = true;
};
/**
* 获取优选品牌模板数据
* @param {[Object]} args 参数列表
* @param {String} type 频道类型
* @return {Object}
*/
const _getPreBrandTopData = (args, type) => {
const title = args[0].data.text;
let item = args[1].data,
logoItems = args[2] || {},
showNum = type === 'boys' ? 16 : 10;
let adData;
let floorDatas = [];
list.push(item[0]);
let brandLogoObj = {showNum: showNum};
_.forEach(secondItem, (floorData) => {
list.push(floorData);
});
const data = {
preferenceBrands: {
name: title,
imgBrand: []
}
};
list.push(thirdItem[0]);
// logo列表
if (logoItems) {
// 品牌数据
if (_.get(args[3], 'data[0].url', '')) {
brandLogoObj.moreBrand = args[3].data[0].url;
}
brandLogoObj.brandLogos = _getBrandLogosData(args[2].data, showNum);
data.preferenceBrands.brandLogoObj = brandLogoObj;
}
data.preferenceBrands.imgBrand = item;
if (type === 'kids') {
data.preferenceBrands.sliderColor = '#7AD3F8';
}
_setChannelType(data.preferenceBrands, type);
data.newReport.list = list;
return data;
};
floorDatas.push(data);
/**
* 获取热门分类模板数据
* @param {[Object]} args 参数列表
* @param {String} type 频道类型
* @return {Object}
*/
const _getHotGoodsFloorData = (args, type) => {
let item = args[0];
let nextItem = args[1];
let list = [];
let object = {},
keyword = [],
category = [],
brands = [],
types = [],
products = [];
const data = {
recommend: {
tplrecommend: []
// 广告位
if (forthItem.template_name && forthItem.template_name === 'single_image') {
adData = this._getadbannerData(forthItem.data[0]);
floorDatas.push(adData);
}
};
category = item.data.menuNav.list;
keyword = item.data.menuNav.blocks;
_.forEach(item.data.imgs, (it, idx) => {
// logo列表
if (forthItem.template_name && forthItem.template_name === 'floor') {
// 品牌数据
if (_.get(args[5], 'data[0].url', '')) {
brandLogoObj.moreBrand = args[5].data[0].url || '';
}
if (idx === 0 || (idx === 4 && type === 'boys')) {
brands.push(it);
} else {
types.push(it);
brandLogoObj.brandLogos = this._getBrandLogosData(forthItem.data, brandLogoObj.showNum);
data.newReport.brandLogoObj = brandLogoObj;
}
});
products = nextItem.data;
object.name = item.data.name;
object.keyword = keyword;
object.category = category;
object.brands = brands;
object.types = types;
object.navs = item.data.navs.list;
object.products = products;
list.push(object);
data.recommend.tplrecommend = list;
_setChannelType(data.recommend, type);
return data;
};
return floorDatas;
}
/**
* 获取japanKorean潮流上装Jacket,title+左大图+右6小图模板数据
* @param {[Object]} args 参数列表
* @param {String} type 频道类型
* @return {Object}
*/
const _getJacketData = (arg) => {
let resData = {
tpltopic: {
bigPic: arg.big_image[0],
types: arg.list
}
};
if (arg.title.title !== '') {
resData.tpltopic.title = arg.title;
/**
* 给目标对象绑定频道属性
* @param {Object} obj 需要绑定频道属性的对象
* @param {String} type 需要设置的频道类型
* @return undefined
*/
_setChannelType(obj, type) {
obj[type + 'Channel'] = true;
}
return resData;
};
/**
* 获取优选品牌模板数据
* @param {[Object]} args 参数列表
* @param {String} type 频道类型
* @return {Object}
*/
_getPreBrandTopData(args, type) {
const title = args[0].data.text;
let item = args[1].data,
logoItems = args[2] || {},
showNum = type === 'boys' ? 16 : 10;
let brandLogoObj = {showNum: showNum};
const data = {
preferenceBrands: {
name: title,
imgBrand: []
}
};
/**
* 获取7个品类图
* @param {[Object]} args 参数列表
* @param {String} type 频道类型
* @return {Object}
*/
const _getClothesCategory = (arg) => {
return {
sevenCategory: {
categorys: arg.list
// logo列表
if (logoItems) {
// 品牌数据
if (_.get(args[3], 'data[0].url', '')) {
brandLogoObj.moreBrand = args[3].data[0].url;
}
brandLogoObj.brandLogos = this._getBrandLogosData(args[2].data, showNum);
data.preferenceBrands.brandLogoObj = brandLogoObj;
}
};
};
/**
* 获取boys人气单品模版数据
* @param {[Object]} args 参数列表
* @param {String} type 频道类型
* @return {Object}
*/
const _getBoysSingleHot = (args, type) => {
const len = 10;
const data = {
singlehot: {
name: args[0].data.text,
imgHot: []
data.preferenceBrands.imgBrand = item;
if (type === 'kids') {
data.preferenceBrands.sliderColor = '#7AD3F8';
}
};
this._setChannelType(data.preferenceBrands, type);
let list = [];
let adData;
let floorDatas = [];
for (let i = 0; i < len; i++) {
let pos = i;
let val = {};
return data;
}
if (i === 1) {
val = args[1].data[0]; // 第二个是大图
} else if (i === len - 1) {
val = args[1].data[1]; // 最后一个是大图
} else {
if (pos > 1) { // 小图
pos = pos - 1;
/**
* 获取热门分类模板数据
* @param {[Object]} args 参数列表
* @param {String} type 频道类型
* @return {Object}
*/
_getHotGoodsFloorData(args, type) {
let item = args[0];
let nextItem = args[1];
let list = [];
let object = {},
keyword = [],
category = [],
brands = [],
types = [],
products = [];
const data = {
recommend: {
tplrecommend: []
}
val = args[2].data[pos];
}
list.push(val);
}
};
_.forEach(list, (item, index) => {
if (index === 1 || index === list.length - 1) {
item.big = true;
}
});
category = item.data.menuNav.list;
data.singlehot.imgHot = list;
_setChannelType(data.singlehot, type);
floorDatas.push(data);
keyword = item.data.menuNav.blocks;
if (args[3].template_name === 'single_image') {
adData = _getadbannerData(args[3].data[0]);
floorDatas.push(adData);
}
_.forEach(item.data.imgs, (it, idx) => {
return floorDatas;
};
if (idx === 0 || (idx === 4 && type === 'boys')) {
brands.push(it);
} else {
types.push(it);
}
});
/**
* 获取girls人气单品模版数据
* @param {[Object]} args 参数列表
* @param {String} type 频道类型
* @return {Object}
*/
const _getGirlsSingleHot = (args, type) => {
let goods = args[2] && args[2].data;
let skns = '';
products = nextItem.data;
if (goods) {
_.forEach(goods, good => {
skns += good.id + ' ';
});
} else {
return;
}
object.name = item.data.name;
object.keyword = keyword;
object.category = category;
object.brands = brands;
object.types = types;
object.navs = item.data.navs.list;
object.products = products;
list.push(object);
data.recommend.tplrecommend = list;
return searchApi.getProductList({
client_type: 'web',
query: skns,
order: 'shelve_time:desc',
status: 1,
sales: 'Y',
attribute_not: '2',
stocknumber: 1,
page: 1,
gender: channelMap[type].gender,
limit: 60
}, config.apiCache);
};
this._setChannelType(data.recommend, type);
/**
* 人气单品入口
* @param {[Object]} args 参数列表
* @param {String} type 频道类型
* @return {Object}
*/
const _getSingleHotFloorData = (args, type) => {
if (type === 'boys') {
return _getBoysSingleHot(args, type);
} else {
return _getGirlsSingleHot(args, type);
return data;
}
};
/**
* 组装最新上架楼层数据
*
* @param string data
* return obj
*/
const _getNewGoodsFloorData = args => {
const data = {};
if (!_.isEmpty(args)) {
data.newArrivls = {
floorId: args[0].template_id,
name: _.replace(args[0].data.text, '最新', '新品'),
navs: []
/**
* 获取japanKorean潮流上装Jacket,title+左大图+右6小图模板数据
* @param {[Object]} args 参数列表
* @param {String} type 频道类型
* @return {Object}
*/
_getJacketData(arg) {
let resData = {
tpltopic: {
bigPic: arg.big_image[0],
types: arg.list
}
};
data.newArrivls.navs = args[1] ? args[1].data : {};
}
return data;
};
if (arg.title.title !== '') {
resData.tpltopic.title = arg.title;
}
/**
* 文本标题
* @param {[Object]} args 参数列表
* @param {String} type 频道类型
* @return {Object}
*/
const _getFloorTitleData = (args) => {
let resData = {
floorHeader: {}
};
if (args instanceof Array) {
resData.floorHeader.name = args[0].data.text;
resData.floorHeader.navs = args[1].data;
resData.floorHeader.floorId = args[0].template_id;
} else {
resData.floorHeader.name = args.data.text;
resData.floorHeader.floorId = args.template_id;
return resData;
}
if (resData.floorHeader.name.indexOf('最新上架') >= 0) {
resData = _getNewGoodsFloorData(args);
/**
* 获取7个品类图
* @param {[Object]} args 参数列表
* @param {String} type 频道类型
* @return {Object}
*/
_getClothesCategory(arg) {
return {
sevenCategory: {
categorys: arg.list
}
};
}
return resData;
};
/**
* 处理异步获取的人气单品数据
* @param {[Object]} args 参数列表
* @param {String} originQuery 原始skns
* @param {Object} queryResult 异步获取的数据
* @param {String} type 频道类型
* @return {Object}
*/
const _getSingehotViaResult = (args, originQuery, queryResult, type) => {
let data = {
singlehot: {
name: args[0].data.text,
navs: [],
imgHot: [],
brands: []
}
};
/**
* 获取boys人气单品模版数据
* @param {[Object]} args 参数列表
* @param {String} type 频道类型
* @return {Object}
*/
_getBoysSingleHot(args, type) {
const len = 10;
const data = {
singlehot: {
name: args[0].data.text,
imgHot: []
}
};
let pos = 0;
let list = [];
let adData;
let floorDatas = [];
for (let i = 0; i < len; i++) {
let pos = i;
let val = {};
if (i === 1) {
val = args[1].data[0]; // 第二个是大图
} else if (i === len - 1) {
val = args[1].data[1]; // 最后一个是大图
} else {
if (pos > 1) { // 小图
pos = pos - 1;
}
val = args[2].data[pos];
}
list.push(val);
}
_.forEach(list, (item, index) => {
if (index === 1 || index === list.length - 1) {
item.big = true;
}
});
const getIndex = skn => {
let index;
data.singlehot.imgHot = list;
this._setChannelType(data.singlehot, type);
floorDatas.push(data);
if (args[3].template_name === 'single_image') {
adData = this._getadbannerData(args[3].data[0]);
floorDatas.push(adData);
}
if (originQuery) {
const originQueryArr = originQuery.split(' ');
let setFlag = false;
return floorDatas;
}
_.forEach(originQueryArr, (query, idx) => {
if (!setFlag && query.toString() === skn.toString()) {
index = idx;
setFlag = true;
}
/**
* 获取girls人气单品模版数据
* @param {[Object]} args 参数列表
* @param {String} type 频道类型
* @return {Object}
*/
_getGirlsSingleHot(args, type) {
let goods = args[2] && args[2].data;
let skns = '';
if (goods) {
_.forEach(goods, good => {
skns += good.id + ' ';
});
} else {
return;
}
return index;
};
if (args[3].template_name === 'app_icon_list') {
data.singlehot.brands = args[3].data;
return this.searchApi.getProductList({
client_type: 'web',
query: skns,
order: 'shelve_time:desc',
status: 1,
sales: 'Y',
attribute_not: '2',
stocknumber: 1,
page: 1,
gender: channelMap[type].gender,
limit: 60
}, config.apiCache);
}
if (queryResult.data) {
_.forEach(queryResult.data.product_list || [], it => {
const formatData = processProduct(it, {
width: 280,
height: 373,
gender: channelMap[type].gender
});
if (pos > 11) {
return;
}
/**
* 人气单品入口
* @param {[Object]} args 参数列表
* @param {String} type 频道类型
* @return {Object}
*/
_getSingleHotFloorData(args, type) {
if (type === 'boys') {
return this._getBoysSingleHot(args, type);
} else {
return this._getGirlsSingleHot(args, type);
}
}
if (it.product_id) {
formatData.idx = getIndex(it.product_skn);
if (formatData.idx === 0 || formatData.idx) {
data.singlehot.imgHot.push(formatData);
pos += 1;
}
}
});
/**
* 组装最新上架楼层数据
*
* @param string data
* return obj
*/
_getNewGoodsFloorData(args) {
const data = {};
if (!_.isEmpty(args)) {
data.newArrivls = {
floorId: args[0].template_id,
name: _.replace(args[0].data.text, '最新', '新品'),
navs: []
};
data.newArrivls.navs = args[1] ? args[1].data : {};
}
return data;
}
data.singlehot.imgHot = _.sortBy(data.singlehot.imgHot, item => {
return item.idx;
});
/**
* 文本标题
* @param {[Object]} args 参数列表
* @param {String} type 频道类型
* @return {Object}
*/
_getFloorTitleData(args) {
let resData = {
floorHeader: {}
};
pos = 1;
_.forEach(data.singlehot.imgHot, item => {
if (pos < 4 && item) {
item.tip = 'TOP' + pos;
pos += 1;
if (args instanceof Array) {
resData.floorHeader.name = args[0].data.text;
resData.floorHeader.navs = args[1].data;
resData.floorHeader.floorId = args[0].template_id;
} else {
resData.floorHeader.name = args.data.text;
resData.floorHeader.floorId = args.template_id;
}
});
data.singlehot.navs = args[1].data;
_setChannelType(data.singlehot, type);
return data;
};
/**
* 异步获取人气单品
* @param {[Object]} rawData 接口返回的原始数据
* @param {[Object]} floorData 已经经过处理的楼层数据
* @param {String} originQuery 原始的query数据
* @param {Object} queryResult 接口中用于请求人气单品的数据
* @param {String} title 人气单品楼层的标题
* @param {Type} type 人气单品楼层的类型
* @return {Object}
*/
const _processFloorDataWithQueryReusult = (rawData, originQuery, queryResult, title, type) => {
let data = {};
_.forEach(rawData, (subData, index) => {
if (resData.floorHeader.name.indexOf('最新上架') >= 0) {
resData = this._getNewGoodsFloorData(args);
}
return resData;
}
if (subData && subData.data && subData.data.text) {
const text = subData.data.text && _getText(subData.data.text);
/**
* 处理异步获取的人气单品数据
* @param {[Object]} args 参数列表
* @param {String} originQuery 原始skns
* @param {Object} queryResult 异步获取的数据
* @param {String} type 频道类型
* @return {Object}
*/
_getSingehotViaResult(args, originQuery, queryResult, type) {
let data = {
singlehot: {
name: args[0].data.text,
navs: [],
imgHot: [],
brands: []
}
};
let pos = 0;
if (text === title) {
data = _getSingehotViaResult(rawData.slice(index, index + 4), originQuery, queryResult, type);
}
}
});
return data;
};
const getIndex = skn => {
let index;
if (originQuery) {
const originQueryArr = originQuery.split(' ');
let setFlag = false;
const _getCategoryFloorData = args => {
const data = {
category: {
name: args[0].data.text,
navs: args[1].data,
list: []
}
};
_.forEach(originQueryArr, (query, idx) => {
if (!setFlag && query.toString() === skn.toString()) {
index = idx;
setFlag = true;
}
});
}
_.forEach(args[2].data, (it, index) => {
return index;
};
// 设置图片大小
if (index === 1) {
it.w = '377;';
it.h = '504;';
} else {
it.w = '185';
it.h = '510';
if (args[3].template_name === 'app_icon_list') {
data.singlehot.brands = args[3].data;
}
data.category.list.push(it);
});
if (queryResult.data) {
_.forEach(queryResult.data.product_list || [], it => {
const formatData = processProduct(it, {
width: 280,
height: 373,
gender: channelMap[type].gender
});
return data;
};
if (pos > 11) {
return;
}
const _getAccordionFloorData = args => {
let data = {
accordion: {
name: args[0].data.text,
navs: args[1].data,
slide: []
if (it.product_id) {
formatData.idx = getIndex(it.product_skn);
if (formatData.idx === 0 || formatData.idx) {
data.singlehot.imgHot.push(formatData);
pos += 1;
}
}
});
}
};
data.accordion.slide = args[2].data;
return data;
};
data.singlehot.imgHot = _.sortBy(data.singlehot.imgHot, item => {
return item.idx;
});
const _requestContent = (type, params, code) => {
let data = {
client_type: 'web',
content_code: code || channelMap[type || 'boys'].code,
gender: channelMap[type || 'boys'].gender,
page: 1,
limit: 1000
};
Object.assign(data, params);
return serviceApi.get('operations/api/v5/resource/home', data, {
cache: true,
code: 200
}).then(result => {
return result;
});
};
pos = 1;
_.forEach(data.singlehot.imgHot, item => {
if (pos < 4 && item) {
item.tip = 'TOP' + pos;
pos += 1;
}
});
data.singlehot.navs = args[1].data;
this._setChannelType(data.singlehot, type);
return data;
}
const floorMap = {
slide: _getSlideData,
hot: _getHotGoodsFloorData,
最新速报: _getNewReportFloorData,
人气单品: _getSingleHotFloorData,
'GIRL KIDS': _getSingleHotFloorData,
'BOY KIDS': _getSingleHotFloorData,
ACCESSORIES: _getSingleHotFloorData,
优选品牌: _getPreBrandTopData,
最新上架: _getNewGoodsFloorData,
ad: _getadbannerData,
category: _getCategoryFloorData,
accordion: _getAccordionFloorData,
debrisSlide: _getDebrisSlide,
jacket: _getJacketData,
sevenCategory: _getClothesCategory,
floorTitle: _getFloorTitleData,
newuser: _getNewUserFloorData
};
/**
* 异步获取人气单品
* @param {[Object]} rawData 接口返回的原始数据
* @param {[Object]} floorData 已经经过处理的楼层数据
* @param {String} originQuery 原始的query数据
* @param {Object} queryResult 接口中用于请求人气单品的数据
* @param {String} title 人气单品楼层的标题
* @param {Type} type 人气单品楼层的类型
* @return {Object}
*/
_processFloorDataWithQueryReusult(rawData, originQuery, queryResult, title, type) {
let data = {};
_.forEach(rawData, (subData, index) => {
const needQuery = {
'GIRL KIDS': true,
'BOY KIDS': true,
人气单品: true,
ACCESSORIES: true
};
if (subData && subData.data && subData.data.text) {
const text = subData.data.text && this._getText(subData.data.text);
const getQuery = args => {
let goods = args[2] && args[2].data;
let skns = '';
if (goods) {
_.forEach(goods, good => {
skns += good.id + ' ';
if (text === title) {
data = this._getSingehotViaResult(rawData.slice(index, index + 4), originQuery, queryResult, type);
}
}
});
}
return skns;
};
return data;
}
const _processFloorData = (rawData, type) => {
let floorList = [];
let searchPromise = [];
let singlehotFloorIndex = [];
let singlehotFloorTitle = [];
let params = [];
let hasNewUser = false;
// 定义各种楼层需要用到的接口返回的数组中元素的个数
const bigFloorLength = 5;
const normalFloorLength = 3;
const hotCategoryLength = 2;
_.forEach(rawData, (data, index) => {
let floorData = null;
let queryParam = '';
if (data && data.template_name === 'recommend_content_three' ||
(data.template_intro === '焦点图' && index === 0)) { // 处理banner
floorData = floorMap.slide.call(null, data.data);
} else if (data && data.template_intro === '热门品类') { // 处理热门品类
floorData = floorMap.hot.call(null, rawData.slice(index, index + hotCategoryLength), type);
} else if (data && data.data && data.data.text) { // 处理一般楼层
let text = _getText(data.data.text);
let lastIndex = index + bigFloorLength < rawData.length ?
index + bigFloorLength : index + (rawData.length - index - 1);
floorData = floorMap[text] &&
floorMap[text].call(null, rawData.slice(index, lastIndex), type);
if (needQuery[text]) {
queryParam = getQuery(rawData.slice(index, lastIndex));
if (queryParam.length > 0) {
params.push(queryParam);
}
_getCategoryFloorData(args) {
const data = {
category: {
name: args[0].data.text,
navs: args[1].data,
list: []
}
};
} else if (data && data.template_name === 'debrisSlider') { // 处理girls的banner
floorData = floorMap.debrisSlide.call(null, data.data);
} else if (data.template_name === 'new_user_floor' || data.template_intro === '新人专享') {
if (!hasNewUser) {
floorData = floorMap.newuser.call(null, data.data);
hasNewUser = true;
}
_.forEach(args[2].data, (it, index) => {
}
// 设置图片大小
if (index === 1) {
it.w = '377;';
it.h = '504;';
} else {
it.w = '185';
it.h = '510';
}
// 处理lifestyle分类楼层
if (!floorData && index + normalFloorLength < rawData.length &&
rawData[index + 1].template_name === 'textNav' &&
rawData[index + 2].template_name === 'floor') {
floorData = floorMap.category.call(null, rawData.slice(index, index + normalFloorLength));
}
data.category.list.push(it);
});
// 处理手风琴楼层
if (!floorData && index + normalFloorLength < rawData.length &&
rawData[index + 1].template_name === 'textNav' &&
rawData[index + 2].template_name === 'focus') {
floorData = floorMap.accordion.call(null, rawData.slice(index, index + normalFloorLength));
}
return data;
}
_getAccordionFloorData(args) {
let data = {
accordion: {
name: args[0].data.text,
navs: args[1].data,
slide: []
}
};
// 处理promise
if (floorData && floorData.then && typeof floorData.then === 'function') {
searchPromise.push(floorData);
data.accordion.slide = args[2].data;
// 记住楼层位置, 以便后面promise获取数据后插入楼层数据
singlehotFloorIndex.push(floorList.length);
return data;
}
// 记住楼层标题, 以便后面promise获取数据后插入楼层数据
singlehotFloorTitle.push(_getText(data.data.text));
} else if (!_.isNil(floorData)) {
_.isArray(floorData) ?
floorList = floorList.concat(floorData) :
floorList.push(floorData);
}
});
return {
floors: floorList,
promise: _.reverse(searchPromise),
queryParams: _.reverse(params),
singlehotFloorTitle: _.reverse(singlehotFloorTitle),
singlehotFloorIndex: _.reverse(singlehotFloorIndex)
};
};
_requestContent(type, params, code) {
let data = {
client_type: 'web',
content_code: code || channelMap[type || 'boys'].code,
gender: channelMap[type || 'boys'].gender,
page: 1,
limit: 1000
};
const _processJKFloorData = (rawData) => {
let floorList = [];
let searchPromise = [];
let singlehotFloorIndex = [];
let singlehotFloorTitle = [];
let params = [];
Object.assign(data, params);
return this.get({
url: 'operations/api/v5/resource/home',
data,
param: {
cache: true,
code: 200
},
api: global.yoho.ServiceAPI
}).then(result => {
return result;
});
}
_.forEach(rawData, (data, index) => {
let floorData = null;
getQuery(args) {
let goods = args[2] && args[2].data;
let skns = '';
if (data && data.template_name === 'recommend_content_three' ||
(data.template_intro === '焦点图' && index === 0)) { // 处理banner
floorData = floorMap.slide.call(null, data.data);
floorData.slide.floorId = data.template_id;
} else if (data && data.data && data.data.text) { // 处理一般楼层
let text = _getText(data.data.text);
if (goods) {
_.forEach(goods, good => {
skns += good.id + ' ';
});
}
// 最新速报
if (text.indexOf('最新速报') >= 0) {
floorData = _getNewReportFloorData(rawData.slice(index, index + 6));
return skns;
}
// 单个图作为最新速报模块用过的,标识一下,不作为广告位了
_.filter(rawData.slice(index, index + 5), function(o) {
if (o.template_name === 'single_image') {
o.hasUser = true;
_processFloorData(rawData, type) {
let floorList = [];
let searchPromise = [];
let singlehotFloorIndex = [];
let singlehotFloorTitle = [];
let params = [];
let hasNewUser = false;
// 定义各种楼层需要用到的接口返回的数组中元素的个数
const bigFloorLength = 5;
const normalFloorLength = 3;
const hotCategoryLength = 2;
_.forEach(rawData, (data, index) => {
let floorData = null;
let queryParam = '';
if (data && data.template_name === 'recommend_content_three' ||
(data.template_intro === '焦点图' && index === 0)) { // 处理banner
floorData = this.floorMap.slide(data.data);
} else if (data && data.template_intro === '热门品类') { // 处理热门品类
floorData = this.floorMap.hot(rawData.slice(index, index + hotCategoryLength), type);
} else if (data && data.data && data.data.text) { // 处理一般楼层
let text = this._getText(data.data.text);
let lastIndex = index + bigFloorLength < rawData.length ?
index + bigFloorLength : index + (rawData.length - index - 1);
floorData = this.floorMap[text] &&
this.floorMap[text](rawData.slice(index, lastIndex), type);
if (needQuery[text]) {
queryParam = this.getQuery(rawData.slice(index, lastIndex));
if (queryParam.length > 0) {
params.push(queryParam);
}
});
} else { // 文本
}
let href = rawData[index + 1].template_name === 'textNav' ?
rawData.slice(index, index + 2) : data;
} else if (data && data.template_name === 'debrisSlider') { // 处理girls的banner
floorData = this.floorMap.debrisSlide(data.data);
} else if (data.template_name === 'new_user_floor' || data.template_intro === '新人专享') {
if (!hasNewUser) {
floorData = this.floorMap.newuser(data.data);
hasNewUser = true;
}
floorData = floorMap.floorTitle.call(null, href);
}
} else if (data && data.template_name === 'jk_floor') { // 左1大图,右6小图,title
floorData = floorMap.jacket.call(null, data.data);
} else if (data && data.template_name === 'recommend_content_five') {
// 1标题12图,在日韩馆频道页,作为7个品类显示
floorData = floorMap.sevenCategory.call(null, data.data);
floorData.sevenCategory.floorId = data.template_id;
} else if (data && data.template_name === 'single_image') {
if (!data.hasUser) {
// 一张图,在日韩馆频道页,做广告位
floorData = floorMap.ad.call(null, data.data);
// 处理lifestyle分类楼层
if (!floorData && index + normalFloorLength < rawData.length &&
rawData[index + 1].template_name === 'textNav' &&
rawData[index + 2].template_name === 'floor') {
floorData = this.floorMap.category(rawData.slice(index, index + normalFloorLength));
}
}
// 处理promise
if (floorData && floorData.then && typeof floorData.then === 'function') {
searchPromise.push(floorData);
// 记住楼层位置, 以便后面promise获取数据后插入楼层数据
singlehotFloorIndex.push(floorList.length);
// 记住楼层标题, 以便后面promise获取数据后插入楼层数据
singlehotFloorTitle.push(_getText(data.data.text));
} else if (!_.isNil(floorData)) {
_.isArray(floorData) ?
floorList = floorList.concat(floorData) :
floorList.push(floorData);
}
// 处理手风琴楼层
if (!floorData && index + normalFloorLength < rawData.length &&
rawData[index + 1].template_name === 'textNav' &&
rawData[index + 2].template_name === 'focus') {
floorData = this.floorMap.accordion(rawData.slice(index, index + normalFloorLength));
}
});
// 处理promise
if (floorData && floorData.then && typeof floorData.then === 'function') {
searchPromise.push(floorData);
return {
floors: floorList,
promise: _.reverse(searchPromise),
queryParams: _.reverse(params),
singlehotFloorTitle: _.reverse(singlehotFloorTitle),
singlehotFloorIndex: _.reverse(singlehotFloorIndex)
};
};
// 记住楼层位置, 以便后面promise获取数据后插入楼层数据
singlehotFloorIndex.push(floorList.length);
const _formatResourceParams = (channel, code) => {
return serviceApi.get('operations/api/v5/resource/get', {content_code: code}, config.apiCache).then(data => {
let result = data && data.data[0] && data.data[0].data[0];
// 记住楼层标题, 以便后面promise获取数据后插入楼层数据
singlehotFloorTitle.push(this._getText(data.data.text));
} else if (!_.isNil(floorData)) {
_.isArray(floorData) ?
floorList = floorList.concat(floorData) :
floorList.push(floorData);
}
});
if (result) {
result.channel = channel;
}
return {
floors: floorList,
promise: _.reverse(searchPromise),
queryParams: _.reverse(params),
singlehotFloorTitle: _.reverse(singlehotFloorTitle),
singlehotFloorIndex: _.reverse(singlehotFloorIndex)
};
}
return result || {};
});
};
_processJKFloorData(rawData) {
let floorList = [];
let searchPromise = [];
let singlehotFloorIndex = [];
let singlehotFloorTitle = [];
let params = [];
/**
* 频道页首次登陆导航并行调接口数据
* @param {Object} data
* @return {Object} formatData
*/
const _formatParams = (channel, data) => {
let params = {};
// 排序数据映射表
let orderMaps = {
s_t_desc: 'shelve_time:desc',
s_t_asc: 'shelve_time:asc',
s_p_asc: 'sales_price:asc',
s_p_desc: 'sales_price:desc',
p_d_desc: 'discount:desc',
p_d_asc: 'discount:asc',
skn_desc: 'product_skn:desc',
skn_asc: 'product_skn:asc',
activities_desc: 'activities.order_by:desc',
activities_asc: 'activities.order_by:asc',
s_n_asc: 'sales_num:asc',
s_n_desc: 'sales_num:desc',
activities_id_desc: 'activities.activity_id:desc',
activities_id_asc: 'activities.activity_id:asc',
brand_desc: 'brand_weight:desc'
};
params.status = 1; // 是否上架,1表示在架,2表示不在
params.sales = 'Y'; // 只搜索销售的产品
params.outlets = 2; // 非奥莱商品
params.stocknumber = 1; // 过滤掉已售罄的商品
params.attribute_not = 2; // 过滤掉赠品
if (!data.order) {
params.order = orderMaps.s_t_desc;
} else {
params.order = orderMaps[data.order] ? orderMaps[data.order] : '';
}
if (!data.page) {
params.page = 1;
}
if (data.viewNum) {
params.viewNum = data.viewNum;
} else if (!data.limit) {
params.viewNum = 60;
} else {
params.viewNum = data.limit;
delete data.limit;
}
if (data) {
params = Object.assign(data);
}
_.forEach(rawData, (data, index) => {
let floorData = null;
return searchApi.getProductList(params).then(result => {
let ret = result.data;
if (data && data.template_name === 'recommend_content_three' ||
(data.template_intro === '焦点图' && index === 0)) { // 处理banner
floorData = this.floorMap.slide.call(null, data.data);
floorData.slide.floorId = data.template_id;
} else if (data && data.data && data.data.text) { // 处理一般楼层
let text = this._getText(data.data.text);
if (ret) {
ret.channel = channel;
}
// 最新速报
if (text.indexOf('最新速报') >= 0) {
floorData = this._getNewReportFloorData(rawData.slice(index, index + 6));
return ret;
});
};
// 单个图作为最新速报模块用过的,标识一下,不作为广告位了
_.filter(rawData.slice(index, index + 5), function(o) {
if (o.template_name === 'single_image') {
o.hasUser = true;
}
});
} else { // 文本
/**
* 格式化频道页首次登陆导航数据
* @param {Object} data
* @return {Object} formatData
*/
const formatIndexGuideData = data => {
let channels = {
boys: {gender: '1,3', limit: 1},
girls: {gender: '2,3', limit: 1},
lifestyle: {msort: 10, misort: '266,280,101,103,259', limit: 1},
kids: {msort: 365, limit: 1}
};
let formatData = [];
let promiseArr = [];
_.forEach(data, item => {
let channel = item.sort_name_en.toLowerCase().replace(' ', '');
formatData.push({
channel: channel,
url: item.sort_url,
sort_name: item.sort_name,
sort_name_en: item.sort_name_en,
content_code: item.content_code,
src: '',
num: 0
});
let href = rawData[index + 1].template_name === 'textNav' ?
rawData.slice(index, index + 2) : data;
if (channels[channel]) {
promiseArr.push(_formatParams(channel, channels[channel]));
}
});
floorData = this.floorMap.floorTitle.call(null, href);
}
return Promise.all(promiseArr).then(result => {
_.forEach(formatData, item => {
_.forEach(result, it => {
if (item && it && item.channel === it.channel) {
item.num = it.total;
} else if (data && data.template_name === 'jk_floor') { // 左1大图,右6小图,title
floorData = this.floorMap.jacket.call(null, data.data);
} else if (data && data.template_name === 'recommend_content_five') {
// 1标题12图,在日韩馆频道页,作为7个品类显示
floorData = this.floorMap.sevenCategory.call(null, data.data);
floorData.sevenCategory.floorId = data.template_id;
} else if (data && data.template_name === 'single_image') {
if (!data.hasUser) {
// 一张图,在日韩馆频道页,做广告位
floorData = this.floorMap.ad.call(null, data.data);
}
});
});
}
return formatData;
});
};
// 处理promise
if (floorData && floorData.then && typeof floorData.then === 'function') {
searchPromise.push(floorData);
/**
* 获取最新上架商品数据
*
* @param string $channel
* @return array
*/
const getNewArrival = (channel, isJKChannel, poolId)=> {
let rel = [],
sortList = sortMap[channel],
params = {},
method = '';
// 记住楼层位置, 以便后面promise获取数据后插入楼层数据
singlehotFloorIndex.push(floorList.length);
// 记住楼层标题, 以便后面promise获取数据后插入楼层数据
singlehotFloorTitle.push(this._getText(data.data.text));
} else if (!_.isNil(floorData)) {
_.isArray(floorData) ?
floorList = floorList.concat(floorData) :
floorList.push(floorData);
}
if (isJKChannel) {
method = 'app.search.sales';
params = {
productPool: poolId
};
});
// 没有商品池id,不查数据
if (!poolId) {
return Promise.all(rel).then();
}
} else {
method = 'web.search.newshelve';
params = {
order: 'shelve_time:desc',
status: 1,
sales: 'Y',
attribute_not: 2,
stocknumber: 3,
dayLimit: 4
return {
floors: floorList,
promise: _.reverse(searchPromise),
queryParams: _.reverse(params),
singlehotFloorTitle: _.reverse(singlehotFloorTitle),
singlehotFloorIndex: _.reverse(singlehotFloorIndex)
};
}
_formatResourceParams(channel, code) {
return this.get({
url: 'operations/api/v5/resource/get',
data: { content_code: code },
param: config.apiCache,
api: global.yoho.ServiceAPI
}).then(data => {
let result = data && data.data[0] && data.data[0].data[0];
if (result) {
result.channel = channel;
}
params.gender = channelMap[channel].gender;
return result || {};
});
}
_.forEach(sortList, (item) => {
let data = Object.assign(item, params, {limit: item.viewNum});
/**
* 频道页首次登陆导航并行调接口数据
* @param {Object} data
* @return {Object} formatData
*/
_formatParams(channel, data) {
let params = {};
// 排序数据映射表
let orderMaps = {
s_t_desc: 'shelve_time:desc',
s_t_asc: 'shelve_time:asc',
s_p_asc: 'sales_price:asc',
s_p_desc: 'sales_price:desc',
p_d_desc: 'discount:desc',
p_d_asc: 'discount:asc',
skn_desc: 'product_skn:desc',
skn_asc: 'product_skn:asc',
activities_desc: 'activities.order_by:desc',
activities_asc: 'activities.order_by:asc',
s_n_asc: 'sales_num:asc',
s_n_desc: 'sales_num:desc',
activities_id_desc: 'activities.activity_id:desc',
activities_id_asc: 'activities.activity_id:asc',
brand_desc: 'brand_weight:desc'
};
rel.push(api.get('', Object.assign({
method: method
}, data), {cache: true}));
});
params.status = 1; // 是否上架,1表示在架,2表示不在
params.sales = 'Y'; // 只搜索销售的产品
params.outlets = 2; // 非奥莱商品
params.stocknumber = 1; // 过滤掉已售罄的商品
params.attribute_not = 2; // 过滤掉赠品
if (!data.order) {
params.order = orderMaps.s_t_desc;
} else {
params.order = orderMaps[data.order] ? orderMaps[data.order] : '';
}
if (!data.page) {
params.page = 1;
}
return Promise.all(rel).then(res => {
let data = [],
result = [];
if (data.viewNum) {
params.viewNum = data.viewNum;
} else if (!data.limit) {
params.viewNum = 60;
} else {
params.viewNum = data.limit;
delete data.limit;
}
if (data) {
params = Object.assign(data);
}
_.forEach(sortList, (it, index) => {
let list = _.get(res[index], 'data.product_list', []);
return this.searchApi.getProductList(params).then(result => {
let ret = result.data;
if (list.length === sortList[index].viewNum) {
data = data.concat(list);
if (ret) {
ret.channel = channel;
}
});
_.forEach(data, (item) => {
result.push(processProduct(item, {
width: 280,
height: 373,
gender: params.gender
}));
return ret;
});
return result;
});
};
}
/**
* 获取频道页数据
* @param {String} type 传入频道页类型,值可以是: boys, girls, kids, lifestyle
* @return {Object}
*/
const getContent = (type, isJKChannel, poolId) => {
/**
* 格式化频道页首次登陆导航数据
* @param {Object} data
* @return {Object} formatData
*/
formatIndexGuideData(data) {
let channels = {
boys: {gender: '1,3', limit: 1},
girls: {gender: '2,3', limit: 1},
lifestyle: {msort: 10, misort: '266,280,101,103,259', limit: 1},
kids: {msort: 365, limit: 1}
};
let formatData = [];
let promiseArr = [];
_.forEach(data, item => {
let channel = item.sort_name_en.toLowerCase().replace(' ', '');
formatData.push({
channel: channel,
url: item.sort_url,
sort_name: item.sort_name,
sort_name_en: item.sort_name_en,
content_code: item.content_code,
src: '',
num: 0
});
let params = {new_device: 'Y'};
if (channels[channel]) {
promiseArr.push(this._formatParams(channel, channels[channel]));
}
});
return Promise.all([
headerModel.requestHeaderData(type),
_requestContent(type, params),
getNewArrival(type, isJKChannel, poolId)
]).then(res => {
return Promise.all(promiseArr).then(result => {
_.forEach(formatData, item => {
_.forEach(result, it => {
if (item && it && item.channel === it.channel) {
item.num = it.total;
}
});
});
let headerData = res[0].data || res[0],
contentData = res[1].data ? res[1].data.list : res[1];
return formatData;
});
}
let data = {};
/**
* 获取最新上架商品数据
*
* @param string $channel
* @return array
*/
getNewArrival(channel, isJKChannel, poolId) {
let rel = [],
sortList = sortMap[channel],
params = {},
method = '';
if (isJKChannel) {
method = 'app.search.sales';
params = {
productPool: poolId
};
// 没有商品池id,不查数据
if (!poolId) {
return Promise.all(rel).then();
}
} else {
method = 'web.search.newshelve';
params = {
order: 'shelve_time:desc',
status: 1,
sales: 'Y',
attribute_not: 2,
stocknumber: 3,
dayLimit: 4
};
}
const processResult = _processFloorData(contentData, type);
data = headerData;
data.module = 'channel';
data.page = 'channel';
data.pageType = type;
data.footerTop = true;
data.channel = processResult.floors.map(function(elem) {
params.gender = channelMap[channel].gender;
if (elem.newArrivls) {
elem.newArrivls.goods = res[2];
}
_.forEach(sortList, (item) => {
let data = Object.assign(item, params, {limit: item.viewNum});
return elem;
rel.push(this.get({
data: Object.assign({
method: method
}, data),
param: {cache: true}
}));
});
return {
rawData: contentData,
floorData: data,
searchPromise: processResult.promise,
singlehotFloorIndex: processResult.singlehotFloorIndex,
singlehotFloorTitle: processResult.singlehotFloorTitle,
queryParams: processResult.queryParams,
channelType: type
};
return Promise.all(rel).then(res => {
let data = [],
result = [];
}).then(result => {
// 如果有promise则做相应处理
if (result.searchPromise.length) {
return Promise.all(result.searchPromise).then(res => {
_.forEach(res, (data, index) => {
result.floorData.channel
.splice(result.singlehotFloorIndex[index], 0,
_processFloorDataWithQueryReusult(
result.rawData,
result.queryParams[index],
data,
result.singlehotFloorTitle[index],
result.channelType
));
});
_.forEach(sortList, (it, index) => {
let list = _.get(res[index], 'data.product_list', []);
return result.floorData;
if (list.length === sortList[index].viewNum) {
data = data.concat(list);
}
});
}
return result.floorData || result;
});
};
/**
* 获取日韩馆频道页数据
* @param {String} type 传入频道页类型,值可以是: boys, girls, kids, lifestyle
* @return {Object}
*/
const getJKContent = (req) => {
let channel = req.query.channel || req.yoho.channel || 'boys',
contentCode = req.query.content_code;
_.forEach(data, (item) => {
result.push(processProduct(item, {
width: 280,
height: 373,
gender: params.gender
}));
});
return result;
});
}
return Promise.all([
headerModel.requestHeaderData(channel),
_requestContent(channel, {}, contentCode),
getNewArrival(channel, true, req.query.template_id)
]).then(res => {
let headerData = res[0].data || res[0],
contentData = res[1].data ? res[1].data.list : res[1];
/**
* 获取频道页数据
* @param {String} type 传入频道页类型,值可以是: boys, girls, kids, lifestyle
* @return {Object}
*/
getContent(type, isJKChannel, poolId) {
let data = {};
let params = {new_device: 'Y'};
const processResult = _processJKFloorData(contentData);
return Promise.all([
headerModel.requestHeaderData(type),
this._requestContent(type, params),
this.getNewArrival(type, isJKChannel, poolId)
]).then(res => {
data = headerData;
data.module = 'channel';
data.page = 'channel';
data.pageType = channel;
data.mchannel = 'japanKorean';// 子频道,如日韩馆
data.footerTop = true;
data.channel = processResult.floors.map(function(elem) {
let headerData = res[0].data || res[0],
contentData = res[1].data ? res[1].data.list : res[1];
if (elem.newArrivls) {
elem.newArrivls.goods = res[2];
}
let data = {};
return elem;
});
const processResult = this._processFloorData(contentData, type);
return {
rawData: contentData,
floorData: data,
searchPromise: processResult.promise,
singlehotFloorIndex: processResult.singlehotFloorIndex,
singlehotFloorTitle: processResult.singlehotFloorTitle,
queryParams: processResult.queryParams,
channelType: channel
};
data = headerData;
data.module = 'channel';
data.page = 'channel';
data.pageType = type;
data.footerTop = true;
data.channel = processResult.floors.map(function(elem) {
}).then(result => {
// 如果有promise则做相应处理
if (result.searchPromise.length) {
return Promise.all(result.searchPromise).then(res => {
_.forEach(res, (data, index) => {
result.floorData.channel
.splice(result.singlehotFloorIndex[index], 0,
_processFloorDataWithQueryReusult(
result.rawData,
result.queryParams[index],
data,
result.singlehotFloorTitle[index],
result.channelType
));
});
if (elem.newArrivls) {
elem.newArrivls.goods = res[2];
}
return result.floorData;
return elem;
});
}
return result.floorData || result;
});
};
const getResourceData = (formatData) => {
let promiseArr = [];
return {
rawData: contentData,
floorData: data,
searchPromise: processResult.promise,
singlehotFloorIndex: processResult.singlehotFloorIndex,
singlehotFloorTitle: processResult.singlehotFloorTitle,
queryParams: processResult.queryParams,
channelType: type
};
}).then(result => {
// 如果有promise则做相应处理
if (result.searchPromise.length) {
return Promise.all(result.searchPromise).then(res => {
_.forEach(res, (data, index) => {
result.floorData.channel
.splice(result.singlehotFloorIndex[index], 0,
this._processFloorDataWithQueryReusult(
result.rawData,
result.queryParams[index],
data,
result.singlehotFloorTitle[index],
result.channelType
));
});
return result.floorData;
});
}
_.forEach(formatData, item => {
if (item.content_code) {
promiseArr.push(_formatResourceParams(item.channel, item.content_code));
}
});
return Promise.all(promiseArr).then(data => {
_.forEach(formatData, (item, index) => {
_.forEach(data, (it, idx) => {
if (formatData[index].channel === data[idx].channel) {
formatData[index].src = data[idx].src;
}
});
return result.floorData || result;
});
}
return formatData;
});
};
/**
* 获取日韩馆频道页数据
* @param {String} type 传入频道页类型,值可以是: boys, girls, kids, lifestyle
* @return {Object}
*/
getJKContent(req) {
let channel = req.query.channel || req.yoho.channel || 'boys',
contentCode = req.query.content_code;
return Promise.all([
headerModel.requestHeaderData(channel),
this._requestContent(channel, {}, contentCode),
this.getNewArrival(channel, true, req.query.template_id)
]).then(res => {
let headerData = res[0].data || res[0],
contentData = res[1].data ? res[1].data.list : res[1];
let data = {};
const processResult = this._processJKFloorData(contentData);
data = headerData;
data.module = 'channel';
data.page = 'channel';
data.pageType = channel;
data.mchannel = 'japanKorean';// 子频道,如日韩馆
data.footerTop = true;
data.channel = processResult.floors.map(function(elem) {
if (elem.newArrivls) {
elem.newArrivls.goods = res[2];
}
/**
* 获取频道页首次登陆导航数据
* @param {String} type 传入频道页类型,值可以是: boys, girls, kids, lifestyle
* @return {Object}
*/
const getIndexGuideData = () => {
let params = {
client_type: 'web',
private_key: '0ed29744ed318fd28d2c07985d3ba633'
};
return elem;
});
return serviceApi.get('operations/api/v6/category/getCategory', params, config.apiCache);
};
return {
rawData: contentData,
floorData: data,
searchPromise: processResult.promise,
singlehotFloorIndex: processResult.singlehotFloorIndex,
singlehotFloorTitle: processResult.singlehotFloorTitle,
queryParams: processResult.queryParams,
channelType: channel
};
}).then(result => {
// 如果有promise则做相应处理
if (result.searchPromise.length) {
return Promise.all(result.searchPromise).then(res => {
_.forEach(res, (data, index) => {
result.floorData.channel
.splice(result.singlehotFloorIndex[index], 0,
this._processFloorDataWithQueryReusult(
result.rawData,
result.queryParams[index],
data,
result.singlehotFloorTitle[index],
result.channelType
));
});
return result.floorData;
});
}
const hasNewUserFloor = (channelType, uid) => {
let params = {uid: uid};
return result.floorData || result;
});
}
return _requestContent(channelType, params).then(res => {
let isNewUser = false,
contentData = res.data ? res.data.list : res;
getResourceData(formatData) {
let promiseArr = [];
_.forEach(contentData, (data) => {
if (data.template_name === 'new_user_floor' || data.template_intro === '新人专享') {
isNewUser = true;
return false;
_.forEach(formatData, item => {
if (item.content_code) {
promiseArr.push(this._formatResourceParams(item.channel, item.content_code));
}
});
return Promise.all(promiseArr).then(data => {
_.forEach(formatData, (item, index) => {
_.forEach(data, (it, idx) => {
if (formatData[index].channel === data[idx].channel) {
formatData[index].src = data[idx].src;
}
});
});
return {
isNewUser: isNewUser
return formatData;
});
}
/**
* 获取频道页首次登陆导航数据
* @param {String} type 传入频道页类型,值可以是: boys, girls, kids, lifestyle
* @return {Object}
*/
getIndexGuideData() {
let params = {
client_type: 'web',
private_key: '0ed29744ed318fd28d2c07985d3ba633'
};
});
};
return this.get({
url: 'operations/api/v6/category/getCategory',
data: params,
param: config.apiCache,
api: global.yoho.ServiceAPI
});
}
hasNewUserFloor(channelType, uid) {
let params = {uid: uid};
return this._requestContent(channelType, params).then(res => {
let isNewUser = false,
contentData = res.data ? res.data.list : res;
module.exports = {
getNewArrival: getNewArrival,
getContent: getContent,
getJKContent: getJKContent,
getIndexGuideData: getIndexGuideData,
formatIndexGuideData: formatIndexGuideData,
getResourceData: getResourceData,
hasNewUserFloor: hasNewUserFloor
_.forEach(contentData, (data) => {
if (data.template_name === 'new_user_floor' || data.template_intro === '新人专享') {
isNewUser = true;
return false;
}
});
return {
isNewUser: isNewUser
};
});
}
};
... ...
/**
* Created by TaoHuang on 2016/6/14.
*/
'use strict';
const _ = require('lodash');
const Fn = require('lodash/fp');
const md5 = require('md5');
const api = global.yoho.API;
const serviceApi = global.yoho.ServiceAPI;
const config = global.yoho.config;
const helpers = global.yoho.helpers;
const cache = global.yoho.cache;
const logger = global.yoho.logger;
// 判断用户是否收藏品牌
const isFavoriteBrandUrl = '/shops/service/v1/favorite/getUidBrandFav';
// 根据品牌查询相关文章
const relateArticleUrl = 'guang/service/v2/article/getArticleByBrand';
const GLOBAL_BASE_URI = '/product/global/list';
// 缓存生效时间
const CACHE_TIME_S = 60;
... ... @@ -38,489 +25,80 @@ const saveCache = (key, kv, cacheTime) => {
.catch(err => logger.debug(`product query save cache data fail:${err.toString()}`));
};
const getProductListOrig = finalParams => api.get('', finalParams);
const getKeyActivityAsync = (query) => {
return api.get('', {
method: 'app.search.word',
query: query
}, {
catch: true,
code: 200
});
};
/**
* 获取商品列表
* @return
*/
const getProductList = (params, from) => {
let finalParams = {
method: 'web.search.search',
sales: 'Y',
outlets: 2,
stocknumber: 1,
need_filter: 'yes',
limit: 60
};
Object.assign(finalParams, params);
// 店铺默认排序s_w_desc
if (params.shopId || params.shop_id || params.shop) {
finalParams.order = params.order || 's_w_desc';
module.exports = class extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
}
if (from) {
finalParams.from = from;
}
if (!config.useCache) {
return getProductListOrig(finalParams);
} else {
let cKey = getSearchCacheKey(finalParams);
return cache.get(cKey)
.catch(err => logger.debug(`product query save cache data fail:${err.toString()}`))
.then(cdata => {
let hasCache = false;
if (cdata) {
try {
cdata = JSON.parse(cdata);
} catch (e) {
logger.debug('getProductList cache data parse fail.');
}
if (cdata.filter && cdata.standard) {
hasCache = true;
finalParams.need_filter = 'no';
}
}
return getProductListOrig(finalParams).then(result => {
if (hasCache && result && result.data) {
Object.assign(result.data, cdata);
} else {
if (result && result.data && result.data.filter) {
saveCache(cKey, Object.assign({}, {
filter: result.data.filter,
standard: result.data.standard
}), CACHE_TIME_S);
}
}
return result;
});
});
getProductListOrig(finalParams) {
return this.get({data: finalParams});
}
};
/**
* 获取seo商品列表
* @return
*/
const getSeoProductList = (params, from) => {
let finalParams = {
method: 'web.search.forseo',
sales: 'Y',
outlets: 2,
stocknumber: 1,
need_filter: 'no',
limit: 60
};
Object.assign(finalParams, params);
/**
* 获取商品列表
* @return
*/
getProductList(params, from) {
let finalParams = {
method: 'web.search.search',
sales: 'Y',
outlets: 2,
stocknumber: 1,
need_filter: 'yes',
limit: 60
};
Object.assign(finalParams, params);
// 店铺默认排序s_w_desc
if (params.shopId || params.shop_id || params.shop) {
finalParams.order = params.order || 's_w_desc';
}
if (from) {
finalParams.from = from;
}
if (from) {
finalParams.from = from;
}
return getProductListOrig(finalParams);
};
if (!config.useCache) {
return this.getProductListOrig(finalParams);
} else {
let cKey = getSearchCacheKey(finalParams);
const getSortListOrig = (finalParams) => api.get('', finalParams, config.apiCache);
return cache.get(cKey)
.catch(err => logger.debug(`product query save cache data fail:${err.toString()}`))
.then(cdata => {
let hasCache = false;
/**
* 获取分类列表
* @return
*/
const getSortList = (params, channel) => {
let finalParams = {
method: 'web.regular.groupsort.sale',
sales: 'Y', // 在销售商品分类
status: 1, // 上架商品分类
stocknumber: 1 // 过滤掉已售罄
};
Object.assign(finalParams, params);
if (cdata) {
if (channel) {
switch (channel) {
case 'boys':
finalParams.yh_channel = 1;
break;
case 'girls':
finalParams.yh_channel = 2;
break;
case 'kids':
finalParams.yh_channel = 3;
break;
case 'lifestyle':
finalParams.yh_channel = 4;
break;
default:
break;
}
}
if (!config.useCache) {
return getSortListOrig(finalParams);
} else {
let cKey = getSearchCacheKey(finalParams);
return cache.get(cKey)
.catch(err => logger.debug(`product query save cache data fail:${err.toString()}`))
.then(cdata => {
let cdataObj;
try {
cdata = JSON.parse(cdata);
} catch (e) {
logger.debug('getProductList cache data parse fail.');
}
if (cdata) {
try {
cdataObj = JSON.parse(cdata);
} catch (e) {
logger.debug('getSortList cache data parse fail.');
}
if (cdata.filter && cdata.standard) {
hasCache = true;
finalParams.need_filter = 'no';
}
}
if (cdataObj) {
return cdataObj;
return this.getProductListOrig(finalParams).then(result => {
if (hasCache && result && result.data) {
Object.assign(result.data, cdata);
} else {
return getSortListOrig(finalParams).then(ret => {
if (ret && ret.code === 200) {
saveCache(cKey, ret, CACHE_TIME_S);
}
return ret;
});
if (result && result.data && result.data.filter) {
saveCache(cKey, Object.assign({}, {
filter: result.data.filter,
standard: result.data.standard
}), CACHE_TIME_S);
}
}
});
}
};
/**
* 获取分类图文介绍
* @return
*/
const getSortIntro = (params) => {
let finalParams = {
method: 'web.search.banner'
};
Object.assign(finalParams, params);
return api.get('', finalParams, config.apiCache);
};
/**
* 获取分类广告
* @return
*/
const getSortAds = (params) => {
let finalParams = {
method: 'app.ads.list'
};
Object.assign(finalParams, params);
return api.get('', finalParams, config.apiCache);
};
/**
* 获取品牌系列
* @return
*/
const getBrandShopSeries = (params) => {
let finalParams = {
method: 'web.brand.series',
status: params.status || 1
};
if (params.brandId) {
finalParams.brand_id = params.brandId;
} else if (params.shopId) {
Object.assign(finalParams, {
method: 'web.shop.series',
shop_id: params.shopId
});
}
return api.get('', finalParams, config.apiCache);
};
/**
* 获取品牌folder
* @return
*/
const getBrandShopFolder = (params) => {
let finalParams = {
method: 'web.brand.folder',
status: params.status || 1
};
if (params.brandId) {
finalParams.brand_id = params.brandId;
} else if (params.shopId) {
Object.assign(finalParams, {
method: 'web.shop.folder',
shop_id: params.shopId
});
}
return api.get('', finalParams, config.apiCache);
};
/**
* 获取品牌水牌
* @return
*/
const getNodeContent = (params) => {
let finalParams = {
method: 'web.html.content',
mode: params.mode || 'release',
node: params.node || ''
};
return api.get('', finalParams, config.apiCache);
};
/**
* 一周新品上架
* @return
*/
const getWeekNew = (params) => {
let finalParams = {
method: 'web.regular.recent'
};
Object.assign(finalParams, params);
return api.get('', finalParams, config.apiCache);
};
const getBrandCouponAsync = (brandId, uid) => {
let extra = {code: 200};
if (!uid) {
extra.cache = true;
}
return api.get('', {
method: 'app.brand.getBrandIntro',
brand_id: brandId,
uid: uid
}, extra);
};
/**
* 根据关键词搜索品牌店铺信息
* @return
*/
const getBrandShop = (query) => {
let finalParams = {
method: 'web.search.shopListInfo'
};
return api.get('', Object.assign(finalParams, {keyword: query}), config.apiCache);
};
/**
* 根据搜索得到店铺/品牌
*/
const getShopList = params => {
if (!params || !params.query) {
return;
}
return getBrandShop(params.query).then(shops => {
let shopEntry = [];
_.forEach(_.get(shops, 'data.shopList', []), value => {
let shopInfo = {
home: helpers.urlFormat('', null, value.shop_domain || value.brand_domain),
logo: value.shop_logo || value.brand_ico,
shopName: value.shop_name || value.brand_name,
shopType: '',
sort: []
};
if (value.is_global === 'Y') {
shopInfo.home = helpers.urlFormat(GLOBAL_BASE_URI, {brand: value.global_brand_id});
shopInfo.shopType = 'global-brand';
}
// 店铺/品牌的小分类
_.forEach(_.get(value, 'sortInfo.sort', []), sortInfo => {
_.forEach(_.get(sortInfo, 'sub', []), subSort => {
let sortHref;
if (value.is_global !== 'Y') {
sortHref = helpers.urlFormat('', {misort: subSort.sort_id},
value.shop_domain || value.brand_domain);
} else {
sortHref = helpers.urlFormat(GLOBAL_BASE_URI, {
misort: subSort.sort_id,
brand: value.global_brand_id
});
}
shopInfo.sort.push({
href: sortHref,
name: subSort.sort_name
return result;
});
});
});
shopEntry.push(shopInfo);
});
return shopEntry;
});
};
/**
* 搜索提示
* @return
*/
const getSuggest = (params) => {
let finalParams = {
method: 'app.search.fuzzy',
keyword: params.keyword || ''
};
return api.get('', finalParams, config.apiCache);
};
/**
* 根据品牌域名获取品牌信息
* @return
*/
const getBrandData = (params) => {
let finalParams = {
method: 'web.brand.byDomain',
domain: params.domain || ''
};
return api.get('', finalParams, config.apiCache);
};
/**
* 根据uid和品牌id判断品牌是否收藏
* @return
*/
const isFavoriteBrand = (uid, brandId) => {
return serviceApi.get(isFavoriteBrandUrl, {
uid: uid,
brandId: brandId
});
};
/**
* 根据shopId获取店铺基本信息
* @return
*/
const getShopInfo = (shopId, uid) => {
let finalParams = {
method: 'app.shops.getIntro',
shop_id: shopId || 0,
uid: uid || 0
};
return api.get('', finalParams, config.apiCache);
};
/**
* 查询店铺下面的所有品牌
*/
const getShopBrands = (shopId) => {
return api.get('', {method: 'app.shops.getShopsBrands', shop_id: shopId || 0}, config.apiCache);
};
/**
* 查询店铺装修
*/
const getShopDecorator = (shopId) => {
return api.get('', {method: 'app.shopsdecorator.getList', shop_id: shopId || 0}, config.apiCache);
};
/**
* 通过品牌获取相关文章
*/
const getArticleByBrand = (brand, udid, limit) => {
let params = {
brand_id: brand || 0,
udid: udid,
limit: limit || 6
};
return serviceApi.get(relateArticleUrl, params);
};
const getBrands4Filter = (params) => {
return api.get('', Object.assign({
method: 'web.regular.aggBrand'
}, params));
};
/**
* 有可能喜欢的商品
* @param int $channel 频道,1代表男生,2代表女生,3代表潮童,4代表创意生活
* @param $uid 用户ID
* @param $udid 设备ID
* @param $rec_pos 位置码
* @param $limit 数量限制
* @return array 接口返回的数据
* */
const lessRecommend = (channelNum, uid, udid, recPos, limit) => {
let param = {
method: 'app.search.newLast7day',
yh_channel: channelNum,
udid: udid,
rec_pos: recPos,
limit: limit
};
if (uid) {
param.uid = uid;
}
}
return api.get('', param);
};
module.exports = {
getKeyActivityAsync,
getProductList,
getSeoProductList,
getSortList,
getSortIntro,
getSortAds,
getBrandShopFolder,
getBrandShopSeries,
getWeekNew,
getBrandCouponAsync,
getBrandShop,
getSuggest,
getBrandData,
getNodeContent,
isFavoriteBrand,
getShopInfo,
getShopBrands,
getShopDecorator,
getArticleByBrand,
getShopList,
getBrands4Filter,
getProductListOrig,
getSearchCacheKey,
lessRecommend
};
... ...
... ... @@ -58,7 +58,7 @@ passport.use('local', new LocalStrategy({
getLoginStat(clientIp).then((times) => {
let errLoginTimes = _.parseInt(times) || 0;
return LoginApi.signin(type, area, username, password, shoppingKey, clientIp, close).then((result) => {
return req.ctx(LoginApi).signin(type, area, username, password, shoppingKey, close).then((result) => {
if (result.code && (result.code === 200 || result.code === 510) && result.data.uid) {
cache.del(errorLoginKey).catch(() => {});
req.session.type = '';
... ...
... ... @@ -7,7 +7,7 @@
const helpers = global.yoho.helpers;
const config = global.yoho.config;
const service = require('../models/back-service');
const BackService = require('../models/back-service');
const passportHelper = require('../models/passport-helper');
const simpleHeaderModel = require('../../../doraemon/models/simple-header');
const _ = require('lodash');
... ... @@ -24,7 +24,7 @@ const index = (req, res, next) => {
domain: config.cookieDomain
});
service.indexPageDataAsync()
req.ctx(BackService).indexPageDataAsync()
.then(result => {
res.render('back/index', Object.assign({
module: 'passport',
... ... @@ -43,7 +43,7 @@ const validateInputAPI = (req, res, next) => {
let userInput = req.body.phoneNum || '';
let areaCode = (req.body.area || '86').replace('+', '');
service.validateEmailOrMobileAsync(userInput, areaCode)
req.ctx(BackService).validateEmailOrMobileAsync(userInput, areaCode)
.then(result => {
req.inputInfo = result;
next();
... ... @@ -63,7 +63,7 @@ const validateInputPage = (req, res, next) => {
let userInput = req.body.phoneNum || '';
let areaCode = (req.body.area || '86').replace('+', '');
service.validateEmailOrMobileAsync(userInput, areaCode)
req.ctx(BackService).validateEmailOrMobileAsync(userInput, areaCode)
.then(result => {
req.inputInfo = result;
next();
... ... @@ -81,7 +81,7 @@ const getUserInfoAPI = (req, res, next) => {
req.session.type = 'back-step1';
service.findUserAsync(inputInfo.type, inputInfo.phone, inputInfo.area)
req.ctx(BackService).findUserAsync(inputInfo.type, inputInfo.phone, inputInfo.area)
.then(result => {
res.json(result);
})
... ... @@ -96,7 +96,7 @@ const sendCodePage = (req, res, next) => {
let inputInfo = req.inputInfo;
req.session.type = 'back-step1';
service.sendCodeToUserAsync(inputInfo.type, inputInfo.phone, inputInfo.area)
req.ctx(BackService).sendCodeToUserAsync(inputInfo.type, inputInfo.phone, inputInfo.area)
.then(result => {
if (!(result.code && result.code === 200)) {
return res.json({
... ... @@ -160,7 +160,7 @@ const sendBackMobileAPI = (req, res, next) => {
let mobile = req.body.mobile || '';
let area = req.body.area || '86';
service.sendCodeToMobileAsync(area, mobile)
req.ctx(BackService).sendCodeToMobileAsync(area, mobile)
.then(result => {
res.json(result);
})
... ... @@ -230,7 +230,7 @@ const validateCodeByEmailPage = (req, res, next) => {
return next();
}
service.checkEmailCodeAsync(code)
req.ctx(BackService).checkEmailCodeAsync(code)
.then(result => {
if (!result) {
return res.redirect(helpers.urlFormat('/passport/back/index'));
... ... @@ -338,7 +338,7 @@ const verifyCodeByMobileAPI = (req, res) => {
return res.json(ERR);
}
service.verifyCodyByMobileAsync(area, mobile, mobileCode)
req.ctx(BackService).verifyCodyByMobileAsync(area, mobile, mobileCode)
.then(result => {
res.json(result);
})
... ... @@ -377,7 +377,7 @@ const validateCodeByMobilePage = (req, res, next) => {
};
code = new Buffer(code, 'base64').toString();
req.mobileAuth = service.authRequest(data, code);
req.mobileAuth = req.ctx(BackService).authRequest(data, code);
next();
};
... ... @@ -397,7 +397,7 @@ const updatePwdAPI = (req, res, next) => {
let mobileAuth = req.mobileAuth || {};
let newPassword = req.body.pwd || '';
service.updatePwdAsync(code, mobileAuth, newPassword)
req.ctx(BackService).updatePwdAsync(code, mobileAuth, newPassword)
.then(result => {
if (result.status) {
req.session.successType = result.type;
... ... @@ -470,7 +470,7 @@ const weakPwdSuccessPage = (req, res, next) => {
const modPwdByCodeAPI = (req, res, next) => {
let body = req.body;
service.modPwdByCodeAsync({
req.ctx(BackService).modPwdByCodeAsync({
uid: req.user.uid,
oldPwd: body.oldPwd,
newPwd: body.newPwd,
... ...
... ... @@ -9,9 +9,9 @@
const _ = require('lodash');
const helpers = global.yoho.helpers;
const passportHelper = require('../models/passport-helper');
const bindService = require('../models/bind-service');
const loginService = require('../models/login-service');
const userService = require('../models/user-service');
const BindService = require('../models/bind-service');
const LoginService = require('../models/login-service');
const UserService = require('../models/user-service');
// const UserService = require('../models/user-service');
const simpleHeaderModel = require('../../../doraemon/models/simple-header');
... ... @@ -77,19 +77,7 @@ const bind = {
return next();
}
// UserService.findByMobileAsync(area, mobile).then(user => {
// if (user) {
// return {
// thumb: user.headImg,
// userName: user.username,
// loginHref: user.bindLogin
// };
// } else {
// return {};
// }
// })
userService.getUserInfo(area, mobile).then(user => {
req.ctx(UserService).getUserInfo(area, mobile).then(user => {
let data = _.assign(user, {
phoneNum: mobile,
areaCode: area,
... ... @@ -125,8 +113,8 @@ const bind = {
res.render('bind/success', data);
},
_bindCheck: (mobile, openId, area, sourceType) => {
return bindService.bindCheck(mobile, openId, sourceType, area).then(result => {
_bindCheck: (req, mobile, openId, area, sourceType) => {
return req.ctx(BindService).bindCheck(mobile, openId, sourceType, area).then(result => {
if (!result || !result.code) {
return {code: 400, message: '', data: ''};
} else if (result.code === 200 && result.data.is_register === 0) {
... ... @@ -135,17 +123,17 @@ const bind = {
// 绑定流程:code=200 未注册,可绑定
return {code: 200, message: result.message, data: {next: nextUrl}};
} else if (result.code === 200 && result.data.is_register === 1) {
return userService.getUserInfo(area, mobile).then(user => {
return req.ctx(UserService).getUserInfo(area, mobile).then(user => {
// 绑定流程:code=201 已注册 绑定过其他第三方
return {code: 201, message: result.message, data: {user: user}};
});
} else if (result.code === 200 && result.data.is_register === 3) {
// 关联流程
return userService.getUserInfo(area, mobile).then(user => {
return req.ctx(UserService).getUserInfo(area, mobile).then(user => {
return {code: 203, message: result.message, data: {user: user}};
});
} else if (result.code === 506 || result.code === 505) {
return userService.getUserInfo(area, mobile).then(user => {
return req.ctx(UserService).getUserInfo(area, mobile).then(user => {
// 绑定流程:code=506 手机号码注册过,而且该手机号码也已经绑定过该类型第三方
// code=505 手机号码注册过,而且该第三方也已经绑定过手机号
return {code: 205, message: result.message, data: {user: user}};
... ... @@ -176,7 +164,7 @@ const bind = {
* code:506 // 手机号码注册过,而且该手机号码也已经绑定过该类型第三方
*/
bind._bindCheck(mobile, openId, area, sourceType).then(result => {
bind._bindCheck(req, mobile, openId, area, sourceType).then(result => {
return res.json(result);
}).catch(next);
} else {
... ... @@ -207,7 +195,7 @@ const bind = {
*/
bind._bindCheck(mobile, openId, area, sourceType).then(result => {
if (result.code === 201) {
bindService.sendBindMsg(area, mobile).then(d => {
req.ctx(BindService).sendBindMsg(area, mobile).then(d => {
if (d && d.code) {
return res.json(result);
} else {
... ... @@ -230,7 +218,7 @@ const bind = {
return res.json({code: 400, message: '非法请求'});
}
bindService.sendBindMsg(area, mobile).then(result => {
req.ctx(BindService).sendBindMsg(area, mobile).then(result => {
if (result && result.code) {
return res.json(result);
} else {
... ... @@ -243,7 +231,7 @@ const bind = {
let area = req.body.area;
let code = req.body.code;
bindService.checkBindCode(area, mobile, code).then(result => {
req.ctx(BindService).checkBindCode(area, mobile, code).then(result => {
if (result && result.code) {
return res.json(result);
} else {
... ... @@ -259,11 +247,11 @@ const bind = {
let code = _.trim(req.body.code);
let password = _.trim(req.body.password) || '';
bindService.checkBindCode(area, mobile, code).then(result => {
req.ctx(BindService).checkBindCode(area, mobile, code).then(result => {
if (result && result.code !== 200) {
return {code: 402, message: '短信验证码不正确', data: ''};
} else {
return bindService.bindMobile(openId, sourceType, mobile, area, password);
return req.ctx(BindService).bindMobile(openId, sourceType, mobile, area, password);
}
}).then(result => {
if (result && result.code) {
... ... @@ -272,7 +260,7 @@ const bind = {
sourceType: sourceType + '_bind'
});
return loginService.syncUserSession(result.data, req, res).then(() => {
return req.ctx(LoginService).syncUserSession(result.data, req, res).then(() => {
return {code: 200, message: result.message, data: {refer: refer}};
});
} else {
... ... @@ -293,9 +281,9 @@ const bind = {
let code = req.body.code;
if (_.toNumber(mobile) && openId && areaCode && sourceType && code) {
bindService.checkBindCode(areaCode, mobile, code).then(result => {
req.ctx(BindService).checkBindCode(areaCode, mobile, code).then(result => {
if (result && result.code && result.code === 200) {
return bindService.relateMobile(openId, sourceType, mobile, areaCode);
return req.ctx(BindService).relateMobile(openId, sourceType, mobile, areaCode);
} else {
return {code: 402, message: '短信验证码错误', data: ''};
}
... ... @@ -306,7 +294,7 @@ const bind = {
sourceType: sourceType + '_relate'
});
return loginService.syncUserSession(
return req.ctx(LoginService).syncUserSession(
result.data,
req,
res
... ...
... ... @@ -9,8 +9,8 @@
const _ = require('lodash');
const helpers = global.yoho.helpers;
const passportHelper = require('../models/passport-helper');
const certService = require('../models/cert-service');
const userService = require('../models/user-service');
const CertService = require('../models/cert-service');
const UserService = require('../models/user-service');
const simpleHeaderModel = require('../../../doraemon/models/simple-header');
const config = global.yoho.config;
... ... @@ -28,7 +28,7 @@ const cert = {
return res.send(req.query.callback + '(' + JSON.stringify(dest) + ')');
}
certService.checkEmailCertTip(uid)
req.ctx(CertService).checkEmailCertTip(uid)
.then(ret => {
dest.data = _.get(ret, 'data.isBindedOrRelated') === 'N' ? 'Y' : 'N';
res.type('text/javascript');
... ... @@ -87,7 +87,7 @@ const cert = {
let area = req.body.area;
let refer = req.body.refer;
userService.getUserInfo(area, mobile).then(user => {
req.ctx(UserService).getUserInfo(area, mobile).then(user => {
let data = _.assign(user, {
phoneNum: mobile,
areaCode: area,
... ... @@ -131,7 +131,7 @@ const cert = {
* code:200,isCanBind=Y // 不可绑定
*/
certService.certCheck(mobile, area).then(result => {
req.ctx(CertService).certCheck(mobile, area).then(result => {
if (!result || !result.code) {
return {code: 400, message: '', data: ''};
} else if (result.code === 200) {
... ... @@ -158,7 +158,7 @@ const cert = {
let mobile = req.body.mobile;
let area = req.body.area;
certService.sendCertMsg(mobile, area).then(result => {
req.ctx(CertService).sendCertMsg(mobile, area).then(result => {
if (result && result.code) {
return res.json(result);
} else {
... ... @@ -174,7 +174,7 @@ const cert = {
let code = _.trim(req.body.code);
let refer = req.body.refer;
certService.certMobile(uid, mobile, code, area).then(result => {
req.ctx(CertService).certMobile(uid, mobile, code, area).then(result => {
if (result && result.code === 200) {
let url = helpers.urlFormat('/passport/cert/success', {
... ... @@ -207,7 +207,7 @@ const cert = {
let refer = req.body.refer;
let email;
userService.profile(uid).then(info => {
req.ctx(UserService).profile(uid).then(info => {
if (info && info.code === 200) {
email = _.get(info, 'data.email');
} else {
... ... @@ -217,7 +217,7 @@ const cert = {
});
}
certService.relateMobile(uid, email, code, mobile, area).then(result => {
req.ctx(CertService).relateMobile(uid, email, code, mobile, area).then(result => {
if (result && result.code === 200) {
let url = helpers.urlFormat('/passport/cert/success', {
type: 'relate',
... ...
... ... @@ -17,7 +17,7 @@ const helpers = global.yoho.helpers;
const log = global.yoho.logger;
const config = global.yoho.config;
const cache = global.yoho.cache;
const loginService = require('../models/login-service');
const LoginService = require('../models/login-service');
const referWhiteListService = require('../models/refer-service');
const PassportHelper = require('../models/passport-helper');
const simpleHeaderModel = require('../../../doraemon/models/simple-header');
... ... @@ -54,7 +54,7 @@ function doPassportCallback(req, res, user) {
user.openId = user.unionId;
}
return loginService.signinByOpenID(user.nickname, user.openId, user.sourceType, shoppingKey)
return req.ctx(LoginService).signinByOpenID(user.nickname, user.openId, user.sourceType, shoppingKey)
.then((result) => {
if (result.code !== 200) {
return res.redirect(config.siteUrl);
... ... @@ -67,7 +67,7 @@ function doPassportCallback(req, res, user) {
});
} else if (result.data['is_bind'] === 'Y' && result.data.uid) {//eslint-disable-line
return loginService.syncUserSession(result.data, req, res).then(() => {
return req.ctx(LoginService).syncUserSession(result.data, req, res).then(() => {
return refer;
});
}
... ... @@ -178,7 +178,7 @@ const local = {
}
if (_.get(req.body, 'isRemember', 'false') === 'true') {
loginService.rememberAccount({
req.ctx(LoginService).rememberAccount({
area: req.body.areaCode || '86',
account: req.body.account,
password: req.body.password
... ... @@ -199,7 +199,7 @@ const local = {
}
}());
loginService.syncUserSession(user, req, res).then((noCertTip) => {
req.ctx(LoginService).syncUserSession(user, req, res).then((noCertTip) => {
// 弱密码
if (user.code === 510) {
refer = `${config.siteUrl}/passport/back/weak?refer=${refer}`;
... ... @@ -268,7 +268,7 @@ const local = {
});
}
loginService.sendPasswordBySMS(area, mobile).then((result) => {
req.ctx(LoginService).sendPasswordBySMS(area, mobile).then((result) => {
return res.json(result);
}).then(() => {
req.session.captcha = 'yoho4946abcdef#$%&!@';
... ... @@ -286,7 +286,7 @@ const local = {
});
}
loginService.verifyPasswordBySMS(area, mobile, code).then((result) => {
req.ctx(LoginService).verifyPasswordBySMS(area, mobile, code).then((result) => {
if (_.get(result, 'code', 200) !== 200) {
return res.json(result);
}
... ... @@ -316,7 +316,7 @@ const local = {
});
}
loginService.checkUserExitBySMS(area, mobile).then((result) => {
req.ctx(LoginService).checkUserExitBySMS(area, mobile).then((result) => {
if (_.get(result, 'code') !== 200) {
return Promise.reject('check user by sms error');
}
... ... @@ -336,7 +336,7 @@ const local = {
},
qrcode: {
refresh: (req, res, next) => {
loginService.fetchByQrCode().then((result) => {
req.ctx(LoginService).fetchByQrCode().then((result) => {
if (result.code === 200) {
return res.json({
code: 200,
... ... @@ -371,7 +371,7 @@ const local = {
let token = decodeURIComponent(qrcode.substring(qrcode.indexOf('=') + 1));
loginService.checkByQrCode(token).then((result) => {
req.ctx(LoginService).checkByQrCode(token).then((result) => {
if (_.isEmpty(result)) {
return res.json({
code: 400,
... ...
... ... @@ -5,9 +5,9 @@
const _ = require('lodash');
const Promise = require('bluebird');
const passportHelper = require('../models/passport-helper');
const regService = require('../models/reg-service');
const userService = require('../models/user-service');
const loginService = require('../models/login-service');
const RegService = require('../models/reg-service');
const UserService = require('../models/user-service');
const LoginService = require('../models/login-service');
const config = require('../../../config/common');
const simpleHeaderModel = require('../../../doraemon/models/simple-header');
let helpers = global.yoho.helpers;
... ... @@ -76,7 +76,7 @@ let index = (req, res, next) => {
domain: config.cookieDomain
});
regService.getRegData().then((result) => {
req.ctx(RegService).getRegData().then((result) => {
res.render('reg/index', {
simpleHeader: simpleHeaderModel.setSimpleHeaderData(),
title: '新用户注册',
... ... @@ -125,7 +125,7 @@ let checkMobile = (req, res, next) => {
}
// 判断用户是否存在
return userService.findByMobileAsync(area, mobile).then((user) => {
return req.ctx(UserService).findByMobileAsync(area, mobile).then((user) => {
if (!_.isEmpty(user)) {
data.message = '手机号码已经存在';
return res.json(data);
... ... @@ -182,7 +182,7 @@ let sendBindMsg = (req, res, next) => {
}
/* 向手机发送注册验证码 */
let result = yield regService.sendCodeToMobile(area, mobile);
let result = yield req.ctx(RegService).sendCodeToMobile(area, mobile);
req.session.type = 'register-step1';
... ... @@ -210,7 +210,7 @@ let msgCaptcha = (req, res, next) => {
let mobile = req.body.mobile;
let code = req.body.code; // 短信验证码
regService.validMobileCode(area, mobile, code).then((result) => {
req.ctx(RegService).validMobileCode(area, mobile, code).then((result) => {
if (result.code) {
return res.json(result);
} else {
... ... @@ -266,7 +266,7 @@ let mobileRegister = (req, res, next) => {
let password = req.body.password;
let inviteCode = req.body.inviteCode;
let clientIp = req.yoho.clientIp;
let result = yield regService.validMobileCode(area, mobile, code); // 验证注册的标识码是否有效
let result = yield req.ctx(RegService).validMobileCode(area, mobile, code); // 验证注册的标识码是否有效
if (!result.code || result.code !== 200) {
data.message = '验证码错误';
... ... @@ -274,7 +274,7 @@ let mobileRegister = (req, res, next) => {
}
/* 手机注册: 调用注册接口*/
let regResult = yield regService.regMobileAes(
let regResult = yield req.ctx(RegService).regMobileAes(
area, mobile, password, code, cookie.getShoppingKey(req), inviteCode, clientIp
);
... ... @@ -286,7 +286,7 @@ let mobileRegister = (req, res, next) => {
// 清除 session type
req.session.type = '';
return loginService.syncUserSession(regResult.data, req, res).then(() => {
return req.ctx(LoginService).syncUserSession(regResult.data, req, res).then(() => {
return res.json({
code: 200,
message: '注册成功',
... ... @@ -305,7 +305,7 @@ let success = (req, res, next) => {
let goUrl = req.query.next || config.siteUrl;
let goShoppingUrl = req.query.goShoppingUrl || config.siteUrl;
regService.getRegData().then((result) => {
req.ctx(RegService).getRegData().then((result) => {
res.render('reg/success', {
title: '注册成功',
module: 'passport',
... ...
... ... @@ -4,181 +4,192 @@
'use strict';
const api = global.yoho.API;
const aes = require('./aes-pwd');
const YOHOBUY_URL = 'https//www.yohobuy.com/';
/**
* 获取地区数据
*/
const getAreaDataAsync = () => {
return api.get('', {
method: 'app.passport.getArea'
}).then(result => {
result.data = result.data.map(value => {
value.areaCode = `+${value.area}`;
if (value.areaCode === '+86') {
value.selected = true;
} else {
value.selected = false;
module.exports = class extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
}
/**
* 获取地区数据
*/
getAreaDataAsync() {
return this.get({
data: {
method: 'app.passport.getArea'
}
}).then(result => {
result.data = result.data.map(value => {
value.areaCode = `+${value.area}`;
delete value.area;
return value;
});
return result;
});
};
/**
* 通过邮箱找回密码
*
* @param string mail 邮箱地址
*/
const sendCodeToEmailAsync = (email) => {
return api.get('', {
method: 'app.register.backpwdByEmail',
email: email
});
};
/**
* 根据邮箱验证码修改密码(调用www.yohobuy.com接口)
*
* @param string pwd 新密码
* @param string code 邮箱验证码
*/
const modifyPasswordByEmailAsync = (pwd, code) => {
const options = {
url: `${YOHOBUY_URL}passport/back/update`,
form: {
pwd: pwd,
're-input': pwd,
code: code
},
timeout: 3000
};
return api._requestFromAPI(options);
};
/**
* 通过手机找回密码
*
* @param string mobile 手机号
* @param integer area 地区码ID
*/
const sendCodeToMobileAsync = (mobile, area) => {
return api.get('', {
mobile: mobile,
area: area,
method: 'app.register.sendBackpwdCodeToMobile'
});
};
/**
* 校验密码修改手机验证码
*
* @param string mobile 手机号
* @param string code 验证码
* @param integer area 地区码ID
*/
const validateMobileCodeAsync = (mobile, code, area) => {
area = area || 86;
return api.get('', {
mobile: mobile,
code: code,
area: area,
method: 'app.register.validBackpwdCode'
});
};
/**
* 根据手机验证码修改密码
*
* @param string mobile 手机号
* @param string token 验证手机验证码返回的token
* @param integer area 地区码ID
*/
const modifyPasswordByMobileAsync = (mobile, token, newpwd, area)=> {
return api.get('', {
mobile: mobile,
token: token,
newpwd: newpwd,
area: area,
method: 'app.register.changepwdByMobileCode'
});
};
/**
* 根据手机验证码修改密码(密码AES加密)
*
* @param string mobile 手机号
* @param string token 验证手机验证码返回的token
* @param integer area 地区码ID
*/
const modifyPasswordByMobileAsyncAes = (mobile, token, newpwd, area)=> {
return api.get('', {
mobile: mobile,
token: token,
newpwd: aes.aesPwd(newpwd),
area: area,
method: 'app.register.changepwdByMobileCodeAES'
});
};
/**
* 验证找回邮件code
*/
const checkEmailCodeAsync = (code) => {
return api.get('', {
code: code,
method: 'web.passport.checkCodeValid'
});
};
if (value.areaCode === '+86') {
value.selected = true;
} else {
value.selected = false;
}
/**
* 根据邮箱code修改密码
*/
const modifyPasswordByEmailCodeAsync = (code, password) => {
return api.get('', {
code: code,
newPwd: password,
method: 'app.register.resetPwdByCode'
});
};
delete value.area;
return value;
});
/**
* 根据邮箱code修改密码(AES密码加密)
*/
const modifyPasswordByEmailCodeAsyncAes = (code, password) => {
return api.get('', {
code: code,
newPwd: aes.aesPwd(password),
method: 'app.register.resetPwdByCodeAES'
});
};
const modPwdByCodeAsync = (params) => {
return api.get('', Object.assign(params, {
method: 'app.password.modPwdByCode',
oldPwd: aes.aesPwd(params.oldPwd),
newPwd: aes.aesPwd(params.newPwd)
}));
};
module.exports = {
getAreaDataAsync,
sendCodeToEmailAsync,
modifyPasswordByEmailAsync,
sendCodeToMobileAsync,
validateMobileCodeAsync,
modifyPasswordByMobileAsync,
modifyPasswordByMobileAsyncAes,
checkEmailCodeAsync,
modifyPasswordByEmailCodeAsync,
modifyPasswordByEmailCodeAsyncAes,
modPwdByCodeAsync
return result;
});
}
/**
* 通过邮箱找回密码
*
* @param string mail 邮箱地址
*/
sendCodeToEmailAsync(email) {
return this.get({
data: {
method: 'app.register.backpwdByEmail',
email: email
}
});
}
/**
* 根据邮箱验证码修改密码(调用www.yohobuy.com接口)
*
* @param string pwd 新密码
* @param string code 邮箱验证码
*/
modifyPasswordByEmailAsync(pwd, code) {
const options = {
url: `${YOHOBUY_URL}passport/back/update`,
form: {
pwd: pwd,
're-input': pwd,
code: code
},
timeout: 3000
};
return this._requestFromAPI(options);
}
/**
* 通过手机找回密码
*
* @param string mobile 手机号
* @param integer area 地区码ID
*/
sendCodeToMobileAsync(mobile, area) {
return this.get({
data: {
mobile: mobile,
area: area,
method: 'app.register.sendBackpwdCodeToMobile'
}
});
}
/**
* 校验密码修改手机验证码
*
* @param string mobile 手机号
* @param string code 验证码
* @param integer area 地区码ID
*/
validateMobileCodeAsync(mobile, code, area) {
area = area || 86;
return this.get({
data: {
mobile: mobile,
code: code,
area: area,
method: 'app.register.validBackpwdCode'
}
});
}
/**
* 根据手机验证码修改密码
*
* @param string mobile 手机号
* @param string token 验证手机验证码返回的token
* @param integer area 地区码ID
*/
modifyPasswordByMobileAsync(mobile, token, newpwd, area) {
return this.get({
data: {
mobile: mobile,
token: token,
newpwd: newpwd,
area: area,
method: 'app.register.changepwdByMobileCode'
}
});
}
/**
* 根据手机验证码修改密码(密码AES加密)
*
* @param string mobile 手机号
* @param string token 验证手机验证码返回的token
* @param integer area 地区码ID
*/
modifyPasswordByMobileAsyncAes(mobile, token, newpwd, area) {
return this.get({
data: {
mobile: mobile,
token: token,
newpwd: aes.aesPwd(newpwd),
area: area,
method: 'app.register.changepwdByMobileCodeAES'
}
});
}
/**
* 验证找回邮件code
*/
checkEmailCodeAsync(code) {
return this.get({
data: {
code: code,
method: 'web.passport.checkCodeValid'
}
});
}
/**
* 根据邮箱code修改密码
*/
modifyPasswordByEmailCodeAsync(code, password) {
return this.get({
data: {
code: code,
newPwd: password,
method: 'app.register.resetPwdByCode'
}
});
}
/**
* 根据邮箱code修改密码(AES密码加密)
*/
modifyPasswordByEmailCodeAsyncAes(code, password) {
return this.get({
data: {
code: code,
newPwd: aes.aesPwd(password),
method: 'app.register.resetPwdByCodeAES'
}
});
}
modPwdByCodeAsync(params) {
return this.get({
data: Object.assign(params, {
method: 'app.password.modPwdByCode',
oldPwd: aes.aesPwd(params.oldPwd),
newPwd: aes.aesPwd(params.newPwd)
})
});
}
};
... ...
... ... @@ -10,219 +10,215 @@ const _ = require('lodash');
const moment = require('moment');
const helpers = global.yoho.helpers;
const api = require('./back-api');
const userService = require('./user-service');
const Api = require('./back-api');
const UserService = require('./user-service');
const passportHelper = require('./passport-helper');
const backHelper = require('./back-helper');
const BACK_LEFT_BANNER_CODE = '3bbaf502c447a2ddad60879042e286d8'; // 找回密码左边的banner
/**
* 验证手机和邮箱输入正确性
*/
const validateEmailOrMobileAsync = (userInput, areaCode) => {
return new Promise(function(resolve, rejected) {
let result = {type: 'email', area: '', phone: ''};
if (passportHelper.validator.isEmail(userInput)) {
result.type = 'email';
result.area = '';
result.phone = userInput;
resolve(result);
} else if (passportHelper.validator.isMobile(userInput)) {
result.type = 'mobile';
result.area = areaCode;
result.phone = userInput;
resolve(result);
} else {
rejected('输入信息出错!');
}
module.exports = class extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
});
this.api = new Api(ctx);
this.userService = new UserService(ctx);
};
/**
* 验证邮件验证码
*/
this.checkEmailCodeAsync = this.api.checkEmailCodeAsync.bind(this.api);
/**
* 查找用户
*/
const findUserAsync = (type, phone, area) => {
return co(function * () {
const MESSAGE = {
mobile: '您输入的手机号码尚未注册!',
email: '您输入的邮件账户尚未注册!',
ok: '验证成功'
};
// 弱密码重置
this.modPwdByCodeAsync = this.api.modPwdByCodeAsync.bind(this.api);
}
const findBy = {
email: userService.findByEmailAsync,
mobile: _.rearg(userService.findByMobileAsync, [1, 0]) // 交换参数
};
/**
* 验证手机和邮箱输入正确性
*/
validateEmailOrMobileAsync(userInput, areaCode) {
return new Promise(function(resolve, rejected) {
let result = {type: 'email', area: '', phone: ''};
if (passportHelper.validator.isEmail(userInput)) {
result.type = 'email';
result.area = '';
result.phone = userInput;
resolve(result);
} else if (passportHelper.validator.isMobile(userInput)) {
result.type = 'mobile';
result.area = areaCode;
result.phone = userInput;
resolve(result);
} else {
rejected('输入信息出错!');
}
const OK = {code: 200, message: MESSAGE.ok};
});
const user = yield findBy[type](phone, area);
}
if (_.isEmpty(user)) {
return {
code: 402,
message: MESSAGE[type]
/**
* 查找用户
*/
findUserAsync(type, phone, area) {
return co(function* () {
const MESSAGE = {
mobile: '您输入的手机号码尚未注册!',
email: '您输入的邮件账户尚未注册!',
ok: '验证成功'
};
}
return OK;
})();
};
/**
* 发送验证码到用户
*/
const sendCodeToUserAsync = (type, mobile, areaCode) => {
let sendTo = {
email: api.sendCodeToEmailAsync,
mobile: api.sendCodeToMobileAsync
};
const findBy = {
email: this.userService.findByEmailAsync.bind(this.userService),
mobile: _.rearg(this.userService.findByMobileAsync.bind(this.userService), [1, 0]) // 交换参数
};
return sendTo[type](mobile, areaCode);
};
const OK = {code: 200, message: MESSAGE.ok};
/**
* 发送找回手机号短信
*/
const sendCodeToMobileAsync = (areaCode, mobile) => {
return api.sendCodeToMobileAsync(mobile, areaCode);
};
const user = yield findBy[type](phone, area);
/**
* 获得首页的数据
*/
const indexPageDataAsync = () => {
return co(function *() {
let banner = yield passportHelper.getLeftBannerAsync(BACK_LEFT_BANNER_CODE);
let countryList = passportHelper.getCountry();
return {
back: {
coverHref: banner.url,
coverImg: banner.img,
countryCode: 86,
countryName: '中国',
captchaUrl: helpers.urlFormat('/passport/imagesNode', {t: moment().unix()}),
countryList: countryList
if (_.isEmpty(user)) {
return {
code: 402,
message: MESSAGE[type]
};
}
return OK;
}).bind(this)();
}
/**
* 发送验证码到用户
*/
sendCodeToUserAsync(type, mobile, areaCode) {
let sendTo = {
email: this.api.sendCodeToEmailAsync.bind(this.api),
mobile: this.api.sendCodeToMobileAsync.bind(this.api)
};
})();
};
/**
* 验证手机验证码
*/
const verifyCodyByMobileAsync = (area, mobile, mobileCode) => {
const ERR = {
code: 400,
message: '验证码错误!',
data: helpers.urlFormat('/passport/back/index')
};
return api.validateMobileCodeAsync(mobile, mobileCode, area)
.then(result => {
if (!(result.code && result.code === 200)) {
return ERR;
}
return sendTo[type](mobile, areaCode);
}
let data = {
mobile: mobile,
area: area,
token: result.data.token,
createdAt: moment().unix()
};
/**
* 发送找回手机号短信
*/
sendCodeToMobileAsync(areaCode, mobile) {
return this.api.sendCodeToMobileAsync(mobile, areaCode);
}
data.code = new Buffer(backHelper.makeToken(data)).toString('base64');
/**
* 获得首页的数据
*/
indexPageDataAsync() {
return co(function* () {
let banner = yield passportHelper.getLeftBannerAsync(BACK_LEFT_BANNER_CODE);
let countryList = passportHelper.getCountry();
return {
code: 200,
message: '验证成功',
data: helpers.urlFormat('/passport/back/backcode', data)
back: {
coverHref: banner.url,
coverImg: banner.img,
countryCode: 86,
countryName: '中国',
captchaUrl: helpers.urlFormat('/passport/imagesNode', {t: moment().unix()}),
countryList: countryList
}
};
});
};
/**
* 手机 token 合法性验证
*/
const authRequest = (data, token) => {
if (!backHelper.validateToken(data, token)) {
return {};
})();
}
let existTime = moment.duration(60, 'minutes').asSeconds();
let isExpired = (moment().unix() - data.createdAt) > existTime;
/**
* 验证手机验证码
*/
verifyCodyByMobileAsync(area, mobile, mobileCode) {
const ERR = {
code: 400,
message: '验证码错误!',
data: helpers.urlFormat('/passport/back/index')
};
if (isExpired) {
return {};
} else {
return data;
}
};
return this.api.validateMobileCodeAsync(mobile, mobileCode, area)
.then(result => {
if (!(result.code && result.code === 200)) {
return ERR;
}
/**
* 更新密码接口
*/
const updatePwdAsync = (emailToken, mobileToken, newPassword) => {
return co(function * () {
let result = {type: 'mobile', status: false};
const ERR = {type: 'unknown', status: false};
if (!_.isEmpty(mobileToken)) {
if (!mobileToken.mobile || mobileToken.uid) {
return ERR;
}
let data = {
mobile: mobile,
area: area,
token: result.data.token,
createdAt: moment().unix()
};
let mobile = mobileToken.mobile;
let area = mobileToken.area;
let token = mobileToken.token;
let modifyStatus = yield api.modifyPasswordByMobileAsyncAes(mobile, token, newPassword, area);
data.code = new Buffer(backHelper.makeToken(data)).toString('base64');
if (!modifyStatus.code || modifyStatus.code !== 200) {
return ERR;
}
return {
code: 200,
message: '验证成功',
data: helpers.urlFormat('/passport/back/backcode', data)
};
});
result.type = 'mobile';
result.status = true;
} else {
let modifyStatus = yield api.modifyPasswordByEmailCodeAsyncAes(emailToken, newPassword);
}
if (!modifyStatus.code || modifyStatus.code !== 200) {
return ERR;
}
/**
* 手机 token 合法性验证
*/
authRequest(data, token) {
if (!backHelper.validateToken(data, token)) {
return {};
}
let existTime = moment.duration(60, 'minutes').asSeconds();
let isExpired = (moment().unix() - data.createdAt) > existTime;
result.type = 'email';
result.status = true;
if (isExpired) {
return {};
} else {
return data;
}
}
return result;
})();
};
/**
* 更新密码接口
*/
updatePwdAsync(emailToken, mobileToken, newPassword) {
return co(function* () {
let result = {type: 'mobile', status: false};
const ERR = {type: 'unknown', status: false};
if (!_.isEmpty(mobileToken)) {
if (!mobileToken.mobile || mobileToken.uid) {
return ERR;
}
let mobile = mobileToken.mobile;
let area = mobileToken.area;
let token = mobileToken.token;
let modifyStatus = yield this.api.modifyPasswordByMobileAsyncAes(mobile, token, newPassword, area);
if (!modifyStatus.code || modifyStatus.code !== 200) {
return ERR;
}
result.type = 'mobile';
result.status = true;
} else {
let modifyStatus = yield this.api.modifyPasswordByEmailCodeAsyncAes(emailToken, newPassword);
if (!modifyStatus.code || modifyStatus.code !== 200) {
return ERR;
}
result.type = 'email';
result.status = true;
}
/**
* 验证邮件验证码
*/
const checkEmailCodeAsync = api.checkEmailCodeAsync;
// 弱密码重置
const modPwdByCodeAsync = api.modPwdByCodeAsync;
module.exports = {
validateEmailOrMobileAsync,
findUserAsync,
sendCodeToUserAsync,
sendCodeToMobileAsync,
indexPageDataAsync,
verifyCodyByMobileAsync,
authRequest,
updatePwdAsync,
checkEmailCodeAsync,
modPwdByCodeAsync
return result;
}).bind(this)();
}
};
... ...
... ... @@ -5,95 +5,87 @@
* @date 2016/06/21
*/
'use strict';
module.exports = class extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
}
const api = global.yoho.API;
bindCheck(mobile, openId, sourceType, area) {
let params = {
method: 'app.passport.signCheck',
area: area,
mobile: mobile,
open_id: openId,
source_type: sourceType
};
const bindCheck = (mobile, openId, sourceType, area) => {
let params = {
method: 'app.passport.signCheck',
area: area,
mobile: mobile,
open_id: openId,
source_type: sourceType
};
return this.get({data: params});
}
return api.get('', params);
};
sendBindMsg(area, mobile) {
let params = {
method: 'app.passport.smsbind',
mobile: mobile,
area: area
};
const sendBindMsg = (area, mobile) => {
let params = {
method: 'app.passport.smsbind',
mobile: mobile,
area: area
};
return this.get({data: params});
}
return api.get('', params);
};
checkBindCode(area, mobile, code) {
return this.get({data: {
method: 'app.register.validRegCode',
mobile: mobile,
area: area,
code: code
}});
}
const checkBindCode = (area, mobile, code) => {
return api.get('', {
method: 'app.register.validRegCode',
mobile: mobile,
area: area,
code: code
});
};
bindMobile(openId, sourceType, mobile, area, password, nickname) {
let params = {
method: 'app.passport.bind',
mobile: mobile,
open_id: openId,
source_type: sourceType,
area: area
};
const bindMobile = (openId, sourceType, mobile, area, password, nickname) => {
let params = {
method: 'app.passport.bind',
mobile: mobile,
open_id: openId,
source_type: sourceType,
area: area
};
if (password) {
params.password = password;
}
if (password) {
params.password = password;
}
if (nickname) {
params.nickname = nickname;
}
if (nickname) {
params.nickname = nickname;
return this.get({data: params});
}
return api.get('', params);
};
const relateMobile = (openId, sourceType, mobile, area) => {
return api.get('', {
method: 'app.passport.relatedMobile',
mobile: mobile,
openId: openId,
source_type: sourceType,
area: area
});
};
const changeCheck = (mobile, area) => {
return api.get('', {
method: 'app.passport.changeCheck',
mobile: mobile,
area: area
});
};
relateMobile(openId, sourceType, mobile, area) {
return this.get({data: {
method: 'app.passport.relatedMobile',
mobile: mobile,
openId: openId,
source_type: sourceType,
area: area
}});
}
const changeMobile = (uid, mobile, area, code) => {
return api.get('', {
method: 'app.passport.changeMobile',
mobile: mobile,
uid: uid,
code: code,
area: area
});
};
changeCheck(mobile, area) {
return this.get({data: {
method: 'app.passport.changeCheck',
mobile: mobile,
area: area
}});
}
module.exports = {
bindCheck,
sendBindMsg,
checkBindCode,
bindMobile,
relateMobile,
changeCheck,
changeMobile
changeMobile(uid, mobile, area, code) {
return this.get({data: {
method: 'app.passport.changeMobile',
mobile: mobile,
uid: uid,
code: code,
area: area
}});
}
};
... ...
... ... @@ -7,6 +7,10 @@
'use strict';
const api = require('./bind-api');
const BindApi = require('./bind-api');
module.exports = api;
module.exports = class extends BindApi {
constructor(ctx) {
super(ctx);
}
};
... ...
... ... @@ -4,24 +4,24 @@
'use strict';
const api = global.yoho.API;
const goodsCount = (uid, shoppingKey) => {
let params = {
method: 'app.Shopping.count'
};
if (uid) {
params.uid = uid;
module.exports = class extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
}
if (shoppingKey) {
params.shopping_key = shoppingKey;
}
goodsCount(uid, shoppingKey) {
let params = {
method: 'app.Shopping.count'
};
return api.get('', params);
};
if (uid) {
params.uid = uid;
}
if (shoppingKey) {
params.shopping_key = shoppingKey;
}
module.exports = {
goodsCount
return this.get({data: params});
}
};
... ...
... ... @@ -5,15 +5,19 @@
'use strict';
const api = require('./cart-api');
const Api = require('./cart-api');
const _ = require('lodash');
const goodsCount = (uid, shoppingKey) => {
return api.goodsCount(uid, shoppingKey).then(result => _.get(result, 'data.cart_goods_count', 0));
};
module.exports = class extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
this.api = new Api(ctx);
}
module.exports = {
goodsCount
goodsCount(uid, shoppingKey) {
return this.api.goodsCount(uid, shoppingKey).then(result => _.get(result, 'data.cart_goods_count', 0));
}
};
... ...
... ... @@ -4,92 +4,61 @@
'use strict';
const api = global.yoho.API;
const certCheck = (mobile, area) => {
let params = {
method: 'app.passport.checkIsCanBind',
area: area,
mobile: mobile
};
return api.get('', params);
};
const sendCertMsg = (mobile, area) => {
let params = {
method: 'app.passport.smsbind',
mobile: mobile,
area: area
};
return api.get('', params);
};
/* const checkCertCode = (area, mobile, code) => {
return api.get('', {
method: 'app.register.validRegCode',
mobile: mobile,
area: area,
code: code
});
};*/
const certMobile = (uid, mobile, code, area) => {
let params = {
method: 'app.passport.changeMobile',
uid: uid,
mobile: mobile,
area: area,
code: code
};
return api.get('', params);
module.exports = class extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
}
certCheck(mobile, area) {
let params = {
method: 'app.passport.checkIsCanBind',
area: area,
mobile: mobile
};
return this.get({data: params});
}
sendCertMsg(mobile, area) {
let params = {
method: 'app.passport.smsbind',
mobile: mobile,
area: area
};
return this.get({data: params});
}
certMobile(uid, mobile, code, area) {
let params = {
method: 'app.passport.changeMobile',
uid: uid,
mobile: mobile,
area: area,
code: code
};
return this.get({data: params});
}
relateMobile(uid, email, code, mobile, area) {
return this.get({data: {
method: 'app.passport.relatedMobileAndEmail',
uid: uid,
email: email,
mobile: mobile,
code: code,
area: area
}});
}
checkEmailCertTip(uid) {
let param = {
method: 'app.passport.checkIsBindedOrRelated',
uid: uid
};
return this.get({data: param});
}
};
const relateMobile = (uid, email, code, mobile, area) => {
return api.get('', {
method: 'app.passport.relatedMobileAndEmail',
uid: uid,
email: email,
mobile: mobile,
code: code,
area: area
});
};
/* const changeCheck = (mobile, area) => {
return api.get('', {
method: 'app.passport.changeCheck',
mobile: mobile,
area: area
});
};*/
/* const changeMobile = (uid, mobile, area, code) => {
return api.get('', {
method: 'app.passport.changeMobile',
mobile: mobile,
uid: uid,
code: code,
area: area
});
};*/
const checkEmailCertTip = (uid) => {
let param = {
method: 'app.passport.checkIsBindedOrRelated',
uid: uid
};
return api.get('', param);
};
module.exports = {
certCheck,
sendCertMsg,
certMobile,
relateMobile,
checkEmailCertTip
};
... ...
'use strict';
const api = require('./cert-api');
const CertApi = require('./cert-api');
module.exports = api;
module.exports = class extends CertApi {
constructor(ctx) {
super(ctx);
}
};
... ...
... ... @@ -5,119 +5,105 @@
'use strict';
const aes = require('./aes-pwd');
const api = global.yoho.API;
const logger = global.yoho.logger;
const signinByPasswordWithAes = (area, profile, password, shoppingKey, clientIp) => {
let param = {
method: 'sesame.flowering.higher',
area: area,
profile: profile,
password: aes.aesPwd(password)
};
if (shoppingKey) {
param.shopping_key = shoppingKey;
module.exports = class extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
}
logger.info('login successfully by password from', clientIp);
signinByPasswordWithAes(area, profile, password, shoppingKey) {
let param = {
method: 'sesame.flowering.higher',
area: area,
profile: profile,
password: aes.aesPwd(password)
};
return api.post('', param, {
headers: {
'user-agent': 'yoho/nodejs',
'X-YOHO-IP': clientIp
if (shoppingKey) {
param.shopping_key = shoppingKey;
}
});
};
const signinBySMS = (area, mobile, token, shoppingKey) => {
let param = {
method: 'app.passport.autoSignin',
area: area,
profile: mobile,
code: token
};
if (shoppingKey) {
param.shopping_key = shoppingKey;
return this.post({data: param});
}
return api.post('', param);
};
signinBySMS(area, mobile, token, shoppingKey) {
let param = {
method: 'app.passport.autoSignin',
area: area,
profile: mobile,
code: token
};
const signinByQrCode = (__1, __2, code, shoppingKey) => { // eslint-disable-line
let param = {
method: 'app.twoDimen.qrCodeLogin',
code: code.substring(code.indexOf('=') + 1)
};
if (shoppingKey) {
param.shopping_key = shoppingKey;
}
if (shoppingKey) {
param.shopping_key = shoppingKey;
return this.post({data: param});
}
return api.post('', param);
};
signinByQrCode(__1, __2, code, shoppingKey) { // eslint-disable-line
let param = {
method: 'app.twoDimen.qrCodeLogin',
code: code.substring(code.indexOf('=') + 1)
};
const checkByQrCode = (code) => {
let param = {
method: 'app.twoDimen.loginCheck',
code: code
};
if (shoppingKey) {
param.shopping_key = shoppingKey;
}
return api.post('', param);
};
return this.post({data: param});
}
const sendPasswordBySMS = (area, mobile) => {
let param = {
method: 'app.message.sendSms',
area: area,
mobile: mobile,
type: 1 // 手机快捷登录短信验证码
};
checkByQrCode(code) {
let param = {
method: 'app.twoDimen.loginCheck',
code: code
};
return api.get('', param);
};
return this.post({data: param});
}
const checkUserExitBySMS = (area, mobile) => {
return api.get('', {
method: 'app.passport.checkUserExist',
area: area,
mobile: mobile
});
};
sendPasswordBySMS(area, mobile) {
let param = {
method: 'app.message.sendSms',
area: area,
mobile: mobile,
type: 1 // 手机快捷登录短信验证码
};
const verifyPasswordBySMS = (area, mobile, code) => {
return api.get('', {
method: 'app.message.verifySmsCode',
area: area,
mobile: mobile,
code: code,
type: 1 // 手机快捷登录短信验证码
});
};
return this.get({data: param});
}
const signinByOpenID = (nickname, openId, sourceType, shoppingKey) => {
let param = {
nickname: nickname,
openId: openId,
source_type: sourceType,
method: 'app.passport.signinByOpenID'
};
checkUserExitBySMS(area, mobile) {
return this.get({data: {
method: 'app.passport.checkUserExist',
area: area,
mobile: mobile
}});
}
if (shoppingKey) {
param.shopping_key = shoppingKey;
verifyPasswordBySMS(area, mobile, code) {
return this.get({data: {
method: 'app.message.verifySmsCode',
area: area,
mobile: mobile,
code: code,
type: 1 // 手机快捷登录短信验证码
}});
}
return api.get('', param);
};
signinByOpenID(nickname, openId, sourceType, shoppingKey) {
let param = {
nickname: nickname,
openId: openId,
source_type: sourceType,
method: 'app.passport.signinByOpenID'
};
if (shoppingKey) {
param.shopping_key = shoppingKey;
}
module.exports = {
signinByPasswordWithAes,
signinBySMS,
signinByQrCode,
checkByQrCode,
sendPasswordBySMS,
checkUserExitBySMS,
verifyPasswordBySMS,
signinByOpenID
return this.get({data: param});
}
};
... ...