188 lines
5.1 KiB
Vue
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>
|