@neatui/vue 2.12.0 → 2.15.1
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neatui/vue",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.15.1",
|
|
4
4
|
"description": "basic component ui",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"license": "MIT",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"@fekit/scale": "^2.0.1",
|
|
28
28
|
"@fekit/scrollto": "^3.0.3",
|
|
29
29
|
"@fekit/toast": "^2.7.2",
|
|
30
|
-
"@fekit/utils": "^3.
|
|
30
|
+
"@fekit/utils": "^4.3.0",
|
|
31
31
|
"@rollup/plugin-commonjs": "^26.0.1",
|
|
32
32
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
33
33
|
"@vue/compiler-sfc": "^3.4.30",
|
|
@@ -230,11 +230,11 @@
|
|
|
230
230
|
e.target.value = props.modelValue;
|
|
231
231
|
return false;
|
|
232
232
|
}
|
|
233
|
-
// 数字类型
|
|
234
|
-
if (props.type === 'number' && !value && props.modelValue?.length !== 1) {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
}
|
|
233
|
+
// 数字类型 - 移除有问题的逻辑,允许用户正常删除数字
|
|
234
|
+
// if (props.type === 'number' && !value && props.modelValue?.length !== 1) {
|
|
235
|
+
// e.target.value = props.modelValue;
|
|
236
|
+
// return false;
|
|
237
|
+
// }
|
|
238
238
|
// 输入事件
|
|
239
239
|
emits('input', e, state);
|
|
240
240
|
emits('update:modelValue', value || null);
|
|
@@ -24,13 +24,13 @@
|
|
|
24
24
|
<template v-for="(item, idx) of state.filter" :key="idx">
|
|
25
25
|
<li v-if="item.disabled" class="ux-hover nx-sm r-ss o-ms nowrap">
|
|
26
26
|
<label style="pointer-events: none" ui-form="@a type:checkbox :block">
|
|
27
|
-
<input type="checkbox" :name="state.name" :checked="
|
|
27
|
+
<input type="checkbox" :name="state.name" :checked="state.processedValue?.some((i: any) => `${i}` === `${item.value}`)" />
|
|
28
28
|
<del class="ml-sm">{{ item.label || item }}</del>
|
|
29
29
|
</label>
|
|
30
30
|
</li>
|
|
31
31
|
<li v-else class="ux-hover nx-sm r-ss nowrap" @click.stop="select(item.value)">
|
|
32
32
|
<label style="pointer-events: none" ui-form="@a type:checkbox :block">
|
|
33
|
-
<input type="checkbox" :name="state.name" :checked="
|
|
33
|
+
<input type="checkbox" :name="state.name" :checked="state.processedValue?.some((i: any) => `${i}` === `${item.value}`)" />
|
|
34
34
|
<span class="ml-sm">{{ item.label || item }}</span>
|
|
35
35
|
</label>
|
|
36
36
|
</li>
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
<div class="ux-hover nx-sm ny-ss r-ss nowrap co-main" @click.stop="allselect()">
|
|
44
44
|
<label style="pointer-events: none" ui-form="@a type:checkbox :block">
|
|
45
45
|
<input type="checkbox" :name="state.name" :checked="state.all" />
|
|
46
|
-
<span class="ml-sm">全选({{ state.
|
|
46
|
+
<span class="ml-sm">全选({{ state.selectedCount }}/{{ state.availableCount }})</span>
|
|
47
47
|
</label>
|
|
48
48
|
</div>
|
|
49
49
|
<div>
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
</template>
|
|
58
58
|
|
|
59
59
|
<script setup lang="ts">
|
|
60
|
-
import { reactive, ref, computed, watch } from 'vue';
|
|
60
|
+
import { reactive, ref, computed, watch, nextTick } from 'vue';
|
|
61
61
|
import { Input } from '.';
|
|
62
62
|
import { IFollowView } from '../basic';
|
|
63
63
|
const ifollow: any = ref(null);
|
|
@@ -96,7 +96,7 @@
|
|
|
96
96
|
|
|
97
97
|
// 类型
|
|
98
98
|
interface Props {
|
|
99
|
-
modelValue?: Array<string | number
|
|
99
|
+
modelValue?: Array<string | number> | string;
|
|
100
100
|
options: Array<object>;
|
|
101
101
|
tools?: boolean;
|
|
102
102
|
spare?: string;
|
|
@@ -158,11 +158,21 @@
|
|
|
158
158
|
show: 0,
|
|
159
159
|
value: '',
|
|
160
160
|
search: '',
|
|
161
|
+
originalType: 'array',
|
|
162
|
+
processedValue: computed(() => processInput(props.modelValue)),
|
|
161
163
|
all: computed(() => {
|
|
162
|
-
|
|
164
|
+
const availableItems = state.filter?.filter((item: any) => !item.disabled);
|
|
165
|
+
return availableItems?.length > 0 && availableItems?.every((item: any) => state.processedValue?.some((i: any) => `${i}` === `${item.value}`));
|
|
163
166
|
}),
|
|
164
167
|
has: computed(() => {
|
|
165
|
-
return state.filter?.some((item: any) =>
|
|
168
|
+
return state.filter?.some((item: any) => state.processedValue?.some((i: any) => `${i}` === `${item.value}`));
|
|
169
|
+
}),
|
|
170
|
+
availableCount: computed(() => {
|
|
171
|
+
return state.filter?.filter((item: any) => !item.disabled)?.length || 0;
|
|
172
|
+
}),
|
|
173
|
+
selectedCount: computed(() => {
|
|
174
|
+
const availableItems = state.filter?.filter((item: any) => !item.disabled);
|
|
175
|
+
return availableItems?.filter((item: any) => state.processedValue?.some((i: any) => `${i}` === `${item.value}`))?.length || 0;
|
|
166
176
|
}),
|
|
167
177
|
filter: computed(() => {
|
|
168
178
|
if (state.search) {
|
|
@@ -175,23 +185,62 @@
|
|
|
175
185
|
}),
|
|
176
186
|
});
|
|
177
187
|
|
|
188
|
+
// 处理输入数据类型转换和过滤
|
|
189
|
+
const processInput = (value: any) => {
|
|
190
|
+
let processedArray: any[] = [];
|
|
191
|
+
|
|
192
|
+
if (typeof value === 'string') {
|
|
193
|
+
state.originalType = 'string';
|
|
194
|
+
processedArray = value.trim() ? (value.includes(',') ? value.split(',').map((s: string) => s.trim()) : [value]) : [];
|
|
195
|
+
} else {
|
|
196
|
+
state.originalType = 'array';
|
|
197
|
+
processedArray = value || [];
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// 过滤掉在options中不存在的值
|
|
201
|
+
const validValues = processedArray.filter((val: any) =>
|
|
202
|
+
props.options?.some((option: any) => `${option.value}` === `${val}`)
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
return validValues;
|
|
206
|
+
};
|
|
207
|
+
|
|
178
208
|
// 监听外部数据
|
|
179
209
|
watch(
|
|
180
210
|
[() => props.modelValue, () => props.options],
|
|
181
211
|
([v = [], o = []]: any = []) => {
|
|
182
|
-
const
|
|
212
|
+
const processedValue = processInput(v);
|
|
213
|
+
|
|
214
|
+
// 如果过滤后的值与原始值不同,需要更新modelValue
|
|
215
|
+
const originalProcessedValue = v ? (typeof v === 'string' ?
|
|
216
|
+
(v.trim() ? (v.includes(',') ? v.split(',').map((s: string) => s.trim()) : [v]) : []) :
|
|
217
|
+
(v || [])) : [];
|
|
218
|
+
|
|
219
|
+
if (originalProcessedValue.length !== processedValue.length) {
|
|
220
|
+
// 异步更新以避免递归
|
|
221
|
+
nextTick(() => {
|
|
222
|
+
emits('update:modelValue', convertOutput(processedValue));
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const selectd: any = o?.filter((item: any) => processedValue?.some((i: any) => `${i}` === `${item.value}`))?.map((item: any) => item.label) || [];
|
|
183
227
|
state.value = selectd?.join(' Ι ') || '';
|
|
184
228
|
},
|
|
185
229
|
{ deep: true, immediate: true },
|
|
186
230
|
);
|
|
187
231
|
|
|
232
|
+
// 输出时类型转换
|
|
233
|
+
const convertOutput = (arrayValue: any[]) => {
|
|
234
|
+
return state.originalType === 'string' ? arrayValue.join(',') : arrayValue;
|
|
235
|
+
};
|
|
236
|
+
|
|
188
237
|
// 更新
|
|
189
238
|
const change = (item: any) => {
|
|
190
|
-
emits('update:modelValue', item);
|
|
239
|
+
emits('update:modelValue', convertOutput(item));
|
|
191
240
|
};
|
|
192
241
|
// 选中
|
|
193
242
|
const select = (item: any) => {
|
|
194
|
-
const s = [...
|
|
243
|
+
const s = [...state.processedValue];
|
|
195
244
|
// s?.indexOf(item) !== -1 ? s?.splice(s?.indexOf(item), 1) : s?.push(item);
|
|
196
245
|
if (s?.indexOf(item) !== -1) {
|
|
197
246
|
s?.splice(s?.indexOf(item), 1);
|
|
@@ -202,7 +251,9 @@
|
|
|
202
251
|
};
|
|
203
252
|
// 全选
|
|
204
253
|
const allselect = () => {
|
|
205
|
-
|
|
254
|
+
// 只选择可用的选项,排除禁用项
|
|
255
|
+
const availableItems = state.filter?.filter((item: any) => !item.disabled);
|
|
256
|
+
const s = state.all ? [] : availableItems?.map((item: any) => item.value);
|
|
206
257
|
change(s);
|
|
207
258
|
};
|
|
208
259
|
// 清除
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<IFollowView ref="ifollow" tipBoxClass="ny-sm nx-no" tipBoxStyle="min-width: 100%" @onshow="onshow" @onhide="onhide">
|
|
4
4
|
<Input
|
|
5
5
|
v-bind="{ placeholder, rules, theme, sz, co, block, ready, type, tips, disabled, readonly: true, clearable: false, verify, prefix, suffix, interacted }"
|
|
6
|
-
v-model="state.
|
|
6
|
+
v-model="state.displayLabel"
|
|
7
7
|
:interacted="interacted"
|
|
8
8
|
>
|
|
9
9
|
<template #suffix>
|
|
@@ -21,21 +21,37 @@
|
|
|
21
21
|
</div>
|
|
22
22
|
<ul v-if="state.filter?.length" ui-scroll=":y s" class="nx-sm lh-sl" style="min-width: 100%; max-height: 16em">
|
|
23
23
|
<template v-for="(item, idx) of state.filter" :key="idx">
|
|
24
|
-
<li v-if="item.disabled" class="ux-hover nx-sm ny-ss r-ss o-ms nowrap" :class="item
|
|
24
|
+
<li v-if="item.disabled" class="ux-hover nx-sm ny-ss r-ss o-ms nowrap" :class="isItemSelected(item) ? 'co-main' : ''">
|
|
25
25
|
<del>{{ item.label || item }}</del>
|
|
26
26
|
</li>
|
|
27
|
-
<li v-else class="ux-hover nx-sm ny-ss r-ss nowrap" :class="item
|
|
27
|
+
<li v-else class="ux-hover nx-sm ny-ss r-ss nowrap" :class="isItemSelected(item) ? 'co-main' : ''" @click="select(item)">
|
|
28
28
|
<span>{{ item.label || item }}</span>
|
|
29
29
|
</li>
|
|
30
30
|
</template>
|
|
31
31
|
</ul>
|
|
32
32
|
<div v-else class="w-full ny-ms" ui-flex="col cm" v-html="spare"></div>
|
|
33
|
+
<!-- 其他选项输入框 -->
|
|
34
|
+
<div v-if="other && state.isInputting" class="nx-sm ny-sm">
|
|
35
|
+
<div class="o-mm" ui-line="@a"></div>
|
|
36
|
+
<div class="ny-sm">
|
|
37
|
+
<Input
|
|
38
|
+
v-model="customInputValue"
|
|
39
|
+
v-bind="other.config || {}"
|
|
40
|
+
:placeholder="other.config?.placeholder || '请输入自定义内容'"
|
|
41
|
+
sz="s"
|
|
42
|
+
@keyup.enter="confirmCustomInput"
|
|
43
|
+
@blur="confirmCustomInput"
|
|
44
|
+
ref="customInputRef"
|
|
45
|
+
/>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
33
49
|
<ul class="nx-sm lh-ml" v-if="tools">
|
|
34
50
|
<li class="my-ss"><div class="o-mm" ui-line="@a"></div></li>
|
|
35
51
|
<li ui-flex="row xm">
|
|
36
52
|
<div class="co-main">
|
|
37
53
|
<p class="nx-sm r-ss nowrap">
|
|
38
|
-
<span>{{ state.
|
|
54
|
+
<span>{{ state.availableCount }}个可选项</span>
|
|
39
55
|
</p>
|
|
40
56
|
</div>
|
|
41
57
|
<div>
|
|
@@ -49,12 +65,14 @@
|
|
|
49
65
|
</template>
|
|
50
66
|
|
|
51
67
|
<script setup lang="ts">
|
|
52
|
-
import { reactive, ref, computed } from 'vue';
|
|
68
|
+
import { reactive, ref, computed, watch, nextTick } from 'vue';
|
|
53
69
|
import { Input } from '.';
|
|
54
70
|
import { IFollowView } from '../basic';
|
|
55
71
|
const ifollow: any = ref(null);
|
|
72
|
+
const customInputRef: any = ref(null);
|
|
73
|
+
|
|
74
|
+
const emits = defineEmits(['update:modelValue', 'change', 'onshow', 'onhide', 'update:other']);
|
|
56
75
|
|
|
57
|
-
const emits = defineEmits(['update:modelValue', 'change', 'onshow', 'onhide']);
|
|
58
76
|
|
|
59
77
|
/**
|
|
60
78
|
* 入参说明
|
|
@@ -89,8 +107,15 @@
|
|
|
89
107
|
|
|
90
108
|
// 类型
|
|
91
109
|
interface Props {
|
|
92
|
-
modelValue?: string | number;
|
|
110
|
+
modelValue?: string | number | null;
|
|
93
111
|
options: Array<object>;
|
|
112
|
+
all?: { label: string; value: null | '*' };
|
|
113
|
+
other?: {
|
|
114
|
+
value: string;
|
|
115
|
+
field?: string;
|
|
116
|
+
config?: object;
|
|
117
|
+
};
|
|
118
|
+
otherValue?: string;
|
|
94
119
|
tools?: boolean;
|
|
95
120
|
spare?: string;
|
|
96
121
|
search?: boolean;
|
|
@@ -122,6 +147,9 @@
|
|
|
122
147
|
const props: any = withDefaults(defineProps<Props>(), {
|
|
123
148
|
modelValue: '',
|
|
124
149
|
options: () => [],
|
|
150
|
+
all: undefined,
|
|
151
|
+
other: undefined,
|
|
152
|
+
otherValue: '',
|
|
125
153
|
tools: false,
|
|
126
154
|
spare: '当前没有可选项',
|
|
127
155
|
search: false,
|
|
@@ -149,35 +177,211 @@
|
|
|
149
177
|
interacted: false,
|
|
150
178
|
});
|
|
151
179
|
|
|
152
|
-
const change = (
|
|
180
|
+
const change = (value: any = null) => {
|
|
153
181
|
emits('update:modelValue', value);
|
|
154
182
|
emits('change', value);
|
|
155
183
|
};
|
|
156
184
|
|
|
185
|
+
// 自定义输入值
|
|
186
|
+
const customInputValue = ref('');
|
|
187
|
+
|
|
157
188
|
const state = reactive({
|
|
158
189
|
show: 0,
|
|
159
190
|
search: '',
|
|
191
|
+
isInputting: computed(() => {
|
|
192
|
+
// 如果配置了"其他"选项且当前选中的是"其他"
|
|
193
|
+
if (props.other) {
|
|
194
|
+
if (props.other.field) {
|
|
195
|
+
// 情况2:有独立字段,当主值匹配other.value且有otherValue时显示输入框
|
|
196
|
+
return props.modelValue === props.other.value && props.otherValue;
|
|
197
|
+
} else {
|
|
198
|
+
// 情况1:无独立字段,当值不在枚举中时显示输入框
|
|
199
|
+
if (props.modelValue && props.modelValue !== '') {
|
|
200
|
+
const isInEnum = props.options?.some((option: any) => `${option.value}` === `${props.modelValue}`);
|
|
201
|
+
return !isInEnum;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return false;
|
|
206
|
+
}),
|
|
160
207
|
selectd: computed(() => {
|
|
161
|
-
|
|
208
|
+
// 优先查找 all 选项
|
|
209
|
+
if (props.all && props.modelValue === props.all.value) {
|
|
210
|
+
return props.all;
|
|
211
|
+
}
|
|
212
|
+
// 查找普通选项
|
|
213
|
+
const found = props?.options?.find((option: any) => `${option.value}` === `${props.modelValue}`);
|
|
214
|
+
if (found) {
|
|
215
|
+
// 如果是分字段存储模式且选中的是other选项,需要显示自定义值
|
|
216
|
+
if (props.other?.field && found.value === props.other.value && props.otherValue) {
|
|
217
|
+
const otherLabel = found.label || '其他';
|
|
218
|
+
return {
|
|
219
|
+
label: `${otherLabel}-${props.otherValue}`,
|
|
220
|
+
value: found.value
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
return found;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// 如果配置了 other 且当前值不在枚举中,可能是自定义输入值(直接存储模式)
|
|
227
|
+
if (props.other && props.modelValue && !props.other.field) {
|
|
228
|
+
// 找到其他选项的label
|
|
229
|
+
const otherOption = props?.options?.find((option: any) => `${option.value}` === `${props.other.value}`);
|
|
230
|
+
const otherLabel = otherOption?.label || '其他';
|
|
231
|
+
return {
|
|
232
|
+
label: `${otherLabel}-${props.modelValue}`,
|
|
233
|
+
value: props.modelValue
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return {};
|
|
238
|
+
}),
|
|
239
|
+
displayLabel: computed(() => {
|
|
240
|
+
return state.selectd.label || '';
|
|
241
|
+
}),
|
|
242
|
+
availableCount: computed(() => {
|
|
243
|
+
return state.filter?.filter((item: any) => !item.disabled)?.length || 0;
|
|
162
244
|
}),
|
|
163
245
|
filter: computed(() => {
|
|
246
|
+
let filteredOptions = props.options || [];
|
|
247
|
+
|
|
164
248
|
if (state.search) {
|
|
165
|
-
|
|
249
|
+
filteredOptions = filteredOptions.filter((item: any) => {
|
|
166
250
|
return item.label?.includes(state.search);
|
|
167
251
|
});
|
|
168
|
-
} else {
|
|
169
|
-
return props.options;
|
|
170
252
|
}
|
|
253
|
+
|
|
254
|
+
// 在顶部添加全部选项
|
|
255
|
+
if (props.all) {
|
|
256
|
+
filteredOptions = [props.all, ...filteredOptions];
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return filteredOptions;
|
|
171
260
|
}),
|
|
172
261
|
});
|
|
262
|
+
|
|
263
|
+
// 同步自定义输入值
|
|
264
|
+
watch(
|
|
265
|
+
[() => props.modelValue, () => props.otherValue, () => props.other, () => props.options],
|
|
266
|
+
() => {
|
|
267
|
+
if (props.other) {
|
|
268
|
+
if (props.other.field) {
|
|
269
|
+
// 情况2:有独立字段,显示otherValue
|
|
270
|
+
customInputValue.value = props.otherValue || '';
|
|
271
|
+
} else {
|
|
272
|
+
// 情况1:无独立字段,显示当前modelValue(如果不在枚举中)
|
|
273
|
+
if (props.modelValue && props.modelValue !== '') {
|
|
274
|
+
const isInEnum = props.options?.some((option: any) => `${option.value}` === `${props.modelValue}`);
|
|
275
|
+
customInputValue.value = !isInEnum ? props.modelValue : '';
|
|
276
|
+
} else {
|
|
277
|
+
customInputValue.value = '';
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
} else {
|
|
281
|
+
customInputValue.value = '';
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
{ immediate: true }
|
|
285
|
+
);
|
|
286
|
+
|
|
287
|
+
// 监听并验证modelValue的有效性
|
|
288
|
+
watch(
|
|
289
|
+
[() => props.modelValue, () => props.options, () => props.all, () => props.other],
|
|
290
|
+
([value, options, allOption, otherConfig]) => {
|
|
291
|
+
// 如果配置了 other,则允许任意值(可能是用户自定义输入)
|
|
292
|
+
if (otherConfig) {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// 如果有值但不在有效选项中,清空该值
|
|
297
|
+
if (value != null && value !== '' && options?.length > 0) {
|
|
298
|
+
let isValid = false;
|
|
299
|
+
|
|
300
|
+
// 检查是否是 all 选项
|
|
301
|
+
if (allOption && value === allOption.value) {
|
|
302
|
+
isValid = true;
|
|
303
|
+
} else {
|
|
304
|
+
// 检查是否在普通选项中
|
|
305
|
+
isValid = options.some((option: any) => `${option.value}` === `${value}`);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (!isValid) {
|
|
309
|
+
nextTick(() => {
|
|
310
|
+
change(null);
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
},
|
|
315
|
+
{ immediate: true }
|
|
316
|
+
);
|
|
317
|
+
|
|
173
318
|
// 选择
|
|
174
319
|
const select = (item: any = {}) => {
|
|
175
|
-
|
|
176
|
-
|
|
320
|
+
if (props.other && item.value === props.other.value) {
|
|
321
|
+
// 选中"其他"选项时,设置值并聚焦输入框
|
|
322
|
+
if (props.other.field) {
|
|
323
|
+
change(props.other.value);
|
|
324
|
+
emits('update:other', '');
|
|
325
|
+
} else {
|
|
326
|
+
change('');
|
|
327
|
+
}
|
|
328
|
+
customInputValue.value = '';
|
|
329
|
+
nextTick(() => {
|
|
330
|
+
customInputRef.value?.focus();
|
|
331
|
+
});
|
|
332
|
+
} else {
|
|
333
|
+
change(item.value);
|
|
334
|
+
ifollow.value.cancel();
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
// 确认自定义输入
|
|
339
|
+
const confirmCustomInput = () => {
|
|
340
|
+
if (customInputValue.value.trim()) {
|
|
341
|
+
if (props.other?.field) {
|
|
342
|
+
// 如果指定了 field,则主字段存储选项值,field 存储自定义输入
|
|
343
|
+
change(props.other.value);
|
|
344
|
+
emits('update:other', customInputValue.value.trim());
|
|
345
|
+
} else {
|
|
346
|
+
// 如果没有指定 field,则直接在主字段存储自定义输入
|
|
347
|
+
change(customInputValue.value.trim());
|
|
348
|
+
}
|
|
349
|
+
ifollow.value.cancel();
|
|
350
|
+
} else {
|
|
351
|
+
// 如果输入为空,清空值
|
|
352
|
+
change(null);
|
|
353
|
+
if (props.other?.field) {
|
|
354
|
+
emits('update:other', '');
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
// 判断选项是否被选中(包括"其他"选项的特殊逻辑)
|
|
360
|
+
const isItemSelected = (item: any) => {
|
|
361
|
+
// 普通选项的判断
|
|
362
|
+
if (item.value === state.selectd?.value) {
|
|
363
|
+
return true;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// "其他"选项的特殊判断
|
|
367
|
+
if (props.other && item.value === props.other.value) {
|
|
368
|
+
if (props.other.field) {
|
|
369
|
+
// 情况2:有独立字段,当主值匹配other.value时高亮
|
|
370
|
+
return props.modelValue === props.other.value;
|
|
371
|
+
} else {
|
|
372
|
+
// 情况1:无独立字段,当值不在枚举中时高亮
|
|
373
|
+
if (props.modelValue && props.modelValue !== '') {
|
|
374
|
+
const isInEnum = props.options?.some((option: any) => `${option.value}` === `${props.modelValue}`);
|
|
375
|
+
return !isInEnum;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
return false;
|
|
177
381
|
};
|
|
178
382
|
// 清空
|
|
179
383
|
const remove = () => {
|
|
180
|
-
change(
|
|
384
|
+
change(null);
|
|
181
385
|
ifollow.value.cancel();
|
|
182
386
|
};
|
|
183
387
|
// 取消
|