focusin-mini-ui 1.0.2 → 1.0.4
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 +38 -36
- package/packages/fs-col-picker/index.vue +609 -0
- package/packages/fs-collapse/index.scss +0 -0
- package/packages/fs-collapse/index.vue +113 -0
- package/packages/fs-common-audio/index.scss +0 -0
- package/packages/fs-common-audio/index.vue +257 -0
- package/packages/fs-empty/index.scss +0 -0
- package/packages/fs-empty/index.vue +33 -0
- package/packages/fs-form/index.scss +0 -0
- package/packages/fs-form/index.vue +804 -0
- package/packages/fs-list-check/index.scss +0 -0
- package/packages/fs-list-check/index.vue +49 -0
- package/packages/fs-pop/index.scss +0 -0
- package/packages/fs-pop/index.vue +136 -0
- package/packages/fs-radio/index.scss +0 -0
- package/packages/fs-radio/index.vue +114 -0
- package/packages/fs-search-bar/index.scss +0 -0
- package/packages/fs-search-bar/index.vue +57 -0
- package/packages/fs-select-button/context.ts +20 -0
- package/packages/fs-select-button/index.scss +0 -0
- package/packages/fs-select-button/index.vue +111 -0
- package/packages/fs-select-button/sButton.vue +38 -0
- package/packages/fs-table/index.scss +0 -0
- package/packages/fs-table/index.vue +94 -0
- package/packages/fs-tabs/index.scss +0 -0
- package/packages/fs-tabs/index.vue +140 -0
- package/packages/fs-time-bar/index.scss +0 -0
- package/packages/fs-time-bar/index.vue +168 -0
- package/packages/fs-tree/index.scss +0 -0
- package/packages/fs-tree/index.vue +249 -0
- package/packages/fs-voice-pop/index.scss +0 -0
- package/packages/fs-voice-pop/index.vue +150 -0
- package/packages/index.js +1 -0
- package/style.scss +57 -0
- package/utils/common.ts +458 -372
- package/packages/fs-demo/index.vue +0 -8
- /package/packages/{fs-demo → fs-col-picker}/index.scss +0 -0
package/package.json
CHANGED
|
@@ -1,38 +1,40 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
2
|
+
"name": "focusin-mini-ui",
|
|
3
|
+
"version": "1.0.4",
|
|
4
|
+
"description": "A collection of UniApp components built with Vue3",
|
|
5
|
+
"main": "index",
|
|
6
|
+
"module": "index",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"packages",
|
|
10
|
+
"*.scss",
|
|
11
|
+
"index.ts",
|
|
12
|
+
"utils"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"dev": "vite",
|
|
16
|
+
"build": "vite build",
|
|
17
|
+
"prepublishOnly": "npm run build"
|
|
18
|
+
},
|
|
19
|
+
"peerDependencies": {
|
|
20
|
+
"@dcloudio/uni-app": "3.0.0-4020920240930001",
|
|
21
|
+
"unocss": "^0.58.9",
|
|
22
|
+
"unocss-applet": "^0.7.8",
|
|
23
|
+
"wot-design-uni": "^1.7.1",
|
|
24
|
+
"vue": "3.4.21",
|
|
25
|
+
"vue-demi": "^0.14.10",
|
|
26
|
+
"xe-utils": "3.7.4"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"vite": "^4.0.0",
|
|
30
|
+
"@vitejs/plugin-vue": "^4.0.0",
|
|
31
|
+
"tailwindcss": "^3.0.0",
|
|
32
|
+
"wot-design-uni": "^1.7.1",
|
|
33
|
+
"postcss": "^8.4.49",
|
|
34
|
+
"postcss-html": "^1.7.0",
|
|
35
|
+
"postcss-scss": "^4.0.9",
|
|
36
|
+
"sass": "1.77.8",
|
|
37
|
+
"typescript": "^5.7.2",
|
|
38
|
+
"@types/node": "^20.17.9"
|
|
39
|
+
}
|
|
38
40
|
}
|
|
@@ -0,0 +1,609 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<view
|
|
3
|
+
:class="`wd-col-picker ${cell.border.value ? 'is-border' : ''} ${customClass}`"
|
|
4
|
+
:style="customStyle"
|
|
5
|
+
>
|
|
6
|
+
<view class="wd-col-picker__field" @click="showPicker">
|
|
7
|
+
<slot v-if="useDefaultSlot"></slot>
|
|
8
|
+
<view
|
|
9
|
+
v-else
|
|
10
|
+
:class="`wd-col-picker__cell ${disabled && 'is-disabled'} ${readonly && 'is-readonly'} ${
|
|
11
|
+
alignRight && 'is-align-right'
|
|
12
|
+
} ${error && 'is-error'} ${size && 'is-' + size}`"
|
|
13
|
+
>
|
|
14
|
+
<view
|
|
15
|
+
v-if="label || useLabelSlot"
|
|
16
|
+
:class="`wd-col-picker__label ${isRequired && 'is-required'} ${customLabelClass}`"
|
|
17
|
+
:style="labelWidth ? 'min-width:' + labelWidth + ';max-width:' + labelWidth + ';' : ''"
|
|
18
|
+
>
|
|
19
|
+
<block v-if="label">{{ label }}</block>
|
|
20
|
+
<slot v-else name="label"></slot>
|
|
21
|
+
</view>
|
|
22
|
+
<view class="wd-col-picker__body">
|
|
23
|
+
<view class="wd-col-picker__value-wraper">
|
|
24
|
+
<view
|
|
25
|
+
:class="`wd-col-picker__value ${ellipsis && 'is-ellipsis'} ${customValueClass} ${
|
|
26
|
+
showValue ? '' : 'wd-col-picker__value--placeholder'
|
|
27
|
+
}`"
|
|
28
|
+
>
|
|
29
|
+
{{ showValue || placeholder || translate('placeholder') }}
|
|
30
|
+
</view>
|
|
31
|
+
<wd-icon
|
|
32
|
+
v-if="!disabled && !readonly"
|
|
33
|
+
custom-class="wd-col-picker__arrow"
|
|
34
|
+
name="arrow-right"
|
|
35
|
+
/>
|
|
36
|
+
</view>
|
|
37
|
+
<view v-if="errorMessage" class="wd-col-picker__error-message">{{ errorMessage }}</view>
|
|
38
|
+
</view>
|
|
39
|
+
</view>
|
|
40
|
+
</view>
|
|
41
|
+
<wd-action-sheet
|
|
42
|
+
v-model="pickerShow"
|
|
43
|
+
:duration="250"
|
|
44
|
+
:title="title || translate('title')"
|
|
45
|
+
:close-on-click-modal="closeOnClickModal"
|
|
46
|
+
:z-index="zIndex"
|
|
47
|
+
:safe-area-inset-bottom="safeAreaInsetBottom"
|
|
48
|
+
@open="handlePickerOpend"
|
|
49
|
+
@close="handlePickerClose"
|
|
50
|
+
@closed="handlePickerClosed"
|
|
51
|
+
>
|
|
52
|
+
<wd-search
|
|
53
|
+
v-model="filterVal"
|
|
54
|
+
placeholder="请输入"
|
|
55
|
+
hide-cancel
|
|
56
|
+
placeholder-left
|
|
57
|
+
@change="handleFilterChange"
|
|
58
|
+
/>
|
|
59
|
+
<view class="wd-col-picker__selected">
|
|
60
|
+
<scroll-view :scroll-x="true" scroll-with-animation :scroll-left="scrollLeft">
|
|
61
|
+
<view class="wd-col-picker__selected-container">
|
|
62
|
+
<view
|
|
63
|
+
v-for="(_, colIndex) in selectList"
|
|
64
|
+
:key="colIndex"
|
|
65
|
+
:class="`wd-col-picker__selected-item ${colIndex === currentCol && 'is-selected'}`"
|
|
66
|
+
@click="handleColClick(colIndex)"
|
|
67
|
+
>
|
|
68
|
+
{{ selectShowList[colIndex] || translate('select') }}
|
|
69
|
+
</view>
|
|
70
|
+
<view class="wd-col-picker__selected-line" :style="state.lineStyle"></view>
|
|
71
|
+
</view>
|
|
72
|
+
</scroll-view>
|
|
73
|
+
</view>
|
|
74
|
+
<view class="wd-col-picker__list-container">
|
|
75
|
+
<view
|
|
76
|
+
v-for="(col, colIndex) in selectList"
|
|
77
|
+
:key="colIndex"
|
|
78
|
+
class="wd-col-picker__list"
|
|
79
|
+
:style="colIndex === currentCol ? 'display: block;' : 'display: none;'"
|
|
80
|
+
>
|
|
81
|
+
<view
|
|
82
|
+
style="display: flex; justify-content: space-between"
|
|
83
|
+
v-for="(item, index) in col"
|
|
84
|
+
:key="index"
|
|
85
|
+
:class="`wd-col-picker__list-item ${
|
|
86
|
+
pickerColSelected[colIndex] &&
|
|
87
|
+
item[valueKey] === pickerColSelected[colIndex] &&
|
|
88
|
+
'is-selected'
|
|
89
|
+
} ${item.disabled && 'is-disabled'}`"
|
|
90
|
+
@click="chooseItem(colIndex, index)"
|
|
91
|
+
>
|
|
92
|
+
<view>
|
|
93
|
+
<view class="wd-col-picker__list-item-label">{{ item[labelKey] }}</view>
|
|
94
|
+
<view v-if="item[tipKey]" class="wd-col-picker__list-item-tip">
|
|
95
|
+
{{ item[tipKey] }}
|
|
96
|
+
</view>
|
|
97
|
+
</view>
|
|
98
|
+
<wd-icon
|
|
99
|
+
custom-class="wd-col-picker__checked"
|
|
100
|
+
name="check"
|
|
101
|
+
v-if="pickerColSelected[colIndex] && item[valueKey] === pickerColSelected[colIndex]"
|
|
102
|
+
></wd-icon>
|
|
103
|
+
</view>
|
|
104
|
+
<view v-if="loading" class="wd-col-picker__loading">
|
|
105
|
+
<wd-loading :color="loadingColor" />
|
|
106
|
+
</view>
|
|
107
|
+
</view>
|
|
108
|
+
</view>
|
|
109
|
+
</wd-action-sheet>
|
|
110
|
+
</view>
|
|
111
|
+
</template>
|
|
112
|
+
<script lang="ts" setup>
|
|
113
|
+
import wdIcon from 'wot-design-uni/components/wd-icon/wd-icon.vue';
|
|
114
|
+
import wdLoading from 'wot-design-uni/components/wd-loading/wd-loading.vue';
|
|
115
|
+
import wdActionSheet from 'wot-design-uni/components/wd-action-sheet/wd-action-sheet.vue';
|
|
116
|
+
|
|
117
|
+
import {
|
|
118
|
+
computed,
|
|
119
|
+
getCurrentInstance,
|
|
120
|
+
onMounted,
|
|
121
|
+
ref,
|
|
122
|
+
watch,
|
|
123
|
+
type CSSProperties,
|
|
124
|
+
reactive,
|
|
125
|
+
nextTick,
|
|
126
|
+
} from 'vue';
|
|
127
|
+
import {
|
|
128
|
+
addUnit,
|
|
129
|
+
debounce,
|
|
130
|
+
getRect,
|
|
131
|
+
isArray,
|
|
132
|
+
isBoolean,
|
|
133
|
+
isDef,
|
|
134
|
+
isFunction,
|
|
135
|
+
objToStyle,
|
|
136
|
+
} from '../../utils/common';
|
|
137
|
+
import { useCell } from '../../composables/useCell';
|
|
138
|
+
import { FORM_KEY, type FormItemRule } from 'wot-design-uni/components/wd-form/types';
|
|
139
|
+
import { useParent } from '../../composables/useParent';
|
|
140
|
+
import { useTranslate } from '../../composables/useTranslate';
|
|
141
|
+
import {
|
|
142
|
+
colPickerProps,
|
|
143
|
+
type ColPickerExpose,
|
|
144
|
+
} from 'wot-design-uni/components/wd-col-picker/types';
|
|
145
|
+
import XEUtils from 'xe-utils';
|
|
146
|
+
|
|
147
|
+
const { translate } = useTranslate('col-picker');
|
|
148
|
+
|
|
149
|
+
const $container = '.wd-col-picker__selected-container';
|
|
150
|
+
const $item = '.wd-col-picker__selected-item';
|
|
151
|
+
const filterVal = ref<string>('');
|
|
152
|
+
const props = defineProps(colPickerProps);
|
|
153
|
+
const emit = defineEmits(['close', 'update:modelValue', 'confirm']);
|
|
154
|
+
const cell = useCell();
|
|
155
|
+
const pickerShow = ref<boolean>(false);
|
|
156
|
+
const currentCol = ref<number>(0);
|
|
157
|
+
const selectList = ref<Record<string, any>[][]>([]);
|
|
158
|
+
const pickerColSelected = ref<(string | number)[]>([]);
|
|
159
|
+
const selectShowList = ref<Record<string, any>[]>([]);
|
|
160
|
+
const loading = ref<boolean>(false);
|
|
161
|
+
const isChange = ref<boolean>(false);
|
|
162
|
+
const lastSelectList = ref<Record<string, any>[][]>([]);
|
|
163
|
+
const lastPickerColSelected = ref<(string | number)[]>([]);
|
|
164
|
+
const scrollLeft = ref<number>(0);
|
|
165
|
+
const inited = ref<boolean>(false);
|
|
166
|
+
const isCompleting = ref<boolean>(false);
|
|
167
|
+
|
|
168
|
+
const state = reactive({
|
|
169
|
+
lineStyle: 'display:none;', // 激活项边框线样式
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
const { proxy } = getCurrentInstance() as any;
|
|
173
|
+
const originalData = ref<Record<string, any>[][]>([]); // Store original all columns data
|
|
174
|
+
|
|
175
|
+
// Initialize original data when component mounts or props.columns changes
|
|
176
|
+
watch(
|
|
177
|
+
() => props.columns,
|
|
178
|
+
(newValue) => {
|
|
179
|
+
if (newValue.length > 0) {
|
|
180
|
+
originalData.value = XEUtils.clone(newValue, true);
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
{ immediate: true, deep: true }
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
const deepFilter = (data: Record<string, any>[], searchText: string): Record<string, any>[] => {
|
|
187
|
+
return XEUtils.searchTree(data, (item) =>
|
|
188
|
+
item[props.labelKey]?.toLowerCase().includes(searchText.toLowerCase())
|
|
189
|
+
);
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
const handleFilterChange = debounce(function () {
|
|
193
|
+
const searchText = filterVal.value.trim().toLowerCase();
|
|
194
|
+
|
|
195
|
+
if (searchText === '') {
|
|
196
|
+
selectList.value = originalData.value;
|
|
197
|
+
console.log(originalData.value);
|
|
198
|
+
pickerColSelected.value = [originalData.value[0][props.labelKey]];
|
|
199
|
+
currentCol.value = 0;
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (selectList.value.length > 0 && originalData.value.length > 0) {
|
|
204
|
+
const cc = XEUtils.clone(originalData.value, true);
|
|
205
|
+
const filteredData = deepFilter(cc[0], searchText);
|
|
206
|
+
selectList.value = [];
|
|
207
|
+
pickerColSelected.value = [];
|
|
208
|
+
selectList.value[0] = filteredData;
|
|
209
|
+
console.log(filteredData[0][props.labelKey]);
|
|
210
|
+
pickerColSelected.value = [filteredData[0][props.labelKey]];
|
|
211
|
+
|
|
212
|
+
currentCol.value = 0;
|
|
213
|
+
updateLineAndScroll(true);
|
|
214
|
+
}
|
|
215
|
+
}, 300);
|
|
216
|
+
const updateLineAndScroll = debounce(function (animation = true) {
|
|
217
|
+
setLineStyle(animation);
|
|
218
|
+
lineScrollIntoView();
|
|
219
|
+
}, 50);
|
|
220
|
+
|
|
221
|
+
const showValue = computed(() => {
|
|
222
|
+
const selectedItems = (props.modelValue || []).map((item, colIndex) => {
|
|
223
|
+
return getSelectedItem(item, colIndex, selectList.value);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
if (props.displayFormat) {
|
|
227
|
+
return props.displayFormat(selectedItems);
|
|
228
|
+
} else {
|
|
229
|
+
return selectedItems
|
|
230
|
+
.map((item) => {
|
|
231
|
+
return item[props.labelKey];
|
|
232
|
+
})
|
|
233
|
+
.join('');
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
watch(
|
|
238
|
+
() => props.modelValue,
|
|
239
|
+
(newValue) => {
|
|
240
|
+
if (newValue === pickerColSelected.value) return;
|
|
241
|
+
pickerColSelected.value = newValue;
|
|
242
|
+
newValue.map((item, colIndex) => {
|
|
243
|
+
return getSelectedItem(item, colIndex, selectList.value)[props.labelKey];
|
|
244
|
+
});
|
|
245
|
+
handleAutoComplete();
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
deep: true,
|
|
249
|
+
immediate: true,
|
|
250
|
+
}
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
watch(
|
|
254
|
+
() => props.columns,
|
|
255
|
+
(newValue, oldValue) => {
|
|
256
|
+
if (newValue.length && !isArray(newValue[0])) {
|
|
257
|
+
console.error(
|
|
258
|
+
'[wot design] error(wd-col-picker): the columns props of wd-col-picker should be a two-dimensional array'
|
|
259
|
+
);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
if (newValue.length === 0 && !oldValue) return;
|
|
263
|
+
|
|
264
|
+
const newSelectedList = newValue.slice(0);
|
|
265
|
+
|
|
266
|
+
selectList.value = newSelectedList;
|
|
267
|
+
|
|
268
|
+
selectShowList.value = pickerColSelected.value.map((item, colIndex) => {
|
|
269
|
+
return getSelectedItem(item, colIndex, newSelectedList)[props.labelKey];
|
|
270
|
+
});
|
|
271
|
+
lastSelectList.value = newSelectedList;
|
|
272
|
+
|
|
273
|
+
if (newSelectedList.length > 0) {
|
|
274
|
+
currentCol.value = newSelectedList.length - 1;
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
deep: true,
|
|
279
|
+
immediate: true,
|
|
280
|
+
}
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
watch(
|
|
284
|
+
() => props.columnChange,
|
|
285
|
+
(fn) => {
|
|
286
|
+
if (fn && !isFunction(fn)) {
|
|
287
|
+
console.error('The type of columnChange must be Function');
|
|
288
|
+
}
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
deep: true,
|
|
292
|
+
immediate: true,
|
|
293
|
+
}
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
watch(
|
|
297
|
+
() => props.displayFormat,
|
|
298
|
+
(fn) => {
|
|
299
|
+
if (fn && !isFunction(fn)) {
|
|
300
|
+
console.error('The type of displayFormat must be Function');
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
deep: true,
|
|
305
|
+
immediate: true,
|
|
306
|
+
}
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
watch(
|
|
310
|
+
() => props.beforeConfirm,
|
|
311
|
+
(fn) => {
|
|
312
|
+
if (fn && !isFunction(fn)) {
|
|
313
|
+
console.error('The type of beforeConfirm must be Function');
|
|
314
|
+
}
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
deep: true,
|
|
318
|
+
immediate: true,
|
|
319
|
+
}
|
|
320
|
+
);
|
|
321
|
+
|
|
322
|
+
const { parent: form } = useParent(FORM_KEY);
|
|
323
|
+
|
|
324
|
+
// 表单校验错误信息
|
|
325
|
+
const errorMessage = computed(() => {
|
|
326
|
+
if (form && props.prop && form.errorMessages && form.errorMessages[props.prop]) {
|
|
327
|
+
return form.errorMessages[props.prop];
|
|
328
|
+
} else {
|
|
329
|
+
return '';
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
// 是否展示必填
|
|
334
|
+
const isRequired = computed(() => {
|
|
335
|
+
let formRequired = false;
|
|
336
|
+
if (form && form.props.rules) {
|
|
337
|
+
const rules = form.props.rules;
|
|
338
|
+
for (const key in rules) {
|
|
339
|
+
if (
|
|
340
|
+
Object.prototype.hasOwnProperty.call(rules, key) &&
|
|
341
|
+
key === props.prop &&
|
|
342
|
+
Array.isArray(rules[key])
|
|
343
|
+
) {
|
|
344
|
+
formRequired = rules[key].some((rule: FormItemRule) => rule.required);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return props.required || props.rules.some((rule) => rule.required) || formRequired;
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
onMounted(() => {
|
|
352
|
+
inited.value = true;
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
// 打开弹框
|
|
356
|
+
function open() {
|
|
357
|
+
showPicker();
|
|
358
|
+
}
|
|
359
|
+
// 关闭弹框
|
|
360
|
+
function close() {
|
|
361
|
+
handlePickerClose();
|
|
362
|
+
}
|
|
363
|
+
function handlePickerOpend() {
|
|
364
|
+
updateLineAndScroll(false);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function handlePickerClose() {
|
|
368
|
+
pickerShow.value = false;
|
|
369
|
+
emit('close');
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function handlePickerClosed() {
|
|
373
|
+
if (isChange.value) {
|
|
374
|
+
setTimeout(() => {
|
|
375
|
+
selectList.value = lastSelectList.value.slice(0);
|
|
376
|
+
pickerColSelected.value = lastPickerColSelected.value.slice(0);
|
|
377
|
+
selectShowList.value = lastPickerColSelected.value.map((item, colIndex) => {
|
|
378
|
+
return getSelectedItem(item, colIndex, lastSelectList.value)[props.labelKey];
|
|
379
|
+
});
|
|
380
|
+
currentCol.value = lastSelectList.value.length - 1;
|
|
381
|
+
isChange.value = false;
|
|
382
|
+
}, 250);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function showPicker() {
|
|
387
|
+
const { disabled, readonly } = props;
|
|
388
|
+
|
|
389
|
+
if (disabled || readonly) return;
|
|
390
|
+
pickerShow.value = true;
|
|
391
|
+
lastPickerColSelected.value = pickerColSelected.value.slice(0);
|
|
392
|
+
lastSelectList.value = selectList.value.slice(0);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function getSelectedItem(
|
|
396
|
+
value: string | number,
|
|
397
|
+
colIndex: number,
|
|
398
|
+
selectList: Record<string, any>[][]
|
|
399
|
+
) {
|
|
400
|
+
const { valueKey, labelKey } = props;
|
|
401
|
+
if (selectList[colIndex]) {
|
|
402
|
+
const selecteds = selectList[colIndex].filter((item) => {
|
|
403
|
+
return item[valueKey] === value;
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
if (selecteds.length > 0) {
|
|
407
|
+
return selecteds[0];
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
return {
|
|
412
|
+
[valueKey]: value,
|
|
413
|
+
[labelKey]: '',
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function chooseItem(colIndex: number, index: number) {
|
|
418
|
+
const item = selectList.value[colIndex][index];
|
|
419
|
+
if (item.disabled) return;
|
|
420
|
+
|
|
421
|
+
const newPickerColSelected = pickerColSelected.value.slice(0, colIndex);
|
|
422
|
+
newPickerColSelected.push(item[props.valueKey]);
|
|
423
|
+
isChange.value = true;
|
|
424
|
+
pickerColSelected.value = newPickerColSelected;
|
|
425
|
+
selectList.value = selectList.value.slice(0, colIndex + 1);
|
|
426
|
+
selectShowList.value = newPickerColSelected.map((item, colIndex) => {
|
|
427
|
+
return getSelectedItem(item, colIndex, selectList.value)[props.labelKey];
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
if (selectShowList.value[colIndex] && colIndex === currentCol.value) {
|
|
431
|
+
updateLineAndScroll(true);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
handleColChange(colIndex, item, index);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function handleColChange(
|
|
438
|
+
colIndex: number,
|
|
439
|
+
item: Record<string, any>,
|
|
440
|
+
index: number,
|
|
441
|
+
callback?: () => void
|
|
442
|
+
) {
|
|
443
|
+
loading.value = true;
|
|
444
|
+
const { columnChange, beforeConfirm } = props;
|
|
445
|
+
columnChange &&
|
|
446
|
+
columnChange({
|
|
447
|
+
selectedItem: item,
|
|
448
|
+
index: colIndex,
|
|
449
|
+
rowIndex: index,
|
|
450
|
+
resolve: (nextColumn: Record<string, any>[]) => {
|
|
451
|
+
if (!isArray(nextColumn)) {
|
|
452
|
+
console.error(
|
|
453
|
+
'[wot design] error(wd-col-picker): the data of each column of wd-col-picker should be an array'
|
|
454
|
+
);
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
const newSelectList = selectList.value.slice(0);
|
|
459
|
+
newSelectList[colIndex + 1] = nextColumn;
|
|
460
|
+
|
|
461
|
+
selectList.value = newSelectList;
|
|
462
|
+
loading.value = false;
|
|
463
|
+
currentCol.value = colIndex + 1;
|
|
464
|
+
|
|
465
|
+
updateLineAndScroll(true);
|
|
466
|
+
if (typeof callback === 'function') {
|
|
467
|
+
isCompleting.value = false;
|
|
468
|
+
selectShowList.value = pickerColSelected.value.map((item, colIndex) => {
|
|
469
|
+
return getSelectedItem(item, colIndex, selectList.value)[props.labelKey];
|
|
470
|
+
});
|
|
471
|
+
callback();
|
|
472
|
+
}
|
|
473
|
+
},
|
|
474
|
+
finish: (isOk?: boolean) => {
|
|
475
|
+
// 每设置展示数据回显
|
|
476
|
+
if (typeof callback === 'function') {
|
|
477
|
+
loading.value = false;
|
|
478
|
+
isCompleting.value = false;
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
if (isBoolean(isOk) && !isOk) {
|
|
482
|
+
loading.value = false;
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
if (beforeConfirm) {
|
|
487
|
+
beforeConfirm(
|
|
488
|
+
pickerColSelected.value,
|
|
489
|
+
pickerColSelected.value.map((item, colIndex) => {
|
|
490
|
+
return getSelectedItem(item, colIndex, selectList.value);
|
|
491
|
+
}),
|
|
492
|
+
(isPass: boolean) => {
|
|
493
|
+
if (isPass) {
|
|
494
|
+
onConfirm();
|
|
495
|
+
} else {
|
|
496
|
+
loading.value = false;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
);
|
|
500
|
+
} else {
|
|
501
|
+
onConfirm();
|
|
502
|
+
}
|
|
503
|
+
},
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
function onConfirm() {
|
|
507
|
+
isChange.value = false;
|
|
508
|
+
loading.value = false;
|
|
509
|
+
pickerShow.value = false;
|
|
510
|
+
|
|
511
|
+
emit('update:modelValue', pickerColSelected.value);
|
|
512
|
+
emit('confirm', {
|
|
513
|
+
value: pickerColSelected.value,
|
|
514
|
+
selectedItems: pickerColSelected.value.map((item, colIndex) => {
|
|
515
|
+
return getSelectedItem(item, colIndex, selectList.value);
|
|
516
|
+
}),
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
function handleColClick(index: number) {
|
|
520
|
+
isChange.value = true;
|
|
521
|
+
currentCol.value = index;
|
|
522
|
+
updateLineAndScroll(true);
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* @description 更新navBar underline的偏移量
|
|
526
|
+
* @param {Boolean} animation 是否伴随动画
|
|
527
|
+
*/
|
|
528
|
+
function setLineStyle(animation: boolean = true) {
|
|
529
|
+
if (!inited.value) return;
|
|
530
|
+
const { lineWidth, lineHeight } = props;
|
|
531
|
+
getRect($item, true, proxy)
|
|
532
|
+
.then((rects) => {
|
|
533
|
+
const lineStyle: CSSProperties = {};
|
|
534
|
+
if (isDef(lineWidth)) {
|
|
535
|
+
lineStyle.width = addUnit(lineWidth);
|
|
536
|
+
}
|
|
537
|
+
if (isDef(lineHeight)) {
|
|
538
|
+
lineStyle.height = addUnit(lineHeight);
|
|
539
|
+
lineStyle.borderRadius = `calc(${addUnit(lineHeight)} / 2)`;
|
|
540
|
+
}
|
|
541
|
+
const rect = rects[currentCol.value];
|
|
542
|
+
const left =
|
|
543
|
+
rects.slice(0, currentCol.value).reduce((prev, curr) => prev + Number(curr.width), 0) +
|
|
544
|
+
Number(rect.width) / 2;
|
|
545
|
+
lineStyle.transform = `translateX(${left}px) translateX(-50%)`;
|
|
546
|
+
|
|
547
|
+
if (animation) {
|
|
548
|
+
lineStyle.transition = 'width 300ms ease, transform 300ms ease';
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
state.lineStyle = objToStyle(lineStyle);
|
|
552
|
+
})
|
|
553
|
+
.catch(() => {});
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* @description scroll-view滑动到active的tab_nav
|
|
557
|
+
*/
|
|
558
|
+
function lineScrollIntoView() {
|
|
559
|
+
if (!inited.value) return;
|
|
560
|
+
Promise.all([getRect($item, true, proxy), getRect($container, false, proxy)])
|
|
561
|
+
.then(([navItemsRects, navRect]) => {
|
|
562
|
+
if (!isArray(navItemsRects) || navItemsRects.length === 0) return;
|
|
563
|
+
// 选中元素
|
|
564
|
+
const selectItem = navItemsRects[currentCol.value];
|
|
565
|
+
// 选中元素之前的节点的宽度总和
|
|
566
|
+
const offsetLeft = navItemsRects
|
|
567
|
+
.slice(0, currentCol.value)
|
|
568
|
+
.reduce((prev, curr) => prev + Number(curr.width), 0);
|
|
569
|
+
// scroll-view滑动到selectItem的偏移量
|
|
570
|
+
scrollLeft.value = offsetLeft - ((navRect as any).width - Number(selectItem.width)) / 2;
|
|
571
|
+
})
|
|
572
|
+
.catch(() => {});
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// 递归列数据补齐
|
|
576
|
+
function diffColumns(colIndex: number) {
|
|
577
|
+
// colIndex 为 -1 时,item 为空对象,>=0 时则具有 value 属性
|
|
578
|
+
const item = colIndex === -1 ? {} : { [props.valueKey]: props.modelValue[colIndex] };
|
|
579
|
+
handleColChange(colIndex, item, -1, () => {
|
|
580
|
+
// 如果 columns 长度还小于 value 长度,colIndex + 1,继续递归补齐
|
|
581
|
+
if (selectList.value.length < props.modelValue.length) {
|
|
582
|
+
diffColumns(colIndex + 1);
|
|
583
|
+
}
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
function handleAutoComplete() {
|
|
587
|
+
if (props.autoComplete) {
|
|
588
|
+
// 如果 columns 数组长度为空,或者长度小于 value 的长度,自动触发 columnChange 来补齐数据
|
|
589
|
+
if (selectList.value.length < props.modelValue.length || selectList.value.length === 0) {
|
|
590
|
+
// isCompleting 是否在自动补全,锁操作
|
|
591
|
+
if (!isCompleting.value) {
|
|
592
|
+
// 如果 columns 长度为空,则传入的 colIndex 为 -1
|
|
593
|
+
const colIndex = selectList.value.length === 0 ? -1 : selectList.value.length - 1;
|
|
594
|
+
diffColumns(colIndex);
|
|
595
|
+
}
|
|
596
|
+
isCompleting.value = true;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
defineExpose<ColPickerExpose>({
|
|
602
|
+
close,
|
|
603
|
+
open,
|
|
604
|
+
});
|
|
605
|
+
</script>
|
|
606
|
+
|
|
607
|
+
<style lang="scss" scoped>
|
|
608
|
+
@import 'wot-design-uni/components/wd-col-picker/index.scss';
|
|
609
|
+
</style>
|
|
File without changes
|