Authored by htoooth

merge master

... ... @@ -37,19 +37,19 @@ const getStaticUrls = (currentStatics) => {
};
// 关键词页面
const keywordsPage = () => {
return redis.getAsync('golobal:yoho:seo:keywords:allIds').then(function(res) {
let page = [];
const keywordsPage = (page) => {
return redis.getAsync(`global:yoho:seo:keywords:allIds:page:${page}`).then(function(res) {
let pages = [];
_.forEach(JSON.parse(res), val => {
page.push({
pages.push({
url: `https://www.yohobuy.com/chanpin/${val}.html`,
changefreq: 'daily',
priority: 0.5
});
});
return page;
return pages;
}).catch(()=>{
return {};
});
... ... @@ -74,10 +74,16 @@ const getArticleUrls = () => {
};
// www 地图数据
const wwwXmlData = () => {// eslint-disable-line
return Promise.all([keywordsPage(), getStaticUrls(_.get(staticUrls, 'www')), getArticleUrls()]).then(result => {
return _.concat(result[1], result[0], result[2]);
});
const wwwXmlData = (page) => {// eslint-disable-line
if (page > 1) {
return keywordsPage(page);
} else {
return Promise.all([keywordsPage(page),
getStaticUrls(_.get(staticUrls, 'www')),
getArticleUrls()]).then(result => {
return _.concat(result[1], result[0], result[2]);
});
}
};
// list 地图数据
... ... @@ -133,7 +139,9 @@ const siteMap = (req, res, next) => {
return;
}
eval(subdomain + 'XmlData')().then(urls => {// eslint-disable-line
let page = req.params[0] || 1;
eval(subdomain + 'XmlData')(page).then(urls => {// eslint-disable-line
sm.createSitemap({
hostname: `https://${subdomain}.yohobuy.com`,
xmlNs: ' ',
... ...
... ... @@ -53,9 +53,9 @@
<p{{#isEqual is_support 'N'}} class="unsp-way"{{/isEqual}}>
<label class="check-btn{{#isY default}} checked{{/isY}}" data-id="{{delivery_way_id}}"
title="{{delivery_way_name}}:运费 ¥ {{delivery_way_cost}}">{{delivery_way_name}}:运费 ¥ {{delivery_way_cost}}</label>
{{#isEqual delivery_way_id 2}}
<span>您所选择的区域暂不在支持顺丰派送范围内</span>
{{/isEqual}}
{{#if is_support_message}}
<span>{{is_support_message}}</span>
{{/if}}
</p>
{{/ deliveryWay}}
<p class="default-line">注:配送会由于天气,交通等不可抗拒的客观因素造成您收货时间延迟,请您知悉。</p>
... ...
... ... @@ -30,6 +30,6 @@ router.post('/common/getNewArrival', channelController.getNewArrival);
router.get('/guide', channelController.getIndexGuide);
// www站点地图
router.get('/sitemap.xml', sitemap.siteMap);
router.get(/\/sitemap(\d*)\.xml/, sitemap.siteMap);
module.exports = router;
... ...
... ... @@ -8,88 +8,11 @@
const listSeoMap = require(`${global.middleware}/seo/listSeoMap`);
const helpers = global.yoho.helpers;
const _ = require('lodash');
const tdk = require('../../../utils/getTDK');
// 搜索相关接口
const searchApi = require('../models/search-api');
const list = require('../models/list');
// 店铺页
const shop = (shopId, req, res, next, brandInfo) => {
let domain = req.query.domain,
params = req.query;
_.unset(params, 'domain');
shopId = parseInt(shopId, 10);
Object.assign(params, {shopId: shopId});
tdk('shop', shopId, req).then(TDKObj => {
if (TDKObj[0]) {
req.tdk = {
title: TDKObj[1],
keywords: TDKObj[2],
description: TDKObj[3]
};
}
return req.ctx(list).getShopInfo(shopId, req.user.uid).then(shopInfo => {
let pjax = params._pjax;
// 获取不到店铺信息跳转至首页
if (!shopInfo || _.isEmpty(shopInfo)) {
return res.redirect(helpers.urlFormat('', null, ''));
}
// 比较品牌域名与店铺域名是否一致,不一致跳转至店铺域名
if (!pjax && shopInfo.domain && domain && domain !== _.toLower(shopInfo.domain)) {
res.redirect(helpers.urlFormat('', params, shopInfo.domain));
return;
}
if (+shopInfo.shopTemplateType === 2) { // 经典模板
if (pjax) {
req.ctx(list).getShopGoodsData(shopId, req.yoho.channel, params, shopInfo).then(result => {
Object.assign(result, {
shopId: shopId,
layout: false
});
res.render('list/goods-list', result);
}).catch(next);
return;
}
req.ctx(list).getShopData(shopId, req.yoho.channel, params, shopInfo).then(result => {
Object.assign(result, {
page: 'shop',
shopId: shopId
});
// 店铺装修为空则不cache
if (!result.shopTopBanner) {
res.set('Cache-Control', 'no-cache');
}
res.render('list/shop-index', result);
}).catch(next);
} else { // 基础模板
req.ctx(list).getBaseShopData(params, Object.assign({uid: req.user.uid}, brandInfo),
req.yoho.channel, shopId).then(result => {
Object.assign(result, {page: 'list'});
// 基础店铺装修为空则不cache
if (!result.brand || !result.brand.shopBanner) {
res.set('Cache-Control', 'no-cache');
}
res.render('list/brand', result);
}).catch(next);
}
});
}).catch(next);
};
/**
* 商品分类列表页
* @param {[type]} req [description]
... ... @@ -186,47 +109,6 @@ exports.newWithChannel = (req, res, next) => {
};
/**
* 品牌页
* @param {[type]} req [description]
* @param {[type]} res [description]
* @return {[type]} [description]
*/
exports.brand = (req, res, next) => {
let brandDomain = req.query.domain;
let shopId = req.query.shopId;
// shopId存在,直接走店铺
if (shopId) {
return shop(shopId, req, res, next);
}
if (!brandDomain) {
return next();
}
// 获取品牌信息
req.ctx(list).getBrandInfo({domain: brandDomain}).then(brandInfo => {
if (!brandInfo.hasOwnProperty('type')) {
return res.redirect(helpers.urlFormat(''));
}
switch (parseInt(brandInfo.type, 10)) {
case 1: // 搜索
res.redirect(helpers.urlFormat('', {query: brandInfo.brandDomain}, 'search'));
break;
case 2: // 店铺
return shop(brandInfo.shopId, req, res, next, brandInfo);
default: // 品牌
res.redirect(helpers.urlFormat('', {
query: brandInfo.brandDomain,
brand: brandInfo.brandId
}, 'search'));
break;
}
}).catch(next);
};
/**
* 品牌介绍页
* @param {[type]} req [description]
* @param {[type]} res [description]
... ... @@ -252,36 +134,6 @@ exports.brandAbout = (req, res, next) => {
};
/**
* 店铺商品列表页
* @param {[type]} req [description]
* @param {[type]} res [description]
* @return {[type]} [description]
*/
exports.shopList = (req, res, next) => {
let shopId = req.query.shopId;
if (!shopId) {
return next();
}
req.ctx(list).getShopListData(req.yoho.channel, req.query, req.user.uid).then(result => {
Object.assign(result, {
page: 'shop',
shopId: shopId
});
if (req.query.query) {
result.shopKey = req.query.query;
}
// 店铺装修为空则不cache
if (!result.shopTopBanner) {
res.set('Cache-Control', 'no-cache');
}
res.render('list/shop-list', result);
}).catch(next);
};
/**
* ajax调用品牌页左侧水牌
* @param {[type]} req [description]
* @param {[type]} res [description]
... ...
'use strict';
const mRoot = '../models';
const shopModel = require(`${mRoot}/shop-service`);
const tdk = require('../../../utils/getTDK');
// 店铺首页(经典&基础)
exports.index = (req, res, next) => {
let domain = req.query.domain;
let shopId = req.query.shopId;
if (!domain) {
return next();
}
if (req.xhr && req.query._pjax && shopId) {
return req.ctx(shopModel).getShopGoodsData(shopId, req.yoho.channel, req.query).then(result => {
Object.assign(result, {
shopId: shopId,
layout: false
});
res.render('list/goods-list', result);
});
}
return Promise.all([
tdk('shop', shopId, req),
req.ctx(shopModel).getShopInfoAsync(domain, req.yoho.channel, req.query)
]).then(result => {
let TDKObj = result[0],
shopObj = result[1];
if (TDKObj && TDKObj[0]) {
req.tdk = {
title: TDKObj[1],
keywords: TDKObj[2],
description: TDKObj[3]
};
}
// 数据异常,重定向
if (shopObj.redirect) {
return res.redirect(shopObj.redirect);
}
if (shopObj.templateType === 2) { // 经典模板
Object.assign(shopObj, {page: 'shop'});
// 店铺装修为空则不cache
if (!shopObj.shopTopBanner) {
res.set('Cache-Control', 'no-cache');
}
res.render('shop/index', shopObj);
} else { // 基础模版
Object.assign(shopObj, {page: 'list'});
// 基础店铺装修为空则不cache
if (!shopObj.brand || !shopObj.brand.shopBanner) {
res.set('Cache-Control', 'no-cache');
}
res.render('list/brand', shopObj);
}
}).catch(next);
};
// 经典店铺列表
exports.list = (req, res, next) => {
let shopId = req.query.shopId;
if (!shopId) {
return next();
}
return req.ctx(shopModel).getShopListInfoAsync(req.yoho.channel, req.query).then(result => {
Object.assign(result, {
page: 'shop',
shopId: shopId,
shopKey: req.query.query || ''
});
// 店铺装修为空则不cache
if (!result.shopTopBanner) {
res.set('Cache-Control', 'no-cache');
}
res.render('shop/list', result);
}).catch(next);
};
// 经典店铺推荐文章
exports.article = (req, res, next) => {
let brands = req.query.brands;
if (!brands) {
return next();
}
return req.ctx(shopModel).getShopArticleByBrandsAsync(brands).then(result => {
res.render('shop/article', Object.assign(result, {layout: false}));
}).catch(next);
};
... ...
... ... @@ -172,12 +172,14 @@ module.exports = class extends global.yoho.BaseModel {
method: 'app.search.findLike',
limit: limit || 10,
product_skn: skn
}, params: {
cache: 86400
}});
}
// 根据small_sort从redis获取分类下的关键词
getRecommendKeywords(smallSort) {
return redis.all([['get', `golobal:yoho:seo:keywords:sortId:${smallSort}`]]).then(res => {
return redis.all([['get', `global:yoho:seo:keywords:sortId:${smallSort}:page:1`]]).then(res => {
return res[0];
});
}
... ...
... ... @@ -965,11 +965,11 @@ function _getSeoByGoodsInfo(goodsInfo, navs) {
title += goodsInfo.name + '正品 | YOHO!BUY 有货';
let keywords = brandName + sortName + ',' + brandName + '官网专卖店,' + brandName + '官方授权店,' +
let keywords = brandName + sortName + ',' + brandName + '专卖店,' + brandName + '官方授权店,' +
brandName + '正品,' + brandName + '打折,' + brandName + '折扣店,' + brandName + '真品,' + brandName + '代购';
let description = `YOHO!BUY 有货-${brandName}官方授权店,${goodsInfo.name}图片、报价、介绍。` +
`YOHO!BUY 有货${brandName}官网专卖店提供${brandName}正品、${brandName}真品、 ${brandName}打折、${brandName}代购等。`;
`YOHO!BUY 有货${brandName}专卖店提供${brandName}正品、${brandName}真品、 ${brandName}打折、${brandName}代购等。`;
let cononicalURL = goodsInfo.productUrl;
... ... @@ -1060,6 +1060,9 @@ function _detailDataPkg(origin, uid, vipLevel, cookies) {
// 定金预售
result.deposit = propOrigin('is_deposit_advance', 'N');
// 定金定时预售商品
result.limitTime = propOrigin('is_limit_time_advance', 'N');
// 秒杀商品
result.secKill = propOrigin('is_secKill', 'N');
... ... @@ -1364,6 +1367,11 @@ function _detailDataPkg(origin, uid, vipLevel, cookies) {
result.addToCart = false;
}
// 定金定时预售商品
if (result.limitTime === 'Y') {
result.addToCart = false;
}
// 线下店商品类型
result.storeStatus = propOrigin('store_show_status', 1);
... ...
... ... @@ -149,8 +149,8 @@ const _getProductSeoData = (detail) => {
resData = {
title: `${bn} | ${gn}正品 | YOHO!BUY 有货`,
keywords: `${bn},${bn}官网专卖店,${bn}官方授权店,${bn}正品,${bn}打折,${bn}折扣店,${bn}真品,${bn}代购`,
description: `YOHO!BUY 有货-${bn}官方授权店,${gn}图片、报价、介绍。YOHO!BUY 有货${bn}官网专卖店提供${bn}正品、${bn}真品、 ${bn}打折、${bn}代购等。` // eslint-disable-line
keywords: `${bn},${bn}专卖店,${bn}官方授权店,${bn}正品,${bn}打折,${bn}折扣店,${bn}真品,${bn}代购`,
description: `YOHO!BUY 有货-${bn}官方授权店,${gn}图片、报价、介绍。YOHO!BUY 有货${bn}专卖店提供${bn}正品、${bn}真品、 ${bn}打折、${bn}代购等。` // eslint-disable-line
};
}
... ...
... ... @@ -23,34 +23,12 @@ const brandFolderSeries = '经典系列';
const folderTitle = '经典款型';
const seriesTitle = '经典系列';
// 经典店铺list url
const shopListUrl = '/product/shoplist';
// 搜索分类信息需要的参数
const positionId = 10;
// 获取分类左侧广告id
const sortAdsId = 79;
const _getGender = (channel) => {
let gender;
switch (channel) {
case 'boys':
gender = '1,3';
break;
case 'girls':
gender = '2,3';
break;
default:
gender = '1,2,3';
break;
}
return gender;
};
/**
* 获取商品分类列表数据
*/
... ... @@ -571,402 +549,6 @@ function getShopInfo(shopId, uid) {
});
}
/**
* 获取经典模板店铺数据
* @param shopId
* @param uid
* @param params
* @param shopInfo 店铺介绍
*/
function getShopData(shopId, channel, params, shopInfo) {
let gender = _getGender(channel);
params = params || {};
params.shopId = shopId;
return Promise.all([
headerModel.requestHeaderData(channel), // 头部数据
this.searchApi.getShopDecorator(shopId), // 店铺装修数据
this.searchApi.getProductList(Object.assign({
shop_id: shopId
}, params), 'shop'), // 搜索店铺商品
this.searchApi.getShopBrands(shopId), // 店铺品牌数据
this.shopApi.shopCouponListAsync(shopId) // 店铺优惠券数据
]).then(result => {
let finalResult = {};
Object.assign(finalResult,
result[0], // 头部数据
searchHandler.handlePathNavData(shopInfo, params, 'shop', channel), // 面包屑导航
searchHandler.getBrandShopSeo(channel, {shopName: shopInfo.shopName || shopInfo.brandName}, params) // 店铺SEO
);
_.set(finalResult, 'headerData.header', true);
// 店铺装修
if (result[1].code === 200) {
Object.assign(finalResult, shopHandler.getShopDecorator(result[1].data, params, shopId));
_.set(finalResult, 'shopTopBanner.brandIntro', {
shopId: shopId,
brandName: shopInfo.brandName || '',
isFavorite: shopInfo.isFavorite || false,
brandCont: shopInfo.brandCont || ''
});
} else {
return Promise.reject('No ShopDecorator data');
}
// 获取商品数据和顶部筛选条件
if (result[2].code === 200) {
let allGoods = {
name: '全部商品 ALL',
sort: searchHandler.handleOptsData(params, _.get(result[2], 'data.total', 0)),
list: productProcess.processProductList(_.get(result[2], 'data.product_list', []), {
newCoverSort: true,
showDiscount: false,
gender: gender
}),
href: `/product/shoplist?navBar=1&shopId=${shopId}`
};
_.set(allGoods, 'sort.newPage', true); // 启用新的分页导航
finalResult.allGoods = allGoods;
}
let sknList = []; // 资源位配置商品skn
let prodList = _.concat(_.get(finalResult, 'newArrivel.list', []),
_.get(finalResult, 'hotSingle.list', []));
_.forEach(prodList, value => {
sknList.push(value.productSkn);
});
let articleApiMethod = [], // 通过品牌获取相关文章接口
apiMethod = [
this.searchApi.getProductList({
viewNum: sknList.length,
query: _.join(_.uniq(sknList), ',')
}, 'shop')
];
if (result[3].code === 200 && result[3].data) {
_.forEach(result[3].data, value => {
articleApiMethod.push(
this.searchApi.getArticleByBrand(value.brand_id, 'udid') // 品牌推荐文章
);
});
}
if (result[4].data && !_.isEmpty(result[4].data)) {
finalResult.coupon = searchHandler.handleBrandShopCoupons(result[4].data, {shopId: shopId});
}
// 根据店铺id获取分类
apiMethod.push(this.searchApi.getSortList({shop_id: shopId}));
apiMethod = _.concat(apiMethod, articleApiMethod);
return Promise.all(apiMethod).then(subRes => {
// 设置资源位商品封面图
if (subRes[0].code === 200) {
let list = {};
prodList = productProcess.processProductList(_.get(subRes[0], 'data.product_list', []), {
newCoverSort: true,
showDiscount: false,
gender: gender
});
_.forEach(prodList, value => {
list[value.product_skn] = {
img: value.default_images,
title: value.product_name,
price: ${value.sales_price}`
};
});
if (_.has(finalResult, 'newArrivel.list')) {
_.forEach(finalResult.newArrivel.list, value => {
if (list[value.productSkn]) {
Object.assign(value, list[value.productSkn]);
}
});
}
if (_.has(finalResult, 'hotSingle.list')) {
_.forEach(finalResult.hotSingle.list, value => {
if (list[value.productSkn]) {
Object.assign(value, list[value.productSkn]);
}
});
}
}
if (subRes[1].code === 200) {
let groupSort = _.get(subRes[1], 'data', []);
finalResult.leftContent = searchHandler.handleSortData(groupSort, params, params, '/product/shoplist');
_.set(finalResult, 'brandShopAd', {baseUrl: shopListUrl});
if (finalResult.allGoods) {
Object.assign(finalResult.allGoods, searchHandler.setShopSort(groupSort, Object.assign({},
params, {page: 1})), searchHandler.setGenderFilter(params));
}
}
let articleList = [];
for (let i = 2; i < subRes.length; i++) {
articleList = _.concat(articleList, _.get(subRes[i], 'data', []));
}
if (articleList.length >= 3) {
let trendList = [];
for (let i = 0; i < 3; i++) {
trendList.push({
href: helpers.urlFormat(`/guang/${articleList[i].id}.html`, null),
src: helpers.getForceSourceUrl(articleList[i].src) +
'?imageView2/1/w/{width}/h/{height}',
mainTitle: articleList[i].title,
Subtitle: articleList[i].intro
});
articleList = _.concat(articleList, _.get(subRes[i], 'data', []));
}
finalResult.trendInfo = {
name: '潮流资讯 HOT ITEMS',
trendList: trendList
};
}
return finalResult;
});
});
}
/**
* 获取店铺商品数据
*/
function getShopGoodsData(shopId, channel, params) {
let gender = _getGender(channel);
let resData = {};
_.unset(params, '_pjax');
return Promise.all([
this.searchApi.getProductList(Object.assign({
shop_id: shopId
}, params), 'shop'), // 搜索店铺商品
this.searchApi.getSortList({shop_id: shopId}) // 根据店铺id获取分类
]).then(result => {
// 获取商品数据和顶部筛选条件
if (result[0].code === 200) {
Object.assign(resData, {
sort: searchHandler.handleOptsData(params, _.get(result[0], 'data.total', 0)),
list: productProcess.processProductList(_.get(result[0], 'data.product_list', []), {
newCoverSort: true,
showDiscount: false,
gender: gender
})
});
_.set(resData, 'sort.newPage', true); // 启用新的分页导航
}
if (result[1].code === 200) {
let groupSort = _.get(result[1], 'data', []);
Object.assign(resData, searchHandler.setShopSort(groupSort, Object.assign({}, params,
{page: 1})), searchHandler.setGenderFilter(params));
}
return resData;
});
}
function getShopListData(channel, params, uid) {
let gender = _getGender(channel),
shopId = params.shopId,
navBar = params.navBar || 1;
let apiArr = [
headerModel.requestHeaderData(channel), // 头部数据
this.searchApi.getShopDecorator(shopId), // 店铺装修数据
this.searchApi.getShopInfo(shopId, uid), // 店铺介绍
this.searchApi.getProductList(Object.assign({shop_id: shopId}, params,
{limit: (params.limit || 60) - 1}), 'shop'), // 搜索店铺商品
this.searchApi.getSortList({shop_id: shopId}) // 店铺分类
];
if (_.has(params, 'query')) {
// 如果有店内搜索,则并行查询店铺所有商品,搜索不到商品则显示所有商品
apiArr.push(this.searchApi.getProductList(Object.assign({shop_id: shopId},
params, {query: ''}), 'shop')); // 搜索店铺所有商品
}
return Promise.all(apiArr).then(result => {
let finalResult = {
headerData: Object.assign(result[0].headerData, {header: true})
};
// 面包屑导航
Object.assign(finalResult, searchHandler.handlePathNavData({}, params, 'shop', channel));
// 店铺装修
if (result[1].code === 200) {
Object.assign(finalResult, shopHandler.getShopDecorator(result[1].data, params, shopId));
// 设置shop nav选中状态
_.set(finalResult, `navigationBar[${navBar}].current`, true);
if (result[2].code === 200) {
let data = _.get(result[2], 'data', {});
_.set(finalResult, 'shopTopBanner.brandIntro', {
shopId: shopId,
brandName: data.shop_name || '',
isFavorite: data.is_favorite === 'Y',
brandCont: data.shop_intro || ''
});
// 店铺SEO
Object.assign(finalResult, searchHandler.getBrandShopSeo(channel, {
shopName: data.shop_name
}, params));
}
} else {
return Promise.reject('No ShopDecorator data');
}
// 获取商品数据和顶部筛选条件
if (result[3].code === 200) {
let info = result[3];
let goodsList = _.get(info, 'data.product_list', []);
if (goodsList.length) {
let totalPage = _.get(info, 'data.total', 1);
Object.assign(finalResult, {
filters: searchHandler.handleFilterDataAll(info.data, params),
opts: searchHandler.handleOptsData(params, totalPage),
goods: productProcess.processProductList(goodsList, {
newCoverSort: true,
showDiscount: false,
gender: _getGender(channel),
query: params.query
}),
hasNextPage: searchHandler.handleNextPage(params, totalPage),
footPager: searchHandler.handlePagerData(totalPage, params)
});
_.set(finalResult, 'filters.checkedConditions.clearUrl',
`?navBar=${params.navBar}&shopId=${params.shopId}`);
} else {
finalResult.searchEmpty = true;
if (result[5] && result[5].code === 200) {
let allGoods = {
name: '全部商品 ALL',
sort: searchHandler.handleOptsData(params, _.get(result[5], 'data.total', 0)),
list: productProcess.processProductList(_.get(result[5], 'data.product_list', []), {
newCoverSort: true,
showDiscount: false,
gender: gender
})
};
_.set(allGoods, 'sort.newPage', true); // 启用新的分页导航
finalResult.allGoods = allGoods;
}
}
}
if (result[4].code === 200) {
let groupSort = _.get(result[4], 'data', []),
noPageQs = Object.assign({}, params, {page: 1});
finalResult.leftContent = searchHandler.handleSortData(groupSort, noPageQs, params);
_.set(finalResult, 'brandShopAd', {baseUrl: shopListUrl});
if (finalResult.allGoods) {
Object.assign(finalResult.allGoods, searchHandler.setShopSort(groupSort, noPageQs));
}
}
finalResult.criteo = {skn: searchHandler.getCriteo(_.get(finalResult, 'goods'))};
return finalResult;
});
}
/**
* 获取基础模板店铺数据
*/
function getBaseShopData(params, extra, channel, shopId) {
let resData = {};
params.shopId = shopId;
return Promise.all([
getBrandData(params, extra, channel),
this.searchApi.getShopDecorator(shopId), // 店铺装修数据
this.searchApi.getShopInfo(shopId, extra.uid),
this.shopApi.shopCouponListAsync(shopId) // 店铺优惠券数据
]).then(result => {
let brand = result[0] || {};
Object.assign(resData, brand);
if (result[1].code === 200) {
let data = result[1].data || {},
decorator = shopHandler.getShopDecorator(data, {}, shopId, true);
Object.assign(decorator.shopTopBannerBase || {}, {
shopId: shopId,
bannerHeight: 150,
shopHome: `/?shopId=${shopId}`,
shopIntro: `/shop${shopId}-about`,
coled: _.get(result[2], 'data.is_favorite', 'N') === 'Y'
});
_.set(resData, 'brand.shopBanner', decorator.shopTopBannerBase);
_.unset(resData, 'brand.brandBanner');
if (decorator.signboard) {
_.unset(resData, 'brand.node');
_.set(resData, 'brand.signboard', decorator.signboard);
}
}
if (result[2].code === 200) {
let shopName = _.get(result[2], 'data.shop_name', '');
_.set(resData, 'brand.shopBanner.shopName', shopName);
_.set(resData, 'brand.pathNav[2]', {
name: shopName,
pathTitle: shopName
});
// 店铺SEO
Object.assign(resData, searchHandler.getBrandShopSeo(channel, {
shopName: shopName
}, params));
}
_.unset(resData, 'brand.coupon');
if (result[3].data && !_.isEmpty(result[3].data)) {
_.set(resData, 'brand.coupon',
searchHandler.handleBrandShopCoupons(result[3].data, {shopId: shopId}));
}
return resData;
});
}
function getUserCoupunStatus(id, uid, type) {
if (type === 'shop') {
return this.shopApi.shopCouponListAsync(id, uid).then(result => {
... ... @@ -1014,10 +596,6 @@ module.exports = class extends global.yoho.BaseModel {
this.getNodeContentData = getNodeContentData.bind(this);
this.getAdnav = getAdnav.bind(this);
this.getShopInfo = getShopInfo.bind(this);
this.getShopData = getShopData.bind(this);
this.getShopGoodsData = getShopGoodsData.bind(this);
this.getShopListData = getShopListData.bind(this);
this.getBaseShopData = getBaseShopData.bind(this);
this.getUserCoupunStatus = getUserCoupunStatus.bind(this);
}
};
... ...
... ... @@ -130,8 +130,8 @@ const handleBrandCheckedData = (params, origin) => {
brandsTotalName = _.map(origin, 'name').join('、');
_.forEach(origin, (value) => {
if (typeof _.find(intBrands, o => {
return _.isEqual(o, +value.id);
}) !== 'undefined') {
return _.isEqual(o, +value.id);
}) !== 'undefined') {
let checked = {
name: value.name
}; // push 到已选择数组
... ... @@ -463,7 +463,7 @@ exports.handleOptsData = (params, total, extra) => {
// 上一页下一页
let preHref = (!_.isEmpty(params.page) && parseInt(params.page, 10) > 1) ?
parseInt(params.page, 10) - 1 : 1;
parseInt(params.page, 10) - 1 : 1;
let nextHref = (!_.isEmpty(params.page)) ? parseInt(params.page, 10) + 1 : 2;
params.page = _.isEmpty(params.page) ? 1 : params.page;
... ... @@ -627,22 +627,24 @@ exports.setShopSort = (data, params) => {
* @returns {{}}
*/
exports.setGenderFilter = (params) => {
return {genderFilter: [
{
name: '全部',
href: handleFilterUrl(params, {}, {gender: true}),
checked: !params.gender || params.gender === '1,2,3'
},
{
name: 'BOYS',
href: handleFilterUrl(params, {gender: '1,3'}),
checked: params.gender === '1,3'
}, {
name: 'GIRLS',
href: handleFilterUrl(params, {gender: '2,3'}),
checked: params.gender === '2,3'
}
]};
return {
genderFilter: [
{
name: '全部',
href: handleFilterUrl(params, {}, {gender: true}),
checked: !params.gender || params.gender === '1,2,3'
},
{
name: 'BOYS',
href: handleFilterUrl(params, {gender: '1,3'}),
checked: params.gender === '1,3'
}, {
name: 'GIRLS',
href: handleFilterUrl(params, {gender: '2,3'}),
checked: params.gender === '2,3'
}
]
};
};
/**
... ... @@ -1091,10 +1093,10 @@ exports.handlePathNavData = (data, params, page, channel) => {
href: handleFilterUrl(sort.relation_parameter),
pathTitle: sort.category_name
},
{
name: misort.category_name,
pathTitle: misort.category_name
}];
{
name: misort.category_name,
pathTitle: misort.category_name
}];
}
});
}
... ... @@ -1595,8 +1597,8 @@ exports.getBrandShopSeo = (channel, info, qs) => {
});
} else {
Object.assign(resData, {
title: `${params.nameEn} | ${params.name}官网`,
keywords: `${params.nameEn}, ${params.name}官网`,
title: `${params.nameEn} | ${params.name}旗舰店`,
keywords: `${params.nameEn}, ${params.name}旗舰店`,
description: `${params.nameEn}正品网购。${params.name}官方授权!`
});
}
... ...
... ... @@ -417,7 +417,7 @@ function getSearchKeywordData(params, channel) {
function getSearchKeywordDataById(id, params, channel) {
return co(function* () {
let redisData = yield redis.all([
['get', `golobal:yoho:seo:keywords:id:${id}`]
['get', `global:yoho:seo:keywords:id:${id}`]
]);
if (!redisData[0]) {
... ...
... ... @@ -61,4 +61,25 @@ module.exports = class extends global.yoho.BaseModel {
}
});
}
/**
* 根据shopId获取店铺基本信息
* @return
*/
getShopInfo(shopId, uid) {
let finalParams = {
method: 'app.shops.getIntro',
shop_id: shopId || 0,
uid: uid || 0
};
return this.get({
data: finalParams,
params: {cache: config.apiCache}
});
};
};
... ...
... ... @@ -355,21 +355,26 @@ const _handleSaleCategory = (shopId, baseUrl, resourceObj) => {
*/
exports.getShopDecorator = (data, params, shopId, base) => {
let dest = {};
let sourceFn;
if (base) {
sourceFn = {
signboard(info) {
dest.signboard = signboard(info);
},
shopTopBanner_base(info) {
Object.assign(dest, shopTopBannerBase(info));
}
};
_.forEach(data.list, (value) => {
if (!sourceFn[value.resource_name]) {
return;
}
let info = Fn.pipe(JSON.parse, _.partial(_handleSaleCategory, shopId, ''))(value.resource_data || '[]');
switch (value.resource_name) {
case 'signboard':
dest.signboard = signboard(info);
break;
case 'shopTopBanner_base':
Object.assign(dest, shopTopBannerBase(info));
break;
default:
break;
}
sourceFn[value.resource_name](info);
});
} else {
Object.assign(dest, {
... ... @@ -377,46 +382,50 @@ exports.getShopDecorator = (data, params, shopId, base) => {
hotSingle: {}
});
sourceFn = {
newProducts(info) {
Object.assign(dest.newArrivel, newProducts(info));
},
hotProducts(info) {
Object.assign(dest.hotSingle, hotProducts(info));
},
goodsTabBar(info) {
let tabBar = goodsTabBar(info, shopId);
Object.assign(dest.newArrivel, {navs: tabBar.new});
Object.assign(dest.hotSingle, {navs: tabBar.hot});
},
shopTopBanner(info) {
Object.assign(dest, shopTopBanner(info));
},
navigationBar(info) {
Object.assign(dest, navigationBar(info, shopId, params));
},
largeSlideImg(info) {
Object.assign(dest, largeSlideImg(info, shopId));
},
oneRowTwoColImages(info) {
Object.assign(dest, oneRowTwoColImages(info, shopId));
},
recommend(info) {
Object.assign(dest, recommend(info, shopId));
},
brandBrowse(info) {
Object.assign(dest, brandBrowse(info, params));
},
hotRecommend(info) {
Object.assign(dest, hotRecommend(info));
}
};
_.forEach(data.list, (value) => {
let info = Fn.pipe(JSON.parse, _.partial(_handleSaleCategory, shopId, shopListUrl))(value.resource_data || '[]'); // eslint-disable-line
let tabBar;
switch (value.resource_name) {
case 'newProducts':
Object.assign(dest.newArrivel, newProducts(info));
break;
case 'hotProducts':
Object.assign(dest.hotSingle, hotProducts(info));
break;
case 'goodsTabBar':
tabBar = goodsTabBar(info, shopId);
Object.assign(dest.newArrivel, {navs: tabBar.new});
Object.assign(dest.hotSingle, {navs: tabBar.hot});
break;
case 'shopTopBanner':
Object.assign(dest, shopTopBanner(info));
break;
case 'navigationBar':
Object.assign(dest, navigationBar(info, shopId, params));
break;
case 'largeSlideImg':
Object.assign(dest, largeSlideImg(info, shopId));
break;
case 'oneRowTwoColImages':
Object.assign(dest, oneRowTwoColImages(info, shopId));
break;
case 'recommend':
Object.assign(dest, recommend(info, shopId));
break;
case 'brandBrowse':
Object.assign(dest, brandBrowse(info, params));
break;
case 'hotRecommend':
Object.assign(dest, hotRecommend(info));
break;
default:
break;
if (!sourceFn[value.resource_name]) {
return;
}
let info = Fn.pipe(JSON.parse, _.partial(_handleSaleCategory, shopId, shopListUrl))(value.resource_data || '[]'); // eslint-disable-line
sourceFn[value.resource_name](info);
});
}
... ...
... ... @@ -7,13 +7,529 @@ const Promise = require('bluebird');
const co = Promise.coroutine;
const _ = require('lodash');
const Api = require('./shop-api');
const SearchApi = require('./search-api');
const helpers = global.yoho.helpers;
const shopHandler = require('./shop-handler');
const searchHandler = require('./search-handler');
const headerModel = require('../../../doraemon/models/header');
const productProcess = require('../../../utils/product-process');
const DEFAULT_IMG = '01091c21f2317a64f123f1649fbbccf7ba';
// 经典店铺list url
const shopListUrl = '/product/shoplist';
const needParams = ['query', 'msort', 'misort', 'category_id', 'gender', 'shelveTime'];
/**
* channel=>gender
*/
const _getGender = (channel) => {
let gender;
switch (channel) {
case 'boys':
gender = '1,3';
break;
case 'girls':
gender = '2,3';
break;
default:
gender = '1,2,3';
break;
}
return gender;
};
function _getShopData(channel, params, shopInfo) {
params = params || {};
let gender = _getGender(channel),
shopId = params.shopId;
let resData = {shopId: shopId};
return co(function* () {
let result = yield Promise.props({
header: headerModel.requestHeaderData(channel), // 头部数据
sort: this.searchApi.getSortList({shop_id: shopId}),
decorator: this.searchApi.getShopDecorator(shopId), // 店铺装修数据
product: this.searchApi.getProductList(Object.assign({
shop_id: shopId,
need_filter: 'no'
}, params), 'shop'), // 搜索店铺商品
brands: this.searchApi.getShopBrands(shopId), // 店铺品牌数据
coupons: this.api.shopCouponListAsync(shopId), // 店铺优惠券数据
shopInfo: shopInfo ? Promise.resolve(shopInfo) : this.api.getShopInfo(shopId)
});
if (!shopInfo) {
shopInfo = _.get(result, 'shopInfo.data', {});
}
Object.assign(resData,
result.header, // 头部数据
searchHandler.handlePathNavData({brandName: shopInfo.shop_name}, params, 'shop', channel), // 面包屑导航
searchHandler.getBrandShopSeo(channel, {shopName: shopInfo.shop_name}, params) // 店铺SEO
);
_.set(resData, 'headerData.header', true);
// 店铺装修
if (result.decorator.code === 200) {
Object.assign(resData, shopHandler.getShopDecorator(result.decorator.data, params, shopId));
_.set(resData, 'shopTopBanner.brandIntro', {
shopId: shopId,
brandName: shopInfo.shop_name || '',
brandCont: shopInfo.shop_intro || ''
});
} else {
return Promise.reject('No ShopDecorator data');
}
// 获取商品数据和顶部筛选条件
if (result.product.code === 200) {
let data = result.product.data;
let allGoods = {
name: '全部商品 ALL',
sort: searchHandler.handleOptsData(params, _.get(data, 'total', 0)),
list: productProcess.processProductList(_.get(data, 'product_list', []), {
newCoverSort: true,
showDiscount: false,
gender: gender
}),
href: `/product/shoplist?navBar=1&shopId=${shopId}`
};
_.set(allGoods, 'sort.newPage', true); // 启用新的分页导航
resData.allGoods = allGoods;
}
// 店铺类目
if (result.sort.code === 200) {
let groupSort = _.get(result.sort, 'data', []);
resData.leftContent = searchHandler.handleSortData(groupSort, params, params, shopListUrl);
_.set(resData, 'brandShopAd', {baseUrl: shopListUrl});
if (resData.allGoods) {
Object.assign(resData.allGoods, searchHandler.setShopSort(groupSort, Object.assign({},
params, {page: 1})), searchHandler.setGenderFilter(params));
}
}
// 店铺优惠券
if (result.coupons.data && !_.isEmpty(result.coupons.data)) {
resData.coupon = searchHandler.handleBrandShopCoupons(result.coupons.data, {shopId: shopId});
}
let sknList = []; // 资源位配置商品skn
let prodList = _.concat(_.get(resData, 'newArrivel.list', []),
_.get(resData, 'hotSingle.list', []));
_.forEach(prodList, value => {
sknList.push(value.productSkn);
});
let apiMethod = [
this.searchApi.getProductList({
viewNum: sknList.length,
query: _.join(_.uniq(sknList), ',')
}, 'shop')
];
// 店铺品牌
if (result.brands.code === 200 && result.brands.data) {
let brands = [];
_.forEach(result.brands.data, value => {
brands.push(value.brand_id);
});
resData.shopBrands = brands.join(',');
}
let subRes = yield Promise.all(apiMethod);
// 设置资源位商品封面图
if (subRes[0].code === 200) {
let list = {};
prodList = productProcess.processProductList(_.get(subRes[0], 'data.product_list', []), {
newCoverSort: true,
showDiscount: false,
gender: gender
});
_.forEach(prodList, value => {
list[value.product_skn] = {
img: value.default_images,
title: value.product_name,
price: ${value.sales_price}`
};
});
if (_.has(resData, 'newArrivel.list')) {
_.forEach(resData.newArrivel.list, value => {
if (list[value.productSkn]) {
Object.assign(value, list[value.productSkn]);
}
});
}
if (_.has(resData, 'hotSingle.list')) {
_.forEach(resData.hotSingle.list, value => {
if (list[value.productSkn]) {
Object.assign(value, list[value.productSkn]);
}
});
}
}
resData.trendInfo = true; // 展示店铺推荐文章
return resData;
}).bind(this)();
}
/**
* 获取基础模板店铺数据
*/
function _getBaseShopData(channel, params, shopInfo) {
params = params || {};
let searchParams = searchHandler.getSearchParams(params);
let shopId = params.shopId;
return co(function* () {
let result = yield Promise.props({
header: headerModel.requestHeaderData(channel), // 头部数据
sort: this.searchApi.getSortList({shop_id: shopId}),
decorator: this.searchApi.getShopDecorator(shopId), // 店铺装修数据
product: this.searchApi.getProductList(Object.assign(searchParams,
{shop_id: shopId}), 'shop'), // 搜索店铺商品
coupons: this.api.shopCouponListAsync(shopId), // 店铺优惠券数据
shopInfo: shopInfo ? Promise.resolve(shopInfo) : this.api.getShopInfo(shopId)
});
if (!shopInfo) {
shopInfo = _.get(result, 'shopInfo.data', {});
}
const shopName = shopInfo.shop_name;
let resData = {
shopId: shopId,
brand: Object.assign({brandShopAd: true},
searchHandler.handlePathNavData({brandName: shopName}, params, 'shop', channel))
};
Object.assign(resData,
result.header, // 头部数据
searchHandler.getBrandShopSeo(channel, {shopName: shopName}, params));
_.set(resData, 'headerData.header', true);
_.set(resData, 'brand.shopBanner', {
shopId: shopId,
shopName: shopName,
shopHome: `/?shopId=${shopId}`,
shopIntro: `/shop${shopId}-about`
});
// 店铺装修
if (result.decorator.code === 200) {
let data = result.decorator.data || {},
decorator = shopHandler.getShopDecorator(data, {}, shopId, true);
Object.assign(resData.brand.shopBanner, decorator.shopTopBannerBase || {});
// 设置店招高度
_.set(resData, 'brand.shopBanner.bannerHeight', 150);
if (decorator.signboard) {
_.set(resData, 'brand.signboard', decorator.signboard);
}
}
// 获取左侧类目数据
if (result.sort.code === 200) {
let dps = {shopId: shopId};
_.forEach(needParams, value => {
if (params[value]) {
dps[value] = params[value];
}
});
Object.assign(resData.brand, {
leftContent: searchHandler.handleSortData(result.sort.data, dps, params)
});
}
// 获取商品数据和顶部筛选条件
if (result.product.code === 200) {
let data = result.product.data;
let filters = Object.assign(searchHandler.handleFilterDataAll(data, params),
resData.brand.leftContent.sort);
filters.checkedConditions.conditions = _.concat(filters.checkedConditions.conditions,
resData.brand.leftContent.checked);
Object.assign(resData.brand, {
filters: filters,
opts: searchHandler.handleOptsData(params, data.total, data.filter),
totalCount: data.total,
footPager: searchHandler.handlePagerData(data.total, params),
goods: productProcess.processProductList(data.product_list,
Object.assign({showDiscount: false, from: {type: 'shop', params: params}}, params)),
hasNextPage: searchHandler.handleNextPage(params, data.total),
// 最近浏览记录
latestWalk: 7
});
// 店铺页不显示品牌筛选项
_.unset(resData, 'brand.filters.brand');
}
// 店铺优惠券
if (result.coupons && !_.isEmpty(result.coupons.data)) {
_.set(resData, 'brand.coupon',
searchHandler.handleBrandShopCoupons(result.coupons.data, {shopId: shopId}));
}
return resData;
}).bind(this)();
}
function getShopInfoAsync(domain, channel, params) {
let resData;
let shopId = _.get(params, 'shopId');
return co(function* () {
let data, shopInfo;
_.unset(params, 'domain');
domain = _.toLower(domain);
if (shopId) { // 带id访问
let result = yield this.api.getShopInfo(shopId);
data = result.data;
// 根据店铺ID,未取到店铺信息,跳转至首页
if (result.code !== 200 || _.isEmpty(data)) {
return {redirect: helpers.urlFormat('')};
}
let lowResDomain = _.toLower(data.shop_domain);
// 根据店铺ID取到的店铺domain与链接中domain不一致,跳转至店铺域名下(解决店铺域名与品牌域名混用的问题)
if (lowResDomain !== domain) {
return {redirect: helpers.urlFormat('', params, lowResDomain)};
}
shopInfo = data;
} else { // 以店铺域名方式直接访问
let result = yield this.searchApi.getBrandData({domain: domain});
data = result.data;
// 未取到domain信息,跳转至首页
if (result.code !== 200) {
return {redirect: helpers.urlFormat('')};
}
// domain类型不为店铺,跳转至搜索
if (data.type * 1 !== 2) {
let d = {query: domain};
if (data.id) {
d.brand = data.id;
}
return {redirect: helpers.urlFormat('', d, 'search')};
}
params.shopId = data.shop_id;
}
if (+data.shop_template_type === 2) { // 经典店铺
resData = yield this._getShopData(channel, params, shopInfo);
} else {
resData = yield this._getBaseShopData(channel, params, shopInfo);
}
return Object.assign(resData, {templateType: +data.shop_template_type});
}).bind(this)();
}
function getShopListInfoAsync(channel, params) {
let gender = _getGender(channel),
shopId = params.shopId,
navBar = params.navBar || 1;
let searchParams = searchHandler.getSearchParams(params);
return co(function* () {
let result = yield Promise.props({
header: headerModel.requestHeaderData(channel), // 头部数据
shopInfo: this.api.getShopInfo(shopId), // 店铺介绍
decorator: this.searchApi.getShopDecorator(shopId), // 店铺装修数据
sort: this.searchApi.getSortList({shop_id: shopId}),
product: this.searchApi.getProductList(Object.assign(searchParams,
{shop_id: shopId}), 'shop'), // 搜索店铺商品
// 如果有店内搜索,则并行查询店铺所有商品,搜索不到商品则显示所有商品
allProduct: params.query ? this.searchApi.getProductList(Object.assign(searchParams,
{shop_id: shopId, query: ''}), 'shop') : Promise.resolve({})
});
let resData = {headerData: Object.assign(result.header.headerData, {header: true})};
Object.assign(resData, searchHandler.handlePathNavData({}, params, 'shop', channel));
// 店铺装修
if (result.decorator.code === 200) {
Object.assign(resData, shopHandler.getShopDecorator(result.decorator.data, params, shopId));
// 设置shop nav选中状态
_.set(resData, `navigationBar[${navBar}].current`, true);
if (result.shopInfo.code === 200) {
let data = _.get(result, 'shopInfo.data', {});
_.set(resData, 'shopTopBanner.brandIntro', {
shopId: shopId,
brandName: data.shop_name || '',
brandCont: data.shop_intro || ''
});
// 店铺SEO
Object.assign(resData, searchHandler.getBrandShopSeo(channel, {
shopName: data.shop_name
}, params));
}
} else {
return Promise.reject('No ShopDecorator data');
}
// 获取商品数据和顶部筛选条件
if (result.product.code === 200) {
let info = result.product;
let goodsList = _.get(info, 'data.product_list', []);
if (goodsList.length) {
let totalPage = _.get(info, 'data.total', 1);
Object.assign(resData, {
filters: searchHandler.handleFilterDataAll(info.data, params),
opts: searchHandler.handleOptsData(params, totalPage),
goods: productProcess.processProductList(goodsList, {
newCoverSort: true,
showDiscount: false,
gender: _getGender(channel),
query: params.query
}),
hasNextPage: searchHandler.handleNextPage(params, totalPage),
footPager: searchHandler.handlePagerData(totalPage, params)
});
_.set(resData, 'filters.checkedConditions.clearUrl',
`?navBar=${params.navBar}&shopId=${params.shopId}`);
} else {
resData.searchEmpty = true;
let data = _.get(result, 'allProduct.data.total', 0);
let plist = _.get(data, 'product_list', []);
if (params.query && plist.length) {
resData.allGoods = {
name: '全部商品 ALL',
sort: searchHandler.handleOptsData(params, data.total || 0),
list: productProcess.processProductList(plist, {
newCoverSort: true,
showDiscount: false,
gender: gender
})
};
_.set(resData.allGoods, 'sort.newPage', true); // 启用新的分页导航
}
}
}
if (result.sort.code === 200) {
let groupSort = _.get(result.sort, 'data', []),
noPageQs = Object.assign({}, params, {page: 1});
resData.leftContent = searchHandler.handleSortData(groupSort, noPageQs, params);
_.set(resData, 'brandShopAd', {baseUrl: shopListUrl});
if (resData.allGoods) {
Object.assign(resData.allGoods, searchHandler.setShopSort(groupSort, noPageQs));
}
}
resData.criteo = {skn: searchHandler.getCriteo(_.get(resData, 'goods'))};
return resData;
}).bind(this)();
}
function getShopGoodsData(shopId, channel, params) {
let gender = _getGender(channel);
let resData = {};
_.unset(params, '_pjax');
return Promise.all([
this.searchApi.getProductList(Object.assign({shop_id: shopId}, params), 'shop'), // 搜索店铺商品
this.searchApi.getSortList({shop_id: shopId}) // 根据店铺id获取分类
]).then(result => {
// 获取商品数据和顶部筛选条件
if (result[0].code === 200) {
Object.assign(resData, {
sort: searchHandler.handleOptsData(params, _.get(result[0], 'data.total', 0)),
list: productProcess.processProductList(_.get(result[0], 'data.product_list', []), {
newCoverSort: true,
showDiscount: false,
gender: gender
})
});
_.set(resData, 'sort.newPage', true); // 启用新的分页导航
}
if (result[1].code === 200) {
let groupSort = _.get(result[1], 'data', []);
Object.assign(resData, searchHandler.setShopSort(groupSort, Object.assign({}, params,
{page: 1})), searchHandler.setGenderFilter(params));
}
return resData;
});
}
module.exports = class extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
this.api = new Api(ctx);
this.searchApi = new SearchApi(ctx);
this._getShopData = _getShopData.bind(this);
this._getBaseShopData = _getBaseShopData.bind(this);
this.getShopInfoAsync = getShopInfoAsync.bind(this);
this.getShopListInfoAsync = getShopListInfoAsync.bind(this);
this.getShopGoodsData = getShopGoodsData.bind(this);
}
getShopBannerAsync(shopId) {
... ... @@ -27,7 +543,7 @@ module.exports = class extends global.yoho.BaseModel {
}
queryShopByBrandIdAsync(sid, bid) {
return co(function * () {
return co(function* () {
let result = yield this.api.queryShopsByBrandId(sid, bid);
if (_.get(result, 'code') !== 200) {
... ... @@ -37,4 +553,42 @@ module.exports = class extends global.yoho.BaseModel {
return _.get(result, 'data[0]', {});
}).bind(this)();
}
getShopArticleByBrandsAsync(brands) {
let resData = {};
brands = _.split(brands, ',');
if (!brands.length) {
return Promise.resolve(resData);
}
return Promise.all(brands.map(value => this.searchApi.getArticleByBrand(value))).then(result => {
let articleList = [];
for (let i = 0; i < result.length; i++) {
articleList = _.concat(articleList, _.get(result[i], 'data', []));
}
if (articleList.length >= 3) {
articleList.length = 3;
resData.trendInfo = {
name: '潮流资讯 HOT ITEMS',
trendList: articleList.map(value => {
return {
href: helpers.urlFormat(`/guang/${value.id}.html`, null),
src: helpers.getForceSourceUrl(value.src) +
'?imageView2/1/w/{width}/h/{height}',
mainTitle: value.title,
Subtitle: value.intro
};
})
};
}
return resData;
});
}
};
... ...
... ... @@ -48,6 +48,9 @@ const newArrive = require(`${cRoot}/newArrive`);
// 全球购controller
const globalCtrl = require(`${cRoot}/global`);
// 店铺controller
const shop = require(`${cRoot}/shop`);
// 商品促销routers
router.get('/sale', sale.index); // sale 首页
router.get(/\/(.*)-sale/, sale.index); // sale 首页(SEO改造)
... ... @@ -114,12 +117,13 @@ router.get('/list/new', list.new);
router.get(/\/list\/(.*)-new/, list.newWithChannel);
// 品牌店铺
router.get('/index/brand', list.brand); // 品牌店铺页
router.get('/index/about', list.brandAbout); // 品牌店铺介绍页
router.post('/index/isFavoriteBrand', list.isFavoriteBrand); // 判断用户是否收藏品牌
router.post('/index/getNodeContent', list.getNodeContent); // 品牌页水牌
router.post('/index/getAdnav', list.getAdnav); // 品牌页系列
router.get('/shoplist', list.shopList); // 店铺列表页
router.get('/shop', shop.index); // 店铺首页
router.get('/shoplist', shop.list); // 店铺列表页
router.get('/shop/article', shop.article); // 店铺推荐文章
router.post('/shop/togglecollect', favorite.collectShop); // 店铺收藏
router.post('/index/isFavoriteShop', favorite.isFavShop); // 判断用户是否收藏品牌
router.get('/brand/couponsync', list.brandCouponSync);
... ...
... ... @@ -14,6 +14,7 @@
data-limitcode="{{goodsInfo.limitProductCode}}"
data-deposit ="{{goodsInfo.deposit}}"
data-secKill ="{{goodsInfo.secKill}}"
data-limittime ="{{goodsInfo.limitTime}}"
data-count="{{goodsInfo.bundle.count}}"
data-type="{{goodsInfo.bundle.type}}"
data-shop="{{goodsInfo.shopId}}">
... ...
{{# trendInfo}}
<div class="trend-info clearfix">
{{> common/floor-header}}
<ul class="trend-list">
{{#each trendList}}
<li>
<a href="{{href}}">
<img src="{{image2 src w=264 h=173}}" />
<div class="main-title">{{mainTitle}}</div>
<div class="sub-title">{{Subtitle}}</div>
</a>
</li>
{{/each}}
</ul>
</div>
{{/ trendInfo}}
... ...
... ... @@ -6,7 +6,7 @@
<div class="list-left pull-left">
{{> list/shop-search}}
{{> product/left-content}}
{{> list/shop-sidebar}}
... ... @@ -54,23 +54,9 @@
{{> list/shop-all-goods}}
{{#trendInfo}}
<div class="trend-info clearfix">
{{> common/floor-header}}
<ul class="trend-list">
{{#each trendList}}
<li>
<a href="{{href}}">
<img src="{{image2 src w=264 h=173}}" />
<div class="main-title">{{mainTitle}}</div>
<div class="sub-title">{{Subtitle}}</div>
</a>
</li>
{{/each}}
</ul>
</div>
{{/trendInfo}}
{{# trendInfo}}
<div class="trend-info" data-brands="{{shopBrands}}"></div>
{{/ trendInfo}}
</div>
</div>
</div>
... ...
... ... @@ -78,6 +78,54 @@ module.exports = [
target: (req, match, p1) => `/product/search/keyword/${p1}`
},
// TODO
// {
// type: TYPE.redirect,
// origin: /^\/so\/(.*)\.html(.*)/,
// target: (req, match, p1) => {
// let urls = {
// '4175746F426F74E6898BE69CBAE9858DE4BBB6E794B7': 57517,
// E6BBA1E58DB0E4BABAE5AD97E68B96: 11877,
// E6BDAEE6ACBEE5A4AAE79CBCE9959C: 43319,
// E6B3A2E782B9E995BFE8A296E8A1ACE8A1A3: 5709,
// E688B7E5A496E58C85E9858D: 27481,
// E993B6E98791E889B2: 12279,
// E697B6E5B09AE68ABDE7BBB3E79FADE8A3A4: 84593,
// '4C554E414C494D49544544E99288E7BB87E5A5B3': 36255,
// '4B4F594F': 10297,
// E99288E7BB87E8A5BFE8A385: 72093,
// E8838CE5BF83E995BFE8A399: 81419,
// E9929FE8A1A8E5A5B3: 71361,
// '424142414D41E79AAEE5B8A6': 47883,
// E5BEBDE7ABA0E58DABE8A1A3: 75023,
// E9BB91E799BDE6A0BC: 20095,
// E7949CE7BE8EE7BAAFE889B2E79FADE8A3A4: 10309,
// E58DB0E88AB1E995BFE6ACBEE7BEBDE7BB92E69C8D: 62085,
// E68B89E993BEE5BC80E8A59F: 43223,
// E7BBBFE889B2E7AE80E7BAA6E4BC91E997B2E8A3A4: 7781,
// E79CBCE5BDB1E5A5B3: 39279,
// E7BAAFE889B2E6A392E79083E5B8BD: 2021,
// E5A191E69699E590B8E7AEA1E69DAF: 1956427,
// E59BB4E5859C20E794B7: 71493,
// E59BB4E5859C20E5A5B3: 65257,
// E68BBCE889B2E6898BE993BE: 48821,
// '5452494E49544573747564696FE8A1ACE8A1AB': 53871,
// E799BDE889B2E9A490E585B7: 36291,
// E8939DE889B2E79CBCE9959C: 6287,
// E7AB96E69DA1E7BAB9E8BF9EE8A1A3E8A399: 40513,
// E7899BE4BB94E8939DE794B7E5A3ABE995BFE8A3A4: 2297,
// E58DB0E88AB1E4BC91E997B2E5A4B9E5858B: 26725,
// E8BF90E58AA8E8939DE78999E880B3E69CBA: 46837,
// E7BAAFE889B2E6B299E6BBA9E8A3A4: 8709,
// E7BAAFE889B2E8B4B4E6A087: 28027
// };
//
// return urls[p1] ?
// helpers.urlFormat(`/chanpin/${urls[p1]}.html`, null, 'www') :
// helpers.urlFormat('/', null, 'www');
// }
// },
// 推荐词id列表页
{
type: TYPE.rewrite,
... ...
... ... @@ -59,6 +59,8 @@ module.exports = () => {
}
} else if (proRegNew.test(url)) {
data.mobileRefer = url.replace(proRegNew, `//${domain}/product/pro_$1_1/1.html$2`);
} else {
data.mobileRefer = `//${domain}${req.originalUrl}`;
}
if (!_.isEmpty(req.query) && !qsReg.test(data.mobileRefer)) {
... ...
... ... @@ -23,7 +23,7 @@ try {
}
return client.multi.call(client, args).execAsync().timeout(timeout).catch(()=>{
logger.err('redis exe time out');
logger.error('redis exe time out');
return false;
});
};
... ...
... ... @@ -4,8 +4,6 @@
* @date: 2016/6/16
*/
'use strict';
const _ = require('lodash');
const qs = require('querystring');
module.exports = () => {
return (req, res, next) => {
... ... @@ -67,21 +65,12 @@ module.exports = () => {
}
break;
}
default: // 其它(识别为品牌)
default: // 其它(识别为店铺)
{ // eslint-disable-line
let queryString = (function() {
if (!_.isEmpty(req.query)) {
return '&' + qs.stringify(req.query);
} else {
return '';
}
}());
req.query.domain = req.subdomains[0];
if (!req.path || req.path === '/') {
req.url = `/product/index/brand?domain=${req.subdomains[0]}${queryString}`;
} else if (req.path === '/about') {
req.url = `/product/index/brand?domain=${req.subdomains[0]}${queryString}`;
req.url = '/product/shop';
}
break;
}
... ...
... ... @@ -11,6 +11,11 @@
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta content="telephone=no" name="format-detection" />
<meta content="email=no" name="format-detection" />
<meta name="applicable-device"content="pc">
{{#if mobileRefer}}
<link rel="alternate" media="only screen and(max-width: 640px)" href="{{mobileRefer}}">
<meta name="mobile-agent" content="format=html5;url={{mobileRefer}}">
{{/if}}
{{#dnsPrefetch.hosts}}
<link rel="dns-prefetch" href="{{this}}">
{{/dnsPrefetch.hosts}}
... ...
{
"name": "yohobuy-node",
"version": "5.9.12",
"version": "6.0.1",
"private": true,
"description": "A New Yohobuy Project With Express",
"repository": {
... ...
... ... @@ -370,7 +370,7 @@ deliveryWay = {
dt = this.deliveryType[id];
if (support) {
if (support && !dt.unsupport) {
dt.dom.parent().removeClass('unsp-way');
dt.unsupport = false;
} else {
... ...
... ... @@ -23,4 +23,9 @@ if ($('.success-box').length > 0) {
$(function() {
yas.givePoint('YB_REGISTER_SUCCESS_L');
// 品众统计
if (window._fxcmd) {
window._fxcmd.push(['trackOrder', 'event', 'reg', '注册', '1']);
}
});
... ...
... ... @@ -35,6 +35,7 @@ var $main = $('.main'),
skn = $main.data('skn'),
deposit = $main.data('deposit') === 'Y',
secKill = $main.data('seckill') === 'Y',
limitTime = $main.data('limittime') === 'Y',
limitCode = $main.data('limitcode'),
isBundleProduct = $main.data('type') === 2, // 量贩商品,
isPackageProduct = $main.data('type') === 1, // 套餐商品
... ... @@ -159,14 +160,16 @@ function addCart() {
}
} else if (code === 500) {
if (deposit) {
if (deposit || limitTime) {
alert = new Alert('定金预售商品只能在APP端购买');
alert.show();
return;
}
if (secKill) {
alert = new Alert('秒杀商品只能在APP端购买');
alert.show();
return;
}
}
... ...
... ... @@ -193,13 +193,27 @@ $(window).on('scroll', function() {
if (scrollTop > fixedAreaTop) {
$fixedArea.css({
position: 'fixed',
top: 0
position: 'fixed'
});
} else {
$fixedArea.css({
position: 'static',
top: 0
position: 'absolute'
});
}
});
// 获取店铺推荐文章
(function() {
var $trendInfo = $('.trend-info');
var brands = $trendInfo.data('brands');
if (brands) {
$.ajax({
type: 'GET',
url: '/product/shop/article',
data: {brands: brands}
}).then(function(data) {
$trendInfo.replaceWith(data);
});
}
}());
... ...
... ... @@ -406,6 +406,8 @@
background: #fff;
z-index: 1;
width: 970px;
position: absolute;
top: 0;
}
.gender-filter {
... ... @@ -540,6 +542,9 @@
}
.goods-wrap {
padding-top: 156px;
position: relative;
.goods-container {
.good-info {
width: 235px;
... ...