Authored by biao

merge feature/index

... ... @@ -33,6 +33,7 @@ app.locals.version = pkg.version;
// 指定libray目录
global.library = path.resolve('./library');
global.middleware = path.resolve('./doraemon/middleware');
app.set('view engine', '.hbs');
... ...
... ... @@ -6,17 +6,51 @@
'use strict';
const _ = require('lodash');
const channelModel = require('../models/index');
exports.boysIndex = (req, res) => {
channelModel.getContent('boys').then(data => {
res.render('boys', data);
exports.index = (req, res) => {
const channelType = req.path.substring(1);
channelModel.getContent(channelType).then(data => {
res.render('channel', data);
});
};
exports.getbrandFloorDataAjax = (req, res) => {
channelModel.getbrandFloorDataAjax('boys').then(data => {
const channelType = req.query.channelType || 'boys';
channelModel.getbrandFloorDataAjax(channelType).then(data => {
res.json(data);
});
};
exports.getNewArrival = (req, res) => {
let reqBody = req.body,
pageIndex = reqBody.pageIndex,
pageCount = reqBody.pageCount,
channel = reqBody.type,
goods = [],
result = {};
if (pageIndex < 0) {
pageIndex = 0;
}
if (pageCount < 0 || pageCount > 50) {
pageCount = 20;
}
channelModel.getNewArrival(channel).then(data => {
goods = _.slice(data, pageIndex, pageIndex + pageCount);
if (goods.length !== 0) {
result = {
code: 200,
goods: goods
};
}
res.send(result);
});
};
... ...
... ... @@ -8,18 +8,42 @@
const _ = require('lodash');
const ServiceAPI = require(`${global.library}/api`).ServiceAPI;
const SearchAPI = require(`${global.library}/api`).SearchAPI;
const sign = require(`${global.library}/sign`);
const helpers = require(`${global.library}/helpers`);
const images = require(`${global.middleware}/images`);
const serviceApi = new ServiceAPI();
const searchApi = new SearchAPI();
const headerModel = require('../../../doraemon/models/header');
// 创意生活
// const CODE_LIFESTYLE_CHANNEL_1 = '380c38155fd8beee10913a3f5b462da6';
const getShelveTime = duration => {
let today = new Date(),
todayMil = today.getTime().toString().substr(0, 10),
startDayMil = (today.setMonth(today.getMonth() - duration)).toString().substr(0, 10);
// const CODE_LIFESTYLE_CHANNEL_2 = '665f7c2fb9d037ee820766953ee34bf7';
return `${startDayMil},${todayMil}`;
// `
};
// 获取可用的标题
const getText = data => {
let text = data.split(' ')[0];
const regResult = /\w+/.exec(text);
if (data === 'GIRL KIDS' || data === 'BOY KIDS') {
return data;
}
if (regResult) {
text = text.replace(regResult[0], '');
}
return text;
};
const channelMap = {
boys: {
... ... @@ -32,12 +56,226 @@ const channelMap = {
},
kids: {
code: 'd71f4b27f2a7229fbb31a4bc490a6f36',
gender: 'kids'
gender: '2,3'
},
lifestyle: {
code: '8a341ca7eacc069ba80f02dec80eaf34',
gender: 'lifestyle'
// code: '380c38155fd8beee10913a3f5b462da6',
// code: '665f7c2fb9d037ee820766953ee34bf7',
gender: '2,3'
}
};
const sortMap = {
boys: [
{sort: 147, viewNum: 5}, // 休闲运动鞋
{sort: 129, viewNum: 5}, // 休闲裤
{sort: 152, viewNum: 5}, // 双肩包
{misort: 11, viewNum: 5}, // T恤
{sort: 115, viewNum: 5}, // 衬衫
{sort: 130, viewNum: 5}, // 牛仔裤
{misort: 60, viewNum: 5}, // 帽子
{sort: 124, viewNum: 5}, // 夹克
{sort: 119, viewNum: 5}, // 卫衣
{sort: 162, viewNum: 5}, // 手表
{sort: 148, viewNum: 5}, // 靴子
{misort: 65, viewNum: 5}, // 首饰
{sort: 151, viewNum: 5}, // 时装鞋
{misort: 61, viewNum: 5}, // 太阳镜
{misort: 39, viewNum: 5}, // 袜子
{sort: 346, viewNum: 5}, // 运动裤
{sort: 131, viewNum: 5}, // 短裤
{misort: 66, viewNum: 5}, // 配饰
{misort: 309, viewNum: 5}, // 内裤
{misort: 30, viewNum: 5}, // 打底裤/紧身裤
{sort: 342, viewNum: 5} // 邮差包
],
girls: [
{misort: 16, viewNum: 4}, // 卫衣
{misort: 12, viewNum: 4}, // 衬衫
{misort: 44, viewNum: 4}, // 休闲/运动鞋
{misort: 11, viewNum: 4}, // T恤
{misort: 21, viewNum: 4}, // 夹克
{misort: 257, viewNum: 4}, // 毛衣/针织
{misort: 22, viewNum: 4}, // 大衣/风衣
{misort: 26, viewNum: 4}, // 休闲裤
{misort: 27, viewNum: 4}, // 牛仔裤
{misort: 31, viewNum: 4}, // 连衣裙
{misort: 32, viewNum: 4}, // 半身裙
{misort: 48, viewNum: 4}, // 时装鞋
{misort: 49, viewNum: 4}, // 双肩包
{misort: 50, viewNum: 4}, // 手拎包/单肩包
{misort: 60, viewNum: 4}, // 帽子
{misort: 65, viewNum: 4}, // 首饰
{misort: 59, viewNum: 4}, // 手表
{misort: 61, viewNum: 4}, // 太阳镜
{misort: 66, viewNum: 4} // 配饰
],
kids: [
{misort: 366, viewNum: 4}, // T恤
{misort: 367, viewNum: 4}, // 衬衫
{misort: 396, viewNum: 4}, // 卫衣
{misort: 400, viewNum: 4}, // // 毛衣/针织
{misort: 404, viewNum: 4}, // 夹克
{misort: 369, viewNum: 4}, // 休闲裤
{misort: 388, viewNum: 4}, // 牛仔裤
{misort: 371, viewNum: 4}, // 连衣裙
{misort: 370, viewNum: 4}, // 半身裙
{misort: 368, viewNum: 4}, // 休闲/运动鞋
{misort: 392, viewNum: 4}, // 双肩包
{misort: 414, viewNum: 4}, // 帽子
{misort: 372, viewNum: 4}, // 短裤
{misort: 384, viewNum: 4}, // 打底裤/紧身裤
{misort: 382, viewNum: 4}, // 凉鞋/拖鞋
{misort: 402, viewNum: 4}, // 马甲
{misort: 386, viewNum: 4}, // 背心
{misort: 406, viewNum: 4}, // 大衣/风衣
{misort: 430, viewNum: 4}, // 羽绒服
{misort: 423, viewNum: 4}, // 棉衣
{misort: 417, viewNum: 4} // 套装
],
lifestyle: [
{sort: 171, viewNum: 5}, // 耳机
{sort: 398, viewNum: 5}, // 只能装备
{sort: 185, viewNum: 5}, // 相机
{misort: 259, viewNum: 5}, // 美妆
{sort: 267, viewNum: 5}, // 杯子/水壶
{sort: 313, viewNum: 5}, // 手机/ipad壳套
{sort: 211, viewNum: 5}, // 数码配件
{sort: 292, viewNum: 5}, // 玩偶
{sort: 272, viewNum: 5}, // 储物收纳
{sort: 183, viewNum: 5}, // 启用家居
{sort: 273, viewNum: 5}, // 厨具/餐具
{sort: 271, viewNum: 5} // 靠枕/靠垫/抱枕
]
};
const getNavs = rawNavs => {
const navs = rawNavs;
let list = [];
_.forEach(navs, it => {
let obj = {};
obj.name = it.name;
obj.href = it.url;
list.push(obj);
});
return list;
};
// 构建url
const httpBuildQuery = data => {
return searchApi.get('/search.json', data);
};
/**
* 格式化商品信息
*
* @param array $productData 需要格式化的商品数据
* @param bool $showTags 控制是否显示标签
* @param bool $showNew 控制是否显示NEW图标
* @param bool $showSale 控制是否显示SALE图标
* @param int $width 图片的宽度
* @param int $height 图片的高度
* @param bool $isApp 判断是不是APP访问
* @param bool $showPoint 商品价格是否显示小数位,默认显示
* @return array | false
*/
const formatProduct = (productData, showTags, showNew, showSale, width, height, isApp, showPoint) => {
let result = {};
// 默认值
if (!showTags) {
showTags = true;
}
if (!showNew) {
showNew = true;
}
if (!showSale) {
showSale = true;
}
if (!width) {
width = 290;
}
if (!height) {
height = 388;
}
if (!isApp) {
isApp = false;
}
if (!showPoint) {
showPoint = true;
}
// 商品信息有问题,则不显示
if (!productData.product_skn || !productData.goods_list[0]) {
return false;
}
// 市场价和售价一样,则不显示市场价
if (parseInt(productData.market_price, 0) === parseInt(productData.sales_price, 0)) {
productData.market_price = false;
}
// 设置默认图片
_.forEach(productData.goods_list, item => {
if (item.is_default === 'Y') {
productData.default_images = item.images_url;
}
});
if (!productData.default_images) {
productData.default_images = productData.goods_list[0].images_url;
}
result.id = productData.product_skn;
result.product_id = productData.product_id;
result.thumb = images.getImageUrl(productData.default_images, width, height);
result.name = productData.product_name;
result.price = !productData.market_price ? false : productData.market_price;
result.salePrice = productData.sales_price;
if (showPoint) {
result.price += '.00';
result.salePrice += '.00';
}
result.is_soon_sold_out = (productData.is_soon_sold_out === 'Y');
result.url = 'http://item.yohobuy.com/product/pro_' +
productData.product_id + '_' +
productData.goods_list[0].goods_id + '/' +
productData.cn_alphabet + '.html';
// APP访问需要加附加的参数
// 备注:如果以后APP的接口太多,可以把这边参数提取出来,变成一个公共的方法来生成,便于以后管理维护
if (isApp) {
result.url += '?openby:yohobuy={"action":"go.productDetail","params":{"product_skn":' +
productData.product_skn + '}}';
}
if (showTags) {
result.tags = {};
result.tags.is_new = showNew && productData.is_new && productData.is_new === 'Y'; // 新品
result.tags.is_discount = showSale && productData.is_discount && productData.is_discount === 'Y'; // 在售
result.tags.is_limited = productData.is_limited && productData.is_limited === 'Y'; // 限量
result.tags.is_yohood = productData.is_yohood && productData.is_yohood === 'Y'; // YOHOOD
result.tags.midYear = productData['mid-year'] && productData['mid-year'] === 'Y'; // 年中
result.tags.yearEnd = productData['year-end'] && productData['year-end'] === 'Y'; // 年末
result.tags.is_advance = productData.is_advance && productData.is_advance === 'Y'; // 再到着
if (result.is_soon_sold_out && result.tags.is_discount) {
result.tags.is_new = false;// 打折与即将售完组合显示打折
} else if (result.tags.is_discount &&
(result.tags.is_new || result.tags.is_limited || result.tags.is_yohood || result.tags.is_advance)) {
result.tags.is_discount = false;// 打折与其它组合则隐藏打折
} else if (result.tags.is_yohood && result.tags.is_new) {
result.tags.is_new = false;// YOHOOD和新品组合显示YOHOOD
}
}
return result;
};
const getBannerList = data => {
... ... @@ -56,6 +294,30 @@ const getBannerList = data => {
return list;
};
const getDebrisSlide = data => {
let floorData = {
debrisSlider: {
left: [],
center: [],
right: []
}
};
_.mapKeys(data, (value, key) => {
_.forEach(value, slideData => {
let obj = {};
obj.href = slideData.url;
obj.img = slideData.img;
floorData.debrisSlider[key].push(obj);
});
});
return floorData;
};
const getadbannerData = data => {
const obj = {
adbanner: {
... ... @@ -80,25 +342,35 @@ const getSlideData = srcData => {
}
};
slideData.slide.list = getBannerList(srcData.big_image);
slideData.slide.pagination = getBannerList(srcData.list);
if (srcData.big_image) {
slideData.slide.list = getBannerList(srcData.big_image);
}
if (srcData.list) {
slideData.slide.pagination = getBannerList(srcData.list);
}
if (_.isArray(srcData)) {
slideData.slide.list = getBannerList(srcData);
}
return slideData;
};
const getNewReportFloorData = args => {
let item = args[0].data;
let secondItem = args[1].data;
let thirdItem = args[2].data;
let forthItem = args[3];
const title = args[0].data.text;
let item = args[1].data;
let secondItem = args[2].data;
let thirdItem = args[3].data;
let forthItem = args[4];
let list = [];
let obj = {};
const data = {
newReport: {
name: '最新速报',
name: title,
list: []
}
};
... ... @@ -139,15 +411,20 @@ const getNewReportFloorData = args => {
return floorDatas;
};
const setChannelType = (obj, type) => {
obj[type + 'Channel'] = true;
};
// 优选品牌
const getPreBrandTopData = args => {
let item = args[0].data;
const getPreBrandTopData = (args, type) => {
const title = args[0].data.text;
let item = args[1].data;
const data = {
preferenceBrands: {
name: '优选品牌',
name: title,
imgBrand: [],
brandUrl: helpers.urlFormat('getbrandFloorDataAjax')
brandUrl: helpers.urlFormat('getbrandFloorDataAjax?channelType=' + type)
}
};
... ... @@ -160,11 +437,13 @@ const getPreBrandTopData = args => {
data.preferenceBrands.imgBrand.push(o);
});
setChannelType(data.preferenceBrands, type);
return data;
};
// 热门品类
const getHotGoodsFloorData = (args) => {
const getHotGoodsFloorData = (args, type) => {
let item = args[0];
let nextItem = args[1];
... ... @@ -175,7 +454,6 @@ const getHotGoodsFloorData = (args) => {
category = [],
brands = [],
types = [],
navs = {},
products = [];
const data = {
... ... @@ -184,16 +462,16 @@ const getHotGoodsFloorData = (args) => {
}
};
_.forEach(item.data.menuNav.list, (it) => {
_.forEach(item.data.menuNav.list, it => {
let obj = {};
obj.name = it.name;
obj.href = it.url;
category.push(obj);
});
_.forEach(item.data.menuNav.blocks, (it) => {
_.forEach(item.data.menuNav.blocks, it => {
let obj = {};
obj.name = it.title;
... ... @@ -209,7 +487,7 @@ const getHotGoodsFloorData = (args) => {
obj.href = it.url;
obj.img = it.img;
if (idx === 0 || idx === 4) {
if (idx === 0 || (idx === 4 && type === 'boys')) {
brands.push(obj);
} else {
types.push(obj);
... ... @@ -226,28 +504,29 @@ const getHotGoodsFloorData = (args) => {
products.push(obj);
});
navs.name = item.data.navs.list[0].name;
navs.href = item.data.navs.list[0].url;
object.name = item.data.name;
object.keyword = keyword;
object.category = category;
object.brands = brands;
object.types = types;
object.navs = navs;
object.navs = getNavs(item.data.navs.list);
object.products = products;
list.push(object);
data.recommend.tplrecommend = list;
setChannelType(data.recommend, type);
return data;
};
// 人气单品
const getSingleHotFloorData = args => {
const getBoysSingleHot = (args, type) => {
const len = 10;
const data = {
singlehot: {
name: '人气单品',
name: args[0].data.text,
imgHot: []
}
};
... ... @@ -262,14 +541,14 @@ const getSingleHotFloorData = args => {
let obj = {};
if (i === 1) {
val = args[0].data[0]; // 第二个是大图
val = args[1].data[0]; // 第二个是大图
} else if (i === len - 1) {
val = args[0].data[1]; // 最后一个是大图
val = args[1].data[1]; // 最后一个是大图
} else {
if (pos > 1) { // 小图
pos = pos - 1;
}
val = args[1].data[pos];
val = args[2].data[pos];
}
obj.href = val.url;
obj.img = val.src;
... ... @@ -277,23 +556,236 @@ const getSingleHotFloorData = args => {
}
data.singlehot.imgHot = list;
setChannelType(data.singlehot, type);
floorDatas.push(data);
if (args[2].template_name === 'single_image') {
adData = getadbannerData(args[2].data[0]);
if (args[3].template_name === 'single_image') {
adData = getadbannerData(args[3].data[0]);
floorDatas.push(adData);
}
return floorDatas;
};
const getGirlsSingleHot = args => {
let goods = args[2].data;
let skns = '';
_.forEach(goods, good => {
skns += good.id + ' ';
});
return searchApi.get('/search.json', {
client_type: 'web',
query: skns,
order: 'shelve_time:desc',
status: 1,
sales: 'Y',
attribute_not: '2',
stocknumber: 1,
page: 1,
viewNum: 60
});
};
// 人气单品
const getSingleHotFloorData = (args, type) => {
if (type === 'boys') {
return getBoysSingleHot(args, type);
} else {
return getGirlsSingleHot(args, type);
}
};
const getAsyncSingleHot = (args, queryResult, type) => {
const data = {
singlehot: {
name: args[0].data.text,
navs: [],
imgHot: [],
brands: []
}
};
if (args[3].template_name === 'app_icon_list') {
_.forEach(args[3].data, it => {
let obj = {};
obj.href = it.url;
obj.name = it.title;
obj.img = it.src;
data.singlehot.brands.push(obj);
});
}
_.forEach(queryResult.data.product_list, (it, index) => {
let obj = {};
const formatData = formatProduct(it, true, true, true, 280, 373);
if (index > 12) {
return;
}
obj.price = formatData.salePrice;
obj.href = formatData.url;
obj.img = formatData.thumb;
obj.name = formatData.name;
if (index < 3) {
obj.tip = 'TOP' + (index + 1);
}
data.singlehot.imgHot.push(obj);
});
data.singlehot.navs = getNavs(args[1].data);
setChannelType(data.singlehot, type);
return data;
};
const processFloorDataWithQueryReusult = (rawData, floorData, queryResult, title, type) => {
let data = {};
_.forEach(rawData, (subData, index) => {
const text = subData.data.text && getText(subData.data.text);
if (text === title) {
data = getAsyncSingleHot(rawData.slice(index, index + 4), queryResult, type);
}
});
return data;
};
/**
* 组装最新上架楼层数据
*
* @param string data
* return obj
*/
const getNewGoodsFloorData = args => {
const data = {
newArrivls: {
name: args[0].data.text,
navs: []
}
};
data.newArrivls.navs = getNavs(args[1].data);
return data;
};
/**
* 获取最新上架商品数据
*
* @param string $channel
* @return array
*/
exports.getNewArrival = channel => {
let rel = [],
sortList = sortMap[channel],
params = {
order: 'shelve_time:desc',
status: 1,
sales: 'Y',
attribute_not: 2,
stocknumber: 3,
shelve_time: getShelveTime(20)
};
params.gender = channelMap[channel].gender;
_.forEach(sortList, (item) => {
let data = Object.assign(item, params);
rel.push(httpBuildQuery(data));
});
return Promise.all(rel).then(res => {
let data = [],
result = [];
_.forEach(sortList, (it, index) => {
if (res[index].data.product_list.length === sortList[index].viewNum) {
data = data.concat(res[index].data.product_list);
}
});
_.forEach(data, (item) => {
result.push(formatProduct(item, true, true, true, 280, 373));
});
return result;
});
};
const getCategoryFloorData = args => {
const data = {
category: {
name: args[0].data.text,
navs: getNavs(args[1].data),
list: []
}
};
_.forEach(args[2].data, (it, index) => {
let obj = {};
obj.href = it.url;
obj.img = it.src;
// 设置图片大小
if (index === 1) {
obj.w = '377;';
obj.h = '504;';
} else {
obj.w = '185';
obj.h = '510';
}
data.category.list.push(obj);
});
return data;
};
const getAccordionFloorData = args => {
let data = {
accordion: {
name: args[0].data.text,
navs: getNavs(args[1].data),
slide: []
}
};
_.forEach(args[2].data, it => {
let obj = {};
obj.name = it.title;
obj.img = it.src;
obj.href = it.url;
data.accordion.slide.push(obj);
});
return data;
};
const requestContent = type => {
let data = sign.apiSign({
/* eslint-disable */
client_type: 'web',
/* eslint-disable */
client_type: 'web',
/* eslint-enable */
content_code: channelMap[type || 'boys'].code,
gender: channelMap[type || 'boys'].gender,
... ... @@ -309,35 +801,90 @@ const floorMap = {
hot: getHotGoodsFloorData,
最新速报: getNewReportFloorData,
人气单品: getSingleHotFloorData,
'GIRL KIDS': getSingleHotFloorData,
'BOY KIDS': getSingleHotFloorData,
优选品牌: getPreBrandTopData,
ad: getadbannerData
最新上架: getNewGoodsFloorData,
ad: getadbannerData,
category: getCategoryFloorData,
accordion: getAccordionFloorData,
debrisSlide: getDebrisSlide
};
const processFloorData = rawData => {
const processFloorData = (rawData, type) => {
let floorList = [];
let searchPromise = [];
let singlehotFloorIndex = [];
let singlehotFloorTitile = [];
const bigFloorLength = 5;
const normalFloorLength = 3;
const hotCategoryLength = 2;
_.forEach(rawData, (data, index) => {
let floorData = null;
if (data.template_name === 'recommend_content_three') {
if (data.template_name === 'recommend_content_three' ||
(data.template_intro === '焦点图' && index === 0)) { // 处理banner
floorData = floorMap.slide.call(null, data.data);
} else if (data.template_intro === '热门品类') {
floorData = floorMap.hot.call(null, rawData.slice(index, index + 2));
} else if (data.data.text) {
floorData = floorMap[data.data.text] &&
floorMap[data.data.text].call(null, rawData.slice(index + 1, index + 5));
} else if (data.template_intro === '热门品类') { // 处理热门品类
floorData = floorMap.hot.call(null, rawData.slice(index, index + hotCategoryLength), type);
} else if (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);
} else if (data.template_name === 'debrisSlider') { // 处理girls的banner
floorData = floorMap.debrisSlide.call(null, data.data);
}
// 处理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));
}
if (!_.isNil(floorData)) {
// 处理手风琴楼层
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));
}
// 处理promise
if (floorData && floorData.then && typeof floorData.then === 'function') {
searchPromise.push(floorData);
// 记住楼层位置, 以便后面promise获取数据后插入楼层数据
singlehotFloorIndex.push(floorList.length);
// 记住楼层标题, 以便后面promise获取数据后插入楼层数据
singlehotFloorTitile.push(getText(data.data.text));
} else if (!_.isNil(floorData)) {
_.isArray(floorData) ?
floorList = floorList.concat(floorData) :
floorList.push(floorData);
}
});
return floorList;
return {
floors: floorList,
promise: _.reverse(searchPromise),
singlehotFloorTitile: _.reverse(singlehotFloorTitile),
singlehotFloorIndex: _.reverse(singlehotFloorIndex)
};
};
/**
* 获取频道页数据
* @param {string} type 传入频道页类型,值可以是: boys, girls, kids, lifestyle
... ... @@ -352,13 +899,42 @@ exports.getContent = type => {
let data = {};
const processResult = processFloorData(contentData, type);
data = headerModel.setHeaderData(headerData, type);
data.module = 'channel';
data.page = type;
data.page = 'channel';
data.pageType = type;
data.footerTop = true;
data.channel = processFloorData(contentData);
data.channel = processResult.floors;
return data;
return {
rawData: contentData,
floorData: data,
searchPromise: processResult.promise,
singlehotFloorIndex: processResult.singlehotFloorIndex,
singlehotFloorTitile: processResult.singlehotFloorTitile,
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,
processFloorDataWithQueryReusult(result.rawData,
result.floorData, data, result.singlehotFloorTitile[index], result.channelType));
});
return result.floorData;
});
} else {
return result.floorData;
}
});
};
... ... @@ -375,16 +951,20 @@ exports.getbrandFloorDataAjax = type => {
moreBrand: ''
};
_.forEach(contentData[6].data, (floorData) => {
let o = {};
_.forEach(contentData, (d, index) => {
if (d.data.text && d.data.text.indexOf('优选品牌') >= 0) {
_.forEach(contentData[index + 2].data, (floorData) => {
let o = {};
o.href = floorData.url;
o.img = helpers.image(floorData.src, 185, 86, 2);
o.href = floorData.url;
o.img = helpers.image(floorData.src, 185, 86, 2);
data.logoBrand.push(o);
});
data.logoBrand.push(o);
});
data.moreBrand = contentData[7].data[0].url;
data.moreBrand = contentData[index + 3].data[0].url;
}
});
return data;
}
... ...
... ... @@ -12,8 +12,14 @@ const cRoot = './controllers';
// Your controller here
const channelController = require(`${cRoot}/index`);
router.get('/boys', channelController.boysIndex);
// 路由
router.get('/boys', channelController.index);
router.get('/girls', channelController.index);
router.get('/kids', channelController.index);
router.get('/lifestyle', channelController.index);
// ajax
router.get('/getbrandFloorDataAjax', channelController.getbrandFloorDataAjax);
router.post('/common/getNewArrival', channelController.getNewArrival);
module.exports = router;
... ...
<div class="home-page yoho-page boys" data-page="boys">
<div class="home-page yoho-page {{pageType}}" data-page="{{pageType}}">
{{# channel}}
{{! 头部banner}}
{{# slide}}
... ... @@ -39,21 +39,26 @@
</div>
{{/ newReport}}
{{! 优选品牌}}
{{# preferenceBrands}}
<div class="preference-brand">
{{> floor-header}}
<div class="img-brand">
<ul class="img-list imgopacity clearfix">
{{# imgBrand}}
<li class="img-item">
<a href="{{href}}" target= "_blank">
<img src="{{img}}" alt="">
{{# debrisSlider}}
<div class="debris-slider clearfix">
<div class="left-col col">
{{# left}}
<a href="{{href}}" target="_blank">
<img class="lazy" data-original="{{image img 200 265}}">
</a>
{{/ left}}
</div>
<div class="center-col col">
<ul class="slide-wrapper">
{{# center}}
<li>
<a href="{{href}}" target="_blank">
<img class="lazy" data-original="{{image img 570 633}}">
</a>
</li>
{{/ imgBrand}}
{{/ center}}
</ul>
<div class="img-brand-switch">
<div class="slide-switch">
<a class="prev" href="javascript:;">
<span class="iconfont">&#xe60c;</span>
</a>
... ... @@ -62,13 +67,48 @@
</a>
</div>
</div>
<div class="logo-brand imgopacity" data-url="{{brandUrl}}"></div>
<div class="right-col col">
{{# right}}
<a href="{{href}}" target="_blank">
<img class="lazy" data-original="{{image img 200 265}}">
</a>
{{/ right}}
</div>
</div>
{{/ debrisSlider}}
{{! 优选品牌}}
{{# preferenceBrands}}
{{> floor-header}}
{{#if boysChannel}}
{{>boy-brands}}
{{/if}}
{{#if girlsChannel}}
{{>girl-brands}}
{{/if}}
{{#if kidsChannel}}
{{>girl-brands}}
{{/if}}
{{#if lifestyleChannel}}
{{>girl-brands}}
{{/if}}
{{/ preferenceBrands}}
{{! 单品/广告}}
{{# singlehot}}
{{> boy-singlehot}}
{{#if boysChannel}}
{{> boy-singlehot}}
{{/if}}
{{#if girlsChannel}}
{{> girl-singlehot}}
{{/if}}
{{#if kidsChannel}}
{{> girl-singlehot}}
{{/if}}
{{#if lifestyleChannel}}
{{> girl-singlehot}}
{{/if}}
{{/ singlehot}}
{{! 广告}}
... ... @@ -80,9 +120,33 @@
{{! 品类推荐}}
{{# recommend}}
{{> boy-recommend}}
{{#if boysChannel}}
{{> boy-recommend}}
{{/if}}
{{#if girlsChannel}}
{{> girl-recommend}}
{{/if}}
{{#if kidsChannel}}
{{> girl-recommend}}
{{/if}}
{{#if lifestyleChannel}}
{{> girl-recommend}}
{{/if}}
{{/ recommend}}
{{#accordion}}
{{> slide-accordion}}
{{/accordion}}
{{# category}}
{{> category-floor}}
{{/ category}}
{{! 新品上架}}
{{# newArrivls}}
... ...
<div class="preference-brand">
<div class="img-brand">
<ul class="img-list imgopacity clearfix">
{{# imgBrand}}
<li class="img-item">
<a href="{{href}}" target= "_blank">
<img src="{{image img 378 175}}" alt="">
</a>
</li>
{{/ imgBrand}}
</ul>
<div class="img-brand-switch">
<a class="prev" href="javascript:;">
<span class="iconfont">&#xe60c;</span>
</a>
<a class="next" href="javascript:;">
<span class="iconfont">&#xe60b;</span>
</a>
</div>
</div>
<div class="logo-brand imgopacity" data-url="{{brandUrl}}"></div>
</div>
... ...
{{> floor-header}}
<div class="categorys-list imgopacity">
<ul class="clearfix">
{{# list}}
<li class="cate-item{{@index}}">
<a href="{{href}}" target= "_blank">
<img class="lazy" data-original="{{image img w h}}" alt="">
</a>
</li>
{{/ list}}
</ul>
</div>
... ...
<div class="preference-brand imgopacity">
<div class="img-slider-wrapper clearfix" style="background-color:{{sliderColor}};">
<div class="img-brand-switch">
<a class="prev iconfont" href="javascript:;">&#xe60f;</a>
<a class="next iconfont" href="javascript:;">&#xe60e;</a>
</div>
<div class="img-container-landscape">
<ul class="img-list">
{{# imgBrand}}
<li class="img-item">
<a href="{{href}}" target= "_blank"> <img src="{{image img 320 430}}" alt="{{alt}}"></a>
</li>
{{/ imgBrand}}
</ul>
</div>
</div>
<div class="logo-brand " data-url="{{brandUrl}}">
</div>
</div>
... ...
{{# tplrecommend}}
<div class="tpl-recommend clearfix">
{{> floor-header}}
<div class="tpl-body clearfix">
<div class="tpl-nav">
<div class="tpl-keywords">
{{#each keyword}}
<a class="keywords{{@index}}" title="{{name}}" href="{{href}}" target= "_blank"><img class="lazy" data-original="{{image img 185 76}}"/></a>
{{/each}}
</div>
<div class="tpl-category clearfix">
{{#each category}}
<a href="{{href}}" target= "_blank">{{name}}</a>
{{/each}}
</div>
</div>
<div class="tpl-brands imgopacity clearfix">
{{#each brands}}
<a title="{{name}}" href="{{href}}" target= "_blank"><img class="lazy" data-original="{{image img 377 504}}"/></a>
{{/each}}
</div>
<div class="tpl-types imgopacity clearfix">
<ul>
{{#each types}}
<li><a title="{{name}}" href="{{href}}" target= "_blank"><img class="lazy" data-original="{{image img 185 504}}"/></a></li>
{{/each}}
</ul>
</div>
</div>
</div>
{{/ tplrecommend}}
... ...
<div class="commodity clearfix">
{{> floor-header}}
<div class="commodity-list">
<ul class="g-list imgopacity clearfix">
{{#each imgHot}}
<li>
<a href="{{href}}" target= "_blank"><div class="commodity-img">
{{# tip}}
<i class="top">{{.}}</i>
{{/ tip}}
<img class="lazy" data-original="{{image img 280 373}}"/></div>
<p class="commodity-name">{{name}}</p>
<p class="commodity-price"><span>¥{{price}}</span></p>
</a>
</li>
{{/each}}
</ul>
</div>
<div class="commodity-brands imgopacity clearfix">
{{#each brands}}
<a href="{{href}}" title="{{name}}" target= "_blank"><img class="lazy" data-original="{{image img 185 86}}"/></a>
{{/each}}
</div>
</div>
... ...
{{> floor-header}}
<div class="slide-accordion clearfix">
<ul>
{{#each slide}}
<li><a title="{{name}}" href="{{href}}" target= "_blank"><div class="g-mask"></div><img class="lazy" data-original="{{image img 650 400}}"/></a></li>
{{/each}}
</ul>
</div>
... ...
... ... @@ -14,7 +14,11 @@ module.exports = {
siteUrl: 'http://localhost:6002/',
domains: {
api: 'http://testapi.yoho.cn:28078/',
service: 'http://testservice.yoho.cn:28077/'
service: 'http://testservice.yoho.cn:28077/',
//api: 'http://192.168.102.205:8080/gateway/',
// service: 'http://testservice.yoho.cn:28077/',
//service: 'http://service.api.yohobuy.com/',
search: 'http://192.168.102.216:8080/yohosearch/'
},
useOneapm: false,
useCache: false,
... ...
/**
* 登录判断
* @author: xuqi<qi.xu@yoho.cn>
* @date: 2016/4/25
*/
'use strict';
const _ = require('lodash');
const // domain = '.static.yhbimg.com',
defaultImage = '/2015/08/25/02/01dd632a6e07bfef457ce4beda21dd6413.png',
qiniuDomain = 'yhfair.qiniudn.com',
domainList = {
'01': ['img10.static.yhbimg.com', 'img11.static.yhbimg.com'],
'02': ['img12.static.yhbimg.com', 'img13.static.yhbimg.com'],
'yhb-head': 'head.static.yhbimg.com'
};
const regexp = /(?:\{)([a-zA-z][^\s\}]+)(?:\})/g;
const myReplace = (tem, data) => {
return tem.replace(regexp, function(fullMatch, capture) {
if (data[capture]) {
return data[capture];
} else {
return fullMatch;
}
});
};
const makeBaseUrl = (domain, key) =>{
encodeURIComponent(key).replace('%2F', '/');
return `http://${domain}/${key}`;
};
const makeTemplateRequest = url => {
let ops = ['{mode}', 'w/{width}', 'h/{height}'];
if (ops.length === 0) {
return url;
}
return url + '?imageView/' + ops.join('/');
};
const getImgTemplateUrl = (fileName, mode, domain) =>{
// 默认值
if (!mode) {
mode = 1;
}
if (!domain) {
domain = null;
}
if (domain === null) {
domain = qiniuDomain;
}
let baseUrl = makeBaseUrl(domain, fileName);
return makeTemplateRequest(baseUrl);
};
const getDomain = (bucket, fileName) => {
let domain = '';
if (bucket in domainList) {
domain = domainList.bucket;
} else {
let node = fileName.substr(15, 2);
if (node in domainList) {
let urlList = domainList[node];
let nodeNum = _.random(urlList.length - 1);
domain = urlList[nodeNum];
}
}
return domain;
};
const url = (fileName, bucket, mode) =>{
// 默认值
if (!mode) {
mode = 1;
}
if (!bucket) {
bucket = 'yhfair';
}
let domain = getDomain(bucket, fileName);
return getImgTemplateUrl(bucket + fileName, mode, domain);
};
const template = (fileName, bucket, mode) => {
// 默认值
if (!mode) {
mode = 1;
}
if (!bucket) {
bucket = 'yhfair';
}
return url(fileName, bucket, mode);
};
exports.getImageUrl = (fileName, width, height, mode, bucket) => {
// 默认值
if (!mode) {
mode = 2;
}
if (!bucket) {
bucket = 'goodsimg';
}
if (typeof(fileName) !== 'string') {
return template(defaultImage, bucket, mode);
}
if (fileName.indexOf('http://') !== 0) {
fileName = template(fileName, bucket, mode);
}
return myReplace(fileName, {width: width, height: height, mode: mode});
};
... ...
... ... @@ -22,7 +22,7 @@ const commonConfig = () => ({
title: 'home'
});
const getChannelIndex = (type) => {
const getChannelIndex = type => {
const channelMap = {
boys: 0,
girls: 1,
... ... @@ -181,7 +181,7 @@ exports.setHeaderData = (resData, type) => {
let data = {
headerData: {
header: true,
headType: type,
headtype: type,
yohoGroup: getMenuData(),
navbars: resData ? getNavBar(resData) : [],
subNav: resData ? getSubNav(resData, type) : []
... ...
... ... @@ -19,14 +19,12 @@ require('../plugins/logo-brand');
require('../plugins/accordion');
$(document).on('mouseenter', '.imgopacity a img', function() {
$(this).css('opacity', 0.8);
$(this).css('opacity', 0.8); // eslint-disable-line
});
$(document).on('mouseout', '.imgopacity a img', function() {
$(this).css('opacity', 1);
$(this).css('opacity', 1); // eslint-disable-line
});
if ($.inArray(homePage, ['boys', 'girls', 'kids', 'lifestyle']) > -1) {
require('../plugins/new-arrivls')({
type: homePage,
... ...
... ... @@ -229,6 +229,8 @@ a {
@import "footer";
@import "404";
@import "index/index";
@import "product/index";
@import "plugins/slider";
/* 模块 */
@import "index/index";
... ...
.yoho-dialog {
position: fixed;
padding: 20px;
top: 50%;
left: 50%;
min-height: 130px;
min-width: 350px;
background: #f8f8f8;
z-index: 1001;
border: 5px solid rgba(0,0,0,.38);
.close {
position: absolute;
top: 5px;
right: 5px;
cursor: pointer;
}
.content {
text-align: center;
}
.btns {
text-align: center;
}
.alert-sure{
background: #000;
color: #fff;
}
.confirm-sure{
background: #000;
color: #fff;
}
.btn {
display: inline-block;
width: 56px;
height: 26px;
line-height: 26px;
text-align: center;
border: 1px solid #000;
cursor: pointer;
margin-left: 10px;
&:first-child {
margin-left: 0;
}
}
&.alert-dialog .content,
&.confirm-dialog .content {
width: 350px;
height: auto;
min-height: 90px;
overflow: hidden;
line-height: 20px;
position: relative;
padding-top: 40px;
padding-bottom: 20px;
p{
position: absolute;
left: 0;
bottom: 25px;
width: 100%;
color: #444;
line-height: 25px;
}
div{
position: absolute;
top: 0;
left: 100px;
padding-top: 30px;
font-size: 22px;
font-weight: bold;
width: 150px;
height: 30px;
line-height: 30px;
margin: 0 auto;
span{
background: url(/cart/del.png);
float: left;
width: 27px;
height: 30px;
}
}
}
&.subcontent-dialog {
padding: 30px 0px 30px 0px;
.content {
font-weight: bold;
margin: 0px auto 30px auto;
}
.sub-content {
text-align: center;
font-size: 12px;
color: #555;
margin-left: 5px;
margin-bottom: 5px;
}
.btn {
margin-top: 25px;
width: 100px;
font-size: 13px;
margin-left: 0;
margin-right: 0;
&.black {
background-color: #000;
color: #fff;
}
}
}
}
... ...
.slider {
position: relative;
height: 327px;
width: 100%;
overflow: hidden;
img {
max-width: 100%;
max-height: 100%;
}
}
.slide-pagination {
position: absolute;
left: 0;
right: 0;
bottom: 12px;
text-align: center;
}
.slide-pagination-inner {
display: inline-block;
position: relative;
padding: 7px;
vertical-align: middle;
}
.slide-shade {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: #000;
opacity: 0.3;
border-radius: 13px;
}
.slide-pagination-last span {
display: block;
float: left;
position: relative;
margin: 0 7px;
width: 12px;
height: 12px;
background: #fff;
cursor: pointer;
opacity: 0.6;
border-radius: 6px;
z-index: 2;
&.focus {
opacity: 1;
}
}
.slide-switch {
display: none;
&.show {
display: block;
}
a {
display: block;
position: absolute;
top: 50%;
margin: -30px 0 0;
width: 60px;
height: 60px;
line-height: 56px;
text-align: center;
z-index: 2;
background: #fff;
opacity: 0.55;
&:hover{
opacity: 0.9;
}
.iconfont {
font-size: 32px;
color: #59585a;
}
}
.prev {
left: 0;
}
.next {
right: 0;
}
}
\ No newline at end of file
... ...
.good-info {
margin-bottom: 35px;
width: 222px;
margin-right: 10px;
float: left;
.good-detail-img {
width: 100%;
height: 300px;
position: relative;
.good-thumb, img.lazy {
display: block;
overflow: hidden;
width: 100%;
height: 100%;
}
.few-tag {
width: 100%;
position: absolute;
left: 0;
height: 16px;
line-height: 16px;
background: #ffac5b;
color: #fff;
font-size: 12px;
text-align: center;
bottom: 0;
}
}
.good-detail-text {
color: #222;
font-size: 12px;
text-align: left;
overflow: hidden;
> a {
margin-top: 16px;
line-height: 1.5;
display: block;
@mixin ellipsis;
}
> .price {
margin-top: 5px;
}
.brand {
a {
color: #666;
line-height: 1.5;
}
}
.market-price {
text-decoration: line-through;
color: #999;
}
}
.col-btn {
position: absolute;
top: 15px;
right: 15px;
color: #ccc;
font-size: 12px;
&.coled {
color: #f95b4f;
}
}
.tag-container {
font-size: 12px;
height: 22px;
line-height: 22px;
.good-tag {
float: left;
box-sizing: border-box;
display: block;
height: 22px;
padding: 0 7px;
margin-right: 3px;
color: #fff;
&:nth-last-of-type(1) {
margin-right: 0;
}
}
.new-tag {
background: #78dc7d;
}
.renew-tag {
background: #78dc7e;
}
.running-man-tag {
background-color: #017df9;
color: #f7ed02;
}
.yep-tag, .ymp-tag, .sale-tag {
background: #ff565b;
}
.limit-tag {
color: #4e4e4e;
border: 1px solid #4e4e4e;
}
}
}
@keyframes slideRight {
from {
max-width: 0;
}
to {
max-width: 150px;
}
}
.good-item-wrapper {
border: 1px solid #dddddd;
padding-left: 20px;
padding-top: 18px;
padding-right: 20px;
position: absolute;
background: #fff;
display: none;
.good-info-main{
float: left;
}
.col-btn {
display: block;
&:hover {
cursor: pointer;
}
}
.good-select-color {
float: left;
margin-top: 22px;
overflow: hidden;
animation: slideRight 600ms 1;
ul {
display: block;
float: left;
margin-left: 15px;
}
li {
width: 50px;
margin-bottom: 15px;
a, img {
display: block;
overflow: hidden;
width: 100%;
}
}
}
.good-info {
margin-right: 10px;
}
}
.block-next-page {
width: 222px;
height: 297px;
padding-top: 22px;
margin-bottom: 35px;
margin-right: 10px;
float: left;
cursor: pointer;
a {
display: block;
img {
width: 100%;
height: 100%;
display: block;
overflow: hidden;
}
}
}
... ...
@import "good";
.product-page {
/*分页*/
.product-pager {
padding: 20px 0;
font-size: 12px;
color: #6a6a6a;
border-top: 2px solid #eaeceb;
.pager {
float: right;
}
}
/*分页 END*/
.list-left {
width: 160px;
}
.list-right {
width: 970px;
}
}
.product-list-page, .new-sale-page {
.goods-container {
height: auto;
padding-top: 25px;
position: relative;
width: calc(970px + 10px);/*每列增加右边距*/
.good-info {
width: 235px;
.good-detail-img {
height: 315px;
}
}
.block-next-page {
width: 235px;
height: 315px;
}
}
.filter-box .brand .attr-content {
max-width: 730px;
}
}
/*990px*/
.min-screen .product-list-page,
.min-screen .new-sale-page {
.list-right {
width: 810px;
}
.goods-container {
height: auto;
padding-top: 25px;
position: relative;
width: calc(810px + 10px);/*每列增加右边距*/
.good-info {
width: 195px;
.good-detail-img {
height: 261px;
}
}
.block-next-page {
width: 195px;
height: 261px;
}
}
.filter-box .brand .attr-content {
max-width: 570px;
}
}
... ...