wip: 根据mock数据渲染表单元素

master
shengwen.chen 2 months ago
parent 559ceec399
commit a6647dcefe

@ -2,5 +2,5 @@
"$schema": "https://json.schemastore.org/prettierrc",
"semi": false,
"singleQuote": true,
"printWidth": 100
"printWidth": 180
}

@ -0,0 +1,68 @@
<script setup lang="ts">
import { inject, defineProps } from 'vue'
import type { IWidget } from '@/types/widgetsConfigInterface'
import RendererDom from '@/components/RendererDom.vue'
const props = defineProps<{
itemData: IWidget
}>()
//
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const docForm = inject('docForm') as any
//
if (props['itemData']['category'] == 'formItem') {
docForm[props['itemData']['options']['name']] = props['itemData']['options']['defaultValue'] || ''
//
if (props['itemData']['type'] == 'el-input-number') {
docForm[props['itemData']['options']['name']] = props['itemData']['options']['defaultValue'] || 0
}
}
</script>
<template>
<!-- 针对表格容器 -->
<template v-if="itemData['type'] == 'table'">
<table border="1" cellpadding="10" cellspacing="0" class="w-full">
<template v-for="(row, rowIndex) in itemData['rows']" :key="rowIndex">
<tr>
<RendererDom v-for="subData in row['cols']" :key="subData['id']" :itemData="subData" />
</tr>
</template>
</table>
</template>
<!-- 针对表格列 -->
<template v-if="itemData['type'] == 'table-cell'">
<td v-if="!itemData['merged']" :colspan="itemData['options']['colspan']" :rowspan="itemData['options']['rowspan']">
<RendererDom v-for="subData in itemData['widgetList']" :key="subData['id']" :itemData="subData" />
</td>
</template>
<!-- 针对普通输入框 -->
<template v-if="itemData['type'] == 'el-input'">
<el-form-item :label="itemData['options']['label']">
<el-input v-model="docForm[itemData['options']['name']]" :placeholder="itemData['options']['placeholder']" />
</el-form-item>
</template>
<!-- 针对数值输入框 -->
<template v-if="itemData['type'] == 'el-input-number'">
<el-form-item :label="itemData['options']['label']">
<el-input-number v-model="docForm[itemData['options']['name']]" :placeholder="itemData['options']['placeholder']"
:controls-position="'right'" />
</el-form-item>
</template>
<!-- 针对单选框 -->
<template v-if="itemData['type'] == 'el-radio'">
<el-form-item :label="itemData['options']['label']">
<el-radio-group v-model="docForm[itemData['options']['name']]">
<template v-for="optionItem in itemData['options']['optionItems']" :key="optionItem['value']">
<el-radio :label="optionItem['label']" :value="optionItem['value']" />
</template>
</el-radio-group>
</el-form-item>
</template>
</template>

