Authored by Aiden Xu

商品详情

... ... @@ -36,6 +36,17 @@ const component = {
api.get('', params).then(result => {
res.json(result);
}).catch(next);
},
intro: (req, res, next) => {
let params = {
method: 'h5.product.intro',
productskn: req.query.skn,
udid: 'f528764d624db129b32c21fbca0cb8d6'
};
api.get('', params).then(result => {
res.json(result);
}).catch(next);
}
};
... ...
... ... @@ -7,11 +7,11 @@
'use strict';
const Router = require('express').Router;
const expressRouter = require('express').Router;
const cRoot = './controllers';
const productList = require(`${cRoot}/list`);
const router = Router();
const router = expressRouter();
// 商品列表
router.use('/list', (req, res, next) => {
... ... @@ -24,7 +24,9 @@ router.post('/list', productList.getProducts);
// 商品详情controller
const detail = require(`${cRoot}/detail`);
router.get(/\/pro_([\d]+)_([\d]+)\/(.*)/, detail.index); // 商品详情routers
router.get(/\/product_([\d]+)_([\d]+)\.json/, detail.product);
router.get(/\/intro\.json/, detail.intro);
module.exports = router;
... ...
... ... @@ -15,8 +15,10 @@ module.exports = {
port: 6004,
siteUrl: '//m.yohobuy.com',
domains: {
api: 'http://devapi.yoho.cn:58078/',
service: 'http://123.206.1.104:28077/'
// api: 'http://devapi.yoho.cn:58078/',
// service: 'http://123.206.1.104:28077/'
api: 'http://api.yoho.yohoops.org/',
service: 'http://service.yoho.yohoops.org/'
},
subDomains: {
host: '.m.yohobuy.com',
... ...
... ... @@ -57,7 +57,6 @@
"handlebars": "^4.0.5",
"handlebars-loader": "^1.3.0",
"husky": "^0.11.4",
"node-sass": "^3.8.0",
"nodemon": "1.9.2",
"postcss-assets": "^4.0.1",
"postcss-cachebuster": "^0.1.3",
... ... @@ -71,13 +70,11 @@
"postcss-sprites": "^3.1.2",
"postcss-use": "^2.2.0",
"precss": "^1.4.0",
"sass-loader": "^4.0.0",
"shelljs": "^0.7.0",
"style-loader": "^0.13.1",
"stylelint": "^6.9.0",
"stylelint-config-yoho": "1.2.5",
"vue-loader": "^8.5.3",
"vue-swipe": "^0.2.6",
"webpack": "^1.13.1",
"webpack-dev-server": "^1.14.1",
"webpack-stream": "^3.1.0",
... ...
... ... @@ -21,7 +21,6 @@
display: inline-block;
vertical-align: middle;
}
}
.separator {
... ... @@ -75,8 +74,15 @@ i.info {
font-size: 32px;
font-weight: lighter;
font-style: normal;
}
&.strike-through {
text-decoration: line-through;
}
&.highlight {
color: #d0021b;
}
}
}
.control-box {
... ... @@ -123,10 +129,45 @@ i.info {
th, td {
border: 1px solid #eeeeee;
min-width: 162px;
min-width: 170px;
line-height: 66px;
text-align: center;
vertical-align: middle;
}
}
.wash-condition {
display: flex;
justify-content: space-around;
}
.wash-condition-item {
flex: 1;
text-align: center;
}
.description {
font-size: 0;
li {
font-size: 24px;
width: 325px;
line-height: 40px;
display: inline-block;
}
.desc-caption {
color: #c7c7c7;
min-width: 100px;
}
}
.model-avatar {
vertical-align: middle;
border-radius: 100%;
}
.model-name {
width: 100px;
display: inline-block;
}
... ...
.image-carousel {
width: 100%;
height: 1000px;
.swipe {
height: 100%;
}
.swipe-indicators {
left: auto;
right: 32px;
}
.swipe-indicator {
width: 8px;
height: 8px;
line-height: 12px;
display: inline-block;
&.active {
width: 12px;
height: 12px;
background: #000;
opacity: 0.6;
margin: -2px 5px;
}
}
}
... ...
... ... @@ -5,6 +5,17 @@
border-bottom: 1px solid #eeeeee;
padding: 30px;
img {
max-width: 100%;
height: auto !important;
}
p {
color: #808080;
font-size: 24px;
line-height: 48px;
}
hr {
border: none;
border-bottom: 1px solid #eeeeee;
... ... @@ -27,6 +38,25 @@
}
}
ul {
list-style: none;
padding: 0;
}
.image-box {
float: left;
}
.text-box {
float: left;
margin-left: 20px;
text-align: center;
}
.clear-fix {
clear: both;
}
&.first-box {
margin-top: 0;
padding: 0;
... ...
<template>
<show-box :is-first="true">
<div>
<image-carousel></image-carousel>
</div>
<image-carousel :goods="entity.goodsList"></image-carousel>
<div class="title-box">
<h1>{{entity.productName}}</h1>
<i class="price">{{entity.productPriceBo.formatMarketPrice}}</i>
<i class="price" :class="{'strike-through': entity.productPriceBo.salesPrice > 0}">{{entity.productPriceBo.formatMarketPrice}}</i>
<i v-if="entity.productPriceBo.salesPrice > 0" class="price highlight">
{{entity.productPriceBo.formatSalesPrice}}
</i>
</div>
</show-box>
<show-box>
<div class="brand">
<img src={{entity.brand.brandIco}} width="55" height="34"/>
<img :src="entity.brand.brandIco | resize 110 68" width="55" height="34"/>
<h2>{{entity.brand.brandName}}</h2>
<a href="#">
... ... @@ -22,26 +24,63 @@
</div>
</show-box>
<div class="separator"><span>继续拖动,查看商品信息</span><hr/></div>
<div class="separator"><span>继续拖动,查看商品信息</span>
<hr/>
</div>
<show-box>
<show-box v-if="intro.productDescBo">
<h2>商品信息</h2>
<i>DESCRIPTION</i>
<hr>
<ul class="description">
<li>
<span class="desc-caption">编号:</span>
<span>{{intro.productDescBo.erpProductId}}</span>
</li>
<li>
<span class="desc-caption">颜色:</span>
<span>{{intro.productDescBo.colorName}}</span>
</li>
<li>
<span class="desc-caption">性别:</span>
<span>{{intro.productDescBo.gender === 1 ? '男款' : '女款'}}</span>
</li>
<li v-for="item in intro.productDescBo.standardBos">
<span class="desc-caption">{{item.standardName}}:</span> <span>{{item.standardVal}}</span>
</li>
</ul>
</show-box>
<show-box>
<show-box v-if="intro.sizeInfoBo">
<h2>尺码信息</h2>
<i>SIZE INFO</i>
<hr>
<div class="horizon-wrapper">
<table class="table">
<thead>
<th>吊牌尺码</th>
<th v-for="header in intro.sizeInfoBo.sizeAttributeBos">{{header.attributeName}}</th>
</thead>
<tbody>
<tr v-for="size in intro.sizeInfoBo.sizeBoList">
<td>{{size.sizeName}}</td>
<td v-for="item in size.sortAttributes">{{item.sizeValue}}</td>
</tr>
</tbody>
</table>
</div>
<i class="info">提示:左滑查看完整表格信息</i>
</show-box>
<show-box>
<show-box v-if="intro.sizeImage">
<h2>测量方式</h2>
<i>MEASUREMENT METHOD</i>
<hr>
<img v-if="intro.sizeImage" :src="intro.sizeImage"/>
</show-box>
<show-box>
... ... @@ -51,18 +90,27 @@
<div class="horizon-wrapper">
<table class="table">
<thead>
<th>模特</th>
<th>身高</th>
<th>体重</th>
<th>三围</th>
<th>三围</th>
<tr>
<th>模特</th>
<th>身高</th>
<th>体重</th>
<th>三围</th>
<th>吊牌尺码</th>
<th>试穿描述</th>
</tr>
</thead>
<tbody>
<td>Oliver</td>
<td>175</td>
<td>51</td>
<td>78/70/87</td>
<td>78/70/87</td>
<tr v-for="item in intro.modelBos">
<td>
<img class="model-avatar" :src="item.avatar"/>
<span class="model-name">{{item.modelName}}</span>
</td>
<td>{{item.height}}</td>
<td>{{item.weight}}</td>
<td>{{item.vitalStatistics}}</td>
<td>{{item.fitModelBo.fit_size}}</td>
<td>{{item.fitModelBo.feel}}</td>
</tr>
</tbody>
</table>
</div>
... ... @@ -70,26 +118,48 @@
</show-box>
<show-box>
<h2>商品材质</h2>
<i>MATERIALS</i>
<hr>
<div>
<div class="image-box">
<img src="#" width="86" height="35"/>
</div>
<div class="text-box">
<div>涤纶</div>
<div>Terylene</div>
</div>
<div v-if="intro.productMaterialList && intro.productMaterialList.length > 0">
<h2>商品材质</h2>
<i>MATERIALS</i>
<hr>
</div>
<p>
用各种洗涤剂,可手洗机洗,但不宜氯漂,宜阴干,避免曝晒,以免深色衣物褪色,在日光下晾晒时,将里面朝外。浸泡时间不能太长,避免褪色。
</p>
<div v-if="intro.productMaterialList">
<ul v-for="item in intro.productMaterialList">
<div>
<div class="image-box">
<img :src="item.imageUrl" width="86" height="35"/>
</div>
<div class="text-box">
<div>{{item.caption}}</div>
<div>{{item.encaption}}</div>
</div>
<div class="clear-fix"/>
</div>
<p>
{{item.remark}}
</p>
<hr/>
</ul>
</div>
<ul class="wash-condition">
<li class="wash-condition-item" v-for="item in intro.washTipsBoList">
<img :src="item.img" width="25" height="25"/>
<div>{{item.caption}}</div>
</li>
</ul>
</show-box>
<show-box :is-last="true">
<h2>商品详情</h2>
<i>DETAILS</i>
<p>
{{{entity.brand.brandIntro}}}
</p>
<p v-if="intro.productIntroBo">
{{{intro.productIntroBo.productIntro}}}
</p>
</show-box>
<div class="control-box">
... ...
<style>
.image-carousel {
width: 100%;
height: 1000px;
background-color: #efefef;
}
</style>
<style src="./css/image-carousel.css"></style>
<template>
<div class="image-carousel">
<img src="" alt="">
<swipe>
<swipe-item v-for="item in goods">
<a href="#" title="{{item.title}}">
<img :src="item.colorImage | resize 750 1000" width="375" height="500" alt="">
</a>
</swipe-item>
</swipe>
</div>
</template>
<script>
const swipe = require('vue-swipe');
require('common/vue-filter');
module.exports = {
props: {
goods: [Object]
},
data() {
return {
};
return {};
},
components: {
swipe: swipe.Swipe,
swipeItem: swipe.SwipeItem
}
};
</script>
... ...
const app = $('#app');
require('vue-swipe/dist/vue-swipe.css');
module.exports = {
data() {
return {
intro: {},
entity: {
brand: {
brandName: '',
... ... @@ -16,9 +19,9 @@ module.exports = {
};
},
components: {
'image-carousel': require('../image-carousel.vue'),
'feature-selector': require('component/product/feature-selector.vue'),
'show-box': require('../show-box.vue')
imageCarousel: require('../image-carousel.vue'),
featureSelector: require('component/product/feature-selector.vue'),
showBox: require('../show-box.vue')
},
methods: {
showAddToCart: function() {
... ... @@ -33,8 +36,12 @@ module.exports = {
});
$.get(`/product/product_${app.data('pid')}_${app.data('goodsId')}.json`).then(result=> {
// console.log(result);
this.entity = result;
return result;
}).then((result)=> {
return $.get('/product/product/intro.json', {skn: result.productPriceBo.productSkn});
}).then(result => {
this.intro = result;
});
}
};
... ...