mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
feat(Sku): add new startSaleNum prop (#5105)
This commit is contained in:
parent
d8e30bdcac
commit
17472e04c5
@ -141,6 +141,7 @@ export default {
|
||||
| message-config | Message related config | *object* | `{}` | - |
|
||||
| get-container | Return the mount node for sku | *string \| () => Element* | - | - |
|
||||
| safe-area-inset-bottom | Whether to enable bottom safe area adaptation | *boolean* | `false` | 2.2.1 |
|
||||
| start-sale-num | Minimum quantity | *number* | `1` | 2.2.15 |
|
||||
|
||||
### Events
|
||||
|
||||
@ -258,10 +259,10 @@ customStepperConfig: {
|
||||
quotaText: 'only 5 can buy',
|
||||
// custom callback when over limit
|
||||
handleOverLimit: (data) => {
|
||||
const { action, limitType, quota, quotaUsed } = data;
|
||||
const { action, limitType, quota, quotaUsed, startSaleNum } = data;
|
||||
|
||||
if (action === 'minus') {
|
||||
Toast('at least select one');
|
||||
Toast(`at least select ${startSaleNum > 1 ? startSaleNum : 'one'}`);
|
||||
} else if (action === 'plus') {
|
||||
// const { LIMIT_TYPE } = Sku.skuConstants;
|
||||
if (limitType === LIMIT_TYPE.QUOTA_LIMIT) {
|
||||
|
@ -145,6 +145,7 @@ export default {
|
||||
| initial-sku | 默认选中的 sku,具体参考高级用法 | *object* | `{}` | - |
|
||||
| show-soldout-sku | 是否展示售罄的 sku,默认展示并置灰 | *boolean* | `true` | - |
|
||||
| safe-area-inset-bottom | 是否开启底部安全区适配,[详细说明](#/zh-CN/quickstart#di-bu-an-quan-qu-gua-pei) | *boolean* | `false` | 2.2.1 |
|
||||
| start-sale-num | 起售数量 | *number* | `1` | 2.2.15 |
|
||||
|
||||
### Events
|
||||
|
||||
@ -270,10 +271,10 @@ customStepperConfig: {
|
||||
quotaText: '每次限购xxx件',
|
||||
// 自定义步进器超过限制时的回调
|
||||
handleOverLimit: (data) => {
|
||||
const { action, limitType, quota, quotaUsed } = data;
|
||||
const { action, limitType, quota, quotaUsed, startSaleNum } = data;
|
||||
|
||||
if (action === 'minus') {
|
||||
Toast('至少选择一件商品');
|
||||
Toast(startSaleNum > 1 ? `${startSaleNum}件起售` : '至少选择一件商品');
|
||||
} else if (action === 'plus') {
|
||||
// const { LIMIT_TYPE } = Sku.skuConstants;
|
||||
if (limitType === LIMIT_TYPE.QUOTA_LIMIT) {
|
||||
|
@ -45,6 +45,10 @@ export default createComponent({
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
startSaleNum: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
initialSku: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
@ -236,22 +240,6 @@ export default createComponent({
|
||||
];
|
||||
},
|
||||
|
||||
quotaText() {
|
||||
const { quotaText, hideQuotaText } = this.customStepperConfig;
|
||||
|
||||
if (hideQuotaText) return '';
|
||||
|
||||
let text = '';
|
||||
|
||||
if (quotaText) {
|
||||
text = quotaText;
|
||||
} else if (this.quota > 0) {
|
||||
text = t('quotaLimit', this.quota);
|
||||
}
|
||||
|
||||
return text;
|
||||
},
|
||||
|
||||
selectedText() {
|
||||
if (this.selectedSkuComb) {
|
||||
return `${t('selected')} ${this.selectedSkuValues.map(item => item.name).join(';')}`;
|
||||
@ -274,6 +262,7 @@ export default createComponent({
|
||||
skuEventBus.$on('sku:numChange', this.onNumChange);
|
||||
skuEventBus.$on('sku:previewImage', this.onPreviewImage);
|
||||
skuEventBus.$on('sku:overLimit', this.onOverLimit);
|
||||
skuEventBus.$on('sku:stepperState', this.onStepperState);
|
||||
skuEventBus.$on('sku:addCart', this.onAddCart);
|
||||
skuEventBus.$on('sku:buy', this.onBuy);
|
||||
|
||||
@ -289,6 +278,8 @@ export default createComponent({
|
||||
const { skuStepper } = this.$refs;
|
||||
const { selectedNum } = this.initialSku;
|
||||
const num = isDef(selectedNum) ? selectedNum : 1;
|
||||
// 用来缓存不合法的情况
|
||||
this.stepperError = null;
|
||||
|
||||
if (skuStepper) {
|
||||
skuStepper.setCurrentNum(num);
|
||||
@ -409,18 +400,35 @@ export default createComponent({
|
||||
}
|
||||
|
||||
if (action === 'minus') {
|
||||
Toast(t('minusTip'));
|
||||
if (this.startSaleNum > 1) {
|
||||
Toast(t('minusStartTip', this.startSaleNum));
|
||||
} else {
|
||||
Toast(t('minusTip'));
|
||||
}
|
||||
} else if (action === 'plus') {
|
||||
if (limitType === QUOTA_LIMIT) {
|
||||
let msg = t('quotaLimit', quota);
|
||||
if (quotaUsed > 0) msg += `,${t('quotaCount', quotaUsed)}`;
|
||||
Toast(msg);
|
||||
if (quotaUsed > 0) {
|
||||
Toast(t('quotaUsedTip', quota, quotaUsed));
|
||||
} else {
|
||||
Toast(t('quotaTip', quota));
|
||||
}
|
||||
} else {
|
||||
Toast(t('soldout'));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onStepperState(data) {
|
||||
if (data.valid) {
|
||||
this.stepperError = null;
|
||||
} else {
|
||||
this.stepperError = {
|
||||
...data,
|
||||
action: 'plus',
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
onAddCart() {
|
||||
this.onBuyOrAddCart('add-cart');
|
||||
},
|
||||
@ -430,6 +438,10 @@ export default createComponent({
|
||||
},
|
||||
|
||||
onBuyOrAddCart(type) {
|
||||
// 有信息表示该sku根本不符合购买条件
|
||||
if (this.stepperError) {
|
||||
return this.onOverLimit(this.stepperError);
|
||||
}
|
||||
const error = this.validateSku();
|
||||
if (error) {
|
||||
Toast(error);
|
||||
@ -463,7 +475,6 @@ export default createComponent({
|
||||
selectedSku,
|
||||
selectedNum,
|
||||
stepperTitle,
|
||||
hideQuotaText,
|
||||
selectedSkuComb
|
||||
} = this;
|
||||
|
||||
@ -494,7 +505,6 @@ export default createComponent({
|
||||
{!this.hideStock && (
|
||||
<SkuHeaderItem>
|
||||
<span class="van-sku__stock">{this.stockText}</span>
|
||||
{!hideQuotaText && this.quotaText && <span class="van-sku__quota">({this.quotaText})</span>}
|
||||
</SkuHeaderItem>
|
||||
)}
|
||||
{this.hasSku && !this.hideSelectedText && (
|
||||
@ -530,6 +540,7 @@ export default createComponent({
|
||||
stock={this.stock}
|
||||
quota={this.quota}
|
||||
quotaUsed={this.quotaUsed}
|
||||
startSaleNum={this.startSaleNum}
|
||||
skuEventBus={skuEventBus}
|
||||
selectedNum={selectedNum}
|
||||
selectedSku={selectedSku}
|
||||
@ -537,6 +548,7 @@ export default createComponent({
|
||||
skuStockNum={sku.stock_num}
|
||||
disableStepperInput={this.disableStepperInput}
|
||||
customStepperConfig={this.customStepperConfig}
|
||||
hideQuotaText={this.hideQuotaText}
|
||||
onChange={event => {
|
||||
this.$emit('stepper-change', event);
|
||||
}}
|
||||
|
@ -16,6 +16,7 @@ export default createComponent({
|
||||
stepperTitle: String,
|
||||
disableStepperInput: Boolean,
|
||||
customStepperConfig: Object,
|
||||
hideQuotaText: Boolean,
|
||||
quota: {
|
||||
type: Number,
|
||||
default: 0
|
||||
@ -23,7 +24,11 @@ export default createComponent({
|
||||
quotaUsed: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
startSaleNum: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
@ -40,9 +45,17 @@ export default createComponent({
|
||||
},
|
||||
|
||||
stepperLimit(limit) {
|
||||
if (limit < this.currentNum) {
|
||||
if (limit < this.currentNum && this.stepperMinLimit <= limit) {
|
||||
this.currentNum = limit;
|
||||
}
|
||||
this.checkState(this.stepperMinLimit, limit);
|
||||
},
|
||||
|
||||
stepperMinLimit(start) {
|
||||
if (start > this.currentNum || start > this.stepperLimit) {
|
||||
this.currentNum = start;
|
||||
}
|
||||
this.checkState(start, this.stepperLimit);
|
||||
}
|
||||
},
|
||||
|
||||
@ -62,7 +75,35 @@ export default createComponent({
|
||||
}
|
||||
|
||||
return limit;
|
||||
}
|
||||
},
|
||||
stepperMinLimit() {
|
||||
return this.startSaleNum < 1 ? 1 : this.startSaleNum;
|
||||
},
|
||||
quotaText() {
|
||||
const { quotaText, hideQuotaText } = this.customStepperConfig;
|
||||
if (hideQuotaText) return '';
|
||||
|
||||
let text = '';
|
||||
|
||||
if (quotaText) {
|
||||
text = quotaText;
|
||||
} else {
|
||||
const textArr = [];
|
||||
if (this.startSaleNum > 1) {
|
||||
textArr.push(t('quotaStart', this.startSaleNum));
|
||||
}
|
||||
if (this.quota > 0) {
|
||||
textArr.push(t('quotaLimit', this.quota));
|
||||
}
|
||||
text = textArr.join(t('comma'));
|
||||
}
|
||||
|
||||
return text;
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
this.checkState(this.stepperMinLimit, this.stepperLimit);
|
||||
},
|
||||
|
||||
methods: {
|
||||
@ -75,7 +116,8 @@ export default createComponent({
|
||||
action,
|
||||
limitType: this.limitType,
|
||||
quota: this.quota,
|
||||
quotaUsed: this.quotaUsed
|
||||
quotaUsed: this.quotaUsed,
|
||||
startSaleNum: this.startSaleNum,
|
||||
});
|
||||
},
|
||||
|
||||
@ -83,7 +125,27 @@ export default createComponent({
|
||||
const { handleStepperChange } = this.customStepperConfig;
|
||||
handleStepperChange && handleStepperChange(currentValue);
|
||||
this.$emit('change', currentValue);
|
||||
}
|
||||
},
|
||||
|
||||
checkState(min, max) {
|
||||
// 如果选择小于起售,则强制变为起售
|
||||
if (this.currentNum < min || min > max) {
|
||||
this.currentNum = min;
|
||||
} else if (this.currentNum > max) {
|
||||
// 当前选择数量大于最大可选时,需要重置已选数量
|
||||
this.currentNum = max;
|
||||
}
|
||||
|
||||
this.skuEventBus.$emit('sku:stepperState', {
|
||||
valid: min <= max,
|
||||
min,
|
||||
max,
|
||||
limitType: this.limitType,
|
||||
quota: this.quota,
|
||||
quotaUsed: this.quotaUsed,
|
||||
startSaleNum: this.startSaleNum,
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
render() {
|
||||
@ -94,11 +156,13 @@ export default createComponent({
|
||||
<Stepper
|
||||
vModel={this.currentNum}
|
||||
class="van-sku__stepper"
|
||||
min={this.stepperMinLimit}
|
||||
max={this.stepperLimit}
|
||||
disableInput={this.disableStepperInput}
|
||||
onOverlimit={this.onOverLimit}
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
{!this.hideQuotaText && this.quotaText && <span class="van-sku__stepper-quota">({this.quotaText})</span>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -2,6 +2,7 @@ export default {
|
||||
goods_id: '946755',
|
||||
quota: 15,
|
||||
quota_used: 0,
|
||||
start_sale_num: 10,
|
||||
goods_info: {
|
||||
title: '测试商品',
|
||||
picture:
|
||||
|
@ -11,6 +11,7 @@
|
||||
:hide-stock="skuData.sku.hide_stock"
|
||||
:quota="skuData.quota"
|
||||
:quota-used="skuData.quota_used"
|
||||
:start-sale-num="skuData.start_sale_num"
|
||||
:close-on-click-overlay="closeOnClickOverlay"
|
||||
:message-config="messageConfig"
|
||||
:custom-sku-validator="customSkuValidator"
|
||||
@ -42,6 +43,7 @@
|
||||
:hide-stock="skuData.sku.hide_stock"
|
||||
:quota="skuData.quota"
|
||||
:quota-used="skuData.quota_used"
|
||||
:start-sale-num="skuData.start_sale_num"
|
||||
:custom-stepper-config="customStepperConfig"
|
||||
:message-config="messageConfig"
|
||||
hide-quota-text
|
||||
@ -70,6 +72,7 @@
|
||||
:hide-stock="skuData.sku.hide_stock"
|
||||
:quota="skuData.quota"
|
||||
:quota-used="skuData.quota_used"
|
||||
:start-sale-num="skuData.start_sale_num"
|
||||
:custom-stepper-config="customStepperConfig"
|
||||
:message-config="messageConfig"
|
||||
:show-soldout-sku="false"
|
||||
@ -99,6 +102,7 @@
|
||||
:hide-stock="skuData.sku.hide_stock"
|
||||
:quota="skuData.quota"
|
||||
:quota-used="skuData.quota_used"
|
||||
:start-sale-num="skuData.start_sale_num"
|
||||
show-add-cart-btn
|
||||
reset-stepper-on-hide
|
||||
safe-area-inset-bottom
|
||||
@ -126,7 +130,7 @@
|
||||
square
|
||||
size="large"
|
||||
type="danger"
|
||||
@click="props.skuEventBus.$emit('sku:buy')"
|
||||
@click="skuEventBus.$emit('sku:buy')"
|
||||
>
|
||||
{{ $t('button2') }}
|
||||
</van-button>
|
||||
@ -185,10 +189,10 @@ export default {
|
||||
quotaText: '单次限购100件',
|
||||
stockFormatter: (stock) => `剩余${stock}件`,
|
||||
handleOverLimit: (data) => {
|
||||
const { action, limitType, quota } = data;
|
||||
const { action, limitType, quota, startSaleNum = 1 } = data;
|
||||
|
||||
if (action === 'minus') {
|
||||
this.$toast('至少选择一件商品');
|
||||
this.$toast(startSaleNum > 1 ? `${startSaleNum}件起售` : '至少选择一件商品');
|
||||
} else if (action === 'plus') {
|
||||
if (limitType === LIMIT_TYPE.QUOTA_LIMIT) {
|
||||
this.$toast(`限购${quota}件`);
|
||||
|
@ -198,6 +198,7 @@
|
||||
&-container {
|
||||
height: 30px;
|
||||
margin-right: 20px;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
@ -208,6 +209,14 @@
|
||||
float: left;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
&-quota {
|
||||
display: inline-block;
|
||||
float: right;
|
||||
color: @red;
|
||||
font-size: @font-size-sm;
|
||||
line-height: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
&__stock {
|
||||
@ -221,12 +230,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
&__quota {
|
||||
display: inline-block;
|
||||
color: @red;
|
||||
font-size: @font-size-sm;
|
||||
}
|
||||
|
||||
&-messages {
|
||||
padding-bottom: @padding-xl;
|
||||
|
||||
|
@ -11,11 +11,12 @@ export default {
|
||||
soldout: '库存不足',
|
||||
originPrice: '原价',
|
||||
minusTip: '至少选择一件',
|
||||
minusStartTip: (start: number) => `${start}件起售`,
|
||||
unavailable: '商品已经无法购买啦',
|
||||
stock: '剩余',
|
||||
stockUnit: '件',
|
||||
quotaLimit: (quota: number) => `每人限购${quota}件`,
|
||||
quotaCount: (count: number) => `你已购买${count}件`
|
||||
quotaTip: (quota: number) => `每人限购${quota}件`,
|
||||
quotaUsedTip: (quota: number, count: number) => `每人限购${quota}件,你已购买${count}件`
|
||||
},
|
||||
vanSkuActions: {
|
||||
buy: '立即购买',
|
||||
@ -26,6 +27,9 @@ export default {
|
||||
fail: '上传失败<br />重新上传'
|
||||
},
|
||||
vanSkuStepper: {
|
||||
quotaLimit: (quota: number) => `限购${quota}件`,
|
||||
quotaStart: (start: number) => `${start}件起售`,
|
||||
comma: ',',
|
||||
num: '购买数量'
|
||||
},
|
||||
vanSkuMessages: {
|
||||
|
Loading…
x
Reference in New Issue
Block a user