This commit is contained in:
张成
2025-10-28 11:24:11 +08:00
parent a8d52f74ad
commit e039ae8c62
39 changed files with 636 additions and 676 deletions

View File

@@ -0,0 +1,21 @@
<template>
<DatePicker
:value="value"
v-bind="$attrs"
@on-change="handleChange"
:style="'width:100%;'"
/>
</template>
<script>
export default {
name: 'DatePicker',
props: ['value'],
methods: {
handleChange(date) {
this.$emit('input', date)
this.$emit('change', date)
}
}
}
</script>

84
src/components/index.js Normal file
View File

@@ -0,0 +1,84 @@
import Main from './main'
import ParentView from './parent-view'
// 导入页面组件
import pages from '../views/index'
const {
LoginPage,
Page401,
Page404,
Page500
} = pages
import Tables from './tables'
import UploadSingle from './upload/Single.vue'
import UploadMultiple from './upload/Multiple.vue'
import TreeGrid from './treeGrid'
import AsyncModal from './asyncModal'
import InfoCard from './info-card'
import LoadFlower from './load-flower'
import SplitPane from './split-pane'
import TextArea from './text-area'
import CommonIcon from './common-icon'
import Editor from './editor/index.vue'
import editModal from './tables/editModal.vue'
import fieldItem from './tables/fieldItem.vue'
import FieldRenderer from './tables/fieldRenderer.vue'
// 注册全局组件的方法
export function registerGlobalComponents(Vue) {
Vue.component('Main', Main)
Vue.component('ParentView', ParentView)
Vue.component('Page401', Page401)
Vue.component('Page404', Page404)
Vue.component('Page500', Page500)
Vue.component('LoginPage', LoginPage)
Vue.component('Tables', Tables)
Vue.component('UploadSingle', UploadSingle)
Vue.component('UploadMultiple', UploadMultiple)
Vue.component('TreeGrid', TreeGrid)
Vue.component('AsyncModal', AsyncModal)
Vue.component('InfoCard', InfoCard)
Vue.component('LoadFlower', LoadFlower)
Vue.component('SplitPane', SplitPane)
Vue.component('TextArea', TextArea)
Vue.component('CommonIcon', CommonIcon)
Vue.component('Editor', Editor)
Vue.component('editModal', editModal)
Vue.component('fieldItem', fieldItem)
Vue.component('FieldRenderer', FieldRenderer)
}
// 注册自定义组件的方法
export function registerComponents(Vue, components = {}) {
Object.keys(components).forEach(name => {
Vue.component(name, components[name])
})
}
export default {
Main,
ParentView,
Tables,
UploadSingle,
UploadMultiple,
TreeGrid,
AsyncModal,
InfoCard,
LoadFlower,
SplitPane,
TextArea,
CommonIcon,
Editor,
editModal,
fieldItem,
FieldRenderer,
registerGlobalComponents,
registerComponents
}

View File

@@ -0,0 +1,20 @@
<template>
<Switch
:value="value"
v-bind="$attrs"
@on-change="handleChange"
/>
</template>
<script>
export default {
name: 'Switch',
props: ['value'],
methods: {
handleChange(checked) {
this.$emit('input', checked)
this.$emit('change', checked)
}
}
}
</script>

View File

@@ -13,38 +13,14 @@
<div :class="col.inLine?'inline-row':'line-row'" :key="col.name" v-if="col.key&&!col.display">
<FormItem :label="col.title" :prop="col.key" :rules="curRules[col.key]" :style=" col.rowStyle">
<Row>
<Select class="text-left" filterable v-if="col.com==='Select'" v-model='row[col.key]' v-bind="col" :disabled="getDisabled(col)">
<Option :value="item.key" :key="item.key" v-for="item in col.source">{{item.value }}</Option>
</Select>
<RadioGroup v-else-if="col.com==='Radio'" v-model="row[col.key]" v-bind="col" :disabled="getDisabled(col)">
<Radio :label="item.key" :key="item.key" v-for="item in col.source">
{{item.value}}
</Radio>
</RadioGroup>
<AutoComplete v-else-if="col.com==='SelectIcon'" icon="ios-search" v-model="row[col.key]" v-bind="col" :disabled="getDisabled(col)">
<Option v-for="(icon,index) in icons" :value="icon" :key="index">
<Icon size="20" :type="icon" />
{{ icon }}
</Option>
</AutoComplete>
<UploadSingle v-else-if="col.com==='upload_Img'" v-model="row[col.key]" v-bind="col" :disabled="getDisabled(col)">
</UploadSingle>
<TextArea v-else-if="col.com==='TextArea'" v-model="row[col.key]" v-bind="col" :disabled="getDisabled(col)">
</TextArea>
<templateRender v-else-if="col.editRender" :value="row[col.key]" :render='col.editRender'></templateRender>
<Input v-else-if="!col.com" v-model="row[col.key]" v-bind="col" style="width:100%;" :disabled="getDisabled(col)" />
<component v-else v-bind:is="col.com" v-model="row[col.key]" v-bind="col" :disabled="getDisabled(col)"></component>
<!-- 使用专门的字段渲染组件 -->
<FieldRenderer
:col="col"
:value="row[col.key]"
:disabled="getDisabled(col)"
@input="handleFieldInput(col.key, $event)"
@change="handleFieldChange(col.key, $event)"
/>
</Row>
</FormItem>
</div>
@@ -64,21 +40,12 @@
<script>
import Vue from 'vue'
import dayjs from 'dayjs'
import templateRender from './templateRender'
// 导入框架中的图标配置
let icons = []
try {
icons = require('../../config/icons.json') || []
} catch (e) {
console.warn('未找到图标配置文件,图标选择功能将不可用', e)
icons = []
}
import FieldRenderer from './fieldRenderer'
export default {
props: ['columns', 'width'],
components: {
templateRender
FieldRenderer
},
data() {
return {
@@ -87,7 +54,6 @@ export default {
isRefresh: true,
isEdit: false,
isOPen: false,
icons: [],
row: {},
callback: null
}
@@ -123,6 +89,16 @@ export default {
}
},
methods: {
// 处理字段输入事件
handleFieldInput(key, value) {
this.$set(this.row, key, value)
},
// 处理字段变化事件
handleFieldChange(key, value) {
this.$set(this.row, key, value)
},
// 判断字段是否禁用
getDisabled(col) {
// 如果是编辑模式且字段设置了disabled则禁用
@@ -192,12 +168,6 @@ export default {
this.isOPen = false
},
async init(row, isgl) {
// 安全处理图标数据
if (Array.isArray(icons)) {
this.icons = icons.map((item) => item.trim ? item.trim() : item)
} else {
this.icons = []
}
row = row || {}
let rules = this.curRules
if (isgl) {

View File

@@ -0,0 +1,196 @@
<template>
<div>
<!-- 使用组件映射表来简化条件渲染 -->
<component
:is="getComponentName(col.com)"
v-model="value"
v-bind="getComponentProps(col)"
:disabled="disabled"
:class="getComponentClass(col.com)"
:style="getComponentStyle(col.com)"
@input="handleInput"
@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="item.key"
:key="item.key"
v-for="item in col.source"
>
{{ item.value }}
</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: []
}
},
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.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
},
// 获取组件样式类
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) {
this.$emit('input', value)
},
// 处理变化事件
handleChange(value) {
this.$emit('change', value)
}
}
}
</script>