mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-30 17:52:48 +00:00
feat: 动态表单
This commit is contained in:
parent
394a6a7ee6
commit
589f895c73
|
|
@ -6,17 +6,17 @@
|
|||
@date:2023/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 *
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"""
|
||||
@project: maxkb
|
||||
@Author:虎
|
||||
@file: array_card.py
|
||||
@file: array_object_card.py
|
||||
@date:2023/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)
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -1,27 +0,0 @@
|
|||
# coding=utf-8
|
||||
"""
|
||||
@project: maxkb
|
||||
@Author:虎
|
||||
@file: number_input_field.py
|
||||
@date:2023/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)
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
@date:2023/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)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"""
|
||||
@project: maxkb
|
||||
@Author:虎
|
||||
@file: combobox_field.py
|
||||
@file: radio_field.py
|
||||
@date:2023/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):
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
# coding=utf-8
|
||||
"""
|
||||
@project: maxkb
|
||||
@Author:虎
|
||||
@file: radio_field.py
|
||||
@date:2023/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}
|
||||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
# coding=utf-8
|
||||
"""
|
||||
@project: maxkb
|
||||
@Author:虎
|
||||
@file: switch_btn.py
|
||||
@date:2023/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)
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
# coding=utf-8
|
||||
"""
|
||||
@project: maxkb
|
||||
@Author:虎
|
||||
@file: table_radio.py
|
||||
@date:2023/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)
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
@date:2023/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)
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
@ -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;
|
||||
|
|
@ -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})}% `'
|
||||
},
|
||||
{
|
||||
type: 'eval',
|
||||
title: '名称',
|
||||
value_field: '`${row.key} `'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
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})}% `'
|
||||
},
|
||||
{
|
||||
type: 'eval',
|
||||
title: '名称',
|
||||
value_field: '`${row.key} `'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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 }
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<template>
|
||||
<el-input v-bind="$attrs" />
|
||||
</template>
|
||||
<script setup lang="ts"></script>
|
||||
<style lang="scss"></style>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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})}% `
|
||||
*/
|
||||
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 }
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
</div>
|
||||
<div class="template-manage__right p-24">
|
||||
<h4>全部模型</h4>
|
||||
|
||||
<Demo></Demo>
|
||||
</div>
|
||||
</div>
|
||||
</LayoutContainer>
|
||||
|
|
|
|||
Loading…
Reference in New Issue