From 17472e04c576b8db1fcefbd329aa749f86bb86e1 Mon Sep 17 00:00:00 2001 From: Waiter Date: Thu, 28 Nov 2019 10:51:27 +0800 Subject: [PATCH] feat(Sku): add new startSaleNum prop (#5105) --- src/sku/README.md | 5 ++- src/sku/README.zh-CN.md | 5 ++- src/sku/Sku.js | 56 ++++++++++++++---------- src/sku/components/SkuStepper.js | 74 +++++++++++++++++++++++++++++--- src/sku/demo/data.js | 1 + src/sku/demo/index.vue | 10 +++-- src/sku/index.less | 15 ++++--- src/sku/lang.ts | 8 +++- 8 files changed, 132 insertions(+), 42 deletions(-) diff --git a/src/sku/README.md b/src/sku/README.md index 29ac44055..338ae6218 100644 --- a/src/sku/README.md +++ b/src/sku/README.md @@ -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) { diff --git a/src/sku/README.zh-CN.md b/src/sku/README.zh-CN.md index 6b1c13a30..c1c23b0a8 100644 --- a/src/sku/README.zh-CN.md +++ b/src/sku/README.zh-CN.md @@ -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) { diff --git a/src/sku/Sku.js b/src/sku/Sku.js index de78d83cc..14bd49804 100644 --- a/src/sku/Sku.js +++ b/src/sku/Sku.js @@ -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 && ( {this.stockText} - {!hideQuotaText && this.quotaText && ({this.quotaText})} )} {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); }} diff --git a/src/sku/components/SkuStepper.js b/src/sku/components/SkuStepper.js index 28eca7c38..dcaa9de55 100644 --- a/src/sku/components/SkuStepper.js +++ b/src/sku/components/SkuStepper.js @@ -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({ + {!this.hideQuotaText && this.quotaText && ({this.quotaText})} ); diff --git a/src/sku/demo/data.js b/src/sku/demo/data.js index 37df50828..c7674f10b 100644 --- a/src/sku/demo/data.js +++ b/src/sku/demo/data.js @@ -2,6 +2,7 @@ export default { goods_id: '946755', quota: 15, quota_used: 0, + start_sale_num: 10, goods_info: { title: '测试商品', picture: diff --git a/src/sku/demo/index.vue b/src/sku/demo/index.vue index 7e91966d1..b64802f40 100644 --- a/src/sku/demo/index.vue +++ b/src/sku/demo/index.vue @@ -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') }} @@ -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}件`); diff --git a/src/sku/index.less b/src/sku/index.less index 3ea21726d..beb8b2318 100644 --- a/src/sku/index.less +++ b/src/sku/index.less @@ -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; diff --git a/src/sku/lang.ts b/src/sku/lang.ts index 216c1dd06..90b5c1c1a 100644 --- a/src/sku/lang.ts +++ b/src/sku/lang.ts @@ -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: '上传失败
重新上传' }, vanSkuStepper: { + quotaLimit: (quota: number) => `限购${quota}件`, + quotaStart: (start: number) => `${start}件起售`, + comma: ',', num: '购买数量' }, vanSkuMessages: {