uview-plus 3.5.20 → 3.5.22
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/changelog.md
CHANGED
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<view class="up-goods-sku">
|
|
3
|
+
<view @click="open">
|
|
4
|
+
<slot name="trigger"></slot>
|
|
5
|
+
</view>
|
|
6
|
+
<up-popup
|
|
7
|
+
v-model:show="show"
|
|
8
|
+
mode="bottom"
|
|
9
|
+
:closeable="pageInline ? false : closeable"
|
|
10
|
+
:pageInline="pageInline"
|
|
11
|
+
:border-radius="20"
|
|
12
|
+
@close="close"
|
|
13
|
+
>
|
|
14
|
+
<view class="up-goods-sku-container" :style="{padding: pageInline ? '0px' : ''}">
|
|
15
|
+
<view class="up-goods-sku__header">
|
|
16
|
+
<slot name="header">
|
|
17
|
+
<view class="up-goods-sku__header__image">
|
|
18
|
+
<image :src="goodsInfo.image || goodsInfo.picture" mode="aspectFill"></image>
|
|
19
|
+
</view>
|
|
20
|
+
<view class="up-goods-sku__header__info">
|
|
21
|
+
<view class="up-goods-sku__header__info__price">
|
|
22
|
+
<text class="up-goods-sku__header__info__price__symbol">¥</text>
|
|
23
|
+
<text class="up-goods-sku__header__info__price__value">{{ price }}</text>
|
|
24
|
+
</view>
|
|
25
|
+
<view class="up-goods-sku__header__info__stock">库存 {{ stock }} 件</view>
|
|
26
|
+
<view class="up-goods-sku__header__info__selected">已选: {{ selectedSkuText }}</view>
|
|
27
|
+
</view>
|
|
28
|
+
</slot>
|
|
29
|
+
</view>
|
|
30
|
+
|
|
31
|
+
<scroll-view class="up-goods-sku__content" scroll-y>
|
|
32
|
+
<view v-for="(treeItem, index) in skuTree" :key="index" class="up-goods-sku__content__item">
|
|
33
|
+
<view class="up-goods-sku__content__item__title">{{ treeItem.label }}</view>
|
|
34
|
+
<view class="up-goods-sku__content__item__list">
|
|
35
|
+
<view
|
|
36
|
+
v-for="(leafItem, leafIndex) in treeItem.children"
|
|
37
|
+
:key="leafIndex"
|
|
38
|
+
class="up-goods-sku__content__item__list__item"
|
|
39
|
+
:class="{
|
|
40
|
+
'up-goods-sku__content__item__list__item--active': isSelected(treeItem.name, leafItem.id),
|
|
41
|
+
'up-goods-sku__content__item__list__item--disabled': isDisabled(treeItem.name, leafItem.id)
|
|
42
|
+
}"
|
|
43
|
+
@click="onSkuClick(treeItem.name, leafItem)"
|
|
44
|
+
>
|
|
45
|
+
<text>{{ leafItem.name }}</text>
|
|
46
|
+
</view>
|
|
47
|
+
</view>
|
|
48
|
+
</view>
|
|
49
|
+
|
|
50
|
+
<view class="up-goods-sku__content__count">
|
|
51
|
+
<view class="up-goods-sku__content__count__title">购买数量</view>
|
|
52
|
+
<view class="up-goods-sku__content__count__control">
|
|
53
|
+
<up-number-box
|
|
54
|
+
v-model="buyNum"
|
|
55
|
+
:min="1"
|
|
56
|
+
:max="maxBuyNum"
|
|
57
|
+
:disabled="!canBuy"
|
|
58
|
+
@change="onNumChange"
|
|
59
|
+
></up-number-box>
|
|
60
|
+
</view>
|
|
61
|
+
</view>
|
|
62
|
+
</scroll-view>
|
|
63
|
+
|
|
64
|
+
<view class="up-goods-sku__footer">
|
|
65
|
+
<up-button
|
|
66
|
+
type="primary"
|
|
67
|
+
:disabled="!canBuy"
|
|
68
|
+
@click="onConfirm"
|
|
69
|
+
>
|
|
70
|
+
{{ confirmText }}
|
|
71
|
+
</up-button>
|
|
72
|
+
</view>
|
|
73
|
+
</view>
|
|
74
|
+
</up-popup>
|
|
75
|
+
</view>
|
|
76
|
+
</template>
|
|
77
|
+
|
|
78
|
+
<script>
|
|
79
|
+
export default {
|
|
80
|
+
name: 'up-goods-sku',
|
|
81
|
+
props: {
|
|
82
|
+
// 商品信息
|
|
83
|
+
goodsInfo: {
|
|
84
|
+
type: Object,
|
|
85
|
+
default: () => ({})
|
|
86
|
+
},
|
|
87
|
+
// SKU树形结构
|
|
88
|
+
skuTree: {
|
|
89
|
+
type: Array,
|
|
90
|
+
default: () => []
|
|
91
|
+
},
|
|
92
|
+
// SKU列表
|
|
93
|
+
skuList: {
|
|
94
|
+
type: Array,
|
|
95
|
+
default: () => []
|
|
96
|
+
},
|
|
97
|
+
// 最大购买数量
|
|
98
|
+
maxBuy: {
|
|
99
|
+
type: Number,
|
|
100
|
+
default: 999
|
|
101
|
+
},
|
|
102
|
+
// 确认按钮文字
|
|
103
|
+
confirmText: {
|
|
104
|
+
type: String,
|
|
105
|
+
default: '确定'
|
|
106
|
+
},
|
|
107
|
+
// 是否显示关闭弹窗按钮
|
|
108
|
+
closeable: {
|
|
109
|
+
type: Boolean,
|
|
110
|
+
default: true
|
|
111
|
+
},
|
|
112
|
+
// 是否页面内联模式
|
|
113
|
+
pageInline: {
|
|
114
|
+
type: Boolean,
|
|
115
|
+
default: false
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
data() {
|
|
119
|
+
return {
|
|
120
|
+
show: false,
|
|
121
|
+
// 已选择的SKU
|
|
122
|
+
selectedSku: {},
|
|
123
|
+
// 购买数量
|
|
124
|
+
buyNum: 1
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
computed: {
|
|
128
|
+
// 当前价格
|
|
129
|
+
price() {
|
|
130
|
+
const selectedSkuComb = this.getSelectedSkuComb()
|
|
131
|
+
if (selectedSkuComb) {
|
|
132
|
+
return selectedSkuComb.price || selectedSkuComb.price_fee
|
|
133
|
+
}
|
|
134
|
+
return this.goodsInfo.price || this.goodsInfo.price_fee || 0
|
|
135
|
+
},
|
|
136
|
+
// 当前库存
|
|
137
|
+
stock() {
|
|
138
|
+
const selectedSkuComb = this.getSelectedSkuComb()
|
|
139
|
+
if (selectedSkuComb) {
|
|
140
|
+
return selectedSkuComb.stock || selectedSkuComb.quantity
|
|
141
|
+
}
|
|
142
|
+
return this.goodsInfo.stock || this.goodsInfo.quantity || 0
|
|
143
|
+
},
|
|
144
|
+
// 最大购买数量
|
|
145
|
+
maxBuyNum() {
|
|
146
|
+
const stock = this.stock
|
|
147
|
+
return stock > this.maxBuy ? this.maxBuy : stock
|
|
148
|
+
},
|
|
149
|
+
// 是否可以购买
|
|
150
|
+
canBuy() {
|
|
151
|
+
const selectedSkuCount = Object.keys(this.selectedSku).length
|
|
152
|
+
const skuTreeCount = this.skuTree.length
|
|
153
|
+
return selectedSkuCount === skuTreeCount && this.buyNum > 0 && this.stock > 0
|
|
154
|
+
},
|
|
155
|
+
// 已选SKU文字描述
|
|
156
|
+
selectedSkuText() {
|
|
157
|
+
const selected = []
|
|
158
|
+
Object.keys(this.selectedSku).forEach(key => {
|
|
159
|
+
const value = this.selectedSku[key]
|
|
160
|
+
if (value) {
|
|
161
|
+
this.skuTree.forEach(treeItem => {
|
|
162
|
+
if (treeItem.name === key) {
|
|
163
|
+
treeItem.children.forEach(leafItem => {
|
|
164
|
+
if (leafItem.id === value) {
|
|
165
|
+
selected.push(leafItem.name)
|
|
166
|
+
}
|
|
167
|
+
})
|
|
168
|
+
}
|
|
169
|
+
})
|
|
170
|
+
}
|
|
171
|
+
})
|
|
172
|
+
return selected.join(', ')
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
watch: {
|
|
176
|
+
},
|
|
177
|
+
emits: ['open', 'confirm', 'close'],
|
|
178
|
+
created() {
|
|
179
|
+
if (this.pageInline) {
|
|
180
|
+
this.show = true;
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
methods: {
|
|
184
|
+
// 判断SKU是否被选中
|
|
185
|
+
isSelected(skuKey, skuValueId) {
|
|
186
|
+
return this.selectedSku[skuKey] === skuValueId
|
|
187
|
+
},
|
|
188
|
+
// 判断SKU是否禁用
|
|
189
|
+
isDisabled(skuKey, skuValueId) {
|
|
190
|
+
// 构造一个临时的已选中SKU对象
|
|
191
|
+
const tempSelected = { ...this.selectedSku, [skuKey]: skuValueId }
|
|
192
|
+
|
|
193
|
+
// 检查是否还有未选择的SKU维度
|
|
194
|
+
const selectedCount = Object.keys(tempSelected).filter(key => tempSelected[key]).length
|
|
195
|
+
const totalSkuCount = this.skuTree.length
|
|
196
|
+
|
|
197
|
+
// 如果所有SKU都已选择,则检查组合是否存在
|
|
198
|
+
if (selectedCount === totalSkuCount) {
|
|
199
|
+
return !this.getSkuComb(tempSelected)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// 检查当前选择的SKU是否会导致无法组成有效组合
|
|
203
|
+
for (let i = 0; i < this.skuList.length; i++) {
|
|
204
|
+
const sku = this.skuList[i]
|
|
205
|
+
let match = true
|
|
206
|
+
|
|
207
|
+
// 检查已选中的SKU是否匹配
|
|
208
|
+
for (const key in tempSelected) {
|
|
209
|
+
if (tempSelected[key] && sku[key] !== tempSelected[key]) {
|
|
210
|
+
match = false
|
|
211
|
+
break
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (match) {
|
|
216
|
+
return false
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return true
|
|
221
|
+
},
|
|
222
|
+
// SKU点击事件
|
|
223
|
+
onSkuClick(skuKey, skuValue) {
|
|
224
|
+
// 如果是禁用状态,直接返回
|
|
225
|
+
if (this.isDisabled(skuKey, skuValue.id)) {
|
|
226
|
+
return
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// 如果已选中,则取消选中
|
|
230
|
+
if (this.selectedSku[skuKey] === skuValue.id) {
|
|
231
|
+
this.$set(this.selectedSku, skuKey, '')
|
|
232
|
+
} else {
|
|
233
|
+
this.$set(this.selectedSku, skuKey, skuValue.id)
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
// 数量改变事件
|
|
237
|
+
onNumChange(e) {
|
|
238
|
+
this.buyNum = e.value
|
|
239
|
+
},
|
|
240
|
+
// 获取选中的SKU组合
|
|
241
|
+
getSelectedSkuComb() {
|
|
242
|
+
return this.getSkuComb(this.selectedSku)
|
|
243
|
+
},
|
|
244
|
+
// 根据已选SKU获取组合信息
|
|
245
|
+
getSkuComb(selectedSku) {
|
|
246
|
+
const selected = { ...selectedSku }
|
|
247
|
+
|
|
248
|
+
// 过滤掉空值
|
|
249
|
+
Object.keys(selected).forEach(key => {
|
|
250
|
+
if (!selected[key]) {
|
|
251
|
+
delete selected[key]
|
|
252
|
+
}
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
// 检查是否所有SKU都已选择
|
|
256
|
+
if (Object.keys(selected).length !== this.skuTree.length) {
|
|
257
|
+
return null
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// 查找匹配的SKU组合
|
|
261
|
+
for (let i = 0; i < this.skuList.length; i++) {
|
|
262
|
+
const sku = this.skuList[i]
|
|
263
|
+
let match = true
|
|
264
|
+
|
|
265
|
+
for (const key in selected) {
|
|
266
|
+
if (sku[key] !== selected[key]) {
|
|
267
|
+
match = false
|
|
268
|
+
break
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (match) {
|
|
273
|
+
return sku
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return null
|
|
278
|
+
},
|
|
279
|
+
// 重置选择
|
|
280
|
+
reset() {
|
|
281
|
+
this.selectedSku = {}
|
|
282
|
+
this.buyNum = 1
|
|
283
|
+
},
|
|
284
|
+
open() {
|
|
285
|
+
this.show = true;
|
|
286
|
+
this.$emit('open')
|
|
287
|
+
},
|
|
288
|
+
// 关闭弹窗
|
|
289
|
+
close() {
|
|
290
|
+
this.false = true;
|
|
291
|
+
this.$emit('close')
|
|
292
|
+
},
|
|
293
|
+
// 确认选择
|
|
294
|
+
onConfirm() {
|
|
295
|
+
if (!this.canBuy) {
|
|
296
|
+
return
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const selectedSkuComb = this.getSelectedSkuComb()
|
|
300
|
+
this.$emit('confirm', {
|
|
301
|
+
sku: selectedSkuComb,
|
|
302
|
+
goodsInfo: this.goodsInfo,
|
|
303
|
+
num: this.buyNum,
|
|
304
|
+
selectedText: this.selectedSkuText
|
|
305
|
+
})
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
</script>
|
|
310
|
+
|
|
311
|
+
<style lang="scss" scoped>
|
|
312
|
+
.up-goods-sku {
|
|
313
|
+
background-color: #fff;
|
|
314
|
+
overflow: hidden;
|
|
315
|
+
|
|
316
|
+
.up-goods-sku-container {
|
|
317
|
+
padding: 4rpx 30rpx;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
&__header {
|
|
321
|
+
display: flex;
|
|
322
|
+
flex-direction: row;
|
|
323
|
+
padding: 30rpx 0;
|
|
324
|
+
position: relative;
|
|
325
|
+
|
|
326
|
+
&__image {
|
|
327
|
+
width: 180rpx;
|
|
328
|
+
height: 180rpx;
|
|
329
|
+
border-radius: 10rpx;
|
|
330
|
+
overflow: hidden;
|
|
331
|
+
margin-right: 20rpx;
|
|
332
|
+
|
|
333
|
+
image {
|
|
334
|
+
width: 100%;
|
|
335
|
+
height: 100%;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
&__info {
|
|
340
|
+
flex: 1;
|
|
341
|
+
|
|
342
|
+
&__price {
|
|
343
|
+
display: flex;
|
|
344
|
+
flex-direction: row;
|
|
345
|
+
align-items: baseline;
|
|
346
|
+
margin-bottom: 20rpx;
|
|
347
|
+
|
|
348
|
+
&__symbol {
|
|
349
|
+
font-size: 24rpx;
|
|
350
|
+
color: #fa3534;
|
|
351
|
+
margin-right: 4rpx;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
&__value {
|
|
355
|
+
font-size: 36rpx;
|
|
356
|
+
color: #fa3534;
|
|
357
|
+
font-weight: bold;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
&__stock {
|
|
362
|
+
font-size: 26rpx;
|
|
363
|
+
color: #999;
|
|
364
|
+
margin-bottom: 20rpx;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
&__selected {
|
|
368
|
+
font-size: 26rpx;
|
|
369
|
+
color: #333;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
&__content {
|
|
375
|
+
max-height: 600rpx;
|
|
376
|
+
padding: 0 30rpx 30rpx 0;
|
|
377
|
+
|
|
378
|
+
&__item {
|
|
379
|
+
margin-bottom: 30rpx;
|
|
380
|
+
|
|
381
|
+
&__title {
|
|
382
|
+
font-size: 28rpx;
|
|
383
|
+
color: #333;
|
|
384
|
+
margin-bottom: 20rpx;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
&__list {
|
|
388
|
+
display: flex;
|
|
389
|
+
flex-direction: row;
|
|
390
|
+
flex-wrap: wrap;
|
|
391
|
+
|
|
392
|
+
&__item {
|
|
393
|
+
padding: 10rpx 20rpx;
|
|
394
|
+
border: 2rpx solid #eee;
|
|
395
|
+
border-radius: 10rpx;
|
|
396
|
+
margin-right: 20rpx;
|
|
397
|
+
margin-bottom: 20rpx;
|
|
398
|
+
font-size: 26rpx;
|
|
399
|
+
color: #333;
|
|
400
|
+
|
|
401
|
+
&--active {
|
|
402
|
+
border-color: #fa3534;
|
|
403
|
+
color: #fa3534;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
&--disabled {
|
|
407
|
+
color: #ccc;
|
|
408
|
+
border-color: #eee;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
&__count {
|
|
415
|
+
display: flex;
|
|
416
|
+
flex-direction: row;
|
|
417
|
+
align-items: center;
|
|
418
|
+
justify-content: space-between;
|
|
419
|
+
margin-top: 20rpx;
|
|
420
|
+
|
|
421
|
+
&__title {
|
|
422
|
+
font-size: 28rpx;
|
|
423
|
+
color: #333;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
&__footer {
|
|
429
|
+
padding: 20rpx 0rpx 40rpx 0;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
</style>
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
<u-transition
|
|
21
21
|
class="u-popup__content—transition"
|
|
22
22
|
:style="contentStyleWrap"
|
|
23
|
-
:show="show"
|
|
23
|
+
:show="pageInline ? true : show"
|
|
24
24
|
:customStyle="transitionStyle"
|
|
25
25
|
:mode="pageInline ? 'none' : position"
|
|
26
26
|
:duration="duration"
|
|
@@ -96,8 +96,8 @@
|
|
|
96
96
|
* @property {String } bgColor 背景色值(默认 '' )
|
|
97
97
|
* @property {Boolean} zoom 当mode=center时 是否开启缩放(默认 true )
|
|
98
98
|
* @property {Boolean} touchable 是否开启底部弹窗手势功能(默认 false )
|
|
99
|
-
* @property {String
|
|
100
|
-
* @property {String
|
|
99
|
+
* @property {String} minHeight 最小高度,单位任意,数值默认为px(默认 '200px' )
|
|
100
|
+
* @property {String} maxHeight 最大高度,单位任意,数值默认为px(默认 '80%' )
|
|
101
101
|
* @property {Object} customStyle 组件的样式,对象形式
|
|
102
102
|
* @event {Function} open 弹出层打开
|
|
103
103
|
* @event {Function} close 弹出层收起
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "uview-plus",
|
|
3
3
|
"name": "uview-plus",
|
|
4
4
|
"displayName": "零云®uview-plus3.0重磅发布,全面的Vue3鸿蒙跨端移动组件库,组件丰富维护更新稳定。",
|
|
5
|
-
"version": "3.5.
|
|
5
|
+
"version": "3.5.22",
|
|
6
6
|
"description": "零云®uview-plus已兼容vue3支持多语言,100+全面的组件和便捷的工具会让您信手拈来。近期新增拖动排序、条码、图片裁剪、下拉刷新、虚拟列表、签名、Markdown等。",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"uview",
|