@neatui/vue 2.11.0 → 2.15.0
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 +1 -1
- package/src/components/basic/LayerView/Layer.vue +0 -16
- package/src/components/display/Calendar.vue +14 -14
- package/src/components/display/CalendarReg.vue +14 -14
- package/src/components/display/Tree.vue +6 -6
- package/src/components/form/Cascader.vue +20 -20
- package/src/components/form/DatePicker.vue +8 -9
- package/src/components/form/DateRangePicker@v3.vue +5 -5
- package/src/components/form/DateRangeView@v3.vue +9 -9
- package/src/components/form/DateView.vue +14 -14
- package/src/components/form/DateView@v2.vue +14 -14
- package/src/components/form/DateView@v3.vue +17 -15
- package/src/components/form/Input@v3.vue +7 -7
- package/src/components/form/MoreSelect@v3.vue +85 -15
- package/src/components/form/MoreSelectList.vue +1 -1
- package/src/components/form/MoreSelectPanel@v3.vue +4 -4
- package/src/components/form/MoreSelectPicker.vue +1 -1
- package/src/components/form/MoreSelectTags.vue +1 -1
- package/src/components/form/PageMoreSelect.vue +15 -15
- package/src/components/form/PageSelect.vue +17 -17
- package/src/components/form/SearchMoreSelect.vue +1 -1
- package/src/components/form/SearchSelect@v3.vue +4 -4
- package/src/components/form/Select@v3.vue +227 -20
- package/src/components/form/SelectList.vue +8 -8
- package/src/components/form/SelectPicker.vue +7 -7
- package/src/components/form/SelectTags.vue +7 -7
- package/src/components/form/SelectTree/SelectTree@v1.vue +6 -6
- package/src/components/form/Switch.vue +33 -58
- package/src/components/form/Textarea@v2.vue +275 -0
- package/src/components/form/TimeView.vue +14 -14
- package/src/components/form/Upload.vue +52 -9
- package/src/components/form/date.ts +321 -0
- package/src/components/form/index.ts +2 -2
- package/src/components/form/number.ts +3 -0
- package/src/components/form/type.ts +224 -0
- package/src/components/loader/FormLoader/FormLoader@v2.vue +20 -20
- package/src/components/loader/FormLoader/FormLoader@v3.vue.backup +372 -291
- package/src/components/loader/FormLoader/FormRender@v3.vue.backup +4 -0
- package/src/components/loader/FormLoader/NodeLoader.vue +85 -0
- package/src/components/loader/FormLoader@v1/FormLoader.vue +1 -1
- package/src/components/loader/FormLoader@v1/FormRender.vue +49 -24
- package/src/components/loader/LayerLoader/LayerLoader.vue +1 -1
- package/src/components/loader/LimitLoader/LimitLoader@v3.vue +1 -1
- package/src/components/loader/MoveLoader/MoveLoader.vue +8 -8
- package/src/components/loader/TableLoader/TableRender.vue +1 -1
- package/src/components/loader/index.ts +1 -1
- package/src/components/tools/Pagination@a.vue +1 -1
- package/tsconfig.json +1 -1
- package/src/components/loader/FormLoader/index.ts +0 -2
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
|
|
43
43
|
<script setup lang="ts">
|
|
44
44
|
import { reactive, ref, computed, watch } from 'vue';
|
|
45
|
-
import { Input } from '
|
|
45
|
+
import { Input } from '.';
|
|
46
46
|
import { IFollowView } from '../basic';
|
|
47
47
|
|
|
48
48
|
const ifollow: any = ref(null);
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
// 用户是否交互
|
|
52
52
|
interacted: {
|
|
53
53
|
type: Boolean,
|
|
54
|
-
default: false
|
|
54
|
+
default: false,
|
|
55
55
|
},
|
|
56
56
|
theme: { type: String, default: '@a' },
|
|
57
57
|
sz: { type: String, default: 'm' },
|
|
@@ -60,51 +60,51 @@
|
|
|
60
60
|
// 提示文案
|
|
61
61
|
tips: {
|
|
62
62
|
type: String,
|
|
63
|
-
default: ''
|
|
63
|
+
default: '',
|
|
64
64
|
},
|
|
65
65
|
placeholder: {
|
|
66
66
|
type: String,
|
|
67
|
-
default: ''
|
|
67
|
+
default: '',
|
|
68
68
|
},
|
|
69
69
|
options: {
|
|
70
70
|
type: Array as () => any[],
|
|
71
|
-
default: () => []
|
|
71
|
+
default: () => [],
|
|
72
72
|
},
|
|
73
73
|
ui: {
|
|
74
74
|
type: Object,
|
|
75
|
-
default: () => ({ sz: 'm' })
|
|
75
|
+
default: () => ({ sz: 'm' }),
|
|
76
76
|
},
|
|
77
77
|
modelValue: {
|
|
78
78
|
type: [String, Number],
|
|
79
|
-
default: ''
|
|
79
|
+
default: '',
|
|
80
80
|
},
|
|
81
81
|
// 校验规则
|
|
82
82
|
rules: {
|
|
83
83
|
type: Array,
|
|
84
|
-
default: () => []
|
|
84
|
+
default: () => [],
|
|
85
85
|
},
|
|
86
86
|
// 是否是示校验图标
|
|
87
87
|
verify: {
|
|
88
88
|
type: Boolean,
|
|
89
|
-
default: false
|
|
89
|
+
default: false,
|
|
90
90
|
},
|
|
91
91
|
tools: {
|
|
92
92
|
type: Boolean,
|
|
93
|
-
default: true
|
|
93
|
+
default: true,
|
|
94
94
|
},
|
|
95
95
|
spare: {
|
|
96
96
|
type: String,
|
|
97
|
-
default: '当前没有可选项'
|
|
97
|
+
default: '当前没有可选项',
|
|
98
98
|
},
|
|
99
99
|
// 分页
|
|
100
100
|
pageInfo: {
|
|
101
101
|
type: Object,
|
|
102
|
-
default: () => ({ total: 0, pages: 0, page: 0 })
|
|
102
|
+
default: () => ({ total: 0, pages: 0, page: 0 }),
|
|
103
103
|
},
|
|
104
104
|
filterable: {
|
|
105
105
|
type: Boolean,
|
|
106
|
-
default: false
|
|
107
|
-
}
|
|
106
|
+
default: false,
|
|
107
|
+
},
|
|
108
108
|
});
|
|
109
109
|
|
|
110
110
|
const emit = defineEmits(['update:modelValue', 'pageChange', 'searchChange']);
|
|
@@ -126,7 +126,7 @@
|
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
return _value;
|
|
129
|
-
})
|
|
129
|
+
}),
|
|
130
130
|
/* filter: computed(() => {
|
|
131
131
|
if (state.search) {
|
|
132
132
|
return props.options?.filter((item) => {
|
|
@@ -170,14 +170,14 @@
|
|
|
170
170
|
() => {
|
|
171
171
|
change({});
|
|
172
172
|
emit('searchChange', state.search);
|
|
173
|
-
}
|
|
173
|
+
},
|
|
174
174
|
);
|
|
175
175
|
|
|
176
176
|
defineExpose({
|
|
177
177
|
select,
|
|
178
178
|
remove,
|
|
179
179
|
change,
|
|
180
|
-
cancel
|
|
180
|
+
cancel,
|
|
181
181
|
});
|
|
182
182
|
</script>
|
|
183
183
|
<style lang="scss" scoped>
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
|
|
49
49
|
<script setup lang="ts">
|
|
50
50
|
import { reactive, ref, computed } from 'vue';
|
|
51
|
-
import { Input } from '
|
|
51
|
+
import { Input } from '.';
|
|
52
52
|
import { IFollowView } from '../basic';
|
|
53
53
|
const ifollow: any = ref(null);
|
|
54
54
|
console.warn('「SearchSelect」 即将废弃,建议使用「Select」 设置参数search为true,示例:<Select v-model="value" :search="true" />');
|
|
@@ -144,7 +144,7 @@
|
|
|
144
144
|
verify: false,
|
|
145
145
|
prefix: () => [],
|
|
146
146
|
suffix: () => [],
|
|
147
|
-
interacted: false
|
|
147
|
+
interacted: false,
|
|
148
148
|
});
|
|
149
149
|
|
|
150
150
|
const change = ({ value = '' }: any = {}) => {
|
|
@@ -166,7 +166,7 @@
|
|
|
166
166
|
} else {
|
|
167
167
|
return props.options;
|
|
168
168
|
}
|
|
169
|
-
})
|
|
169
|
+
}),
|
|
170
170
|
});
|
|
171
171
|
// 选择
|
|
172
172
|
const select = (item: any = {}) => {
|
|
@@ -196,7 +196,7 @@
|
|
|
196
196
|
select,
|
|
197
197
|
remove,
|
|
198
198
|
change,
|
|
199
|
-
cancel
|
|
199
|
+
cancel,
|
|
200
200
|
});
|
|
201
201
|
</script>
|
|
202
202
|
. .
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div :ui-form="`@a type:select sz
|
|
2
|
+
<div :ui-form="`@a type:select${sz ? 'sz:' + sz : ''}`" :ui-form-open="state.show ? 'show' : ''">
|
|
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
|
-
<template #suffix
|
|
9
|
+
<template #suffix>
|
|
10
|
+
<i v-if="clearable && modelValue && !readonly && !disabled" ui-form-clean="" @click.stop="remove"></i>
|
|
11
|
+
<i ui-form-select=""></i>
|
|
12
|
+
</template>
|
|
10
13
|
</Input>
|
|
11
14
|
<template #tips v-if="!readonly && !disabled">
|
|
12
15
|
<div v-if="search" class="ny-sm nx-sl">
|
|
@@ -16,23 +19,39 @@
|
|
|
16
19
|
</template>
|
|
17
20
|
</Input>
|
|
18
21
|
</div>
|
|
19
|
-
<ul v-if="
|
|
22
|
+
<ul v-if="state.filter?.length" ui-scroll=":y s" class="nx-sm lh-sl" style="min-width: 100%; max-height: 16em">
|
|
20
23
|
<template v-for="(item, idx) of state.filter" :key="idx">
|
|
21
|
-
<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' : ''">
|
|
22
25
|
<del>{{ item.label || item }}</del>
|
|
23
26
|
</li>
|
|
24
|
-
<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)">
|
|
25
28
|
<span>{{ item.label || item }}</span>
|
|
26
29
|
</li>
|
|
27
30
|
</template>
|
|
28
31
|
</ul>
|
|
29
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
|
+
|
|
30
49
|
<ul class="nx-sm lh-ml" v-if="tools">
|
|
31
50
|
<li class="my-ss"><div class="o-mm" ui-line="@a"></div></li>
|
|
32
51
|
<li ui-flex="row xm">
|
|
33
52
|
<div class="co-main">
|
|
34
53
|
<p class="nx-sm r-ss nowrap">
|
|
35
|
-
<span>{{ state.
|
|
54
|
+
<span>{{ state.availableCount }}个可选项</span>
|
|
36
55
|
</p>
|
|
37
56
|
</div>
|
|
38
57
|
<div>
|
|
@@ -46,12 +65,14 @@
|
|
|
46
65
|
</template>
|
|
47
66
|
|
|
48
67
|
<script setup lang="ts">
|
|
49
|
-
import { reactive, ref, computed } from 'vue';
|
|
50
|
-
import { Input } from '
|
|
68
|
+
import { reactive, ref, computed, watch, nextTick } from 'vue';
|
|
69
|
+
import { Input } from '.';
|
|
51
70
|
import { IFollowView } from '../basic';
|
|
52
71
|
const ifollow: any = ref(null);
|
|
72
|
+
const customInputRef: any = ref(null);
|
|
73
|
+
|
|
74
|
+
const emits = defineEmits(['update:modelValue', 'change', 'onshow', 'onhide', 'update:other']);
|
|
53
75
|
|
|
54
|
-
const emits = defineEmits(['update:modelValue', 'change', 'onshow', 'onhide']);
|
|
55
76
|
|
|
56
77
|
/**
|
|
57
78
|
* 入参说明
|
|
@@ -86,8 +107,15 @@
|
|
|
86
107
|
|
|
87
108
|
// 类型
|
|
88
109
|
interface Props {
|
|
89
|
-
modelValue?: string | number;
|
|
110
|
+
modelValue?: string | number | null;
|
|
90
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;
|
|
91
119
|
tools?: boolean;
|
|
92
120
|
spare?: string;
|
|
93
121
|
search?: boolean;
|
|
@@ -119,6 +147,9 @@
|
|
|
119
147
|
const props: any = withDefaults(defineProps<Props>(), {
|
|
120
148
|
modelValue: '',
|
|
121
149
|
options: () => [],
|
|
150
|
+
all: undefined,
|
|
151
|
+
other: undefined,
|
|
152
|
+
otherValue: '',
|
|
122
153
|
tools: false,
|
|
123
154
|
spare: '当前没有可选项',
|
|
124
155
|
search: false,
|
|
@@ -139,42 +170,218 @@
|
|
|
139
170
|
minlength: null,
|
|
140
171
|
disabled: false,
|
|
141
172
|
readonly: false,
|
|
142
|
-
clearable:
|
|
173
|
+
clearable: true,
|
|
143
174
|
verify: false,
|
|
144
175
|
prefix: () => [],
|
|
145
176
|
suffix: () => [],
|
|
146
177
|
interacted: false,
|
|
147
178
|
});
|
|
148
179
|
|
|
149
|
-
const change = (
|
|
180
|
+
const change = (value: any = null) => {
|
|
150
181
|
emits('update:modelValue', value);
|
|
151
182
|
emits('change', value);
|
|
152
183
|
};
|
|
153
184
|
|
|
185
|
+
// 自定义输入值
|
|
186
|
+
const customInputValue = ref('');
|
|
187
|
+
|
|
154
188
|
const state = reactive({
|
|
155
189
|
show: 0,
|
|
156
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
|
+
}),
|
|
157
207
|
selectd: computed(() => {
|
|
158
|
-
|
|
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;
|
|
159
244
|
}),
|
|
160
245
|
filter: computed(() => {
|
|
246
|
+
let filteredOptions = props.options || [];
|
|
247
|
+
|
|
161
248
|
if (state.search) {
|
|
162
|
-
|
|
249
|
+
filteredOptions = filteredOptions.filter((item: any) => {
|
|
163
250
|
return item.label?.includes(state.search);
|
|
164
251
|
});
|
|
165
|
-
} else {
|
|
166
|
-
return props.options;
|
|
167
252
|
}
|
|
253
|
+
|
|
254
|
+
// 在顶部添加全部选项
|
|
255
|
+
if (props.all) {
|
|
256
|
+
filteredOptions = [props.all, ...filteredOptions];
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return filteredOptions;
|
|
168
260
|
}),
|
|
169
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
|
+
|
|
170
318
|
// 选择
|
|
171
319
|
const select = (item: any = {}) => {
|
|
172
|
-
|
|
173
|
-
|
|
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;
|
|
174
381
|
};
|
|
175
382
|
// 清空
|
|
176
383
|
const remove = () => {
|
|
177
|
-
change(
|
|
384
|
+
change(null);
|
|
178
385
|
ifollow.value.cancel();
|
|
179
386
|
};
|
|
180
387
|
// 取消
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<ul v-if="props.options?.length" class="my-sm-sub lh-ss">
|
|
3
3
|
<li
|
|
4
|
-
class="hover:bg-main-ss n-sl r-ss b-solid b-xs"
|
|
5
|
-
:class="`${item.value === mv ? 'bk-main-ml bg-main-ss' : 'bk-case'}`"
|
|
4
|
+
class="hover:bg-main-o-ss n-sl r-ss b-solid b-xs"
|
|
5
|
+
:class="`${item.value === mv ? 'bk-main-o-ml bg-main-o-ss' : 'bk-case'}`"
|
|
6
6
|
v-for="(item, idx) of props.options"
|
|
7
7
|
:key="idx"
|
|
8
8
|
@click="mv = item.value === mv ? '' : item.value"
|
|
@@ -27,16 +27,16 @@
|
|
|
27
27
|
placeholder: { type: String, default: '' },
|
|
28
28
|
options: {
|
|
29
29
|
type: Array as () => any[],
|
|
30
|
-
default: () => []
|
|
30
|
+
default: () => [],
|
|
31
31
|
},
|
|
32
32
|
modelValue: {
|
|
33
33
|
type: [String, Number],
|
|
34
|
-
default: ''
|
|
34
|
+
default: '',
|
|
35
35
|
},
|
|
36
36
|
rules: {
|
|
37
37
|
type: Array,
|
|
38
|
-
default: () => []
|
|
39
|
-
}
|
|
38
|
+
default: () => [],
|
|
39
|
+
},
|
|
40
40
|
});
|
|
41
41
|
|
|
42
42
|
// eslint-disable-next-line vue/no-dupe-keys
|
|
@@ -47,12 +47,12 @@
|
|
|
47
47
|
() => props.modelValue,
|
|
48
48
|
(value: any) => {
|
|
49
49
|
mv.value = value;
|
|
50
|
-
}
|
|
50
|
+
},
|
|
51
51
|
);
|
|
52
52
|
watch(
|
|
53
53
|
() => mv.value,
|
|
54
54
|
(value: any) => {
|
|
55
55
|
emits('update:modelValue', value);
|
|
56
|
-
}
|
|
56
|
+
},
|
|
57
57
|
);
|
|
58
58
|
</script>
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
|
|
30
30
|
<script setup lang="ts">
|
|
31
31
|
import { reactive, ref, computed } from 'vue';
|
|
32
|
-
import { Input } from '
|
|
32
|
+
import { Input } from '.';
|
|
33
33
|
import { IPickerView, IScrollView } from '../basic';
|
|
34
34
|
import { watch } from 'vue';
|
|
35
35
|
const ipicker: any = ref(null);
|
|
@@ -43,16 +43,16 @@
|
|
|
43
43
|
placeholder: { type: String, default: '' },
|
|
44
44
|
options: {
|
|
45
45
|
type: Array as () => any[],
|
|
46
|
-
default: () => []
|
|
46
|
+
default: () => [],
|
|
47
47
|
},
|
|
48
48
|
modelValue: {
|
|
49
49
|
type: [String, Number],
|
|
50
|
-
default: ''
|
|
50
|
+
default: '',
|
|
51
51
|
},
|
|
52
52
|
rules: {
|
|
53
53
|
type: Array,
|
|
54
|
-
default: () => []
|
|
55
|
-
}
|
|
54
|
+
default: () => [],
|
|
55
|
+
},
|
|
56
56
|
});
|
|
57
57
|
// 内部数据
|
|
58
58
|
const mv: any = ref(props.modelValue);
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
(v: any) => {
|
|
62
62
|
mv.value = v;
|
|
63
63
|
},
|
|
64
|
-
{ deep: true, immediate: true }
|
|
64
|
+
{ deep: true, immediate: true },
|
|
65
65
|
);
|
|
66
66
|
const state = reactive({
|
|
67
67
|
view: 0,
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
return _value;
|
|
77
|
-
})
|
|
77
|
+
}),
|
|
78
78
|
});
|
|
79
79
|
// 更新
|
|
80
80
|
const change = ({ value = null }: any = {}) => {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<div v-if="props.options?.length" class="mr-sm-sub mb-sm-sub">
|
|
3
3
|
<span
|
|
4
4
|
class="lh-ss ny-sm nx-ms r-xl dib"
|
|
5
|
-
:class="`${mv == item.value ? 'bg-main-sm co-main' : 'bg-weak'}`"
|
|
5
|
+
:class="`${mv == item.value ? 'bg-main-o-sm co-main' : 'bg-weak'}`"
|
|
6
6
|
v-for="(item, idx) of props.options"
|
|
7
7
|
:key="idx"
|
|
8
8
|
@click="mv = item.value === mv ? '' : item.value"
|
|
@@ -24,16 +24,16 @@
|
|
|
24
24
|
placeholder: { type: String, default: '' },
|
|
25
25
|
options: {
|
|
26
26
|
type: Array as () => any[],
|
|
27
|
-
default: () => []
|
|
27
|
+
default: () => [],
|
|
28
28
|
},
|
|
29
29
|
modelValue: {
|
|
30
30
|
type: [String, Number],
|
|
31
|
-
default: ''
|
|
31
|
+
default: '',
|
|
32
32
|
},
|
|
33
33
|
rules: {
|
|
34
34
|
type: Array,
|
|
35
|
-
default: () => []
|
|
36
|
-
}
|
|
35
|
+
default: () => [],
|
|
36
|
+
},
|
|
37
37
|
});
|
|
38
38
|
// 内部数据
|
|
39
39
|
const mv: any = ref(props.modelValue);
|
|
@@ -41,12 +41,12 @@
|
|
|
41
41
|
() => props.modelValue,
|
|
42
42
|
(value: any) => {
|
|
43
43
|
mv.value = value;
|
|
44
|
-
}
|
|
44
|
+
},
|
|
45
45
|
);
|
|
46
46
|
watch(
|
|
47
47
|
() => mv.value,
|
|
48
48
|
(value: any) => {
|
|
49
49
|
emits('update:modelValue', value);
|
|
50
|
-
}
|
|
50
|
+
},
|
|
51
51
|
);
|
|
52
52
|
</script>
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
|
|
41
41
|
<script setup lang="ts">
|
|
42
42
|
import { reactive, ref, computed, watch } from 'vue';
|
|
43
|
-
import { Input } from '
|
|
43
|
+
import { Input } from '..';
|
|
44
44
|
import { IFollowView } from '../../basic';
|
|
45
45
|
import { TreeView } from '../../display';
|
|
46
46
|
import { findByJson, filterJson } from '@fekit/utils';
|
|
@@ -144,7 +144,7 @@
|
|
|
144
144
|
verify: false,
|
|
145
145
|
prefix: () => [],
|
|
146
146
|
suffix: () => [],
|
|
147
|
-
interacted: false
|
|
147
|
+
interacted: false,
|
|
148
148
|
});
|
|
149
149
|
|
|
150
150
|
const state: any = reactive({
|
|
@@ -158,7 +158,7 @@
|
|
|
158
158
|
return (props.chain ? _item.chain : _item.label) || '';
|
|
159
159
|
}),
|
|
160
160
|
filter: [],
|
|
161
|
-
value: ''
|
|
161
|
+
value: '',
|
|
162
162
|
});
|
|
163
163
|
watch(
|
|
164
164
|
() => state.value,
|
|
@@ -167,7 +167,7 @@
|
|
|
167
167
|
change(value);
|
|
168
168
|
}
|
|
169
169
|
},
|
|
170
|
-
{ deep: true }
|
|
170
|
+
{ deep: true },
|
|
171
171
|
);
|
|
172
172
|
watch(
|
|
173
173
|
[() => state.search, () => props.options],
|
|
@@ -178,7 +178,7 @@
|
|
|
178
178
|
state.filter = props.options;
|
|
179
179
|
}
|
|
180
180
|
},
|
|
181
|
-
{ deep: true, immediate: true }
|
|
181
|
+
{ deep: true, immediate: true },
|
|
182
182
|
);
|
|
183
183
|
|
|
184
184
|
const change = (value: any = '') => {
|
|
@@ -221,7 +221,7 @@
|
|
|
221
221
|
select,
|
|
222
222
|
remove,
|
|
223
223
|
change,
|
|
224
|
-
cancel
|
|
224
|
+
cancel,
|
|
225
225
|
});
|
|
226
226
|
</script>
|
|
227
227
|
.. ..
|