feat: 动态表单

This commit is contained in:
shaohuzhang1 2023-11-23 17:55:39 +08:00
parent 394a6a7ee6
commit 589f895c73
42 changed files with 2170 additions and 162 deletions

View File

@ -6,17 +6,17 @@
@date2023/10/31 17:56
@desc:
"""
from .array_card import *
from .array_object_card import *
from .base_field import *
from .base_form import *
from .combobox_field import *
from .multi_select import *
from .number_input_field import *
from .object_card import *
from .password_input import *
from .radio_field import *
from .single_select_field import *
from .switch_btn import *
from .tab_card import *
from .table_radio import *
from .text_input_field import *
from .radio_button_field import *
from .table_checkbox import *
from .radio_card_field import *

View File

@ -2,7 +2,7 @@
"""
@project: maxkb
@Author
@file array_card.py
@file array_object_card.py
@date2023/10/31 18:03
@desc:
"""
@ -24,13 +24,10 @@ class ArrayCard(BaseExecField):
method: str,
required: bool = False,
default_value: object = None,
relation_show_field_list: List[str] = None,
relation_show_value_list: List[str] = None,
relation_trigger_field_list: List[str] = None,
relation_trigger_value_list: List[str] = None,
relation_show_field_dict: Dict = None,
relation_trigger_field_dict: Dict = None,
trigger_type: TriggerType = TriggerType.OPTION_LIST,
attrs: Dict[str, object] = None,
props_info: Dict[str, object] = None):
super().__init__("ArrayCard", label, text_field, value_field, provider, method, required, default_value,
relation_show_field_list, relation_show_value_list, relation_trigger_field_list,
relation_trigger_value_list, trigger_type, attrs, props_info)
super().__init__("ArrayObjectCard", label, text_field, value_field, provider, method, required, default_value,
relation_show_field_dict, relation_trigger_field_dict, trigger_type, attrs, props_info)

View File

@ -23,10 +23,8 @@ class BaseField:
label: str,
required: bool = False,
default_value: object = None,
relation_show_field_list: List[str] = None,
relation_show_value_list: List[str] = None,
relation_trigger_field_list: List[str] = None,
relation_trigger_value_list: List[str] = None,
relation_show_field_dict: Dict = None,
relation_trigger_field_dict: Dict = None,
trigger_type: TriggerType = TriggerType.OPTION_LIST,
attrs: Dict[str, object] = None,
props_info: Dict[str, object] = None):
@ -35,10 +33,8 @@ class BaseField:
:param input_type: 字段
:param label: 提示
:param default_value: 默认值
:param relation_show_field_list: 指定那些当那些字段有值的时候 当前字段显示
:param relation_show_value_list: 指定字段有值 并且值在relation_show_value_list列表中则显示当前字段
:param relation_trigger_field_list: 指定那些字段有值的时候 调用当前字段的 执行函数获取optionList数据
:param relation_trigger_value_list: 指定那些字段有值 并且值在relation_trigger_value_list列表中 则执行函数获取optionList数据
:param relation_show_field_dict: {field:field_value_list} 表示在 field有值 ,并且值在field_value_list中才显示
:param relation_trigger_field_dict: {field:field_value_list} 表示在 field有值 ,并且值在field_value_list中才 执行函数获取 数据
:param trigger_type: 执行器类型 OPTION_LIST请求Option_list数据 CHILD_FORMS请求子表单
:param attrs: 前端attr数据
:param props_info: 其他额外信息
@ -52,10 +48,8 @@ class BaseField:
self.props_info = props_info
self.default_value = default_value
self.input_type = input_type
self.relation_show_field_list = [] if relation_show_field_list is None else relation_show_field_list
self.relation_show_value_list = [] if relation_show_value_list is None else relation_show_value_list
self.relation_trigger_field_list = [] if relation_trigger_field_list is None else relation_trigger_field_list
self.relation_trigger_value_field_list = [] if relation_trigger_value_list is None else relation_trigger_value_list
self.relation_show_field_dict = {} if relation_show_field_dict is None else relation_show_field_dict
self.relation_trigger_field_dict = [] if relation_trigger_field_dict is None else relation_trigger_field_dict
self.required = required
self.trigger_type = trigger_type
@ -65,10 +59,8 @@ class BaseField:
'label': self.label,
'required': self.required,
'default_value': self.default_value,
'relation_show_field_list': self.relation_show_field_list,
'relation_show_value_list': self.relation_show_value_list,
'relation_trigger_field_list': self.relation_trigger_field_list,
'relation_trigger_value_field_list': self.relation_trigger_value_field_list,
'relation_show_field_dict': self.relation_show_field_dict,
'relation_trigger_field_dict': self.relation_trigger_field_dict,
'trigger_type': self.trigger_type.value,
'attrs': self.attrs,
'props_info': self.props_info,
@ -83,8 +75,7 @@ class BaseDefaultOptionField(BaseField):
option_list: List[dict],
required: bool = False,
default_value: object = None,
relation_show_field_list: List[str] = None,
relation_show_value_list: List[str] = None,
relation_show_field_dict: Dict[str, object] = None,
attrs: Dict[str, object] = None,
props_info: Dict[str, object] = None):
"""
@ -96,13 +87,12 @@ class BaseDefaultOptionField(BaseField):
:param option_list: 可选列表
:param required: 是否必填
:param default_value: 默认值
:param relation_show_field_list: 指定那些当那些字段有值的时候 当前字段显示
:param relation_show_value_list: 指定字段有值 并且值在relation_show_value_list列表中则显示当前字段
:param relation_show_field_dict: {field:field_value_list} 表示在 field有值 ,并且值在field_value_list中才显示
:param attrs: 前端attr数据
:param props_info: 其他额外信息
"""
super().__init__(input_type, label, required, default_value, relation_show_field_list, relation_show_value_list,
[], [], TriggerType.OPTION_LIST, attrs, props_info)
super().__init__(input_type, label, required, default_value, relation_show_field_dict,
{}, TriggerType.OPTION_LIST, attrs, props_info)
self.text_field = text_field
self.value_field = value_field
self.option_list = option_list
@ -122,10 +112,8 @@ class BaseExecField(BaseField):
method: str,
required: bool = False,
default_value: object = None,
relation_show_field_list: List[str] = None,
relation_show_value_list: List[str] = None,
relation_trigger_field_list: List[str] = None,
relation_trigger_value_list: List[str] = None,
relation_show_field_dict: Dict = None,
relation_trigger_field_dict: Dict = None,
trigger_type: TriggerType = TriggerType.OPTION_LIST,
attrs: Dict[str, object] = None,
props_info: Dict[str, object] = None):
@ -139,16 +127,15 @@ class BaseExecField(BaseField):
:param method: 执行供应商函数 method
:param required: 是否必填
:param default_value: 默认值
:param relation_show_field_list: 指定那些当那些字段有值的时候 当前字段显示
:param relation_show_value_list: 指定字段有值 并且值在relation_show_value_list列表中则显示当前字段
:param relation_trigger_field_list: 指定那些字段有值的时候 调用当前字段的 执行函数获取optionList数据
:param relation_trigger_value_list: 指定那些字段有值 并且值在relation_trigger_value_list列表中 则执行函数获取optionList数据
:param relation_show_field_dict: {field:field_value_list} 表示在 field有值 ,并且值在field_value_list中才显示
:param relation_trigger_field_dict: {field:field_value_list} 表示在 field有值 ,并且值在field_value_list中才 执行函数获取 数据
:param trigger_type: 执行器类型 OPTION_LIST请求Option_list数据 CHILD_FORMS请求子表单
:param attrs: 前端attr数据
:param props_info: 其他额外信息
"""
super().__init__(input_type, label, required, default_value, relation_show_field_list, relation_show_value_list,
relation_trigger_field_list, relation_trigger_value_list, trigger_type, attrs, props_info)
super().__init__(input_type, label, required, default_value, relation_show_field_dict,
relation_trigger_field_dict,
trigger_type, attrs, props_info)
self.text_field = text_field
self.value_field = value_field
self.provider = provider

View File

