Authored by biao

Merge branch 'feature/m-product' into developwap

# Created by https://www.gitignore.io/api/node,webstorm,netbeans,sublimetext,vim
### Node ###
# Logs
logs
*.log
npm-debug.log*
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules
jspm_packages
# Optional npm cache directory
.npm
# Optional REPL history
.node_repl_history
### WebStorm ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff:
.idea/workspace.xml
.idea/tasks.xml
.idea/dictionaries
.idea/vcs.xml
.idea/jsLibraryMappings.xml
# Sensitive or high-churn files:
.idea/dataSources.ids
.idea/dataSources.xml
.idea/dataSources.local.xml
.idea/sqlDataSources.xml
.idea/dynamic.xml
.idea/uiDesigner.xml
# Gradle:
.idea/gradle.xml
.idea/libraries
# Mongo Explorer plugin:
.idea/mongoSettings.xml
## File-based project format:
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
### WebStorm Patch ###
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
# *.iml
# modules.xml
### NetBeans ###
nbproject/private/
build/
nbbuild/
dist/
nbdist/
nbactions.xml
.nb-gradle/
### SublimeText ###
# cache files for sublime text
*.tmlanguage.cache
*.tmPreferences.cache
*.stTheme.cache
# workspace files are user-specific
*.sublime-workspace
# project files should be checked into the repository, unless a significant
# proportion of contributors will probably not be using SublimeText
# *.sublime-project
# sftp configuration file
sftp-config.json
### Vim ###
# swap
[._]*.s[a-w][a-z]
[._]s[a-w][a-z]
# session
Session.vim
# temporary
.netrwhist
*~
# auto-generated tag files
tags
### YOHO ###
dist
# Created by https://www.gitignore.io/api/node,webstorm,netbeans,sublimetext,vim
### Node ###
# Logs
logs
*.log
npm-debug.log*
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules
jspm_packages
# Optional npm cache directory
.npm
# Optional REPL history
.node_repl_history
### WebStorm ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
.idea/
# User-specific stuff:
.idea/workspace.xml
.idea/tasks.xml
.idea/dictionaries
.idea/vcs.xml
.idea/jsLibraryMappings.xml
# Sensitive or high-churn files:
.idea/dataSources.ids
.idea/dataSources.xml
.idea/dataSources.local.xml
.idea/sqlDataSources.xml
.idea/dynamic.xml
.idea/uiDesigner.xml
# Gradle:
.idea/gradle.xml
.idea/libraries
# Mongo Explorer plugin:
.idea/mongoSettings.xml
## File-based project format:
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
### WebStorm Patch ###
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
# *.iml
# modules.xml
### NetBeans ###
nbproject/private/
build/
nbbuild/
dist/
nbdist/
nbactions.xml
.nb-gradle/
### SublimeText ###
# cache files for sublime text
*.tmlanguage.cache
*.tmPreferences.cache
*.stTheme.cache
# workspace files are user-specific
*.sublime-workspace
# project files should be checked into the repository, unless a significant
# proportion of contributors will probably not be using SublimeText
# *.sublime-project
# sftp configuration file
sftp-config.json
### Vim ###
# swap
[._]*.s[a-w][a-z]
[._]s[a-w][a-z]
# session
Session.vim
# temporary
.netrwhist
*~
# auto-generated tag files
tags
### YOHO ###
dist
public/css/*
public/bundle/*
.eslintcache
public/bundle/*
.eslintcache
*.log.*
... ...
... ... @@ -23,6 +23,6 @@ app.engine('.hbs', hbs({
}));
// router
app.use(require('./router'));
require('./router')(app);
module.exports = app;
... ...
... ... @@ -6,9 +6,10 @@
'use strict';
const router = require('express').Router(); // eslint-disable-line
const router = require('express').Router(); // eslint-disable-line
const cRoot = './controllers';
const guangController = require(`${cRoot}/index`);
// Your controller here
... ...
/**
* 商品详情controller
* @author: xuqi<qi.xu@yoho.cn>
* @date: 2016/5/6
*/
'use strict';
const mRoot = '../models';
// 商品详情model
const detail = require(`${mRoot}/detail`);
exports.index = (req, res) => {
var uid = null, // 需要修改为正式取 UID 的方式
vipLevel = 0;// 用户等级
detail({
id: req.params.id,
uid: uid,
vipLevel: vipLevel,
ua: req.get('user-agent') ||  ''
}).then((result) => {
res.render('detail', {
resultShow: JSON.stringify(result, null, 4),
result: result,
devEnv: true,
module: 'product',
page: 'detail',
title: result.goodsName
});
});
};
... ...
/**
* 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
... ...
/**
* 商品详情models
* @author: xuqi<qi.xu@yoho.cn>
* @date: 2016/5/6
*/
'use strict';
const library = '../../../library';
const API = require(`${library}/api`).API;
const sign = require(`${library}/sign`);
const _ = require('lodash');
const HELPERS = require(`${library}/helpers`);
var api = new API();
var helpers = new HELPERS();
/**
* 处理品牌关联店铺信息
* @param {array}
* @return {array}
*/
const getShopsInfo = (data) => {
var enterStore = {};
_.forEach(data, function(value, key) {
enterStore[key] = {};
enterStore[key].img = helpers.getImageUrl(value.brand_ico, 47, 47);
enterStore[key].storeName = value.brand_name;
if (value.shop_id !== null && value.shop_id !== undefined) {
let params = {};
params.shop_id = value.shop_id;
enterStore[key].url =
helpers.url('/product/index/brand', params);
} else {
enterStore[key].url =
helpers.url('', null, value.brand_domain);
}
});
return enterStore;
};
/**
* 处理限购商品的有关按钮状态(或取现购买以及底部商品购买按钮)
* @param {array} 需要处理的数据
* @param {int} 限购商品的关联状态
* @param {Boolean} 限购商品是否已开售
* @return {array}
*/
const procShowStatus = (data, showStatus, isBeginSale) => {
switch (showStatus) {
case 1:// 开售前/后,立即分享获得限购码(用户未领取限购码)
// 显示获取限购码按钮
data.canGetLimitCode = true;
if (isBeginSale) { // 开售后
data.cartInfo.noLimitCode = true;
} else {
data.cartInfo.limitNotForSale = true;
}
break;
case 2: // 开售后,限购码已抢光(用户未领取限购码)
data.codeEmpty = true;
data.cartInfo.noLimitCode = true;
break;
case 3: // 开售后,商品已经售罄
data.noLimitGoodsBtn = true;
data.cartInfo.soldOut = true;
break;
case 4: // 开售后,立即购买(用户已领取限购码)
data.gotCode = true;
data.cartInfo.canBuyLimit = true;
break;
case 5: // 开售前,限购码已被抢光(用户未领取限购码)
data.codeEmpty = true;
data.cartInfo.limitNotForSale = true;
break;
case 6: // 开售前,即将开售(用户已领取限购码)
data.gotCode = true;
data.cartInfo.limitNotForSale = true;
break;
case 7: // 开售后,用户已经用获得的限购码购买过商品
data.gotCode = true;
data.cartInfo.noLimitCode = true;
break;
default:
break;
}
return data;
};
/**
* 根据设备类型获得限购商品跳转app的url 待处理
* @param {[string]} productCode 限购商品码
* @param {[string]} skn 限购商品skn
* @return {[string]} 限购商品跳转url
*/
const getLimitCodeUrl = (productCode, skn, ua) => {
var url = 'yohoapp://yoho.app/openwith?limit_product_code=' + productCode +
'&product_skn=' + skn;
let isIphone = String(ua).indexOf('iPhone') >= 0;
let isIpad = ua.indexOf('iPad') >= 0;
if (isIphone || isIpad) {
let params = {};
params.lp = productCode;
url = 'yohobuy://' + helpers.url('/limitpurchase', params);
}
return url;
};
/**
* 详情页数据格式化
* @param origin Object 原始数据
* @return dest Object 格式化数据
*/
const detailDataPkg = (origin, uid, vipLevel, ua) => {
var dest = {}, // 结果输出
colorGroup = {},
thumbImageList = {},
sizeGroup = {},
totalStorageNum = 0;
// 商品名称
if (origin.productName === null || origin.productName === undefined) {
return dest;
}
dest.goodsName = origin.productName;
// 用户未登录时 待处理
if (uid === null || uid === undefined) {
let params = {};
params.refer = helpers.url('/product/show_' + origin.erpProductId + '.html');
dest.loginUrl = helpers.url('/signin.html', params);
}
// 商品促销短语
if (origin.salesPhrase !== null && origin.salesPhrase !== undefined) {
dest.goodsSubtitle = origin.salesPhrase;
}
// 商品标签
if (origin.productTagBoList !== null && origin.productTagBoList !== undefined) {
_.forEach(origin.productTagBoList, function(value) {
switch (value.tagLabel) {
case 'is_soon_sold_out':
dest.tags.is_soon_sold_out = true;
break;
case 'is_new':
dest.tags.is_new = true;
break;
case 'is_discount':
dest.tags.is_discount = true;
break;
case 'is_limited':
dest.tags.is_limited = true;
break;
case 'is_yohood':
dest.tags.is_yohood = true;
break;
case 'is_advance':
dest.tags.is_advance = true;
break;
default:
break;
}
});
}
// 商品价格
dest.goodsPrice = {};
if (origin.productPriceBo !== null && origin.productPriceBo !== undefined) {
dest.goodsPrice.currentPrice = origin.productPriceBo.formatSalesPrice;
if (origin.productPriceBo.formatMarketPrice !== origin.productPriceBo.formatSalesPrice) {
dest.goodsPrice.previousPrice = origin.productPriceBo.formatMarketPrice;
}
// 商品返回 YOHO 币
if (origin.productPriceBo.yohoCoinNum !== null && origin.productPriceBo.yohoCoinNum !== 0) {
dest.commodityReturn = dest.productPriceBo.yohoCoinNum;
}
}
// VIP 商品价格
dest.vipLevel = {};
dest.vipLevel.list = {};
if (origin.productPriceBo.vipPrices !== null && origin.productPriceBo.vipPrices !== undefined) {
_.forEach(origin.productPriceBo.vipPrices, function(value, key) {
dest.vipLevel.list[key] = {};
dest.vipLevel.list[key].level = value.vipLevel;
dest.vipLevel.list[key].text = value.vipPrice;
dest.vipLevel.list[key].currentLevel = (value.vipLevel === vipLevel) ? true : false;
});
}
// 上市期
if (origin.expectArrivalTime !== null && origin.expectArrivalTime !== undefined) {
dest.periodOfMarket = origin.expectArrivalTime + '月';
}
// 促销信息
dest.goodsDiscount = {};
dest.goodsDiscount.list = {};
if (origin.promotionBoList !== null && origin.promotionBoList !== undefined) {
_.forEach(origin.promotionBoList, function(value, key) {
dest.goodsDiscount.list[key] = {};
dest.goodsDiscount.list[key].text = '【' + value.promotionType + '】' +
value.promotionTitle;
});
}
// 商品咨询
dest.feedbacks = {};
dest.feedbacks.consults = {};
dest.feedbacks.consultsNum = 0;
if (origin.consultBoWrapper !== null && origin.consultBoWrapper !== undefined) {
dest.feedbacks.consultsNum = origin.consultBoWrapper.consultTotal;
_.forEach(origin.consultBoWrapper.consultBoList, function(value, key) {
dest.feedbacks.consults[key] = {};
dest.feedbacks.consults[key].question = value.ask;
dest.feedbacks.consults[key].time = value.askTime;
dest.feedbacks.consults[key].answer = value.answer;
});
let params = {};
params.product_id = origin.id;
params.total = dest.feedbacks.consultsNum;
dest.feedbacks.consultsUrl = helpers.url('/product/detail/consults', params);
} else { // 暂无咨询
let params = {};
params.product_id = origin.id;
dest.feedbacks.consultsUrl = helpers.url('/product/detail/consultform', params);
}
// 商品评价
dest.feedbacks.commentsNum = 0;
if (origin.commentBoWrapper !== null && origin.commentBoWrapper !== undefined) {
dest.feedbacks.commentsNum = origin.commentBoWrapper.commentTotal;
dest.feedbacks.comments = {};
_.forEach(origin.commentBoWrapper.commentBoList, function(value, key) {
dest.feedbacks.comments[key] = {};
dest.feedbacks.comments[key].userName = value.nickName;
dest.feedbacks.comments[key].desc = value.colorName +
'/' + value.sizeName;
dest.feedbacks.comments[key].content = (value.content !== null &&
value.content !== undefined) ? value.content : '';
dest.feedbacks.comments[key].time = value.createTime;
});
let params = {};
params.product_id = origin.id;
params.total = dest.feedbacks.commentsNum;
dest.feedbacks.commentsUrl = helpers.url('/product/detail/comments', params);
}
// 品牌信息
if (origin.brand !== null && origin.brand !== undefined) {
// dest.enterStore[0] = {};
// dest.enterStore[0].img =
// helpers.getImageUrl(origin.brand.brandIco, 47, 47);
// dest.enterStore[0].storeName = origin.brand.brandName;
// dest.enterStore[0].url = helpers.url('', null, origin.brand.brandDomain);
// 为你优选的链接
let params = {};
params.productSkn = origin.erpProductId;
params.brandId = origin.brand.id;
dest.preferenceUrl = helpers.url('/product/detail/preference', params, '');
}
dest.productSkn = origin.erpProductId;
// 商品信息
if (origin.goodsList !== null && origin.goodsList !== undefined) {
let goodsGroup = {},
sizeName = '',
colorList = {},
sizeList = {},
allSizeList = {},
colorStorageGroup = {},
colorStorageNum = 0;
_.forEach(origin.goodsList, function(value, key) {
if (value.status === 0) {
return true;
}
colorStorageNum = 0;
// 商品分组
if (value.goodsImagesList !== null && value.goodsImagesList !== undefined) {
_.forEach(value.goodsImagesList, function(good, keyForGood) {
goodsGroup[keyForGood] = {};
goodsGroup[keyForGood].goodsId = good.goodsId;
goodsGroup[keyForGood].img = good.imageUrl;
});
}
// 商品的尺码列表
colorStorageGroup[value.productSkc] = {};
if (value.goodsSizeBoList !== null && value.goodsSizeBoList !== undefined) {
_.forEach(value.goodsSizeBoList, function(size, keyForSize) {
sizeList[value.productSkc] = {};
sizeList[value.productSkc][keyForSize] = {};
sizeList[value.productSkc][keyForSize].id = size.id;
sizeList[value.productSkc][keyForSize].skuId = size.goodsSizeSkuId;
sizeList[value.productSkc][keyForSize].goodsId = size.goodsId;
sizeList[value.productSkc][keyForSize].colorId = size.colorId;
sizeList[value.productSkc][keyForSize].name = size.sizeName;
sizeList[value.productSkc][keyForSize].sizeNum = size.goodsSizeStorageNum;
sizeName = size.sizeName;
// 所有尺码列表,赋值用于前端展示默认尺码的时候
// 判断出没有库存则显示灰色
let build = {};
build.storage = size.goodsSizeStorageNum;
build.id = size.id;
allSizeList[sizeName] = (allSizeList[sizeName] === null ||
allSizeList[sizeName] === undefined) ? build :
allSizeList[sizeName];
colorStorageNum += parseInt(size.goodsSizeStorageNum);
colorStorageGroup[value.productSkc][sizeName] = parseInt(size.goodsSizeStorageNum);
});
// 颜色分组
colorList[key] = {};
colorList[key].id = value.colorId;
colorList[key].skcId = value.productSkc;
colorList[key].name = value.colorName;
colorList[key].goodsName = value.goodsName;
colorList[key].colorNum = colorStorageNum;
}
// 缩略图
let params = {};
params.img = helpers.getImageUrl(value.colorImage, 60, 60);
thumbImageList[key] = params;
// 商品库存总数
totalStorageNum += colorStorageNum;
});
// 遍历所有尺码,构建颜色显示数据
let i = 1;
_.forEach(allSizeList, function(value, key) {
// 默认尺码
sizeGroup[0] = {};
sizeGroup[0].size = {};
sizeGroup[0].size[key] = {};
sizeGroup[0].size[key].name = sizeName;
sizeGroup[0].size[key].sizeNum = (value.storage === undefined || value.storage === null) ? false : true;
sizeGroup[0].size[key].id = value.id;
// 各个颜色的尺码, 每行显示一个尺码对应的颜色
_.forEach(colorList, function(colorArr, keyForColorArr) {
colorGroup[i] = {};
colorGroup[i].color = {};
colorGroup[i].color[keyForColorArr] = {};
colorGroup[i].color[keyForColorArr].colorNum =
(colorStorageGroup[colorArr.skcId][sizeName] !== null &&
colorStorageGroup[colorArr.skcId][sizeName] !== undefined) ?
colorStorageGroup[colorArr.skcId][sizeName] : 0;
});
colorGroup[i].id = value.id;
++i;
});
// 遍历所有颜色, 构建尺码显示数据
i = 1;
_.forEach(colorList, function(value, key) {
// 各个尺码的颜色, 每行显示一个颜色的对应尺码
sizeGroup[i] = {};
sizeGroup[i].size = sizeList[value.skcId];
sizeGroup[i].colorId = value.skcId;
// 默认颜色
colorGroup[0] = {};
colorGroup[0].color = {};
colorGroup[0].color[key] = value;
++i;
});
// 商品图:多个
if (goodsGroup[1] !== null && goodsGroup[1] !== undefined) {
_.forEach(goodsGroup, function(value, key) {
dest.bannerTop = {};
dest.bannerTop.list = {};
let params = {};
params.img = helpers.getImageUrl(value.img, 450, 600);
dest.bannerTop.list[key] = params;
});
} else if (goodsGroup[0] !== null && goodsGroup[0] !== undefined) {
dest.bannerTop = {};
dest.bannerTop.img = helpers.getImageUrl(goodsGroup[0].img, 450, 600);
}
}
// 悬浮的购物车信息
dest.cartInfo = {};
dest.cartInfo.cartUrl = helpers.url('/cart/index/index', null);
dest.cartInfo.numInCart = 0;
dest.cartInfo.goodsInstore = origin.storage;
let soldOut = (origin.storage === 0) || (origin.status === 0 || totalStorageNum === 0);
let notForSale = origin.attribute === 2;
// 显示加入购物车链接
if (!soldOut && !notForSale) {
_.orderBy(colorGroup);
dest.cartInfo = {};
dest.cartInfo.productId = origin.id;
dest.cartInfo.thumbs = thumbImageList;
dest.cartInfo.name = (dest.goodsName !== null && dest.goodsName !== undefined) ? dest.goodsName : '';
dest.cartInfo.price = (dest.goodsPrice.previousPrice !== null &&
dest.goodsPrice.previousPrice !== undefined) ? dest.goodsPrice.previousPrice : '';
dest.cartInfo.salePrice = (dest.goodsPrice.currentPrice !== null &&
dest.goodsPrice.currentPrice !== undefined) ? dest.goodsPrice.currentPrice : '';
dest.cartInfo.totalNum = totalStorageNum;
dest.cartInfo.colors = colorGroup;
dest.cartInfo.sizes = sizeGroup;
// 限购商品
if (origin.isLimitBuy === 'Y') {
// 是否开售
let isBeginSale = (origin.saleStatus !== null && origin.saleStatus !== undefined &&
origin.saleStatus === 1);
// 限购商品有关的展示状态
let showStatus = 1;
if (origin.showStatus !== null && origin.showStatus !== undefined) {
showStatus = parseInt(origin.showStatus);
}
// 处理限购商品有关的按钮状态
dest = procShowStatus(dest, showStatus, isBeginSale);
dest.cartInfo.limitProductCode = origin.limitProductCode;
dest.cartInfo.limitCodeUrl = getLimitCodeUrl(origin.limitProductCode, origin.erpProductId, ua);
dest.cartInfo.limitProductPay = helpers.url('/cart/index/orderEnsure');
} else {
dest.cartInfo.addToCartUrl = helpers.url('/product/buy_' + origin.id + '_' +
origin.goodsList.id + '.html'); // 待处理 确认 goodsId 的含义
}
} else if (notForSale) {
dest.cartInfo.notForSale = true;
} else if (soldOut) {
dest.cartInfo.soldOut = true;
}
// 是否收藏
dest.isCollect = false;
if (origin.isCollect !== null && origin.isCollect !== undefined && origin.isCollect === 'Y') {
dest.isCollect = true;
}
// 底部简介的URL链接
dest.introUrl = helpers.url('/product/intro_' + origin.erpProductId + '/' + origin.cnAlphabet + '.html', null, '');
dest.id = origin.id;
return dest;
};
module.exports = (data) => {
var finalResult;
return api.get('', sign.apiSign({
productId: data.id,
uid: data.uid,
vipLevel: data.vipLevel,
method: 'h5.product.data'
})).then(result => {
finalResult = detailDataPkg(result, data.uid, data.vipLevel, data.ua);
return api.get('', sign.apiSign({
method: 'app.shop.queryShopsByBrandId',
brand_id: result.brand.id
})).then(shops => {
if (shops.code === 200) {
finalResult.enterStore = getShopsInfo(shops.data);
}
return finalResult;
});
});
};
... ...
/**
* router of sub app product
* @author: xuqi<qi.xu@yoho.cn>
* @date: 2016/05/06
*/
'use strict';
const router = require('express').Router();
const cRoot = './controllers';
// 商品详情controller
const detail = require(`${cRoot}/detail`);
// routers
router.get('/detail/:id/:gid', detail.index);
module.exports = router;
... ...
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>
{{/ result}}
\ No newline at end of file
... ...
{{#cartInfo}}
<div class="chose-panel">
<div class="main">
<div class="infos">
<div class="basic-info" >
{{#thumbs}}
<img class="thumb {{#unless @first}}hide{{/if}}" src={{img}}>
{{/thumbs}}
<div class="text-info">
<p class="name">{{name}}</p>
<p class="price">
<span class="sale-price{{^price}} no-price{{/price}}">{{salePrice}}</span>
{{#if price}}
<span class="market-price">{{price}}</span>
{{/if}}
</p>
</div>
</div>
<div class="chose-items">
<div class="color-list block-list">
<span>颜色</span>
{{# colors}}
<ul id="{{id}}" data-index="{{@index}}" class="size-row clearfix {{#unless @first}}hide{{/if}}">
{{# color}}
<li class="block {{#if chosed}}chosed{{/if}} {{#unless colorNum}}zero-stock{{/unless}}" data-num="{{colorNum}}">
{{name}}
</li>
{{/ color}}
</ul>
{{/ colors}}
</div>
<div class="size-list block-list">
<span>尺码</span>
{{# sizes}}
<ul class="size-row clearfix {{#unless @first}}hide{{/if}}">
{{# size}}
<li class="block {{#if chosed}}chosed{{/if}} {{#unless sizeNum}}zero-stock{{/unless}}" data-num="{{sizeNum}}" data-id="{{id}}" data-skuid="{{skuId}}">
{{name}}
</li>
{{/ size}}
</ul>
{{/ sizes}}
</div>
<p>
<div class="num">
<span>数量</span>
<div class="clearfix">
<a class="btn btn-minus" href="javascript:void(0);">
<span class="iconfont {{#if promotionId}}disabled{{/if}}">&#xe625;</span>
</a>
<input id="good-num" class="good-num disabled" type="text" value="1" disabled="true">
<a class="btn btn-plus" href="javascript:void(0);">
<span class="iconfont {{#if promotionId}}disabled{{/if}}">&#xe624;</span>
</a>
</div>
<span class="left-num"></span>
<input id="left-num" type="hidden" value="0">
</div>
</div>
</div>
<div class="btn-wrap">
<button id="chose-btn-sure" class="btn btn-sure">加入购物车</button>
</div>
</div>
</div>
{{/cartInfo}}
<input id="promotionId" type="hidden" value="{{promotionId}}">
\ No newline at end of file
... ...
{{#if list}}
<div class="banner-top">
<div class="banner-swiper swiper-container">
<ul class="swiper-wrapper">
{{# list}}
<li class="swiper-slide">
<a href="javascript:;">
<img src="{{img}}" alt="">
</a>
</li>
{{/ list}}
</ul>
</div>
<div class="swiper-pagination">
<div class="pagination-inner">
</div>
</div>
<div class="my-swiper-button-prev prev-grey"></div>
<div class="my-swiper-button-next next-grey"></div>
</div>
{{^}}
<div class="banner-top-single">
<a href={{url}}>
<img class="img" src="{{img}}">
</a>
</div>
{{/if}}
\ No newline at end of file
... ...
<ul id="nav-tab" class="nav-tab clearfix">
<li class="comment-nav tap-hightlight">商品评价(<span class="comments-num">{{commentsNum}}</span>)</li>
<li class="consult-nav tap-hightlight">购买咨询(<span class="consults-num">{{consultsNum}}</span>)</li>
</ul>
<div id="feedback-content" >
<div class="comment-content content ">
{{#if commentsNum}}
<div class="comment-content-main content-main">
{{# comments}}
<span class="user-name">
{{userName}}
</span>
<span class="goods-spec">
购买了{{desc}}
</span>
<p class="detail-content">
{{content}}
</p>
<span class="comment-time">
{{time}}
</span>
{{/ comments}}
</div>
<a class="comment-content-footer tap-hightlight" href="{{commentsUrl}}">
查看更多
<span class="iconfont">&#xe604;</span>
</a>
{{^}}
<div class="comment-content-main content-main no-item">
<span class="iconfont">&#xe63d;</span>暂无评论
</div>
{{/if}}
</div>
<div class="consult-content content hide ">
{{#if consultsNum}}
<div class="consult-content-main content-main">
{{# consults}}
<div class="question">
<span class="iconfont">&#xe644;</span>
<p>
{{question}}<br>
<span class="time">{{time}}</span>
</p>
</div>
<div class="answer">
<span class="iconfont">&#xe642;</span>
<p>{{answer}}</p>
</div>
{{/ consults}}
</div>
<a class="consult-content-footer tap-hightlight" href="{{consultsUrl}}">
查看更多
<span class="iconfont">&#xe604;</span>
</a>
{{else}}
<div class="consult-content-main content-main no-item">
<span class="iconfont">&#xe63f;</span>暂无咨询
</div>
<div class="consult-content-footer tap-hightlight">
<a href="{{consultsUrl}}">
我要咨询
<span class="iconfont">&#xe604;</span></a>
</div>
{{/if}}
</div>
</div>
... ...
<div class="recommend-for-you hide">
</div>
\ No newline at end of file
... ...
... ... @@ -12,5 +12,5 @@ module.exports = app => {
app.use(require('./apps/channel'));
// 业务模块
app.use('/guang', require('./apps/guang'));
//app.use('/product', require('./apps/product'));
};
... ...
... ... @@ -19,7 +19,7 @@
(function(d,c){var e=d.documentElement,a="orientationchange" in window?"orientationchange":"resize",b=function(){var f=e.clientWidth;if(!f){return}if(f>=640){e.style.fontSize="40px"}else{e.style.fontSize=40*(f/640)+"px"}};if(!d.addEventListener){return}b();c.addEventListener(a,b,false);d.addEventListener("DOMContentLoaded",b,false)})(document,window);
</script>
{{#if devEnv}}
<link rel="stylesheet" href="//localhost:5000/css/index.css">
<link rel="stylesheet" href="//localhost:5001/css/index.css">
{{^}}
<link rel="stylesheet" href="//cdn.yoho.cn/m-yohobuy-node/{{version}}/index.css">
{{/if}}
... ... @@ -27,7 +27,7 @@
<body>
{{{body}}}
{{#if devEnv}}
<script src="//localhost:5000/{{module}}.{{page}}.js"></script>
<script src="//localhost:5001/{{module}}.{{page}}.js"></script>
{{^}}
<script src="//cdn.yoho.cn/m-yohobuy-node/{{version}}/{{module}}.{{page}}.js"></script>
{{/if}}
... ...
... ... @@ -75,3 +75,92 @@ exports.upperCase = (str) => {
str = str || '';
return str.toUpperCase();
};
/*
* @Author: Targaryen
* @Date: 2016-05-10 10:11:34
* @Last Modified by: Targaryen
* @Last Modified time: 2016-05-12 11:25:53
*/
/* -----------------------------------------
* 实现 PHP 的 Helpers 函数
* -----------------------------------------
*/
//'use strict';
//
//const SUB_DOMAIN = '.yohobuy.com';
//const SITE_MAIN = 'http://www.yohobuy.com';
//const _ = require('lodash');
//
//class HELPERS {
//
// /**
// * 构建网站的URL
// * @param uri String
// * @param param Array
// * @param module String
// */
// url(uri, param, module) {
// let url = '';
//
// if (module === null) {
// module = 'index';
// }
// switch (module) {
// case 'default':
// url = 'http://m.yohobuy.com';
// break;
// case 'guang':
// url = 'http://guang' + SUB_DOMAIN;
// break;
// case 'list':
// url = 'http://list' + SUB_DOMAIN;
// break;
// case 'search':
// url = 'http://search' + SUB_DOMAIN;
// break;
// case 'index':
// url = SITE_MAIN;
// break;
// case '':
// break;
// case undefined:
// break;
// default:
// url = 'http://' + module + SUB_DOMAIN;
// break;
// }
//
// url += uri;
// if (param !== null && param !== undefined) {
// url += '?';
// _.forEach(param, function(value, key) {
// url += (key + '=' + value + '&');
// });
// }
// if (url.substr(-1, 1) === '&') {
// return url.substr(0, url.length - 1);
// } else {
// return url;
// }
//
// }
//
// /**
// * 根据尺寸获得图片url
// * @param uri String
// * @param param Array
// * @param module String
// */
// getImageUrl(url, width, height, mode) {
// if (mode === null) {
// mode = 2;
// }
// return url.replace(/{width}/g, width)
// .replace(/{height}/g, height)
// .replace(/{mode}/g, mode);
// }
//}
//
//module.exports = HELPERS;
... ...
... ... @@ -7,13 +7,15 @@
'use strict';
let winston = require('winston'),
config = require('../config/common');
config = require('../config/common'),
FileTransport = require('winston-daily-rotate-file');
require('influxdb-winston');
let logger = new (winston.Logger)({
transports: [
new (winston.transports.File)(config.loggers.file),
new (FileTransport)(config.loggers.infoFile),
new (FileTransport)(config.loggers.errorFile),
new (winston.transports.UdpTransport)(config.loggers.udp),
new (winston.transports.Console)(config.loggers.console)
]
... ...
... ... @@ -40,7 +40,8 @@
"morgan": "^1.7.0",
"request-promise": "^3.0.0",
"serve-favicon": "^2.3.0",
"winston": "^2.2.0"
"winston": "^2.2.0",
"winston-daily-rotate-file": "^1.0.1"
},
"devDependencies": {
"autoprefixer": "^6.3.6",
... ...
... ... @@ -201,11 +201,11 @@ gulp.task('webpack-dev-server', () => {
headers: {
'Access-Control-Allow-Origin': '*'
}
}).listen(5000, 'localhost', (err) => {
}).listen(5001, 'localhost', (err) => {
if (err) {
throw new gutil.PluginError('webpack-dev-server', err);
}
gutil.log('[webpack-serve]', 'http://localhost:5000/');
gutil.log('[webpack-serve]', 'http://localhost:5001/');
});
});
... ... @@ -218,5 +218,6 @@ gulp.task('webpack', () => {
if (err) {
throw new gutil.PluginError('webpack', err);
}
gutil.log('[webpack compile]:', stats.endTime - stats.startTime, 'ms');
});
});
... ...
... ... @@ -92,3 +92,6 @@ a {
@import "common/loading";
@import "common/swiper";
@import "channel/index";
@import "product/detail";
@import "product/comments-consults";
@import "product/product-description";
... ...
@define-mixin consult-item {
margin-top: 30px;
padding: 20px 28px;
background-color: #fff;
border-bottom: 1px solid $borderC;
border-top: 1px solid $borderC;
.question {
font-size: 24px;
color: $mainFontC;
span {
display: block;
float: left;
padding-right: 15px;
}
p {
overflow: hidden;
padding-bottom: 15px;
border-bottom: 1px solid $borderC;
}
}
.time {
font-size: 22px;
color: $subFontC;
}
.answer {
font-size: 24px;
line-height: 36px;
color: $subFontC;
margin-top: 14px;
span {
display: block;
float: left;
color: $mainFontC;
padding-right: 15px;
}
p {
overflow: hidden;
}
}
.operation {
width: 120%;
height: 60px;
line-height: 80px;
position: relative;
right: 12%;
border-top: 1px solid #e0e0e0;
margin-top: 20px;
li{
&.highlight{
color: $basicBtnC;
}
font-size:28px;
float:left;
width: 50%;
text-align: center;
color:$subFontC;
.iconfont{
display: inline-block;
padding-right: 5PX;
font-size: inherit;
}
position: relative;
.animate-count {
display: none;
position: absolute;
top: 0;
font-size: 20px;
z-index: 5;
}
i.count {
position: absolute;
}
}
li.fav {
.animate-count {
right: 100px;
}
}
li.useful {
.animate-count {
right: 88px;
}
}
}
}
.goods-comments-page {
.goods-comments {
.comment-item {
border-bottom: 1px solid $borderC;
padding: 0 28px;
.user-name {
display: inline-block;
float: left;
max-width: 9rem;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 24px;
line-height: 62px;
color: $mainFontC;
}
.goods-spec,
.comment-time {
font-size: 24px;
line-height: 62px;
}
.detail-content {
font-size: 24px;
line-height: 62px;
color: $mainFontC;
}
.goods-spec,
.comment-time {
font-size: 24px;
line-height: 62px;
}
.detail-content {
font-size: 28px;
line-height: 36px;
}
.goods-spec,
.detail-content {
color: $mainFontC;
}
.comment-time {
color: #c1c1c1;
}
}
}
}
.goods-consults-page {
background-color: #f0f0f0;
.goto-consult {
position: fixed;
top: 2.25rem;
width: 100%;
box-sizing:border-box;
padding: 0 28px;
height: 120px;
background-color: #ffffff;
border-bottom: 1px solid $borderC;
z-index: 10;
i,
span,
a {
line-height: 120px;
font-size: 28px;
color: $mainFontC;
}
.consult-logo {
padding-right: 15px;
}
.enter-consult-page {
float: right;
color: $subFontC;
}
}
.goods-consults.customer-consults {
.consult-item:nth-child(1) {
display: block;
}
.consult-item:nth-child(2) {
display: block;
}
.consult-item {
display: none;
}
}
.goods-consults {
margin-top: 5.25rem;
overflow: hidden;
@mixin consult-item;
}
.readmore{
display: block;
height: 88px;
line-height: 88px;
background-color: #fff;
text-align: center;
color: $subFontC;
margin-top: 30px;
border-top: 1px solid $borderC;
border-bottom: 1px solid $borderC;
font-size: 28px;
i{
font-size: inherit;
}
}
.faq-title{
height: 88px;
line-height: 88px;
text-align: center;
font-size: 32px;
}
.goods-consults .faq-item{
@mixin consult-item;
margin-top: 0;
margin-bottom: 30px;
.answer{
border-bottom: none;
}
}
}
.consult-form-page {
padding: 28px;
text-align: center;
textarea {
box-sizing: border-box;
width: 100%;
height: 400px;
font-size: 28px;
padding: 10px;
color: $mainFontC;
}
a {
display: inline-block;
height: 80px;
width: 360px;
color: #fff;
background-color: #444;
font-size: 40px;
line-height: 80px;
text-align: center;
margin-top: 20px;
}
}
.good-detail-page {
.feedback-list {
padding-top: 30px;
margin-bottom: 30px;
background-color: #f0f0f0;
.nav-tab {
width: 100%;
height: 60px;
padding: 10px 0;
background-color: #fff;
border-top: 1px solid $borderC;
border-bottom: 1px solid $borderC;
}
.comment-nav,
.consult-nav {
box-sizing: border-box;
float: left;
width: 50%;
height: 60px;
line-height: 60px;
font-size: 28px;
text-align: center;
color: $subFontC;
&.focus {
color: #000;
}
}
.comment-nav {
border-right: 1px solid #ccc;
}
.content {
.content-main {
background-color: #fff;
border-bottom: 1px solid $borderC;
&.comment-content-main {
.user-name {
font-size: 24px;
line-height: 62px;
color: $mainFontC;
padding-left: 28px;
padding-right: 18px;
}
.goods-spec,
.comment-time {
font-size: 24px;
line-height: 62px;
}
.detail-content {
font-size: 24px;
line-height: 62px;
color: $mainFontC;
padding-left: 28px;
padding-right: 18px;
}
.goods-spec,
.comment-time {
font-size: 24px;
line-height: 62px;
}
.detail-content {
font-size: 28px;
line-height: 36px;
}
.goods-spec,
.detail-content {
color: $mainFontC;
}
.detail-content,
.comment-time {
padding-left: 28px;
}
.detail-content {
padding-right: 28px;
padding-left: 28px;
}
.detail-content {
padding-right: 28px;
}
.comment-time {
color: #c1c1c1;
}
}
&.consult-content-main {
padding-right: 28px;
padding-left: 28px;
padding-top: 20px;
padding-bottom: 20px;
.question {
font-size: 24px;
color: $mainFontC;
span {
display: block;
float: left;
font-size: inherit;
padding-right: 15px;
}
p {
overflow: hidden;
}
}
.time {
font-size: 22px;
color: $subFontC;
}
.answer {
font-size: 24px;
line-height: 36px;
color: $subFontC;
margin-top: 14px;
span {
display: block;
float: left;
font-size: inherit;
color: $mainFontC;
padding-right: 15px;
}
p {
overflow: hidden;
}
}
}
&.no-item{
height: 200px;
line-height: 200px;
color: #e0e0e0;
font-size: 16PX;
text-align: center;
span{
display: inline-block;
font-size: 16PX;
padding-right: 5PX;
}
}
}
}
.comment-content-footer,
.consult-content-footer {
display: block;
min-height: 88px;
text-align: center;
background-color: #fff;
border-bottom: 1px solid $borderC;
line-height: 88px;
font-size: 28px;
color: #b0b0b0;
.iconfont {
font-size: inherit;
}
}
.content.hide {
display: none;
}
.nodata {
height: 88px;
font-size: 28px;
line-height: 88px;
background-color: #fff;
padding: 0 28px;
border-top: 1px solid $borderC;
border-bottom: 1px solid $borderC;
.go-consult {
float: right;
color: $subFontC;
span {
font-size: 28px;
}
}
}
}
}
... ...
$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;
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;
}
}
.pro-detail {
margin-top: 20px;
margin-bottom: 20px;
}
.detail {
margin-top: 20px;
margin-bottom: 20px;
font-size: 24px;
line-height: 36px;
b {
font-weight: bold;
}
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;
}
}
}
}
.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;
}
}
.next-grey {
right: 30px;
left: auto;
}
.prev-grey {
left: 30px;
right: auto;
}
.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;
box-sizing: border-box;
margin-left: .5px;
font-size: 18px;
text-align: center;
padding:1px 5PX;
}
.new-tag {
background-color: #78dc7e;
color: #fff;
}
.renew-tag {
background-color: #78dc7e;
color: #fff;
}
.sale-tag {
background-color: #ff575c;
color: #fff;
}
.new-festival-tag {
background-color: #000;
color: #fff;
}
.yohood-tag {
background-color: #000;
color: #fff;
}
.limit-tag {
border: 1px solid #000;
background-color: #fff;
color: #000;
}
.soonSoldOut-tag {
background-color: #ffac5b;
color: #fff;
}
}
.banner-container {
position: relative;
background-color: #fff;
}
.banner-top-single{
margin:0 auto;
overflow: hidden;
img{
width: 448px;
margin-top:30px;
margin-bottom:30px;
}
}
.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;
}
}
}
}
.banner-swiper {
min-height: 600px;
min-width: 448px;
margin: 30px 96px;
overflow: hidden;
ul {
position: relative;
height: auto;
li {
float: left;
img {
height: auto;
}
}
}
}
.goodsName {
box-sizing: border-box;
width: 100%;
font-size: 28px;
color: #fff;
padding: 20px 28px;
line-height: 48px;
background-color: #515150;
}
.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;
}
}
.price-date {
position: relative;
width: 100%;
color: $subFontC;
height: 88px;
padding-left: 28px;
padding-right: 28px;
background-color: #fff;
border-bottom: 1px solid $borderC;
}
.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;
}
.limit-sale:active {
background-color: #f0f0f0;
}
.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;
}
.goodsPrice {
float: left;
font-size: 34.59px;
h1 {
display: inline-block;
line-height: 88px;
}
.currentPrice {
color: #d0021b;
margin-right: 10px;
}
.previousPrice {
text-decoration: line-through;
}
}
.periodOfMarket {
font-size: 24px;
float: right;
color: #d0021b;
margin-right: 1.4rem;
h1 {
display: inline-block;
line-height: 88px;
}
}
.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;
}
.vip-img {
width: 53px;
height: 32px;
}
&:nth-child(1) {
text-align: left;
.vip-img {
background: resolve('product/silver.png') no-repeat;
}
}
&:nth-child(2) {
.vip-img {
background: resolve('product/golden.png') no-repeat;
}
}
&:nth-child(3) {
text-align: right;
.vip-img {
background: resolve('product/platinum.png') no-repeat;
}
}
}
}
.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;
}
.short-text {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.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;
}
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;
text-align: center;
img {
display: inline-block;
width: auto;
height: 68px;
vertical-align: middle;
}
}
.store-name {
font-size: 34px;
color: $mainFontC;
}
.store-link {
position: absolute;
right: 0;
top: 1px;
padding-right: 30px;
font-size: 28px;
color: $subFontC;
text-align: right;
span {
font-size: inherit;
}
}
}
/*底部固定栏*/
.cart-bar {
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;
}
&.sold-out {
background-color: #f58189;
}
}
.num-tag {
display: block;
position: absolute;
top: 0;
left: 48px;
width: 72px;
height: 72px;
font-size: 40px;
line-height: 72px;
color: #fff;
background: $basicBtnC;
text-align: center;
border-radius: 50%;
transform: scale(0.5);
&.hide{
display: none;
}
}
}
.recommend-for-you{
border-bottom: none;
}
.yoho-tip{
top:40%;
}
}
@import "comments-consults";
@import "product-description";
... ...
.good-detail-page{
.goods-desc {
padding-bottom: 20px;
padding-top: 20px;
.service {
width: 494px;
height: 28px;
margin-left: 50px;
background: resolve('product/service.png') no-repeat;
background-size: cover;
}
.detail{
margin-bottom: 1px;
}
.desc-text {
font-size: 24px;
padding: 16px 12px;
color: $mainFontC;
background-color: $tableCellC;
}
}
.tips {
color: $subFontC;
font-size: 18px;
margin-top: 20px;
}
.materials {
overflow: hidden;
&.page-block{
margin-bottom: 0;
border-bottom: none;
.detail{
margin-bottom: 0;
}
}
.detail {
.material-item{
margin: 10px 0;
width: 100%;
height: auto;
overflow: hidden;
display: block;
position: relative;
img {
margin: 0;
}
.material-image {
width: 23%;
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
}
.material-desc {
font-size: 24px;
box-sizing: border-box;
text-align: left;
padding-left: 2%;
height: auto;
line-height: 38px;
color: #4b4b4b;
word-wrap: break-word;
width: 76.9%;
float: right;
}
&:last-child{
border-bottom: none;
}
}
}
}
.wash-tips{
padding-top:20px;
&.page-block{
padding-left: 15px;
padding-right: 15px;
}
.tip{
display: inline-block;
width: 16.6%;
float:left;
img{
width: 48px;
height: 48px;
margin-bottom: 10px;
}
.caption{
display: block;
padding: 0 13px;
font-size: 18px;
line-height: 22px;
min-height: 44px;
text-align:center;
}
}
}
.product-detail {
.detail {
img {
margin-top: 20px;
width: 581px;
height:auto;
}
a {
color: #2f91f6;
text-decoration: underline;
}
}
margin-top: 30px;
margin-bottom: 30px;
}
.detail-swiper {
.swiper-wrapper {
.swiper-slide {
width: auto;
div {
text-align: center;
&.cell {
line-height: 53px;
font-size: 24px;
background-color: $tableCellC;
padding: 0 40px;
border: 1px solid #fff;
}
}
}
}
}
/*模特*/
#reference-swiper-container {
.first-group {
width: 70px;
margin-top: 55px;
div{
height: 55px;
.avatar {
display: inline-block;
width: 40px;
border-radius: 50%;
margin-top:7px;
}
}
}
}
/*测量方法*/
.measurement-method {
.detail {
width: 100%;
margin-top:0;
margin-bottom: 0;
img {
width: 100%;
height:auto;
}
}
}
}
... ...