😎增加字典互斥配置
This commit is contained in:
parent
417a0a19d2
commit
a871c31e90
@ -40,10 +40,22 @@ interface DictItem {
|
|||||||
tagType?: TagType;
|
tagType?: TagType;
|
||||||
styleSetting?: string;
|
styleSetting?: string;
|
||||||
classSetting?: string;
|
classSetting?: string;
|
||||||
|
disabled?: boolean;
|
||||||
label?: string;
|
label?: string;
|
||||||
value?: string | number;
|
value?: string | number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 互斥选项配置
|
||||||
|
* @type {Object}
|
||||||
|
* @property {string|number} value - 触发互斥的选项值
|
||||||
|
* @property {Array<string|number>} excludes - 被互斥的选项值列表
|
||||||
|
*/
|
||||||
|
interface MutexConfig {
|
||||||
|
value: string | number;
|
||||||
|
excludes: (string | number)[];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 多选值模式枚举
|
* 多选值模式枚举
|
||||||
* @enum {string}
|
* @enum {string}
|
||||||
@ -81,7 +93,7 @@ import { reactive, watch, computed, PropType } from 'vue';
|
|||||||
import { useUserInfo } from '/@/stores/userInfo';
|
import { useUserInfo } from '/@/stores/userInfo';
|
||||||
|
|
||||||
const userStore = useUserInfo();
|
const userStore = useUserInfo();
|
||||||
const emit = defineEmits(['update:modelValue']);
|
const emit = defineEmits(['update:modelValue', 'change']);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 组件属性定义
|
* 组件属性定义
|
||||||
@ -206,6 +218,19 @@ const props = defineProps({
|
|||||||
default: MultipleModel.Array,
|
default: MultipleModel.Array,
|
||||||
validator: isMultipleModel,
|
validator: isMultipleModel,
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 互斥配置项(仅在多选模式下有效)
|
||||||
|
* @type {Array<MutexConfig>}
|
||||||
|
* @example
|
||||||
|
* :mutex-configs="[
|
||||||
|
* { value: 'all', excludes: ['1', '2', '3'] },
|
||||||
|
* { value: '1', excludes: ['all'] }
|
||||||
|
* ]"
|
||||||
|
*/
|
||||||
|
mutexConfigs: {
|
||||||
|
type: Array as PropType<MutexConfig[]>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -214,11 +239,26 @@ const props = defineProps({
|
|||||||
* @returns {DictItem[]} - 过滤并格式化后的字典数据
|
* @returns {DictItem[]} - 过滤并格式化后的字典数据
|
||||||
*/
|
*/
|
||||||
const formattedDictData = computed(() => {
|
const formattedDictData = computed(() => {
|
||||||
return state.dictData.filter(props.onItemFilter).map((item) => ({
|
const baseData = state.dictData.filter(props.onItemFilter).map((item) => ({
|
||||||
...item,
|
...item,
|
||||||
label: item[props.propLabel],
|
label: item[props.propLabel],
|
||||||
value: item[props.propValue],
|
value: item[props.propValue],
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// 如果没有互斥配置或多选模式,直接返回基础数据
|
||||||
|
if (!props.multiple || !props.mutexConfigs || props.mutexConfigs.length === 0) {
|
||||||
|
return baseData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理互斥逻辑,设置禁用状态
|
||||||
|
return baseData.map((item) => {
|
||||||
|
// 检查当前项是否应该被禁用
|
||||||
|
const isDisabled = isItemDisabled(item.value, state.value, props.mutexConfigs);
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
disabled: isDisabled || item.disabled, // 保持原有的disabled状态
|
||||||
|
};
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -337,16 +377,83 @@ const parseMultipleValue = (value: any): any => {
|
|||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查选项是否应该被禁用
|
||||||
|
* @function
|
||||||
|
* @param {string|number} itemValue - 当前选项的值
|
||||||
|
* @param {any} currentValue - 当前选中的值
|
||||||
|
* @param {MutexConfig[]} mutexConfigs - 互斥配置列表
|
||||||
|
* @returns {boolean} - 是否应该禁用
|
||||||
|
*/
|
||||||
|
const isItemDisabled = (itemValue: string | number, currentValue: any, mutexConfigs: MutexConfig[]): boolean => {
|
||||||
|
// 如果没有配置互斥规则,不禁用任何项
|
||||||
|
if (!mutexConfigs || mutexConfigs.length === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前选中的值数组
|
||||||
|
const selectedValues = Array.isArray(currentValue) ? currentValue : currentValue ? [currentValue] : [];
|
||||||
|
|
||||||
|
// 检查每个互斥配置
|
||||||
|
for (const config of mutexConfigs) {
|
||||||
|
// 如果互斥触发项已被选中,且当前项是被互斥项,则禁用
|
||||||
|
if (selectedValues.includes(config.value) && config.excludes.includes(itemValue)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果当前项是互斥触发项,且有被互斥项被选中,则禁用
|
||||||
|
if (itemValue === config.value && config.excludes.some((exclude) => selectedValues.includes(exclude))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 互斥处理函数
|
||||||
|
* @function
|
||||||
|
* @param {any} newValue - 新选中的值
|
||||||
|
* @param {MutexConfig[]} mutexConfigs - 互斥配置列表
|
||||||
|
* @returns {any} - 处理后的值
|
||||||
|
*/
|
||||||
|
const handleMutex = (newValue: any, mutexConfigs: MutexConfig[]): any => {
|
||||||
|
// 如果没有配置互斥规则,直接返回原值
|
||||||
|
if (!mutexConfigs || mutexConfigs.length === 0) {
|
||||||
|
return newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是单选模式,直接返回
|
||||||
|
if (!props.multiple) {
|
||||||
|
return newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对于禁用模式,我们只需要确保新值是有效的(即没有违反互斥规则)
|
||||||
|
// 实际的禁用逻辑在formattedDictData中处理
|
||||||
|
let resultValue = Array.isArray(newValue) ? [...newValue] : newValue ? [newValue] : [];
|
||||||
|
|
||||||
|
// 过滤掉无效的值(可能由于异步更新导致的无效选择)
|
||||||
|
const validValues = formattedDictData.value.filter((item) => !item.disabled).map((item) => item.value);
|
||||||
|
|
||||||
|
return resultValue.filter((val) => validValues.includes(val));
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新绑定值(修复逗号模式问题)
|
* 更新绑定值(修复逗号模式问题)
|
||||||
* @function
|
* @function
|
||||||
* @param {any} newValue - 新值
|
* @param {any} newValue - 新值
|
||||||
*/
|
*/
|
||||||
const updateValue = (newValue: any) => {
|
const updateValue = (newValue: any) => {
|
||||||
// 先对值进行去重处理
|
// 如果有互斥配置,先处理互斥
|
||||||
let processedValue = newValue;
|
let processedValue = newValue;
|
||||||
if (Array.isArray(newValue)) {
|
if (props.mutexConfigs && props.mutexConfigs.length > 0) {
|
||||||
processedValue = [...new Set(newValue.filter((v) => v !== null && v !== undefined && v !== ''))];
|
processedValue = handleMutex(newValue, props.mutexConfigs);
|
||||||
|
// console.log('[g-sys-dict] 字典数据:', state.dictData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 去重处理
|
||||||
|
if (Array.isArray(processedValue)) {
|
||||||
|
processedValue = [...new Set(processedValue.filter((v) => v !== null && v !== undefined && v !== ''))];
|
||||||
}
|
}
|
||||||
|
|
||||||
let emitValue = processedValue;
|
let emitValue = processedValue;
|
||||||
@ -361,6 +468,7 @@ const updateValue = (newValue: any) => {
|
|||||||
|
|
||||||
state.value = processedValue;
|
state.value = processedValue;
|
||||||
emit('update:modelValue', emitValue);
|
emit('update:modelValue', emitValue);
|
||||||
|
emit('change', state.value, state.dictData);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -416,7 +524,7 @@ watch(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
watch(() => [userStore.dictList, userStore.constList], initData, { immediate: true });
|
watch(() => [userStore.dictList, userStore.constList, state], initData, { immediate: true });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -437,12 +545,12 @@ watch(() => [userStore.dictList, userStore.constList], initData, { immediate: tr
|
|||||||
|
|
||||||
<!-- 渲染选择器 -->
|
<!-- 渲染选择器 -->
|
||||||
<el-select v-else-if="props.renderAs === 'select'" v-model="state.value" v-bind="$attrs" :multiple="props.multiple" @change="updateValue" clearable>
|
<el-select v-else-if="props.renderAs === 'select'" v-model="state.value" v-bind="$attrs" :multiple="props.multiple" @change="updateValue" clearable>
|
||||||
<el-option v-for="(item, index) in formattedDictData" :key="index" :label="getDisplayText(item)" :value="item.value" />
|
<el-option v-for="(item, index) in formattedDictData" :key="index" :label="getDisplayText(item)" :value="item.value" :disabled="item.disabled" />
|
||||||
</el-select>
|
</el-select>
|
||||||
|
|
||||||
<!-- 渲染复选框(多选) -->
|
<!-- 渲染复选框(多选) -->
|
||||||
<el-checkbox-group v-else-if="props.renderAs === 'checkbox'" v-model="state.value" v-bind="$attrs" @change="updateValue">
|
<el-checkbox-group v-else-if="props.renderAs === 'checkbox'" v-model="state.value" v-bind="$attrs" @change="updateValue">
|
||||||
<el-checkbox-button v-for="(item, index) in formattedDictData" :key="index" :value="item.value">
|
<el-checkbox-button v-for="(item, index) in formattedDictData" :key="index" :value="item.value" :disabled="item.disabled">
|
||||||
{{ getDisplayText(item) }}
|
{{ getDisplayText(item) }}
|
||||||
</el-checkbox-button>
|
</el-checkbox-button>
|
||||||
</el-checkbox-group>
|
</el-checkbox-group>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user