@ -13,5 +13,7 @@ const iconComponent = computed<Component>(() => {
</script>
<template>
<el-icon> <component :is="iconComponent" /></el-icon>
<el-icon>
<component :is="iconComponent" />
</el-icon>
</template>

@ -1,12 +1,31 @@
export interface IContainerOption {
export interface IOption {
// 元素唯一标识符
name: string
// 隐藏状态
hidden: boolean
customClass: string
// 自定义类名
customClass?: string
// 标签名称
label?: string
// 默认值
defaultValue?: string | boolean | number | []
// 提示词
placeholder?: string
// 选择项
optionItems?: []
// 行合并
colspan?: number
// 列合并
rowspan?: number
}
export type ICategory = 'container' | 'formItem'
export interface IWidget {
// 元素唯一标识符
key?: number
// 元素id
id?: string
// 类别
category: ICategory
// 类型
@ -16,9 +35,15 @@ export interface IWidget {
// 图标
icon: string
// 子类
rows?: []
rows?: [{ cols: [IWidget] }]
// 属性
options: IContainerOption
options: IOption
// 子结构
widgetList?: []
// 单元格是否被合并
merged?: boolean
}
export interface IWidgetJson {
widgetList: IWidget[]
}

@ -1,16 +0,0 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import {
ElTable,
ElTableColumn,
ElInput,
ElForm,
ElFormItem
} from 'element-plus'
export const componentMap: Record<string, any> = {
'el-table': ElTable,
'el-table-column': ElTableColumn,
'el-input': ElInput,
'el-form': ElForm,
'el-form-item': ElFormItem,
}

@ -2,7 +2,7 @@
"key": 47004,
"id": "table-61396",
"category": "container",
"type": "el-table",
"type": "table",
"displayName": "表格",
"icon": "Monitor",
"rows": [
@ -10,14 +10,37 @@
"cols": [
{
"key": 47005,
"id": "table-column-12332",
"id": "table-cell-12332",
"category": "container",
"type": "el-table-column",
"type": "table-cell",
"displayName": "子单元格",
"icon": "Monitor",
"merged": false,
"widgetList": [
{
"key": 47016,
"id": "input-12355",
"category": "formItem",
"type": "el-input",
"displayName": "输入框",
"icon": "Folder",
"options": {
"name": "input-12355",
"keyNameEnabled": false,
"keyName": "",
"label": "名称",
"labelAlign": "",
"type": "text",
"defaultValue": "",
"hidden": false,
"customClass": "",
"placeholder": "请输入名称"
}
}
],
"rows": [],
"options": {
"name": "table-column-12332",
"name": "table-cell-12332",
"cellWidth": "",
"cellHeight": "",
"colspan": 1,
@ -28,26 +51,27 @@
},
{
"key": 47015,
"id": "table-column-12344",
"id": "table-cell-12344",
"category": "container",
"type": "el-table-column",
"type": "table-cell",
"displayName": "子单元格",
"icon": "Monitor",
"merged": false,
"widgetList": [
{
"key": 47016,
"id": "input-12355",
"id": "input-12366",
"category": "formItem",
"type": "el-input",
"type": "el-input-number",
"displayName": "输入框",
"icon": "Folder",
"options": {
"name": "input-12355",
"name": "input-12366",
"keyNameEnabled": false,
"keyName": "",
"label": "input",
"label": "年龄",
"labelAlign": "",
"type": "text",
"type": "number",
"defaultValue": "",
"hidden": false,
"customClass": ""
@ -56,7 +80,7 @@
],
"rows": [],
"options": {
"name": "table-column-12344",
"name": "table-cell-12344",
"cellWidth": "",
"cellHeight": "",
"colspan": 1,
@ -66,6 +90,80 @@
}
}
]
},
{
"cols": [
{
"key": 47015,
"id": "table-cell-12344",
"category": "container",
"type": "table-cell",
"displayName": "子单元格",
"icon": "Monitor",
"merged": false,
"widgetList": [
{
"key": 47016,
"id": "radio-12377",
"category": "formItem",
"type": "el-radio",
"displayName": "单选框",
"icon": "Folder",
"options": {
"name": "input-12377",
"keyNameEnabled": false,
"keyName": "",
"label": "性别",
"labelAlign": "",
"type": "text",
"defaultValue": "1",
"hidden": false,
"customClass": "",
"optionItems": [
{
"label": "男",
"value": "1"
},
{
"label": "女",
"value": 2
}
]
}
}
],
"rows": [],
"options": {
"name": "table-cell-12344",
"cellWidth": "",
"cellHeight": "",
"colspan": 2,
"rowspan": 1,
"wordBreak": false,
"customClass": ""
}
},
{
"key": 47018,
"id": "table-cell-12399",
"category": "container",
"type": "table-cell",
"displayName": "子单元格",
"icon": "Monitor",
"merged": true,
"widgetList": [],
"rows": [],
"options": {
"name": "table-cell-12399",
"cellWidth": "",
"cellHeight": "",
"colspan": 2,
"rowspan": 1,
"wordBreak": false,
"customClass": ""
}
}
]
}
],
"options": {

@ -6,11 +6,9 @@ export const containers: IWidget[] = [
type: 'el-table',
displayName: '表格',
icon: 'Monitor',
rows: [],
options: {
name: '',
hidden: false,
customClass: '',
}
},
{
@ -18,11 +16,9 @@ export const containers: IWidget[] = [
type: 'el-table-column',
displayName: '子单元格',
icon: 'Monitor',
rows: [],
options: {
name: '',
hidden: false,
customClass: '',
}
}
]
@ -37,7 +33,16 @@ export const basicFields: IWidget[] = [
options: {
name: '',
hidden: false,
customClass: '',
},
},
{
category: 'formItem',
type: 'el-input-number',
displayName: '数值输入框',
icon: 'Folder',
options: {
name: '',
hidden: false,
},
},
{
@ -48,7 +53,6 @@ export const basicFields: IWidget[] = [
options: {
name: '',
hidden: false,
customClass: '',
},
},
]

@ -37,8 +37,7 @@ const widgetJson = inject('widgetJson')
<template v-for="item in group['subItem']" :key="item['displayName']">
<div
class="basis-2/5 flex justify-between items-center border border-solid border-[#c1c1c1] px-2 mb-4"
@click="addItem('', widgetJson)"
>
@click="addItem('', widgetJson)">
<UseIcon :iconName="item['icon']"></UseIcon>
<p>{{ item['displayName'] }}</p>
</div>

@ -1,10 +1,24 @@
<script setup lang="ts">
import { inject } from 'vue'
import { provide, inject } from 'vue'
import { reactive } from 'vue'
import type { IWidgetJson } from '@/types/widgetsConfigInterface'
import RendererDom from '@/components/RendererDom.vue'
//
const widgetJson = inject('widgetJson')
const widgetJson = inject<IWidgetJson>('widgetJson')!
//
const docForm = reactive({})
provide('docForm', docForm)
</script>
<template>
<section>{{ widgetJson }}</section>
<section>
<h1 class="text-sky-300">{{ widgetJson }}</h1>
<el-form :model="docForm" label-width="80px">
<template v-for="item in widgetJson['widgetList']" :key="item['id']">
<RendererDom :itemData="item" />
</template>
</el-form>
</section>
</template>

Loading…
Cancel
Save