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

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,
(newValue) => {
state.data = newValue ?? [];
console.log(state.data);
},
{ immediate: true }
);

View File

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

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
@ -355,6 +366,18 @@ const parseMultipleValue = (value: any): any => {
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') {
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;
}
}
@ -454,20 +477,20 @@ const updateValue = (newValue: any) => {
let emitValue = processedValue;
if (props.multipleModel === MultipleModel.Comma) {
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) {
emitValue = undefined;
}
} else {
if (Array.isArray(processedValue)) {
emitValue = processedValue.length > 0 ? processedValue.sort() : undefined;
emitValue = processedValue.length > 0 ? processedValue.sort() : [];
} else if (processedValue === null || processedValue === undefined) {
emitValue = undefined;
}
}
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);
};
@ -527,7 +550,7 @@ const validateInitialValue = () => {
reject(`[g-sys-dict] 未匹配到选项值:${JSON.stringify(errorValues)}`);
}
} 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}`);
}
}
@ -535,16 +558,6 @@ const validateInitialValue = () => {
});
};
/**
* 组件状态
* @property {DictItem[]} dictData - 原始字典数据
* @property {any} value - 当前值
*/
const state = reactive({
dictData: [] as DictItem[],
value: parseMultipleValue(props.modelValue),
});
//
watch(
() => props.modelValue,