xt-element-ui 1.2.7 → 1.3.0

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.
@@ -3,14 +3,14 @@
3
3
  <div v-if="title || $slots.header" class="xt-step-price__header">
4
4
  <xt-text v-if="title" bold size="medium">{{ title }}</xt-text>
5
5
  <slot name="header" />
6
- <el-button
6
+ <xt-button
7
7
  v-if="!disabled && !isLimitReached"
8
8
  type="primary"
9
9
  size="small"
10
10
  icon="el-icon-plus"
11
11
  plain
12
12
  @click="onAdd"
13
- >新增阶梯</el-button>
13
+ >新增档位</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="step"
30
31
  :left-bracket="leftBracket"
31
32
  :right-bracket="rightBracket"
32
33
  :field-keys="fieldKeys"
@@ -39,7 +40,7 @@
39
40
  </div>
40
41
 
41
42
  <div v-if="localItems.length === 0" class="xt-step-price__empty">
42
- <span>暂无数据,点击右上角「新增阶梯」开始配置</span>
43
+ <span>暂无数据,点击右上角「新增档位」开始配置</span>
43
44
  </div>
44
45
 
45
46
  <div v-if="tip || $slots.tip" class="xt-step-price__tip">
@@ -87,6 +88,8 @@ export default {
87
88
  },
88
89
  // 阶梯数量上限;<= 0 表示不限制
89
90
  limit: { type: Number, default: 0 },
91
+ // 阶梯增量:新增/校正时,下一条阶梯的 min = 当前 max = 当前 min + step(默认 1)
92
+ step: { type: Number, default: 10 },
90
93
  disabled: { type: Boolean, default: false },
