2026-04-23 09:05:55 +08:00
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
|
import { computed } from 'vue';
|
|
|
|
|
|
import { useDict } from '@/hooks/business/dict';
|
|
|
|
|
|
|
|
|
|
|
|
defineOptions({ name: 'DictSelect' });
|
|
|
|
|
|
|
|
|
|
|
|
interface Props {
|
|
|
|
|
|
dictCode: string;
|
|
|
|
|
|
placeholder?: string;
|
|
|
|
|
|
disabled?: boolean;
|
|
|
|
|
|
clearable?: boolean;
|
|
|
|
|
|
filterable?: boolean;
|
|
|
|
|
|
onlyEnabled?: boolean;
|
|
|
|
|
|
multiple?: boolean;
|
|
|
|
|
|
collapseTags?: boolean;
|
|
|
|
|
|
collapseTagsTooltip?: boolean;
|
2026-05-21 21:42:23 +08:00
|
|
|
|
/** 下拉项右侧追加字典 remark 中文释义(优先级等需要"P0 → 紧急"对照的场景) */
|
|
|
|
|
|
showRemark?: boolean;
|
2026-04-23 09:05:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
|
|
|
|
placeholder: '请选择',
|
|
|
|
|
|
disabled: false,
|
|
|
|
|
|
clearable: true,
|
|
|
|
|
|
filterable: false,
|
|
|
|
|
|
onlyEnabled: true,
|
|
|
|
|
|
multiple: false,
|
|
|
|
|
|
collapseTags: false,
|
2026-05-21 21:42:23 +08:00
|
|
|
|
collapseTagsTooltip: false,
|
|
|
|
|
|
showRemark: false
|
2026-04-23 09:05:55 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const model = defineModel<string | number | Array<string | number> | null | undefined>({
|
|
|
|
|
|
default: undefined
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const { enabledDictData, dictData } = useDict(() => props.dictCode);
|
|
|
|
|
|
|
|
|
|
|
|
const dictOptions = computed(() => {
|
|
|
|
|
|
const source = props.onlyEnabled ? enabledDictData.value : dictData.value;
|
|
|
|
|
|
return source.map(item => ({
|
|
|
|
|
|
label: item.label,
|
2026-05-21 21:42:23 +08:00
|
|
|
|
value: item.value,
|
|
|
|
|
|
colorType: item.colorType ?? null,
|
|
|
|
|
|
remark: item.remark ?? null
|
2026-04-23 09:05:55 +08:00
|
|
|
|
}));
|
|
|
|
|
|
});
|
2026-05-21 21:42:23 +08:00
|
|
|
|
|
|
|
|
|
|
// 单选时取当前选中项的 colorType,用于触发器 prefix 色块
|
|
|
|
|
|
const selectedColorType = computed<string | null>(() => {
|
|
|
|
|
|
if (props.multiple) return null;
|
|
|
|
|
|
const value = model.value;
|
|
|
|
|
|
if (value === null || value === undefined || value === '') return null;
|
|
|
|
|
|
return dictOptions.value.find(opt => opt.value === value)?.colorType ?? null;
|
|
|
|
|
|
});
|
2026-04-23 09:05:55 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
|
<ElSelect
|
|
|
|
|
|
v-model="model"
|
2026-05-21 21:42:23 +08:00
|
|
|
|
class="dict-select w-full"
|
2026-04-23 09:05:55 +08:00
|
|
|
|
:placeholder="props.placeholder"
|
|
|
|
|
|
:disabled="props.disabled"
|
|
|
|
|
|
:clearable="props.clearable"
|
|
|
|
|
|
:filterable="props.filterable"
|
|
|
|
|
|
:multiple="props.multiple"
|
|
|
|
|
|
:collapse-tags="props.collapseTags"
|
|
|
|
|
|
:collapse-tags-tooltip="props.collapseTagsTooltip"
|
|
|
|
|
|
>
|
2026-05-21 21:42:23 +08:00
|
|
|
|
<template v-if="selectedColorType" #prefix>
|
|
|
|
|
|
<span class="dict-select__color-dot" :style="{ background: selectedColorType }" />
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<ElOption v-for="item in dictOptions" :key="item.value" :label="item.label" :value="item.value">
|
|
|
|
|
|
<span class="dict-select__option">
|
|
|
|
|
|
<span
|
|
|
|
|
|
v-if="item.colorType"
|
|
|
|
|
|
class="dict-select__color-dot dict-select__color-dot--option"
|
|
|
|
|
|
:style="{ background: item.colorType }"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<span class="dict-select__option-label">{{ item.label }}</span>
|
|
|
|
|
|
<span v-if="props.showRemark && item.remark" class="dict-select__option-remark">{{ item.remark }}</span>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</ElOption>
|
2026-04-23 09:05:55 +08:00
|
|
|
|
</ElSelect>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
2026-05-21 21:42:23 +08:00
|
|
|
|
<style scoped>
|
|
|
|
|
|
.dict-select__color-dot {
|
|
|
|
|
|
display: inline-block;
|
|
|
|
|
|
width: 10px;
|
|
|
|
|
|
height: 10px;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
vertical-align: middle;
|
|
|
|
|
|
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.08);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.dict-select__color-dot--option {
|
|
|
|
|
|
margin-right: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.dict-select__option {
|
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.dict-select__option-label {
|
|
|
|
|
|
flex: 0 0 auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.dict-select__option-remark {
|
|
|
|
|
|
margin-left: auto;
|
|
|
|
|
|
color: var(--el-text-color-secondary);
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|