[improvement] rename packages dir to src (#3659)
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
<template>
|
||||
<demo-section>
|
||||
<demo-block :title="$t('basicUsage')">
|
||||
<van-coupon-cell
|
||||
:coupons="coupons"
|
||||
:chosen-coupon="chosenCoupon"
|
||||
@click="showList = true"
|
||||
/>
|
||||
|
||||
<van-popup
|
||||
v-model="showList"
|
||||
position="bottom"
|
||||
>
|
||||
<van-coupon-list
|
||||
:coupons="coupons"
|
||||
:chosen-coupon="chosenCoupon"
|
||||
:disabled-coupons="disabledCoupons"
|
||||
@change="onChange"
|
||||
@exchange="onExchange"
|
||||
/>
|
||||
</van-popup>
|
||||
</demo-block>
|
||||
</demo-section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* eslint-disable camelcase */
|
||||
export default {
|
||||
i18n: {
|
||||
'zh-CN': {
|
||||
coupon: {
|
||||
name: '优惠券名称',
|
||||
reason: '优惠券不可用原因',
|
||||
description: '描述信息'
|
||||
},
|
||||
exchange: '兑换成功'
|
||||
},
|
||||
'en-US': {
|
||||
coupon: {
|
||||
name: 'Coupon name',
|
||||
reason: 'Coupon unavailable reason',
|
||||
description: 'Description'
|
||||
},
|
||||
exchange: 'Success'
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
showList: false,
|
||||
chosenCoupon: -1,
|
||||
exchangedCoupons: []
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
coupons() {
|
||||
return [this.coupon, this.discountCoupon, ...this.exchangedCoupons];
|
||||
},
|
||||
|
||||
disabledCoupons() {
|
||||
return [this.disabledCoupon, this.disabledDiscountCoupon];
|
||||
},
|
||||
|
||||
coupon() {
|
||||
return {
|
||||
id: 1,
|
||||
condition: '无使用门槛\n最多优惠12元',
|
||||
reason: '',
|
||||
value: 150,
|
||||
name: this.$t('coupon.name'),
|
||||
description: this.$t('coupon.description'),
|
||||
startAt: 1489104000,
|
||||
endAt: 1514592000,
|
||||
valueDesc: '1.5',
|
||||
unitDesc: '元'
|
||||
};
|
||||
},
|
||||
|
||||
discountCoupon() {
|
||||
return {
|
||||
...this.coupon,
|
||||
id: 2,
|
||||
value: 12,
|
||||
valueDesc: '8.8',
|
||||
unitDesc: '折'
|
||||
};
|
||||
},
|
||||
|
||||
disabledCoupon() {
|
||||
return {
|
||||
...this.coupon,
|
||||
id: 3,
|
||||
reason: this.$t('coupon.reason')
|
||||
};
|
||||
},
|
||||
|
||||
disabledDiscountCoupon() {
|
||||
return {
|
||||
...this.discountCoupon,
|
||||
valueDesc: '1',
|
||||
unitDesc: '折',
|
||||
id: 4,
|
||||
reason: this.$t('coupon.reason')
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onChange(index) {
|
||||
this.showList = false;
|
||||
this.chosenCoupon = index;
|
||||
},
|
||||
onExchange() {
|
||||
this.$toast(this.$t('exchange'));
|
||||
this.exchangedCoupons.push({
|
||||
...this.coupon,
|
||||
id: this.randomId()
|
||||
});
|
||||
},
|
||||
randomId(max = 999999) {
|
||||
return Math.floor(Math.random() * max) + 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.demo-coupon-list {
|
||||
.van-popup {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,121 @@
|
||||
# Coupon
|
||||
|
||||
### Install
|
||||
|
||||
``` javascript
|
||||
import { CouponCell, CouponList } from 'vant';
|
||||
|
||||
Vue.use(CouponCell).use(CouponList);
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```html
|
||||
<!-- Coupon Cell -->
|
||||
<van-coupon-cell
|
||||
:coupons="coupons"
|
||||
:chosen-coupon="chosenCoupon"
|
||||
@click="showList = true"
|
||||
/>
|
||||
|
||||
<!-- Coupon List -->
|
||||
<van-popup v-model="showList" position="bottom">
|
||||
<van-coupon-list
|
||||
:coupons="coupons"
|
||||
:chosen-coupon="chosenCoupon"
|
||||
:disabled-coupons="disabledCoupons"
|
||||
@change="onChange"
|
||||
@exchange="onExchange"
|
||||
/>
|
||||
</van-popup>
|
||||
```
|
||||
|
||||
```javascript
|
||||
const coupon = {
|
||||
available: 1,
|
||||
originCondition: 0,
|
||||
reason: '',
|
||||
value: 150,
|
||||
name: 'Coupon name',
|
||||
startAt: 1489104000,
|
||||
endAt: 1514592000,
|
||||
valueDesc: '1.5',
|
||||
unitDesc: '元'
|
||||
};
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
chosenCoupon: -1,
|
||||
coupons: [coupon],
|
||||
disabledCoupons: [coupon]
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onChange(index) {
|
||||
this.showList = false;
|
||||
this.chosenCoupon = index;
|
||||
},
|
||||
onExchange(code) {
|
||||
this.coupons.push(coupon);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### CouponCell Props
|
||||
|
||||
| Attribute | Description | Type | Default |
|
||||
|------|------|------|------|
|
||||
| title | Cell title | `String` | `Coupon` |
|
||||
| chosen-coupon | Index of chosen coupon | `Number` | `-1` |
|
||||
| coupons | Coupon list | `Array` | `[]` |
|
||||
| editable | Cell editable | `Boolean` | `true` |
|
||||
| border | Whether to show innner border | `Boolean` | `true` |
|
||||
| currency | Currency symbol | `String` | `¥` |
|
||||
|
||||
### CouponList Props
|
||||
|
||||
| Attribute | Description | Type | Default |
|
||||
|------|------|------|------|
|
||||
| v-model | Current exchange code | `String` | - |
|
||||
| chosen-coupon | Index of chosen coupon | `Number` | `-1` |
|
||||
| coupons | Coupon list | `Array` | `[]` |
|
||||
| disabled-coupons | Disabled coupon list | `Array` | `[]` |
|
||||
| enabled-title | Title of coupon list | `String` | `Available` | - |
|
||||
| disabled-title | Title of disabled coupon list | `String` | `Unavailable` | - |
|
||||
| exchange-button-text | Exchange button text | `String` | `Exchange` |
|
||||
| exchange-button-loading | Whether to show loading in exchange button | `Boolean` | `false` |
|
||||
| exchange-button-disabled | Whether to disable exchange button | `Boolean` | `false` |
|
||||
| exchange-min-length | Min length to enable exchange button | `Number` | `1` |
|
||||
| displayed-coupon-index | Index of displayed coupon | `Number` | - |
|
||||
| close-button-text | Close button text | `String` | `Close` |
|
||||
| input-placeholder | Input placeholder | `String` | `Coupon code` |
|
||||
| currency | Currency symbol | `String` | `¥` |
|
||||
|
||||
### CouponList Events
|
||||
|
||||
| Event | Description | Arguments |
|
||||
|------|------|------|
|
||||
| change | Triggered when change chosen coupon | index: index of chosen coupon |
|
||||
| exchange | Triggered when exchange coupon | code: exchange code |
|
||||
|
||||
### Coupon Item Data Structure
|
||||
|
||||
| key | Description | Type |
|
||||
|------|------|------|
|
||||
| id | Id | `String` |
|
||||
| name | Name | `String` |
|
||||
| condition | Condition | `String` |
|
||||
| startAt | Start time (Timestmap, unit second) | `Number` |
|
||||
| endAt | End time (Timestmap, unit second) | `Number` |
|
||||
| description | Description | `String` |
|
||||
| reason | Unavailable reason | `String` |
|
||||
| value | Value | `Number` |
|
||||
| valueDesc | Value Text | `String` |
|
||||
| unitDesc | Unit Text | `String` |
|
||||
@@ -0,0 +1,215 @@
|
||||
import { createNamespace } from '../utils';
|
||||
import Tab from '../tab';
|
||||
import Tabs from '../tabs';
|
||||
import Field from '../field';
|
||||
import Button from '../button';
|
||||
import Coupon from '../coupon';
|
||||
|
||||
const [createComponent, bem, t] = createNamespace('coupon-list');
|
||||
const EMPTY_IMAGE = 'https://img.yzcdn.cn/vant/coupon-empty.png';
|
||||
|
||||
export default createComponent({
|
||||
model: {
|
||||
prop: 'code'
|
||||
},
|
||||
|
||||
props: {
|
||||
code: String,
|
||||
coupons: Array,
|
||||
disabledCoupons: Array,
|
||||
closeButtonText: String,
|
||||
inputPlaceholder: String,
|
||||
enabledTitle: String,
|
||||
disabledTitle: String,
|
||||
exchangeButtonText: String,
|
||||
exchangeButtonLoading: Boolean,
|
||||
exchangeButtonDisabled: Boolean,
|
||||
exchangeMinLength: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
chosenCoupon: {
|
||||
type: Number,
|
||||
default: -1
|
||||
},
|
||||
displayedCouponIndex: {
|
||||
type: Number,
|
||||
default: -1
|
||||
},
|
||||
showExchangeBar: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
showCloseButton: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
currency: {
|
||||
type: String,
|
||||
default: '¥'
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
tab: 0,
|
||||
winHeight: window.innerHeight,
|
||||
currentCode: this.code || ''
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
buttonDisabled() {
|
||||
return (
|
||||
!this.exchangeButtonLoading &&
|
||||
(this.exchangeButtonDisabled ||
|
||||
!this.currentCode ||
|
||||
this.currentCode.length < this.exchangeMinLength)
|
||||
);
|
||||
},
|
||||
|
||||
listStyle() {
|
||||
return {
|
||||
height: this.winHeight - (this.showExchangeBar ? 140 : 94) + 'px'
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
code(code) {
|
||||
this.currentCode = code;
|
||||
},
|
||||
|
||||
currentCode(code) {
|
||||
this.$emit('input', code);
|
||||
},
|
||||
|
||||
displayedCouponIndex(val) {
|
||||
this.scrollToShowCoupon(val);
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.scrollToShowCoupon(this.displayedCouponIndex);
|
||||
},
|
||||
|
||||
methods: {
|
||||
onClickExchangeButton() {
|
||||
this.$emit('exchange', this.currentCode);
|
||||
|
||||
// auto clear currentCode when not use vModel
|
||||
if (!this.code) {
|
||||
this.currentCode = '';
|
||||
}
|
||||
},
|
||||
|
||||
// scroll to show specific coupon
|
||||
scrollToShowCoupon(index) {
|
||||
if (index === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$nextTick(() => {
|
||||
const { card, list } = this.$refs;
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (list && card && card[index]) {
|
||||
list.scrollTop = card[index].$el.offsetTop - 100;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
renderEmpty() {
|
||||
return (
|
||||
<div class={bem('empty')}>
|
||||
<img src={EMPTY_IMAGE} />
|
||||
<p>{t('empty')}</p>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
renderExchangeButton() {
|
||||
return (
|
||||
<Button
|
||||
size="small"
|
||||
type="danger"
|
||||
class={bem('exchange')}
|
||||
text={this.exchangeButtonText || t('exchange')}
|
||||
loading={this.exchangeButtonLoading}
|
||||
disabled={this.buttonDisabled}
|
||||
onClick={this.onClickExchangeButton}
|
||||
/>
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
render(h) {
|
||||
const { coupons, disabledCoupons } = this;
|
||||
const title = `${this.enabledTitle || t('enable')} (${coupons.length})`;
|
||||
const disabledTitle = `${this.disabledTitle || t('disabled')} (${
|
||||
disabledCoupons.length
|
||||
})`;
|
||||
|
||||
const ExchangeBar = this.showExchangeBar && (
|
||||
<Field
|
||||
vModel={this.currentCode}
|
||||
clearable
|
||||
border={false}
|
||||
class={bem('field')}
|
||||
placeholder={this.inputPlaceholder || t('placeholder')}
|
||||
maxlength="20"
|
||||
scopedSlots={{
|
||||
button: this.renderExchangeButton
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
const onChange = index => () => this.$emit('change', index);
|
||||
|
||||
const CouponTab = (
|
||||
<Tab title={title}>
|
||||
<div class={bem('list')} style={this.listStyle}>
|
||||
{coupons.map((coupon, index) => (
|
||||
<Coupon
|
||||
ref="card"
|
||||
key={coupon.id}
|
||||
coupon={coupon}
|
||||
currency={this.currency}
|
||||
chosen={index === this.chosenCoupon}
|
||||
nativeOnClick={onChange(index)}
|
||||
/>
|
||||
))}
|
||||
{!coupons.length && this.renderEmpty()}
|
||||
</div>
|
||||
</Tab>
|
||||
);
|
||||
|
||||
const DisabledCouponTab = (
|
||||
<Tab title={disabledTitle}>
|
||||
<div class={bem('list')} style={this.listStyle}>
|
||||
{disabledCoupons.map(coupon => (
|
||||
<Coupon disabled key={coupon.id} coupon={coupon} currency={this.currency} />
|
||||
))}
|
||||
{!disabledCoupons.length && this.renderEmpty()}
|
||||
</div>
|
||||
</Tab>
|
||||
);
|
||||
|
||||
return (
|
||||
<div class={bem()}>
|
||||
{ExchangeBar}
|
||||
<Tabs vModel={this.tab} class={bem('tab')} line-width={120}>
|
||||
{CouponTab}
|
||||
{DisabledCouponTab}
|
||||
</Tabs>
|
||||
<Button
|
||||
vShow={this.showCloseButton}
|
||||
size="large"
|
||||
class={bem('close')}
|
||||
text={this.closeButtonText || t('close')}
|
||||
onClick={onChange(-1)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,47 @@
|
||||
@import '../style/var';
|
||||
|
||||
.van-coupon-list {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
background-color: @coupon-list-background-color;
|
||||
|
||||
&__field {
|
||||
padding: @coupon-list-field-padding;
|
||||
}
|
||||
|
||||
&__exchange {
|
||||
height: @coupon-list-exchange-button-height;
|
||||
line-height: @coupon-list-exchange-button-height - 2px;
|
||||
}
|
||||
|
||||
&__list {
|
||||
box-sizing: border-box;
|
||||
padding: 15px 0;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
&__close {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
&__empty {
|
||||
padding-top: 60px;
|
||||
text-align: center;
|
||||
|
||||
p {
|
||||
margin: 15px 0;
|
||||
color: @coupon-list-empty-tip-color;
|
||||
font-size: @coupon-list-empty-tip-font-size;
|
||||
line-height: @coupon-list-empty-tip-line-height;
|
||||
}
|
||||
|
||||
img {
|
||||
width: @coupon-list-empty-image-size;
|
||||
height: @coupon-list-empty-image-size;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders demo correctly 1`] = `
|
||||
<div>
|
||||
<div>
|
||||
<div class="van-cell van-cell--clickable van-coupon-cell">
|
||||
<div class="van-cell__title"><span>优惠券</span></div>
|
||||
<div class="van-cell__value"><span>2张可用</span></div><i class="van-icon van-icon-arrow van-cell__right-icon">
|
||||
<!----></i>
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,179 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`render coupon cell 1`] = `
|
||||
<div class="van-cell van-cell--clickable van-coupon-cell">
|
||||
<div class="van-cell__title"><span>优惠券</span></div>
|
||||
<div class="van-cell__value"><span>使用优惠</span></div><i class="van-icon van-icon-arrow van-cell__right-icon">
|
||||
<!----></i>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`render coupon cell with coupon 1`] = `
|
||||
<div class="van-cell van-cell--clickable van-coupon-cell">
|
||||
<div class="van-cell__title"><span>优惠券</span></div>
|
||||
<div class="van-cell__value van-coupon-cell--selected"><span>-¥1.00</span></div><i class="van-icon van-icon-arrow van-cell__right-icon">
|
||||
<!----></i>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`render coupon list 1`] = `
|
||||
<div class="van-coupon-list">
|
||||
<div class="van-cell van-cell--borderless van-field van-coupon-list__field">
|
||||
<div class="van-cell__value van-cell__value--alone">
|
||||
<div class="van-field__body"><input type="text" placeholder="请输入优惠码" maxlength="20" class="van-field__control">
|
||||
<div class="van-field__button"><button disabled="disabled" class="van-button van-button--danger van-button--small van-button--disabled van-coupon-list__exchange"><span class="van-button__text">兑换</span></button></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-tabs van-tabs--line van-coupon-list__tab">
|
||||
<div class="van-tabs__wrap van-hairline--top-bottom">
|
||||
<div role="tablist" class="van-tabs__nav van-tabs__nav--line">
|
||||
<div role="tab" aria-selected="true" class="van-tab van-tab--active"><span class="van-ellipsis">可使用优惠券 (6)</span></div>
|
||||
<div role="tab" class="van-tab"><span class="van-ellipsis">不可使用优惠券 (2)</span></div>
|
||||
<div class="van-tabs__line"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-tabs__content">
|
||||
<div role="tabpanel" class="van-tab__pane">
|
||||
<div class="van-coupon-list__list" style="height: 628px;">
|
||||
<div class="van-coupon">
|
||||
<div class="van-coupon__content">
|
||||
<div class="van-coupon__head">
|
||||
<h2 class="van-coupon__amount"></h2>
|
||||
<p>无使用门槛</p>
|
||||
</div>
|
||||
<div class="van-coupon__body">
|
||||
<h2 class="van-coupon__name"></h2>
|
||||
<p>有效期:2017.03.10 - 2017.12.30</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-coupon">
|
||||
<div class="van-coupon__content">
|
||||
<div class="van-coupon__head">
|
||||
<h2 class="van-coupon__amount"><span>¥</span> 1.5</h2>
|
||||
<p>无使用门槛</p>
|
||||
</div>
|
||||
<div class="van-coupon__body">
|
||||
<h2 class="van-coupon__name">name</h2>
|
||||
<p>有效期:2017.03.10 - 2017.12.30</p>
|
||||
<div role="checkbox" tabindex="0" aria-checked="true" class="van-checkbox van-coupon__corner">
|
||||
<div class="van-checkbox__icon van-checkbox__icon--round van-checkbox__icon--checked"><i class="van-icon van-icon-success" style="border-color: #f44; background-color: rgb(255, 68, 68);">
|
||||
<!----></i></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="van-coupon__description">description</p>
|
||||
</div>
|
||||
<div class="van-coupon">
|
||||
<div class="van-coupon__content">
|
||||
<div class="van-coupon__head">
|
||||
<h2 class="van-coupon__amount"><span>¥</span> 1</h2>
|
||||
<p>无使用门槛</p>
|
||||
</div>
|
||||
<div class="van-coupon__body">
|
||||
<h2 class="van-coupon__name">name</h2>
|
||||
<p>有效期:2017.03.10 - 2017.12.30</p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="van-coupon__description">description</p>
|
||||
</div>
|
||||
<div class="van-coupon">
|
||||
<div class="van-coupon__content">
|
||||
<div class="van-coupon__head">
|
||||
<h2 class="van-coupon__amount"><span>¥</span> 1.23</h2>
|
||||
<p>无使用门槛</p>
|
||||
</div>
|
||||
<div class="van-coupon__body">
|
||||
<h2 class="van-coupon__name">name</h2>
|
||||
<p>有效期:2017.03.10 - 2017.12.30</p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="van-coupon__description">description</p>
|
||||
</div>
|
||||
<div class="van-coupon">
|
||||
<div class="van-coupon__content">
|
||||
<div class="van-coupon__head">
|
||||
<h2 class="van-coupon__amount">8.8折</h2>
|
||||
<p>满0.5元可用</p>
|
||||
</div>
|
||||
<div class="van-coupon__body">
|
||||
<h2 class="van-coupon__name">name</h2>
|
||||
<p>有效期:2017.03.10 - 2017.12.30</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-coupon">
|
||||
<div class="van-coupon__content">
|
||||
<div class="van-coupon__head">
|
||||
<h2 class="van-coupon__amount">9折</h2>
|
||||
<p>满0.5元可用</p>
|
||||
</div>
|
||||
<div class="van-coupon__body">
|
||||
<h2 class="van-coupon__name">name</h2>
|
||||
<p>有效期:2017.03.10 - 2017.12.30</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div role="tabpanel" class="van-tab__pane" style="display: none;">
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
</div><button class="van-button van-button--default van-button--large van-coupon-list__close"><span class="van-button__text">不使用优惠</span></button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`render disabled coupon 1`] = `
|
||||
<div class="van-coupon van-coupon--disabled">
|
||||
<div class="van-coupon__content">
|
||||
<div class="van-coupon__head">
|
||||
<h2 class="van-coupon__amount"><span>¥</span> 1.5</h2>
|
||||
<p>无使用门槛</p>
|
||||
</div>
|
||||
<div class="van-coupon__body">
|
||||
<h2 class="van-coupon__name">name</h2>
|
||||
<p>有效期:2017.03.10 - 2017.12.30</p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="van-coupon__description">reason</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`render empty coupon list 1`] = `
|
||||
<div class="van-coupon-list">
|
||||
<div class="van-cell van-cell--borderless van-field van-coupon-list__field">
|
||||
<div class="van-cell__value van-cell__value--alone">
|
||||
<div class="van-field__body"><input type="text" placeholder="请输入优惠码" maxlength="20" class="van-field__control">
|
||||
<div class="van-field__button"><button disabled="disabled" class="van-button van-button--danger van-button--small van-button--disabled van-coupon-list__exchange"><span class="van-button__text">兑换</span></button></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-tabs van-tabs--line van-coupon-list__tab">
|
||||
<div class="van-tabs__wrap van-hairline--top-bottom">
|
||||
<div role="tablist" class="van-tabs__nav van-tabs__nav--line">
|
||||
<div role="tab" class="van-tab"><span class="van-ellipsis">可使用优惠券 (0)</span></div>
|
||||
<div role="tab" class="van-tab van-tab--active" aria-selected="true"><span class="van-ellipsis">不可使用优惠券 (0)</span></div>
|
||||
<div class="van-tabs__line"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-tabs__content">
|
||||
<div role="tabpanel" class="van-tab__pane" style="display: none;">
|
||||
<div class="van-coupon-list__list" style="height: 628px;">
|
||||
<div class="van-coupon-list__empty"><img src="https://img.yzcdn.cn/vant/coupon-empty.png">
|
||||
<p>暂无优惠券</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div role="tabpanel" class="van-tab__pane" style="">
|
||||
<div class="van-coupon-list__list" style="height: 628px;">
|
||||
<div class="van-coupon-list__empty"><img src="https://img.yzcdn.cn/vant/coupon-empty.png">
|
||||
<p>暂无优惠券</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div><button class="van-button van-button--default van-button--large van-coupon-list__close"><span class="van-button__text">不使用优惠</span></button>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,4 @@
|
||||
import Demo from '../demo';
|
||||
import demoTest from '../../../test/demo-test';
|
||||
|
||||
demoTest(Demo);
|
||||
@@ -0,0 +1,147 @@
|
||||
import Coupon from '../../coupon';
|
||||
import CouponList from '..';
|
||||
import CouponCell from '../../coupon-cell';
|
||||
import { later, mount } from '../../../test/utils';
|
||||
|
||||
const coupon = {
|
||||
id: 1,
|
||||
discount: 0,
|
||||
denominations: 150,
|
||||
originCondition: 0,
|
||||
reason: '',
|
||||
value: 150,
|
||||
name: 'name',
|
||||
description: 'description',
|
||||
startAt: 1489104000,
|
||||
endAt: 1514592000
|
||||
};
|
||||
|
||||
const coupon2 = {
|
||||
...coupon,
|
||||
denominations: 100
|
||||
};
|
||||
|
||||
const coupon3 = {
|
||||
...coupon,
|
||||
denominations: 123
|
||||
};
|
||||
|
||||
const emptyCoupon = {
|
||||
id: 0,
|
||||
discount: 0,
|
||||
denominations: 0,
|
||||
originCondition: 0,
|
||||
startAt: 1489104000,
|
||||
endAt: 1514592000
|
||||
};
|
||||
|
||||
const discountCoupon = {
|
||||
...coupon,
|
||||
id: 2,
|
||||
discount: 88,
|
||||
denominations: 0,
|
||||
originCondition: 50,
|
||||
value: 12,
|
||||
description: ''
|
||||
};
|
||||
|
||||
const discountCoupon2 = {
|
||||
...coupon,
|
||||
id: 2,
|
||||
discount: 90,
|
||||
denominations: 0,
|
||||
originCondition: 50,
|
||||
value: 12,
|
||||
description: ''
|
||||
};
|
||||
|
||||
const disabledCoupon = {
|
||||
...coupon,
|
||||
id: 3,
|
||||
reason: 'reason'
|
||||
};
|
||||
|
||||
const disabledDiscountCoupon = {
|
||||
...discountCoupon,
|
||||
discount: 10,
|
||||
id: 4,
|
||||
reason: ''
|
||||
};
|
||||
|
||||
test('render disabled coupon', () => {
|
||||
const wrapper = mount(Coupon, {
|
||||
propsData: {
|
||||
coupon: disabledCoupon,
|
||||
disabled: true
|
||||
}
|
||||
});
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('render coupon list', async () => {
|
||||
const wrapper = mount(CouponList, {
|
||||
propsData: {
|
||||
chosenCoupon: 1,
|
||||
coupons: [emptyCoupon, coupon, coupon2, coupon3, discountCoupon, discountCoupon2],
|
||||
disabledCoupons: [disabledCoupon, disabledDiscountCoupon]
|
||||
}
|
||||
});
|
||||
await later();
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('render empty coupon list', () => {
|
||||
const wrapper = mount(CouponList, {
|
||||
propsData: {
|
||||
coupons: [],
|
||||
disabledCoupons: []
|
||||
}
|
||||
});
|
||||
wrapper.findAll('.van-tab').at(1).trigger('click');
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('exchange coupon', () => {
|
||||
const wrapper = mount(CouponList);
|
||||
const exchange = wrapper.find('.van-coupon-list__exchange');
|
||||
|
||||
wrapper.setData({
|
||||
currentCode: '1',
|
||||
displayedCouponIndex: 1
|
||||
});
|
||||
exchange.trigger('click');
|
||||
wrapper.setProps({ code: '2' });
|
||||
exchange.trigger('click');
|
||||
|
||||
expect(wrapper.emitted('exchange')[0][0]).toBe('1');
|
||||
expect(wrapper.emitted('exchange')[1][0]).toBe('2');
|
||||
expect(wrapper.emitted('input')[0][0]).toBe('1');
|
||||
expect(wrapper.emitted('input')[1][0]).toBe('');
|
||||
expect(wrapper.emitted('input')[2][0]).toBe('2');
|
||||
});
|
||||
|
||||
test('render coupon cell', () => {
|
||||
const onClick = jest.fn();
|
||||
const wrapper = mount(CouponCell, {
|
||||
context: {
|
||||
on: {
|
||||
click: onClick
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
wrapper.trigger('click');
|
||||
expect(onClick).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('render coupon cell with coupon', () => {
|
||||
const wrapper = mount(CouponCell, {
|
||||
propsData: {
|
||||
coupons: [{ value: 100 }],
|
||||
chosenCoupon: 0
|
||||
}
|
||||
});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
@@ -0,0 +1,123 @@
|
||||
# Coupon 优惠券选择器
|
||||
|
||||
### 引入
|
||||
|
||||
``` javascript
|
||||
import { CouponCell, CouponList } from 'vant';
|
||||
|
||||
Vue.use(CouponCell).use(CouponList);
|
||||
```
|
||||
|
||||
## 代码演示
|
||||
|
||||
### 基础用法
|
||||
|
||||
```html
|
||||
<!-- 优惠券单元格 -->
|
||||
<van-coupon-cell
|
||||
:coupons="coupons"
|
||||
:chosen-coupon="chosenCoupon"
|
||||
@click="showList = true"
|
||||
/>
|
||||
|
||||
<!-- 优惠券列表 -->
|
||||
<van-popup v-model="showList" position="bottom">
|
||||
<van-coupon-list
|
||||
:coupons="coupons"
|
||||
:chosen-coupon="chosenCoupon"
|
||||
:disabled-coupons="disabledCoupons"
|
||||
@change="onChange"
|
||||
@exchange="onExchange"
|
||||
/>
|
||||
</van-popup>
|
||||
```
|
||||
|
||||
```javascript
|
||||
const coupon = {
|
||||
available: 1,
|
||||
condition: '无使用门槛\n最多优惠12元',
|
||||
reason: '',
|
||||
value: 150,
|
||||
name: '优惠券名称',
|
||||
startAt: 1489104000,
|
||||
endAt: 1514592000,
|
||||
valueDesc: '1.5',
|
||||
unitDesc: '元'
|
||||
};
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
chosenCoupon: -1,
|
||||
coupons: [coupon],
|
||||
disabledCoupons: [coupon]
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onChange(index) {
|
||||
this.showList = false;
|
||||
this.chosenCoupon = index;
|
||||
},
|
||||
onExchange(code) {
|
||||
this.coupons.push(coupon);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### CouponCell Props
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
|------|------|------|------|------|
|
||||
| title | 单元格标题 | `String` | `优惠券` | - |
|
||||
| chosen-coupon | 当前选中优惠券的索引 | `Number` | `-1` | - |
|
||||
| coupons | 可用优惠券列表 | `Array` | `[]` | - |
|
||||
| editable | 能否切换优惠券 | `Boolean` | `true` | - |
|
||||
| border | 是否显示内边框 | `Boolean` | `true` | 1.3.10 |
|
||||
| currency | 货币符号 | `String` | `¥` | - | 1.5.0 |
|
||||
|
||||
### CouponList Props
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
|------|------|------|------|------|
|
||||
| v-model | 当前输入的兑换码 | `String` | - | - |
|
||||
| chosen-coupon | 当前选中优惠券的索引 | `Number` | `-1` | - |
|
||||
| coupons | 可用优惠券列表 | `Array` | `[]` | - |
|
||||
| disabled-coupons | 不可用优惠券列表 | `Array` | `[]` | - |
|
||||
| enabled-title | 可用优惠券列表标题 | `String` | `可使用优惠券` | - |
|
||||
| disabled-title | 不可用优惠券列表标题 | `String` | `不可使用优惠券` | - |
|
||||
| exchange-button-text | 兑换按钮文字 | `String` | `兑换` | - |
|
||||
| exchange-button-loading | 是否显示兑换按钮加载动画 | `Boolean` | `false` | - |
|
||||
| exchange-button-disabled | 是否禁用兑换按钮 | `Boolean` | `false` | - |
|
||||
| exchange-min-length | 兑换码最小长度 | `Number` | `1` | - |
|
||||
| displayed-coupon-index | 滚动至特定优惠券位置 | `Number` | - | - |
|
||||
| show-close-button | 是否显示列表底部按钮 | `Boolean` | `true` | - |
|
||||
| close-button-text | 列表底部按钮文字 | `String` | `不使用优惠` | - |
|
||||
| input-placeholder | 输入框文字提示 | `String` | `请输入优惠码` | - |
|
||||
| show-exchange-bar | 是否展示兑换栏 | `Boolean` | `true` | - |
|
||||
| currency | 货币符号 | `String` | `¥` | - | 1.5.0 |
|
||||
|
||||
### CouponList Events
|
||||
|
||||
| 事件名 | 说明 | 回调参数 |
|
||||
|------|------|------|
|
||||
| change | 优惠券切换回调 | index, 选中优惠券的索引 |
|
||||
| exchange | 兑换优惠券回调 | code, 兑换码 |
|
||||
|
||||
### 优惠券字段说明
|
||||
|
||||
| key | 说明 | 类型 |
|
||||
|------|------|------|
|
||||
| id | 优惠券 id | `String` |
|
||||
| name | 优惠券名称 | `String` |
|
||||
| condition | 满减条件 | `String` |
|
||||
| startAt | 卡有效开始时间 (时间戳, 单位秒) | `Number` |
|
||||
| endAt | 卡失效日期 (时间戳, 单位秒) | `Number` |
|
||||
| description | 描述信息,优惠券可用时展示 | `String` |
|
||||
| reason | 不可用原因,优惠券不可用时展示 | `String` |
|
||||
| value | 折扣券优惠金额,单位分 | `Number` |
|
||||
| valueDesc | 折扣券优惠金额文案 | `String` |
|
||||
| unitDesc | 单位文案 | `String` |
|
||||
Reference in New Issue
Block a user