😎优化字典组件、下拉组件

This commit is contained in:
zuohuaijun 2025-09-14 11:38:38 +08:00
parent 0bac43bc87
commit 41b8b361cd
3 changed files with 420 additions and 380 deletions

View File

@ -99,7 +99,6 @@ watch(
() => props.data, () => props.data,
(newValue) => { (newValue) => {
state.data = newValue ?? []; state.data = newValue ?? [];
console.log(state.data);
}, },
{ immediate: true } { immediate: true }
); );

View File

@ -112,7 +112,7 @@ const props = defineProps({
*/ */
dropdownHeight: { dropdownHeight: {
type: String, type: String,
default: '400px', default: '550px',
}, },
/** /**
* 占位符 * 占位符
@ -128,6 +128,19 @@ const props = defineProps({
type: Array<any>, type: Array<any>,
default: [], default: [],
}, },
/**
* 查询表单高度偏移量
*/
queryHeightOffset: {
type: Number,
default: 35,
},
/**
* 查询表单标签宽度
*/
queryLabelWidth: {
type: String,
},
/** /**
* 查询参数 * 查询参数
*/ */
@ -341,6 +354,7 @@ defineExpose({
:remote-method="remoteMethod" :remote-method="remoteMethod"
:default-first-option="allowCreate" :default-first-option="allowCreate"
@visible-change="selectVisibleChange" @visible-change="selectVisibleChange"
:style="{ width: dropdownWidth }"
popper-class="popper-class" popper-class="popper-class"
ref="selectRef" ref="selectRef"
remote-show-suffix remote-show-suffix
@ -355,14 +369,14 @@ defineExpose({
<!-- 下拉框内容区域 --> <!-- 下拉框内容区域 -->
<div class="w100" v-loading="state.loading"> <div class="w100" v-loading="state.loading">
<el-form :model="state.tableQuery" v-if="$slots.queryForm" class="mg5 query-form" @click.stop> <el-form :model="state.tableQuery" v-if="$slots.queryForm" class="mg5 query-form" :label-width="queryLabelWidth ?? ''" @click.stop>
<el-row :gutter="10"> <el-row :gutter="10">
<!-- 查询表单插槽内容 --> <!-- 查询表单插槽内容 -->
<slot name="queryForm" :query="state.tableQuery" :handleQuery="handleQuery"></slot> <slot name="queryForm" :query="state.tableQuery" :handleQuery="handleQuery"></slot>
<!-- 查询和重置按钮 --> <!-- 查询和重置按钮 -->
<el-button-group style="position: absolute; right: 10px"> <el-button-group style="position: absolute; right: 10px">
<el-button type="primary" icon="ele-Search" @click="remoteMethod(state.tableQuery)"> 查询 </el-button> <el-button type="primary" icon="ele-Search" @click="remoteMethod(state.tableQuery)" v-reclick="1000"> 查询 </el-button>
<el-button icon="ele-Refresh" @click="resetQuery"> 重置 </el-button> <el-button icon="ele-Refresh" @click="resetQuery" v-reclick="1000"> 重置 </el-button>
</el-button-group> </el-button-group>
</el-row> </el-row>
</el-form> </el-form>
@ -372,8 +386,7 @@ defineExpose({
ref="tableRef" ref="tableRef"
@row-click="handleChange" @row-click="handleChange"
:data="state.tableData?.items ?? []" :data="state.tableData?.items ?? []"
:height="`calc(${dropdownHeight} - 175px${$slots.queryForm ? ' - 35px' : ''}${state.tableQuery[keywordProp] && allowCreate ? ' - 35px' : ''})`" :height="`calc(${dropdownHeight} - 175px${$slots.queryForm ? ` - ${queryHeightOffset}px` : ''}${state.tableQuery[keywordProp] && allowCreate ? ` - ${queryHeightOffset}px` : ''})`"
:style="{ width: dropdownWidth }"
highlight-current-row highlight-current-row
> >
<template #empty><el-empty :image-size="25" /></template> <template #empty><el-empty :image-size="25" /></template>
@ -409,4 +422,19 @@ defineExpose({
.popper-class { .popper-class {
min-width: 400px !important; min-width: 400px !important;
} }
/* 组合多个深度选择器 */
:deep(.popper-class) :deep(.el-select-dropdown__wrap) {
max-height: 600px !important;
}
</style>
<style>
.popper-class .el-select-dropdown__wrap {
max-height: 450px !important;
}
/* 或者使用属性选择器 */
.el-select-dropdown__wrap[max-height] {
max-height: 450px !important;
}
</style> </style>

View File

@ -246,6 +246,17 @@ const props = defineProps({
}, },
}); });
/**
* 组件状态
* @property {DictItem[]} dictData - 原始字典数据
* @property {any} value - 当前值
*/
const state = reactive({
dictData: [] as DictItem[],
value: props.modelValue,
conversion: false,
});
/** /**
* 格式化后的字典数据计算属性 * 格式化后的字典数据计算属性
* @computed * @computed
@ -355,6 +366,18 @@ const parseMultipleValue = (value: any): any => {
return props.multiple ? [] : value; return props.multiple ? [] : value;
} }
//
if (typeof value === 'number' && !state.conversion) {
try {
state.dictData.forEach((item) => {
if (item.value) item.value = Number(item.value);
});
state.conversion = true;
} catch (error) {
console.warn('[g-sys-dict] 数字转换失败:', error);
}
}
// //
if (typeof value === 'string') { if (typeof value === 'string') {
const trimmedValue = value.trim(); const trimmedValue = value.trim();
@ -407,7 +430,7 @@ const isItemDisabled = (itemValue: string | number, currentValue: any, mutexConf
} }
// //
if (itemValue === config.value && config.excludes.some((exclude) => selectedValues.includes(exclude))) { if (itemValue == config.value && config.excludes.some((exclude) => selectedValues.includes(exclude))) {
return true; return true;
} }
} }
@ -454,20 +477,20 @@ const updateValue = (newValue: any) => {
let emitValue = processedValue; let emitValue = processedValue;
if (props.multipleModel === MultipleModel.Comma) { if (props.multipleModel === MultipleModel.Comma) {
if (Array.isArray(processedValue)) { if (Array.isArray(processedValue)) {
emitValue = processedValue.length > 0 ? processedValue.sort().join(',') : undefined; emitValue = processedValue.length > 0 ? processedValue.sort().join(',') : [];
} else if (processedValue === null || processedValue === undefined) { } else if (processedValue === null || processedValue === undefined) {
emitValue = undefined; emitValue = undefined;
} }
} else { } else {
if (Array.isArray(processedValue)) { if (Array.isArray(processedValue)) {
emitValue = processedValue.length > 0 ? processedValue.sort() : undefined; emitValue = processedValue.length > 0 ? processedValue.sort() : [];
} else if (processedValue === null || processedValue === undefined) { } else if (processedValue === null || processedValue === undefined) {
emitValue = undefined; emitValue = undefined;
} }
} }
state.value = processedValue; state.value = processedValue;
emit('update:modelValue', emitValue === '' ? undefined : emitValue); emit('update:modelValue', emitValue === '' || emitValue.length === 0 ? undefined : emitValue);
emit('change', state.value, currentDictItems, state.dictData); emit('change', state.value, currentDictItems, state.dictData);
}; };
@ -527,7 +550,7 @@ const validateInitialValue = () => {
reject(`[g-sys-dict] 未匹配到选项值:${JSON.stringify(errorValues)}`); reject(`[g-sys-dict] 未匹配到选项值:${JSON.stringify(errorValues)}`);
} }
} else if (state.value) { } else if (state.value) {
if (!state.dictData.find((e) => e[props.propValue] === state.value)) { if (!state.dictData.find((e) => e[props.propValue] == state.value)) {
reject(`[g-sys-dict] 未匹配到选项值:${state.value}`); reject(`[g-sys-dict] 未匹配到选项值:${state.value}`);
} }
} }
@ -535,16 +558,6 @@ const validateInitialValue = () => {
}); });
}; };
/**
* 组件状态
* @property {DictItem[]} dictData - 原始字典数据
* @property {any} value - 当前值
*/
const state = reactive({
dictData: [] as DictItem[],
value: parseMultipleValue(props.modelValue),
});
// //
watch( watch(
() => props.modelValue, () => props.modelValue,