feat: 迁移sku组件

This commit is contained in:
niunai
2017-09-08 16:25:07 +08:00
parent 0c69e70a12
commit 8f4122f8ad
20 changed files with 1890 additions and 216 deletions
+34
View File
@@ -0,0 +1,34 @@
<template>
<div class="van-sku-actions">
<button v-if="showAddCartBtn" class="van-sku__add-cart-btn" @click="onAddCartClicked">
加入购物车
</button>
<button class="van-sku__buy-btn" @click="onBuyClicked">
{{ buyText }}
</button>
</div>
</template>
<script>
export default {
name: 'van-sku-actions',
props: {
skuEventBus: Object,
showAddCartBtn: Boolean,
buyText: {
type: String,
default: '立即购买'
}
},
methods: {
onAddCartClicked() {
this.skuEventBus.$emit('sku:addCart');
},
onBuyClicked() {
this.skuEventBus.$emit('sku:buy');
}
}
};
</script>
+65
View File
@@ -0,0 +1,65 @@
<template>
<div class="van-sku-header">
<div class="van-sku-header__img-wrap">
<img class="van-sku__goods-img" :src="goodsImg">
</div>
<div class="van-sku-header__goods-info">
<div class="van-sku__goods-name">{{ goods.title }}</div>
<div class="van-sku__goods-price"><span class="van-sku__price-symbol"></span><span class="van-sku__price-num">{{ price }}</span></div>
<span class="van-sku__close-icon" @click="onCloseClicked"></span>
</div>
</div>
</template>
<script>
import find from 'lodash/find';
import urlHelper from 'zan-utils/url/helper';
export default {
name: 'van-sku-header',
props: {
skuEventBus: Object,
sku: Object,
selectedSku: Object,
selectedSkuComb: Object,
goods: Object
},
computed: {
skuTree() {
return this.sku.tree;
},
goodsImg() {
const s1Id = this.selectedSku.s1;
const skuImg = this.getSkuImg(s1Id);
return skuImg || this.goods.picture;
},
price() {
if (this.selectedSkuComb) {
return (this.selectedSkuComb.price / 100).toFixed(2);
}
// sku.price是一个格式化好的价格区间
return this.sku.price;
}
},
methods: {
onCloseClicked() {
this.skuEventBus.$emit('sku:close');
},
getSkuImg(id) {
if (!id) return;
// 目前skuImg都挂载在skuTree中s1那类sku上
const treeItem = find(this.skuTree, (treeItem) => treeItem.k_s === 's1') || {};
const matchedSku = find(treeItem.v, (skuValue) => skuValue.id === id);
if (matchedSku && matchedSku.imgUrl) {
return urlHelper.getCdnImageUrl(matchedSku.imgUrl);
}
}
}
};
</script>
+156
View File
@@ -0,0 +1,156 @@
<template>
<van-cell-group>
<template v-for="(message, index) in internalMessages">
<template v-if="message.type === 'image'"></template>
<van-field v-else-if="message.multiple == '1'"
:key="index"
:required="message.required == '1'"
:label="message.name"
placeholder="点击填写段落文本"
type="textarea"
v-model="messageValues[index]">
</van-field>
<van-field v-else
:key="index"
:required="message.required == '1'"
:label="message.name"
:placeholder="PLACEHOLDER_MAP[message.type]"
:type="getType(message)"
v-model="messageValues[index]">
</van-field>
</template>
</van-cell-group>
</template>
<script>
import isEmpty from 'lodash/isEmpty';
import Field from 'packages/field';
import CellGroup from 'packages/cell-group';
import validateEmail from 'zan-utils/validate/email';
import validateNumber from 'zan-utils/validate/number';
const PLACEHOLDER_MAP = {
'id_no': '输入18位身份证号码',
text: '输入文本',
tel: '输入数字',
email: '输入邮箱',
date: '点击选择日期',
time: '点击选择时间'
};
export default {
name: 'van-sku-messages',
components: {
[Field.name]: Field,
[CellGroup.name]: CellGroup
},
props: {
messages: Array
},
data() {
return {
PLACEHOLDER_MAP
};
},
// for debug
// watch: {
// messageValues() {
// console.log(this.messageValues);
// }
// },
computed: {
internalMessages() {
if (Object.prototype.toString.call(this.messages) === '[object Array]') {
return this.messages;
}
return [];
},
messageValues() {
const messageValues = [];
this.internalMessages.forEach((message, index) => {
messageValues[index] = '';
});
return messageValues;
}
},
methods: {
getType({ type, datetime }) {
if (type === 'id_no') return 'text';
return datetime > 0 ? 'datetime-local' : type;
},
getMessages() {
const messages = {};
this.messageValues.forEach((value, index) => {
if (this.internalMessages[index].datetime > 0) {
value = value.replace(/T/g, ' ');
}
messages[`message_${index}`] = value;
});
return messages;
},
getCartMessages() {
const messages = {};
this.messageValues.forEach((value, index) => {
const message = this.internalMessages[index];
if (message.datetime > 0) {
value = value.replace(/T/g, ' ');
}
messages[message.name] = value;
});
return messages;
},
validateMessages() {
const values = this.messageValues;
for (let i = 0; i < values.length; i++) {
const value = values[i];
const message = this.internalMessages[i];
if (isEmpty(value)) {
// 必填字段的校验
if (message.required == '1') { // eslint-disable-line
if (message.type === 'image') {
continue;
// return `请上传${message.name}`;
} else {
return `请填写${message.name}`;
}
}
} else {
// if (message.type == 'image') {
// loaded = _this.$el.find('#ipt-' + j).data('uploaded');
// if (loaded == 'false' || !loaded) {
// return '图片还在上传中,请稍等。。';
// }
// }
if (message.type === 'tel' && !validateNumber(value)) {
return '请填写正确的数字格式留言';
}
if (message.type === 'email' && !validateEmail(value)) {
return '请填写正确的邮箱';
}
if (message.type === 'id_no' && (value.length < 15 || value.length > 18)) {
return '请填写正确的身份证号码';
}
}
if (value.length > 200) {
return `${message.name} 写的太多了<br/>不要超过200字`;
}
}
}
}
};
</script>
+100
View File
@@ -0,0 +1,100 @@
<template>
<div class="van-sku-quantity-stock">
<div class="van-sku-quantity-container">
<div class="van-sku__quantity-title">{{ quantityTitle }}</div>
<van-quantity v-model="currentNum" :min="1" :max="quantityLimit" class="van-sku__quantity" @overlimit="handleOverLimit"></van-quantity>
</div>
<div v-if="!hideStock" class="van-sku__stock">剩余{{ stock }}</div>
<div v-if="quota > 0" class="van-sku__quota">每人限购{{ quota }}</div>
</div>
</template>
<script>
import Quantity from 'packages/quantity';
import { LIMIT_TYPE } from '../constants';
const { QUOTA_LIMIT, STOCK_LIMIT } = LIMIT_TYPE;
export default {
name: 'van-sku-quantity',
components: {
[Quantity.name]: Quantity
},
props: {
skuEventBus: Object,
sku: Object,
selectedSku: Object,
selectedSkuComb: Object,
selectedNum: Number,
quota: Number,
quotaUsed: Number,
hideStock: {
type: Boolean,
default: false
},
quantityTitle: {
type: String,
default: '购买数量'
}
},
data() {
return {
currentNum: this.selectedNum,
// 购买限制类型: 限购/库存
limitType: STOCK_LIMIT
};
},
watch: {
currentNum(num) {
this.skuEventBus.$emit('sku:numChange', num);
},
quantityLimit(limit) {
if (limit < this.currentNum) {
this.currentNum = limit;
}
}
},
computed: {
stock() {
if (this.selectedSkuComb) {
return this.selectedSkuComb.stock_num;
}
return this.sku.stock_num;
},
quantityLimit() {
const quotaLimit = this.quota - this.quotaUsed;
let limit;
// 无限购时直接取库存,有限购时取限购数和库存数中小的那个
if (this.quota > 0 && quotaLimit <= this.stock) {
// 修正负的limit
limit = quotaLimit < 0 ? 0 : quotaLimit;
this.limitType = QUOTA_LIMIT;
} else {
limit = this.stock;
}
return limit;
}
},
methods: {
setCurrentNum(num) {
this.currentNum = num;
},
handleOverLimit(action) {
this.skuEventBus.$emit('sku:overLimit', {
action,
limitType: this.limitType,
quota: this.quota,
quotaUsed: this.quotaUsed
});
}
}
};
</script>
+36
View File
@@ -0,0 +1,36 @@
<template>
<div class="van-sku-row">
<div class="van-sku-row__title">{{ skuRow.k }}</div>
<div class="van-sku-row__items">
<slot name="sku-row-items">
<van-sku-row-item
v-for="(skuValue, index) in skuRow.v"
:key="index"
:skuKeyStr="skuRow.k_s"
:skuValue="skuValue"
:skuEventBus="$attrs.skuEventBus"
:selectedSku="$attrs.selectedSku"
:skuList="$attrs.skuList">
</van-sku-row-item>
</slot>
</div>
</div>
</template>
<script>
import SkuRowItem from './SkuRowItem';
export default {
name: 'van-sku-row',
inheritAttrs: false,
components: {
[SkuRowItem.name]: SkuRowItem
},
props: {
skuRow: Object
}
};
</script>
+54
View File
@@ -0,0 +1,54 @@
<template>
<span v-if="isChoosable"
@click="onSkuSelected"
:class="{ 'van-sku-row__item': true, 'van-sku-row__item--active': isChoosed }">
{{ skuValue.name }}
</span>
<span v-else class="van-sku-row__item van-sku-row__item--disabled">{{ skuValue.name }}</span>
</template>
<script>
import assign from 'lodash/assign';
import filter from 'lodash/filter';
import keys from 'lodash/keys';
import every from 'lodash/every';
export default {
name: 'van-sku-row-item',
props: {
skuEventBus: Object,
skuValue: Object,
skuList: Array,
selectedSku: Object,
skuKeyStr: String
},
computed: {
isChoosed() {
return this.skuValue.id === this.selectedSku[this.skuKeyStr];
},
isChoosable() {
const matchedSku = assign({}, this.selectedSku, {
[this.skuKeyStr]: this.skuValue.id
});
const skusToCheck = filter(keys(matchedSku), skuKey => matchedSku[skuKey] !== '');
const filteredSku = filter(this.skuList, sku => {
return every(skusToCheck, function(skuKey) {
// 后端给的skuValue.id有时候是数字有时候是字符串,全等会匹配不上
return matchedSku[skuKey] == sku[skuKey]; // eslint-disable-line
});
});
const stock = filteredSku.reduce((total, sku) => (total += sku.stock_num), 0);
return stock > 0;
}
},
methods: {
onSkuSelected() {
this.skuEventBus.$emit('sku:select', assign({}, this.skuValue, { skuKeyStr: this.skuKeyStr }));
}
}
};
</script>