Files
dafuweng-saiadmin6.x/saiadmin-artd/src/components/sai/sa-radio/index.vue
2026-03-19 15:40:06 +08:00

144 lines
3.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<el-radio-group
v-model="modelValue"
v-bind="$attrs"
:disabled="disabled"
:size="size"
:fill="fill"
:text-color="textColor"
>
<!-- 模式1: 按钮样式 -->
<template v-if="type === 'button'">
<el-radio-button v-if="allowNull" :value="nullValue" :label="nullLabel">
{{ nullLabel }}
</el-radio-button>
<el-radio-button
v-for="(item, index) in options"
:key="index"
:value="item.value"
:label="item.value"
:disabled="item.disabled"
>
{{ item.label }}
</el-radio-button>
</template>
<!-- 模式2: 普通/边框样式 -->
<template v-else>
<el-radio v-if="allowNull" :value="nullValue" :label="nullLabel" :border="type === 'border'">
{{ nullLabel }}
</el-radio>
<el-radio
v-for="(item, index) in options"
:key="index"
:value="item.value"
:label="item.value"
:border="type === 'border'"
:disabled="item.disabled"
>
{{ item.label }}
</el-radio>
</template>
</el-radio-group>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useDictStore } from '@/store/modules/dict'
import { useI18n } from 'vue-i18n'
defineOptions({ name: 'SaRadio', inheritAttrs: false })
interface Props {
dict: string
type?: 'radio' | 'button' | 'border'
disabled?: boolean
size?: 'large' | 'default' | 'small'
fill?: string
textColor?: string
allowNull?: boolean
nullValue?: string | number
nullLabel?: string
/**
* 强制转换字典值的类型
* 可选值: 'number' | 'string'
* 默认使用 'number'
*/
valueType?: 'number' | 'string'
}
const props = withDefaults(defineProps<Props>(), {
type: 'radio',
disabled: false,
size: 'default',
fill: '',
textColor: '',
allowNull: false,
nullValue: '',
nullLabel: '全部',
valueType: 'number' // 默认不转换
})
// 这里支持泛型,保证外部接收到的类型是正确的
const modelValue = defineModel<string | number | undefined>()
const dictStore = useDictStore()
const { t, te, locale } = useI18n()
// 判断能否转成数字
const canConvertToNumberStrict = (value: any) => {
// 严格模式:排除 null、undefined、布尔值、空数组等
if (value == null) return false
if (typeof value === 'boolean') return false
if (Array.isArray(value) && value.length !== 1) return false
if (typeof value === 'object' && !Array.isArray(value)) return false
const num = Number(value)
return !isNaN(num)
}
// 核心逻辑:在 computed 中处理数据类型转换
const options = computed(() => {
// 让字典选项在切换语言时可响应更新
locale.value
const list = dictStore.getByCode(props.dict) || []
// 如果没有指定 valueType直接返回原始字典
if (!props.valueType) {
return list.map((item) => {
const key = `dict.${props.dict}.${item.value}`
return {
...item,
label: te(key) ? t(key) : item.label
}
})
}
// 如果指定了类型,进行映射转换
return list.map((item) => {
let newValue = item.value
switch (props.valueType) {
case 'number':
if (canConvertToNumberStrict(item.value)) {
newValue = Number(item.value)
}
break
case 'string':
newValue = String(item.value)
break
}
return {
...item,
value: newValue,
label: (() => {
const key = `dict.${props.dict}.${newValue}`
return te(key) ? t(key) : item.label
})()
}
})
})
</script>