@ -25,17 +25,14 @@ class MultiSelect(BaseExecField):
method: str = None,
required: bool = False,
default_value: object = None,
relation_show_field_list: List[str] = None,
relation_show_value_list: List[str] = None,
relation_trigger_field_list: List[str] = None,
relation_trigger_value_list: List[str] = None,
relation_show_field_dict: Dict = None,
relation_trigger_field_dict: Dict = None,
trigger_type: TriggerType = TriggerType.OPTION_LIST,
attrs: Dict[str, object] = None,
props_info: Dict[str, object] = None):
super().__init__("MultiSelect", label, text_field, value_field, provider, method, required, default_value,
relation_show_field_list, relation_show_value_list, relation_trigger_field_list,
relation_trigger_value_list, trigger_type, attrs, props_info)
relation_show_field_dict, relation_trigger_field_dict, trigger_type, attrs, props_info)
self.option_list = option_list
def to_dict(self):
return {**super().to_dict(), 'option_list': self.option_list}
return {**super().to_dict(), 'option_list': self.option_list}

View File

@ -1,27 +0,0 @@
# coding=utf-8
"""
@project: maxkb
@Author
@file number_input_field.py
@date2023/10/31 17:58
@desc:
"""
from typing import List
from common.froms.base_field import BaseField, TriggerType
class NumberInput(BaseField):
"""
文本输入框
"""
def __init__(self, label: str,
required: bool = False,
default_value=None,
relation_show_field_list: List[str] = None,
relation_show_value_list: List[str] = None,
attrs=None, props_info=None):
super().__init__('NumberInput', label, required, default_value, relation_show_field_list,
relation_show_value_list, [], [],
TriggerType.OPTION_LIST, attrs, props_info)

View File

@ -24,13 +24,10 @@ class ObjectCard(BaseExecField):
method: str,
required: bool = False,
default_value: object = None,
relation_show_field_list: List[str] = None,
relation_show_value_list: List[str] = None,
relation_trigger_field_list: List[str] = None,
relation_trigger_value_list: List[str] = None,
relation_show_field_dict: Dict = None,
relation_trigger_field_dict: Dict = None,
trigger_type: TriggerType = TriggerType.OPTION_LIST,
attrs: Dict[str, object] = None,
props_info: Dict[str, object] = None):
super().__init__("ObjectCard", label, text_field, value_field, provider, method, required, default_value,
relation_show_field_list, relation_show_value_list, relation_trigger_field_list,
relation_trigger_value_list, trigger_type, attrs, props_info)
relation_show_field_dict, relation_trigger_field_dict, trigger_type, attrs, props_info)

View File

