Files
BMS/bms-front/src/components/BasicForm/FormControl.vue
T
2026-09-23 15:53:12 +08:00

188 lines
5.1 KiB
Vue

<template>
<!-- 输入框 -->
<el-input
v-if="comp === 'input'"
v-model="model[item.prop]"
:placeholder="placeholder"
:disabled="item.disabled"
:style="controlStyle"
v-bind="item.props"
/>
<!-- 文本域 -->
<el-input
v-else-if="comp === 'textarea'"
v-model="model[item.prop]"
type="textarea"
:placeholder="placeholder"
:disabled="item.disabled"
:style="controlStyle"
v-bind="item.props"
/>
<!-- 数字输入 -->
<el-input-number
v-else-if="comp === 'inputNumber'"
v-model="model[item.prop]"
:disabled="item.disabled"
:style="controlStyle"
v-bind="item.props"
/>
<!-- 下拉选择 -->
<el-select
v-else-if="comp === 'select'"
v-model="model[item.prop]"
:placeholder="placeholder || '请选择'"
:disabled="item.disabled"
:style="controlStyle"
v-bind="item.props"
>
<el-option
v-for="opt in options"
:key="opt[valueKey]"
:label="opt[labelKey]"
:value="opt[valueKey]"
/>
</el-select>
<!-- 单选组 -->
<el-radio-group
v-else-if="comp === 'radio'"
v-model="model[item.prop]"
:disabled="item.disabled"
v-bind="item.props"
>
<el-radio v-for="opt in options" :key="opt[valueKey]" :value="opt[valueKey]">{{ opt[labelKey] }}</el-radio>
</el-radio-group>
<!-- 复选组 -->
<el-checkbox-group
v-else-if="comp === 'checkbox'"
v-model="model[item.prop]"
:disabled="item.disabled"
v-bind="item.props"
>
<el-checkbox v-for="opt in options" :key="opt[valueKey]" :value="opt[valueKey]">{{ opt[labelKey] }}</el-checkbox>
</el-checkbox-group>
<!-- 开关 -->
<el-switch
v-else-if="comp === 'switch'"
v-model="model[item.prop]"
:disabled="item.disabled"
v-bind="item.props"
/>
<!-- 日期 -->
<el-date-picker
v-else-if="comp === 'date'"
v-model="model[item.prop]"
type="date"
:placeholder="placeholder || '请选择日期'"
:disabled="item.disabled"
:style="controlStyle"
value-format="YYYY-MM-DD"
v-bind="item.props"
/>
<!-- 日期时间 -->
<el-date-picker
v-else-if="comp === 'datetime'"
v-model="model[item.prop]"
type="datetime"
:placeholder="placeholder || '请选择日期时间'"
:disabled="item.disabled"
:style="controlStyle"
value-format="YYYY-MM-DD HH:mm:ss"
v-bind="item.props"
/>
<!-- 日期范围 -->
<el-date-picker
v-else-if="comp === 'daterange'"
v-model="model[item.prop]"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
:disabled="item.disabled"
:style="controlStyle"
value-format="YYYY-MM-DD"
v-bind="item.props"
/>
<!-- 日期时间范围 -->
<el-date-picker
v-else-if="comp === 'datetimerange'"
v-model="model[item.prop]"
type="datetimerange"
range-separator="至"
start-placeholder="开始时间"
end-placeholder="结束时间"
:disabled="item.disabled"
:style="controlStyle"
value-format="YYYY-MM-DD HH:mm:ss"
v-bind="item.props"
/>
<!-- 时间 -->
<el-time-picker
v-else-if="comp === 'time'"
v-model="model[item.prop]"
:disabled="item.disabled"
:style="controlStyle"
value-format="HH:mm:ss"
v-bind="item.props"
/>
<!-- 级联 -->
<el-cascader
v-else-if="comp === 'cascader'"
v-model="model[item.prop]"
:options="options"
:placeholder="placeholder || '请选择'"
:disabled="item.disabled"
:style="controlStyle"
v-bind="item.props"
/>
<!-- 未知控件回退到 input -->
<el-input
v-else
v-model="model[item.prop]"
:placeholder="placeholder"
:disabled="item.disabled"
:style="controlStyle"
v-bind="item.props"
/>
</template>
<script setup>
/**
* 表单控件渲染器(BasicForm 内部使用)
* 根据 item.component 渲染对应的 Element Plus 控件,支持字典自动加载选项。
* 控件直接双向绑定 model[item.prop](引用修改,与 el-form 一致)。
*/
defineOptions({ name: 'FormControl' })
const props = defineProps({
// 表单数据对象(引用,控件原地修改其字段)
model: { type: Object, required: true },
// schema 项配置
item: { type: Object, required: true },
// 字典映射表(来自父级 BasicForm)
dictMap: { type: Object, default: () => ({}) },
// 拉伸模式(固定每行 N 项的栅格布局):忽略 item.width,控件填满单元格
stretch: { type: Boolean, default: false }
})
const comp = computed(() => props.item.component || 'input')
const placeholder = computed(() => props.item.placeholder)
const valueKey = computed(() => props.item.valueKey || 'value')
const labelKey = computed(() => props.item.labelKey || 'label')
// 控件宽度样式(stretch 模式下填满单元格)
const controlStyle = computed(() => {
if (props.stretch) return { width: '100%' }
return props.item.width ? { width: props.item.width } : null
})
// 选项:静态 options 优先,其次字典
const options = computed(() => {
if (props.item.options) return props.item.options
if (props.item.dict) {
const d = props.dictMap[props.item.dict]
return isRef(d) ? d.value : d || []
}
return []
})
</script>