267 lines
6.9 KiB
Vue
267 lines
6.9 KiB
Vue
<template>
|
||
<div style="width: 100%;">
|
||
<!-- 使用组件映射表来简化条件渲染 -->
|
||
<component
|
||
:is="getComponentName(col.com)"
|
||
:value="col.com === 'Radio' ? radioValue : value"
|
||
v-bind="getComponentProps(col)"
|
||
:disabled="disabled"
|
||
:class="getComponentClass(col.com)"
|
||
:style="getComponentStyle(col.com)"
|
||
@input="handleInput"
|
||
@on-change="handleChange"
|
||
>
|
||
<!-- Select 组件的选项 -->
|
||
<template v-if="col.com === 'Select'">
|
||
<Option
|
||
:value="item.key"
|
||
:key="item.key"
|
||
v-for="item in col.source"
|
||
>
|
||
{{ item.value }}
|
||
</Option>
|
||
</template>
|
||
|
||
<!-- Radio 组件的选项 -->
|
||
<template v-else-if="col.com === 'Radio'">
|
||
<Radio
|
||
:label="getRadioValue(item)"
|
||
:key="getRadioKey(item)"
|
||
v-for="item in getRadioSource(col)"
|
||
>
|
||
{{ getRadioLabel(item) }}
|
||
</Radio>
|
||
</template>
|
||
|
||
<!-- SelectIcon 组件的选项 -->
|
||
<template v-else-if="col.com === 'SelectIcon'">
|
||
<Option
|
||
v-for="(icon, index) in icons"
|
||
:value="icon"
|
||
:key="index"
|
||
>
|
||
<Icon size="20" :type="icon" />
|
||
{{ icon }}
|
||
</Option>
|
||
</template>
|
||
|
||
<!-- 自定义渲染 -->
|
||
<template v-else-if="col.editRender">
|
||
<templateRender
|
||
:value="value"
|
||
:render="col.editRender"
|
||
/>
|
||
</template>
|
||
</component>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import templateRender from './templateRender'
|
||
|
||
// 导入框架中的图标配置
|
||
let icons = []
|
||
try {
|
||
icons = require('../../config/icons.json') || []
|
||
} catch (e) {
|
||
console.warn('未找到图标配置文件,图标选择功能将不可用', e)
|
||
icons = []
|
||
}
|
||
|
||
export default {
|
||
name: 'FieldRenderer',
|
||
components: {
|
||
templateRender
|
||
},
|
||
props: {
|
||
col: {
|
||
type: Object,
|
||
required: true
|
||
},
|
||
value: {
|
||
type: [String, Number, Boolean, Array, Object, Date],
|
||
default: ''
|
||
},
|
||
disabled: {
|
||
type: Boolean,
|
||
default: false
|
||
}
|
||
},
|
||
data() {
|
||
return {
|
||
icons: []
|
||
}
|
||
},
|
||
computed: {
|
||
// 直接返回原始值,不进行类型转换
|
||
radioValue() {
|
||
return this.value
|
||
}
|
||
},
|
||
mounted() {
|
||
// 安全处理图标数据
|
||
if (Array.isArray(icons)) {
|
||
this.icons = icons.map((item) => item.trim ? item.trim() : item)
|
||
} else {
|
||
this.icons = []
|
||
}
|
||
},
|
||
methods: {
|
||
// 组件映射表 - 统一管理组件类型
|
||
getComponentName(componentType) {
|
||
const componentMap = {
|
||
'Select': 'Select',
|
||
'Radio': 'RadioGroup',
|
||
'SelectIcon': 'AutoComplete',
|
||
'UploadSingle': 'UploadSingle',
|
||
'TextArea': 'TextArea',
|
||
'Input': 'Input',
|
||
'DatePicker': 'DatePicker',
|
||
'TimePicker': 'TimePicker',
|
||
'Switch': 'Switch',
|
||
'Checkbox': 'Checkbox',
|
||
'Slider': 'Slider',
|
||
'Rate': 'Rate',
|
||
'Cascader': 'Cascader',
|
||
'TreeSelect': 'TreeSelect',
|
||
'Transfer': 'Transfer',
|
||
'Upload': 'Upload',
|
||
'ColorPicker': 'ColorPicker',
|
||
'InputNumber': 'InputNumber'
|
||
}
|
||
|
||
// 如果没有指定组件类型,默认为 Input
|
||
return componentMap[componentType] || 'Input'
|
||
},
|
||
|
||
// 获取组件属性
|
||
getComponentProps(col) {
|
||
const baseProps = { ...col }
|
||
|
||
// 移除不需要传递给组件的属性
|
||
delete baseProps.com
|
||
delete baseProps.source
|
||
delete baseProps.options
|
||
delete baseProps.editRender
|
||
delete baseProps.inLine
|
||
delete baseProps.display
|
||
delete baseProps.disabled
|
||
delete baseProps.disabledOnAdd
|
||
delete baseProps.required
|
||
delete baseProps.data_type
|
||
delete baseProps.type
|
||
delete baseProps.rowStyle
|
||
|
||
// 根据组件类型添加特定属性
|
||
if (col.com === 'Select') {
|
||
baseProps.filterable = true
|
||
baseProps.clearable = true
|
||
} else if (col.com === 'SelectIcon') {
|
||
baseProps.icon = 'ios-search'
|
||
} else if (col.com === 'TextArea') {
|
||
baseProps.rows = 4
|
||
baseProps.placeholder = '请输入内容'
|
||
} else if (col.com === 'Input' || !col.com) {
|
||
baseProps.placeholder = col.placeholder || '请输入' + col.title
|
||
baseProps.clearable = true
|
||
}
|
||
|
||
return baseProps
|
||
},
|
||
|
||
// 获取 Radio 数据源(支持 source 和 options 两种格式)
|
||
getRadioSource(col) {
|
||
return col.source || col.options || []
|
||
},
|
||
|
||
// 获取 Radio 选项的值(支持多种数据格式)
|
||
getRadioValue(item) {
|
||
// 支持 { key: value, value: label } 格式
|
||
if (item.key !== undefined) {
|
||
return item.key
|
||
}
|
||
// 支持 { value: value, label: label } 格式
|
||
if (item.value !== undefined) {
|
||
return item.value
|
||
}
|
||
// 支持字符串数组
|
||
if (typeof item === 'string' || typeof item === 'number') {
|
||
return item
|
||
}
|
||
return item
|
||
},
|
||
|
||
// 获取 Radio 选项的 key(用于 v-for)
|
||
getRadioKey(item) {
|
||
if (item.key !== undefined) {
|
||
return item.key
|
||
}
|
||
if (item.value !== undefined) {
|
||
return item.value
|
||
}
|
||
if (typeof item === 'string' || typeof item === 'number') {
|
||
return item
|
||
}
|
||
return JSON.stringify(item)
|
||
},
|
||
|
||
// 获取 Radio 选项的显示文本
|
||
getRadioLabel(item) {
|
||
// 支持 { key: value, value: label } 格式
|
||
if (item.value !== undefined && typeof item.value === 'string') {
|
||
return item.value
|
||
}
|
||
// 支持 { value: value, label: label } 格式
|
||
if (item.label !== undefined) {
|
||
return item.label
|
||
}
|
||
// 支持字符串数组
|
||
if (typeof item === 'string' || typeof item === 'number') {
|
||
return item
|
||
}
|
||
return item.value || item.key || item
|
||
},
|
||
|
||
// 获取组件样式类
|
||
getComponentClass(componentType) {
|
||
const classMap = {
|
||
'Select': 'text-left',
|
||
'SelectIcon': 'text-left'
|
||
}
|
||
return classMap[componentType] || ''
|
||
},
|
||
|
||
// 获取组件样式
|
||
getComponentStyle(componentType) {
|
||
const styleMap = {
|
||
'Input': 'width:100%;',
|
||
'TextArea': 'width:100%;',
|
||
'DatePicker': 'width:100%;',
|
||
'TimePicker': 'width:100%;'
|
||
}
|
||
return styleMap[componentType] || ''
|
||
},
|
||
|
||
// 处理输入事件
|
||
handleInput(value) {
|
||
// 如果接收到的是事件对象,提取值
|
||
if (value && typeof value === 'object' && value.target) {
|
||
value = value.target.value
|
||
}
|
||
// 直接传递值,不进行类型转换
|
||
this.$emit('input', value)
|
||
},
|
||
|
||
// 处理变化事件
|
||
handleChange(value) {
|
||
// 如果接收到的是事件对象,提取值
|
||
if (value && typeof value === 'object' && value.target) {
|
||
value = value.target.value
|
||
}
|
||
// 直接传递值,不进行类型转换
|
||
this.$emit('change', value)
|
||
}
|
||
}
|
||
}
|
||
</script>
|