@ -6,7 +6,7 @@
@date2023/11/1 14:48
@desc:
"""
from typing import List
from typing import List, Dict
from common.froms import BaseField, TriggerType
@ -19,9 +19,8 @@ class PasswordInputField(BaseField):
def __init__(self, label: str,
required: bool = False,
default_value=None,
relation_show_field_list: List[str] = None,
relation_show_value_list: List[str] = None,
relation_show_field_dict: Dict = None,
attrs=None, props_info=None):
super().__init__('TextInput', label, required, default_value, relation_show_field_list,
relation_show_value_list, [], [],
super().__init__('PasswordInput', label, required, default_value, relation_show_field_dict,
{},
TriggerType.OPTION_LIST, attrs, props_info)

View File

@ -2,7 +2,7 @@
"""
@project: maxkb
@Author
@file combobox_field.py
@file radio_field.py
@date2023/10/31 17:59
@desc:
"""
@ -11,9 +11,9 @@ from typing import List, Dict
from common.froms.base_field import BaseExecField, TriggerType
class Combobox(BaseExecField):
class Radio(BaseExecField):
"""
多选框
下拉单选
"""
def __init__(self,
@ -21,20 +21,17 @@ class Combobox(BaseExecField):
text_field: str,
value_field: str,
option_list: List[str:object],
provider: str = None,
method: str = None,
provider: str,
method: str,
required: bool = False,
default_value: object = None,
relation_show_field_list: List[str] = None,
relation_show_value_list: List[str] = None,
relation_trigger_field_list: List[str] = None,
relation_trigger_value_list: List[str] = None,
relation_show_field_dict: Dict = None,
relation_trigger_field_dict: Dict = None,
trigger_type: TriggerType = TriggerType.OPTION_LIST,
attrs: Dict[str, object] = None,
props_info: Dict[str, object] = None):
super().__init__("Combobox", label, text_field, value_field, provider, method, required, default_value,
relation_show_field_list, relation_show_value_list, relation_trigger_field_list,
relation_trigger_value_list, trigger_type, attrs, props_info)
super().__init__("RadioButton", label, text_field, value_field, provider, method, required, default_value,
relation_show_field_dict, relation_trigger_field_dict, trigger_type, attrs, props_info)
self.option_list = option_list
def to_dict(self):

View File

@ -0,0 +1,38 @@
# coding=utf-8
"""
@project: maxkb
@Author
@file radio_field.py
@date2023/10/31 17:59
@desc:
"""
from typing import List, Dict
from common.froms.base_field import BaseExecField, TriggerType
class Radio(BaseExecField):
"""
下拉单选
"""
def __init__(self,
label: str,
text_field: str,
value_field: str,
option_list: List[str:object],
provider: str,
method: str,
required: bool = False,
default_value: object = None,
relation_show_field_dict: Dict = None,
relation_trigger_field_dict: Dict = None,
trigger_type: TriggerType = TriggerType.OPTION_LIST,
attrs: Dict[str, object] = None,
props_info: Dict[str, object] = None):
super().__init__("RadioCard", label, text_field, value_field, provider, method, required, default_value,
relation_show_field_dict, relation_trigger_field_dict, trigger_type, attrs, props_info)
self.option_list = option_list
def to_dict(self):
return {**super().to_dict(), 'option_list': self.option_list}

View File

@ -25,17 +25,14 @@ class Radio(BaseExecField):
method: str,
required: bool = False,
default_value: object = None,
relation_show_field_list: List[str] = None,
relation_show_value_list: List[str] = None,
relation_trigger_field_list: List[str] = None,
relation_trigger_value_list: List[str] = None,
relation_show_field_dict: Dict = None,
relation_trigger_field_dict: Dict = None,
trigger_type: TriggerType = TriggerType.OPTION_LIST,
attrs: Dict[str, object] = None,
props_info: Dict[str, object] = None):
super().__init__("Radio", label, text_field, value_field, provider, method, required, default_value,
relation_show_field_list, relation_show_value_list, relation_trigger_field_list,
relation_trigger_value_list, trigger_type, attrs, props_info)
relation_show_field_dict, relation_trigger_field_dict, trigger_type, attrs, props_info)
self.option_list = option_list
def to_dict(self):
return {**super().to_dict(), 'option_list': self.option_list}
return {**super().to_dict(), 'option_list': self.option_list}

View File

@ -25,16 +25,13 @@ class SingleSelect(BaseExecField):
method: str = None,
required: bool = False,
default_value: object = None,
relation_show_field_list: List[str] = None,
relation_show_value_list: List[str] = None,
relation_trigger_field_list: List[str] = None,
relation_trigger_value_list: List[str] = None,
relation_show_field_dict: Dict = None,
relation_trigger_field_dict: Dict = None,
trigger_type: TriggerType = TriggerType.OPTION_LIST,
attrs: Dict[str, object] = None,
props_info: Dict[str, object] = None):
super().__init__("SingleSelect", label, text_field, value_field, provider, method, required, default_value,
relation_show_field_list, relation_show_value_list, relation_trigger_field_list,
relation_trigger_value_list, trigger_type, attrs, props_info)
relation_show_field_dict, relation_trigger_field_dict, trigger_type, attrs, props_info)
self.option_list = option_list
def to_dict(self):

View File

@ -1,28 +0,0 @@
# coding=utf-8
"""
@project: maxkb
@Author
@file switch_btn.py
@date2023/10/31 18:00
@desc:
"""
from typing import List
from common.froms.base_field import TriggerType, BaseField
class SwitchBtn(BaseField):
"""
开关
"""
def __init__(self,
label: str,
required: bool = False,
default_value=None,
relation_show_field_list: List[str] = None,
relation_show_value_list: List[str] = None,
attrs=None, props_info=None):
super().__init__('SwitchBtn', label, required, default_value, relation_show_field_list,
relation_show_value_list, [], [],
TriggerType.OPTION_LIST, attrs, props_info)

View File

@ -24,13 +24,10 @@ class TabCard(BaseExecField):
method: str,
required: bool = False,
default_value: object = None,
relation_show_field_list: List[str] = None,
relation_show_value_list: List[str] = None,
relation_trigger_field_list: List[str] = None,
relation_trigger_value_list: List[str] = None,
relation_show_field_dict: Dict = None,
relation_trigger_field_dict: Dict = None,
trigger_type: TriggerType = TriggerType.OPTION_LIST,
attrs: Dict[str, object] = None,
props_info: Dict[str, object] = None):
super().__init__("TabCard", label, text_field, value_field, provider, method, required, default_value,
relation_show_field_list, relation_show_value_list, relation_trigger_field_list,
relation_trigger_value_list, trigger_type, attrs, props_info)
relation_show_field_dict, relation_trigger_field_dict, trigger_type, attrs, props_info)

View File

@ -0,0 +1,33 @@
# coding=utf-8
"""
@project: maxkb
@Author
@file table_radio.py
@date2023/10/31 18:01
@desc:
"""
from typing import List, Dict
from common.froms.base_field import TriggerType, BaseExecField
class TableRadio(BaseExecField):
"""
table 单选
"""
def __init__(self,
label: str,
text_field: str,
value_field: str,
provider: str,
method: str,
required: bool = False,
default_value: object = None,
relation_show_field_dict: Dict = None,
relation_trigger_field_dict: Dict = None,
trigger_type: TriggerType = TriggerType.OPTION_LIST,
attrs: Dict[str, object] = None,
props_info: Dict[str, object] = None):
super().__init__("TableCheckbox", label, text_field, value_field, provider, method, required, default_value,
relation_show_field_dict, relation_trigger_field_dict, trigger_type, attrs, props_info)

View File

@ -24,13 +24,10 @@ class TableRadio(BaseExecField):
method: str,
required: bool = False,
default_value: object = None,
relation_show_field_list: List[str] = None,
relation_show_value_list: List[str] = None,
relation_trigger_field_list: List[str] = None,
relation_trigger_value_list: List[str] = None,
relation_show_field_dict: Dict = None,
relation_trigger_field_dict: Dict = None,
trigger_type: TriggerType = TriggerType.OPTION_LIST,
attrs: Dict[str, object] = None,
props_info: Dict[str, object] = None):
super().__init__("TableRadio", label, text_field, value_field, provider, method, required, default_value,
relation_show_field_list, relation_show_value_list, relation_trigger_field_list,
relation_trigger_value_list, trigger_type, attrs, props_info)
relation_show_field_dict, relation_trigger_field_dict, trigger_type, attrs, props_info)

View File

@ -6,7 +6,7 @@
@date2023/10/31 17:58
@desc:
"""
from typing import List
from typing import List, Dict
from common.froms.base_field import BaseField, TriggerType
@ -19,9 +19,9 @@ class TextInputField(BaseField):
def __init__(self, label: str,
required: bool = False,
default_value=None,
relation_show_field_list: List[str] = None,
relation_show_value_list: List[str] = None,
relation_show_field_dict: Dict = None,
attrs=None, props_info=None):
super().__init__('TextInput', label, required, default_value, relation_show_field_list,
relation_show_value_list, [], [],
super().__init__('TextInput', label, required, default_value, relation_show_field_dict,
{},
TriggerType.OPTION_LIST, attrs, props_info)

View File

@ -19,7 +19,8 @@
"nprogress": "^0.2.0",
"pinia": "^2.1.6",
"vue": "^3.3.4",
"vue-router": "^4.2.4"
"vue-router": "^4.2.4",
"mitt": "^3.0.0"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.3.2",

12
ui/src/api/provider.ts Normal file
View File

@ -0,0 +1,12 @@
import { Result } from '@/request/Result'
import { get, post } from '@/request/index'
import type { Ref } from 'vue'
const trigger: (
provider: string,
method: string,
request_body: any,
loading?: Ref<boolean>
) => Promise<Result<Array<any> | string>> = (provider, method, request_body, loading) => {
return post(`provider/${provider}/${method}`, {}, request_body, loading)
}
export default { trigger, get }

8
ui/src/bus/index.ts Normal file
View File

@ -0,0 +1,8 @@
import mitt from "mitt";
const bus: any = {};
const emitter = mitt();
bus.on = emitter.on;
bus.off = emitter.off;
bus.emit = emitter.emit;
export default bus;

View File

@ -0,0 +1,278 @@
<template>
<div style="width: 1024px">
<DynamicsForm v-model="form_data" :render_data="damo_data" ref="dynamicsFormRef">
<template #default="scope">
<el-form-item label="其他字段">
<el-input v-model="scope.form_value['zha']" /> </el-form-item
></template>
</DynamicsForm>
<el-button @click="click">点我校验</el-button>
</div>
</template>
<script setup lang="ts">
import type { FormField } from '@/components/dynamics-form/type'
import DynamicsForm from '@/components/dynamics-form/index.vue'
import { ref } from 'vue'
import type { Dict } from '@/api/type/common'
const damo_data: Array<FormField> = [
{ field: 'name', input_type: 'PasswordInput', label: '用戶名', required: false },
{
field: 'array_object_card_field',
input_type: 'ArrayObjectCard',
label: '測試',
trigger_type: 'CHILD_FORMS',
attrs: { 'label-width': '120px', 'label-suffix': ':ssss', 'label-position': 'top' },
required: false,
children: [
{ field: 'name1', input_type: 'TextInput', label: '用戶名1' },
{ field: 'name2', input_type: 'TextInput', label: '用戶名2' },
{ field: 'name3', input_type: 'TextInput', label: '用戶名3' }
]
},
{
field: 'object_card_field',
input_type: 'ObjectCard',
label: '測試',
trigger_type: 'CHILD_FORMS',
attrs: { 'label-width': '120px', 'label-suffix': ':ssss', 'label-position': 'left' },
required: false,
children: [
{ field: 'name1', input_type: 'TextInput', label: '用戶名1' },
{ field: 'name2', input_type: 'TextInput', label: '用戶名2' },
{ field: 'name3', input_type: 'TextInput', label: '用戶名3' }
]
},
{
field: 'tab_card_field',
input_type: 'TabCard',
label: '測試',
trigger_type: 'CHILD_FORMS',
attrs: { 'label-width': '120px', 'label-suffix': ':ssss', 'label-position': 'left' },
required: false,
relation_trigger_field_dict: {
'array_object_card_field.0.name1': ['111']
},
props_info: { tabs_label: '用户' },
children: [
{ field: 'name1', input_type: 'TextInput', label: '用戶名1' },
{ field: 'name2', input_type: 'TextInput', label: '用戶名2' },
{ field: 'name3', input_type: 'TextInput', label: '用戶名3' }
]
},
{
field: 'single_select_field',
input_type: 'SingleSelect',
label: '测试单选',
required: true,
attrs: { placeholder: '请选择' },
option_list: [
{
key: '测试',
value: 'test'
},
{
key: '测试1',
value: 'test1'
}
]
},
{
field: 'multi_select_field',
input_type: 'MultiSelect',
default_value: ['test1'],
relation_show_field_dict: {
'object_card_field.name1': []
},
label: '测试多选下拉',
required: true,
attrs: { placeholder: '请选择' },
option_list: [
{
key: '测试',
value: 'test'
},
{
key: '测试1',
value: 'test1'
}
]
},
{
field: 'radio_field',
input_type: 'Radio',
label: '测试单选',
required: true,
attrs: { placeholder: '请选择' },
option_list: [
{
key: '测试',
value: 'test'
},
{
key: '测试1',
value: 'test1'
}
]
},
{
field: 'radio_button_field',
input_type: 'RadioButton',
label: '测试单选',
required: true,
attrs: { placeholder: '请选择' },
option_list: [
{
key: '测试',
value: 'test'
},
{
key: '测试1',
value: 'test1'
}
]
},
{
field: 'radio_card_field',
input_type: 'RadioCard',
label: '测试单选1',
required: true,
attrs: { placeholder: '请选择' },
option_list: [
{
key: '测试',
value: 'test'
},
{
key: '测试111111',
value: 'test1'
}
]
},
{
field: 'table_radio_field',
input_type: 'TableRadio',
label: '表格单选',
required: true,
attrs: { placeholder: '请选择' },
props_info: {
active_msg: '当前选中',
table_columns: [
{
property: '`${row.key}${row.number}`',
label: '名称',
type: 'eval'
},
{
property: 'ProgressTableItem',
label: '数值',
type: 'component',
value_field: 'number',
attrs: {
color: [
{ color: '#f56c6c', percentage: 20 },
{ color: '#e6a23c', percentage: 40 },
{ color: '#5cb87a', percentage: 60 },
{ color: '#1989fa', percentage: 80 },
{ color: '#6f7ad3', percentage: 100 }
]
},
props_info: {
view_card: [
{
type: 'eval',
title: '测试',
value_field:
'`${parseFloat(row.number).toLocaleString("zh-CN",{style: "decimal",maximumFractionDigits:1})}%&nbsp;&nbsp;&nbsp;`'
},
{
type: 'eval',
title: '名称',
value_field: '`${row.key}&nbsp;&nbsp;&nbsp;`'
}
]
}
}
],
style: { width: '500px' }
},
option_list: [
{
key: '测试',
value: 'test',
number: 10
},
{
key: '测试111111',
value: 'test1',
number: 100
}
]
},
{
field: 'table_checkbox_field',
input_type: 'TableCheckbox',
label: '表格多选',
required: true,
attrs: { placeholder: '请选择' },
props_info: {
active_msg: '当前选中',
table_columns: [
{
property: '`${row.key}${row.number}`',
label: '名称',
type: 'eval'
},
{
property: 'ProgressTableItem',
label: '数值',
type: 'component',
value_field: 'number',
attrs: {
color: [
{ color: '#f56c6c', percentage: 20 },
{ color: '#e6a23c', percentage: 40 },
{ color: '#5cb87a', percentage: 60 },
{ color: '#1989fa', percentage: 80 },
{ color: '#6f7ad3', percentage: 100 }
]
},
props_info: {
view_card: [
{
type: 'eval',
title: '测试',
value_field:
'`${parseFloat(row.number).toLocaleString("zh-CN",{style: "decimal",maximumFractionDigits:1})}%&nbsp;&nbsp;&nbsp;`'
},
{
type: 'eval',
title: '名称',
value_field: '`${row.key}&nbsp;&nbsp;&nbsp;`'
}
]
}
}
],
style: { width: '500px' }
},
option_list: [
{
key: '测试',
value: 'test',
number: 10
},
{
key: '测试111111',
value: 'test1',
number: 100
}
]
}
]
const form_data = ref<Dict<any>>({})
const dynamicsFormRef = ref<InstanceType<typeof DynamicsForm>>()
const click = () => {
dynamicsFormRef.value?.validate()
}
</script>
<style lang="scss" scope></style>

View File

@ -0,0 +1,155 @@
<template>
<el-form-item
v-loading="loading"
:style="formItemStyle"
:label="formfield.label"
:prop="formfield.field"
:key="formfield.field"
:rules="rules"
>
<template #label v-if="formfield.label">
<FormItemLabel :form-field="formfield"></FormItemLabel>
</template>
<component
ref="componentFormRef"
:view="view"
v-model="itemValue"
:is="formfield.input_type"
:form-field="formfield"
:other-params="otherParams"
:style="componentStyle"
:field="formfield.field"
v-bind="attrs"
:formfield-list="formfieldList"
></component>
</el-form-item>
</template>
<script setup lang="ts">
import { ref, computed, onMounted, type Ref } from 'vue'
import type { FormField } from '@/components/dynamics-form/type'
import FormItemLabel from './FormItemLabel.vue'
import type { Dict } from '@/api/type/common'
import bus from '@/bus'
const props = defineProps<{
//
modelValue: any
// Item
formfield: FormField
//
view: boolean
//
otherParams: any
// Options
trigger: (formItem: FormField, loading: Ref<boolean>) => Promise<any>
//
initDefaultData: (formItem: FormField) => void
//
defaultItemWidth: string
//
formValue: Dict<any>
formfieldList: Array<FormField>
parent_field?: string
}>()
const emit = defineEmits(['change'])
const loading = ref<boolean>(false)
const itemValue = computed({
get: () => {
return props.modelValue
},
set: (value: any) => {
emit('change', value)
if (props.parent_field) {
bus.emit(props.parent_field + '.' + props.formfield.field, value)
} else {
bus.emit(props.formfield.field, value)
}
}
})
const componentFormRef = ref<any>()
const props_info = computed(() => {
return props.formfield.props_info ? props.formfield.props_info : {}
})
/**
* 表单 item style
*/
const formItemStyle = computed(() => {
return props_info.value.item_style ? props_info.value.item_style : {}
})
/**
* 表单错误Msg
*/
const errMsg = computed(() => {
return props_info.value.err_msg ? props_info.value.err_msg : props.formfield.label + '不能为空'
})
/**
* 校验
*/
const rules = computed(() => {
return props_info.value.rules
? props_info.value.rules
: {
message: errMsg.value,
trigger: 'blur',
required: props.formfield.required === false ? false : true
}
})
/**
* 组件样式
*/
const componentStyle = computed(() => {
return props_info.value.style ? props_info.value.style : {}
})
/**
* 组件attrs
*/
const attrs = computed(() => {
return props.formfield.attrs ? props.formfield.attrs : {}
})
onMounted(() => {
props.initDefaultData(props.formfield)
if (props.formfield.provider && props.formfield.method) {
props.trigger(props.formfield, loading)
}
//
const trigger_field_dict = props.formfield.relation_trigger_field_dict
if (trigger_field_dict) {
const keys = Object.keys(trigger_field_dict)
keys.forEach((key) => {
const value = trigger_field_dict[key]
//
bus.on(key, (v: any) => {
if (value && value.length > 0) {
if (value.includes(v)) {
console.log('符合情况,即将获取数据', key, v)
props.trigger(props.formfield, loading)
}
} else {
console.log('符合情况,即将获取数据', key, v)
props.trigger(props.formfield, loading)
}
})
})
}
})
const validate = () => {
if (props.formfield.trigger_type === 'CHILD_FORMS' && componentFormRef.value) {
return componentFormRef.value.validate()
}
return Promise.resolve()
}
defineExpose({ validate })
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,11 @@
<template>
{{ formField.label }}
</template>
<script setup lang="ts">
import type { FormField } from '@/components/dynamics-form/type'
const props = defineProps<{
// Item
formField: FormField
}>()
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,23 @@
import type { App } from 'vue'
import type { Dict } from '@/api/type/common'
import DynamicsForm from '@/components/dynamics-form/index.vue'
let components: Dict<any> = import.meta.glob('@/components/dynamics-form/**/**.vue', {
eager: true
})
components = {
...components,
...import.meta.glob('@/components/dynamics-form/**/**/**.vue', {
eager: true
})
}
const install = (app: App) => {
Object.keys(components).forEach((key: string) => {
const commentName: string = key
.substring(key.lastIndexOf('/') + 1, key.length)
.replace('.vue', '')
app.component(commentName, components[key].default)
})
app.component('DynamicsForm', DynamicsForm)
}
export default { install }

View File

@ -0,0 +1,175 @@
<template>
<el-form
@submit.prevent
ref="ruleFormRef"
label-width="130px"
label-suffix=":"
v-loading="loading"
v-bind="$attrs"
:model="formValue"
>
<slot :form_value="formValue"></slot>
<template v-for="item in formFieldList" :key="item.field">
<FormItem
ref="formFieldRef"
:key="item.field"
v-if="show(item)"
@change="change(item, $event)"
v-bind:modelValue="formValue[item.field]"
:formfield="item"
:trigger="trigger"
:view="view"
:initDefaultData="initDefaultData"
:defaultItemWidth="defaultItemWidth"
:other-params="otherParams"
:form-value="formValue"
:formfield-list="formFieldList"
:parent_field="parent_field"
>
</FormItem>
</template>
</el-form>
</template>
<script lang="ts" setup>
import type { Dict } from '@/api/type/common'
import FormItem from '@/components/dynamics-form/FormItem.vue'
import type { FormField } from '@/components/dynamics-form/type'
import { ref, onMounted, type Ref } from 'vue'
import type { FormInstance } from 'element-plus'
import triggerApi from '@/api/provider'
import type Result from '@/request/Result'
import _ from 'lodash'
const props = withDefaults(
defineProps<{
//
render_data: Promise<Result<Array<FormField>>> | string | Array<FormField>
//
otherParams?: any
//
view?: boolean
//
defaultItemWidth?: string
parent_field?: string
}>(),
{ view: false, defaultItemWidth: '75%', otherParams: () => {} }
)
const formValue = ref<Dict<any>>({})
const loading = ref<boolean>(false)
const formFieldList = ref<Array<FormField>>([])
const ruleFormRef = ref<FormInstance>()
const formFieldRef = ref<Array<InstanceType<typeof FormItem>>>([])
/**
* 当前 field是否展示
* @param field
*/
const show = (field: FormField) => {
if (field.relation_show_field_dict) {
let keys = Object.keys(field.relation_show_field_dict)
for (const index in keys) {
const key = keys[index]
let v = _.get(formValue.value, key)
console.log(v, key)
if (v && v !== undefined && v !== null) {
let values = field.relation_show_field_dict[key]
if (values && values.length > 0) {
return values.includes(v)
} else {
return true
}
} else {
return false
}
}
}
return true
}
const emit = defineEmits(['update:modelValue'])
/**
* 表单字段修改
* @param field
* @param value
*/
const change = (field: FormField, value: any) => {
formValue.value[field.field] = value
emit('update:modelValue', formValue.value)
}
/**
* 触发器,用户获取子表单 或者 下拉选项
* @param field
* @param loading
*/
const trigger = (field: FormField, loading: Ref<boolean>) => {
if (field.provider && field.method) {
return triggerApi
.trigger(
field.provider,
field.method,
{
...props.otherParams,
...formValue.value
},
loading
)
.then((ok) => {
if (field.trigger_type === 'CHILD_FORMS') {
field.children = ok.data as Array<FormField>
} else {
field.option_list = ok.data as Array<any>
}
})
}
return Promise.resolve([])
}
/**
* 初始化默认数据
*/
const initDefaultData = (formField: FormField) => {
if (
formField.default_value &&
(formValue.value[formField.field] === undefined ||
formValue.value[formField.field] === null ||
!formValue.value[formField.field])
) {
formValue.value[formField.field] = formField.default_value
}
}
onMounted(() => {
if (typeof props.render_data == 'string') {
triggerApi.get(props.render_data, {}, loading).then((ok) => {
formFieldList.value = ok.data
})
} else if (props.render_data instanceof Array) {
formFieldList.value = props.render_data
} else {
props.render_data.then((ok) => {
formFieldList.value = ok.data
})
}
})
/**
* 校验函数
*/
const validate = () => {
return Promise.all([
...formFieldRef.value.map((item) => item.validate()),
ruleFormRef.value ? ruleFormRef.value.validate() : Promise.resolve()
])
}
//
defineExpose({
initDefaultData,
validate,
ruleFormRef
})
</script>
<style lang="scss" scope></style>

View File

@ -0,0 +1,5 @@
<template>
<el-input v-bind="$attrs" :show-password="true"></el-input>
</template>
<script setup lang="ts"></script>
<style lang="scss"></style>

View File

@ -0,0 +1,5 @@
<template>
<el-input v-bind="$attrs" />
</template>
<script setup lang="ts"></script>
<style lang="scss"></style>

View File

@ -0,0 +1,161 @@
<template v-loading="_loading">
<div style="width: 100%; display: flex; flex-wrap: wrap">
<el-card class="box-card" :style="style" v-for="(item, index) in _data" :key="index">
<DynamicsForm
:style="formStyle"
:view="view"
label-position="top"
require-asterisk-position="right"
ref="ceFormRef"
v-model="_data[index]"
:other-params="other"
:render_data="render_data()"
v-bind="attr"
:parent_field="formField.field + '.' + index"
></DynamicsForm>
<el-tooltip effect="dark" content="删除" placement="top">
<el-button text @click.stop="deleteDateset(item)" class="delete-button">
<el-icon><Delete /></el-icon>
</el-button>
</el-tooltip>
</el-card>
<el-card shadow="never" class="card-add box-card" @click="add_card">
<div class="flex-center">
<AppIcon iconName="Plus" class="add-icon p-8" />
<span>{{ add_msg }}</span>
</div>
</el-card>
</div>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import _ from 'lodash'
import type { FormField } from '@/components/dynamics-form/type'
import DynamicsForm from '@/components/dynamics-form/index.vue'
import Result from '@/request/Result'
const props = defineProps<{
modelValue?: Array<any>
formValue?: any
formfieldList?: Array<FormField>
field: string
otherParams: any
formField: FormField
view?: boolean
}>()
const render_data = () => {
return Promise.resolve(Result.success(props.formField.children as Array<FormField>))
}
const deleteDateset = (item: any) => {
_data.value = _data.value.filter((row) => row !== item)
}
const emit = defineEmits(['update:modelValue', 'change'])
//
const dynamicsFormRef = ref<Array<InstanceType<typeof DynamicsForm>>>([])
const _data = computed<Array<any>>({
get() {
if (props.modelValue) {
return props.modelValue
} else {
emit('update:modelValue', [{}])
return []
}
},
set(value) {
emit('update:modelValue', value)
}
})
const props_info = computed(() => {
return props.formField.props_info ? props.formField.props_info : {}
})
const add_msg = computed(() => {
return props_info.value.add_msg ? props_info.value.add_msg : '添加'
})
/**
* 添加一个card
*/
const add_card = () => {
_data.value = [..._data.value, {}]
}
/**
* 组件样式
*/
const formStyle = computed(() => {
return props_info.value.form_style ? props_info.value.form_style : {}
})
const style = computed(() => {
return props_info.value.style ? props_info.value.style : {}
})
const attr = computed(() => {
if (props.formField.attrs) {
return props.formField.attrs
}
return {}
})
/**
* 校验方法
*/
function validate() {
return Promise.all(dynamicsFormRef.value.map((item) => item.validate()))
}
const other = computed(() => {
return { ...(props.formValue ? props.formValue : {}), ...props.otherParams }
})
defineExpose({
validate,
field: props.field
})
</script>
<style lang="scss" scoped>
.box-card {
width: 30%;
position: relative;
margin: 10px;
padding-top: 20px;
}
.card-add {
display: inline-flex;
justify-content: center;
align-items: center;
font-size: 16px;
cursor: pointer;
min-height: var(--card-min-height);
border: 1px dashed var(--el-color-primary);
background: #eff0f1;
padding-bottom: 20px;
.add-icon {
font-size: 14px;
border-radius: 4px;
border: 1px solid var(--app-border-color-dark);
background: var(--app-layout-bg-color);
margin-right: 12px;
}
&:hover {
color: var(--el-color-primary);
background: #ffffff;
.add-icon {
background: #ffffff;
border-color: var(--el-color-primary);
}
}
}
:deep(.el-form-item) {
&:last-child {
margin-bottom: 0px;
}
margin-bottom: 18px;
}
.delete-button {
position: absolute;
right: 12px;
top: 10px;
height: auto;
}
</style>

View File

@ -0,0 +1,82 @@
<template>
<el-card class="box-card" :style="style">
<DynamicsForm
:read-only="view"
:style="formStyle"
label-position="top"
require-asterisk-position="right"
ref="dynamicsFormRef"
v-model="data"
:other-params="other"
:render_data="formField.children ? formField.children : []"
v-bind="$attrs"
:parent_field="formField.field"
></DynamicsForm>
</el-card>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import type { FormField } from '@/components/dynamics-form/type'
import DynamicsForm from '@/components/dynamics-form/index.vue'
const emit = defineEmits(['update:modelValue', 'change'])
const props = defineProps<{
modelValue?: any
formValue?: any
formfieldList?: Array<FormField>
otherParams: any
formField: FormField
view?: boolean
}>()
const data = computed({
get: () => {
if (props.modelValue) {
return props.modelValue
}
return {}
},
set: ($event) => {
emit('update:modelValue', $event)
}
})
const other = computed(() => {
return { ...(props.formfieldList ? props.formfieldList : {}), ...props.otherParams }
})
//
const dynamicsFormRef = ref<InstanceType<typeof DynamicsForm>>()
/**
* 组件样式
*/
const formStyle = computed(() => {
return props_info.value.form_style ? props_info.value.form_style : {}
})
const props_info = computed(() => {
return props.formField.props_info ? props.formField.props_info : {}
})
const style = computed(() => {
return props_info.value.style ? props_info.value.style : {}
})
/**
* 校验方法
*/
function validate() {
if (dynamicsFormRef.value) {
return dynamicsFormRef.value.validate()
}
return Promise.resolve()
}
defineExpose({
validate
})
</script>
<style lang="scss" scoped>
:deep(.el-form-item) {
&:last-child {
margin-bottom: 0px;
}
margin-bottom: 18px;
}
</style>

View File

@ -0,0 +1,129 @@
<template v-loading="_loading">
<div style="width: 100%">
<el-tabs v-model="activeTab" editable @edit="handleTabsEdit" type="card">
<el-tab-pane
v-for="(item, index) in _data"
:key="index"
:label="tabs_label + (index + 1)"
:name="index"
>
<template v-if="formField.children">
<el-card class="box-card" :style="style">
<DynamicsForm
:style="formStyle"
:view="view"
label-position="top"
require-asterisk-position="right"
ref="ceFormRef"
v-model="_data[index]"
:other-params="other"
:render_data="render_data()"
v-bind="attr"
:parent_field="formField.field + '.' + index"
></DynamicsForm>
</el-card>
</template>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import _ from 'lodash'
import type { FormField } from '@/components/dynamics-form/type'
import DynamicsForm from '@/components/dynamics-form/index.vue'
import Result from '@/request/Result'
import type { TabPaneName } from 'element-plus'
const props = defineProps<{
modelValue?: Array<any>
formValue?: any
formfieldList?: Array<FormField>
field: string
otherParams: any
formField: FormField
view?: boolean
}>()
const render_data = () => {
return Promise.resolve(Result.success(props.formField.children as Array<FormField>))
}
const emit = defineEmits(['update:modelValue', 'change'])
//
const dynamicsFormRef = ref<Array<InstanceType<typeof DynamicsForm>>>([])
const _data = computed<Array<any>>({
get() {
if (props.modelValue) {
return props.modelValue
} else {
emit('update:modelValue', [{}])
return []
}
},
set(value) {
emit('update:modelValue', value)
}
})
const props_info = computed(() => {
return props.formField.props_info ? props.formField.props_info : {}
})
const tabs_label = computed(() => {
return props_info.value.tabs_label ? props_info.value.tabs_label : 'label'
})
/**
* 组件样式
*/
const formStyle = computed(() => {
return props_info.value.form_style ? props_info.value.form_style : {}
})
const attr = computed(() => {
if (props.formField.attrs) {
return props.formField.attrs
}
return {}
})
const activeTab = ref(0)
/**
* 校验方法
*/
function validate() {
return Promise.all(dynamicsFormRef.value.map((item) => item.validate()))
}
const other = computed(() => {
return { ...(props.formValue ? props.formValue : {}), ...props.otherParams }
})
const style = computed(() => {
return props_info.value.style ? props_info.value.style : {}
})
const handleTabsEdit = (targetName: TabPaneName | undefined, action: 'remove' | 'add') => {
if (action === 'add') {
_data.value = [..._data.value, {}]
activeTab.value = _data.value.length
} else if (action === 'remove') {
const update_value = _data.value.filter((item, index) => index != targetName)
_data.value = update_value
activeTab.value = update_value.length - 1
}
}
defineExpose({
validate,
field: props.field
})
</script>
<style lang="scss" scoped>
:deep(.el-form-item) {
&:last-child {
margin-bottom: 0px;
}
margin-bottom: 18px;
}
</style>

View File

@ -0,0 +1,38 @@
<template>
<el-radio-group v-bind="$attrs">
<el-radio v-for="(item, index) in option_list" :key="index" :label="item[valueField]">
<div v-html="label(item)"></div>
</el-radio>
</el-radio-group>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import type { FormField } from '@/components/dynamics-form/type'
import _ from 'lodash'
const props = defineProps<{
formValue?: any
formfieldList?: Array<FormField>
field: string
otherParams: any
formField: FormField
view?: boolean
}>()
const textField = computed(() => {
return props.formField.text_field ? props.formField.text_field : 'key'
})
const valueField = computed(() => {
return props.formField.value_field ? props.formField.value_field : 'value'
})
const option_list = computed(() => {
return props.formField.option_list ? props.formField.option_list : []
})
const label = (option: any) => {
return option[textField.value]
}
</script>
<style lang="scss"></style>

View File

@ -0,0 +1,38 @@
<template>
<el-radio-group v-bind="$attrs">
<el-radio-button v-for="(item, index) in option_list" :key="index" :label="item[valueField]">
<div v-html="label(item)"></div>
</el-radio-button>
</el-radio-group>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import type { FormField } from '@/components/dynamics-form/type'
import _ from 'lodash'
const props = defineProps<{
formValue?: any
formfieldList?: Array<FormField>
field: string
otherParams: any
formField: FormField
view?: boolean
}>()
const textField = computed(() => {
return props.formField.text_field ? props.formField.text_field : 'key'
})
const valueField = computed(() => {
return props.formField.value_field ? props.formField.value_field : 'value'
})
const option_list = computed(() => {
return props.formField.option_list ? props.formField.option_list : []
})
const label = (option: any) => {
return option[textField.value]
}
</script>
<style lang="scss"></style>

View File

@ -0,0 +1,92 @@
<template>
<div class="radio_content">
<div
v-for="item in option_list"
:key="item.value"
class="item"
:class="[modelValue == item[valueField] ? 'active' : '']"
@click="selected(item[valueField])"
>
{{ item[textField] }}
</div>
</div>
</template>
<script lang="ts" setup>
import { watch, computed } from 'vue'
import type { FormField } from '@/components/dynamics-form/type'
const props = defineProps<{
formValue?: any
formfieldList?: Array<FormField>
field: string
otherParams: any
formField: FormField
view?: boolean
//
modelValue?: any
}>()
const selected = (activeValue: string | number) => {
emit('update:modelValue', activeValue)
}
const emit = defineEmits(['update:modelValue'])
const textField = computed(() => {
return props.formField.text_field ? props.formField.text_field : 'key'
})
const valueField = computed(() => {
return props.formField.value_field ? props.formField.value_field : 'value'
})
const option_list = computed(() => {
return props.formField.option_list ? props.formField.option_list : []
})
watch(
option_list,
() => {
if (
(option_list.value &&
option_list.value.length > 0 &&
!option_list.value.some((item) => item.value === props.modelValue)) ||
!props.modelValue
) {
emit('update:modelValue', option_list.value[0][valueField.value])
}
},
{ immediate: true }
)
</script>
<style lang="scss" scoped>
.radio_content {
height: 32px;
display: inline-flex;
border: 1px solid #bbbfc4;
border-radius: 4px;
font-weight: 400;
font-size: 14px;
color: #1f2329;
padding: 3px 4px;
box-sizing: border-box;
.active {
border-radius: 4px;
background: rgba(51, 112, 255, 0.1);
color: #3370ff;
}
.item {
cursor: pointer;
margin: 0px 2px;
padding: 2px 8px;
height: 20px;
display: flex;
justify-content: center;
align-items: center;
&:last-child {
margin: 0 4px 0 2px;
}
&:first-child {
margin: 0 2px 0 4px;
}
}
}
</style>

View File

@ -0,0 +1,65 @@
<template>
<el-select
class="m-2"
multiple
collapse-tags
filterable
clearable
v-bind="$attrs"
v-model="_modelValue"
>
<el-option
v-for="(item, index) in option_list"
:key="index"
:label="label(item)"
:value="item[valueField]"
>
</el-option>
</el-select>
</template>
<script setup lang="ts">
import type { FormField } from '@/components/dynamics-form/type'
import { computed, ref } from 'vue'
import _ from 'lodash'
const rowTemp = ref<any>()
const props = defineProps<{
modelValue?: Array<any>
formValue?: any
formfieldList?: Array<FormField>
field: string
otherParams: any
formField: FormField
view?: boolean
}>()
const emit = defineEmits(['update:modelValue', 'change'])
const _modelValue = computed({
get() {
if (props.modelValue) {
return props.modelValue
}
return []
},
set($event) {
emit('update:modelValue', $event)
}
})
const textField = computed(() => {
return props.formField.text_field ? props.formField.text_field : 'key'
})
const valueField = computed(() => {
return props.formField.value_field ? props.formField.value_field : 'value'
})
const option_list = computed(() => {
return props.formField.option_list ? props.formField.option_list : []
})
const label = (option: any) => {
return option[textField.value]
}
</script>
<style lang="scss"></style>

View File

@ -0,0 +1,63 @@
<template>
<el-select class="m-2" filterable clearable v-bind="$attrs" v-model="_modelValue">
<el-option
v-for="(item, index) in option_list"
:key="index"
:label="label(item)"
:value="item[valueField]"
>
</el-option>
</el-select>
</template>
<script setup lang="ts">
import type { FormField } from '@/components/dynamics-form/type'
import { computed, ref } from 'vue'
import _ from 'lodash'
const rowTemp = ref<any>()
const props = defineProps<{
modelValue?: string
formValue?: any
formfieldList?: Array<FormField>
field: string
otherParams: any
formField: FormField
view?: boolean
}>()
const emit = defineEmits(['update:modelValue', 'change'])
const _modelValue = computed({
get() {
return props.modelValue
},
set(value) {
emit('update:modelValue', value)
emit('change', props.formField)
}
})
const textField = computed(() => {
return props.formField.text_field ? props.formField.text_field : 'key'
})
const valueField = computed(() => {
return props.formField.value_field ? props.formField.value_field : 'value'
})
const option_list = computed(() => {
return props.formField.option_list ? props.formField.option_list : []
})
const label = (option: any) => {
//
if (props.modelValue && option_list.value) {
const oldItem = option_list.value.find((item) => item[valueField.value] === props.modelValue)
if (!oldItem) {
emit('update:modelValue', undefined)
}
}
return option[textField.value]
}
</script>
<style lang="scss"></style>

View File

@ -0,0 +1,68 @@
<template>
<div>
<el-popover placement="top-start" :title="row[text_field]" :width="200" trigger="hover">
<template #reference>
<el-progress v-bind="$attrs" :percentage="row[value_field]"></el-progress
></template>
<div>
<el-row v-for="item in view_card"
><el-col :span="6">{{ item.title }}</el-col
><el-col :span="18"> <span class="value" :innerHTML="value_html(item)"> </span></el-col
></el-row>
</div>
</el-popover>
</div>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
const props = defineProps<{
/**
*表单渲染Item column
*/
column: any
/**
* 这一行数据
*/
row: any
}>()
const rowRef = ref<any>()
function evalF(text: string, row: any) {
rowRef.value = row
return eval(text)
}
const props_info = computed(() => {
return props.column.props_info ? props.column.props_info : {}
})
const text_field = computed(() => {
return props.column.text_field ? props.column.text_field : 'key'
})
const value_field = computed(() => {
return props.column.value_field ? props.column.value_field : 'value'
})
const value_html = (view_card_item: any) => {
if (view_card_item.type === 'eval') {
return evalF(view_card_item.value_field, props.row)
} else {
return props.row[view_card_item.value_field]
}
}
const view_card = computed(() => {
return props_info.value.view_card ? props_info.value.view_card : []
})
</script>
<style lang="scss" scoped>
@mixin valueScss() {
color: rgba(31, 35, 41, 1);
font-weight: 500;
font-size: 12px;
line-height: 22px;
height: 22px;
}
.value {
float: right;
@include valueScss;
}
</style>

View File

@ -0,0 +1,211 @@
<template>
<div>
<div class="header">
<div class="title">{{ title }}</div>
<el-input
v-model="filterText"
:validate-event="false"
placeholder="请输入关键字搜索"
class="input-with-select"
style="--el-color-danger: #c0c4cc"
>
<template #prepend>
<el-button :icon="Search" />
</template>
</el-input>
</div>
<el-table
ref="multipleTableRef"
:data="tableData"
highlight-current-row
style="width: 100%; height: 100%; --el-bg-color: #f5f6f7"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" />
<el-table-column
v-for="(column, index) in tableColumns"
:key="index"
v-bind="column"
:label="column.label"
>
<template #default="scope">
<template v-if="column.type === 'component'">
<TableColumn :column="column" :row="scope.row"></TableColumn>
</template>
<template v-else-if="column.type === 'eval'">
<span v-html="evalF(column.property, scope.row)"></span
></template>
<template v-else>
<span>{{ scope.row[column.property] }}</span></template
>
</template>
</el-table-column>
</el-table>
<div class="msg" v-show="props.modelValue">
{{ activeMsg }}
<span class="active">
{{ activeText }}
</span>
</div>
</div>
</template>
<script setup lang="ts">
import type { FormField } from '@/components/dynamics-form/type'
import { computed, ref, watch } from 'vue'
import { Search } from '@element-plus/icons-vue'
import type { ElTable } from 'element-plus'
import _ from 'lodash'
import TableColumn from '@/components/dynamics-form/items/table/TableColumn.vue'
const filterText = ref<string>('')
const props = defineProps<{
formValue?: any
formfieldList?: Array<FormField>
field: string
otherParams: any
formField: FormField
view?: boolean
//
modelValue?: Array<any>
}>()
const rowTemp = ref<any>()
const evalF = (text: string, row: any) => {
rowTemp.value = row
return eval(text)
}
const emit = defineEmits(['update:modelValue', 'change'])
const multipleTableRef = ref<InstanceType<typeof ElTable>>()
const _data = computed({
get() {
return props.modelValue
},
set(value) {
emit('update:modelValue', value)
emit('change', props.formField)
}
})
const handleSelectionChange = (val: any[]) => {
_data.value = val.map((row) => row[valueField.value])
}
const propsInfo = computed(() => {
return props.formField.props_info ? props.formField.props_info : {}
})
const activeMsg = computed(() => {
return propsInfo.value.active_msg ? propsInfo.value.active_msg : ''
})
const title = computed(() => {
return propsInfo.value.title ? propsInfo.value.title : ''
})
const tableColumns = computed(() => {
return propsInfo.value.table_columns ? propsInfo.value.table_columns : []
})
const option_list = computed(() => {
return props.formField.option_list ? props.formField.option_list : []
})
const textField = computed(() => {
return props.formField.text_field ? props.formField.text_field : 'key'
})
const valueField = computed(() => {
return props.formField.value_field ? props.formField.value_field : 'value'
})
const tableData = computed(() => {
if (option_list.value) {
if (filterText.value) {
return option_list.value.filter((item: any) =>
tableColumns.value.some((c: any) => {
let v = ''
if (c.type === 'eval') {
v = evalF(c.property, item)
} else if (c.type === 'component') {
return false
} else {
v = item[c.property]
}
return typeof v == 'string' ? v.indexOf(filterText.value) >= 0 : false
})
)
} else {
return option_list.value.filter((item: any) => item[valueField.value])
}
}
return []
})
/**
* 监听表格数据设置默认值
*/
watch(
() => tableData.value,
() => {
if (tableData.value && tableData.value.length > 0) {
const defaultItem = _.head(tableData.value)
let defaultItemValue = _.get(defaultItem, valueField.value)
if (props.modelValue) {
const row = option_list.value.find((f: any) => f[valueField.value] === props.modelValue)
if (row) {
defaultItemValue = row[valueField.value]
}
}
emit('update:modelValue', defaultItemValue)
} else {
emit('update:modelValue', undefined)
}
emit('change', props.formField)
}
)
const activeText = computed(() => {
if (props.modelValue) {
const rows = option_list.value.filter(
(f: any) => props.modelValue?.includes(f[valueField.value])
)
if (rows) {
if (rows.length > 3) {
return (
rows
.map((row) => row[textField.value])
.splice(0, 3)
.join(',') + '...'
)
} else {
return rows.map((row) => row[textField.value]).join(',')
}
}
}
return props.modelValue
})
</script>
<style lang="scss" scoped>
.header {
display: flex;
justify-content: space-between;
margin-bottom: 16px;
.title {
color: #1f2329;
font-weight: 400;
font-size: 14px;
line-height: 22px;
}
.input-with-select {
width: 45%;
}
}
.msg {
margin-top: 12px;
color: rgba(100, 106, 115, 1);
.active {
margin-left: 3px;
color: rgba(51, 112, 255, 1);
}
}
</style>

View File

@ -0,0 +1,22 @@
<template>
<component :is="column.property" v-bind="attrs" :column="column" :row="row"></component>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import _ from 'lodash'
const props = defineProps<{
/**
*表单渲染Item column
*/
column: any
/**
* 这一行数据
*/
row: any
}>()
const attrs = computed(() => {
return props.column.attrs ? props.column.attrs : {}
})
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,199 @@
<template>
<div>
<div class="header">
<div class="title">{{ title }}</div>
<el-input
v-model="filterText"
:validate-event="false"
placeholder="请输入关键字搜索"
class="input-with-select"
style="--el-color-danger: #c0c4cc"
>
<template #prepend>
<el-button :icon="Search" />
</template>
</el-input>
</div>
<el-table
ref="singleTableRef"
:data="tableData"
highlight-current-row
style="width: 100%; height: 100%; --el-bg-color: #f5f6f7"
@current-change="_data = $event[valueField]"
>
<el-table-column width="50px">
<template #default="scope">
<input type="radio" :checked="_data === scope.row[valueField]" />
</template>
</el-table-column>
<el-table-column
v-for="(column, index) in tableColumns"
v-bind="column"
:label="column.label"
:key="index"
>
<template #default="scope">
<template v-if="column.type === 'component'">
<TableColumn :column="column" :row="scope.row"></TableColumn>
</template>
<template v-else-if="column.type === 'eval'">
<span v-html="evalF(column.property, scope.row)"></span
></template>
<template v-else>
<span>{{ scope.row[column.property] }}</span></template
>
</template>
</el-table-column>
</el-table>
<div class="msg" v-show="props.modelValue">
{{ activeMsg }}
<span class="active">
{{ activeText }}
</span>
</div>
</div>
</template>
<script setup lang="ts">
import type { FormField } from '@/components/dynamics-form/type'
import { computed, ref, watch } from 'vue'
import { Search } from '@element-plus/icons-vue'
import type { ElTable } from 'element-plus'
import _ from 'lodash'
import TableColumn from '@/components/dynamics-form/items/table/TableColumn.vue'
const filterText = ref<string>('')
const props = defineProps<{
formValue?: any
formfieldList?: Array<FormField>
field: string
otherParams: any
formField: FormField
view?: boolean
//
modelValue?: any
}>()
const rowTemp = ref<any>()
const evalF = (text: string, row: any) => {
rowTemp.value = row
return eval(text)
}
const emit = defineEmits(['update:modelValue', 'change'])
const singleTableRef = ref<InstanceType<typeof ElTable>>()
const _data = computed({
get() {
return props.modelValue
},
set(value) {
emit('update:modelValue', value)
emit('change', props.formField)
}
})
const propsInfo = computed(() => {
return props.formField.props_info ? props.formField.props_info : {}
})
const activeMsg = computed(() => {
return propsInfo.value.active_msg ? propsInfo.value.active_msg : ''
})
const title = computed(() => {
return propsInfo.value.title ? propsInfo.value.title : ''
})
const tableColumns = computed(() => {
return propsInfo.value.table_columns ? propsInfo.value.table_columns : []
})
const option_list = computed(() => {
return props.formField.option_list ? props.formField.option_list : []
})
const textField = computed(() => {
return props.formField.text_field ? props.formField.text_field : 'key'
})
const valueField = computed(() => {
return props.formField.value_field ? props.formField.value_field : 'value'
})
const tableData = computed(() => {
if (option_list.value) {
if (filterText.value) {
return option_list.value.filter((item: any) =>
tableColumns.value.some((c: any) => {
let v = ''
if (c.type === 'eval') {
v = evalF(c.property, item)
} else if (c.type === 'component') {
return false
} else {
v = item[c.property]
}
return typeof v == 'string' ? v.indexOf(filterText.value) >= 0 : false
})
)
} else {
return option_list.value.filter((item: any) => item[valueField.value])
}
}
return []
})
/**
* 监听表格数据设置默认值
*/
watch(
() => tableData.value,
() => {
if (tableData.value && tableData.value.length > 0) {
const defaultItem = _.head(tableData.value)
let defaultItemValue = _.get(defaultItem, valueField.value)
if (props.modelValue) {
const row = option_list.value.find((f: any) => f[valueField.value] === props.modelValue)
if (row) {
defaultItemValue = row[valueField.value]
}
}
emit('update:modelValue', defaultItemValue)
} else {
emit('update:modelValue', undefined)
}
emit('change', props.formField)
}
)
const activeText = computed(() => {
if (props.modelValue) {
const row = option_list.value.find((f: any) => f[valueField.value] === props.modelValue)
return row[textField.value]
}
return props.modelValue
})
</script>
<style lang="scss" scoped>
.header {
display: flex;
justify-content: space-between;
margin-bottom: 16px;
.title {
color: #1f2329;
font-weight: 400;
font-size: 14px;
line-height: 22px;
}
.input-with-select {
width: 45%;
}
}
.msg {
margin-top: 12px;
color: rgba(100, 106, 115, 1);
.active {
margin-left: 3px;
color: rgba(51, 112, 255, 1);
}
}
</style>

View File

@ -0,0 +1,172 @@
import { Dict } from '@/api/type/common'
interface ViewCardItem {
/**
*
*/
type: 'eval' | 'default'
/**
*
*/
title: string
/**
* default= row[value_field] eval `${parseFloat(row.number).toLocaleString("zh-CN",{style: "decimal",maximumFractionDigits:1})}%&nbsp;&nbsp;&nbsp;`
*/
value_field: string
}
interface TableColumn {
/**
* ||
*/
property: string
/**
*
*/
label: string
/**
*
*/
value_field?: string
attrs?: Attrs
/**
*
*/
type: 'eval' | 'component' | 'default'
props_info?: PropsInfo
}
interface ColorItem {
/**
* #f56c6c
*/
color: string
/**
*
*/
percentage: number
}
interface Attrs {
/**
*
*/
placeholder?: string
/**
* '50px' Form form-item 使 auto
*/
labelWidth?: string
/**
*
*/
labelSuffix?: string
/**
*
*/
requireAsteriskPosition?: 'left' | 'right'
color?: Array<ColorItem>
[propName: string]: any
}
interface PropsInfo {
/**
* card
*/
view_card?: Array<ViewCardItem>
/**
*
*/
table_columns?: Array<TableColumn>
/**
* message
*/
active_msg?: string
/**
*
*/
style?: Dict<any>
/**
* el-form-item
*/
item_style?: Dict<any>
/**
* element校验一样
*/
rules?: Dict<any>
/**
*
*/
err_msg?: string
/**
*tabs的时候使用
*/
tabs_label?: string
[propName: string]: any
}
interface FormField {
field: string
/**
*
*/
input_type: string
/**
*
*/
label?: string
/**
*
*/
required?: boolean
/**
*
*/
default_value?: any
/**
* {field:field_value_list} field有值 ,field_value_list中才显示
*/
relation_show_field_dict?: Dict<Array<any>>
/**
* {field:field_value_list} field有值 ,field_value_list中才
*/
relation_trigger_field_dict?: Dict<Array<any>>
/**
* OPTION_LIST请求Option_list数据 CHILD_FORMS请求子表单
*/
trigger_type?: 'OPTION_LIST' | 'CHILD_FORMS'
/**
* attr数据
*/
attrs?: Attrs
/**
*
*/
props_info?: PropsInfo
/**
* field
*/
text_field?: string
/**
* value
*/
value_field?: string
/**
*
*/
option_list?: Array<any>
/**
*
*/
provider?: string
/**
*
*/
method?: string
children?: Array<FormField>
}
export type { FormField }

View File

@ -12,7 +12,7 @@ import AppTable from './app-table/index.vue'
import ReadWrite from './read-write/index.vue'
import TagEllipsis from './tag-ellipsis/index.vue'
import CommonList from './common-list/index.vue'
import dynamicsForm from './dynamics-form'
export default {
install(app: App) {
app.component(AppIcon.name, AppIcon)
@ -28,5 +28,6 @@ export default {
app.component(ReadWrite.name, ReadWrite)
app.component(TagEllipsis.name, TagEllipsis)
app.component(CommonList.name, CommonList)
app.use(dynamicsForm)
}
}

View File

@ -0,0 +1,16 @@
function format(decimal?: number, digits?: number): string | undefined {
if (digits == undefined) {
digits = 0;
}
return decimal?.toLocaleString("zh-CN", {
style: "decimal",
minimumFractionDigits: digits,
maximumFractionDigits: digits,
});
}
const util = {
format,
};
export default util;

View File

@ -14,7 +14,7 @@
</div>
<div class="template-manage__right p-24">
<h4>全部模型</h4>
<Demo></Demo>
</div>
</div>
</LayoutContainer>