hy-app 0.6.4 → 0.6.6

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.
Files changed (106) hide show
  1. package/attributes.json +1 -1
  2. package/components/hy-address-picker/hy-address-picker.vue +249 -249
  3. package/components/hy-address-picker/props.ts +103 -103
  4. package/components/hy-button/hy-button.vue +320 -289
  5. package/components/hy-button/props.ts +143 -143
  6. package/components/hy-button/typing.d.ts +43 -35
  7. package/components/hy-calendar/header.vue +58 -58
  8. package/components/hy-calendar/hy-calendar.vue +8 -6
  9. package/components/hy-calendar/month.vue +402 -402
  10. package/components/hy-calendar/props.ts +169 -169
  11. package/components/hy-calendar/typing.d.ts +47 -45
  12. package/components/hy-cell-item/hy-cell-item.vue +161 -161
  13. package/components/hy-cell-item/props.ts +59 -59
  14. package/components/hy-check-button/hy-check-button.vue +135 -135
  15. package/components/hy-code-input/hy-code-input.vue +231 -231
  16. package/components/hy-code-input/props.ts +90 -90
  17. package/components/hy-config-provider/hy-config-provider.vue +53 -53
  18. package/components/hy-config-provider/props.ts +30 -30
  19. package/components/hy-coupon/hy-coupon.vue +183 -183
  20. package/components/hy-coupon/props.ts +108 -108
  21. package/components/hy-datetime-picker/hy-datetime-picker.vue +41 -55
  22. package/components/hy-datetime-picker/props.ts +144 -144
  23. package/components/hy-datetime-picker/typing.d.ts +2 -0
  24. package/components/hy-divider/props.ts +83 -83
  25. package/components/hy-empty/icon.ts +72 -72
  26. package/components/hy-folding-panel/hy-folding-panel-group.vue +162 -162
  27. package/components/hy-form/hy-form.vue +220 -220
  28. package/components/hy-icon/hy-icon.vue +112 -112
  29. package/components/hy-index-bar/hy-index-bar.vue +185 -185
  30. package/components/hy-index-bar/index.scss +64 -64
  31. package/components/hy-index-bar/props.ts +94 -94
  32. package/components/hy-index-bar/typing.d.ts +36 -36
  33. package/components/hy-input/hy-input.vue +333 -333
  34. package/components/hy-input/props.ts +186 -186
  35. package/components/hy-modal/hy-modal.vue +211 -211
  36. package/components/hy-modal/props.ts +94 -94
  37. package/components/hy-modal/typing.d.ts +16 -16
  38. package/components/hy-notice-bar/hy-row-notice.vue +121 -121
  39. package/components/hy-notify/hy-notify.vue +174 -174
  40. package/components/hy-number-step/hy-number-step.vue +367 -367
  41. package/components/hy-overlay/hy-overlay.vue +61 -61
  42. package/components/hy-overlay/props.ts +38 -38
  43. package/components/hy-pagination/hy-pagination.vue +136 -136
  44. package/components/hy-pagination/props.ts +58 -58
  45. package/components/hy-parse/hy-parse.vue +550 -550
  46. package/components/hy-parse/node/node.vue +781 -781
  47. package/components/hy-parse/parser.js +1455 -1455
  48. package/components/hy-parse/props.ts +19 -19
  49. package/components/hy-parse/typing.d.ts +68 -68
  50. package/components/hy-picker/hy-picker.vue +435 -435
  51. package/components/hy-picker/props.ts +122 -122
  52. package/components/hy-picker/typing.d.ts +38 -38
  53. package/components/hy-qrcode/props.ts +72 -72
  54. package/components/hy-qrcode/qrcode.js.bak +1433 -1433
  55. package/components/hy-radio/props.ts +97 -97
  56. package/components/hy-read-more/props.ts +48 -48
  57. package/components/hy-search/props.ts +133 -133
  58. package/components/hy-signature/canvasHelper.ts +51 -51
  59. package/components/hy-signature/props.ts +121 -121
  60. package/components/hy-skeleton/hy-skeleton.vue +142 -142
  61. package/components/hy-skeleton/props.ts +46 -46
  62. package/components/hy-skeleton/typing.d.ts +31 -31
  63. package/components/hy-steps/hy-steps.vue +275 -275
  64. package/components/hy-steps/typing.d.ts +25 -25
  65. package/components/hy-swiper/hy-swiper.vue +3 -3
  66. package/components/hy-swiper/index.scss +5 -5
  67. package/components/hy-swiper/props.ts +0 -1
  68. package/components/hy-table/hy-table.vue +630 -630
  69. package/components/hy-table/props.ts +62 -62
  70. package/components/hy-table/typing.d.ts +29 -29
  71. package/components/hy-tabs/hy-tabs.vue +336 -335
  72. package/components/hy-tabs/props.ts +84 -77
  73. package/components/hy-tag/hy-tag.vue +173 -173
  74. package/components/hy-tag/props.ts +89 -89
  75. package/components/hy-text/hy-text.vue +237 -237
  76. package/components/hy-text/props.ts +115 -115
  77. package/components/hy-textarea/hy-textarea.vue +198 -198
  78. package/components/hy-toast/hy-toast.vue +200 -200
  79. package/components/hy-toast/props.ts +3 -3
  80. package/components/hy-transition/hy-transition.vue +157 -157
  81. package/components/hy-transition/props.ts +32 -32
  82. package/components/hy-upload/hy-upload.vue +384 -384
  83. package/components/hy-watermark/hy-watermark.vue +1058 -1058
  84. package/components/hy-watermark/props.ts +109 -109
  85. package/global.d.ts +94 -94
  86. package/libs/api/http.ts +119 -119
  87. package/libs/composables/index.ts +8 -8
  88. package/libs/composables/useMessage.ts +149 -149
  89. package/libs/composables/useToast.ts +45 -45
  90. package/libs/composables/useTranslate.ts +10 -10
  91. package/libs/css/_config.scss +5 -5
  92. package/libs/index.ts +8 -8
  93. package/libs/locale/index.ts +32 -32
  94. package/libs/locale/lang/en-US.ts +84 -84
  95. package/libs/locale/lang/zh-CN.ts +87 -87
  96. package/libs/typing/index.ts +2 -2
  97. package/libs/typing/modules/common.d.ts +139 -139
  98. package/libs/typing/modules/form.ts +176 -176
  99. package/libs/typing/modules/http.d.ts +19 -19
  100. package/libs/typing/modules/index.d.ts +12 -12
  101. package/libs/utils/inside.ts +340 -340
  102. package/libs/utils/inspect.ts +140 -140
  103. package/libs/utils/utils.ts +525 -525
  104. package/package.json +81 -81
  105. package/tags.json +1 -1
  106. package/web-types.json +1 -1
