Authored by Aiden Xu

Merge branch 'feature/product' into develop

# Conflicts:
#	config/common.js
/**
*
* @author: Aiden Xu<aiden.xu@yoho.cn>
* @date: 2016/07/19
*/
'use strict';
// const _ = require('lodash');
// const helpers = global.yoho.helpers;
const api = global.yoho.API;
const _ = require('lodash');
/**
* 商品详情
*/
const component = {
index(req, res) {
const pid = req.params[0], goodsId = req.params[1];
res.render('detail', {
module: 'product',
page: 'detail',
pid: pid,
goodsId: goodsId
});
},
product(req, res, next) {
const pid = req.params[0];// , goodsId = req.params[1];
let params = {
productId: _.toString(pid),
method: 'h5.product.data' // TODO replace this to 'app.product.data'
};
api.get('', params).then(result => {
res.json(result);
}).catch(next);
},
intro(req, res, next) {
let params = {
method: 'h5.product.intro', // TODO replace this to 'app.product.intro'
productskn: req.query.skn,
udid: 'f528764d624db129b32c21fbca0cb8d6'
};
api.get('', params).then(result => {
res.json(result);
}).catch(next);
},
/**
* 加入购物车接口
*
*/
addToCart(req, res, next) {
let params = {
method: 'app.Shopping.add',
product_sku: req.body.productSku, // 商品SKU
buy_number: req.body.buyNumber, // 购买数量
goods_type: req.body.goodsType || 0, // 商品类型,0表示普通商品,1表示加价购商品
edit_product_sku: req.body.isEdit || 0, // 是否是编辑商品SKU,0表示不是编辑
selected: 'Y',
promotion_id: req.body.promotionId || null, // 促销id,默认null(加价购有关)
uid: req.user.uid || null, // TODO: fix uid
shopping_key: global.yoho.cookie.getShoppingKey(req)
};
api.get('', params).then(result => {
res.json(result);
}).catch(next);
},
getFavorite(req, res, next) {
api.get('', {}).then(result => {
res.json(result);
}).catch(next);
},
/**
* 收藏
*
* @param req
* @param res
* @param next
*/
addFavorite(req, res, next) {
let params = {
method: 'app.Shopping.addfavorite',
product_sku_list: req.body.sku,
uid: req.user.uid || 8050378 // TODO: fix this hard coded uid
};
api.get('', params).then(result => {
res.json(result);
}).catch(next);
},
/**
* 获取购物车数量
*
* @param req
* @param res
* @param next
*/
getCartCount: (req, res, next) => {
let params = {
method: 'app.Shopping.count',
shopping_key: global.yoho.cookie.getShoppingKey(req),
uid: req.user.uid || 0 // TODO fix uid
};
api.get('', params).then(result => {
res.json(result);
}).catch(next);
}
};
module.exports = component;
... ...
/**
* sub app product
* @author: chen xuan<xuan.chen@yoho.cn>
* @date: 2016/07/19
* sub app
* @author: Bi Kai<kai.bi@yoho.cn>
* @date: 2016/05/09
*/
var express = require('express'),
path = require('path'),
hbs = require('express-handlebars');
const express = require('express');
const path = require('path');
const hbs = require('express-handlebars');
var app = express();
const app = express();
// set view engin
var doraemon = path.join(__dirname, '../../doraemon/views'); // parent view root
// set view engine
const doraemon = path.join(__dirname, '../../doraemon/views'); // parent view root
app.on('mount', function(parent) {
delete parent.locals.settings; // 不继承父 App 的设置
... ...
/**
* router of sub app product
* @author: Aiden Xu<aiden.xu@yoho.cn>
* @author: chen xuan<xuan.chen@yoho.cn>
* @date: 2016/07/19
*/
'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) => {
... ... @@ -21,4 +22,14 @@ router.use('/list', (req, res, next) => {
router.get('/list', productList.index);
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);
router.post(/cart.json/, detail.addToCart);
router.get(/favorite.json/, detail.getFavorite);
router.post(/favorite.json/, detail.addFavorite);
router.get(/cart-count.json/, detail.getCartCount);
module.exports = router;
... ...
<div id="app" class="product-page" data-pid="{{pid}}" data-goods-id="{{goodsId}}">
<app/>
</div>
... ...
... ... @@ -13,20 +13,20 @@ module.exports = {
app: 'h5',
appVersion: '4.6.0', // 调用api的版本
port: 6004,
siteUrl: '//m.yohobuy.com',
siteUrl: '//m.yohoblk.com',
domains: {
api: 'http://devapi.yoho.cn:58078/',
service: 'http://192.168.102.202:8080/gateway/'
service: 'http://devservice.yoho.cn:58077/'
},
subDomains: {
host: '.m.yohobuy.com',
default: '//m.yohobuy.com',
guang: '//guang.m.yohobuy.com',
list: '//list.m.yohobuy.com',
search: '//search.m.yohobuy.com',
huodong: '//huodong.m.yohobuy.com',
activity: '//activity.yohobuy.com',
index: '//m.yohobuy.com'
host: '.m.yohoblk.com',
default: '//m.yohoblk.com',
guang: '//guang.m.yohoblk.com',
list: '//list.m.yohoblk.com',
search: '//search.m.yohoblk.com',
huodong: '//huodong.m.yohoblk.com',
activity: '//activity.yohoblk.com',
index: '//m.yohoblk.com'
},
useOneapm: false,
useCache: false,
... ...
/**
* 路由分发
* @author: xuqi<qi.xu@yoho.cn>
*
* @author: Aiden Xu<aiden.xu@yoho.cn>
* @date: 2016/4/27
*/
... ... @@ -13,4 +14,6 @@ module.exports = app => {
if (app.locals.devEnv) {
app.use('/example', require('./apps/example'));
}
app.use('/product', require('./apps/product'));
};
... ...
... ... @@ -107,6 +107,8 @@ class Overlay {
overflow: 'auto'
});
}
this.settings.onClose();
}
}
... ...
... ... @@ -5,18 +5,42 @@ let Vue = require('yoho-vue');
* 替换参数
*
* @example
* value = /{width}/{height}/{model}
* value = /{width}/{height}/{mode}
*
* {value | resize 100 200 2} ==> /100/200/2
*/
Vue.filter('resize', (value, width, height, model)=>{
return value.replace(/({width}|{height}|{mode})/g, function($0) {
Vue.filter('resize', (value, width, height, mode)=> {
return value ? value.replace(/(\{width}|\{height}|\{mode})/g, function($0) {
const dict = {
'{width}': width,
'{height}': height,
'{mode}': model || 2
'{mode}': mode || 2
};
return dict[$0];
});
}) : '';
});
/**
* 性别款式
*
* @example
*
* {value | gender}
*/
Vue.filter('clothingGenderIdentity', (value)=> {
let ret = null;
switch (value) {
case 1:
ret = '男款';
break;
case 2:
ret = '女款';
break;
default:
ret = '通用';
}
return ret;
});
... ...
const Vue = require('yoho-vue');
const app = require('product/detail.vue');
require('../common/overlay');
new Vue({
el: '#app',
components: {
app: app
}
});
... ...
... ... @@ -12,6 +12,11 @@
&.button-solid {
background: $black;
color: $white;
&:disabled {
background: $grey;
color: $white;
}
}
&.button-round {
... ...
@charset "utf-8";
@import "common/index";
@import "example/index";
@import "product/index";
@import "channel/index";
@import "home/index";
... ...
.product-page {
background: #f6f6f6;
}
... ...
.feature-options {
display: inline-block;
}
.feature-button {
min-width: 88px;
height: 88px;
min-height: inherit;
margin-right: 20px;
&:disabled::before {
}
}
... ...
.feature-selector {
background: #FFFFFF;
width: 100%;
height: 608px;
bottom: 0;
position: fixed;
padding: 20px 30px 30px 30px;
z-index: 1001;
transform: translate3d(0, 100%, 0);
transition: all 0.1s ease-in-out;
.header {
height: 120px;
h3 {
margin: 0;
max-height: 60px;
font-weight: 300;
}
h4 {
color: #b0b0b0;
font-weight: 200;
font-size: 30px;
margin-top: 32px;
margin-bottom: 0;
}
.image-box {
width: 90px;
height: 120px;
display: inline-block;
}
.text-box {
display: inline-block;
margin-left: 24px;
max-width: 512px;
}
}
hr {
border: none;
border-top: 1px solid #F0F0F0;
margin-top: 30px;
margin-bottom: 20px;
}
ul {
list-style: none;
border: none;
margin-left: 18px;
margin-top: 30px;
margin-bottom: 0;
padding: 0;
}
li {
display: inline-block;
}
section {
h4 {
margin: 0;
font-size: 25px;
line-height: 80px;
display: inline-block;
}
}
.add-to-cart {
width: 100%;
margin-top: 50px;
font-size: 27px;
}
&.slide-in {
transform: translate3d(0, 0, 0);
}
}
... ...
<template>
<ul class="feature-options">
<li v-for="item in options">
<button :class="{ 'button-solid': value && value === item.value}"
:disabled="item.disabled"
@click="selectOption(item.value)"
class="button feature-button">
{{item.text}}
</button>
</li>
</ul>
</template>
<style src="./css/feature-options.css"></style>
<script src="./js/feature-options.js"></script>
... ...
<template>
<div class="feature-selector" :class="{ 'slide-in': isVisible }">
<div class="header">
<div class="image-box">
<img :src="selection.thumbnail | resize 45 60"/>
</div>
<div class="text-box">
<h3>{{entity.productName}}</h3>
<h4>{{entity.productPriceBo.formatSalesPrice}}</h4>
</div>
</div>
<hr>
<div>
<section>
<h4>颜色</h4>
<feature-options name="color" :options="colors" :selection="selection.color"></feature-options>
</section>
<section>
<h4>尺码</h4>
<feature-options name="size" :options="sizes" :selection="selection.size"></feature-options>
</section>
<button @click="addToCart()"
class="button button-solid add-to-cart">加入购物袋
</button>
</div>
</div>
</template>
<style src="./css/feature-selector.css"></style>
<script src="./js/feature-selector.js"></script>
... ...
module.exports = {
props: {
options: Array,
name: String,
selection: null
},
data() {
return {
value: ''
};
},
watch: {
selection() {
this.value = this.selection;
}
},
methods: {
selectOption: function(opt) {
this.value = opt;
this.$parent.$emit(`feature:${this.name}.select`, opt);
}
}
};
... ...
module.exports = {
init() {
},
props: {
isVisible: Boolean,
entity: Object,
onAddToCart: Function
},
watch: {
isVisible() {
const self = this;
if (this.isVisible) {
this.overlay = $.overlay({
onClose: function() {
self.isVisible = false;
}
});
this.overlay.show();
} else {
this.overlay.hide();
this.$parent.$emit('featureselector.close');
}
},
entity() {
const thumbnails = {};
const selection = {};
const colorSizes = {};
const stocks = {};
// 更新颜色
this.colors = this.entity.goodsList.filter((goods)=> {
// 确保商品启用
return goods.status !== 0;
}).map((goods)=> {
// 缩略图
thumbnails[goods.colorId] = goods.colorImage;
// 更新颜色对应尺码
colorSizes[goods.colorId] = goods.goodsSizeBoList.map((size)=> {
if (!stocks[goods.colorId]) {
stocks[goods.colorId] = 0;
}
// 默认选中有库存的第一个颜色尺码
if (size.goodsSizeStorageNum > 0) {
if (!selection.color) {
selection.color = goods.colorId;
}
if (!selection.size && size.goodsSizeStorageNum > 0) {
selection.size = size.goodsSizeSkuId;
}
// 计算所有尺码的库存
stocks[goods.colorId] += size.goodsSizeStorageNum;
}
return {
text: size.sizeName,
value: size.goodsSizeSkuId,
disabled: size.goodsSizeStorageNum === 0
};
});
return {
text: goods.colorName,
value: goods.colorId,
disabled: stocks[goods.colorId] === 0 // 是否售完
};
});
this.sizes = colorSizes[selection.color];
this.colorSizes = colorSizes;
this.thumbnails = thumbnails;
// 选择默认值
this.$emit('feature:color.select', selection.color);
this.$emit('feature:size.select', selection.size);
}
},
data() {
return {
colors: [],
sizes: [],
colorSizes: {},
thumbnails: {},
selection: {
color: null,
size: null,
thumbnail: ''
}
};
},
components: {
featureOptions: require('../feature-options.vue')
},
created() {
// 选择颜色
this.$on('feature:color.select', (opt)=> {
const selection = {
color: opt,
size: ((color, size)=> {
// 切换颜色后选择匹配的尺码
const sizes = this.colorSizes[color];
if (sizes && sizes.length > 0) {
const oldSizes = sizes.filter((item) => {
return item.value === size;
});
if (oldSizes && oldSizes.length > 0) {
const newSizes = this.colorSizes[opt];
const matchedSize = newSizes.filter((item)=> {
return !item.disabled && item.text === oldSizes[0].text;
});
if (matchedSize && matchedSize.length > 0) {
return matchedSize[0].value;
}
}
}
return null;
})(this.selection.color, this.selection.size),
thumbnail: this.thumbnails[opt]
};
this.sizes = this.colorSizes[opt];
Object.assign(this.selection, selection);
});
// 选择尺码
this.$on('feature:size.select', (opt)=> {
const selection = {
size: opt
};
Object.assign(this.selection, selection);
});
},
methods: {
/**
* 将当前选择添加到购物车
*/
addToCart() {
// console.log(`${this.selection.color}:${this.selection.size}`);
const sku = this.selection.size;
$.post('/product/cart.json', {
productSku: sku,
buyNumber: 1
}).then((result)=> {
this.onAddToCart(result);
});
}
}
};
... ...
.show-box .brand {
max-height: 108px;
line-height: 48px;
overflow: hidden;
img {
vertical-align: middle;
}
h2 {
font-size: 28px;
vertical-align: middle;
margin-left: 30px;
}
a {
float: right;
margin-top: 12px;
font-size: 28px;
color: #b0b0b0;
display: inline-block;
vertical-align: middle;
}
}
.separator {
text-align: center;
color: #c4c4c4;
height: 110px;
line-height: 110px;
margin-bottom: -20px;
span {
background: #f6f6f6;
padding: 0 15px;
}
hr {
max-width: 512px;
margin-top: -55px;
border: none;
border-top: 1px solid #eeeeee;
}
}
i.info {
font-style: normal;
color: #b0b0b0;
margin-top: 24px;
display: block;
font-size: 18px;
}
.image-box {
background: #ffffff;
}
.title-box {
text-align: center;
margin-bottom: 50px;
max-height: 195px;
h1 {
text-align: center;
font-size: 30px;
line-height: 48px;
font-weight: normal;
max-width: 580px;
margin: 30px auto 30px auto;
}
i.price {
color: #b0b0b0;
font-size: 32px;
font-weight: lighter;
font-style: normal;
&.strike-through {
text-decoration: line-through;
}
&.highlight {
color: #d0021b;
}
}
}
.control-box {
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: stretch;
position: fixed;
width: 100%;
height: 99px;
bottom: 0;
.control-button {
min-width: 100px;
border: none;
border-top: 1px solid #CCC;
.icon {
font-size: 40px;
}
}
.control-button:first-child {
border-right: 1px solid #CCC;
}
.button-solid {
font-size: 26px;
}
}
.horizon-wrapper {
overflow-x: scroll;
}
.table {
border-collapse: collapse;
th {
background: #f6f6f6;
}
th, td {
border: 1px solid #eeeeee;
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;
}
.badge-tr {
margin-top: -10px;
}
... ...
.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;
}
}
}
... ...
.show-box {
margin-top: 20px;
background: #ffffff;
border-top: 1px solid #eeeeee;
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;
margin: 32px 0 20px 0;
}
h2 {
margin: 0;
font-size: 32px;
text-align: left;
color: #000000;
font-weight: normal;
display: inline-block;
+ i {
font-size: 14px;
font-style: normal;
color: #b0b0b0;
font-weight: normal;
}
}
ul {
list-style: none;
padding: 0;
}
.image-box {
float: left;
}
.text-box {
float: left;
margin-left: 20px;
text-align: center;
line-height: 36px;
}
.clear-fix {
clear: both;
}
&.first-box {
margin-top: 0;
padding: 0;
}
&.last-box {
margin-bottom: 99px;
}
}
... ...
<template>
<show-box :is-first="true">
<image-carousel :goods="entity.goodsList"></image-carousel>
<div class="title-box">
<h1>{{entity.productName}}</h1>
<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 | resize 110 68" width="55" height="34"/>
<h2>{{entity.brand.brandName}}</h2>
<a href="#">
进入店铺
<span class="icon icon-right"></span>
</a>
</div>
</show-box>
<div class="separator"><span>继续拖动,查看商品信息</span>
<hr/>
</div>
<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 | clothingGenderIdentity}}</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 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 v-if="intro.sizeImage">
<h2>测量方式</h2>
<i>MEASUREMENT METHOD</i>
<hr>
<img v-if="intro.sizeImage" :src="intro.sizeImage"/>
</show-box>
<show-box v-if="intro.modelBos && intro.modelBos.length > 0">
<h2>模特试穿</h2>
<i>REFERENCE</i>
<hr>
<div class="horizon-wrapper">
<table class="table">
<thead>
<tr>
<th>模特</th>
<th>身高</th>
<th>体重</th>
<th>三围</th>
<th>吊牌尺码</th>
<th>试穿描述</th>
</tr>
</thead>
<tbody>
<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>
<i class="info">提示:左滑查看完整表格信息</i>
</show-box>
<show-box>
<div v-if="intro.productMaterialList && intro.productMaterialList.length > 0">
<h2>商品材质</h2>
<i>MATERIALS</i>
<hr>
</div>
<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>
</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">
<button class="button control-button" style="flex: 1">
<a style="position:relative">
<i class="icon icon-bag"></i>
<span v-if="cartCount > 0" class="badge badge-tr">{{cartCount}}</span>
</a>
</button>
<button class="button control-button" style="flex: 1">
<span class="icon icon-love"></span>
</button>
<button class="button button-solid" style="flex: 2"
@click="showAddToCart()"
:disabled="isSoldOut">
<span v-if="isSoldOut">
已售完
</span>
<span v-else="">
加入购物袋
</span>
</button>
</div>
<feature-selector :is-visible="showFeatureSelector" :entity="entity"
:on-add-to-cart="onAddToCart"></feature-selector>
</template>
<style src="./css/detail.css"></style>
<script src="./js/detail.js"></script>
... ...
<style src="./css/image-carousel.css"></style>
<template>
<div class="image-carousel">
<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 {};
},
components: {
swipe: swipe.Swipe,
swipeItem: swipe.SwipeItem
}
};
</script>
... ...
const app = $('#app');
const tip = require('common/tip');
require('vue-swipe/dist/vue-swipe.css');
module.exports = {
data() {
return {
intro: {},
entity: {
brand: {
brandName: '',
brandIco: ''
},
productPriceBo: {
formatMarketPrice: ''
}
},
showFeatureSelector: false,
cartCount: 0,
/**
* 加入购物车回调
*
* @param result
*/
onAddToCart: (result)=> {
// TODO: 库存不足
// TODO: 商品已下架
if (result.code === 200) {
this.cartCount = result.data.goods_count;
this.showFeatureSelector = false;
} else {
this.showFeatureSelector = false;
tip('系统异常,请稍后重试');
}
}
};
},
computed: {
isSoldOut: function() {
return this.entity.storage === 0;
}
},
components: {
imageCarousel: require('../image-carousel.vue'),
featureSelector: require('component/product/feature-selector.vue'),
showBox: require('../show-box.vue')
},
methods: {
showAddToCart: function() {
this.showFeatureSelector = true;
}
},
created() {
const self = this;
// 显示商品特征选择组件
this.$on('featureselector.close', function() {
self.showFeatureSelector = false;
});
// 读取基础数据
$.get(`/product/product_${app.data('pid')}_${app.data('goodsId')}.json`).then(result=> {
this.entity = result;
return result;
}).then((result)=> {
// 读取商品详情
return $.get('/product/product/intro.json', {skn: result.productPriceBo.productSkn});
}).then(result => {
this.intro = result;
});
// 读取购物车数量
$.get('/product/cart-count.json', {}).then(result=> {
if (result.code === 200) {
this.cartCount = result.data.cart_goods_count;
}
});
}
};
... ...
<template>
<div class="show-box" :class="{ 'first-box': isFirst, 'last-box': isLast }">
<slot></slot>
</div>
</template>
<style src="./css/show-box.css"></style>
<script>
module.exports = {
props: {
isFirst: [Boolean],
isLast: [Boolean]
},
data() {
return {};
}
};
</script>
... ...