xt-element-ui 2.0.1 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -7,17 +7,17 @@
|
|
|
7
7
|
]"
|
|
8
8
|
>
|
|
9
9
|
<el-input
|
|
10
|
-
:value="
|
|
10
|
+
:value="displayValue"
|
|
11
11
|
:placeholder="placeholder"
|
|
12
|
-
:type="type"
|
|
12
|
+
:type="isNumberType ? 'text' : type"
|
|
13
13
|
:size="size"
|
|
14
14
|
:disabled="disabled"
|
|
15
15
|
:readonly="readonly"
|
|
16
16
|
:style="inputStyle"
|
|
17
|
-
@input="
|
|
18
|
-
@change="
|
|
19
|
-
@focus="
|
|
20
|
-
@blur="
|
|
17
|
+
@input="handleInput"
|
|
18
|
+
@change="handleChange"
|
|
19
|
+
@focus="handleFocus"
|
|
20
|
+
@blur="handleBlur"
|
|
21
21
|
/>
|
|
22
22
|
</div>
|
|
23
23
|
</template>
|
|
@@ -52,7 +52,22 @@ export default {
|
|
|
52
52
|
default: ''
|
|
53
53
|
}
|
|
54
54
|
},
|
|
55
|
+
data() {
|
|
56
|
+
return {
|
|
57
|
+
currentStr: '',
|
|
58
|
+
isFocused: false
|
|
59
|
+
}
|
|
60
|
+
},
|
|
55
61
|
computed: {
|
|
62
|
+
isNumberType() {
|
|
63
|
+
return this.type === 'number'
|
|
64
|
+
},
|
|
65
|
+
displayValue() {
|
|
66
|
+
if (this.isNumberType) {
|
|
67
|
+
return this.currentStr
|
|
68
|
+
}
|
|
69
|
+
return this.value
|
|
70
|
+
},
|
|
56
71
|
inputStyle() {
|
|
57
72
|
if (this.color) {
|
|
58
73
|
return {
|
|
@@ -61,6 +76,71 @@ export default {
|
|
|
61
76
|
}
|
|
62
77
|
return {}
|
|
63
78
|
}
|
|
79
|
+
},
|
|
80
|
+
watch: {
|
|
81
|
+
value: {
|
|
82
|
+
immediate: true,
|
|
83
|
+
handler(val) {
|
|
84
|
+
if (this.isNumberType && !this.isFocused) {
|
|
85
|
+
this.currentStr = val === null || val === undefined || val === '' ? '' : String(val)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
methods: {
|
|
91
|
+
isValidNumber(str) {
|
|
92
|
+
return /^[+-]?\d*\.?\d*$/.test(str)
|
|
93
|
+
},
|
|
94
|
+
handleInput(val) {
|
|
95
|
+
if (this.isNumberType) {
|
|
96
|
+
if (this.isValidNumber(val)) {
|
|
97
|
+
this.currentStr = val
|
|
98
|
+
const num = this.parseToNumber(val)
|
|
99
|
+
if (num !== undefined) {
|
|
100
|
+
this.$emit('input', num)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
this.$emit('input', val)
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
handleChange(val) {
|
|
108
|
+
if (this.isNumberType) {
|
|
109
|
+
const num = this.parseToNumber(val)
|
|
110
|
+
this.$emit('change', num)
|
|
111
|
+
} else {
|
|
112
|
+
this.$emit('change', val)
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
handleFocus(e) {
|
|
116
|
+
this.isFocused = true
|
|
117
|
+
this.$emit('focus', e)
|
|
118
|
+
},
|
|
119
|
+
handleBlur(e) {
|
|
120
|
+
this.isFocused = false
|
|
121
|
+
if (this.isNumberType) {
|
|
122
|
+
const num = this.parseToNumber(this.currentStr)
|
|
123
|
+
this.$emit('blur', num, e)
|
|
124
|
+
if (num !== undefined) {
|
|
125
|
+
this.currentStr = String(num)
|
|
126
|
+
this.$emit('input', num)
|
|
127
|
+
} else {
|
|
128
|
+
if (this.currentStr !== '') {
|
|
129
|
+
this.currentStr = ''
|
|
130
|
+
this.$emit('input', undefined)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
this.$emit('blur', e)
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
parseToNumber(str) {
|
|
138
|
+
if (!str || str === '+' || str === '-' || str === '.' || str === '+.' || str === '-.' || str === '-.') {
|
|
139
|
+
return undefined
|
|
140
|
+
}
|
|
141
|
+
const num = parseFloat(str)
|
|
142
|
+
return isNaN(num) ? undefined : num
|
|
143
|
+
}
|
|
64
144
|
}
|
|
65
145
|
}
|
|
66
146
|
</script>
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
icon="el-icon-plus"
|
|
11
11
|
plain
|
|
12
12
|
@click="onAdd"
|
|
13
|
-
|
|
13
|
+
>新增{{stepName}}</xt-button>
|
|
14
14
|
<xt-text v-if="isLimitReached" size="small" type-color="info">已达上限({{ localItems.length }}/{{ limit }})</xt-text>
|
|
15
15
|
</div>
|
|
16
16
|
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
:min-locked="idx !== 0 ? true : false"
|
|
28
28
|
:unit="unit"
|
|
29
29
|
:precision="precision"
|
|
30
|
+
:step-name="stepName"
|
|
30
31
|
:step="step"
|
|
31
32
|
:left-bracket="leftBracket"
|
|
32
33
|
:right-bracket="rightBracket"
|
|
@@ -36,11 +37,12 @@
|
|
|
36
37
|
@max-change="onMaxChange"
|
|
37
38
|
@min-change="onMinChange"
|
|
38
39
|
@delete="onDelete"
|
|
40
|
+
@blur="onFieldBlur"
|
|
39
41
|
/>
|
|
40
42
|
</div>
|
|
41
43
|
|
|
42
44
|
<div v-if="localItems.length === 0" class="xt-step-price__empty">
|
|
43
|
-
<span
|
|
45
|
+
<span>暂无数据,点击右上角「新增{{stepName}}」开始配置</span>
|
|
44
46
|
</div>
|
|
45
47
|
|
|
46
48
|
<div v-if="tip || $slots.tip" class="xt-step-price__tip">
|
|
@@ -59,6 +61,12 @@ export default {
|
|
|
59
61
|
|
|
60
62
|
components: { XtStepPriceItem },
|
|
61
63
|
|
|
64
|
+
inject: {
|
|
65
|
+
elFormItem: {
|
|
66
|
+
default: ''
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
|
|
62
70
|
computed: {
|
|
63
71
|
keyMin() { return (this.fieldKeys && this.fieldKeys.min) || 'min' },
|
|
64
72
|
keyMax() { return (this.fieldKeys && this.fieldKeys.max) || 'max' },
|
|
@@ -76,6 +84,7 @@ export default {
|
|
|
76
84
|
},
|
|
77
85
|
title: { type: String, default: '' },
|
|
78
86
|
unit: { type: String, default: '元' },
|
|
87
|
+
stepName: { type: String, default: '阶梯' },
|
|
79
88
|
precision: { type: Number, default: 2 },
|
|
80
89
|
// 左括号:默认 '[',传空字符串则不显示
|
|
81
90
|
leftBracket: { type: String, default: '[' },
|
|
@@ -125,11 +134,14 @@ export default {
|
|
|
125
134
|
|
|
126
135
|
cloneItems(items) {
|
|
127
136
|
if (!Array.isArray(items)) return []
|
|
128
|
-
return items.map((it) =>
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
137
|
+
return items.map((it) => {
|
|
138
|
+
const price = (it && it[this.keyPrice])
|
|
139
|
+
return {
|
|
140
|
+
[this.keyMin]: this.safeNumber(it && it[this.keyMin], 0),
|
|
141
|
+
[this.keyMax]: (it && it[this.keyMax] == null) || (it && it[this.keyMax] === '') ? null : this.safeNumber(it[this.keyMax], null),
|
|
142
|
+
[this.keyPrice]: (price === null || price === undefined || price === '') ? '' : this.safeNumber(price, 0)
|
|
143
|
+
}
|
|
144
|
+
})
|
|
133
145
|
},
|
|
134
146
|
|
|
135
147
|
normalize(items) {
|
|
@@ -160,7 +172,8 @@ export default {
|
|
|
160
172
|
} else {
|
|
161
173
|
cur[this.keyMax] = null
|
|
162
174
|
}
|
|
163
|
-
|
|
175
|
+
const price = cur[this.keyPrice]
|
|
176
|
+
cur[this.keyPrice] = (price === null || price === undefined || price === '') ? '' : this.safeNumber(price, 0)
|
|
164
177
|
}
|
|
165
178
|
},
|
|
166
179
|
|
|
@@ -169,15 +182,118 @@ export default {
|
|
|
169
182
|
const cloned = this.cloneItems(this.localItems)
|
|
170
183
|
this.$emit('input', cloned)
|
|
171
184
|
this.$emit('change', cloned)
|
|
185
|
+
this.dispatchFormEvent('el.form.change', cloned)
|
|
186
|
+
},
|
|
187
|
+
|
|
188
|
+
dispatchFormEvent(eventName, value) {
|
|
189
|
+
if (this.elFormItem) {
|
|
190
|
+
this.elFormItem.$emit(eventName, value)
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
|
|
194
|
+
onFieldBlur() {
|
|
195
|
+
this.dispatchFormEvent('el.form.blur', this.localItems)
|
|
196
|
+
},
|
|
197
|
+
|
|
198
|
+
validate(callback) {
|
|
199
|
+
const list = this.localItems
|
|
200
|
+
if (!Array.isArray(list) || list.length === 0) {
|
|
201
|
+
callback && callback(false, [{ field: 'stepPrice', message: `请配置${this.stepName}`, type: 'error' }])
|
|
202
|
+
return false
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const errors = []
|
|
206
|
+
for (let i = 0; i < list.length; i++) {
|
|
207
|
+
const item = list[i]
|
|
208
|
+
const rawPrice = item[this.keyPrice]
|
|
209
|
+
const rawMin = item[this.keyMin]
|
|
210
|
+
const rawMax = item[this.keyMax]
|
|
211
|
+
const price = this.safeNumber(rawPrice, 0)
|
|
212
|
+
const min = this.safeNumber(rawMin, 0)
|
|
213
|
+
|
|
214
|
+
if (rawPrice === null || rawPrice === undefined || rawPrice === '') {
|
|
215
|
+
errors.push({
|
|
216
|
+
field: `stepPrice[${i}].price`,
|
|
217
|
+
message: `第${i + 1}${this.stepName}价格不能为空`,
|
|
218
|
+
type: 'error'
|
|
219
|
+
})
|
|
220
|
+
} else if (price < 0) {
|
|
221
|
+
errors.push({
|
|
222
|
+
field: `stepPrice[${i}].price`,
|
|
223
|
+
message: `第${i + 1}${this.stepName}价格不能为负数`,
|
|
224
|
+
type: 'error'
|
|
225
|
+
})
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (rawMin === null || rawMin === undefined || rawMin === '') {
|
|
229
|
+
errors.push({
|
|
230
|
+
field: `stepPrice[${i}].min`,
|
|
231
|
+
message: `第${i + 1}${this.stepName}下限不能为空`,
|
|
232
|
+
type: 'error'
|
|
233
|
+
})
|
|
234
|
+
} else if (min < 0) {
|
|
235
|
+
errors.push({
|
|
236
|
+
field: `stepPrice[${i}].min`,
|
|
237
|
+
message: `第${i + 1}${this.stepName}下限不能为负数`,
|
|
238
|
+
type: 'error'
|
|
239
|
+
})
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (!this.isLast(i)) {
|
|
243
|
+
if (rawMax === null || rawMax === undefined || rawMax === '') {
|
|
244
|
+
errors.push({
|
|
245
|
+
field: `stepPrice[${i}].max`,
|
|
246
|
+
message: `第${i + 1}${this.stepName}上限不能为空`,
|
|
247
|
+
type: 'error'
|
|
248
|
+
})
|
|
249
|
+
} else if (this.safeNumber(rawMax, 0) <= min) {
|
|
250
|
+
errors.push({
|
|
251
|
+
field: `stepPrice[${i}].max`,
|
|
252
|
+
message: `第${i + 1}${this.stepName}上限必须大于下限`,
|
|
253
|
+
type: 'error'
|
|
254
|
+
})
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (i > 0) {
|
|
259
|
+
const prev = list[i - 1]
|
|
260
|
+
const prevMax = prev[this.keyMax]
|
|
261
|
+
if (prevMax !== null && this.safeNumber(prevMax, 0) !== min) {
|
|
262
|
+
errors.push({
|
|
263
|
+
field: `stepPrice[${i}].min`,
|
|
264
|
+
message: `第${i + 1}${this.stepName}下限必须等于上一${this.stepName}上限`,
|
|
265
|
+
type: 'error'
|
|
266
|
+
})
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (errors.length > 0) {
|
|
272
|
+
callback && callback(false, errors)
|
|
273
|
+
return false
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
callback && callback(true)
|
|
277
|
+
return true
|
|
278
|
+
},
|
|
279
|
+
|
|
280
|
+
isLast(idx) {
|
|
281
|
+
return idx === this.localItems.length - 1
|
|
172
282
|
},
|
|
173
283
|
|
|
174
284
|
onItemInput(val, idx) {
|
|
175
285
|
const cur = this.localItems[idx]
|
|
176
286
|
if (!cur) return
|
|
177
287
|
if (val && val[this.keyPrice] !== undefined) {
|
|
178
|
-
|
|
179
|
-
p
|
|
180
|
-
|
|
288
|
+
const p = val[this.keyPrice]
|
|
289
|
+
if (p === null || p === undefined || p === '') {
|
|
290
|
+
cur[this.keyPrice] = ''
|
|
291
|
+
} else {
|
|
292
|
+
let num = this.safeNumber(p, 0)
|
|
293
|
+
num = Number(num.toFixed(this.precision))
|
|
294
|
+
cur[this.keyPrice] = num
|
|
295
|
+
}
|
|
296
|
+
this.emit()
|
|
181
297
|
}
|
|
182
298
|
},
|
|
183
299
|
|
|
@@ -232,15 +348,8 @@ export default {
|
|
|
232
348
|
const newMin = this.safeNumber(last[this.keyMin], 0)
|
|
233
349
|
const newMax = newMin + stepVal
|
|
234
350
|
|
|
235
|
-
// 新条 price
|
|
236
|
-
|
|
237
|
-
let newPrice = 10
|
|
238
|
-
if (prev) {
|
|
239
|
-
newPrice = this.safeNumber(prev[this.keyPrice], 10)
|
|
240
|
-
} else {
|
|
241
|
-
const lastPrice = this.safeNumber(last[this.keyPrice], 0)
|
|
242
|
-
newPrice = lastPrice > 0 ? lastPrice : 10
|
|
243
|
-
}
|
|
351
|
+
// 新条 price:使用默认值,由用户自行填写
|
|
352
|
+
let newPrice = 0
|
|
244
353
|
|
|
245
354
|
const newArr = [
|
|
246
355
|
...list.slice(0, -1),
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<div class="xt-step-price-item">
|
|
3
3
|
<div class="xt-step-price-item__range">
|
|
4
4
|
<span class="xt-step-price-item__bracket">{{ finalLeftBracket }}</span>
|
|
5
|
-
<span v-if="itemsLength > 1" class="xt-step-price-item__name">第{{ index + 1 }}
|
|
5
|
+
<span v-if="itemsLength > 1" class="xt-step-price-item__name">第{{ index + 1 }}{{stepName}}</span>
|
|
6
6
|
<span class="xt-step-price-item__bracket">{{ finalRightBracket }}</span>
|
|
7
7
|
<xt-input
|
|
8
8
|
v-model.number="minInput"
|
|
@@ -10,17 +10,18 @@
|
|
|
10
10
|
size="small"
|
|
11
11
|
placeholder="下限"
|
|
12
12
|
class="xt-step-price-item__input"
|
|
13
|
-
@blur="onMinBlur"
|
|
13
|
+
@blur="(e) => { onMinBlur(); onBlur(e) }"
|
|
14
14
|
/>
|
|
15
15
|
<span class="xt-step-price-item__comma">-</span>
|
|
16
16
|
<xt-input
|
|
17
17
|
v-if="!isLast"
|
|
18
18
|
v-model.number="maxInput"
|
|
19
|
+
type="number"
|
|
19
20
|
:disabled="disabled"
|
|
20
21
|
size="small"
|
|
21
22
|
placeholder="上限"
|
|
22
23
|
class="xt-step-price-item__input"
|
|
23
|
-
@blur="onMaxBlur"
|
|
24
|
+
@blur="(e) => { onMaxBlur(); onBlur(e) }"
|
|
24
25
|
/>
|
|
25
26
|
<span v-else class="xt-step-price-item__infinity">+∞</span>
|
|
26
27
|
</div>
|
|
@@ -29,11 +30,12 @@
|
|
|
29
30
|
<div class="xt-step-price-item__price">
|
|
30
31
|
<xt-input
|
|
31
32
|
v-model.number="priceInput"
|
|
33
|
+
type="number"
|
|
32
34
|
:disabled="disabled"
|
|
33
35
|
size="small"
|
|
34
36
|
placeholder="价格"
|
|
35
37
|
class="xt-step-price-item__input xt-step-price-item__input--price"
|
|
36
|
-
@blur="onPriceBlur"
|
|
38
|
+
@blur="(e) => { onPriceBlur(); onBlur(e) }"
|
|
37
39
|
/>
|
|
38
40
|
<span class="xt-step-price-item__unit">{{ unit }}</span>
|
|
39
41
|
</div>
|
|
@@ -58,6 +60,7 @@ export default {
|
|
|
58
60
|
required: true,
|
|
59
61
|
default: () => ({ min: 0, max: null, price: 0 })
|
|
60
62
|
},
|
|
63
|
+
stepName: { type: String, default: '阶梯' },
|
|
61
64
|
index: { type: Number, default: 0 },
|
|
62
65
|
isFirst: { type: Boolean, default: false },
|
|
63
66
|
isLast: { type: Boolean, default: false },
|
|
@@ -177,13 +180,23 @@ export default {
|
|
|
177
180
|
},
|
|
178
181
|
|
|
179
182
|
onPriceBlur() {
|
|
180
|
-
|
|
183
|
+
const rawVal = this.priceInput
|
|
184
|
+
if (rawVal === null || rawVal === undefined || rawVal === '' || isNaN(rawVal)) {
|
|
185
|
+
this.priceInput = ''
|
|
186
|
+
this.emitChange({ [this.keyPrice]: '' })
|
|
187
|
+
return
|
|
188
|
+
}
|
|
189
|
+
let v = this.safeNumber(rawVal, 0)
|
|
181
190
|
if (v < 0) v = 0
|
|
182
191
|
v = Number(v.toFixed(this.precision))
|
|
183
192
|
this.priceInput = v
|
|
184
193
|
this.emitChange({ [this.keyPrice]: v })
|
|
185
194
|
},
|
|
186
195
|
|
|
196
|
+
onBlur(e) {
|
|
197
|
+
this.$emit('blur', e)
|
|
198
|
+
},
|
|
199
|
+
|
|
187
200
|
onDelete() {
|
|
188
201
|
this.$emit('delete', this.index)
|
|
189
202
|
}
|