Authored by yyq

Merge branch 'feature/newGolbal' into release/5.6

... ... @@ -71,8 +71,6 @@ app.use(global.yoho.hbs({
helpers: Object.assign(global.yoho.helpers, require('./utils/helpers'))
}));
app.use(global.yoho.middleware());
app.use(favicon(path.join(__dirname, '/favicon.ico')));
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.json());
... ...
... ... @@ -24,7 +24,7 @@ const getBrandTopData = (contentCode) => {
* @param int $channel 频道标识 1:男,2:女,3:潮童,4:创意生活
*/
const getBrandListData = channel => {
let params = {method: 'app.brand.brandlist'};
let params = {method: 'app.brand.allBrandList'};
if (!isNaN(channel)) {
params.yh_channel = channel;
... ...
... ... @@ -31,6 +31,8 @@ const GIRLS = 'girls';
const KIDS = 'kids';
const LIFESTYLE = 'lifestyle';
const GLOBAL_BASE_URI = '/product/global/list';
/**
* 获取品牌一览资源位&channelType
*
... ... @@ -167,13 +169,14 @@ const getBrandViewList = (channel, start, length) => {
}
// 品牌list A-Z 0-9
if (res.data && res.data.brands) {
if (res.data && res.data.all_list) {
_.forEach(res.data.brands, (subValue, key) => {
_.forEach(res.data.all_list, (subValue, key) => {
let listTmp = [];
_.forEach(subValue, ssubValue => {
let extQs = {};
let baseUri = '';
// 为品牌名称
let href;
... ... @@ -183,22 +186,35 @@ const getBrandViewList = (channel, start, length) => {
} else if (switchParams.channelType === 2) {
Object.assign(extQs, {gender: '2,3'});
}
let shopInfo, shopId;
switch (ssubValue.type * 1) {
case 1:
extQs = {query: ssubValue.brand_domain};
extQs = {
query: ssubValue.brand_domain,
brand: ssubValue.id
};
ssubValue.brand_domain = 'search';
break;
case 2:
if (ssubValue.shop_id) {
Object.assign(extQs, {shopId: ssubValue.shop_id});
shopInfo = _.get(ssubValue, 'shop_info.yoho_shop_list[0]', {});
shopId = shopInfo.shop_id || ssubValue.shop_id;
ssubValue.brand_domain = shopInfo.shop_domain || ssubValue.brand_domain;
if (shopId) {
Object.assign(extQs, {shopId: shopId});
}
break;
case 3:
Object.assign(extQs, {brand: ssubValue.global_brand_id});
ssubValue.brand_domain = '';
baseUri = GLOBAL_BASE_URI;
break;
default:
break;
}
href = helpers.urlFormat('', extQs, ssubValue.brand_domain);
href = helpers.urlFormat(baseUri, extQs, ssubValue.brand_domain);
let brandItem = {
name: ssubValue.brand_name,
... ...
/**
* 商品促销controller
* @author: yyq<yanqing.yang@yoho.cn>
* @date: 2017/4/6
*/
'use strict';
const mRoot = '../models';
const globalModel = require(`${mRoot}/global`); // global model
/**
* 全球购列表页
* @param {[type]} req [description]
* @param {[type]} res [description]
* @return {[type]} [description]
*/
exports.list = (req, res, next) => {
globalModel.getGlobalProductListData(req.query, req.yoho).then(result => {
res.render('list/index', Object.assign({
page: 'list',
pageClass: 'global-list-page'
}, result));
}).catch(next);
};
/**
* 全球购商品详情页
* @param {[type]} req [description]
* @param {[type]} res [description]
* @return {[type]} [description]
*/
exports.detail = (req, res, next) => {
globalModel.getGlobalProductDetailData(req.params[0], req.yoho.channelNum,
req.yoho.channel).then(result => {
res.render('global/detail', Object.assign({
page: 'detail'
}, result));
}).catch(next);
};
... ...
... ... @@ -174,7 +174,6 @@ exports.newWithChannel = (req, res, next) => {
exports.brand = (req, res, next) => {
let brandDomain = req.query.domain;
let shopId = req.query.shopId;
let resData = {};
// shopId存在,直接走店铺
if (shopId) {
... ... @@ -198,13 +197,11 @@ exports.brand = (req, res, next) => {
case 2: // 店铺
return shop(brandInfo.shopId, req, res, next, brandInfo);
default: // 品牌
return list.getBrandData(req.query, Object.assign({uid: req.user.uid}, brandInfo),
req.yoho.channel).then(result => {
Object.assign(resData, result, {
page: 'list'
});
res.render('list/brand', resData);
});
res.redirect(helpers.urlFormat('', {
query: brandInfo.brandDomain,
brand: brandInfo.brandId
}, 'search'));
break;
}
}).catch(next);
};
... ...
/**
* 全球购API
* @author: yyq<yanqing.yang@yoho.cn>
* @date: 2017/4/6
*/
'use strict';
const globalApi = global.yoho.GlobalAPI;
const config = global.yoho.config;
const getGlobalProductListAsync = (params, from) => {
let finalParams = {
limit: 60
};
Object.assign(finalParams, params);
if (from) {
finalParams.fromPage = from;
}
return globalApi.get('product/api/v2/detail/getlist', finalParams, config.apiCache);
};
const getGlobalProductDetailAsync = (skn, channelNum) => {
return globalApi.get('product/api/v2/detail/get', {
physical_channel: channelNum,
product_skn: skn,
client_type: 'iphone'
}, config.apiCache);
};
const getGlobalProductHtmlAsync = (skn, channelNum) => {
return globalApi.get('product/api/v1/detail/gethtml', {
physical_channel: channelNum,
product_skn: skn,
return_type: 'html',
client_type: 'iphone'
}, config.apiCache);
};
module.exports = {
getGlobalProductListAsync,
getGlobalProductDetailAsync,
getGlobalProductHtmlAsync
};
... ...
/**
* 商品促销 model
* @author: yyq<yanqing.yang@yoho.cn>
* @date: 2017/4/6
*/
'use strict';
const _ = require('lodash');
const helpers = global.yoho.helpers;
const homeService = require('./home-service');
const globalApi = require('./global-api');
const headerModel = require('../../../doraemon/models/header');
const searchHandler = require('./search-handler');
const pager = require(`${global.utils}/pager`).setPager;
const productProcess = require(`${global.utils}/product-process`);
const GLOBAL_LIST_URI = '/product/global/list';
const _handelGlobalPathNav = (data, channel, page) => {
let rootName = '首页';
if (channel && _.isString(channel)) {
rootName = `${channel.toUpperCase()}首页`;
}
let pathNav = [{
href: channel === 'boys' ? '/' : helpers.urlFormat(`/${channel}/`),
name: rootName,
pathTitle: rootName
}, {
href: helpers.urlFormat(GLOBAL_LIST_URI),
name: '全球购',
pathTitle: '全球购'
}];
if (data.sort) {
pathNav.push({
href: helpers.urlFormat(GLOBAL_LIST_URI, data.sort.params),
name: data.sort.name,
pathTitle: data.sort.name
});
}
if (data.brand) {
pathNav.push({
name: data.brand.name,
pathTitle: data.brand.name
});
page = 'global-brand';
}
return {
pathNav: pathNav,
listType: page
};
};
const _checkSortEqual = (rp, params) => {
let status = true;
_.forEach(rp, (value, key) => {
if (status && params[key] !== value) {
status = false;
}
});
return status;
};
const _handelGlobalSort = (origin, params, originParams) => {
let all = [{
name: '全部品类',
href: `${searchHandler.handleFilterUrl(params, {}, {msort: true, misort: true, sort: true})}`
}];
let list = [];
let selectSort = {};
_.forEach(origin, value => {
let equalCategory = _checkSortEqual(value.relation_parameter, originParams);
let category = {
name: value.category_name,
num: value.node_count,
childList: [
{
name: `全部${value.category_name}`,
num: value.node_count,
href: `${searchHandler.handleFilterUrl(params, value.relation_parameter)}`,
childActive: _checkSortEqual(value.relation_parameter, originParams)
}
]
};
if (equalCategory) {
Object.assign(selectSort, {
name: value.category_name,
params: value.relation_parameter
});
}
_.forEach(value.sub, subValue => {
let child = {
name: subValue.category_name,
num: subValue.node_count,
href: `${searchHandler.handleFilterUrl(params, subValue.relation_parameter)}`,
childActive: _checkSortEqual(subValue.relation_parameter, originParams)
};
category.childList.push(child);
if (child.childActive) {
category.active = true;
Object.assign(selectSort, {
name: subValue.category_name,
params: subValue.relation_parameter
});
}
});
list.push(category);
});
return {
allSort: {
all: all,
list: list
},
selectSort: selectSort
};
};
const getGlobalProductListData = (params, yoho) => {
let dps = {};
if (params.brand) {
dps.brand = params.brand;
}
return Promise.props({
header: headerModel.requestHeaderData(yoho.channel),
fullList: globalApi.getGlobalProductListAsync({
physical_channel: yoho.channelNum,
limit: 1
}),
list: globalApi.getGlobalProductListAsync(Object.assign({
physical_channel: yoho.channelNum
}, params, {limit: params.limit ? params.limit - 1 : 59}))
}).then(result => {
let resData = {};
Object.assign(resData, result.header);
if (result.list.code === 200) {
let listData = _.get(result.list, 'data', {});
let totalNum = _.get(listData, 'total', 0);
// opts 显示新品、折扣
listData.filter = listData.filter || {};
Object.assign(listData.filter, {
new: 'Y',
specialoffer: 'Y'
});
resData.list = {
leftContent: _handelGlobalSort(_.get(result.fullList, 'data.filter.group_sort', []), dps, params),
filters: searchHandler.handleFilterDataAll(listData, params),
opts: searchHandler.handleOptsData(params, totalNum, listData.filter),
totalCount: totalNum,
footPager: pager(_.get(listData, 'page_total', 0), params),
goods: productProcess.processProductList(_.get(listData, 'product_list', []),
Object.assign({showDiscount: false, isGlobal: true}, params)),
hasNextPage: searchHandler.handleNextPage(params, totalNum),
latestWalk: 6 // 最近浏览记录
};
if (resData.list.filters && resData.list.filters.brand) {
_.set(resData.list, 'filters.brand.showAllBrands', true); // 设置首次展示品牌筛选所有品牌
}
// pathNav brand
let pathInfo = {};
if (dps.brand) {
let bandInfo = _.find(_.get(result.fullList, 'data.filter.brand', []), o => {
return o.id * 1 === dps.brand * 1;
});
if (bandInfo) {
pathInfo.brand = {
name: bandInfo.brand_name
};
}
}
// psthNav sort
let selectedSort = _.get(resData.list, 'leftContent.selectSort', {});
if (!_.isEmpty(selectedSort)) {
pathInfo.sort = selectedSort;
}
Object.assign(resData.list, _handelGlobalPathNav(pathInfo, yoho.channel, 'global-list'));
}
return resData;
});
};
const getGlobalProductDetailData = (skn, channelNum, channel) => {
return Promise.props({
header: headerModel.requestHeaderData(channel),
detail: globalApi.getGlobalProductDetailAsync(skn, channelNum),
html: globalApi.getGlobalProductHtmlAsync(skn, channelNum)
}).then(result => {
let resData = {};
let detailInfo, html = '';
if (+result.detail.code === 200) {
detailInfo = _.get(result, 'detail.data', {});
let brandInfo = detailInfo.brand_info || {};
resData.banner = {
bgColor: '#000',
homeUrl: helpers.urlFormat(GLOBAL_LIST_URI, {brand: brandInfo.brand_id}),
brandName: brandInfo.brand_name,
logo: brandInfo.brand_ico
};
resData.pathNav = _.concat(
homeService.getHomeChannelNav(channel),
[
{name: '全球购', href: helpers.urlFormat(GLOBAL_LIST_URI)},
{name: detailInfo.product_name || ''}
]
);
if (detailInfo.orign_price - detailInfo.final_price === 0) {
_.unset(detailInfo, 'formart_orign_price');
} else {
detailInfo.promotion = ((detailInfo.final_price / detailInfo.orign_price) * 10).toFixed(1);
// 只显示大于1折小于9折的折扣
if (detailInfo.promotion <= 1.0 || detailInfo.promotion >= 9.0) {
detailInfo.promotion = false;
}
}
if (detailInfo.market_price - detailInfo.sales_price === 0) {
_.unset(detailInfo, 'format_market_price');
}
if (!_.isEmpty(detailInfo.goods_list)) {
let colors = [];
_.forEach(detailInfo.goods_list, (value, index) => {
let size = [];
_.forEach(value.size_list || [], subVal => {
size.push({
sku: subVal.product_sku,
name: subVal.size_name,
soldOut: subVal.storage_number * 1 <= 0
});
});
if (_.isEmpty(value.images_list)) {
value.images_list = [{
image_url: value.color_image
}];
}
if (index === 0 && !detailInfo.mainThumb) {
value.focus = true;
detailInfo.mainThumb = _.get(value, 'images_list[0].image_url', value.color_image);
}
colors.push({
src: value.color_image,
name: value.color_name,
title: value.color_name,
imgList: value.images_list,
focus: value.focus,
size: size
});
});
detailInfo.colors = colors;
}
}
if (result.html && !_.get(result.html, 'code', '')) {
let regContent = /<body[^>]*>([\s\S]*)<\/body>/.exec(result.html);
html = regContent[1] || '';
html = html.replace(/<script.*?>.*?<\/script>/ig, '');
}
Object.assign(resData, result.header, {
goodsInfo: detailInfo,
detailHtml: html || ''
});
return resData;
});
};
module.exports = {
getGlobalProductListData,
getGlobalProductDetailData
};
... ...
... ... @@ -26,6 +26,8 @@ const isFavoriteBrandUrl = '/shops/service/v1/favorite/getUidBrandFav';
// 根据品牌查询相关文章
const relateArticleUrl = 'guang/service/v2/article/getArticleByBrand';
const GLOBAL_BASE_URI = '/product/global/list';
// 缓存生效时间
const CACHE_TIME_S = 60;
... ... @@ -287,7 +289,7 @@ const getBrandCouponAsync = (brandId, uid) => {
*/
const getBrandShop = (query) => {
let finalParams = {
method: 'web.search.shopNewInfo'
method: 'web.search.shopListInfo'
};
return api.get('', Object.assign(finalParams, {keyword: query}), config.apiCache);
... ... @@ -302,32 +304,42 @@ const getShopList = params => {
}
return getBrandShop(params.query).then(shops => {
let shopEntry = {},
sort = _.get(shops, 'data.sortInfo.sort', {}),
shopInfo = _.get(shops, 'data.shopBrandInfo.shopInfo', {}) ||
_.get(shops, 'data.shopBrandInfo.brandInfo', {});
if (_.isEmpty(shopInfo)) {
return;
}
shopEntry = {
home: helpers.urlFormat('', '', shopInfo.shop_domain || shopInfo.brand_domain),
logo: shopInfo.shop_logo || shopInfo.brand_ico,
shopName: shopInfo.shop_name || shopInfo.brand_name,
sort: []
};
// 店铺/品牌的小分类
_.forEach(sort, (sortInfo) => {
_.forEach(_.get(sortInfo, 'sub', []), (subSort) => {
shopEntry.sort.push({
href: helpers.urlFormat('', {misort: subSort.sort_id},
shopInfo.shop_domain || shopInfo.brand_domain),
name: subSort.sort_name
let shopEntry = [];
_.forEach(_.get(shops, 'data.shopList', []), value => {
let shopInfo = {
home: helpers.urlFormat('', null, value.shop_domain || value.brand_domain),
logo: value.shop_logo || value.brand_ico,
shopName: value.shop_name || value.brand_name,
sort: []
};
if (value.is_global === 'Y') {
shopInfo.home = helpers.urlFormat(GLOBAL_BASE_URI, {brand: value.global_brand_id});
}
// 店铺/品牌的小分类
_.forEach(value.sort, sortInfo => {
_.forEach(_.get(sortInfo, 'sub', []), subSort => {
let sortHref;
if (value.is_global === 'Y') {
sortHref = helpers.urlFormat('', {misort: subSort.sort_id},
value.shop_domain || value.brand_domain);
} else {
sortHref = helpers.urlFormat(GLOBAL_BASE_URI, {
misort: subSort.sort_id,
brand: value.global_brand_id
});
}
shopInfo.sort.push({
href: sortHref,
name: subSort.sort_name
});
});
});
shopEntry.push(shopInfo);
});
return shopEntry;
... ...
... ... @@ -647,7 +647,9 @@ exports.handleFilterData = (origin, params, total) => {
}
};
dest.brand = formatterFilterBrands(origin.brand, origin.paramBrand, params);
if (origin.brand) {
dest.brand = formatterFilterBrands(origin.brand, origin.paramBrand, params);
}
// 处理价格筛选数据
let priceRangechecked = false;
... ... @@ -751,6 +753,8 @@ exports.handleFilterData = (origin, params, total) => {
// 处理颜色筛选数据
if (!_.isEmpty(origin.color)) {
_.forEach(origin.color, (value) => {
value.color_code = value.color_code.replace(/#/ig, '');
let color = {
checked: parseInt(params.color, 10) === parseInt(value.color_id, 10),
href: handleFilterUrl(params, {color: value.color_id}),
... ... @@ -817,7 +821,7 @@ exports.handleFilterData = (origin, params, total) => {
handleCheckedData(params, dest.gender, 'gender'));
// 处理品牌筛选数据
if (dest.brand.brandsShow) {
if (dest.brand && dest.brand.brandsShow) {
dest.checkedConditions.conditions = _.union(dest.checkedConditions.conditions,
handleBrandCheckedData(params, dest.brand.selectedBrands));
... ... @@ -1364,10 +1368,9 @@ exports.handleFilterUrl = handleFilterUrl;
exports.handleCheckedData = handleCheckedData;
exports.handleNextPage = (params, total) => {
let href;
let currentPage = parseInt((_.isEmpty(params.page) ? 1 : params.page), 10); // 当前页
let perPageCount = parseInt((_.isEmpty(params.limit) ? 60 : params.limit) - 1, 10); // 每页商品数
let currentPage = parseInt((params.page ? params.page : 1), 10); // 当前页
let perPageCount = parseInt((params.limit ? params.limit : 60) - 1, 10); // 每页商品数
let totalPage = _.ceil(total / perPageCount); // 总页数
if (currentPage >= totalPage) {
... ...
... ... @@ -44,6 +44,9 @@ const students = require(`${cRoot}/students`);
// 新品到着controller
const newArrive = require(`${cRoot}/newArrive`);
// 全球购controller
const globalCtrl = require(`${cRoot}/global`);
// 商品促销routers
router.get('/sale', sale.index); // sale 首页
router.get(/\/(.*)-sale/, sale.index); // sale 首页(SEO改造)
... ... @@ -83,6 +86,13 @@ router.get('/detail/notify/status', auth, notify.show); // 到è´
router.post('/detail/notify/add', auth, notify.add); // 增加到货通知
router.post('/detail/notify/cancel', auth, notify.cancel); // 删除到货通知
// 全球购routers
router.get('/global/list', globalCtrl.list); // 全球购列表页
router.get('/global/detail', globalCtrl.detail);
router.get(/\/global\/([\d]+)(.*)/, globalCtrl.detail);
// router.get(/\/global\/([\d]+)(.*)/, globalCtrl.detail); // 全球购商品详情页
// 搜索
router.get('/search/index', gbk2utf, search.index);
router.get('/search/filter/brands', search.searchFilterBrands);
... ...
<div class="global-detail-page product-detail-page yoho-page">
{{>product/brand-banner}}
<div class="center-content">
{{> common/path-nav}}
<div class="main clearfix">
{{# goodsInfo}}
<div class="pull-left imgs clearfix">
<div class="pull-left img">
<div class="tags clearfix">
<span class="good-tag global-tag">{{country_name}}</span>
</div>
<div id="min-img">
<img id="img-show" class="img-show" src="{{image2 mainThumb w=420 h=560}}">
<div class="magnifier move-object hide"></div>
<div class="magnifier move-over"></div>
<div id="max" class="magnifier max hide">
<img id='big' src="{{image2 mainThumb w=750 h=1000}}">
</div>
</div>
<div class="share-row">
<span class="title pull-left">分享:</span> {{> common/share }}
</div>
</div>
<div id="thumbs" class="pull-right thumbs">
{{# goods_list}}
<div class="thumb-wrap{{#unless focus}} hide{{/unless}}">
{{#if focus}}
{{# images_list}}
<img class="thumb {{#if @first}}active{{/if}}" src="{{image2 image_url w=75 h=100}}"
data-shower="{{image2 image_url w=420 h=560}}"
data-origin="{{image2 image_url w=750 h=1000}}">
{{/ images_list}}
{{^}}
{{# images_list}}
<img class="thumb lazy"
data-original="{{image2 image_url w=75 h=100}}"
data-shower="{{image2 image_url w=420 h=560}}"
data-origin="{{image2 image_url w=750 h=1000}}">
{{/ images_list}}
{{/if}}
</div>
{{/ goods_list}}
</div>
</div>
<div class="pull-right infos">
<h1 class="name">{{product_name}}</h1>
<div class="line"></div>
<p class="market-price">
{{# formart_orign_price}}
<span class="price-row">
<span class="title"><s></s>价:</span>
<span class="price has-other-price">{{.}}</span>
</span><br>
{{/ formart_orign_price}}
{{# formart_final_price}}
<span class="price-row">
<span class="title">当前价:</span>
<span class="price">{{.}}</span>
</span>
{{/ formart_final_price}}
{{#if promotion}}
<span class="desc">
<span class="promotion">{{promotion}}</span>
</span>
{{/if}}
</p>
<p class="foreign-price">
{{# format_market_price}}
<span class="title">原 价:</span>
<span class="price">{{.}}</span>
{{/ format_market_price}}
{{# format_sales_price}}
<span class="title">当前价:</span>
<span class="price">{{.}}</span>
{{/ format_sales_price}}
</p>
<div class="line"></div>
<div class="trade-content">
<div id="type-chose" class="type-chose">
{{> product/color-list}}
{{> product/size-list}}
<div class="chose-count row clearfix">
<span class="title pull-left">&nbsp;&nbsp;量:</span>
<div class="num-wraper pull-left clearfix">
{{> product/num}}
</div>
</div>
<div class="line"></div>
<span id="code-buy" class="code-buy" skn="{{product_skn}}">
<i class="iconfont">&#xe703;</i>
<em>扫一扫购买</em>
<div class="code-box">
<div id="qrcode-img" class="code-img" data-url='http://union.yoho.cn/union/app-downloads.html?openby:yohobuy={"action":"go.globalpurchase","params":{"skn":"{{product_skn}}"}}'></div>
</div>
</span>
</div>
</div>
<div class="extra-tip">
<a href="#">全球购物须知</a>
<ul class="global-buy-tips">
{{# illustrate_contents}}
<li>
{{title}} >
<div class="hover-tip">{{content}}</div>
</li>
{{/ illustrate_contents}}
</ul>
</div>
</div>
{{/ goodsInfo}}
</div>
<div class="global-detail-wrap">{{{detailHtml}}}</div>
</div>
</div>
... ...
<div class="product-page yoho-page product-list-page">
<div class="product-page yoho-page product-list-page {{pageClass}}">
{{#if hideInfo}}
<div id="page-hide-info"{{#each hideInfo}} data-{{@key}}="{{.}}"{{/each}}></div>
{{/if}}
... ...
... ... @@ -10,10 +10,12 @@
<a class="home" href="{{homeUrl}}" title="{{brandName}}">
<span class="iconfont">&#xe61a;</span>
</a>
<span id="brand-favour" class="brand-fav{{#if isCollect}} coled{{/if}}" data-id="{{brandId}}">
<i class="iconfont">&#xe641;</i>
<span class="fav-num"></span>
</span>
{{#if brandId}}
<span id="brand-favour" class="brand-fav{{#if isCollect}} coled{{/if}}" data-id="{{brandId}}">
<i class="iconfont">&#xe641;</i>
<span class="fav-num"></span>
</span>
{{/if}}
</div>
</div>
{{/if}}
... ...
... ... @@ -74,3 +74,4 @@
<span class="date">{{arrivalDate}}</span>
</div>
{{/if}}
</p>
... ...
... ... @@ -21,12 +21,14 @@ module.exports = {
api: 'http://api-test3.yohops.com:9999/',
service: 'http://service-test3.yohops.com:9999/',
serviceNotify: 'http://service-test3.yohops.com:9999/',
global: 'http://global-test-soa.yohops.com:9999/',
// prod
// singleApi: 'http://single.yoho.cn/',
// api: 'http://api.yoho.cn/',
// service: 'http://service.yoho.cn/',
// serviceNotify: 'http://service.yoho.cn/',
// global: 'http://api-global.yohobuy.com/',
// gray
// singleApi: 'http://single.gray.yohops.com/',
... ... @@ -139,6 +141,7 @@ if (isProduction) {
api: 'http://api.yoho.yohoops.org/',
service: 'http://service.yoho.yohoops.org/',
search: 'http://search.yohoops.org/yohosearch/',
global: 'http://api-global.yohobuy.com/product/',
serviceNotify: 'http://service.yoho.cn/',
imSocket: 'ws://imsocket.yohobuy.com:10000',
imCs: 'https://imhttp.yohobuy.com/api',
... ... @@ -170,6 +173,7 @@ if (isProduction) {
singleApi: process.env.TEST_API || 'http://192.168.102.31:8092/brower',
api: process.env.TEST_API || 'http://testapi.yoho.cn:28078/',
service: process.env.TEST_SERVICE || 'http://testservice.yoho.cn:28077/',
global: process.env.TEST_GOLBAL || 'http://global-test-soa.yohops.com:9999/',
search: process.env.TEST_SEARCH || 'http://192.168.102.216:8080/yohosearch/',
serviceNotify: process.env.TEST_SERVICE || 'http://testservice.yoho.cn:28077/',
imSocket: 'ws://socket.yohobuy.com:10240',
... ...
... ... @@ -6,7 +6,11 @@
{{#each pathNav}}
{{#if name}}
{{#if href}}
<a {{#if @last}}class="last"{{/if}} href="{{href}}" title="{{pathTitle}}">{{{name}}}</a>
{{#if @last}}
<span class="last" title="{{pathTitle}}">{{{name}}}</span>
{{^}}
<a href="{{href}}" title="{{pathTitle}}">{{{name}}}</a>
{{/if}}
{{^}}
<span {{#if @last}}class="last"{{/if}} title="{{pathTitle}}">{{{name}}}</span>
{{/if}}
... ...
... ... @@ -122,7 +122,11 @@
<span id="brand-multi" class="multi-select">多选 +</span>
{{/if}}
</div>
<div data-role="all-brand"></div>
<div data-role="all-brand">
{{#if showAllBrands}}
{{> product/filter-brands-sync}}
{{/if}}
</div>
</div>
</div>
{{/ brand}}
... ...
<div class="brand-panel hide">
<div class="panel-head clearfix">
<p class="brands-index">
{{#each brandIndex}}
<span data-index="{{index}}">{{name}}</span>
{{/each}}
</p>
<div class="brand-search">
<input id="brand-search-input" type="text">
<span class="btn">
<i class="iconfont">&#xe60f;</i>
</span>
</div>
</div>
<div class="panel-body">
<div class="ul-scroll">
<ul class="check-container clearfix">
{{# brandsShow}}
<li class="attr {{#if checked}}checked{{/if}}" data-index="{{index}}" data-key="{{key}}">
<a href="{{href}}">
<span class="iconfont checkbox {{#if checked}}checked{{/if}}" data-id="{{id}}">
{{#if checked}}
&#xe613;
{{else}}
&#xe612;
{{/if}}
</span>
<span title="{{name}}">{{name}}</span>
</a>
</li>
{{/ brandsShow}}
</ul>
</div>
</div>
<div class="btns">
<button id="brand-multi-ok" class="multi-select-ok dis">确定</button>
<button class="multi-select-cancel">取消</button>
</div>
</div>
... ...
... ... @@ -5,6 +5,9 @@
<span class="hide shelve-time">{{shelve_time}}</span>
<div class="tag-container clearfix">
{{# tags}}
{{#if is_global}}
<span class="good-tag global-tag">{{name}}</span>
{{/if}}
{{# is_new_festival}}
<span class="good-tag new-festival-tag">新品节</span>
{{/ is_new_festival}}
... ...
... ... @@ -49,7 +49,7 @@
"urlencode": "^1.1.0",
"uuid": "^2.0.2",
"yoho-express-session": "^2.0.0",
"yoho-node-lib": "0.2.11",
"yoho-node-lib": "0.2.14",
"yoho-zookeeper": "^1.0.8"
},
"devDependencies": {
... ...

7.35 KB | W: | H:

7.66 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin

1.96 KB | W: | H:

3.76 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
... ... @@ -162,7 +162,6 @@ if ($brandMore.length > 0) {
// 【品牌】加载更多品牌数据
function checkMoreBrands(callback) {
var squery = window.location.search;
// /product/search/filter/brands?callback=?
... ... @@ -170,6 +169,17 @@ function checkMoreBrands(callback) {
var brandsHtml;
var params = (location.search || '').substr(1);
// 直出brands list取消异步加载,目前只用于5.6全球购商品列表
if (!moreBrandLoaded && $filterBrands.find('.brand-panel').length) {
moreBrandLoaded = true;
// init brand vars
$brandInput = $filterBrands.find('#brand-search-input');
$brandPanel = $filterBrands.find('.brand-panel');
$brandAttrs = $brandPanel.find('.attr');
$brandsIndex = $('.brands-index');
}
if (squery && squery.length > 0) {
url += squery + '&callback=?';
} else {
... ...
... ... @@ -121,6 +121,21 @@
}
}
.global-tag {
background-color: #482d3d;
font-weight: 300;
&:before {
content: "";
width: 16px;
height: 14px;
margin-right: 2px;
background-image: url("/product/airplane-tag.png");
display: inline-block;
vertical-align: sub;
}
}
.new-tag {
background: #78dc7d;
}
... ...
... ... @@ -11,6 +11,7 @@
@import "outlets/index";
@import "shop-index";
@import "students/index";
@import "global/index";
@import "top-coupon";
@import "new-arrive";
@import "good-slide";
... ...
.global-detail-page {
.tags > .global-tag {
background-color: #482d3d;
font-weight: 300;
&:before {
content: "";
width: 16px;
height: 14px;
margin-right: 4px;
background-image: url("/product/airplane-tag.png");
display: inline-block;
vertical-align: sub;
}
}
.main .foreign-price {
> * {
color: #b0b0b0;
font-weight: 300;
}
.price {
font-size: 13px;
margin-right: 20px;
}
}
.extra-tip {
font-size: 13px;
> a {
color: #f00;
text-decoration: underline;
}
.global-buy-tips {
padding-top: 20px;
> li {
float: left;
margin-right: 60px;
cursor: default;
&:hover > .hover-tip {
display: block;
}
}
.hover-tip {
width: 220px;
line-height: 1.5;
padding: 10px;
color: #666;
font-size: 12px;
background-color: #fff;
border: 1px solid #ddd;
margin-top: 6px;
display: none;
position: absolute;
}
}
}
.global-detail-wrap {
padding: 30px 0;
}
.good-detail-page {
background-color: transparent;
position: relative;
width: 100%;
overflow: hidden;
border: 1px solid #e0e0e0;
box-sizing: border-box;
.good-sure {
text-align: center;
margin-top: 30px;
margin-bottom: 20px;
padding-top: 10px;
padding-bottom: 10px;
border: 1px #e0e0e0 solid;
img {
width: 517px;
max-width: 100%;
display: block;
border: 0;
margin: 0 auto;
}
}
.info {
margin-top: 39px;
margin-left: 175px;
margin-right: 175px;
color: #999;
border-top: 1px solid #e0e0e0;
font-size: 12px;
text-align: center;
h2 {
color: #444;
border: 1px solid #444;
padding: 7px 28px 6px;
text-align: center;
background-color: #fff;
display: inline-block;
font-size: 16px;
margin: 30px auto;
span {
display: none;
}
}
}
.description {
table {
background: #fff;
width: 100%;
border-collapse: collapse;
border-spacing: 0;
text-align: center;
margin: 0 auto 20px;
font-size: 14px;
color: #666;
}
td {
float: left;
width: 25%;
font-size: 14px;
line-height: 22px;
color: #444;
}
}
.table-wrap {
text-align: center;
margin: 0 auto 20px;
width: 100%;
font-size: 14px;
color: #666;
border: 1px solid #e0e0e0;
table {
width: 100%;
}
thead {
background-color: #f5f5f5;
color: #666;
font-size: 14px;
border-bottom: 1px solid #e0e0e0;
}
tr {
text-align: center;
height: 30px;
}
th,
td {
text-align: center;
}
tbody {
color: #222;
tr:nth-child(2n) {
background-color: rgb(249, 249, 249);
}
}
}
.details {
font-size: 14px;
line-height: 1.5;
table {
text-align: center;
margin: 0 auto 20px;
width: 100%;
font-size: 14px;
color: #666;
border: 1px solid #e0e0e0;
thead {
background-color: #f5f5f5;
color: #666;
font-size: 14px;
border-bottom: 1px solid #e0e0e0;
}
tbody {
color: #222;
}
tr {
text-align: center;
height: 30px;
}
th,
td {
text-align: center;
height: 30px;
}
tr:nth-child(2n) {
background-color: rgb(249, 249, 249);
}
& + p {
color: #999;
font-size: 14px;
line-height: 20px;
text-align: center;
margin-top: 20px;
margin-bottom: 30px;
}
}
img {
width: 100%;
}
}
.brand-intro {
p {
font-size: 14px;
color: #444;
display: inline-block;
margin-bottom: 0;
line-height: 25px;
}
img {
display: block;
width: 100%;
margin-bottom: 20px;
}
}
.service-info {
img {
width: 517px;
display: block;
margin: 0 auto 20px;
}
.service-prob {
display: block;
width: 100%;
margin-bottom: 10px;
line-height: 20px;
color: #000;
font-size: 14px;
text-align: left;
&:before {
display: inline-block;
content: "\e695";
line-height: 18px;
margin-right: 10px;
font-style: normal;
font-family: "iconfont";
font-size: 18px;
text-decoration: none;
-webkit-font-smoothing: antialiased;
-webkit-text-stroke-width: 0.2px;
}
}
.service-answer {
display: block;
float: left;
margin-top: 0;
margin-bottom: 30px;
line-height: 20px;
font-size: 14px;
font-family: initial;
text-align: justify;
&:before {
display: inline-block;
content: "\e696";
line-height: 18px;
margin-right: 10px;
font-style: normal;
font-family: "iconfont";
font-size: 18px;
text-decoration: none;
-webkit-font-smoothing: antialiased;
-webkit-text-stroke-width: 0.2px;
}
}
}
.service-operation,
.recommend-for-you {
display: none;
}
}
}
... ...
@import "detail";
.global-list-page {
.path-nav:after {
content: "";
width: 54px;
height: 20px;
margin-left: 6px;
display: inline-block;
background-image: url("/product/global-path-icon.png");
vertical-align: bottom;
}
}
... ...
... ... @@ -33,10 +33,11 @@ const joinUrl = (params) => {
*/
exports.setPager = (total, params)=>{
let resData = {};
let defParams = _.cloneDeep(params);
let cutStatus, // 切割状态 1:去头 2:去尾 3:双切
i;
let pages = [];
let currentPage = parseInt(params.page || 1, 10); // 当前页
let currentPage = parseInt(defParams.page || 1, 10); // 当前页
// 小于两页直接退出
if (total < 2) {
... ... @@ -55,7 +56,7 @@ exports.setPager = (total, params)=>{
}
pages.push({
url: joinUrl(Object.assign(params, {page: i})),
url: joinUrl(Object.assign(defParams, {page: i})),
num: i,
cur: currentPage === i
});
... ... @@ -74,7 +75,7 @@ exports.setPager = (total, params)=>{
}
list.push({
url: joinUrl(Object.assign(params, {page: p})),
url: joinUrl(Object.assign(defParams, {page: p})),
num: p
});
}
... ... @@ -88,7 +89,7 @@ exports.setPager = (total, params)=>{
}
list.push({
url: joinUrl(Object.assign(params, {page: p})),
url: joinUrl(Object.assign(defParams, {page: p})),
num: p
});
}
... ... @@ -102,12 +103,12 @@ exports.setPager = (total, params)=>{
if (fnum > 1) {
if (fnum > 2) {
pages = _.concat({
url: joinUrl(Object.assign(params, {page: 1})),
url: joinUrl(Object.assign(defParams, {page: 1})),
num: 1
}, {num: '...'}, pages);
} else {
pages = _.concat({
url: joinUrl(Object.assign(params, {page: 1})),
url: joinUrl(Object.assign(defParams, {page: 1})),
num: 1
}, pages);
}
... ... @@ -116,12 +117,12 @@ exports.setPager = (total, params)=>{
if (lnum < total) {
if (lnum < total - 1) {
pages = _.concat(pages, {num: '...'}, {
url: joinUrl(Object.assign(params, {page: total})),
url: joinUrl(Object.assign(defParams, {page: total})),
num: total
});
} else {
pages = _.concat(pages, {
url: joinUrl(Object.assign(params, {page: total})),
url: joinUrl(Object.assign(defParams, {page: total})),
num: total
});
}
... ... @@ -131,12 +132,12 @@ exports.setPager = (total, params)=>{
// 上一页
if (currentPage > 1) {
resData.prePage = {url: joinUrl(Object.assign(params, {page: currentPage - 1}))};
resData.prePage = {url: joinUrl(Object.assign(defParams, {page: currentPage - 1}))};
}
// 下一页
if (currentPage < total) {
resData.nextPage = {url: joinUrl(Object.assign(params, {page: currentPage + 1}))};
resData.nextPage = {url: joinUrl(Object.assign(defParams, {page: currentPage + 1}))};
}
return resData;
... ...
... ... @@ -102,10 +102,6 @@ const procProductImgs = (item, gender) => {
}
};
const procCnAlphabetName = (nameStr) => {
return nameStr.match(/\w/ig).join('');
};
/**
* 商品搜索商品数据处理
*/
... ... @@ -153,6 +149,18 @@ exports.processProductList = (list, options) => {
// }
_.forEach(list, (product) => {
// 全球购接口与普通接口返回商品差异属性预处理
if (options.isGlobal && product) {
Object.assign(product, {
goods_list: [{
images_url: product.default_images,
status: 1
}],
sales_price: product.orign_price,
market_price: null,
tbl_country_name: product.country_name
});
}
// 商品信息有问题,则不显示
if (!product || !product.product_skn || !_.get(product, 'goods_list.length', 0)) {
... ... @@ -198,20 +206,32 @@ exports.processProductList = (list, options) => {
thumb: product.default_images
});
product.cn_alphabet = procCnAlphabetName(product.cn_alphabet);
product.is_few = product.is_soon_sold_out === 'Y';
product.url = helpers.getUrlBySkc(product.product_id, _.get(product, 'goods_list[0].goods_id'), product.cn_alphabet);// eslint-disable-line
if (product.is_global === 'Y') {
product.url = helpers.urlFormat(`/product/global/${product.product_skn}.html`, null);
} else {
if (product.product_id) {
product.url = helpers.getUrlBySkc(product.product_id);
} else if (product.product_skn) {
product.url = helpers.urlFormat('/common/erp2goods', {skn: product.product_skn});
}
}
// 4.6需求 商品列表显示店铺名
if (product.shop_id * 1) {
// is_global = Y & tbl_brand_id!= 0 则跳全球购品牌否则走品牌,因为全球购的商品有可能融进了有货的牌子
if (product.is_global === 'Y' && product.tbl_brand_id) {
product.brandUrl = helpers.urlFormat('/product/global/list', {brand: product.tbl_brand_id});
} else if (product.shop_id * 1) {
product.brand_name = product.shop_name;
product.brandUrl = helpers.urlFormat('', {
shopId: product.shop_id
}, product.shop_domain || 'default-domain');
} else {
// tar add 1606071146 品牌链接处理
product.brandUrl = helpers.urlFormat('', '', product.brand_domain);
// 5.6商品列表未关联店铺不显示品牌
_.unset(product, 'brand_name');
// product.brandUrl = helpers.urlFormat('', '', product.brand_domain);
}
// TODO 删除from参数,暂时保留注释
... ... @@ -225,6 +245,13 @@ exports.processProductList = (list, options) => {
let tags = [],
isfew = false;
if (product.is_global === 'Y') {
tags.push({
is_global: true,
name: product.tbl_country_name
});
}
_.get(product, 'tags', []).forEach((value) => {
let tag = {};
... ...