Authored by yoho

ok

Showing 47 changed files with 3418 additions and 696 deletions
... ... @@ -31,7 +31,7 @@ global.library = path.resolve('./library');
global.middleware = path.resolve('./doraemon/middleware');
global.utils = path.resolve('./utils');
const seo = require(`${global.middleware}/seo`);
const seo = require(`${global.middleware}/seo/seo`);
... ...
... ... @@ -19,7 +19,7 @@ exports.special = (req, res) => {
res.render('special', _.merge({
module: 'activity',
page: 'activity',
page: 'special'
}, headerData, result[1]));
}).catch((err) => {
res.send(err);
... ...
... ... @@ -10,7 +10,7 @@ const _ = require('lodash');
const channelModel = require('../models/index');
exports.index = (req, res) => {
exports.index = (req, res, next) => {
let channelType = req.path.substring(1) || 'boys';
// 将woman转换为girls,以便model层进行处理
... ... @@ -18,7 +18,7 @@ exports.index = (req, res) => {
channelModel.getContent(channelType).then(data => {
res.render('channel', data);
});
}).catch(next);
};
exports.getbrandFloorDataAjax = (req, res) => {
... ... @@ -56,4 +56,3 @@ exports.getNewArrival = (req, res) => {
res.send(result);
});
};
... ...
... ... @@ -11,38 +11,12 @@ const cRoot = './controllers';
// Your controller here
const channelController = require(`${cRoot}/index`);
const seo = require(`${global.middleware}/seo`);
const seoMap = {
/* eslint-disable */
boys: {
title: 'YOHO!有货 | 年轻人潮流购物中心,中国潮流购物风向标,官方授权正品保证',
keywords: 'Yoho! 有货官网,潮流志,潮流男装,潮牌,美国潮牌,日本潮牌,香港潮牌,潮牌店,新品首发,欧美潮流,全球购,代购,时尚,流行,特卖,B2C,正品,购物网站,网上购物,货到付款',
description: 'YOHO! 有货,年轻人潮流购物中心,中国最大的潮流商品购物网站。100%品牌正品保证,支持货到付款。作为YOHO!旗下的购物平台,汇集了全球潮流时尚商品和中国最流行的商品,也是国内最大的原创文化商品平台,也是香港,台湾地区流行商品的集中地。同时包含日本、韩国等众多国外潮流品牌,带给您全新潮流购物体验。'
},
girls: {
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 */
};
// 频道页路由
router.get('/', seo(seoMap.boys), channelController.index);
router.get('/woman', seo(seoMap.girls), channelController.index);
router.get('/kids', seo(seoMap.kids), channelController.index);
router.get('/lifestyle', seo(seoMap.lifestyle), channelController.index);
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);
... ...
... ... @@ -9,25 +9,74 @@
const mRoot = '../models';
// 商品详情model
const detail = require(`${mRoot}/detail`);
const itemModel = require(`${mRoot}/ItemModel`);
const moment = require('moment');
exports.index = (req, res) => {
var uid = null, // 需要修改为正式取 UID 的方式
vipLevel = 0;// 用户等级
/* COOKIE标识访问的是男生频道 */
const COOKIE_NAME_BOYS = 'boys';
detail({
id: req.params.id,
uid: uid,
vipLevel: vipLevel,
ua: req.get('user-agent') ||  ''
//TODO
const COOKIE_DOMAIN = "";
function setSwitchToCookie(req) {
req.cookie('_Channel', COOKIE_NAME_BOYS, {
domain: COOKIE_DOMAIN,
expires: moment().add("days", 300).valueOf()
});
}
function getGenderByCookie(req) {
let gender = null;
let channel = req.cookies._Channel || "boys";
switch (channel) {
case 'boys':
{
gender = '1,3';
break;
}
case 'girls':
{
gender = '2,3';
break;
}
default:
{
gender = "1,2,3";
}
}
return channel;
}
exports.index = (req, res, next) => {
// var uid = null, // 需要修改为正式取 UID 的方式
// vipLevel = 0; // 用户等级
let pid = 204503;
let channel = COOKIE_NAME_BOYS;
if (req.cookies._Channel) {
channel = req.cookies._Channel;
} else {
setSwitchToCookie(req);
}
let gender = getGenderByCookie(req);
itemModel({
id: pid,
ua: req.get('user-agent') || '',
channel: channel,
gender: gender,
uid: 0,
vipLevel: 0
}).then((result) => {
res.render('detail', {
resultShow: JSON.stringify(result, null, 4),
result: result,
devEnv: true,
res.render('detail', Object.assign({
module: 'product',
page: 'detail',
title: result.goodsName
});
});
page: 'detail'
}, result));
}).catch(next);
};
... ...
/**
* sub app product
* @author: xuqi<qi.xu@yoho.cn>
* @date: 2016/05/06
*/
var express = require('express'),
path = require('path'),
hbs = require('express-handlebars');
var app = express();
// set view engin
var doraemon = path.join(__dirname, '../../doraemon/views'); //parent view root
app.set('views', path.join(__dirname, 'views/action'));
app.engine('.hbs', hbs({
extname: '.hbs',
defaultLayout: 'layout',
layoutsDir: doraemon,
partialsDir: ['./views/partial', `${doraemon}/partial`],
helpers: 'helpers'
}));
// router
app.use(require('./router'));
module.exports = app;
\ No newline at end of file
/**
* sub app product
* @author: xuqi<qi.xu@yoho.cn>
* @date: 2016/05/06
*/
var express = require('express'),
path = require('path'),
hbs = require('express-handlebars');
var app = express();
// set view engin
var doraemon = path.join(__dirname, '../../doraemon/views'); // parent view root
app.set('views', path.join(__dirname, 'views/action'));
app.on('mount', function(parent) {
delete parent.locals.settings; // 不继承父 App 的设置
Object.assign(app.locals, parent.locals);
});
app.engine('.hbs', hbs({
extname: '.hbs',
defaultLayout: 'layout',
layoutsDir: doraemon,
partialsDir: ['./views/partial', `${doraemon}/partial`],
helpers: 'helpers'
}));
// router
app.use(require('./router'));
module.exports = app;
... ...
'use strict';
const library = '../../../library';
const API = require(`${library}/api`).API;
const sign = require(`${library}/sign`);
const Promise = require('bluebird');
const co = Promise.coroutine;
const api = new API();
module.exports.getBannerInfoAsync = function(bid, isUrl) {
isUrl;
return api.get('', sign.apiSign({
method: 'web.brand.banner',
brand_id: bid
}));
};
function getBrandLogoByDomainAsync(domain) {
return api.get('', sign.apiSign({
domain: domain,
method: 'web.brand.byDomain'
}));
}
module.exports.getBrandByDomainAsync = function(domain) {
return co(function*() {
let brandInfo = yield getBrandLogoByDomainAsync(domain);
let result = {};
if (brandInfo.data && brandInfo.code === 200) {
result.brandId = brandInfo.data.id || '';
result.node = brandInfo.data.static_content_code || false;
result.brandBanner = brandInfo.data.brand_banner || '';
result.brandNameEn = brandInfo.data.brand_name_en || '';
result.brandNameCn = brandInfo.data.brand_name_cn || '';
result.brandAbout = brandInfo.data.brand_intro || '';
result.shopTemplateType = brandInfo.data.shop_template_type ?
parseInt(brandInfo.data.shop_template_type) : '';
result.type = brandInfo.data.type ? +brandInfo.data.type : 0;
result.shopId = brandInfo.data.shop_id || '';
}
return result;
})();
};
... ...
const library = '../../../library';
const API = require(`${library}/api`).API;
const ServiceAPI = require(`${library}/api`).ServiceAPI;
const sign = require(`${library}/sign`);
const api = new API();
const serviceAPI = new ServiceAPI();
module.exports.getUidProductFavAsync = function(uid, pid, isUrl) {
isUrl;
return api.get('', sign.apiSign({
method: 'app.favorite.isFavorite',
id: pid,
uid: uid,
type: 'product'
}));
};
module.exports.isFavoriteBrandAsync = function(uid, bid) {
return serviceAPI.get('shops/service/v1/favorite/getUidBrandFav', sign.apiSign({
uid: uid,
brandId: bid
}));
};
... ...
'use strict';
const library = '../../../library';
const API = require(`${library}/api`).API;
const sign = require(`${library}/sign`);
const helpers = require(`${library}/helpers`);
const Promise = require('bluebird');
const co = Promise.coroutine;
/**
* 获取首页频道nav
*/
// TODO
// index home
module.exports.getHomeChannelNav = function (channel) {
let home = null;
switch (channel) {
case 'boys':
{
home = helpers.urlFormat('', '', "default");
break;
}
case 'girls':
{
home = helpers.urlFormat('/woman', '', "new");
break;
}
case 'lifestyle':
{
home = helpers.urlFormat('/lifestyle', '', "new");
break;
}
case 'kids':
{
home = helpers.urlFormat('/kids', '', "new");
break;
}
default:
{
home = helpers.urlFormat('', '', "default");
}
}
return {
href : home,
name : `${channel.toUpperCase()}首页`,
pathTitle:'YOHO!有货'
}
}
... ...
'use strict';
const library = '../../../library';
const API = require(`${library}/api`).API;
const sign = require(`${library}/sign`);
const api = new API();
module.exports.getProductBannerAsync = function(pid) {
return api.get('', sign.apiSign({
method: 'web.productBanner.data',
product_id: pid
})).catch(err => console.log(err));
};
module.exports.sizeInfoAsync = function(skn) {
return api.get('', sign.apiSign({
method: 'h5.product.intro',
productskn: skn
})).catch(err => console.log(err));
};
module.exports.getProductComfortAsync = function(pid) {
return api.get('', sign.apiSign({
method: 'web.productComfort.data',
product_id: pid
})).catch(err => console.log(err));
};
module.exports.getProductModelCardAsync = function(pid) {
return api.get('', sign.apiSign({
method: 'web.productModelcard.list',
product_id: pid
})).catch(err => console.log(err));
};
/**
*
* @param skn
* @param isUrl
* @returns {type[]}
*/
module.exports.getProductModelTryAsync = function(skn, isUrl) {
isUrl;
return api.get('', sign.apiSign({
method: 'web.productModelTry.data',
product_skn: skn
})).catch(err => console.log(err));
};
... ...
/**
* 商品详情models
* @author: xuqi<qi.xu@yoho.cn>
* @date: 2016/5/6
*/
'use strict';
const Promise = require('bluebird');
const co = Promise.coroutine;
const moment = require('moment');
const _ = require('lodash');
const library = '../../../library';
const API = require(`${library}/api`).API;
const sign = require(`${library}/sign`);
const helpers = require(`${library}/helpers`);
const ItemData = require('./ItemData');
const BrandData = require('./Brand');
const FavoriteData = require('./FavoriteData');
const ShopModel = require('./Shop');
const SearchData = require('./SearchData');
const HomeModel = require('./HomeModel');
const BLANK_STR = ' ';
var api = new API();
const multiResourcesUrl = {};
const setMultiResourceByProductBaseInfo = (data) => {
return co(function * () {
let productId = data.id;
let uid = data.uid ? data.uid : 0;
let skn = data.erpProductId;
let brandId = data.brand.id ? data.brand.id : 0;
let isOnlyUrl = true;
// 获取相关url
let result = yield Promise.all([
ItemData.getProductBannerAsync(productId, 'web', isOnlyUrl),
ItemData.sizeInfoAsync(skn, isOnlyUrl),
ItemData.getProductComfortAsync(productId, isOnlyUrl),
ItemData.getProductModelCardAsync(productId, isOnlyUrl),
ItemData.getProductModelTryAsync(skn, isOnlyUrl),
BrandData.getBannerInfoAsync(brandId, isOnlyUrl)
]);
multiResourcesUrl['ItemData::getProductBanner'] = result[0];
multiResourcesUrl['ItemData::sizeInfo'] = result[1];
multiResourcesUrl['ItemData::getProductComfort'] = result[2];
multiResourcesUrl['ItemData::getProductModelCard'] = result[3];
multiResourcesUrl['ItemData::getProductModelTry'] = result[4];
multiResourcesUrl['BrandData::getBannerInfo'] = result[5];
if (uid) {
multiResourcesUrl['FavoriteData::getUidProductFav'] =
yield FavoriteData.getUidProductFavAsync(uid, productId, isOnlyUrl);
}
})();
};
function getMultiDataByResourceName(resourceName) {
return multiResourcesUrl[resourceName] || false;
}
/**
* 获取商品的喜欢
* @param uid
* @param pid
* @param bid
*/
const getProductFavoriteData = (uid, pid, bid) => {
return co(function*() {
let result = {
product: false,
brand: false
};
if (uid) {
if (pid) {
let productData = getMultiDataByResourceName('FavoriteData::getUidProductFav');
if (!productData) {
productData = yield FavoriteData.getUidProductFavAsync(uid, pid);
}
result.product = productData.code === 200 && productData.data ? true : false;
}
if (bid) {
let brandData = yield FavoriteData.isFavoriteBrandAsync(uid, bid);
result.brand = brandData.code && brandData.code === 200 ? true : false;
}
}
return result;
})();
};
const getTagsDataByProductInfo = (data) => {
let tags = {};
if (data.productTagBoList) {
data.productTagBoList.forEach(
value => {
switch (value.tagLabel) {
case 'is_soon_sold_out': // 即将售磬
tags.isFew = true;
break;
case 'is_new': // 新品NEW
tags.isNew = true;
break;
case 'is_discount': // SALE
tags.isSale = true;
break;
case 'is_limited': // 限量
tags.isLimit = true;
break;
case 'is_yohood': // YOHOOD
tags.isNewFestival = true;
break;
case 'is_advance': // 再到着
tags.isReNew = true;
break;
case 'midYear':// 年中热促
tags.isYearMidPromotion = true;
break;
case 'yearEnd':// 年终大促
tags.isYearEndPromotion = true;
break;
}
}
);
}
return tags;
};
const getVipDataByProductBaseInfo = (data, vipLevel, uid) => {
vipLevel = vipLevel || 0;
uid = uid || 0;
let vipData = {};
vipData.prices = [];
if (data.productPriceBo.vipPrices) {
if (vipLevel) {
data.productPriceBo.vipPrices.for(value => {
vipData.prices.push({
level: value.vipLevel,
price: value.vipPrice,
name: value.vipTitle,
cur: value.vipLevel === vipLevel ? true : false
});
});
}
vipData.unLogin = false;
if (!uid) {
vipData.unLogin = helpers.urlFormat('signin.html');
}
if (!vipLevel && uid) {
vipData.normalUser = true;
}
vipData.vipSchedualUrl = helpers.urlFormat('home/vip', {
t: _.random(10000, 9999999)
});
}
return vipData;
};
function getProductActivityBannerAsync(pid) {
return co(function*() {
let result = {};
let data = getMultiDataByResourceName('ItemData::getProductBanner');
if (!data) {
data = yield ItemData.getProductBannerAsync(pid);
}
if (data.code && data.code === 200 && data.data) {
result.activityImg = helpers.image(data.data.bannerImg, 260, 64);
result.url = data.data.promotionUrl;
}
return result;
})();
}
const getActivityDataByProductBaseInfo = (data) => {
return co(function *() {
let result = [];
let activityBanner = yield getProductActivityBannerAsync(data.id);
if (activityBanner) {
result.push(activityBanner);
}
if (data.promotionBoList) {
data.promotionBoList.forEach(value => {
result.push({
type: value.promotionType,
des: value.promotionTitle
});
});
}
return result;
})();
};
/**
* 获取商品咨询和评论数据
* @param data
* @returns {{}}
*/
const getConsultCommentDataByProductInfo = (data) => {
// 商品咨询
let consultComment = {};
consultComment.consultNum = 0;
consultComment.captchaUrl = helpers.urlFormat('/passport/images', {
t: moment().valueOf()
});
if (data.consultBoWrapper) {
consultComment.consults = [];
}
// 商品评价
consultComment.commentNum = 0;
if (data.commentBoWrapper) {
consultComment.comments = [];
consultComment.commentUrl = helpers.urlFormat('/home/commnet');
}
return consultComment;
};
/**
* 获取品牌数据
* @param data
*/
const getBrandDataByProductBaseInfo = (data) => {
return co(function *() {
if (!data.brand) {
return {};
}
let brandId = data.brand.id;
let bgImg = '';
let logo = '';
let bannerInfo = null;
let result = getMultiDataByResourceName('BrandData::getBannerInfo');
if (!result) {
result = yield BrandData.getBannerInfoAsync(brandId);
}
if (data.brand.brandIco) {
logo = helpers.getForceSourceUrl(data.brand.brandIco);
}
if (result.code && result.code === 200 && result.data) {
bannerInfo = result.data;
if (bannerInfo.bannerUrl) {
bgImg = helpers.getForceSourceUrl(bannerInfo.bannerUrl);
}
}
// banner的logo
if (bannerInfo.logo) {
logo = helpers.image(bannerInfo.logo);
}
let homeUrl = 'javascript:void(0)';
if (data.brand.brandDomain) {
homeUrl = helpers.urlFormat('', {}, data.brand.brandDomain);
}
// 导航的品牌banner
return {
brandId: brandId,
bgColor: bannerInfo.colorValue ? bannerInfo.colorValue : '#000000',
bgImg: bgImg,
logo: logo,
alt: data.brand.brandName,
brandName: data.brand.brandName,
brandDomain: data.brand.brandDomain,
homeUrl: homeUrl,
isCollect: false
};
})();
};
/**
* 获得sku商品数据
* @param data
* @returns {{defaultImage: number, skuGoods: number, totalStorageNum: number}}
*/
const getSkuDataByProductBaseInfo = (data) => {
let totalStorageNum = 0;
let skuGoods = null;// sku商品
let defaultImage = '';// 默认图
let chooseSkuFlag = false; // 选中状态
if (data.goodsList) {
skuGoods = data.goodsList.reduce((acc, cur, pos)=> {
// 如果status为0,即skc下架时就跳过该商品$value['status'] === 0
let goodsGroup = {};
if (_.isUndefined(cur.colorImage)) {
return acc;
}
if (cur.goodsImagesList) {
// 商品列表
goodsGroup.productSkc = cur.productSkc;
goodsGroup.src = helpers.image(cur.colorImage, 40, 40);
goodsGroup.title = `${_.trim(data.productName)} ${cur.colorName}`;
goodsGroup.name = cur.colorName;
goodsGroup.focus = false;
goodsGroup.total = 0;
goodsGroup.thumbs = [];
goodsGroup.size = [];
}
cur.goodsImagesList.forEach(good => {
if (good.imageUrl) {
goodsGroup.thumbs.push({
url: '',
shower: helpers.image(good.imageUrl, 420, 560),
img: helpers.image(good.imageUrl, 75, 100)
});
}
});
// 缩略图空,不显示
if (_.isEmpty(goodsGroup.thumbs)) {
return acc;
}
// 默认第一张图片
if (pos === 0) {
defaultImage = helpers.image(cur.colorImage, 420, 560);
}
// 商品的尺码列表
cur.goodsSizeBoList.forEach(size => {
if (data.attribute === 3) {
size.goodsSizeStorageNum = size.goodsSizeStorageNum > 1 ? 1 : 0;
}
// 如果status为0,即skc下架时就跳过该商品
if (cur.status === 0) {
size.goodsSizeStorageNum = 0;
}
goodsGroup.size.push({
name: size.sizeName,
sku: size.goodsSizeSkuId,
num: parseInt(size.goodsSizeStorageNum),
goodsId: size.goodsId
});
// 单个sku商品的总数
goodsGroup.total += parseInt(size.goodsSizeStorageNum);
if (goodsGroup.total > 0 && !chooseSkuFlag) { // 默认选中该sku商品
goodsGroup.focus = true;
chooseSkuFlag = true;// 选中sku商品
}
totalStorageNum += parseInt(size.goodsSizeStorageNum);
});
acc.push(goodsGroup);
return acc;
}, []);
if (!_.isEmpty(skuGoods) && !chooseSkuFlag) { // 没有选中一个sku商品,默认选中第一个sku商品
_.head(skuGoods).focus = true;
}
}
return {
defaultImage: defaultImage,
skuGoods: skuGoods,
totalStorageNum: totalStorageNum
};
};
/**
* 处理限购商品的有关按钮状态(或取现购买以及底部商品购买按钮)
*
* @param int $uid
* @param int $showStatus 限购商品的关联状态
* @param boolean $isBeginSale 限购商品是否已开售
*/
const getFashionTopGoodsStatus = (uid, showStatus, isBeginSale) => {
// 潮流尖货状态
// getLimitedCode //限购码状态
// hasLimitedCode //是否已经获取限购码
// limitedCodeSoldOut //限购码是否已经抢光
// openSoon//即将开售
// dis //失效
// buyNow //是否立即购买
let result = {
getLimitedCode: true,
hasLimitedCode: false,
limitedCodeSoldOut: false,
openSoon: false,
dis: false,
buyNow: false,
soldOut: false,
getLimitedCodeDis: false
};
// 显示获取限购码按钮
switch (showStatus) {
case 1: // 开售前/后,立即分享获得限购码(用户未领取限购码)
{
if (isBeginSale) {
result.buyNow = true;
result.dis = true;
} else {
result.openSoon = true;
result.hasLimitedCode = false;
}
break;
}
case 2: // 开售后,限购码已抢光(用户未领取限购码)
{
result.buyNow = true;
result.dis = true;
result.limitedCodeSoldOut = true;
result.getLimitedCode = false;
result.hasLimitedCode = false;
break;
}
case 3: // 开售后,商品已经售罄
{
result.soldOut = true;
result.getLimitedCode = false;
break;
}
case 4:// 开售后,立即购买(用户已领取限购码)
{
result.buyNow = true;
result.dis = false;
result.hasLimitedCode = true;
if (uid) { // 限购码失效
result.getLimitedCodeDis = true;
}
break;
}
case 5: // 开售前,限购码已被抢光(用户未领取限购码)
result.openSoon = true;
result.hasLimitedCode = true;
result.limitedCodeSoldOut = true;
result.getLimitedCode = false;
break;
case 6: // 开售前,即将开售(用户已领取限购码)
result.openSoon = true;
result.hasLimitedCode = true;
if (uid) { // 限购码失效
result.getLimitedCodeDis = true;
}
break;
case 7: // 开售后,用户已经用获得的限购码购买过商品
result.buyNow = true;
result.dis = true;
result.hasLimitedCode = true;
if (uid) { // 限购码失效
result.getLimitedCodeDis = true;
}
}
return result;
};
/**
* 获取分类导航列表
* @returns {Promise.<{}>}
*/
// controller item.php 32;
function getSortNavAsync(smallSortId, gender) {
return co(function*() {
let navs = [];
let data = yield SearchData.getSortByConditionAsync({sort: smallSortId});
if (data.data) {
let sort = _.head(data.data.sort);
// 一级分类
navs.push({
href: helpers.urlFormat('', {msort: sort.sort_id, gender: gender}, 'list'),
name: sort.sort_name,
pathTitle: sort.sort_name
});
if (sort.sub) {
// 二级分类
let subSort = _.head(sort.sub);
navs.push({
href: helpers.urlFormat('', {msort: sort.sort_id, misort: subSort.sort_id, gender: gender}, 'list'),
name: subSort.sort_name,
pathTitle: subSort.sort_name
});
}
}
return navs;
})();
}
/**
* 详情页数据格式化
* @param origin Object 原始数据
* @return result Object 格式化数据
*/
const detailDataPkg = (origin, uid, vipLevel, ua) => {
return co(function*() {
let result = {}; // 结果输出
// 商品名称
if (!origin.productName) {
return result;
}
origin.uid = uid;
result.name = origin.productName;
result.skn = origin.erpProductId;
result.productId = origin.id;
result.maxSortId = origin.maxSortId;
result.smallSortId = origin.smallSortId;
result.promotionId = origin.isPromotion;
result.goCartUrl = helpers.urlFormat('/shopping/cart');
// 接口处理数据,设置并发请求数据
yield setMultiResourceByProductBaseInfo(origin);
let brandId = 0;
if (origin.brand.id) {
brandId = origin.brand.id;
}
// 处理收藏喜欢数据
let favoriteData = yield getProductFavoriteData(uid, result.productId, brandId);
// 商品标签
result.tags = getTagsDataByProductInfo(origin);
// 商品促销短语
if (origin.salesPhase) {
result.saleTip = origin.salesPhrase;
}
// 商品价格
if (origin.productPriceBo) {
result.marketPrice = origin.productPriceBo.formatMarketPrice;
result.hasOtherPrice = true;
result.salePrice = origin.productPriceBo.formatSalesPrice;
if (result.marketPrice === result.salePrice) {
delete result.salePrice;
result.hasOtherPrice = false;
}
}
// VIP数据
result.vipPrice = getVipDataByProductBaseInfo(origin, vipLevel, uid);
// 促销活动banner
result.activity = yield getActivityDataByProductBaseInfo(origin);
const C_VALUE = {
type: '返YOHO币',
des: '每件返 ',
rest: '个 YOHO币'
};
if (origin.productPriceBo.yohoCoinNum && origin.productPriceBo.yohoCoinNum !== 0) {
result.activity.push({
type: C_VALUE.type,
des: `${C_VALUE.des}${origin.productPriceBo.yohoCoinNum}${C_VALUE.rest}`
});
}
// 上市期
if (origin.expectArrivalTime) {
result.arrivalDate = `${origin.expectArrivalTime}月`;
result.presalePrice = origin.productPriceBo.formatSalesPrice;
delete result.salePrice;
result.hasOtherPrice = false;
}
// 商品咨询和评论数据,当前为空
let consultComment = getConsultCommentDataByProductInfo(origin);
// 品牌信息
let banner = null;
if (origin.brand) {
result.brandImg = helpers.image(origin.brand.brandIco, 47, 47);
result.brandName = origin.brand.brandName;
result.brandUrl = helpers.urlFormat('', {}, origin.brand.brandDomain);
banner = yield getBrandDataByProductBaseInfo(origin);
if (banner.isCollect && favoriteData.brand) {
banner.isCollect = favoriteData.brand;
}
}
// sku商品信息
let skuData = getSkuDataByProductBaseInfo(origin);
result.img = skuData.defaultImage;
result.colors = skuData.skuGoods;
let totalStorageNum = skuData.totalStorageNum;
// 是否收藏
result.isCollect = favoriteData.product;
if (origin.isLimitBuy === 'y') {
// 是否开售
let isBeginSale = !!(origin.saleStatus && origin.saleStatus === 1);
// 限购商品有关的展示状态
let showStatus = 1;
if (origin.showStatus) {
showStatus = parseInt(origin.showStatus);
}
let fashTopGoods = getFashionTopGoodsStatus(uid, showStatus, isBeginSale);
result.fashTopGoods = {
getLimitedCode: fashTopGoods.getLimitedCode, // 限购码状态
hasLimitedCode: fashTopGoods.hasLimitedCode, // 是否已经获取限购码
limitedCodeSoldOut: fashTopGoods.limitedCodeSoldOut, // 限购码是否已经抢光
getLimitedCodeDis: fashTopGoods.getLimitedCodeDis // 限购码是否失效
};
if (fashTopGoods.soldOut) {
result.soldOut = fashTopGoods.soldOut;
totalStorageNum = 0; // 改总数为已售磬
} else {
result.openSoon = fashTopGoods.openSoon; // 即将开售
result.dis = fashTopGoods.dis; // 是否失效
result.buyNow = fashTopGoods.buyNow; // 是否立即购买
}
}
let soldOut = !!(origin.status === 0 || totalStorageNum === 0);
let notForSale = origin.attribute === 2; // 非卖品
let virtualGoods = origin.attribute === 3; // 虚拟商品
if (!soldOut && !notForSale && !virtualGoods) {
result.addToCart = true;
// 立即购买或者即将开售存在
if (result.buyNow || result.openSoon) {
delete result.addToCart;
}
} else if (notForSale) {
// 非卖品
result.notForSale = true;
} else if (soldOut) {
// 已售磬
result.soldOut = true;
delete result.fashTopGoods;
} else if (virtualGoods) {
// 虚拟商品
result.buyNow = true; // 是否立即购买
result.buyNowBase = helpers.urlFormat('/ticket', {}, 'shopping');
result.virtualGoods = virtualGoods;
if (result.salePrice) {
result.advancePrice = result.salePrice; // 先行价格
delete result.salePrice;
}
}
// 去掉即将售罄
if (totalStorageNum || soldOut) {
if (result.tags.isFew) {
delete result.tags.isFew; // 去掉即将售罄
}
}
// 分享相关,产品的链接
result.weixinUrl = helpers.urlFormat(origin.productUrl, {}, 'item');
result.shareTitle = result.name;
result.shareImg = result.img;
result.shareDesc = result.phrase;
// 统计需要的商品信息
let statGoodsInfo = {};
statGoodsInfo.uid = uid;
statGoodsInfo.skn = origin.erpProductId;
statGoodsInfo.productId = origin.id;
statGoodsInfo.productName = result.name.replace('\'', '’');
statGoodsInfo.brandName = (result.brandName || '').replace('\'', '’');
statGoodsInfo.marketPrice = result.marketPrice.replace('¥', '');
if (result.salePrice) {
statGoodsInfo.salePrice = result.salePrice.replace('¥', '');
} else {
statGoodsInfo.salePrice = result.marketPrice.replace('¥', '');
}
if (banner.brandId) {
let domainBrand = yield BrandData.getBrandByDomainAsync(banner.brandDomain);
if (domainBrand.type && domainBrand.shopId) {
switch (parseInt(domainBrand.type)) {
case 1:
{
// 多品店不显示
banner = [];
break;
}
case 2:
{
// TODO:单品店显示新版的店铺banner,item.php 210
let basisData = ShopModel.basisTemplate(domainBrand.shopId);
banner.bgImg = basisData.shopTopBanner.banner || banner.bgImg;
break;
}
}
}
}
statGoodsInfo.imageUrl = result.img;
statGoodsInfo.productUrl = result.weixinUrl;
statGoodsInfo.smallSortId = result.smallSortId;
statGoodsInfo.soldOut = parseInt(soldOut);
return {
goodsInfo: result,
consultComment: consultComment,
banner: banner,
statGoodsInfo: statGoodsInfo
};
})();
};
/**
* 获取商品的舒适度
*/
function getProductComfortAsync(productId) {
return co(function*() {
let result = [];
let comfort = getMultiDataByResourceName('ItemData::getProductComfort');
if (!comfort) {
comfort = yield FavoriteData.getProductComfortAsync(productId);
}
if (comfort.data) {
comfort.data.forEach(value => {
let blocks = [];
let flag = false;
_.range(1, 6).forEach(i => {
if (i === value.wearSense.value) {
flag = true;
blocks.push({
cur: true
});
} else {
blocks.push({});
}
});
// 存在,添加
if (flag) {
result.push({
name: value.caption.caption,
minDes: value.caption.low,
blocks: blocks,
maxDes: value.caption.high
});
}
});
}
return result;
})();
}
function getDescriptionDataBySizeInfoAsync(sizeInfo) {
return co(function *() {
let description = {};
if (sizeInfo.productDescBo.erpProductId) {
let sex = '通用';
switch (sizeInfo.productDescBo.gender) {
case 1:
{
sex = '男款';
break;
}
case 2:
{
sex = '女款';
break;
}
}
description.basic = [];
description.basic.push({
key: '编号',
value: sizeInfo.productDescBo.erpProductId
});
description.basic.push({
key: '颜色',
value: sizeInfo.productDescBo.colorName,
dColor: true
});
description.basic.push({
key: '性别',
value: sex
});
if (sizeInfo.productDescBo.standardBos) {
sizeInfo.productDescBo.standardBos.forEach(value => {
description.basic.push({
key: value.standardName,
value: value.standardVal
});
});
}
description.confort = yield getProductComfortAsync(sizeInfo.productBo.id);
}
return description;
})();
}
/**
* 使sizeBoList id以 sizeAttributeBos id顺序一样
* @param sizeInfoBo
*/
function sizeInfoBoSort(sizeInfoBo) {
if (!sizeInfoBo.sizeBoList || !sizeInfoBo.sizeAttributeBos) {
return {};
}
// TODO: 这里的排序代码很乱
_(sizeInfoBo.sizeBoList).forEach((sizeBoList, sizek)=> {
let sortAttr = {};
sizeBoList.sortAttributes.forEach(sortAttributes => {
sortAttr[sortAttributes.id] = sortAttributes;
});
sizeInfoBo.sizeBoList[sizek].sortAttributes = sortAttr;
});
_(sizeInfoBo.sizeBoList).forEach((sizeBoList, sizek)=> {
let sortAttr = [];
sizeInfoBo.sizeAttributeBos.forEach(val => {
sortAttr.push(sizeBoList.sortAttributes[val.id]);
});
sizeInfoBo.sizeBoList[sizek].sortAttributes = sortAttr;
});
return sizeInfoBo;
}
/**
* 获取尺寸信息
* @param sizeInfo
* @returns {{}}
*/
function getSizeDataBySizeInfo(sizeInfo) {
let size = {};
// 尺码信息
if (sizeInfo.sizeInfoBo) {
sizeInfo.sizeInfoBo = sizeInfoBoSort(sizeInfo.sizeInfoBo);
let boyReference = !!sizeInfo.productExtra.boyReference;
let girlReference = !!sizeInfo.productExtra.girlReference;
let gender = sizeInfo.productDescBo.gender || 3;
let referenceName = '参考尺码';
if ((gender === 1 && boyReference) || (gender === 2 && girlReference)) {
referenceName = '参考尺码';
} else if (gender === 3 && boyReference) {
referenceName = '参考尺码(男)';
} else if (gender === 3 && girlReference) {
referenceName = '参考尺码(女)';
}
// 判断是否显示参考尺码
let showReference = (boyReference && sizeInfo.sizeInfoBo.sizeBoList[0].boyReferSize) ||
(girlReference && sizeInfo.sizeInfoBo.sizeBoList[0].girlReferSize);
if (sizeInfo.sizeInfoBo.sizeAttributeBos) {
// 尺码信息头部
size.thead = [{name: '吊牌尺码', id: ''}];
// 显示参考尺码
if (showReference) {
size.thead[1] = {name: referenceName, id: ''};
}
sizeInfo.sizeInfoBo.sizeAttributeBos.forEach(attr => {
size.thead.push({
name: attr.attributeName || ' ',
id: attr.id
});
});
size.tbody = [];
sizeInfo.sizeInfoBo.sizeBoList.forEach(value => {
let sizes = [];
// 吊牌尺码
sizes.push(value.sizeName);
// 判断是否显示参考尺码
if (boyReference && (gender === 1 || gender === 3) && showReference) {
sizes.push(value.boyReferSize.referenceName || ' ');
} else if (girlReference && (gender === 2 || gender === 3) && showReference) {
sizes.push(value.girlReferSize.referenceName || ' ');
} else {
if (size.thead[1] && showReference) {
size.thead[1] = {};
}
}
// 其他尺码信息
value.sortAttributes.forEach(attr => {
sizes.push((attr.sizeValue || BLANK_STR));
});
// 尺码信息
size.tbody.push(sizes);
});
// 参考尺码为空
if (_.isEmpty(size.thead[1]) && showReference) {
// 移除这个值
size.thead.slice(1, 1);
}
}
}
// 测量方式
if (sizeInfo.sizeImage) {
size.sizeImg = sizeInfo.sizeImage;
}
return size;
}
/**
* 获取商品模特卡
* @param productId
*/
function getProductModelCardAsync(productId) {
return co(function*() {
let result = [];
let data = getMultiDataByResourceName('ItemData::getProductModelCard');
if (!data) {
data = yield ItemData.getProductModelCardAsync(productId);
}
if (data.code && data.code === 200) {
_(data.data).forEach(val => {
result.push({
url: helpers.getForceSourceUrl(val.modelImg),
size: val.size,
name: val.modelName
});
});
}
return result;
})();
}
/**
* 获取模特数据
* @param sizeInfo
*/
function getReferenceDataBySizeInfo(sizeInfo) {
let reference = {};
if (sizeInfo.modelBos) {
// 模特试穿, 竖着输出排列显示
// 模特信息
reference.tbody = [];
reference.thead = [
{name: ''},
{name: '模特', modelCol: true},
{name: '身高'},
{name: '体重'},
{name: '三围'},
{name: '吊牌尺码'},
{name: '试穿描述'}
];
// 模特数据
sizeInfo.modelBos.forEach(value => {
let modelValue = [
helpers.getForceSourceUrl(value.avatar),
value.modelName,
value.height,
value.weight,
value.vitalStatistics,
value.fitModelBo.fit_size,
value.fitModelBo.feel
];
// 是否有备注
if (value.fitModelBo.fit_remark) {
modelValue.push(value.fitModelBo.fit_remark);
reference.thead[7] = {name: '备注', remarkCol: true};
}
reference.tbody.push(modelValue);
});
}
return reference;
}
/**
* 获取洗涤材质
* @param sizeInfo
*/
function getMaterialDataBySizeInfo(sizeInfo) {
let material = {};
// 洗涤提示
if (sizeInfo.washTipsBoList) {
material.wash = [];
sizeInfo.washTipsBoList.forEach(value => {
material.wash.push({
name: value.caption,
img: value.img
});
});
}
if (sizeInfo.productMaterialList) {
// 商品材质[洗涤说明]
material.materialDetail = [];
sizeInfo.productMaterialList.forEach(value => {
material.materialDetail.push({
img: value.imageUrl,
name: value.caption,
enName: value.encaption,
text: value.remark
});
});
}
return material;
}
/**
* 获取商品详情页介绍
* @param sizeInfo
*/
function getDetailDataBySizeInfo(sizeInfo) {
let details = '';
// 详情配图
if (sizeInfo.productIntroBo.productIntro) {
if (sizeInfo.productDescBo.phrase) {
details += `${sizeInfo.productDescBo.phrase}<br/>`;
}
}
// 图片换成懒加载方式
const replacePairs = {
'<img src=': '<img class="lazy" src="data:image/gif;base64,R0lGODlhAQABAJEAAAAAAP///93d3f///yH5BAEAAAMALAAAAAABAAEAAAICVAEAOw==" data-original=',
'<img border="0" src=': '<img border="0" class="lazy" src="data:image/gif;base64,R0lGODlhAQABAJEAAAAAAP///93d3f///yH5BAEAAAMALAAAAAABAAEAAAICVAEAOw==" data-original='
};
let intro = sizeInfo.productIntroBo.productIntro;
_(replacePairs).forEach((value, key)=> {
intro = _.replace(intro, key, value);
});
details += intro;
return details;
}
/**
* 获取模特试穿
* @param productSkn
*/
function getProductModelTryAsync(productSkn) {
return co(function*() {
let modelTry = {};
let result = getMultiDataByResourceName('ItemData::getProductModelTry');
if (!result) {
result = yield ItemData.getProductModelTryAsync(productSkn);
}
if (result.code && result.code === 200 && result.data) {
// 先显示模特信息
if (result.data.modelTryBoList) {
modelTry.thead = ['模特', '身高', '体重', '三围', '试穿尺码', '试穿描述'];
modelTry.tbody = [];
result.data.modelTryBoList.forEach(val => {
if (val.modelBo &&
val.sizeBo &&
val.modelBo.modelName &&
val.sizeBo.sizeName) {
modelTry.tbody.push([
val.modelBo.modelName,
val.modelBo.height,
val.modelBo.weight,
val.modelBo.vitalStatistics,
val.sizeBo.sizeName,
val.tryDesc
]);
}
});
} else if (result.data.modelTryImgBoList) {
let tryImg = _.head(result.data.modelTryImgBoList);
modelTry.frImg = helpers.getForceSourceUrl(tryImg.tryImg);
}
}
return modelTry;
})();
}
/**
* 根据最大分类ID获取尺寸属性
* @param maxSortId
* @param sizeInfoBo
*/
function getSizeAttrByMaxSortId(maxSortId, sizeList) {
let attributeIds = null;
// 不同分类,取得属性值不同
switch (maxSortId) {
case 1:
case 2:
{
attributeIds = [3, 4];
break;
}
case 3:
{
attributeIds = [6, 10];
break;
}
case 6:
{
attributeIds = [13];
break;
}
default:
{
attributeIds = [];
}
}
let sizeInfos = [];
let attributeNames = {};
// 获取属性名称
sizeList.sizeAttributeBos.forEach(size => {
attributeNames[size.id] = size.attributeName;
});
sizeList.sizeBoList.forEach(size => {
let sizeValues = [];
size.sortAttributes.forEach(sort => {
if (_.includes(attributeIds, sort.id)) {
if (sort.sizeValue) {
sizeValues.push(
`${attributeNames[sort.id]} ${sort.sizeValue}cm`
);
}
}
});
// 获取尺寸属性
if (!_.isEmpty(sizeValues)) {
sizeInfos[size.sizeName] = sizeValues.join(' / ');
}
});
return sizeInfos;
}
/**
* 商品尺码信息
*
* @param string $productSkn
* @param int $maxSortId
* @return array
*/
const getSizeInfoAsync = (productSkn, maxSortId)=> {
return co(function*() {
let result = {};
if (productSkn) {
// 并发资源中是否存在数据
let sizeInfo = getMultiDataByResourceName('ItemData::sizeInfo');
if (!sizeInfo) {
// 获取尺码
sizeInfo = yield ItemData.sizeInfoAsync(productSkn);
}
if (!sizeInfo) {
return result;
}
let productId = sizeInfo.productBo.id;
// 描述数据
result.description = yield getDescriptionDataBySizeInfoAsync(sizeInfo);
// 尺寸数据
result.size = getSizeDataBySizeInfo(sizeInfo);
// 模特卡
result.modelCards = yield getProductModelCardAsync(productId);
// 模特数据
result.reference = getReferenceDataBySizeInfo(sizeInfo);
// 洗涤材质
result.material = getMaterialDataBySizeInfo(sizeInfo);
// 商品详情页介绍
result.details = getDetailDataBySizeInfo(sizeInfo);
// 试穿模特
let fittingReport = yield getProductModelTryAsync(productSkn);
if (!_.isEmpty(fittingReport)) {
result.fittingReport = fittingReport;
}
// 获取尺寸说明
result.sizeTitleJson =
sizeInfo.sizeInfoBo ? JSON.stringify(getSizeAttrByMaxSortId(maxSortId, sizeInfo.sizeInfoBo)) : '';
}
return result;
})();
};
module.exports = (data) => {
return co(function * () {
// 获取商品信息
let productInfo = yield api.get('', sign.apiSign({
productId: data.id,
method: 'h5.product.data'
}));
productInfo = yield detailDataPkg(productInfo, data.uid, data.vipLevel, data.ua);
//获取商品尺寸相关
let sizeInfo = yield getSizeInfoAsync(productInfo.goodsInfo, productInfo.goodsInfo.maxSortId);
let navs = yield getSortNavAsync(productInfo.goodsInfo.smallSortId, data.gender);
let data = {
productDetailPage: true,
detail: Object.assign(productInfo, sizeInfo),
statGoodsInfo: Object.assign({fullSortName: navs.map(x => x.name).join('-')}, productInfo.statGoodsInfo)
};
//导航
data.detail.pathNav = _.concat(HomeModel.getHomeChannelNav(data.channel), navs, [{name: productInfo.goodsInfo.name}]);
data.detail.lastWalk = 5;
return data;
})();
};
... ...
'use strict';
const Promise = require('bluebird');
const co = Promise.coroutine;
const moment = require('moment');
const _ = require('lodash');
const library = '../../../library';
const API = require(`${library}/api`).SearchAPI;
const sign = require(`${library}/sign`);
const helpers = require(`${library}/helpers`);
const api = new API();
module.exports.getSortByConditionAsync = function(conddition) {
return api.get('/sortgroup.json', conddition);
};
... ...
'use strict';
const Promise = require('bluebird');
const co = Promise.coroutine;
module.exports.basisTemplate = function(shopid) {
return co(function* () {
return {shopid};
})();
};
... ...
hello, I am product hbs
<pre>
{{resultShow}}
</pre>
{{# result}}
<div class="good-detail-page yoho-page">
<div class="banner-container">
<div class="tag-container">
{{# tags}}
{{# is_new}}
<p class="good-tag new-tag">NEW</p>
{{/ is_new}}
{{# is_advance}}
<p class="good-tag renew-tag">再到着</p>
{{/ is_advance}}
{{# is_discount}}
<p class="good-tag sale-tag">SALE</p>
{{/ is_discount}}
{{# is_yohood}}
<div class="good-tag running-man-tag">跑男同款</div>
{{/ is_yohood}}
{{# is_limited}}
<p class="good-tag limit-tag">限量商品</p>
{{/ is_limited}}
{{# is_soon_sold_out}}
<p class="good-tag soonSoldOut-tag">即将售罄</p>
{{/ is_soon_sold_out}}
{{/ tags}}
</div>
{{# bannerTop}}
{{!> product/banner-swiper-arrow}}
{{/ bannerTop}}
</div>
{{# goodsName}}
<h2 class="goodsName"><span>{{.}}</span></h2>
{{/ goodsName}}
{{# goodsSubtitle}}
<h1 class="goodsSubtitle"><span>{{.}}</span></h1>
{{/ goodsSubtitle}}
<div class="price-date">
{{# goodsPrice}}
<div class="goodsPrice">
<h1 class="currentPrice">{{currentPrice}}</h1>
<h1 class="previousPrice">{{previousPrice}}</h1>
</div>
{{/ goodsPrice}}
{{^ noLimitGoodsBtn}}
{{#if canGetLimitCode}}
<button class="limit-sale" id='limit-sale'>获取限购码</button>
{{/if}}
{{#if codeEmpty}}
<button class="got-limit-sale">限购码已被抢光</button>
{{/if}}
{{#if gotCode}}
<button class="got-limit-sale">已获取限购码</button>
{{/if}}
{{/noLimitGoodsBtn}}
{{#if periodOfMarket}}
<div class="periodOfMarket">
<h1>上市期:</h1>
<h1 >{{periodOfMarket}}</h1>
</div>
{{/if}}
</div>
{{# vipLevel}}
<ul class="vip-level clearfix">
{{# list}}
<li class="icons-item {{#if currentLevel}}current-level{{/if}}">
<span class="vip-img " style="background-size:contain;">
</span>
<span class="vip-price ">{{text}}</span>
</li>
{{/ list}}
</ul>
{{/vipLevel}}
{{# goodsDiscount}}
<div class="goodsDiscount" id="goodsDiscount">
{{# list}}
{{#if @first}}
{{#if text}}
<h1 class="first-item short-text tap-hightlight">{{text}}<span class="icon-down iconfont dropdown">&#xe609;</span></h1>
{{/if}}
{{/if}}
{{/ list}}
<div class="discount-folder">
{{# list}}
{{#if @first}}
{{else}}
{{#if text}}
<h1 class="folder-item tap-hightlight">{{text}}</h1>
{{/if}}
{{/if}}
{{/list}}
</div>
</div>
{{/ goodsDiscount}}
{{# feedbacks}}
<div class="feedback-list ">
{{#if commentsNum}}
{{> product/feedback-tab}}
{{else}}
{{#if consultsNum}}
{{> product/feedback-tab}}
{{else}}
<div class="nodata tap-hightlight" id="goto-consult">
<span>暂无商品评价和咨询</span>
<a href="{{consultsUrl}}" class="go-consult">我要咨询<span class="iconfont">&#xe604;</span></a>
</div>
{{/if}}
{{/if}}
</div>
{{/ feedbacks}}
{{# enterStore}}
<div id="enter-store" class="enter-store page-block tap-hightlight">
<a class="store-logo" href="{{url}}" style="">
<img class="lazy" data-original="{{img}}" alt="{{storeName}}">
</a>
<a class="store-name" href="{{url}}">{{storeName}}</a>
<a class="store-link" href="{{url}}">进入店铺<span class="iconfont">&#xe604;</span></a>
</div>
{{/ enterStore}}
<div id="productDesc"> </div>
{{!> product/recommend-for-you}}
{{!> cart/chose-panel}}
{{#cartInfo}}
<div class="cart-bar">
<a href="{{cartUrl}}" class="num-incart iconfont"><span class="num-tag hide"></span>&#xe62c;</a>
{{#if addToCartUrl}}
<!-- <a id="addtoCart" href="{{addToCartUrl}}" class="addto-cart">加入购物车</a> -->
<a id="addtoCart" href="javascript:;" class="addto-cart">加入购物车</a>
{{/if}}
{{#if soldOut}}
<a href="javascript:;" class="sold-out">已售罄</a>
{{/if}}
{{#if notForSale}}
<a href="javascript:;" class="sold-out">非卖品</a>
{{/if}}
{{#if limitNotForSale}}
<a href="javascript:;" class="sold-out limit">即将发售</a>
{{/if}}
{{#if canBuyLimit}}
<a href="javascript:;" id="addtoCart" class="addto-cart">立即购买</a>
{{/if}}
{{#if noLimitCode}}
<a href="javascript:;" class="sold-out limit">立即购买</a>
{{/if}}
<input type="hidden" id="limitCodeUrl" name="limitCodeUrl" value="{{limitCodeUrl}}">
<input type="hidden" id="limitProductPay" name="limitProductPay" value="{{limitProductPay}}">
{{#limitProductCode}}
<input type="hidden" id="limitProductCode" name="limitProductCode" value="{{.}}">
{{/limitProductCode}}
<a href="javascript:;" id="likeBtn" class="favorite iconfont {{#isCollect}}liked{{/isCollect}}">&#xe605;</a>
</div>
{{/cartInfo}}
{{#if introUrl}}
<input id="introUrl" type="hidden" value="{{introUrl}}">
{{/if}}
{{#if id}}
<input id="productId" type="hidden" value="{{id}}">
{{/if}}
{{#if preferenceUrl}}
<input id="preferenceUrl" type="hidden" value="{{preferenceUrl}}">
{{/if}}
<input id="productSkn" type="hidden" value="{{productSkn}}">
{{#loginUrl}}
<input type="hidden" name="loginUrl" id="loginUrl" value="{{.}}">
{{/loginUrl}}
<div class="product-detail-page yoho-page">
{{# detail}}
{{# banner}}
<div class="brand-banner" style="background:{{bgColor}}{{#if bgImg}} url({{bgImg}}){{/if}}">
<div class="center-content clearfix">
<a class="pull-left" href="{{homeUrl}}">
<img src="{{logo}}">
</a>
<div class="opt pull-right">
<a class="home" href="{{homeUrl}}" title="{{brandName}}">
<span class="iconfont">&#xe617;</span>
</a>
<span id="brand-favour" class="brand-fav{{#if isCollect}} coled{{/if}}" data-id="{{brandId}}">
<i class="iconfont">&#xe616;</i>
</span>
</div>
</div>
</div>
{{/ banner}}
<div class="center-content">
{{# goodsInfo}}
<div class="main clearfix" data-skn="{{skn}}" data-id="{{productId}}">
<div class="pull-left imgs clearfix">
<div class="pull-left img">
<div class="tags clearfix">
{{# tags}}
{{# isNew}}
<span class="good-tag new-tag">NEW</span>
{{/ isNew}}
{{# isReNew}}
<span class="good-tag renew-tag">再到着</span>
{{/ isReNew}}
{{# isSale}}
<span class="good-tag sale-tag">SALE</span>
{{/ isSale}}
{{# isNewFestival}}
<span class="good-tag new-festival-tag">新品节</span>
{{/ isNewFestival}}
{{# isLimit}}
<span class="good-tag limit-tag">限量商品</span>
{{/ isLimit}}
{{# isYearEndPromotion}}
<span class="good-tag yep-tag">年终大促</span>
{{/ isYearEndPromotion}}
{{# isYearMidPromotion}}
<span class="good-tag ymp-tag">年中热促</span>
{{/ isYearMidPromotion}}
{{/ tags}}
</div>
<img id="img-show" class="img-show" src="{{img}}">
</div>
<div id="thumbs" class="pull-right thumbs">
{{# colors}}
<div class="thumb-wrap{{#unless focus}} hide{{/unless}}">
{{#if focus}}
{{# thumbs}}
<img class="thumb" src="{{img}}" data-shower="{{shower}}">
{{/ thumbs}}
{{^}}
{{# thumbs}}
<img class="thumb lazy" data-original="{{img}}" data-shower="{{shower}}">
{{/ thumbs}}
{{/if}}
</div>
{{/ colors}}
</div>
</div>
<div class="pull-right infos">
<p class="name">
{{name}}
{{#if saleTip}}
<span class="sale-tip">{{saleTip}}</span>
{{/if}}
</p>
<a class="brand-name" href="{{brandUrl}}">{{brandName}}</a>
<p class="market-price">
<span class="title">市场价:</span>
<span class="price{{#if hasOtherPrice}} has-other-price{{/if}}">{{marketPrice}}</span>
</p>
{{#if salePrice}}
<p class="sale-price">
<span class="title">促销价:</span>
<span class="price">{{salePrice}}</span>
</p>
{{/if}}
{{#if presalePrice}}
<p class="presale-price">
<span class="title">预售价:</span>
<span class="price">{{presalePrice}}</span>
<span class="arrival-date">上市期:{{arrivalDate}}</span>
</p>
{{/if}}
{{#if advancePrice}}
<p class="advance-price">
<span class="title">先行价:</span>
<span class="price">{{advancePrice}}</span>
</p>
{{/if}}
{{# vipPrice}}
<p class="vip-price">
{{#if unLogin}}
登录后即可查看vip价格
<a class="login-url" href="{{unLogin}}">立即登录</a>
{{/if}}
{{#if normalUser}}
<span class="vip-price-item">您当前是普通会员,成为VIP享受更多优惠!</span>
{{/if}}
{{# prices}}
<span class="vip-price-item{{#if cur}} cur{{/if}}">
{{name}}
<em>
{{price}}
</em>
</span>
{{/ prices}}
{{#unless unLogin}}
<a class="vip-schedual" href="{{vipSchedualUrl}}">查看我的VIP进度</a>
{{/unless}}
</p>
{{/ vipPrice}}
{{#if activity}}
<ul class="activity">
{{#each activity}}
<li>
{{#if activityImg}}
<a class="img-link" href="{{url}}">
<img src="{{activityImg}}">
</a>
{{^}}
<span class="ac-type">{{type}}</span>
<span class="ac-des">{{des}}</span>
{{/if}}
</li>
{{/each}}
</ul>
{{/if}}
<div class="trade-content">
<div id="type-chose" class="type-chose">
<div class="chose-color row clearfix">
<span class="title pull-left">选颜色:</span>
<ul class="colors pull-left clearfix">
{{#each colors}}
<li class="{{#if focus}}focus{{/if}} {{#if disable}}disable{{/if}} pull-left" title="{{title}}" data-color="{{name}}" data-total="{{total}}">
<img src="{{src}}">
</li>
{{/each}}
</ul>
</div>
<div class="chose-size row clearfix">
<span class="title pull-left">
{{#if virtualGoods}}
选日期:
{{^}}
选尺码:
{{/if}}
</span>
<div id="sizes" class="size-wrapper pull-left">
{{#each colors}}
<ul class="size{{#unless focus}} hide{{/unless}}">
{{#each size}}
<li {{#unless num}}class="disable"{{/unless}} data-sku="{{sku}}" data-num="{{num}}" data-name="{{name}}">{{name}}</li>
{{/each}}
{{#unless virtualGoods}}
<span class="size-ruler"></span>
{{/unless}}
<span class="size-warn warn-tip hide">
<i class="iconfont">&#xe62c;</i>
{{#if virtualGoods}}
请选择日期
{{^}}
请选择尺码
{{/if}}
</span>
</ul>
{{/each}}
{{#unless virtualGoods}}
<p class="color-size-tip hide"></p>
{{/unless}}
</div>
</div>
<div class="chose-count row clearfix">
<span class="title pull-left">选数量:</span>
<div class="num-wraper pull-left clearfix">
<span id="num" class="num pull-left">1</span>
<span class="minus-plus pull-left">
<i id="plus-num" class="plus iconfont">&#xe610;</i>
<i id="minus-num" class="minus dis iconfont">&#xe600;</i>
</span>
{{#each tags}}
{{#if isFew}}
<span class="warn-tip">即将售罄</span>
{{/if}}
{{/each}}
{{# fashionTopGoods}}
{{#if getLimitedCode}}
<span class="lc-btn get-lc{{#if getLimitedCodeDis}} dis{{/if}}">获取限购码</span>
<div class="lc-container hide">
<span class="lc-arrow"></span>
<div class="lc-content">
<div class="qr-code"></div>
<p class="title">打开APP扫描二维码获取限购码</p>
<p class="sub-title">商品开售后即可购买</p>
</div>
</div>
{{/if}}
{{#if hadLimitedCode}}
<span class="lc-btn had-lc">已获取限购码</span>
{{/if}}
{{#if limitedCodeSoldOut}}
<span class="lc-btn lc-sold-out">限购码已抢光</span>
{{/if}}
{{/ fashionTopGoods}}
</div>
</div>
<p class="row">
{{!-- 各颜色下所有尺码均售罄则只显示售罄按钮 --}}
{{#unless soldOut}}
{{# buyNow}}
<span id="buy-now" class="buy-btn buy-now item-buy{{#if dis}} dis{{/if}}" data-base="{{buyNowBase}}">立即购买</span>
{{/ buyNow}}
{{# openSoon}}
<span id="open-soon" class="buy-btn item-buy dis">即将开售</span>
{{/ openSoon}}
{{#if notForSale}}
<span class="buy-btn dis">
<i class="iconfont">&#xe62d;</i>
非买品
</span>
{{/if}}
{{#if addToCart}}
<span id="add-to-cart" class="buy-btn item-buy add-to-cart">
<i class="iconfont">&#xe628;</i>
添加到购物车
</span>
{{/if}}
{{/unless}}
<span id="sold-out" class="buy-btn dis{{#unless soldOut}} hide{{/unless}}">
<i class="iconfont">&#xe62d;</i>
已售罄
</span>
<span id="collect-product" class="{{#if isCollect}}coled {{/if}}collect-product">
<i class="iconfont">&#xe616;</i>
{{#if isCollect}}
<em>已收藏</em>
{{^}}
<em>收藏商品</em>
{{/if}}
</span>
</p>
<div class="share-row">
<span class="title pull-left">分享商品:</span>
</div>
</div>
<div id="balance" class="balance">
<p class="success-tip">商品已成功添加到购物车!</p>
<p class="cart-total">购物车一共有<span id="cart-num">0</span>件商品</p>
<p class="balance-btns">
<a class="go-cart buy-btn" href="{{goCartUrl}}">
去购物车结算
<i class="iconfont">&#xe601;</i>
</a>
<span id="keep-shopping" class="keep-shopping">
继续购物
</span>
</p>
</div>
</div>
</div>
</div>
{{/ goodsInfo}}
{{!-- 因接口原因,暂存size的title的值 --}}
<div id="size-title-json" style="display: none;">{{sizeTitleJson}}</div>
<div class="other-infos">
<div class="description-material info-block">
<p class="block-title">
<span class="title cur">商品信息 DESCRIPTION</span>
<span class="sep">|</span>
<span class="title">材质洗涤 MATERIALS</span>
</p>
<div class="description-content">
{{# description}}
<ul class="basic clearfix">
{{# basic}}
<li>
{{#if dColor}}
{{key}}: <span id="desc-color">{{value}}</span>
{{^}}
{{key}}: {{value}}
{{/if}}
</li>
{{/ basic}}
</ul>
{{#if comfort}}
<ul class="comfort clearfix">
{{# comfort}}
<li class="pull-left">
<span class="comfort-title">{{name}}</span>
<span class="min-des">{{minDes}}</span>
{{# blocks}}
<span class="comfort-block {{#if cur}}cur{{/if}}"></span>
{{/ blocks}}
<span class="max-des">{{maxDes}}</span>
</li>
{{/ comfort}}
</ul>
{{/if}}
{{/ description}}
</div>
<div class="material-content">
{{# material}}
{{#if materialDetail}}
<ul class="material-detail">
{{# materialDetail}}
<li class="clearfix">
<img src="{{img}}">
<p class="name">{{name}}<br>{{enName}}</p>
<p class="text">{{text}}</p>
</li>
{{/ materialDetail}}
</ul>
{{/if}}
{{#if wash}}
<ul class="wash">
{{# wash}}
<li>
<img class="wash-icon" src="{{img}}">
<p class="wash-name">{{name}}</p>
</li>
{{/ wash}}
</ul>
{{/if}}
{{/ material}}
</div>
</div>
<div class="size-info info-block">
<p class="block-title">
<span class="title cur">尺码信息 SIZE INFO</span>
</p>
{{# size}}
<table class="size-table">
<thead>
<tr>
{{# thead}}
<th>{{name}}</th>
{{/ thead}}
</tr>
</thead>
<tbody>
{{# tbody}}
<tr>
{{#each .}}
<td>{{.}}</td>
{{/each}}
</tr>
{{/ tbody}}
</tbody>
</table>
<p class="size-tip">
※ 以上尺寸为实物人工测量,因测量方式不同会有1-2CM误差,相关数据仅作参考,以收到实物为准。 单位:CM
</p>
<p class="size-tip">
※ 参考尺码因衣服版型、剪裁不同会有误差,仅供参考
</p>
{{#if sizeImg}}
<img class="size-img" src="{{sizeImg}}">
{{/if}}
{{/ size}}
</div>
{{#if reference}}
<div class="reference info-block">
<p class="block-title">
<span class="title cur">模特试穿 REFERENCE</span>
</p>
{{# reference}}
<table class="reference-table">
<thead>
<tr>
{{# thead}}
<th class="{{#if @first}}avatar-col{{/if}}{{#if modelCol}}model-col{{/if}}{{#if remarkCol}}remark-col{{/if}}">{{name}}</th>
{{/ thead}}
</tr>
</thead>
<tbody>
{{# tbody}}
<tr>
{{#each .}}
<td>
{{#if @first}}
<img class="avatar" src="{{.}}">
{{^}}
{{.}}
{{/if}}
</td>
{{/each}}
</tr>
{{/ tbody}}
</tbody>
</table>
{{/ reference}}
<p class="size-tip">
※ 模特试穿中身高单位:CM,体重单位:KG,三围单位:CM
</p>
</div>
{{/if}}
{{#if modelCards}}
<div class="ref-model info-block">
<div class="ref-model">
{{# modelCards}}
<div class="model" style="background: url({{url}}) no-repeat">
<span>试穿尺码: <em>{{size}}</em></span>
</div>
{{/ modelCards}}
</div>
</div>
{{/if}}
{{#if fittingReport}}
<div class="fitting-report info-block">
<p class="block-title">
<span class="title cur">试穿报告 FITTING REPORT</span>
</p>
{{# fittingReport}}
{{#if frImg}}
<div class="fr-img-wrap">
<img src="{{frImg}}">
</div>
{{^}}
<table class="fitting-report-table">
<thead>
<tr>
{{# thead}}
<th>{{.}}</th>
{{/ thead}}
</tr>
</thead>
<tbody>
{{# tbody}}
<tr>
{{#each .}}
<td>{{.}}</td>
{{/each}}
</tr>
{{/ tbody}}
</tbody>
</table>
{{/if}}
{{/ fittingReport}}
</div>
{{/if}}
<div class="details info-block">
<p class="block-title">
<span class="title cur">商品详情 DETAILS</span>
</p>
<div id="details-html" class="details-html">
{{{details}}}
</div>
</div>
{{# consultComment}}
<div class="consult-comment info-block">
<p class="block-title">
<span class="title">顾客咨询(<em class="consult-num">0</em></span>
<span class="sep">|</span>
<span class="title cur">购买评价(<em class="comment-num">0</em></span>
</p>
<div class="comments cc-content">
<h2>购买评价(<em class="comment-num">0</em></h2>
<ul id="comments-ul"></ul>
<p class="more-wrap">
<span class="load-more-comments load-more">
加载更多
<i class="iconfont">&#xe61d;</i>
</span>
</p>
<p class="btn-wrap">
<a class="btn" href="{{commentUrl}}" target="_blank">
<i class="iconfont">&#xe62a;</i>
我要评论
</a>
</p>
</div>
<div class="consults cc-content">
<h2>顾客咨询(<em class="consult-num">0</em></h2>
<ul id="consults-ul"></ul>
<p class="more-wrap">
<span class="load-more-consults load-more">
加载更多
<i class="iconfont">&#xe61d;</i>
</span>
</p>
<p class="btn-wrap">
<span id="consults-btn" class="btn">
<i class="iconfont">&#xe62a;</i>
我要咨询
</span>
</p>
<div class="new-consult hide">
<textarea class="my-consult"></textarea>
<span class="consult-warn warn-tip hide">
<i class="iconfont">&#xe62c;</i>
请输入咨询内容
</span>
<span id="submit-consult" class="btn submit-consult">提交咨询</span>
</div>
<div class="consult-success hide">
<p>
<span class="iconfont">&#xe61a;</span>
咨询成功,请等待客服回复
</p>
</div>
</div>
</div>
{{/ consultComment}}
<div class="after-service">
<p id="after-service-switch" class="after-service-switch">
<span class="iconfont">&#xe62b;</span>
售后服务
<span class="iconfont triangle">&#xe604;</span>
</p>
<div class="after-service-content info-block">
<div class="block-title">
<span class="title cur">售后服务 AFTER SERVICE</span>
</div>
<div class="img-1"></div>
<div class="img-2"></div>
<div class="text">
<h4>退换货承诺</h4>
<p>自您签收商品7日内可以退货,15日内可以换货,在商品不影响二次销售的情况下,YOHO!有货将为您办理退换货服务,请在网站提交"退换货"申请。需要说明的是:非质量问题的退换货,来回运费由您承担。</p>
<h4>退换货方式</h4>
<p>
针对国内大中型城市,YOHO!有货开通了<span class="orange">"上门换货"</span>服务,上门服务区域及费用请联系客服中心;若您所在的区域不在上门换货范围内,请您选择普通快递将商品、内包装、赠品及发货单等一并寄回。质量问题的退换货,目前不支持运费到付款业务,请您先垫付运费寄回。如需退换货,请致电客服电话:400-889-9646。
</p>
<h4>退换货邮寄地址</h4>
<p>
南京市江宁区江宁经济技术开发区苏源大道87号YOHO!有货物流中心东一楼 收件人:YOHO!有货 邮编:211106
<br>
YOHO!有货客服热线:400-889-9646  客服邮箱:<a href="mailto:service@yoho.cn">service@yoho.cn</a>
<br>
有疑问请联系我们,我们将为您提供最优质的产品和服务。
</p>
</div>
</div>
</div>
<div class="service"></div>
{{#if latestWalk}}
<div class="info-block latest-walk">
<input id="latest-walk-count" type="hidden" value="{{latestWalk}}">
<p class="block-title">
<span class="title cur">最近浏览 RECENT REVIEW</span>
</p>
<div id="latest-walk-goods" class="goods clearfix"></div>
</div>
{{/if}}
</div>
</div>
{{/ detail}}
<script id="comments-tpl" type="text/html">
\{{# comments}}
<li>
<div class="user-info clearfix">
<img class="user-avatar pull-left" src="\{{avatar}}">
<p>
<span class="name">\{{userName}} </span>
购买了\{{color}}/\{{size}}
<br>
<span class="date">\{{date}}</span>
</p>
</div>
<p class="comment">\{{comment}}</p>
</li>
\{{/ comments}}
</script>
<script id="consults-tpl" type="text/html">
\{{# consults}}
<li>
<div class="user-info clearfix">
<img class="user-avatar" src="\{{avatar}}">
<p>
<span class="question">\{{question}}</span>
<br>
<span class="date">\{{date}}</span>
</p>
</div>
<p class="consult">\{{answer}}</p>
</li>
\{{/ consults}}
</script>
</div>
{{/ result}}
\ No newline at end of file
{{# statGoodsInfo}}
<script type="text/javascript" src="//static.criteo.net/js/ld/ld.js" async="true"></script>
<script type="text/javascript">
window.criteo_q = window.criteo_q || [];
window.criteo_q.push(
{ event: "setAccount", account: 16184 },
{ event: "setCustomerId", id: "{{uid}}" },
{ event: "setSiteType", type: "d" },
{ event: "viewItem", item: "{{skn}}" }
);
</script>
<script type="text/javascript">
var _mvq = _mvq || [];
_mvq.push(['$setAccount', 'm-23428-1']);
_mvq.push(['$setGeneral', 'goodsdetail', '', /*用户名*/ '', /*用户id*/ '']);
_mvq.push(['$logConversion']);
_mvq.push(['$addGoods', /*分类id*/ '', /*品牌id*/ '', /*商品名称*/ '',/*商品ID*/ '{{skn}}',/*商品售价*/ '',/*商品图片url*/ '', /*分类名*/ '',/*品牌名*/ '', /*商品库存状态1或是0*/ '', /*网络价*/ '',/*收藏人数*/ '']);
_mvq.push(['$logData']);
var _goodsData = {
id:'{{skn}}',// 商品ID
name:'{{productName}}', // 商品名称
brand:'{{brandName}}', // 商品品牌(非必填)
origPrice:'{{marketPrice}}', // 商品原价(非必填)
price:'{{salePrice}}', // 商品售价
imgUrl:'{{imageUrl}}', // 商品预览图
productUrl:'{{productUrl}}', // 商品URL地址
categoryId:'{{smallSortId}}', // 所属分类ID
category:'{{fullSortName}}', // 所属分类完整路径, // 所属分类完整路径
soldOut:'{{soldOut}}' // 状态 1下架,0在售(必填)
};
</script>
{{/statGoodsInfo}}
<script type="text/javascript">
(function () {
try {
var timestamp = (new Date()).valueOf();
var view = document.createElement('img');
view.src = 'http://shopping.yohobuy.com/1.jpg?t='+timestamp;
} catch (e) {}
} )();
</script>
... ...
... ... @@ -13,8 +13,8 @@ module.exports = {
port: 6002,
siteUrl: 'http://localhost:6002/',
domains: {
api: 'http://192.168.102.205:8080/gateway/',
service: 'http://service.api.yohobuy.com/', // 'http://testservice.yoho.cn:28077/',
api: 'http://testapi.yoho.cn:28078/',
service: 'http://testservice.yoho.cn:28077/',
search: 'http://192.168.102.216:8080/yohosearch/'
},
useOneapm: 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
}
});
}
... ...
... ... @@ -15,4 +15,7 @@ module.exports = app => {
// 频道页
app.use('/', require('./apps/channel'));
// 商品详细
app.use('/product', require('./apps/product'));
};
... ...
'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;
... ...
... ... @@ -42,8 +42,8 @@ class Http {
return rp(options).then((result) => {
const duration = timer.put('getApi');// 统计时间结束
// 数据校验
if (!result || !result.code) {
// 数据校验,去掉了code验证有些接口没有提供这些
if (!result) {
log.error('error: 接口返回的数据结构错误,非 JSON');
return Promise.reject({
statusCode: 500,
... ...
... ... @@ -150,3 +150,11 @@ exports.dateDiffFormat = (format, diff, type) => {
return format;
}
};
/**
* 强行获取原图片
* @param imageUrl
*/
exports.getForceSourceUrl = (imageUrl) => {
return _.head(imageUrl.split('?'));
};
... ...
{
"apps": [
{
"name": "yohobuy-node",
"script": "app.js",
"instances": "max",
"exec_mode": "cluster",
"env": {
"PORT": 6002
}
}
]
}
\ No newline at end of file
... ...
This diff could not be displayed because it is too large.

6.28 KB | W: | H:

4.79 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin

6.28 KB | W: | H:

4.79 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
require('../common');
... ...
$pageBgC:#f0f0f0;
$mainFontC:#444444;
$subFontC:#b0b0b0;
$borderC:#e0e0e0;
$tableCellC:#eee;
$basicBtnC:#eb0313;
.good-detail-page {
overflow: hidden;
background-color: #f0f0f0;
.yoho-tip {
z-index: 4;
}
.page-block {
background-color: #fff;
box-sizing: border-box;
.product-detail-page {
.brand-banner {
height: 45px;
width: 100%;
border-bottom: 1px solid $borderC;
border-top: 1px solid $borderC;
padding: 0 28px;
margin-bottom: 30px;
>.title {
line-height: 88px;
color: $mainFontC;
font-size: 28px;
border-bottom: 1px solid $borderC;
span {
color: #a0a0a0;
font-size: 18px;
}
img {
display: block;
height: 45px;
}
.pro-detail {
margin-top: 20px;
margin-bottom: 20px;
.opt {
margin-top: 5px;
}
.detail {
margin-top: 20px;
margin-bottom: 20px;
font-size: 24px;
line-height: 36px;
b {
font-weight: bold;
}
.home, .brand-fav {
display: inline-block;
width: 32px;
height: 32px;
line-height: 32px;
border: 1px solid #fff;
text-align: center;
color: #fff;
cursor: pointer;
}
i {
font-style: italic;
}
&.table {
.js-wraper {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
}
width: 100%;
.column {
box-sizing: border-box;
/*padding: 20px 12px;*/
padding: 6px 3%;
width: 49.9%;
border: 1px solid #fff;
font-size: 24px;
background-color: $tableCellC;
word-wrap: break-word;
display: flex;
align-items: center;
flex-basis: 49.9%;
}
.oldbox{
padding: 6px 3%;
width: 49.9%;
background-color: $tableCellC;
box-sizing: border-box;
border: 1px solid #fff;
width: 49.9%;
height: 100%;
float: left;
text-overflow:ellipsis;
white-space:nowrap;
overflow:hidden;
}
.home {
margin-right: 5px;
.iconfont {
font-size: 14px;
}
}
}
.my-swiper-button-prev,
.my-swiper-button-next {
position: absolute;
top: 50%;
width: 48px;
height: 48px;
margin-top: -44px;
cursor: pointer;
color: #666;
font-size: 48px;
&.swiper-button-disabled{
opacity: .3;
.brand-fav .iconfont {
font-size: 13px;
}
}
.next-grey {
right: 30px;
left: auto;
.coled {
color: #ee0014;
}
}
.prev-grey {
left: 30px;
right: auto;
.path-nav {
border: none;
margin-bottom: 0;
}
.main {
width: 990px;
margin: 0 auto;
.infos {
width: 465px;
}
.img {
position: relative;
width: 420px;
height: 560px;
}
.img-show {
display: block;
width: 100%;
height: 100%;
}
.tags {
position: absolute;
top: 0;
left: 0;
}
.tag-container {
position: absolute;
left: 108px;
top: 40px;
height: 35px;
color: #fff;
font-size: 20px;
line-height: 35px;
z-index: 2;
.good-tag {
display: inline-block;
float: left;
box-sizing: border-box;
margin-left: .5px;
font-size: 18px;
text-align: center;
padding:1px 5PX;
height: 22px;
line-height: 22px;
color: #fff;
padding: 0 7px;
margin-right: 5px;
font-size: 12px;
}
.new-tag {
background-color: #78dc7e;
color: #fff;
background: #78dc7d;
}
.renew-tag {
background-color: #78dc7e;
color: #fff;
background: #78dc7e;
}
.sale-tag {
background-color: #ff575c;
color: #fff;
.running-man-tag {
background-color: #017df9;
color: #f7ed02;
}
.new-festival-tag {
background-color: #000;
color: #fff;
.yep-tag, .ymp-tag, .sale-tag {
background: #ff565b;
}
.yohood-tag {
background-color: #000;
color: #fff;
.few-tag {
background: #ffac5b;
}
.limit-tag {
border: 1px solid #000;
background-color: #fff;
border: 1px solid #4e4e4e;
color: #4e4e4e;
background: #fff;
}
.thumbs {
width: 75px;
height: 510px;
margin-left: 2px;
overflow: hidden;
}
.thumb {
display: block;
width: 75px;
cursor: pointer;
margin-bottom: 2px;
}
.name {
font-size: 18px;
font-weight: bold;
line-height: 24px;
}
.sale-tip {
color: #ee0014;
padding-left: 3px;
}
.brand-name {
color: #666;
font-size: 12px;
}
.title {
color: #999;
font-size: 12px;
}
.market-price {
margin-top: 8px;
}
.price {
color: #000;
font-size: 22px;
line-height: 24px;
font-weight: bold;
}
.has-other-price {
color: #999;
text-decoration: line-through;
font-size: 12px;
}
.soonSoldOut-tag {
background-color: #ffac5b;
.arrival-date {
color: #ee0014;
font-size: 14px;
font-weight: bold;
margin-left: 24px;
}
.vip-price {
line-height: 14px;
color: #222;
margin-top: 5px;
background: resolve('product/vip-price-icon.png') no-repeat;
padding-left: calc(5px + width(product/vip-price-icon.png));
font-size: 12px;
.login-url,
.cur {
color: #f02200;
}
.vip-price-item {
margin-left: 5px;
}
.vip-schedual {
color: #999;
text-decoration: underline;
margin-left: 5px;
}
}
.activity {
margin-top: 12px;
li {
line-height: 20px;
}
}
.ac-type {
display: inline-block;
min-width: 50px;
max-width: 100px;
height: 16px;
line-height: 16px;
margin-right: 5px;
padding: 0 5px;
text-align: center;
background: #999;
color: #fff;
font-size: 12px;
overflow: hidden;
vertical-align: middle;
}
}
.banner-container {
position: relative;
background-color: #fff;
}
.banner-top-single{
margin:0 auto;
overflow: hidden;
img{
width: 448px;
margin-top:30px;
margin-bottom:30px;
.ac-des {
font-size: 12px;
}
}
.banner-top {
min-height: 660px;
overflow: hidden;
position: relative;
.swiper-pagination {
position: absolute;
z-index: 2;
bottom: 40px;
.pagination-inner {
span {
background-color: #b0b0b0;
}
.swiper-pagination-bullet {
margin-right: 2PX;
}
.swiper-pagination-bullet-active {
background-color: #000;
}
.row {
margin-top: 10px;
}
.trade-content {
padding-top: 20px;
margin-top: 20px;
border-top: 1px solid #eaeceb;
}
.chose-color {
font-size: 12px;
.title {
margin-top: 14px;
}
img {
display: block;
height: 36px;
width: 36px;
border: 2px solid #fff;
}
.focus img {
border-color: #222;
}
li {
margin-right: 5px;
margin-bottom: 5px;
cursor: pointer;
}
}
}
.banner-swiper {
min-height: 600px;
min-width: 448px;
margin: 30px 96px;
overflow: hidden;
ul {
position: relative;
height: auto;
.chose-size {
font-size: 12px;
.title {
margin-top: 6px;
}
li {
float: left;
img {
height: auto;
display: block;
height: 22px;
line-height: 22px;
margin-right: 5px;
margin-bottom: 5px;
padding: 0 5px;
border: 1px solid #eaeceb;
text-align: center;
cursor: pointer;
min-width: 28px;
&.disable {
opacity: 0.5;
}
&.focus {
color: #fff;
background: #222;
}
}
}
.size-wrapper {
width: 415px;
}
.size {
float: left;
color: #666;
}
.size-ruler {
float: left;
display: block;
width: 57px;
height: 24px;
background: resolve('product/size-ruler.jpg');
margin-bottom: 5px;
cursor: pointer;
}
.size-warn, .num-warn {
float: left;
height: 24px;
line-height: 24px;
}
.color-size-tip {
color: #999;
clear: both;
line-height: 18px;
}
.chose-count .title {
margin-top: 6px;
}
.num {
display: block;
width: 38px;
height: 23px;
line-height: 23px;
text-align: center;
border: 1px solid #eaeceb;
color: #333;
font-size: 12px;
background: #ebebe4;
}
.minus-plus {
display: block;
width: 14px;
height: 23px;
border: 1px solid #eaeceb;
border-left: none;
text-align: center;
cursor: pointer;
i {
display: block;
width: 13px;
height: 11px;
line-height: 8px;
font-size: 12px;
-moz-user-select: none;
}
.dis {
color: #999;
}
}
.minus {
border-top: 1px solid #eaeceb;
font-size: 13px;
}
.lc-btn {
float: left;
display: block;
width: 80px;
height: 25px;
line-height: 25px;
color: #fff;
background: #222;
margin-left: 10px;
font-size: 12px;
text-align: center;
cursor: default;
&.had-lc, &.lc-sold-out {
background: #ccc;
}
&.dis {
background: #ccc;
}
}
.num-wraper {
position: relative;
}
$arrowTop: 40px;
$arrow: product/arrow.png;
$contentW: 220px;
.lc-container {
position: absolute;
top: calc(-($arrowTop - 1px));
right: calc(-(width($arrow) + $contentW));
z-index: 1;
}
.lc-arrow {
position: absolute;
top: $arrowTop;
left: calc(-(width($arrow) - 1px));
width: width($arrow);
height: height($arrow);
background: resolve($arrow);
}
.lc-content {
box-sizing: border-box;
width: $contentW;
height: 285px;
text-align: center;
background: #f8f8f8;
border: 1px solid #cecece;
padding: 40px 25px 0;
.qr-code {
width: 137px;
height: 137px;
background: resolve(product/top-good-qr.png);
margin: 0 auto;
}
.title {
font-size: 18px;
color: #000;
margin: 12px 0;
line-height: 24px;
}
.sub-title {
font-size: 14px;
color: #939290;
}
}
.buy-btn {
display: inline-block;
margin-right: 10px;
height: 48px;
line-height: 48px;
width: 197px;
text-align: center;
color: #fff;
background: #e92601;
font-size: 14px;
cursor: pointer;
&.hover {
background: #eb3b19;
background: rgba(233, 38, 1, .8);
}
&.dis {
background: #ccc;
}
}
.collect-product, .keep-shopping {
display: inline-block;
width: 127px;
height: 48px;
text-align: center;
line-height: 48px;
background: #fff;
color: #222;
border: 1px solid #ccc;
font-weight: bold;
font-size: 12px;
cursor: pointer;
.iconfont {
color: #ccc;
font-size: 14px;
}
&.coled .iconfont{
color: #fa5252;
}
}
.share-row {
margin-top: 20px;
.title {
margin-top: 2px;
}
}
.balance {
display: none;
.success-tip {
color: #222;
font-size: 18px;
margin-bottom: 10px;
}
.cart-total {
color: #999;
font-size: 12px;
}
.balance-btns {
margin-top: 20px;
}
}
}
.goodsName {
box-sizing: border-box;
width: 100%;
font-size: 28px;
color: #fff;
padding: 20px 28px;
line-height: 48px;
background-color: #515150;
.other-infos {
padding-bottom: 30px;
}
.goodsSubtitle {
/*display: table;*/
height: 88px;
font-size: 24px;
color: $subFontC;
padding-left: 28px;
padding-right: 28px;
border-bottom: 1px solid $borderC;
background-color: $pageBgC;
display: flex;
align-items: center;
span{
/*display: table-cell;*/
display: -webkit-box;
line-height: 36px;
margin: 0;
text-overflow: -o-ellipsis-lastline;
overflow: hidden;
text-overflow: ellipsis;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
.info-block {
margin-top: 30px;
color: #999;
border-top: 2px solid #eaeceb;
font-size: 12px;
.basic {
width: 640px;
margin: 0 auto;
li {
float: left;
width: 25%;
line-height: 20px;
}
}
.comfort {
width: 470px;
border: 1px solid #eaeceb;
margin: 17px auto 0;
padding-bottom: 15px;
li {
margin: 12px 20px 0;
}
}
.comfort-block {
display: inline-block;
width: 14px;
height: 10px;
border: 1px solid #eaeceb;
margin-right: 2px;
&.cur {
background: #999;
border: 1px solid #999;
}
}
}
.price-date {
position: relative;
width: 100%;
color: $subFontC;
height: 88px;
padding-left: 28px;
padding-right: 28px;
background-color: #fff;
border-bottom: 1px solid $borderC;
.block-title {
margin-bottom: 25px;
text-align: center;
.title {
display: inline-block;
padding-top: 15px;
font-weight: bold;
cursor: pointer;
&.cur {
color: #222;
border-top: 2px solid #222;
margin-top: -2px;
}
}
.sep {
display: inline-block;
margin: 0 30px;
color: #eaeceb;
font-size: 14px;
cursor: default;
font-weight: bold;
}
}
.limit-sale {
height: 48px;
position: absolute;
right: 84px;
top: 50%;
margin-top: -24px;
color: #d0021b;
border: 2PX solid #d0021b;
background-color: #fff;
border-radius: 40px;
padding: 4px 20px;
font-size: 24px;
font-weight: bold;
.description-content {
overflow: hidden;
}
.limit-sale:active {
background-color: #f0f0f0;
.material-content {
display: none;
overflow: hidden;
}
.got-limit-sale {
position: absolute;
right: 84px;
top: 24px;
color: #d0021b;
border: 2px solid #d0021b;
background-color: #fff;
border-radius: 40px;
padding: 4px 20px;
font-size: 24px;
font-weight: bold;
color: #ccc;
border-color: #ccc;
.material-detail li {
width: 860px;
padding-bottom: 20px;
border-bottom: 1px dotted #eaeceb;
margin: 0 auto 20px;
img {
float: left;
width: 125px;
height: 50px;
}
.name {
float: left;
width: 100px;
line-height: 25px;
border-right: 1px dotted #eaeceb;
color: #666;
font-weight: bold;
text-align: center;
font-size: 14px;
}
.text {
float: left;
width: 614px;
padding-left: 20px;
line-height: 18px;
}
}
.goodsPrice {
float: left;
font-size: 34.59px;
h1 {
.wash {
text-align: center;
li {
display: inline-block;
line-height: 88px;
padding: 0 20px;
color: #666;
border-right: 1px solid #eaeceb;
}
.currentPrice {
color: #d0021b;
margin-right: 10px;
}
.size-info {
text-align: center;
}
.size-table,
.reference-table,
.fitting-report-table {
text-align: center;
margin: 0 auto;
th {
width: 110px;
text-align: center;
}
.previousPrice {
text-decoration: line-through;
tr {
height: 30px;
}
tr,
td {
text-align: center;
}
thead {
background: #f5f7f6;
color: #999;
}
tbody {
color: #222;
}
.avatar {
width: 26px;
height: 26px;
border-radius: 50px;
}
.avatar-col {
width: 26px;
padding-left: 20px;
padding-right: 20px;
}
.model-col {
width: 90px;
}
.remark-col {
width: 200px;
}
}
.periodOfMarket {
font-size: 24px;
float: right;
color: #d0021b;
margin-right: 1.4rem;
h1 {
display: inline-block;
line-height: 88px;
.fr-img-wrap {
width: 100%;
text-align: center;
img {
max-width: 100%;
}
}
.vip-level {
box-sizing: box-border;
padding-left: 28px;
padding-right: 28px;
min-height: 88px;
background-color: #fff;
font-size: 22px;
color: #999999;
border-bottom: 1px solid $borderC;
.icons-item {
float: left;
width: 33.3%;
height: 88px;
margin: 0;
&.current-level{
.vip-price{
color:#d0021b;
}
}
span {
vertical-align: middle;
display: inline-block;
line-height: 88px;
padding-left: 8px;
.ref-model {
padding-top: 10px;
.model {
width: 444px;
height: 35px;
padding-top: 47px;
padding-left: 316px;
color: #666;
overflow: hidden;
margin: 10px auto 0;
em {
margin-left: 5px;
}
.vip-img {
width: 53px;
height: 32px;
}
}
.size-tip {
color: #999;
margin-top: 15px;
text-align: center;
}
.details {
text-align: center;
font-size: 12px;
color: #999;
line-height: 18px;
}
.details-html {
width: 750px;
text-align: center;
margin: 0 auto;
b {
font-weight: bold;
}
i {
font-style: italic;
}
}
.consults {
display: none;
}
.consult-comment .title {
color: #666;
&.cur {
color: #666;
}
}
.cc-content {
background: #f5f7f6;
padding: 20px 20px 0 20px;
font-size: 12px;
h2 {
font-weight: bold;
font-size: 14px;
margin-bottom: 10px;
color: #000;
}
li {
border-top: 1px solid #eaeceb;
padding: 20px 0;
}
.user-info {
color: #999;
line-height: 16px;
> * {
float: left;
}
&:nth-child(1) {
text-align: left;
.vip-img {
background: resolve('product/silver.png') no-repeat;
}
.name {
color: #666;
}
&:nth-child(2) {
.vip-img {
background: resolve('product/golden.png') no-repeat;
}
.date {
color: #bbb;
}
&:nth-child(3) {
text-align: right;
.vip-img {
background: resolve('product/platinum.png') no-repeat;
}
.question {
color: #222;
}
}
}
.goodsDiscount {
display: block;
width: 100%;
height:auto;
font-size: 28px;
color: $mainFontC;
background-color: #fff;
border-bottom: 1px solid $borderC;
h1 {
position: relative;
padding: 30px 60px 30px 28px;
line-height: 36px;
.user-avatar {
width: 30px;
height: 30px;
margin-right: 5px;
}
.short-text {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.more-wrap {
text-align: center;
color: #666;
border-top: 1px solid #eaeceb;
padding: 20px 0;
font-size: 14px;
font-weight: bold;
color: #666;
}
.iconfont {
position: absolute;
top: 30px;
right: 36px;
width: 35px;
font-size: 45px;
float: right;
color: #e0e0e0;
/*padding-left:50px;*/
}
.discount-folder {
.folder-item {
border-top: 1px solid $borderC;
.btn-wrap {
padding: 20px 0;
border-top: 1px solid #eaeceb;
}
.load-more {
cursor: pointer;
}
.btn {
display: block;
width: 140px;
height: 32px;
line-height: 32px;
color: #fff;
background: #222;
text-align: center;
font-size: 12px;
margin: 0 auto;
cursor: pointer;
.iconfont {
font-size: 14px;
}
}
.comment, .consult {
margin-top: 10px;
}
.consults {
display: none;
}
}
.enter-store {
position: relative;
padding: 0 180px 0 114px;
line-height: 84px;
background-color: #fff;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.store-logo {
position: absolute;
left: 0;
top: 1px;
width: 68px;
height: 84px;
margin-left: 30px;
font-size: 0;
.new-consult {
padding: 20px 0;
border-top: 1px solid #eaeceb;
textarea {
width: 590px;
height: 80px;
padding: 5px;
outline: none;
resize: none;
}
.submit-consult {
display: block;
width: 140px;
height: 32px;
line-height: 32px;
margin: 8px 0 0;
}
.error {
border-color: #e01;
}
}
.consult-success {
border-top: 1px solid #eaeceb;
margin-top: 30px;
text-align: center;
padding: 20px 0;
p {
width: 295px;
height: 55px;
line-height: 55px;
margin: 0 auto;
border: 2px solid #222;
display: block;
color: #222;
font-weight: bold;
}
}
.after-service {
text-align: center;
margin-top: 30px;
.after-service-content {
display: none;
}
.after-service-switch {
height: 44px;
line-height: 44px;
background: #eaeceb;
text-align: center;
img {
display: inline-block;
width: auto;
height: 68px;
vertical-align: middle;
font-size: 12px;
cursor: pointer;
.iconfont {
font-size: 12px;
}
}
.store-name {
font-size: 34px;
color: $mainFontC;
.text {
padding: 20px 15px;
color: #666;
background: #f5f7f6;
text-align: left;
color: #666;
line-height: 18px;
}
.store-link {
position: absolute;
right: 0;
top: 1px;
padding-right: 30px;
font-size: 28px;
color: $subFontC;
text-align: right;
span {
font-size: inherit;
.orange {
color: #f9761a;
}
h4 {
font-weight: bold;
font-size: 14px;
line-height: 24px;
color: #222;
margin-top: 10px;
&:first-child {
margin-top: 0;
}
}
.img-1 {
width: 715px;
height: 259px;
margin: 0 auto;
background: resolve('product/after-service-1.png');
}
.img-2 {
width: 715px;
height: 230px;
margin: 0 auto;
background: resolve('product/after-service-2.png');
}
a {
color: #666;
}
}
.service {
$service: product/service.png;
width: width($service);
height: height($service);
margin: 45px auto;
background: resolve($service);
}
/*底部固定栏*/
.cart-bar {
.latest-walk {
overflow: inherit;
.goods {
width: 1010px;
margin: 0 auto;
height: auto;
> div {
float: left;
width: 180px;
margin-right: 22px;
}
}
img {
height: 240px;
width: 180px;
display: block;
}
.name {
display: block;
margin-top: 5px;
color: #222;
line-height: 16px;
}
.price {
color: #222;
font-weight: bold;
margin-top: 5px;
}
.market-price {
margin-right: 5px;
}
.has-sale {
text-decoration: line-through;
color: #999;
}
}
.warn-tip {
display: inline-block;
color: #e01;
margin-left: 7px;
font-size: 12px;
i {
font-size: 14px;
}
}
.hot-point-wrap {
position: relative;
box-sizing: border-box;
width: 100%;
height: 120px;
position: fixed;
bottom: 0;
background-color: #fff;
z-index: 2;
padding: 20px 28px;
text-align: center;
border-top: 1px solid $borderC;
a {
display: inline-block;
&.num-incart {
font-size: 47px;
color: #444;
}
&.favorite {
font-size: 34px;
color: #ccc
}
&.favorite.liked {
color: $basicBtnC;
;
}
&.addto-cart,
&.sold-out {
height: 80px;
width: 260px;
margin: 0 100px 0 115px;
color: #fff;
background-color: $basicBtnC;
font-size: 32px;
line-height: 80px;
text-align: center;
margin: 0 auto;
.hot-point {
position: absolute;
background: #fff\9;
/*IE8 Hack*/
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=0);
&.hover .pointer{
background-position: 0 -25px;
}
&.sold-out {
background-color: #f58189;
&.hover .hp-good {
display: block;
}
}
.num-tag {
display: block;
.pointer {
position: absolute;
top: 0;
left: 48px;
width: 72px;
height: 72px;
font-size: 40px;
line-height: 72px;
display: block;
background: resolve(product/hp-num.png) no-repeat 0 0;
color: #fff;
background: $basicBtnC;
cursor: pointer;
width: 25px;
height: 25px;
line-height: 25px;
text-align: center;
border-radius: 50%;
transform: scale(0.5);
left: 0;
top: 0;
font-size: 18px;
}
.hp-good {
display: none;
position: absolute;
left: 30px;
top: 0;
width: 210px;
background: #000;
height: 60px;
padding: 10px;
.pic {
display: block;
float: left;
width: 60px;
height: 60px;
margin-right: 10px;
}
.info {
position: relative;
float: left;
color: #fff;
font-size: 12px;
width: 140px;
height: 60px;
line-height: 20px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
text-align: left;
}
&.hide{
display: none;
.check-btn {
display: block;
position: absolute;
height: 18px;
width: 40px;
text-decoration: none;
right: 0;
bottom: 0;
text-align: center;
background: #e8e8e8;
border-radius: 2px;
}
}
}
.recommend-for-you{
border-bottom: none;
}
.yoho-tip{
top:40%;
}
}
@import "comments-consults";
@import "product-description";
... ...
@import "good";
@import 'detail';
.product-page {
... ...