Authored by yyq

Merge branch 'develop' into feature/sale

Showing 82 changed files with 1566 additions and 318 deletions
... ... @@ -26,13 +26,19 @@ const pkg = require('./package.json');
const app = express();
const MemcachedStore = memcached(session);
// 指定libray目录
global.library = path.resolve('./library');
global.middleware = path.resolve('./doraemon/middleware');
global.utils = path.resolve('./utils');
const seo = require(`${global.middleware}/seo`);
// 向模板注入变量
app.locals.devEnv = app.get('env') === 'development';
app.locals.version = pkg.version;
// 指定libray目录
global.library = path.resolve('./library');
app.set('view engine', '.hbs');
... ... @@ -68,9 +74,13 @@ app.use((req, res, next) => {
if (req.session && _.isNumber(req.session._LOGIN_UID)) {
req.user.uid = req.session._LOGIN_UID;
}
next();
});
app.use(seo());
// dispatcher
require('./dispatch')(app);
... ...
... ... @@ -6,7 +6,6 @@
'use strict';
const headerModel = require('../../../doraemon/models/header');
const specialModel = require('../models/special');
const _ = require('lodash');
... ... @@ -14,12 +13,12 @@ exports.special = (req, res) => {
let id = req.params[0] || 0;
let channel = req.query.channel ? req.query.channel : 'boys';
specialModel.getSpecialData(id).then((result) => {
let headerData = headerModel.setHeaderData(result[0].data, channel);
specialModel.getSpecialData(id, channel).then((result) => {
let headerData = result[0];
res.render('special', _.merge({
module: 'index',
page: 'index'
module: 'activity',
page: 'special'
}, headerData, result[1]));
}).catch((err) => {
res.send(err);
... ...
... ... @@ -28,6 +28,6 @@ const getstaticFile = (id) => {
});
};
exports.getSpecialData = (id) => {
return Promise.all([headerModel.requestHeaderData(), getstaticFile(id)]);
exports.getSpecialData = (id, type) => {
return Promise.all([headerModel.requestHeaderData(type), getstaticFile(id)]);
};
... ...
... ... @@ -6,17 +6,54 @@
'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) => {
let channelType = req.path.substring(1) || 'boys';
// 将woman转换为girls,以便model层进行处理
channelType === 'woman' ? channelType = 'girls' : null;
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);
});
};
... ...
... ... @@ -14,6 +14,7 @@ var app = express();
var doraemon = path.join(__dirname, '../../doraemon/views'); // parent view root
var partials = path.join(__dirname, './views'); // parent view root
app.on('mount', function(parent) {
delete parent.locals.settings; // 不继承父 App 的设置
Object.assign(app.locals, parent.locals);
... ... @@ -28,6 +29,7 @@ app.engine('.hbs', hbs({
helpers: require('../../library/helpers')
}));
// router
app.use(require('./router'));
... ...
... ... @@ -8,18 +8,43 @@
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.utils}/images`);
const log = require(`${global.library}/logger`);
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,14 +57,228 @@ 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 => {
let list = [];
... ... @@ -56,6 +295,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 +343,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 +412,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 +438,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 +455,6 @@ const getHotGoodsFloorData = (args) => {
category = [],
brands = [],
types = [],
navs = {},
products = [];
const data = {
... ... @@ -184,16 +463,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 +488,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 +505,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 +542,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 +557,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,
... ... @@ -301,7 +794,14 @@ const requestContent = type => {
limit: 1000
});
return serviceApi.get('/operations/api/v5/resource/home', data);
return serviceApi.get('/operations/api/v5/resource/home', data).then(res => {
if (res.code === 200) {
return res;
} else {
log.error('获取资源位接口返回状态码 不是 200');
return {};
}
});
};
const floorMap = {
... ... @@ -309,56 +809,138 @@ 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);
}
if (!_.isNil(floorData)) {
// 处理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 (!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
* @return {object}
*/
exports.getContent = type => {
return Promise.all([headerModel.requestHeaderData(), requestContent(type)]).then(res => {
return Promise.all([headerModel.requestHeaderData(type), requestContent(type)]).then(res => {
let headerData = res[0].data || res[0],
contentData = res[1].data ? res[1].data.list : res[1];
let data = {};
const processResult = processFloorData(contentData, type);
data = headerData;
data.module = 'channel';
data.page = 'channel';
data.pageType = type;
data.footerTop = true;
data.channel = processResult.floors;
if (res[0].code === 200 && res[1].code === 200) {
let headerData = res[0].data,
contentData = res[1].data.list;
return {
rawData: contentData,
floorData: data,
searchPromise: processResult.promise,
singlehotFloorIndex: processResult.singlehotFloorIndex,
singlehotFloorTitile: processResult.singlehotFloorTitile,
channelType: type
};
let data = {};
}).then(result => {
data = headerModel.setHeaderData(headerData, type);
data.module = 'channel';
data.page = type;
data.footerTop = true;
data.channel = processFloorData(contentData);
// 如果有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 data;
return result.floorData;
});
} else {
return result.floorData || result;
}
});
};
... ... @@ -367,26 +949,28 @@ exports.getContent = type => {
// 优选品牌楼层floorData-ajax
exports.getbrandFloorDataAjax = type => {
return requestContent(type).then(res => {
if (res.code === 200) {
let contentData = res.data.list;
let contentData = res.data ? res.data.list : [];
let data = {
logoBrand: [],
moreBrand: ''
};
let data = {
logoBrand: [],
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;
}
return data;
});
};
... ...
... ... @@ -12,8 +12,14 @@ const cRoot = './controllers';
// Your controller here
const channelController = require(`${cRoot}/index`);
router.get('/boys', channelController.boysIndex);
// 频道页路由
router.get('/', channelController.index);
router.get('/woman', 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">
{{# channel}}
{{! 头部banner}}
{{# slide}}
{{> banner}}
{{/ slide}}
{{! 新品速报}}
{{# newReport}}
<div class="new-report imgopacity clearfix">
{{> floor-header}}
<ul class="report-list clearfix">
{{# list}}
{{#unless @last}}
<li>
<a href="{{href}}" target= "_blank">
{{#if @first}}
<img class="lazy" data-original="{{image img 377 504}}" alt="" >
{{^}}
<img class="lazy" data-original="{{image img 185 248}}" alt="" >
{{/if}}
</a>
</li>
{{/unless}}
{{/ list}}
</ul>
{{# list}}
{{#if @last}}
<div class="last-item">
<a href="{{href}}" target= "_blank">
<img class="lazy" data-original="{{image img 377 504}}" alt="">
</a>
</div>
{{/if}}
{{/ list}}
</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="">
</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>
{{/ preferenceBrands}}
{{! 单品/广告}}
{{# singlehot}}
{{> boy-singlehot}}
{{/ singlehot}}
{{! 广告}}
{{# adbanner}}
<div class="floor-ad">
<a href="{{href}}" target= "_blank"><img class="lazy" data-original="{{image img 1150 129}}"/></a>
</div>
{{/ adbanner}}
{{! 品类推荐}}
{{# recommend}}
{{> boy-recommend}}
{{/ recommend}}
{{! 新品上架}}
{{# newArrivls}}
{{> commodity}}
{{/ newArrivls}}
{{/ channel}}
</div>
<div class="home-page yoho-page {{pageType}}" data-page="{{pageType}}">
{{# channel}}
{{! 头部banner}}
{{# slide}}
{{> banner}}
{{/ slide}}
{{! 左中右格式的头部banner}}
{{# debrisSlider}}
{{> big-slider}}
{{/ debrisSlider}}
{{! 新品速报}}
{{# newReport}}
{{> newreport-floor}}
{{/ newReport}}
{{! 优选品牌}}
{{# 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}}
{{#if boysChannel}}
{{> boy-singlehot}}
{{/if}}
{{#if girlsChannel}}
{{> girl-singlehot}}
{{/if}}
{{#if kidsChannel}}
{{> girl-singlehot}}
{{/if}}
{{#if lifestyleChannel}}
{{> girl-singlehot}}
{{/if}}
{{/ singlehot}}
{{! 广告}}
{{# adbanner}}
{{> ad-floor}}
{{/ adbanner}}
{{! 品类推荐}}
{{# 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}}
{{> commodity}}
{{/ newArrivls}}
{{/ channel}}
</div>
... ...
<div class="floor-ad">
<a href="{{href}}" target= "_blank"><img class="lazy" data-original="{{image img 1150 129}}"/></a>
</div>
... ...
<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>
{{/ center}}
</ul>
<div class="slide-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="right-col col">
{{# right}}
<a href="{{href}}" target="_blank">
<img class="lazy" data-original="{{image img 200 265}}">
</a>
{{/ right}}
</div>
</div>
... ...
<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>
... ...
<div class="new-report imgopacity clearfix">
{{> floor-header}}
<ul class="report-list clearfix">
{{# list}}
{{#unless @last}}
<li>
<a href="{{href}}" target= "_blank">
{{#if @first}}
<img class="lazy" data-original="{{image img 377 504}}" alt="" >
{{^}}
<img class="lazy" data-original="{{image img 185 248}}" alt="" >
{{/if}}
</a>
</li>
{{/unless}}
{{/ list}}
</ul>
{{# list}}
{{#if @last}}
<div class="last-item">
<a href="{{href}}" target= "_blank">
<img class="lazy" data-original="{{image img 377 504}}" alt="">
</a>
</div>
{{/if}}
{{/ list}}
</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>
... ...
... ... @@ -33,7 +33,6 @@ exports.index = (req, res) => {
responseData.module = 'product';
responseData.page = 'sale';
responseData.footerTop = true;
responseData.devEnv = true;
// 假数据输出
// res.render('sale/index', Object.assign(responseData, simulation.saleIndex()));
... ... @@ -74,7 +73,6 @@ exports.discount = (req, res) => {
responseData.module = 'product';
responseData.page = 'sale';
responseData.footerTop = true;
responseData.devEnv = true;
// 假数据输出
// res.render('sale/discount', Object.assign(responseData, simulation.discount()));
... ... @@ -117,7 +115,6 @@ exports.vip = (req, res) => {
responseData.module = 'product';
responseData.page = 'sale';
responseData.footerTop = true;
responseData.devEnv = true;
// 假数据输出
// res.render('sale/other', Object.assign(responseData, simulation.other()));
... ... @@ -155,7 +152,6 @@ exports.newSale = (req, res) => {
responseData.module = 'product';
responseData.page = 'sale';
responseData.footerTop = true;
responseData.devEnv = true;
// 假数据输出
// res.render('sale/other', Object.assign(responseData, simulation.other()));
... ... @@ -193,7 +189,6 @@ exports.breakingYards = (req, res) => {
responseData.module = 'product';
responseData.page = 'sale';
responseData.footerTop = true;
responseData.devEnv = true;
// 假数据输出
// res.render('sale/other', Object.assign(responseData, simulation.other()));
... ... @@ -224,7 +219,6 @@ exports.getGoodsList = (req, res) => {
return sale.getSaleGoodsData(params).then(result => {
let responseData = {};
responseData.devEnv = true;
responseData.footerTop = false;
responseData.layout = false;
... ...
... ... @@ -13,6 +13,11 @@ var app = express();
// set view engin
var doraemon = path.join(__dirname, '../../doraemon/views'); // parent view root
app.on('mount', function(parent) {
delete parent.locals.settings; // 不继承父 App 的设置
Object.assign(app.locals, parent.locals);
});
app.set('views', path.join(__dirname, 'views/action'));
app.engine('.hbs', hbs({
extname: '.hbs',
... ...
... ... @@ -13,9 +13,9 @@ module.exports = {
port: 6002,
siteUrl: 'http://localhost:6002/',
domains: {
api: 'http://devapi.yoho.cn:58078/', // testapi.yoho.cn:28078
service: 'http://devservice.yoho.cn:58077/', // devservice.yoho.cn:58077 testservice.yoho.cn:28077
search: 'http://192.168.10.64:8080/yohosearch/'
api: 'http://testapi.yoho.cn:28078/',
service: 'http://testservice.yoho.cn:28077/',
search: 'http://192.168.102.216:8080/yohosearch/'
},
useOneapm: false,
useCache: false,
... ... @@ -41,7 +41,7 @@ module.exports = {
udp: { // send by udp
level: 'debug', // logger level
host: '192.168.102.162', // influxdb host
port: '4444'// influxdb port
port: '4444' // influxdb port
},
console: {
level: 'debug',
... ... @@ -71,6 +71,13 @@ if (isProduction) {
Object.assign(module.exports, {
appName: 'www.yohobuy.com for test',
useOneapm: true,
useCache: true
useCache: true,
memcache: {
master: ['127.0.0.1:12111'],
slave: ['127.0.0.1:12112'],
session: ['127.0.0.1:12111'],
timeout: 1000,
retries: 0
}
});
}
... ...
'use strict';
// 页面seo相关属性的配置文件
const seoMap = require('./seoConfig');
/**
* 设置seo相关的数据,包括title, keywords, description
* @param {undefined}
* @return {Function} 中间件函数,用于给res.locals对象添加属性
*/
module.exports = () => {
return (req, res, next) => {
if (!req.xhr) {
Object.assign(res.locals, seoMap[req.path] || seoMap['/']);
}
next();
};
};
... ...
const seoMap = {
/* eslint-disable */
'/': {
title: 'YOHO!有货 | 年轻人潮流购物中心,中国潮流购物风向标,官方授权正品保证',
keywords: 'Yoho! 有货官网,潮流志,潮流男装,潮牌,美国潮牌,日本潮牌,香港潮牌,潮牌店,新品首发,欧美潮流,全球购,代购,时尚,流行,特卖,B2C,正品,购物网站,网上购物,货到付款',
description: 'YOHO! 有货,年轻人潮流购物中心,中国最大的潮流商品购物网站。100%品牌正品保证,支持货到付款。作为YOHO!旗下的购物平台,汇集了全球潮流时尚商品和中国最流行的商品,也是国内最大的原创文化商品平台,也是香港,台湾地区流行商品的集中地。同时包含日本、韩国等众多国外潮流品牌,带给您全新潮流购物体验。'
},
'/woman': {
title: '女生|时尚潮流女装,日韩女装,潮牌女装全球购|YOHO!BUY有货 100%正品保证',
keywords: '女生服饰,时尚潮流女装,日韩女装,女装正品购物网站,女装全球购',
description: 'YOHO!BUY有货官网女生频道汇集了全球女装潮流时尚,提供时尚潮流女装,日版女装,韩版女装,潮牌女装正品全球购。YOHO!BUY有货购物100%正品保证,支持货到付款。'
},
'/kids': {
title: '潮童|男童装,女童装,韩版童装,儿童服装服饰|YOHO!BUY有货 100%正品保证',
keywords: '潮童,男童装,女童装,韩版童装,儿童服装服饰',
description: 'YOHO!BUY有货官网潮童频道汇集了全球潮童潮流时尚,提供新款男童装,女童装,韩版童装,儿童服装服饰正品全球购。YOHO!BUY有货购物100%正品保证,支持货到付款。'
},
'/lifestyle': {
title: '创意生活|创意生活馆,潮流创意家居,家居生活用品|YOHO!BUY有货 100%正品保证',
keywords: '创意生活,创意生活馆,潮流家居,潮流创意家居,家居生活用品,YOHO!有货',
description: 'YOHO!BUY有货官网创意生活频道汇集了创意生活馆,潮流创意家居,家居生活用品等正品网购,给您的生活带来更多创意。YOHO!BUY有货购物100%正品保证,支持货到付款。'
}
/* eslint-enable */
};
module.exports = seoMap;
... ...
... ... @@ -13,27 +13,7 @@ const sign = require(`${global.library}/sign`);
const serviceApi = new ServiceAPI();
/**
* 获取公共配置
* @param undefined
* @return {Object} 配置对象
*/
const commonConfig = () => ({
title: 'home'
});
const getChannelIndex = (type) => {
const channelMap = {
boys: 0,
girls: 1,
kids: 2,
lifestyle: 3
};
const index = channelMap[type];
return _.isNil(index) ? 0 : index;
};
const log = require(`${global.library}/logger`);
/**
* 获取菜单
... ... @@ -72,19 +52,24 @@ const getMenuData = () => (
/**
* 获取导航
* @param undefined
* @param {Object} data 要处理的数据
* @param {String} type 频道类型
* @return {array} 导航数组
*/
const getNavBar = (data) => {
const getNavBar = (data, type) => {
let navBars = [];
_.forEach(data, function(item) {
_.forEach(data, item => {
let obj = {};
obj.link = item.sort_url;
obj.cn = item.sort_name;
obj.en = item.sort_name_en;
if (type === _.camelCase(item.sort_name_en).toLowerCase()) {
obj.active = true;
}
navBars.push(obj);
});
... ... @@ -94,14 +79,18 @@ const getNavBar = (data) => {
/**
* 获取品牌名字
* @param undefined
* @param {Object} data 要处理数据
* @return {array} 品牌数组
*/
const getBrandItems = (data) => {
let brandItems = [];
_.forEach(data, function(item) {
let obj = {};
_.forEach(data, item => {
let obj = {
link: '',
hot: false,
brandName: ''
};
obj.link = item.sort_url;
obj.hot = item.is_hot === 'Y' ? true : false;
... ... @@ -116,18 +105,22 @@ const getBrandItems = (data) => {
/**
* 获取三级菜单
* @param undefined
* @param {Object} data 要处理数据
* @return {array} 三级菜单数组
*/
const getThirdNav = (data) => {
let thirdNav = [];
_.forEach(data, function(item) {
let obj = {};
_.forEach(data, item => {
let obj = {
link: '',
title: '',
brandItems: false
};
obj.link = item.sort_url;
obj.title = item.sort_name;
obj.imgCode = item.content_code;
if (item.sub) {
obj.brandItems = getBrandItems(item.sub);
... ... @@ -137,33 +130,39 @@ const getThirdNav = (data) => {
});
return thirdNav;
};
/**
* 获取子菜单
* @param undefined
* @param {Object} data 要处理数据
* @param {String} type 频道类型
* @return {array} 子菜单数组
*/
const getSubNav = (data, type) => {
let subNav = [];
_.forEach(data[getChannelIndex(type)].sub, function(item) {
let obj = {};
_.forEach(data, it => {
if (type === _.camelCase(it.sort_name_en).toLowerCase()) {
_.forEach(it.sub, item => {
let obj = {};
obj.link = item.sort_url;
obj.name = item.sort_name;
obj.isHot = item.is_hot === 'Y' ? true : false;
obj.isNew = item.is_new === 'Y' ? true : false;
obj.link = item.sort_url;
obj.name = item.sort_name;
obj.isHot = item.is_hot === 'Y' ? true : false;
obj.isNew = item.is_new === 'Y' ? true : false;
if (item.sub) {
obj.thirdNav = getThirdNav(item.sub);
}
if (item.sub) {
obj.thirdNav = getThirdNav(item.sub);
obj.imgCode = item.content_code;
}
subNav.push(obj);
subNav.push(obj);
});
}
});
return subNav;
};
... ... @@ -176,31 +175,28 @@ const getSubNav = (data, type) => {
* @param {String} 指定页面类型为boys,girls,kids,lifestyle
* @return {object} 头部数据
*/
exports.setHeaderData = (resData, type) => {
let config = commonConfig();
const setHeaderData = (resData, type) => {
let data = {
headerData: {
header: true,
headType: type,
headtype: type,
yohoGroup: getMenuData(),
navbars: resData ? getNavBar(resData) : [],
navbars: resData ? getNavBar(resData, type) : [],
subNav: resData ? getSubNav(resData, type) : []
}
};
if (data.headerData.navbars.length) {
data.headerData.navbars[getChannelIndex(type)].active = true;
}
return _.merge(config, data);
return data;
};
/**
* 请求头部数据
* @param undefined
* @param {String} 频道类型
* @return {promise}
*/
exports.requestHeaderData = () => {
exports.requestHeaderData = type => {
let data = sign.apiSign({
/* eslint-disable */
... ... @@ -208,5 +204,14 @@ exports.requestHeaderData = () => {
/* eslint-enable */
});
return serviceApi.get('operations/api/v6/category/getCategory', data, true);
type = type || 'boys';
return serviceApi.get('operations/api/v6/category/getCategory', data, true).then(res => {
if (res && res.code === 200) {
return setHeaderData(res.data, type);
} else {
log.error('获取头部信息的接口返回状态码 不是 200');
return {};
}
});
};
... ...
... ... @@ -189,8 +189,10 @@
</div>
<div class="left">
<span class="iconfont rgbf">&#xe602;</span>
<span class="red">便捷</span>
<span class="rgbf">在线客服</span>
<a href="http://chat8.live800.com/live800/chatClient/chatbox.jsp?companyID=620092&amp;configID=149091&amp;jid=8732423409" target="_blank">
<span class="red">便捷</span>
<span class="rgbf">在线客服</span>
</a>
</div>
<div class="right subscribe footer-right">
<input id="subscriber-box" class="rgb6 top" name="subscriberBox"value="订阅我们的邮件">
... ...
... ... @@ -15,6 +15,7 @@ const Timer = require('./timer');
const config = require('../config/common');
const api = config.domains.api;
const serviceApi = config.domains.service;
const searchApi = config.domains.search;
class Http {
... ... @@ -182,5 +183,12 @@ class ServiceAPI extends Http {
}
}
class SearchAPI extends Http {
constructor() {
super(searchApi);
}
}
exports.API = API;
exports.ServiceAPI = ServiceAPI;
exports.SearchAPI = SearchAPI;
... ...
... ... @@ -13,7 +13,10 @@ let camelCase,
camelCaseObject = (obj) => {
_.forEach(Object.keys(obj), (k) => {
obj[k] = camelCase(obj[k]);
obj[_.camelCase(k)] = obj[k];
if (/[_-]/.test(k)) {
obj[_.camelCase(k)] = obj[k];
delete obj[k];
}
});
return obj;
};
... ...
{
"apps": [
{
"name": "yohobuy-node",
"script": "app.js",
"instances": "max",
"exec_mode": "cluster",
"env": {
"PORT": 6002
}
}
]
}
\ No newline at end of file
... ...
/** ****/ (function(modules) { // webpackBootstrap
/** ****/ // The module cache
/** ****/ var installedModules = {};
/** ****/ // The require function
/** ****/ function __webpack_require__(moduleId) {
/** ****/ // Check if module is in cache
/** ****/ if (installedModules[moduleId])
/** ****/ return installedModules[moduleId].exports;
/** ****/ // Create a new module (and put it into the cache)
/** ****/ var module = installedModules[moduleId] = {
/** ****/ exports: {},
/** ****/ id: moduleId,
/** ****/ loaded: false
/** ****/ };
/** ****/ // Execute the module function
/** ****/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/** ****/ // Flag the module as loaded
/** ****/ module.loaded = true;
/** ****/ // Return the exports of the module
/** ****/ return module.exports;
/** ****/ }
/** ****/ // expose the modules object (__webpack_modules__)
/** ****/ __webpack_require__.m = modules;
/** ****/ // expose the module cache
/** ****/ __webpack_require__.c = installedModules;
/** ****/ // __webpack_public_path__
/** ****/ __webpack_require__.p = '';
/** ****/ // Load entry module and return exports
/** ****/ return __webpack_require__(0);
/** ****/ })([
/* 0 */
/** */ function(module, exports) {
console.log(1);
/** */ }
/** ****/ ]);
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
... ... @@ -2,7 +2,7 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>
Created by FontForge 20120731 at Mon May 23 22:22:36 2016
Created by FontForge 20120731 at Tue May 31 15:22:26 2016
By admin
</metadata>
<defs>
... ... @@ -19,7 +19,7 @@ Created by FontForge 20120731 at Mon May 23 22:22:36 2016
bbox="0 -212 1158 896"
underline-thickness="50"
underline-position="-100"
unicode-range="U+0078-E607"
unicode-range="U+0078-E617"
/>
<missing-glyph horiz-adv-x="374"
d="M34 0v682h272v-682h-272zM68 34h204v614h-204v-614z" />
... ... @@ -56,5 +56,41 @@ d="M903 577l-68 69l-388 -388l-231 230l-68 -68l299 -298l65 65z" />
d="M512 599q47 0 88 -18t72 -49t49 -72t18 -89q0 -46 -18 -87t-49 -72t-72 -49t-88 -18t-88 18t-72 49t-49 72t-18 87q0 48 18 89t49 72t72 49t88 18v0zM512 599z" />
<glyph glyph-name="uniE607" unicode="&#xe607;"
d="M797 219.5q0 -7.5 -5 -13.5l-29 -28q-6 -6 -13.5 -6t-12.5 6l-225 224l-224 -224q-6 -6 -13.5 -6t-13.5 6l-28 28q-6 6 -6 13.5t6 13.5l266 266q6 6 13.5 6t12.5 -6l267 -266q5 -6 5 -13.5z" />
<glyph glyph-name="uniE608" unicode="&#xe608;"
d="M284 15q-14 -14 -14 -33t13.5 -32.5t32.5 -13.5t32 14l397 401q13 14 13 33t-13 33l-397 401q-13 14 -32 14t-32.5 -13.5t-13.5 -32.5t13 -33l351 -369l-350 -369v0zM284 15z" />
<glyph glyph-name="uniE609" unicode="&#xe609;"
d="M745 753q13 14 13 33t-13.5 32.5t-32.5 13.5t-32 -14l-396 -401q-14 -14 -14 -33t14 -33l396 -401q14 -14 32.5 -14t32 13.5t13.5 32.5t-13 33l-351 369l351 369v0zM745 753z" />
<glyph glyph-name="uniE60A" unicode="&#xe60a;"
d="M512.5 750q-12.5 0 -21.5 -9t-9 -22v-311h-249q-12 0 -21.5 -9t-9.5 -22t9.5 -22t21.5 -9h280q12 0 21.5 9t9.5 22v342q0 13 -9.5 22t-22 9zM513 874q-101 0 -193 -39.5t-158.5 -105.5t-106 -158t-39.5 -193t39.5 -193t106 -158.5t158.5 -105.5t193 -39t192.5 39
t158 105.5t106 158.5t39.5 193t-39.5 193t-106 158t-158 105.5t-192.5 39.5zM513 -56q-118 0 -218 58t-158.5 158t-58.5 218t58.5 218t158.5 158t218 58t218 -58t158 -158t58 -218t-58 -218t-158 -158t-218 -58z" />
<glyph glyph-name="uniE60B" unicode="&#xe60b;"
d="M286 509l-46 -45l272 -272l272 272l-46 45l-226 -226z" />
<glyph glyph-name="uniE60C" unicode="&#xe60c;"
d="M387 158l45 -46l272 272l-272 272l-45 -46l226 -226z" />
<glyph glyph-name="uniE60D" unicode="&#xe60d;"
d="M766 193l-196 192l196 192l-61 60l-196 -193l-196 193l-60 -60l196 -192l-196 -192l60 -59l196 192l196 -192z" />
<glyph glyph-name="uniE60E" unicode="&#xe60e;"
d="M704 665l-41 39l-343 -320l343 -320l41 39l-301 281z" />
<glyph glyph-name="uniE60F" unicode="&#xe60f;"
d="M892 125l-236 236q54 77 54 172q0 124 -87 211t-210.5 87t-211 -87t-87.5 -211t87.5 -211t210.5 -87q95 0 173 55l236 -236q16 -17 38 -18t37 14t14 37t-18 38zM213 533q0 82 58.5 140.5t140.5 58.5t140.5 -58.5t58.5 -140.5t-58.5 -140.5t-140.5 -58.5t-140.5 58.5
t-58.5 140.5z" />
<glyph glyph-name="uniE610" unicode="&#xe610;"
d="M512 77l-439 614h878z" />
<glyph glyph-name="uniE611" unicode="&#xe611;" horiz-adv-x="1173"
d="M569 607q-28 66 -74 108.5t-95 56.5t-100 2.5t-91.5 -45t-66 -94t-26.5 -137.5q0 -36 8.5 -67.5t26 -58t35.5 -47t46.5 -41t49 -34t52.5 -32.5t48 -30q71 -47 124.5 -106.5t63.5 -93.5q7 31 62.5 92t124.5 110q19 14 55.5 36.5t61 38.5t55 42.5t49 52t31.5 62.5t13 79
q0 76 -26.5 136t-67 92t-92 42.5t-101 -4t-94.5 -56t-72 -104.5z" />
<glyph glyph-name="uniE612" unicode="&#xe612;"
d="M0 896h1024v-1024h-1024v1024zM85 -43h854v854h-854v-854z" />
<glyph glyph-name="uniE613" unicode="&#xe613;"
d="M1024 -128h-1024v1024h1024v-1024zM947 674l-34 34q-13 13 -30 13t-30 -13l-486 -495l-196 205q-13 13 -30 13t-30 -13l-34 -34q-13 -13 -13 -30t13 -30l256 -256q23 -22 51 -8q9 0 9 8l546 546q18 13 20 30.5t-12 29.5z" />
<glyph glyph-name="uniE614" unicode="&#xe614;"
d="M160 996zM865 247q0 -18 -13 -31l-308 -308q-13 -13 -31 -13t-31 13l-309 308q-13 13 -13 31t13.5 31t30.5 13h617q18 0 31 -13t13 -31zM865 511q0 -18 -13 -31t-31 -13h-617q-18 0 -31 13t-13 31t13 31l309 309q13 13 31 13t31 -13l308 -309q13 -13 13 -31z" />
<glyph glyph-name="uniE615" unicode="&#xe615;"
d="M951 77h-878l439 614z" />
<glyph glyph-name="uniE616" unicode="&#xe616;"
d="M877 896h-730q-61 0 -104 -43t-43 -104v-730q0 -61 43 -104t104 -43h730q61 0 104 43t43 104v730q0 61 -43 104t-104 43zM939 19q0 -26 -18 -44t-44 -18h-730q-26 0 -44 18t-18 44v730q0 26 18 44t44 18h730q26 0 44 -18t18 -44v-730z" />
<glyph glyph-name="uniE617" unicode="&#xe617;"
d="M939 -128h-854q-35 0 -60 25t-25 60v854q0 35 25 60t60 25h854q35 0 60 -25t25 -60v-854q0 -35 -25 -60t-60 -25zM939 789q0 10 -6 16t-16 6h-810q-10 0 -16 -6t-6 -16v-810q0 -10 6 -16t16 -6h810q10 0 16 6t6 16v810zM457 183q-10 -12 -30.5 -12t-29.5 12l-171 171
q-13 10 -13 30q0 18 12.5 30.5t30.5 12.5q20 0 30 -13l141 -141l311 312q13 12 30 12q18 0 30.5 -12.5t12.5 -29.5q0 -21 -13 -30z" />
</font>
</defs></svg>
... ...

6.28 KB | W: | H:

4.98 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
require('../common');
... ...
... ... @@ -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,
... ...
... ... @@ -5,7 +5,7 @@ var $contain = $('.slide-accordion');
var $item = $contain.find('li');
var $width = $item.width();
var $spn = parseInt($('.home-page').width()) === 1150 ? (120 + 5) : (102 + 5);
var $spn = parseInt($('.home-page').width(), 0) === 1150 ? (120 + 5) : (102 + 5);
var slide;
function switchfun(to) {
... ...
... ... @@ -86,7 +86,7 @@ function uriLoc(attr, val) {
}
// 隐藏高级选项面板
function hideSeniorPanel(index) {
function hideSeniorPanel() {
$seniorSubWrap.children('.senior-sub:eq(' + hoveredIndex + ')').addClass('hide');
$seniorAttrWrap.children('.attr:eq(' + hoveredIndex + ')').removeClass('hover');
hoveredIndex = -1;
... ... @@ -371,11 +371,11 @@ $seniorAttrWrap.on('mouseenter', '.attr', function() {
$('.senior-sub').on('click', '.multi-select', function() {
$(this).closest('.senior-sub').addClass('multi');
}).on('click', '.multi-select-ok', function() {
var $btn = $(this),
$sub = $btn.closest('.senior-sub'),
var $btn2 = $(this),
$sub = $btn2.closest('.senior-sub'),
val = [];
if ($btn.hasClass('dis')) {
if ($btn2.hasClass('dis')) {
return;
}
... ...
... ... @@ -31,9 +31,9 @@ var logoAngle = 0,
loopTime = 500;
// handlebars模板
centerFn = handlebars.compile($('#simple-account-info-tpl').html());
loginFn = handlebars.compile($('#header-login-info-tpl').html());
cartFn = handlebars.compile($('#mini-cart-tpl').html());
centerFn = handlebars.compile($('#simple-account-info-tpl').html() || '');
loginFn = handlebars.compile($('#header-login-info-tpl').html() || '');
cartFn = handlebars.compile($('#mini-cart-tpl').html() || '');
// handlebars helper
handlebars.registerHelper('notzero', function(v1, options) {
... ... @@ -60,6 +60,9 @@ function formatThirdMenu() {
i++;
});
for (i = 0; i < 3; i++) {
if (!list[i]) {
return;
}
$thirdList.before('<dl class="category-list">' + list[i] + '</dl>');
}
$thirdList.remove();
... ... @@ -400,8 +403,8 @@ $subNav.on({
}
param.content_code = $show.data().code;
param.client_type = 'web';
param.width = 174;
param.height = 155;
param.width = 337;
param.height = 250;
param._ = new Date();
$.getJSON('http://new.yohobuy.com/common/getbanner?callback=?', param, function(JsonData) {
if (JsonData.code === 200) {
... ...
... ... @@ -563,8 +563,8 @@
background-image: resolve('layout/new.png');
background-repeat: no-repeat;
position: absolute;
margin-top: -20px;
margin-left: 16px;
right: -29px;
top: -6px;
}
a {
... ... @@ -572,6 +572,7 @@
font-size: 14px;
line-height: 14px;
display: inline-block;
position: relative;
}
li:hover a {
... ... @@ -775,4 +776,9 @@
.head-wrapper .main-logo {
left: 39%;
}
.show-detail img {
width: 174px;
height: 155px;
}
}
... ...
... ... @@ -228,8 +228,9 @@ a {
@import "header";
@import "footer";
@import "404";
@import "common/index";
@import "plugin/slider";
@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
... ...
... ... @@ -242,7 +242,6 @@
overflow: hidden;
}
}
}
.good-info-big {
... ...
... ... @@ -63,6 +63,7 @@
}
/* 990px */
.min-screen .product-list-page,
.min-screen .new-sale-page {
... ...
/**
* 登录判断
* @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});
};
... ...
'use strict';
const _ = require('lodash');
module.exports = seoData => {
const defaultSeoData = {
/* eslint-disable */
title: 'YOHO!有货 | 年轻人潮流购物中心,中国潮流购物风向标,官方授权正品保证',
keywords: 'Yoho! 有货官网,潮流志,潮流男装,潮牌,美国潮牌,日本潮牌,香港潮牌,潮牌店,新品首发,欧美潮流,全球购,代购,时尚,流行,特卖,B2C,正品,购物网站,网上购物,货到付款',
description: 'YOHO! 有货,年轻人潮流购物中心,中国最大的潮流商品购物网站。100%品牌正品保证,支持货到付款。作为YOHO!旗下的购物平台,汇集了全球潮流时尚商品和中国最流行的商品,也是国内最大的原创文化商品平台,也是香港,台湾地区流行商品的集中地。同时包含日本、韩国等众多国外潮流品牌,带给您全新潮流购物体验。'
/* eslint-enable */
};
_.merge(defaultSeoData, seoData);
return (req, res, next) => {
if (!req.xhr) {
res.locals.title = seoData.title;
res.locals.keywords = seoData.keywords;
res.locals.description = seoData.description;
}
next();
};
};
... ...