@@ -1,435 +1,435 @@
1
- <template>
2
- <view class="hy-picker">
3
- <view v-if="hasInput" class="hy-picker-input cursor-pointer" @click="onShowByClickInput">
4
- <slot v-if="$slots.default"></slot>
5
- <template v-else>
6
- <hy-input
7
- v-model="inputLabelValue"
8
- :disabled="input?.disabled"
9
- :disabledColor="input?.disabledColor"
10
- :shape="input?.shape"
11
- :border="input?.border"
12
- :prefixIcon="input?.prefixIcon"
13
- :suffixIcon="input?.suffixIcon"
14
- :color="input?.color"
15
- :fontSize="input?.fontSize"
16
- :inputAlign="input?.inputAlign"
17
- :placeholder="input?.placeholder || t('placeholder')"
18
- :placeholderStyle="input?.placeholderStyle"
19
- :placeholderClass="input?.placeholderClass"
20
- :customStyle="Object.assign({ 'pointer-events': 'none' }, input?.customStyle)"
21
- ></hy-input>
22
- <view class="input-cover"></view>
23
- </template>
24
- </view>
25
- <hy-popup
26
- :show="show || (hasInput && showByClickInput)"
27
- :mode="popupMode"
28
- :zIndex="zIndex"
29
- @close="closeHandler"
30
- >
31
- <view class="hy-picker">
32
- <!-- 头部内容 -->
33
- <view class="hy-picker__title" v-if="showToolbar">
34
- <view
35
- class="hy-picker__title--left"
36
- :style="{ color: cancelColor }"
37
- @tap="cancel"
38
- >
39
- {{ cancelText }}
40
- </view>
41
- <view class="hy-picker__title--center">
42
- {{ title }}
43
- </view>
44
- <view
45
- class="hy-picker__title--right"
46
- :style="{ color: confirmColor }"
47
- @tap="onConfirm"
48
- >
49
- <slot v-if="$slots['toolbar-right']" name="toolbar-right"></slot>
50
- <text v-else>{{ confirmText }}</text>
51
- </view>
52
- </view>
53
- <!-- 头部内容 -->
54
-
55
- <slot name="toolbar-bottom"></slot>
56
-
57
- <!-- 加载loading -->
58
- <hy-loading
59
- v-if="loading"
60
- mode="circle"
61
- custom-class="hy-picker__loading"
62
- :custom-style="{
63
- height: `${addUnit(visibleItemCount * itemHeight)}`
64
- }"
65
- ></hy-loading>
66
- <!-- 加载loading -->
67
-
68
- <!-- 选择器内容 -->
69
- <picker-view
70
- v-else
71
- class="hy-picker--view"
72
- :indicatorStyle="`height: ${addUnit(itemHeight)}`"
73
- :value="innerIndex"
74
- :immediateChange="immediateChange"
75
- :style="{
76
- height: `${addUnit(visibleItemCount * itemHeight)}`
77
- }"
78
- mask-class="hy-picker--view__mask"
79
- @change="changeHandler"
80
- >
81
- <picker-view-column
82
- v-for="(item, index) in innerColumns"
83
- :key="index"
84
- class="hy-picker--view__column"
85
- >
86
- <view
87
- v-if="Array.isArray(item)"
88
- :class="[
89
- 'hy-picker--view__column__item',
90
- index1 === innerIndex[index] &&
91
- 'hy-picker--view__column__item--selected'
92
- ]"
93
- v-for="(item1, index1) in item"
94
- :key="index1"
95
- :style="{
96
- height: addUnit(itemHeight),
97
- lineHeight: addUnit(itemHeight),
98
- fontWeight: index1 === innerIndex[index] ? 'bold' : 'normal',
99
- display: 'block'
100
- }"
101
- >
102
- {{ getItemText(item1) }}
103
- </view>
104
- </picker-view-column>
105
- </picker-view>
106
- <!-- 选择器内容 -->
107
- </view>
108
- </hy-popup>
109
- </view>
110
- </template>
111
-
112
- <script lang="ts">
113
- export default {
114
- name: 'hy-picker',
115
- options: {
116
- addGlobalClass: true,
117
- virtualHost: true,
118
- styleIsolation: 'shared'
119
- }
120
- }
121
- </script>
122
-
123
- <script setup lang="ts">
124
- import { computed, ref, watch } from 'vue'
125
- import { deepClone, sleep, addUnit, isArray, useTranslate } from '../../libs'
126
- import type { IPickerEmits } from './typing'
127
- import pickerProps from './props'
128
- // 组件
129
- import HyInput from '../hy-input/hy-input.vue'
130
- import HyLoading from '../hy-loading/hy-loading.vue'
131
- import HyPopup from '../hy-popup/hy-popup.vue'
132
-
133
- /**
134
- * 此选择器用于单列,多列,多列联动的选择场景。
135
- * @displayName hy-picker
136
- */
137
- defineOptions({})
138
-
139
- const props = defineProps(pickerProps)
140
- const emit = defineEmits<IPickerEmits>()
141
-
142
- const { t } = useTranslate('picker')
143
- // 上一次选择的列索引
144
- const lastIndex = ref<number[]>([])
145
- // 索引值 ,对应picker-view的value
146
- const innerIndex = ref<number[]>([])
147
- // 各列的值
148
- const innerColumns = ref<any[][]>([])
149
- // 上一次的变化列索引
150
- const columnIndex = ref<number>(0)
151
- const showByClickInput = ref<boolean>(false)
152
- // 当前用户选中,但是还没确认的值,用户没做change操作时候,点击确认可以默认选中第一个
153
- const currentActiveValue = ref<number[]>([])
154
-
155
- /**
156
- * 设置整体各列的columns的值
157
- * */
158
- const setColumns = (columns: any[]) => {
159
- innerColumns.value = columns
160
- // 如果在设置各列数据时,没有被设置默认的各列索引defaultIndex,那么用0去填充它,数组长度为列的数量
161
- if (innerIndex.value.length === 0) {
162
- innerIndex.value = new Array(columns.length).fill(0)
163
- }
164
- }
165
-
166
- /**
167
- * 监听默认索引的变化,重新设置对应的值
168
- * */
169
- watch(
170
- () => props.defaultIndex,
171
- (newValue) => {
172
- setIndexs(newValue)
173
- },
174
- { immediate: true }
175
- )
176
-
177
- /**
178
- * 监听默认值,给索引赋值
179
- * */
180
- watch(
181
- () => props.modelValue,
182
- (v) =>
183
- setIndexs(
184
- (isArray(v)
185
- ? v
186
- : String(v).includes(props.separator)
187
- ? String(v).split(props.separator)
188
- : [v]
189
- )
190
- .map((item, i) =>
191
- props.columns[i]?.findIndex(
192
- (val) => (typeof val === 'object' ? val[props.valueKey] : val) === item
193
- )
194
- )
195
- .map((n) => (n < 0 ? 0 : n))
196
- ),
197
- { immediate: true }
198
- )
199
-
200
- /**
201
- * 监听columns参数的变化
202
- * */
203
- watch(
204
- () => props.columns,
205
- (newValue) => {
206
- setColumns(newValue)
207
- },
208
- { deep: true, immediate: true }
209
- )
210
-
211
- /**
212
- * 已选&&已确认的值显示在input上面的文案
213
- * */
214
- const inputLabelValue = computed((): string => {
215
- let firstItem = innerColumns.value[0][0]
216
- // //区分是不是对象数组
217
- if (firstItem && Object.prototype.toString.call(firstItem) === '[object Object]') {
218
- let res: Record<string, any>[] = []
219
- innerColumns.value.map((ite, i) => {
220
- res.push(
221
- ...innerColumns.value[i]?.filter((item) => {
222
- return isArray(props.modelValue)
223
- ? props.modelValue.includes(item[props.valueKey])
224
- : props.modelValue === item[props.valueKey]
225
- })
226
- )
227
- })
228
- res = res.map((item) => item[props.labelKey])
229
- return res.join(props.separator)
230
- } else {
231
- //用户确定的值,才显示到输入框
232
- if (props.modelValue.length && isArray(props.modelValue)) {
233
- return props.modelValue.join(props.separator)
234
- }
235
- return props.modelValue as string
236
- }
237
- })
238
-
239
- /**
240
- * 已选,待确认的值
241
- * */
242
- const inputValue = computed(() => {
243
- let items = innerColumns.value.map((item, index) => item[innerIndex.value[index]])
244
- let res: any[] = []
245
- //区分是不是对象数组
246
- if (items[0] && Object.prototype.toString.call(items[0]) === '[object Object]') {
247
- //对象数组返回id集合
248
- items.forEach((element) => {
249
- res.push(element && element[props.valueKey])
250
- })
251
- } else {
252
- //非对象数组返回元素集合
253
- items.forEach((element) => {
254
- res.push(element)
255
- })
256
- }
257
- return res
258
- })
259
-
260
- /**
261
- * 显示
262
- * */
263
- const onShowByClickInput = () => {
264
- if (!props.input?.disabled) {
265
- showByClickInput.value = !showByClickInput.value
266
- }
267
- }
268
-
269
- /**
270
- * 获取item需要显示的文字,判别为对象还是文本
271
- * */
272
- const getItemText = (item: any) => {
273
- if (Object.prototype.toString.call(item) === '[object Object]' && props.labelKey) {
274
- return item[props.labelKey]
275
- } else {
276
- return item
277
- }
278
- }
279
-
280
- /**
281
- * 关闭选择器
282
- * */
283
- const closeHandler = () => {
284
- if (props.closeOnClickOverlay) {
285
- if (props.hasInput) {
286
- showByClickInput.value = false
287
- }
288
- emit('update:show', false)
289
- emit('close')
290
- }
291
- }
292
-
293
- /**
294
- * 点击工具栏的取消按钮
295
- * */
296
- const cancel = () => {
297
- if (props.hasInput) {
298
- showByClickInput.value = false
299
- }
300
- emit('update:show', false)
301
- emit('cancel')
302
- }
303
-
304
- /**
305
- * 点击工具栏的确定按钮
306
- * */
307
- const onConfirm = () => {
308
- //如果用户还没有触发过change
309
- if (!currentActiveValue.value.length) {
310
- let arr = [0]
311
- //如果有默认值&&默认值的数组长度是正确的,就用默认值
312
- if (
313
- Array.isArray(props.defaultIndex) &&
314
- props.defaultIndex.length === innerColumns.value.length
315
- ) {
316
- arr = [...props.defaultIndex]
317
- } else {
318
- //否则默认都选中第一个
319
- arr = Array(innerColumns.value.length).fill(0)
320
- }
321
- setIndexs(arr, true)
322
- }
323
- emit('update:modelValue', inputValue.value)
324
- if (props.hasInput) {
325
- showByClickInput.value = false
326
- }
327
- emit('update:show', false)
328
- emit('confirm', {
329
- indexs: innerIndex.value,
330
- value: innerColumns.value.map((item, index) => item[innerIndex.value[index]]),
331
- values: innerColumns.value
332
- })
333
- }
334
-
335
- /**
336
- * 选择器某一列的数据发生变化时触发
337
- * */
338
- const changeHandler = (e: any) => {
339
- const { value } = e.detail
340
- // 优化:使用更高效的方式找出变化的列
341
- let changedColumnIndex = -1
342
- let changedItemIndex = 0
343
-
344
- // 优化循环:使用for...of循环更简洁,并且在找到变化后立即退出
345
- for (let [i, newValue] of value.entries()) {
346
- const oldValue = lastIndex.value[i] || 0
347
- if (newValue !== oldValue) {
348
- changedColumnIndex = i
349
- changedItemIndex = newValue
350
- currentActiveValue.value = value
351
- break
352
- }
353
- }
354
-
355
- // 如果有变化的列,才执行后续操作
356
- if (changedColumnIndex !== -1) {
357
- columnIndex.value = changedColumnIndex
358
-
359
- // 移除无条件重置索引的代码,仅在数据实际变化时重置
360
-
361
- // 优化:创建params对象时使用更简洁的方式
362
- const params = {
363
- value: innerColumns.value.map((item, idx) => item[value[idx]]),
364
- index: changedItemIndex,
365
- indexs: value,
366
- values: innerColumns.value,
367
- columnIndex: changedColumnIndex
368
- }
369
-
370
- // 将当前的各项变化索引,设置为"上一次"的索引变化值
371
- setIndexs(value, true)
372
-
373
- //如果是非自带输入框才会在change时候触发v-model绑值的变化
374
- if (!props.hasInput) {
375
- emit('update:modelValue', inputValue.value)
376
- }
377
- emit('change', params)
378
- }
379
- }
380
-
381
- /**
382
- * 设置index索引,此方法可被外部调用设置
383
- * */
384
- function setIndexs(index: number[], isSetLastIndex?: boolean) {
385
- innerIndex.value = index
386
- // 移除调试日志
387
- if (isSetLastIndex) {
388
- setLastIndex(index)
389
- }
390
- }
391
-
392
- /**
393
- * 记录上一次的各列索引位置
394
- * */
395
- const setLastIndex = (index: number[]) => {
396
- // 当能进入此方法,意味着当前设置的各列默认索引,即为“上一次”的选中值,需要记录,是因为changeHandler中
397
- // 需要拿前后的变化值进行对比,得出当前发生改变的是哪一列
398
- lastIndex.value = index
399
- }
400
-
401
- /**
402
- * 设置对应列选项的所有值
403
- * */
404
- const setColumnValues = (columnI: number, values: AnyObject[]) => {
405
- innerColumns.value.splice(columnI, 1, values)
406
- let tmpIndex = deepClone(innerIndex.value)
407
- for (let i = 0; i < innerColumns.value.length; i++) {
408
- if (i > columnIndex.value) {
409
- tmpIndex[i] = 0
410
- }
411
- }
412
- // 一次性赋值,不能单个修改,否则无效
413
- setIndexs(tmpIndex, true)
414
- }
415
-
416
- /**
417
- * 获取对应列的所有选项
418
- * */
419
- const getColumnValues = (columnI: number) => {
420
- // 进行同步阻塞,因为外部得到change事件之后,可能需要执行setColumnValues更新列的值
421
- // 索引如果在外部change的回调中调用getColumnValues的话,可能无法得到变更后的列值,这里进行一定延时,保证值的准确性
422
- ;(async () => {
423
- await sleep()
424
- })()
425
- return innerColumns.value[columnI]
426
- }
427
-
428
- defineExpose({
429
- setColumnValues
430
- })
431
- </script>
432
-
433
- <style lang="scss" scoped>
434
- @import './index.scss';
435
- </style>
1
+ <template>
2
+ <view class="hy-picker">
3
+ <view v-if="hasInput" class="hy-picker-input cursor-pointer" @click="onShowByClickInput">
4
+ <slot v-if="$slots.default"></slot>
5
+ <template v-else>
6
+ <hy-input
7
+ v-model="inputLabelValue"
8
+ :disabled="input?.disabled"
9
+ :disabledColor="input?.disabledColor"
10
+ :shape="input?.shape"
11
+ :border="input?.border"
12
+ :prefixIcon="input?.prefixIcon"
13
+ :suffixIcon="input?.suffixIcon"
14
+ :color="input?.color"
15
+ :fontSize="input?.fontSize"
16
+ :inputAlign="input?.inputAlign"
17
+ :placeholder="input?.placeholder || t('placeholder')"
18
+ :placeholderStyle="input?.placeholderStyle"
19
+ :placeholderClass="input?.placeholderClass"
20
+ :customStyle="Object.assign({ 'pointer-events': 'none' }, input?.customStyle)"
21
+ ></hy-input>
22
+ <view class="input-cover"></view>
23
+ </template>
24
+ </view>
25
+ <hy-popup
26
+ :show="show || (hasInput && showByClickInput)"
27
+ :mode="popupMode"
28
+ :zIndex="zIndex"
29
+ @close="closeHandler"
30
+ >
31
+ <view class="hy-picker">
32
+ <!-- 头部内容 -->
33
+ <view class="hy-picker__title" v-if="showToolbar">
34
+ <view
35
+ class="hy-picker__title--left"
36
+ :style="{ color: cancelColor }"
37
+ @tap="cancel"
38
+ >
39
+ {{ cancelText }}
40
+ </view>
41
+ <view class="hy-picker__title--center">
42
+ {{ title }}
43
+ </view>
44
+ <view
45
+ class="hy-picker__title--right"
46
+ :style="{ color: confirmColor }"
47
+ @tap="onConfirm"
48
+ >
49
+ <slot v-if="$slots['toolbar-right']" name="toolbar-right"></slot>
50
+ <text v-else>{{ confirmText }}</text>
51
+ </view>
52
+ </view>
53
+ <!-- 头部内容 -->
54
+
55
+ <slot name="toolbar-bottom"></slot>
56
+
57
+ <!-- 加载loading -->
58
+ <hy-loading
59
+ v-if="loading"
60
+ mode="circle"
61
+ custom-class="hy-picker__loading"
62
+ :custom-style="{
63
+ height: `${addUnit(visibleItemCount * itemHeight)}`
64
+ }"
65
+ ></hy-loading>
66
+ <!-- 加载loading -->
67
+
68
+ <!-- 选择器内容 -->
69
+ <picker-view
70
+ v-else
71
+ class="hy-picker--view"
72
+ :indicatorStyle="`height: ${addUnit(itemHeight)}`"
73
+ :value="innerIndex"
74
+ :immediateChange="immediateChange"
75
+ :style="{
76
+ height: `${addUnit(visibleItemCount * itemHeight)}`
77
+ }"
78
+ mask-class="hy-picker--view__mask"
79
+ @change="changeHandler"
80
+ >
81
+ <picker-view-column
82
+ v-for="(item, index) in innerColumns"
83
+ :key="index"
84
+ class="hy-picker--view__column"
85
+ >
86
+ <view
87
+ v-if="Array.isArray(item)"
88
+ :class="[
89
+ 'hy-picker--view__column__item',
90
+ index1 === innerIndex[index] &&
91
+ 'hy-picker--view__column__item--selected'
92
+ ]"
93
+ v-for="(item1, index1) in item"
94
+ :key="index1"
95
+ :style="{
96
+ height: addUnit(itemHeight),
97
+ lineHeight: addUnit(itemHeight),
98
+ fontWeight: index1 === innerIndex[index] ? 'bold' : 'normal',
99
+ display: 'block'
100
+ }"
101
+ >
102
+ {{ getItemText(item1) }}
103
+ </view>
104
+ </picker-view-column>
105
+ </picker-view>
106
+ <!-- 选择器内容 -->
107
+ </view>
108
+ </hy-popup>
109
+ </view>
110
+ </template>
111
+
112
+ <script lang="ts">
113
+ export default {
114
+ name: 'hy-picker',
115
+ options: {
116
+ addGlobalClass: true,
117
+ virtualHost: true,
118
+ styleIsolation: 'shared'
119
+ }
120
+ }
121
+ </script>
122
+
123
+ <script setup lang="ts">
124
+ import { computed, ref, watch } from 'vue'
125
+ import { deepClone, sleep, addUnit, isArray, useTranslate } from '../../libs'
126
+ import type { IPickerEmits } from './typing'
127
+ import pickerProps from './props'
128
+ // 组件
129
+ import HyInput from '../hy-input/hy-input.vue'
130
+ import HyLoading from '../hy-loading/hy-loading.vue'
131
+ import HyPopup from '../hy-popup/hy-popup.vue'
132
+
133
+ /**
134
+ * 此选择器用于单列,多列,多列联动的选择场景。
135
+ * @displayName hy-picker
136
+ */
137
+ defineOptions({})
138
+
139
+ const props = defineProps(pickerProps)
140
+ const emit = defineEmits<IPickerEmits>()
141
+
142
+ const { t } = useTranslate('picker')
143
+ // 上一次选择的列索引
144
+ const lastIndex = ref<number[]>([])
145
+ // 索引值 ,对应picker-view的value
146
+ const innerIndex = ref<number[]>([])
147
+ // 各列的值
148
+ const innerColumns = ref<any[][]>([])
149
+ // 上一次的变化列索引
150
+ const columnIndex = ref<number>(0)
151
+ const showByClickInput = ref<boolean>(false)
152
+ // 当前用户选中,但是还没确认的值,用户没做change操作时候,点击确认可以默认选中第一个
153
+ const currentActiveValue = ref<number[]>([])
154
+
155
+ /**
156
+ * 设置整体各列的columns的值
157
+ * */
158
+ const setColumns = (columns: any[]) => {
159
+ innerColumns.value = columns
160
+ // 如果在设置各列数据时,没有被设置默认的各列索引defaultIndex,那么用0去填充它,数组长度为列的数量
161
+ if (innerIndex.value.length === 0) {
162
+ innerIndex.value = new Array(columns.length).fill(0)
163
+ }
164
+ }
165
+
166
+ /**
167
+ * 监听默认索引的变化,重新设置对应的值
168
+ * */
169
+ watch(
170
+ () => props.defaultIndex,
171
+ (newValue) => {
172
+ setIndexs(newValue)
173
+ },
174
+ { immediate: true }
175
+ )
176
+
177
+ /**
178
+ * 监听默认值,给索引赋值
179
+ * */
180
+ watch(
181
+ () => props.modelValue,
182
+ (v) =>
183
+ setIndexs(
184
+ (isArray(v)
185
+ ? v
186
+ : String(v).includes(props.separator)
187
+ ? String(v).split(props.separator)
188
+ : [v]
189
+ )
190
+ .map((item, i) =>
191
+ props.columns[i]?.findIndex(
192
+ (val) => (typeof val === 'object' ? val[props.valueKey] : val) === item
193
+ )
194
+ )
195
+ .map((n) => (n < 0 ? 0 : n))
196
+ ),
197
+ { immediate: true }
198
+ )
199
+
200
+ /**
201
+ * 监听columns参数的变化
202
+ * */
203
+ watch(
204
+ () => props.columns,
205
+ (newValue) => {
206
+ setColumns(newValue)
207
+ },
208
+ { deep: true, immediate: true }
209
+ )
210
+
211
+ /**
212
+ * 已选&&已确认的值显示在input上面的文案
213
+ * */
214
+ const inputLabelValue = computed((): string => {
215
+ let firstItem = innerColumns.value[0][0]
216
+ // //区分是不是对象数组
217
+ if (firstItem && Object.prototype.toString.call(firstItem) === '[object Object]') {
218
+ let res: Record<string, any>[] = []
219
+ innerColumns.value.map((ite, i) => {
220
+ res.push(
221
+ ...innerColumns.value[i]?.filter((item) => {
222
+ return isArray(props.modelValue)
223
+ ? props.modelValue.includes(item[props.valueKey])
224
+ : props.modelValue === item[props.valueKey]
225
+ })
226
+ )
227
+ })
228
+ res = res.map((item) => item[props.labelKey])
229
+ return res.join(props.separator)
230
+ } else {
231
+ //用户确定的值,才显示到输入框
232
+ if (props.modelValue.length && isArray(props.modelValue)) {
233
+ return props.modelValue.join(props.separator)
234
+ }
235
+ return props.modelValue as string
236
+ }
237
+ })
238
+
239
+ /**
240
+ * 已选,待确认的值
241
+ * */
242
+ const inputValue = computed(() => {
243
+ let items = innerColumns.value.map((item, index) => item[innerIndex.value[index]])
244
+ let res: any[] = []
245
+ //区分是不是对象数组
246
+ if (items[0] && Object.prototype.toString.call(items[0]) === '[object Object]') {
247
+ //对象数组返回id集合
248
+ items.forEach((element) => {
249
+ res.push(element && element[props.valueKey])
250
+ })
251
+ } else {
252
+ //非对象数组返回元素集合
253
+ items.forEach((element) => {
254
+ res.push(element)
255
+ })
256
+ }
257
+ return res
258
+ })
259
+
260
+ /**
261
+ * 显示
262
+ * */
263
+ const onShowByClickInput = () => {
264
+ if (!props.input?.disabled) {
265
+ showByClickInput.value = !showByClickInput.value
266
+ }
267
+ }
268
+
269
+ /**
270
+ * 获取item需要显示的文字,判别为对象还是文本
271
+ * */
272
+ const getItemText = (item: any) => {
273
+ if (Object.prototype.toString.call(item) === '[object Object]' && props.labelKey) {
274
+ return item[props.labelKey]
275
+ } else {
276
+ return item
277
+ }
278
+ }
279
+
280
+ /**
281
+ * 关闭选择器
282
+ * */
283
+ const closeHandler = () => {
284
+ if (props.closeOnClickOverlay) {
285
+ if (props.hasInput) {
286
+ showByClickInput.value = false
287
+ }
288
+ emit('update:show', false)
289
+ emit('close')
290
+ }
291
+ }
292
+
293
+ /**
294
+ * 点击工具栏的取消按钮
295
+ * */
296
+ const cancel = () => {
297
+ if (props.hasInput) {
298
+ showByClickInput.value = false
299
+ }
300
+ emit('update:show', false)
301
+ emit('cancel')
302
+ }
303
+
304
+ /**
305
+ * 点击工具栏的确定按钮
306
+ * */
307
+ const onConfirm = () => {
308
+ //如果用户还没有触发过change
309
+ if (!currentActiveValue.value.length) {
310
+ let arr = [0]
311
+ //如果有默认值&&默认值的数组长度是正确的,就用默认值
312
+ if (
313
+ Array.isArray(props.defaultIndex) &&
314
+ props.defaultIndex.length === innerColumns.value.length
315
+ ) {
316
+ arr = [...props.defaultIndex]
317
+ } else {
318
+ //否则默认都选中第一个
319
+ arr = Array(innerColumns.value.length).fill(0)
320
+ }
321
+ setIndexs(arr, true)
322
+ }
323
+ emit('update:modelValue', inputValue.value)
324
+ if (props.hasInput) {
325
+ showByClickInput.value = false
326
+ }
327
+ emit('update:show', false)
328
+ emit('confirm', {
329
+ indexs: innerIndex.value,
330
+ value: innerColumns.value.map((item, index) => item[innerIndex.value[index]]),
331
+ values: innerColumns.value
332
+ })
333
+ }
334
+
335
+ /**
336
+ * 选择器某一列的数据发生变化时触发
337
+ * */
338
+ const changeHandler = (e: any) => {
339
+ const { value } = e.detail
340
+ // 优化:使用更高效的方式找出变化的列
341
+ let changedColumnIndex = -1
342
+ let changedItemIndex = 0
343
+
344
+ // 优化循环:使用for...of循环更简洁,并且在找到变化后立即退出
345
+ for (let [i, newValue] of value.entries()) {
346
+ const oldValue = lastIndex.value[i] || 0
347
+ if (newValue !== oldValue) {
348
+ changedColumnIndex = i
349
+ changedItemIndex = newValue
350
+ currentActiveValue.value = value
351
+ break
352
+ }
353
+ }
354
+
355
+ // 如果有变化的列,才执行后续操作
356
+ if (changedColumnIndex !== -1) {
357
+ columnIndex.value = changedColumnIndex
358
+
359
+ // 移除无条件重置索引的代码,仅在数据实际变化时重置
360
+
361
+ // 优化:创建params对象时使用更简洁的方式
362
+ const params = {
363
+ value: innerColumns.value.map((item, idx) => item[value[idx]]),
364
+ index: changedItemIndex,
365
+ indexs: value,
366
+ values: innerColumns.value,
367
+ columnIndex: changedColumnIndex
368
+ }
369
+
370
+ // 将当前的各项变化索引,设置为"上一次"的索引变化值
371
+ setIndexs(value, true)
372
+
373
+ //如果是非自带输入框才会在change时候触发v-model绑值的变化
374
+ if (!props.hasInput) {
375
+ emit('update:modelValue', inputValue.value)
376
+ }
377
+ emit('change', params)
378
+ }
379
+ }
380
+
381
+ /**
382
+ * 设置index索引,此方法可被外部调用设置
383
+ * */
384
+ function setIndexs(index: number[], isSetLastIndex?: boolean) {
385
+ innerIndex.value = index
386
+ // 移除调试日志
387
+ if (isSetLastIndex) {
388
+ setLastIndex(index)
389
+ }
390
+ }
391
+
392
+ /**
393
+ * 记录上一次的各列索引位置
394
+ * */
395
+ const setLastIndex = (index: number[]) => {
396
+ // 当能进入此方法,意味着当前设置的各列默认索引,即为“上一次”的选中值,需要记录,是因为changeHandler中
397
+ // 需要拿前后的变化值进行对比,得出当前发生改变的是哪一列
398
+ lastIndex.value = index
399
+ }
400
+
401
+ /**
402
+ * 设置对应列选项的所有值
403
+ * */
404
+ const setColumnValues = (columnI: number, values: AnyObject[]) => {
405
+ innerColumns.value.splice(columnI, 1, values)
406
+ let tmpIndex = deepClone(innerIndex.value)
407
+ for (let i = 0; i < innerColumns.value.length; i++) {
408
+ if (i > columnIndex.value) {
409
+ tmpIndex[i] = 0
410
+ }
411
+ }
412
+ // 一次性赋值,不能单个修改,否则无效
413
+ setIndexs(tmpIndex, true)
414
+ }
415
+
416
+ /**
417
+ * 获取对应列的所有选项
418
+ * */
419
+ const getColumnValues = (columnI: number) => {
420
+ // 进行同步阻塞,因为外部得到change事件之后,可能需要执行setColumnValues更新列的值
421
+ // 索引如果在外部change的回调中调用getColumnValues的话,可能无法得到变更后的列值,这里进行一定延时,保证值的准确性
422
+ ;(async () => {
423
+ await sleep()
424
+ })()
425
+ return innerColumns.value[columnI]
426
+ }
427
+
428
+ defineExpose({
429
+ setColumnValues
430
+ })
431
+ </script>
432
+
433
+ <style lang="scss" scoped>
434
+ @import './index.scss';
435
+ </style>