91
94
  tip: {
92
95
  type: String,
@@ -105,6 +108,7 @@ export default {
105
108
  watch: {
106
109
  value: {
107
110
  deep: true,
111
+ immediate: true,
108
112
  handler(val) {
109
113
  this.localItems = this.normalize(val)
110
114
  }
@@ -141,14 +145,15 @@ export default {
141
145
  ensureContinuity(list) {
142
146
  if (!Array.isArray(list) || list.length === 0) return
143
147
  list[0][this.keyMin] = 0
148
+ const stepVal = this.safeNumber(this.step, 1)
144
149
 
145
150
  for (let i = 0; i < list.length; i++) {
146
151
  const cur = list[i]
147
152
  const next = list[i + 1]
148
153
  const curMin = this.safeNumber(cur[this.keyMin], 0)
149
154
  if (next) {
150
- let curMax = this.safeNumber(cur[this.keyMax], curMin + 1)
151
- if (curMax <= curMin) curMax = curMin + 1
155
+ let curMax = this.safeNumber(cur[this.keyMax], curMin + stepVal)
156
+ if (curMax <= curMin) curMax = curMin + stepVal
152
157
  cur[this.keyMax] = curMax
153
158
  next[this.keyMin] = curMax
154
159
  } else {
@@ -196,10 +201,10 @@ export default {
196
201
  },
197
202
 
198
203
  onAdd() {
199
- debugger
200
204
  const list = this.localItems
201
205
  const lim = Number(this.limit)
202
206
  if (lim > 0 && list.length >= lim) return
207
+ const stepVal = this.safeNumber(this.step, 1)
203
208
 
204
209
  // 场景 1:空数组 —— 直接 push 一条 [0, +∞)
205
210
  if (list.length === 0) {
@@ -212,10 +217,10 @@ export default {
212
217
  return
213
218
  }
214
219
 
215
- // 场景 2:已有数据 —— 在末条前插入新条
220
+ // 场景 2:已有数据 —— 在末条前插入新条,新条的 max = 末条 min + step
216
221
  const last = list[list.length - 1]
217
222
  const newMin = this.safeNumber(last[this.keyMin], 0)
218
- const newMax = newMin + 1
223
+ const newMax = newMin + stepVal
219
224
 
220
225
  // 新条 price:优先继承「倒数第二条」的 price,其次用末条 price(>0 时),否则默认 10
221
226
  const prev = list[list.length - 2]
@@ -227,9 +232,6 @@ export default {
227
232
  newPrice = lastPrice > 0 ? lastPrice : 10
228
233
  }
229
234
 
230
- // 关键修复:构造全新数组,避免 splice 导致 Vue 组件复用 & 响应式不同步
231
- // 新条 = { newMin, newMax, newPrice }
232
- // 新末条 = { min: newMax, max: null, price: newPrice }
233
235
  const newArr = [
234
236
  ...list.slice(0, -1),
235
237
  {
@@ -1,8 +1,10 @@
1
+ @import '../../../styles/variables.scss';
2
+
1
3
  .xt-step-price {
2
4
  padding: 12px 16px;
3
- background-color: #ffffff;
4
- border: 1px solid #ebeef5;
5
- border-radius: 4px;
5
+ background-color: var(--xt-fill-color-blank, #ffffff);
6
+ border: 1px solid var(--xt-border-color-lighter, #ebeef5);
7
+ border-radius: var(--xt-border-radius-base, 4px);
6
8
 
7
9
  &__header {
8
10
  display: flex;
@@ -20,19 +22,19 @@
20
22
  &__empty {
21
23
  padding: 24px;
22
24
  text-align: center;
23
- color: #909399;
24
- font-size: 13px;
25
+ color: var(--xt-text-color-secondary, #909399);
26
+ font-size: var(--xt-font-size-small, 13px);
25
27
  }
26
28
 
27
29
  &__tip {
28
30
  margin-top: 12px;
29
- color: #909399;
30
- font-size: 12px;
31
+ color: var(--xt-text-color-secondary, #909399);
32
+ font-size: var(--xt-font-size-extra-small, 12px);
31
33
  line-height: 1.6;
32
34
  }
33
35
 
34
36
  &.is-disabled {
35
- background-color: #fafafa;
37
+ background-color: var(--xt-fill-color-light, #f5f7fa);
36
38
  opacity: 0.85;
37
39
  pointer-events: none;
38
40
  }
@@ -42,44 +44,50 @@
42
44
  display: flex;
43
45
  align-items: center;
44
46
  padding: 8px 12px;
45
- background-color: #f5f7fa;
46
- border-radius: 4px;
47
- transition: background-color 0.2s ease;
47
+ gap: 8px;
48
+ background-color: var(--xt-fill-color-light, #f5f7fa);
49
+ border-radius: var(--xt-border-radius-base, 4px);
50
+ transition: background-color var(--xt-transition-duration-fast, 0.2s) ease;
48
51
 
49
52
  &:hover {
50
- background-color: #ecf0f4;
53
+ background-color: var(--xt-fill-color, #f0f2f5);
51
54
  }
52
55
 
53
56
  &__range {
54
57
  display: inline-flex;
55
58
  align-items: center;
56
59
  flex: 0 0 auto;
57
- color: #606266;
58
- font-size: 13px;
60
+ color: var(--xt-text-color-regular, #606266);
61
+ font-size: var(--xt-font-size-small, 13px);
62
+ }
63
+
64
+ &__name {
65
+ color: var(--xt-text-color-primary, #303133);
66
+ font-weight: 600;
59
67
  }
60
68
 
61
69
  &__bracket {
62
70
  margin: 0 4px;
63
- color: #909399;
71
+ color: var(--xt-text-color-secondary, #909399);
64
72
  font-weight: 600;
65
73
  }
66
74
 
67
75
  &__comma {
68
76
  margin: 0 6px;
69
- color: #909399;
77
+ color: var(--xt-text-color-secondary, #909399);
70
78
  }
71
79
 
72
80
  &__infinity {
73
81
  display: inline-block;
74
- min-width: 60px;
82
+ min-width: 80px;
75
83
  text-align: center;
76
- color: #c0c4cc;
77
- font-size: 13px;
84
+ color: var(--xt-text-color-placeholder, #c0c4cc);
85
+ font-size: var(--xt-font-size-small, 13px);
78
86
  }
79
87
 
80
88
  &__arrow {
81
89
  margin: 0 12px;
82
- color: #409eff;
90
+ color: var(--xt-color-primary, #1890ff);
83
91
  font-weight: 600;
84
92
  }
85
93
 
@@ -91,8 +99,8 @@
91
99
 
92
100
  &__unit {
93
101
  margin-left: 8px;
94
- color: #606266;
95
- font-size: 13px;
102
+ color: var(--xt-text-color-regular, #606266);
103
+ font-size: var(--xt-font-size-small, 13px);
96
104
  }
97
105
 
98
106
  &__input {
@@ -106,10 +114,10 @@
106
114
 
107
115
  &__delete {
108
116
  margin-left: 12px;
109
- color: #f56c6c !important;
117
+ color: var(--xt-color-danger, #f56c6c) !important;
110
118
  }
111
119
 
112
120
  &__delete:hover {
113
- color: #f78989 !important;
121
+ color: var(--xt-color-danger-light-5, #f57786) !important;
114
122
  }
115
123
  }
@@ -2,15 +2,17 @@
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
- <el-input
5
+ <span v-if="itemsLength > 1" class="xt-step-price-item__name">第{{ index + 1 }}档</span>
6
+ <span class="xt-step-price-item__bracket">{{ finalRightBracket }}</span>
7
+ <xt-input
6
8
  v-model.number="minInput"
7
9
  :disabled="disabled || minLocked"
8
10
  size="small"
9
11
  class="xt-step-price-item__input"
10
12
  @blur="onMinBlur"
11
13
  />
12
- <span class="xt-step-price-item__comma">,</span>
13
- <el-input
14
+ <span class="xt-step-price-item__comma">-</span>
15
+ <xt-input
14
16
  v-if="!isLast"
15
17
  v-model.number="maxInput"
16
18
  :disabled="disabled"
@@ -19,13 +21,11 @@
19
21
  @blur="onMaxBlur"
20
22
  />
21
23
  <span v-else class="xt-step-price-item__infinity">+∞</span>
22
- <span class="xt-step-price-item__bracket">{{ finalRightBracket }}</span>
23
24
  </div>
24
25
 
25
- <span class="xt-step-price-item__arrow">→</span>
26
26
 
27
27
  <div class="xt-step-price-item__price">
28
- <el-input
28
+ <xt-input
29
29
  v-model.number="priceInput"
30
30
  :disabled="disabled"
31
31
  size="small"
@@ -36,9 +36,9 @@
36
36
  <span class="xt-step-price-item__unit">{{ unit }}</span>
37
37
  </div>
38
38
 
39
- <el-button
39
+ <xt-button
40
40
  v-if="!disabled && removable && itemsLength > 1"
41
- type="text"
41
+ text
42
42
  icon="el-icon-delete"
43
43
  class="xt-step-price-item__delete"
44
44
  @click="onDelete"
@@ -65,6 +65,8 @@ export default {
65
65
  minLocked: { type: Boolean, default: false },
66
66
  unit: { type: String, default: '元' },
67
67
  precision: { type: Number, default: 2 },
68
+ // 阶梯增量:控制新增/校正时的区间跨度,默认 1
69
+ step: { type: Number, default: 1 },
68
70
  // 左括号:默认 '[',传空则不显示
69
71
  leftBracket: { type: String, default: '[' },
70
72
  // 右括号:默认 null,走内置规则(只有1条为 ']',多条为 ')');传值则强制使用
@@ -90,10 +92,7 @@ export default {
90
92
  },
91
93
 
92
94
  data() {
93
- const v = this.value
94
- const minVal = this.safeNumber(v && v[this.keyMin], 0)
95
- const maxVal = this.isLast ? null : this.safeNumber(v && v[this.keyMax], minVal + 1)
96
- const priceVal = this.safeNumber(v && v[this.keyPrice], 0)
95
+ const { minVal, maxVal, priceVal } = this.getPriceItem(this.value)
97
96
  return {
98
97
  minInput: minVal,
99
98
  maxInput: maxVal,
@@ -104,11 +103,12 @@ export default {
104
103
  watch: {
105
104
  value: {
106
105
  deep: true,
106
+ immediate: true,
107
107
  handler(val) {
108
- const minVal = this.safeNumber(val && val[this.keyMin], 0)
108
+ const { minVal, maxVal, priceVal } = this.getPriceItem(val)
109
109
  this.minInput = minVal
110
- this.maxInput = this.isLast ? null : this.safeNumber(val && val[this.keyMax], minVal + 1)
111
- this.priceInput = this.safeNumber(val && val[this.keyPrice], 0)
110
+ this.maxInput = maxVal
111
+ this.priceInput = priceVal
112
112
  }
113
113
  },
114
114
  isLast(val) {
@@ -123,6 +123,17 @@ export default {
123
123
  },
124
124
 
125
125
  methods: {
126
+ getPriceItem(value) {
127
+ const v = value
128
+ const minVal = this.safeNumber(v && v[this.keyMin], 0)
129
+ const maxVal = this.isLast ? null : this.safeNumber(v && v[this.keyMax], minVal + 1)
130
+ const priceVal = this.safeNumber(v && v[this.keyPrice], 0)
131
+ return {
132
+ minVal,
133
+ maxVal,
134
+ priceVal
135
+ }
136
+ },
126
137
  // 统一兜底:非数字输入一律转为 fallback(默认 0)
127
138
  safeNumber(v, fallback = 0) {
128
139
  if (v === null || v === undefined || v === '' || v === Infinity || v === -Infinity) return fallback