@tplc/wot 1.0.16 → 1.0.18

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
@@ -2,6 +2,26 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [1.0.18](https://gitlab888.30jia.com.cn/tourism-front/zero-code-pro/compare/v1.0.17...v1.0.18) (2025-12-29)
6
+
7
+
8
+ ### 🚀 Chore | 构建/工程依赖/工具
9
+
10
+ * **release:** 0.7.33 ([1d6cbfd](https://gitlab888.30jia.com.cn/tourism-front/zero-code-pro/commit/1d6cbfd08c7bfca80e6116ac40d46b909b49b888))
11
+
12
+
13
+ ### ✨ Features | 新功能
14
+
15
+ * Add `payCardId` to payment form and component, and refine payment type watch logic with minor UI alignment. ([0cac8e4](https://gitlab888.30jia.com.cn/tourism-front/zero-code-pro/commit/0cac8e49e678a81f3a1340b251c05aa591e28146))
16
+ * add button type to SelectPicker and implement remote search functionality ([2e09dea](https://gitlab888.30jia.com.cn/tourism-front/zero-code-pro/commit/2e09dea2be7087b925d732b0211641d2e1039424))
17
+
18
+ ### [1.0.17](https://gitlab888.30jia.com.cn/tourism-front/zero-code-pro/compare/v0.7.32...v1.0.17) (2025-12-28)
19
+
20
+
21
+ ### ♻️ Code Refactoring | 代码重构
22
+
23
+ * remove unused type definitions and components from business package ([2bd79a4](https://gitlab888.30jia.com.cn/tourism-front/zero-code-pro/commit/2bd79a4c6c546a1c079ca4e291c73bd9d49a8f23))
24
+
5
25
  ### [1.0.16](https://gitlab888.30jia.com.cn/tourism-front/zero-code-pro/compare/v0.7.22...v1.0.16) (2025-12-17)
6
26
 
7
27
 
@@ -18,7 +18,7 @@
18
18
  }
19
19
 
20
20
  @include b(select-picker) {
21
- @include edeep(cell) {
21
+ @include edeep(cell) {
22
22
  @include when(disabled) {
23
23
  .wd-cell__value {
24
24
  color: $-input-disabled-color;
@@ -47,7 +47,7 @@
47
47
  }
48
48
  }
49
49
  }
50
-
50
+
51
51
  @include edeep(arrow, clear) {
52
52
  display: block;
53
53
  font-size: $-cell-icon-size;
@@ -58,7 +58,7 @@
58
58
  @include edeep(clear) {
59
59
  color: $-cell-clear-color;
60
60
  }
61
-
61
+
62
62
  @include e(loading) {
63
63
  position: absolute;
64
64
  display: flex;
@@ -71,7 +71,7 @@
71
71
  z-index: 3;
72
72
  background: $-picker-loading-bg;
73
73
  }
74
-
74
+
75
75
  @include edeep(header) {
76
76
  height: 72px;
77
77
  line-height: 72px;
@@ -99,41 +99,4 @@
99
99
  @include e(footer) {
100
100
  padding: 24px 15px;
101
101
  }
102
-
103
- // ========== 你的自定义样式 ==========
104
-
105
- // 没有更多数据样式
106
- @include e(no-more) {
107
- text-align: center;
108
- color: $-cell-arrow-color;
109
- padding: 24rpx 0;
110
- font-size: 28rpx;
111
- }
112
-
113
- // 内部加载样式
114
- @include e(innerLoading) {
115
- display: flex;
116
- align-items: center;
117
- justify-content: center;
118
- background: $-picker-loading-bg;
119
- padding: 24rpx 0;
120
- }
121
-
122
- // 按钮样式
123
- @include e(button) {
124
- width: 100%;
125
- height: 72rpx;
126
- line-height: 72rpx;
127
- border-radius: 8rpx;
128
- font-size: 28rpx;
129
- color: #333;
130
- box-sizing: border-box;
131
- text-align: center;
132
- border: 1px solid #eee;
133
- &--active {
134
- color: $-color-theme;
135
- border: 1px solid $-color-theme;
136
- }
137
- }
138
102
  }
139
-
@@ -1,8 +1,23 @@
1
1
  import type { ComponentPublicInstance, ExtractPropTypes, PropType } from 'vue'
2
- import { baseProps, makeArrayProp, makeBooleanProp, makeNumberProp, makeRequiredProp, makeStringProp } from '../common/props'
2
+ import {
3
+ baseProps,
4
+ makeArrayProp,
5
+ makeBooleanProp,
6
+ makeNumberProp,
7
+ makeRequiredProp,
8
+ makeStringProp,
9
+ } from '../common/props'
3
10
  import type { FormItemRule } from '../wd-form/types'
4
11
 
5
- export type SelectPickerType = 'checkbox' | 'radio'
12
+ export type SelectPickerType = 'checkbox' | 'radio' | 'button'
13
+ export type SelectPickerRemote = {
14
+ action: (
15
+ search: string,
16
+ params: { pageSearch: { page: number; limit: number } },
17
+ ) => Promise<Record<string, any>[]>
18
+ pageSize?: number
19
+ isPage?: boolean
20
+ }
6
21
 
7
22
  export const selectPickerProps = {
8
23
  ...baseProps,
@@ -24,22 +39,12 @@ export const selectPickerProps = {
24
39
  error: makeBooleanProp(false),
25
40
  /** 必填样式 */
26
41
  required: makeBooleanProp(false),
27
- /**
28
- * 使用 label 插槽时设置该选项
29
- * @deprecated 可以直接使用标签插槽,无需配置此选项
30
- */
42
+ /** 使用 label 插槽时设置该选项 */
31
43
  useLabelSlot: makeBooleanProp(false),
32
- /**
33
- * 使用默认插槽时设置该选项
34
- * @deprecated 可以直接使用默认插槽,无需配置此选项
35
- */
44
+ /** 使用默认插槽时设置该选项 */
36
45
  useDefaultSlot: makeBooleanProp(false),
37
46
  /** 设置选择器大小 */
38
47
  size: String,
39
- /**
40
- * 是否垂直居中
41
- */
42
- center: makeBooleanProp(false),
43
48
  /** 选中的颜色(单/复选框) */
44
49
  checkedColor: String,
45
50
  /** 最小选中的数量(仅在复选框类型下生效,`type`类型为`checkbox`) */
@@ -55,7 +60,9 @@ export const selectPickerProps = {
55
60
  /** 点击遮罩是否关闭 */
56
61
  closeOnClickModal: makeBooleanProp(true),
57
62
  /** 选中项,`type`类型为`checkbox`时,类型为 array;`type`为`radio` 时 ,类型为 number / boolean / string */
58
- modelValue: makeRequiredProp([String, Number, Boolean, Array] as PropType<string | number | boolean | (string | number | boolean)[]>),
63
+ modelValue: makeRequiredProp([String, Number, Boolean, Array] as PropType<
64
+ string | number | boolean | (string | number | boolean)[]
65
+ >),
59
66
  /** 选择器数据,一维数组 */
60
67
  columns: makeArrayProp<Record<string, any>>(),
61
68
  /** 单复选选择器类型 */
@@ -76,6 +83,10 @@ export const selectPickerProps = {
76
83
  safeAreaInsetBottom: makeBooleanProp(true),
77
84
  /** 可搜索(目前只支持本地搜索) */
78
85
  filterable: makeBooleanProp(false),
86
+ /** 远程搜索配置 */
87
+ remoteConfig: {
88
+ type: Object as PropType<SelectPickerRemote>,
89
+ },
79
90
  /** 搜索框占位符 */
80
91
  filterPlaceholder: String,
81
92
  /** 是否超出隐藏 */
@@ -94,24 +105,20 @@ export const selectPickerProps = {
94
105
  customValueClass: makeStringProp(''),
95
106
  /** 是否显示确认按钮(radio类型生效),默认值为:true */
96
107
  showConfirm: makeBooleanProp(true),
97
- /**
98
- * 显示清空按钮
99
- */
100
- clearable: makeBooleanProp(false),
101
- /**
102
- * 是否从页面中脱离出来,用于解决各种 fixed 失效问题 (H5: teleport, APP: renderjs, 小程序: root-portal)
103
- */
104
- rootPortal: makeBooleanProp(false),
105
- /**
106
- * 必填标记位置,可选值:before、after
107
- */
108
- markerSide: makeStringProp<'before' | 'after'>('before')
108
+ /** 默认展示文案 */
109
+ defaultLabel: String,
109
110
  }
110
111
  export type SelectPickerProps = ExtractPropTypes<typeof selectPickerProps>
111
112
 
112
- export type SelectPickerDisplayFormat = (items: string | number | boolean | (string | number | boolean)[], columns: Record<string, any>[]) => string
113
+ export type SelectPickerDisplayFormat = (
114
+ items: string | number | boolean | (string | number | boolean)[],
115
+ columns: Record<string, any>[],
116
+ ) => string
113
117
 
114
- export type SelectPickerBeforeConfirm = (value: string | number | boolean | (string | number | boolean)[], resolve: (isPass: boolean) => void) => void
118
+ export type SelectPickerBeforeConfirm = (
119
+ value: string | number | boolean | (string | number | boolean)[],
120
+ resolve: (isPass: boolean) => void,
121
+ ) => void
115
122
 
116
123
  export type SelectPickerExpose = {
117
124
  // 打开picker弹框
@@ -1,38 +1,45 @@
1
1
  <template>
2
- <view :class="`wd-select-picker ${customClass}`" :style="customStyle">
3
- <wd-cell
4
- v-if="!$slots.default"
5
- :title="label"
6
- :value="showValue || placeholder || translate('placeholder')"
7
- :required="required"
8
- :size="size"
9
- :title-width="labelWidth"
10
- :prop="prop"
11
- :rules="rules"
12
- :clickable="!disabled && !readonly"
13
- :value-align="alignRight ? 'right' : 'left'"
14
- :center="center"
15
- :custom-class="cellClass"
16
- :custom-style="customStyle"
17
- :custom-title-class="customLabelClass"
18
- :custom-value-class="customValueClass"
19
- :ellipsis="ellipsis"
20
- :use-title-slot="!!$slots.label"
21
- :marker-side="markerSide"
22
- @click="open"
23
- >
24
- <template v-if="$slots.label" #title>
25
- <slot name="label"></slot>
26
- </template>
27
- <template #right-icon>
28
- <wd-icon v-if="showArrow" custom-class="wd-select-picker__arrow" name="arrow-right" />
29
- <view v-else-if="showClear" @click.stop="handleClear">
30
- <wd-icon custom-class="wd-select-picker__clear" name="error-fill" />
2
+ <view
3
+ :class="`wd-select-picker ${cell.border.value ? 'is-border' : ''} ${customClass}`"
4
+ :style="customStyle"
5
+ >
6
+ <view class="wd-select-picker__field" @click="open">
7
+ <slot v-if="useDefaultSlot"></slot>
8
+ <view
9
+ v-else
10
+ :class="`wd-select-picker__cell ${disabled && 'is-disabled'} ${readonly && 'is-readonly'} ${alignRight && 'is-align-right'} ${
11
+ error && 'is-error'
12
+ } ${size && 'is-' + size}`"
13
+ >
14
+ <view
15
+ v-if="label || useLabelSlot"
16
+ :class="`wd-select-picker__label ${isRequired && 'is-required'} ${customLabelClass}`"
17
+ :style="labelWidth ? 'min-width:' + labelWidth + ';max-width:' + labelWidth + ';' : ''"
18
+ >
19
+ <text v-if="label" class="wd-select-picker__label-inner">{{ label }}</text>
20
+ <slot v-else name="label"></slot>
21
+ </view>
22
+ <view class="wd-select-picker__body">
23
+ <view class="wd-select-picker__value-wraper">
24
+ <view
25
+ :class="`wd-select-picker__value ${ellipsis && 'is-ellipsis'} ${customValueClass} ${
26
+ showValue ? '' : 'wd-select-picker__value--placeholder'
27
+ }`"
28
+ >
29
+ {{ showValue || placeholder || translate('placeholder') }}
30
+ </view>
31
+ <wd-icon
32
+ v-if="!disabled && !readonly"
33
+ custom-class="wd-select-picker__arrow"
34
+ name="arrow-right"
35
+ />
36
+ </view>
37
+
38
+ <view v-if="errorMessage" class="wd-select-picker__error-message">
39
+ {{ errorMessage }}
40
+ </view>
31
41
  </view>
32
- </template>
33
- </wd-cell>
34
- <view v-else @click="open">
35
- <slot></slot>
42
+ </view>
36
43
  </view>
37
44
  <wd-action-sheet
38
45
  v-model="pickerShow"
@@ -41,7 +48,6 @@
41
48
  :close-on-click-modal="closeOnClickModal"
42
49
  :z-index="zIndex"
43
50
  :safe-area-inset-bottom="safeAreaInsetBottom"
44
- :root-portal="rootPortal"
45
51
  @close="close"
46
52
  @opened="scrollIntoView ? setScrollIntoView() : ''"
47
53
  custom-header-class="wd-select-picker__header"
@@ -52,22 +58,39 @@
52
58
  :placeholder="filterPlaceholder || translate('filterPlaceholder')"
53
59
  hide-cancel
54
60
  placeholder-left
61
+ @search="handleFilterSearch"
55
62
  @change="handleFilterChange"
56
63
  />
64
+
57
65
  <scroll-view
58
66
  :class="`wd-select-picker__wrapper ${filterable ? 'is-filterable' : ''} ${loading ? 'is-loading' : ''} ${customContentClass}`"
59
67
  :scroll-y="!loading"
60
68
  :scroll-top="scrollTop"
61
69
  :scroll-with-animation="true"
70
+ @scrolltolower="handleScrollToLower"
62
71
  >
63
72
  <!-- 多选 -->
64
73
  <view v-if="type === 'checkbox' && isArray(selectList)" id="wd-checkbox-group">
65
- <wd-checkbox-group v-model="selectList" cell :size="selectSize" :checked-color="checkedColor" :min="min" :max="max" @change="handleChange">
66
- <view v-for="item in filterColumns" :key="item[valueKey]" :id="'check' + item[valueKey]">
74
+ <wd-checkbox-group
75
+ v-model="selectList"
76
+ cell
77
+ :size="selectSize"
78
+ :checked-color="checkedColor"
79
+ :min="min"
80
+ :max="max"
81
+ @change="handleChange"
82
+ >
83
+ <view
84
+ v-for="item in filterColumns"
85
+ :key="item[valueKey]"
86
+ :id="'check' + item[valueKey]"
87
+ >
67
88
  <wd-checkbox :modelValue="item[valueKey]" :disabled="item.disabled">
68
89
  <block v-if="filterable && filterVal">
69
90
  <block v-for="text in item[labelKey]" :key="text.label">
70
- <text v-if="text.type === 'active'" class="wd-select-picker__text-active">{{ text.label }}</text>
91
+ <text v-if="text.type === 'active'" class="wd-select-picker__text-active">
92
+ {{ text.label }}
93
+ </text>
71
94
  <block v-else>{{ text.label }}</block>
72
95
  </block>
73
96
  </block>
@@ -78,14 +101,59 @@
78
101
  </view>
79
102
  </wd-checkbox-group>
80
103
  </view>
104
+ <!-- 多选/单选 -->
105
+ <view
106
+ v-if="type === 'button' && !isArray(selectList)"
107
+ id="wd-radio-group"
108
+ class="grid gap-3 grid-cols-3 mb-3"
109
+ >
110
+ <view
111
+ v-for="item in filterColumns"
112
+ :key="item[valueKey]"
113
+ :id="'radio' + item[valueKey]"
114
+ @click="
115
+ handleChange({
116
+ value: item[valueKey],
117
+ })
118
+ "
119
+ :disabled="item.disabled"
120
+ :round="false"
121
+ plain
122
+ class="wd-select-picker__button"
123
+ :class="`${selectList === item[valueKey] ? 'wd-select-picker__button--active' : ''} ${item.disabled ? 'wd-select-picker__button--disabled' : ''}`"
124
+ >
125
+ <block v-if="filterable && filterVal">
126
+ <block v-for="text in item[labelKey]" :key="text.label">
127
+ {{ text.label }}
128
+ </block>
129
+ </block>
130
+ <block v-else>
131
+ {{ item[labelKey] }}
132
+ </block>
133
+ </view>
134
+ </view>
81
135
  <!-- 单选 -->
82
136
  <view v-if="type === 'radio' && !isArray(selectList)" id="wd-radio-group">
83
- <wd-radio-group v-model="selectList" cell :size="selectSize" :checked-color="checkedColor" @change="handleChange">
84
- <view v-for="(item, index) in filterColumns" :key="index" :id="'radio' + item[valueKey]">
137
+ <wd-radio-group
138
+ v-model="selectList"
139
+ cell
140
+ :size="selectSize"
141
+ :checked-color="checkedColor"
142
+ @change="handleChange"
143
+ >
144
+ <view
145
+ v-for="(item, index) in filterColumns"
146
+ :key="index"
147
+ :id="'radio' + item[valueKey]"
148
+ >
85
149
  <wd-radio :value="item[valueKey]" :disabled="item.disabled">
86
- <block v-if="filterable && filterVal">
150
+ <block v-if="filterable && filterVal && !remoteConfig">
87
151
  <block v-for="text in item[labelKey]" :key="text.label">
88
- <text :class="`${text.type === 'active' ? 'wd-select-picker__text-active' : ''}`">{{ text.label }}</text>
152
+ <text
153
+ :clsss="`${text.type === 'active' ? 'wd-select-picker__text-active' : ''}`"
154
+ >
155
+ {{ text.label }}
156
+ </text>
89
157
  </block>
90
158
  </block>
91
159
  <block v-else>
@@ -98,10 +166,16 @@
98
166
  <view v-if="loading" class="wd-select-picker__loading" @touchmove="noop">
99
167
  <wd-loading :color="loadingColor" />
100
168
  </view>
169
+ <view v-if="innerLoading" class="wd-select-picker__innerLoading">
170
+ <wd-loading :color="loadingColor" />
171
+ </view>
172
+ <view v-if="noMore" class="wd-select-picker__no-more">没有更多数据了</view>
101
173
  </scroll-view>
102
174
  <!-- 确认按钮 -->
103
175
  <view v-if="showConfirm" class="wd-select-picker__footer">
104
- <wd-button block size="large" @click="onConfirm" :disabled="loading">{{ confirmButtonText || translate('confirm') }}</wd-button>
176
+ <wd-button block size="large" @click="onConfirm" :disabled="loading">
177
+ {{ confirmButtonText || translate('confirm') }}
178
+ </wd-button>
105
179
  </view>
106
180
  </wd-action-sheet>
107
181
  </view>
@@ -112,30 +186,24 @@ export default {
112
186
  options: {
113
187
  addGlobalClass: true,
114
188
  virtualHost: true,
115
- styleIsolation: 'shared'
116
- }
189
+ styleIsolation: 'shared',
190
+ },
117
191
  }
118
192
  </script>
119
193
 
120
194
  <script lang="ts" setup>
121
- import wdActionSheet from '../wd-action-sheet/wd-action-sheet.vue'
122
- import wdCheckbox from '../wd-checkbox/wd-checkbox.vue'
123
- import wdCheckboxGroup from '../wd-checkbox-group/wd-checkbox-group.vue'
124
- import wdRadio from '../wd-radio/wd-radio.vue'
125
- import wdRadioGroup from '../wd-radio-group/wd-radio-group.vue'
126
- import wdButton from '../wd-button/wd-button.vue'
127
- import wdLoading from '../wd-loading/wd-loading.vue'
128
- import wdCell from '../wd-cell/wd-cell.vue'
129
-
130
- import { getCurrentInstance, onBeforeMount, ref, watch, nextTick, computed } from 'vue'
131
- import { getRect, isArray, isDef, isFunction, pause } from '../common/util'
195
+ import { getCurrentInstance, onBeforeMount, ref, watch, nextTick, computed, watchEffect } from 'vue'
196
+ import { useCell } from '../composables/useCell'
197
+ import { getRect, isArray, isDef, isFunction, requestAnimationFrame } from '../common/util'
198
+ import { useParent } from '../composables/useParent'
199
+ import { FORM_KEY, type FormItemRule } from '../wd-form/types'
132
200
  import { useTranslate } from '../composables/useTranslate'
133
201
  import { selectPickerProps, type SelectPickerExpose } from './types'
134
202
 
135
203
  const { translate } = useTranslate('select-picker')
136
204
 
137
205
  const props = defineProps(selectPickerProps)
138
- const emit = defineEmits(['change', 'cancel', 'confirm', 'clear', 'update:modelValue', 'open', 'close'])
206
+ const emit = defineEmits(['change', 'cancel', 'confirm', 'update:modelValue', 'open', 'close'])
139
207
 
140
208
  const pickerShow = ref<boolean>(false)
141
209
  const selectList = ref<Array<number | boolean | string> | number | boolean | string>([])
@@ -143,44 +211,55 @@ const isConfirm = ref<boolean>(false)
143
211
  const lastSelectList = ref<Array<number | boolean | string> | number | boolean | string>([])
144
212
  const filterVal = ref<string>('')
145
213
  const filterColumns = ref<Array<Record<string, any>>>([])
146
- const scrollTop = ref<number>(0) // 滚动位置
147
-
148
- const showValue = computed(() => {
214
+ const scrollTop = ref<number | null>(0) // 滚动位置
215
+ const cell = useCell()
216
+ const pageNum = ref<number>(1)
217
+ const noMore = ref<boolean>(false)
218
+ const innerLoading = ref<boolean>(false)
219
+ const currentColumns = ref<Record<string, any>>()
220
+ const showValue = ref<string>('')
221
+
222
+ watchEffect(() => {
149
223
  const value = valueFormat(props.modelValue)
150
- let showValueTemp: string = ''
151
224
 
152
225
  if (props.displayFormat) {
153
- showValueTemp = props.displayFormat(value, props.columns)
226
+ showValue.value = props.displayFormat(value, props.columns || filterColumns.value)
154
227
  } else {
155
228
  const { type, labelKey } = props
156
229
  if (type === 'checkbox') {
157
230
  const selectedItems = (isArray(value) ? value : []).map((item) => {
158
231
  return getSelectedItem(item)
159
232
  })
160
- showValueTemp = selectedItems
233
+ showValue.value = selectedItems
161
234
  .map((item) => {
162
235
  return item[labelKey]
163
236
  })
164
237
  .join(', ')
165
238
  } else if (type === 'radio') {
166
239
  const selectedItem = getSelectedItem(value as string | number | boolean)
167
- showValueTemp = selectedItem[labelKey]
240
+ showValue.value = selectedItem[labelKey] || currentColumns.value?.[labelKey]
241
+ if (selectedItem[labelKey]) {
242
+ currentColumns.value = selectedItem
243
+ }
168
244
  } else {
169
- showValueTemp = value as string
245
+ showValue.value = value as string
170
246
  }
171
247
  }
172
- return showValueTemp
173
- })
174
-
175
- const cellClass = computed(() => {
176
- const classes = ['wd-select-picker__cell']
177
- if (props.disabled) classes.push('is-disabled')
178
- if (props.readonly) classes.push('is-readonly')
179
- if (props.error) classes.push('is-error')
180
- if (!showValue.value) classes.push('wd-select-picker__cell--placeholder')
181
- return classes.join(' ')
182
248
  })
183
-
249
+ watch(
250
+ () => props.defaultLabel,
251
+ (defaultLabel) => {
252
+ if (defaultLabel) {
253
+ currentColumns.value = {
254
+ [props.valueKey]: props.modelValue,
255
+ [props.labelKey]: defaultLabel,
256
+ }
257
+ }
258
+ },
259
+ {
260
+ immediate: true,
261
+ },
262
+ )
184
263
  watch(
185
264
  () => props.modelValue,
186
265
  (newValue) => {
@@ -190,8 +269,8 @@ watch(
190
269
  },
191
270
  {
192
271
  deep: true,
193
- immediate: true
194
- }
272
+ immediate: true,
273
+ },
195
274
  )
196
275
 
197
276
  watch(
@@ -205,8 +284,8 @@ watch(
205
284
  },
206
285
  {
207
286
  deep: true,
208
- immediate: true
209
- }
287
+ immediate: true,
288
+ },
210
289
  )
211
290
 
212
291
  watch(
@@ -218,8 +297,8 @@ watch(
218
297
  },
219
298
  {
220
299
  deep: true,
221
- immediate: true
222
- }
300
+ immediate: true,
301
+ },
223
302
  )
224
303
 
225
304
  watch(
@@ -231,20 +310,73 @@ watch(
231
310
  },
232
311
  {
233
312
  deep: true,
234
- immediate: true
235
- }
313
+ immediate: true,
314
+ },
236
315
  )
237
316
 
317
+ const { parent: form } = useParent(FORM_KEY)
318
+
319
+ // 表单校验错误信息
320
+ const errorMessage = computed(() => {
321
+ if (form && props.prop && form.errorMessages && form.errorMessages[props.prop]) {
322
+ return form.errorMessages[props.prop]
323
+ } else {
324
+ return ''
325
+ }
326
+ })
327
+
328
+ // 是否展示必填
329
+ const isRequired = computed(() => {
330
+ let formRequired = false
331
+ if (form && form.props.rules) {
332
+ const rules = form.props.rules
333
+ for (const key in rules) {
334
+ if (
335
+ Object.prototype.hasOwnProperty.call(rules, key) &&
336
+ key === props.prop &&
337
+ Array.isArray(rules[key])
338
+ ) {
339
+ formRequired = rules[key].some((rule: FormItemRule) => rule.required)
340
+ }
341
+ }
342
+ }
343
+ return props.required || props.rules.some((rule) => rule.required) || formRequired
344
+ })
345
+ /** 获取远程数据 */
346
+ const getRemoteData = async () => {
347
+ innerLoading.value = true
348
+ const list = await props.remoteConfig?.action(filterVal.value, {
349
+ pageSearch: {
350
+ page: pageNum.value,
351
+ limit: props.remoteConfig?.pageSize || 10,
352
+ },
353
+ })
354
+
355
+ if (list) {
356
+ filterColumns.value = pageNum.value === 1 ? list : [...filterColumns.value, ...list]
357
+ pageNum.value++
358
+ noMore.value = !list.length
359
+ }
360
+ innerLoading.value = false
361
+ }
362
+ const handleScrollToLower = () => {
363
+ if (noMore.value || innerLoading.value || !props.remoteConfig?.isPage) return
364
+ getRemoteData()
365
+ }
238
366
  onBeforeMount(() => {
239
367
  selectList.value = valueFormat(props.modelValue)
240
- filterColumns.value = props.columns
368
+ if (props.remoteConfig) {
369
+ getRemoteData()
370
+ } else {
371
+ filterColumns.value = props.columns
372
+ }
241
373
  })
242
374
 
243
375
  const { proxy } = getCurrentInstance() as any
244
376
 
245
- async function setScrollIntoView() {
377
+ function setScrollIntoView() {
246
378
  let wraperSelector: string = ''
247
- let selectorPromise: Promise<UniApp.NodeInfo>[] = []
379
+ let selectorPromise: Promise<UniApp.NodeInfo | UniApp.NodeInfo[]>[] = []
248
380
  if (isDef(selectList.value) && selectList.value !== '' && !isArray(selectList.value)) {
249
381
  wraperSelector = '#wd-radio-group'
250
382
  selectorPromise = [getRect(`#radio${selectList.value}`, false, proxy)]
@@ -255,24 +387,38 @@ async function setScrollIntoView() {
255
387
  wraperSelector = '#wd-checkbox-group'
256
388
  }
257
389
  if (wraperSelector) {
258
- await pause(2000 / 30)
259
- Promise.all([getRect('.wd-select-picker__wrapper', false, proxy), getRect(wraperSelector, false, proxy), ...selectorPromise]).then((res) => {
260
- if (isDef(res) && isArray(res)) {
261
- const scrollView = res[0]
262
- const wraper = res[1]
263
- const target = res.slice(2) || []
264
- if (isDef(wraper) && isDef(scrollView)) {
265
- const index = target.findIndex((item) => {
266
- return item.bottom! > scrollView.top! && item.top! < scrollView.bottom!
390
+ requestAnimationFrame().then(() => {
391
+ requestAnimationFrame().then(() => {
392
+ Promise.all([
393
+ getRect('.wd-select-picker__wrapper', false, proxy),
394
+ getRect(wraperSelector, false, proxy),
395
+ ...selectorPromise,
396
+ ])
397
+ .then((res: any[]) => {
398
+ if (isDef(res) && isArray(res)) {
399
+ const scrollView = res[0]
400
+ const wraper = res[1]
401
+ const target = res.slice(2) || []
402
+ if (isDef(wraper) && isDef(scrollView)) {
403
+ const index = target.findIndex((item) => {
404
+ return item.top >= scrollView.top && item.bottom <= scrollView.bottom
405
+ })
406
+ if (index < 0) {
407
+ scrollTop.value = -1
408
+ nextTick(() => {
409
+ scrollTop.value = Math.max(
410
+ 0,
411
+ target[0].top - wraper.top - scrollView.height / 2,
412
+ )
413
+ })
414
+ }
415
+ }
416
+ }
267
417
  })
268
- if (index < 0) {
269
- scrollTop.value = -1
270
- nextTick(() => {
271
- scrollTop.value = Math.max(0, target[0].top! - wraper.top! - scrollView.height! / 2)
272
- })
273
- }
274
- }
275
- }
418
+ .catch((error) => {
419
+ console.log(error)
420
+ })
421
+ })
276
422
  })
277
423
  }
278
424
  }
@@ -281,8 +427,8 @@ function noop() {}
281
427
 
282
428
  function getSelectedItem(value: string | number | boolean) {
283
429
  const { valueKey, labelKey, columns } = props
284
-
285
- const selecteds = columns.filter((item) => {
430
+ const list = columns.length > 0 ? columns : filterColumns.value
431
+ const selecteds = list.filter((item) => {
286
432
  return item[valueKey] === value
287
433
  })
288
434
 
@@ -292,7 +438,7 @@ function getSelectedItem(value: string | number | boolean) {
292
438
 
293
439
  return {
294
440
  [valueKey]: value,
295
- [labelKey]: ''
441
+ [labelKey]: '',
296
442
  }
297
443
  }
298
444
 
@@ -300,10 +446,14 @@ function valueFormat(value: string | number | boolean | (string | number | boole
300
446
  return props.type === 'checkbox' ? (isArray(value) ? value : []) : value
301
447
  }
302
448
 
303
- function handleChange({ value }: { value: string | number | boolean | (string | number | boolean)[] }) {
449
+ function handleChange({
450
+ value,
451
+ }: {
452
+ value: string | number | boolean | (string | number | boolean)[]
453
+ }) {
304
454
  selectList.value = value
305
455
  emit('change', { value })
306
- if (props.type === 'radio' && !props.showConfirm) {
456
+ if (['radio', 'button'].includes(props.type) && !props.showConfirm) {
307
457
  onConfirm()
308
458
  }
309
459
  }
@@ -357,7 +507,7 @@ function handleConfirm() {
357
507
  emit('update:modelValue', lastSelectList.value)
358
508
  emit('confirm', {
359
509
  value: lastSelectList.value,
360
- selectedItems
510
+ selectedItems,
361
511
  })
362
512
  emit('close')
363
513
  }
@@ -368,12 +518,15 @@ function getFilterText(label: string, filterVal: string) {
368
518
  return label.split(reg).map((text) => {
369
519
  return {
370
520
  type: text === filterVal ? 'active' : 'normal',
371
- label: text
521
+ label: text,
372
522
  }
373
523
  })
374
524
  }
375
525
 
376
526
  function handleFilterChange({ value }: { value: string }) {
527
+ if (props.remoteConfig) {
528
+ return
529
+ }
377
530
  if (value === '') {
378
531
  filterColumns.value = []
379
532
  filterVal.value = value
@@ -386,6 +539,14 @@ function handleFilterChange({ value }: { value: string }) {
386
539
  }
387
540
  }
388
541
 
542
+ function handleFilterSearch(value: string) {
543
+ if (!props.remoteConfig) {
544
+ return
545
+ }
546
+ pageNum.value = 1
547
+ getRemoteData()
548
+ }
549
+
389
550
  function formatFilterColumns(columns: Record<string, any>[], filterVal: string) {
390
551
  const filterColumnsTemp = columns.filter((item) => {
391
552
  return item[props.labelKey].indexOf(filterVal) > -1
@@ -394,7 +555,7 @@ function formatFilterColumns(columns: Record<string, any>[], filterVal: string)
394
555
  const formatFilterColumns = filterColumnsTemp.map((item) => {
395
556
  return {
396
557
  ...item,
397
- [props.labelKey]: getFilterText(item[props.labelKey], filterVal)
558
+ [props.labelKey]: getFilterText(item[props.labelKey], filterVal),
398
559
  }
399
560
  })
400
561
  filterColumns.value = []
@@ -407,26 +568,11 @@ const showConfirm = computed(() => {
407
568
  return (props.type === 'radio' && props.showConfirm) || props.type === 'checkbox'
408
569
  })
409
570
 
410
- // 是否展示清除按钮
411
- const showClear = computed(() => {
412
- return props.clearable && !props.disabled && !props.readonly && showValue.value.length
413
- })
414
-
415
- function handleClear() {
416
- emit('update:modelValue', props.type === 'checkbox' ? [] : '')
417
- emit('clear')
418
- }
419
-
420
- // 是否展示箭头
421
- const showArrow = computed(() => {
422
- return !props.disabled && !props.readonly && !showClear.value
423
- })
424
-
425
571
  defineExpose<SelectPickerExpose>({
426
572
  close,
427
- open
573
+ open,
428
574
  })
429
575
  </script>
430
576
  <style lang="scss" scoped>
431
- @import './index.scss';
577
+ @import './index';
432
578
  </style>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "@tplc/wot",
3
3
  "name": "@tplc/wot",
4
- "version": "1.0.16",
4
+ "version": "1.0.18",
5
5
  "keywords": [
6
6
  "wot-design-uni",
7
7
  "国际化",
@@ -1,6 +1,19 @@
1
1
  import type { ComponentPublicInstance, ExtractPropTypes, PropType } from 'vue'
2
2
  import type { FormItemRule } from '../wd-form/types'
3
- export type SelectPickerType = 'checkbox' | 'radio'
3
+ export type SelectPickerType = 'checkbox' | 'radio' | 'button'
4
+ export type SelectPickerRemote = {
5
+ action: (
6
+ search: string,
7
+ params: {
8
+ pageSearch: {
9
+ page: number
10
+ limit: number
11
+ }
12
+ },
13
+ ) => Promise<Record<string, any>[]>
14
+ pageSize?: number
15
+ isPage?: boolean
16
+ }
4
17
  export declare const selectPickerProps: {
5
18
  /** 选择器左侧文案 */
6
19
  label: StringConstructor
@@ -35,31 +48,18 @@ export declare const selectPickerProps: {
35
48
  type: BooleanConstructor
36
49
  default: boolean
37
50
  }
38
- /**
39
- * 使用 label 插槽时设置该选项
40
- * @deprecated 可以直接使用标签插槽,无需配置此选项
41
- */
51
+ /** 使用 label 插槽时设置该选项 */
42
52
  useLabelSlot: {
43
53
  type: BooleanConstructor
44
54
  default: boolean
45
55
  }
46
- /**
47
- * 使用默认插槽时设置该选项
48
- * @deprecated 可以直接使用默认插槽,无需配置此选项
49
- */
56
+ /** 使用默认插槽时设置该选项 */
50
57
  useDefaultSlot: {
51
58
  type: BooleanConstructor
52
59
  default: boolean
53
60
  }
54
61
  /** 设置选择器大小 */
55
62
  size: StringConstructor
56
- /**
57
- * 是否垂直居中
58
- */
59
- center: {
60
- type: BooleanConstructor
61
- default: boolean
62
- }
63
63
  /** 选中的颜色(单/复选框) */
64
64
  checkedColor: StringConstructor
65
65
  /** 最小选中的数量(仅在复选框类型下生效,`type`类型为`checkbox`) */
@@ -135,6 +135,10 @@ export declare const selectPickerProps: {
135
135
  type: BooleanConstructor
136
136
  default: boolean
137
137
  }
138
+ /** 远程搜索配置 */
139
+ remoteConfig: {
140
+ type: PropType<SelectPickerRemote>
141
+ }
138
142
  /** 搜索框占位符 */
139
143
  filterPlaceholder: StringConstructor
140
144
  /** 是否超出隐藏 */
@@ -174,27 +178,8 @@ export declare const selectPickerProps: {
174
178
  type: BooleanConstructor
175
179
  default: boolean
176
180
  }
177
- /**
178
- * 显示清空按钮
179
- */
180
- clearable: {
181
- type: BooleanConstructor
182
- default: boolean
183
- }
184
- /**
185
- * 是否从页面中脱离出来,用于解决各种 fixed 失效问题 (H5: teleport, APP: renderjs, 小程序: root-portal)
186
- */
187
- rootPortal: {
188
- type: BooleanConstructor
189
- default: boolean
190
- }
191
- /**
192
- * 必填标记位置,可选值:before、after
193
- */
194
- markerSide: {
195
- type: PropType<'before' | 'after'>
196
- default: 'before' | 'after'
197
- }
181
+ /** 默认展示文案 */
182
+ defaultLabel: StringConstructor
198
183
  customStyle: {
199
184
  type: PropType<string>
200
185
  default: string
@@ -1,3 +1,4 @@
1
+ import { type FormItemRule } from '../wd-form/types'
1
2
  declare const _default: __VLS_WithTemplateSlots<
2
3
  import('vue').DefineComponent<
3
4
  {
@@ -34,10 +35,6 @@ declare const _default: __VLS_WithTemplateSlots<
34
35
  default: boolean
35
36
  }
36
37
  size: StringConstructor
37
- center: {
38
- type: BooleanConstructor
39
- default: boolean
40
- }
41
38
  checkedColor: StringConstructor
42
39
  min: {
43
40
  type: NumberConstructor
@@ -95,6 +92,9 @@ declare const _default: __VLS_WithTemplateSlots<
95
92
  type: BooleanConstructor
96
93
  default: boolean
97
94
  }
95
+ remoteConfig: {
96
+ type: import('vue').PropType<import('./types').SelectPickerRemote>
97
+ }
98
98
  filterPlaceholder: StringConstructor
99
99
  ellipsis: {
100
100
  type: BooleanConstructor
@@ -106,7 +106,7 @@ declare const _default: __VLS_WithTemplateSlots<
106
106
  }
107
107
  prop: StringConstructor
108
108
  rules: {
109
- type: import('vue').PropType<import('../wd-form/types.js').FormItemRule[]>
109
+ type: import('vue').PropType<FormItemRule[]>
110
110
  default: () => never[]
111
111
  }
112
112
  customContentClass: {
@@ -125,18 +125,7 @@ declare const _default: __VLS_WithTemplateSlots<
125
125
  type: BooleanConstructor
126
126
  default: boolean
127
127
  }
128
- clearable: {
129
- type: BooleanConstructor
130
- default: boolean
131
- }
132
- rootPortal: {
133
- type: BooleanConstructor
134
- default: boolean
135
- }
136
- markerSide: {
137
- type: import('vue').PropType<'before' | 'after'>
138
- default: 'before' | 'after'
139
- }
128
+ defaultLabel: StringConstructor
140
129
  customStyle: {
141
130
  type: import('vue').PropType<string>
142
131
  default: string
@@ -162,7 +151,6 @@ declare const _default: __VLS_WithTemplateSlots<
162
151
  open: (...args: any[]) => void
163
152
  change: (...args: any[]) => void
164
153
  confirm: (...args: any[]) => void
165
- clear: (...args: any[]) => void
166
154
  },
167
155
  string,
168
156
  import('vue').PublicProps,
@@ -201,10 +189,6 @@ declare const _default: __VLS_WithTemplateSlots<
201
189
  default: boolean
202
190
  }
203
191
  size: StringConstructor
204
- center: {
205
- type: BooleanConstructor
206
- default: boolean
207
- }
208
192
  checkedColor: StringConstructor
209
193
  min: {
210
194
  type: NumberConstructor
@@ -262,6 +246,9 @@ declare const _default: __VLS_WithTemplateSlots<
262
246
  type: BooleanConstructor
263
247
  default: boolean
264
248
  }
249
+ remoteConfig: {
250
+ type: import('vue').PropType<import('./types').SelectPickerRemote>
251
+ }
265
252
  filterPlaceholder: StringConstructor
266
253
  ellipsis: {
267
254
  type: BooleanConstructor
@@ -273,7 +260,7 @@ declare const _default: __VLS_WithTemplateSlots<
273
260
  }
274
261
  prop: StringConstructor
275
262
  rules: {
276
- type: import('vue').PropType<import('../wd-form/types.js').FormItemRule[]>
263
+ type: import('vue').PropType<FormItemRule[]>
277
264
  default: () => never[]
278
265
  }
279
266
  customContentClass: {
@@ -292,18 +279,7 @@ declare const _default: __VLS_WithTemplateSlots<
292
279
  type: BooleanConstructor
293
280
  default: boolean
294
281
  }
295
- clearable: {
296
- type: BooleanConstructor
297
- default: boolean
298
- }
299
- rootPortal: {
300
- type: BooleanConstructor
301
- default: boolean
302
- }
303
- markerSide: {
304
- type: import('vue').PropType<'before' | 'after'>
305
- default: 'before' | 'after'
306
- }
282
+ defaultLabel: StringConstructor
307
283
  customStyle: {
308
284
  type: import('vue').PropType<string>
309
285
  default: string
@@ -320,7 +296,6 @@ declare const _default: __VLS_WithTemplateSlots<
320
296
  onCancel?: ((...args: any[]) => any) | undefined
321
297
  onOpen?: ((...args: any[]) => any) | undefined
322
298
  onConfirm?: ((...args: any[]) => any) | undefined
323
- onClear?: ((...args: any[]) => any) | undefined
324
299
  },
325
300
  {
326
301
  customStyle: string
@@ -328,8 +303,6 @@ declare const _default: __VLS_WithTemplateSlots<
328
303
  type: import('./types').SelectPickerType
329
304
  required: boolean
330
305
  zIndex: number
331
- rootPortal: boolean
332
- center: boolean
333
306
  closeOnClickModal: boolean
334
307
  safeAreaInsetBottom: boolean
335
308
  readonly: boolean
@@ -339,7 +312,7 @@ declare const _default: __VLS_WithTemplateSlots<
339
312
  loading: boolean
340
313
  loadingColor: string
341
314
  scrollIntoView: boolean
342
- rules: import('../wd-form/types.js').FormItemRule[]
315
+ rules: FormItemRule[]
343
316
  labelWidth: string
344
317
  useLabelSlot: boolean
345
318
  useDefaultSlot: boolean
@@ -350,18 +323,16 @@ declare const _default: __VLS_WithTemplateSlots<
350
323
  customValueClass: string
351
324
  columns: Record<string, any>[]
352
325
  customContentClass: string
353
- markerSide: 'before' | 'after'
354
326
  min: number
355
327
  valueKey: string
356
328
  labelKey: string
357
- clearable: boolean
358
329
  filterable: boolean
359
330
  },
360
331
  {}
361
332
  >,
362
333
  {
363
- label?(_: {}): any
364
334
  default?(_: {}): any
335
+ label?(_: {}): any
365
336
  }
366
337
  >
367
338
  export default _default