跳转到内容

动态表单 DynamicView

DynamicView 动态表单

在某些特殊场景下,视图容器不能被枚举,需要动态的被加载。例如合同模板生成场景,需要数据中勾选了特定模块,才会出现特定的数据容器。

这种场景下可使用动态表单 DynamicView 布局,此布局会在页面渲染时通过指定的 LogicFlow/LogicFunction 加载动态的 DSL 及元数据,将子元素挂在到该布局下。

动态表单返回的 DSL 中的容器均是通过 lookupFrom 与静态的容器关联。从而实现数据回填及连带提交。

DynamicView API

IDynamicViewProps

参数类型说明默认值
logicFuncstring获取动态表单DSL的func key-
logicFunctionstring获取动态表单DSL的func key,等价于logicFunc-
logicFlowstring获取动态表单DSL的flow key-
dataParamsstring获取动态表单 func/flow 的入参。在页面打开时解析,不会收集依赖。可以不需要表达式格式#{expression}。一般可以用来接收pageRecord。例如 dataParams=”{ id: pageRecord.id }“-
dynamicLookupFromstring动态表单内的容器 lookupFrom 关联的父容器key,目的是提交时父容器可以带上动态表单内的数据-
showboolean是否显示, 表达式只在页面打开执行一次,且只能读取env, pageRecord或者固定值-

主要开发步骤:

  1. 写含动态视图的XML
  2. 主容器模型继承 DynamicView, 用于接收或回显动态数据
  3. 定义接口响应动态视图模型数据

动态视图XML

<View type="Form" forModel="item_MyUser" title="用户编辑" >
<Form key="user" model="item_MyUser" dataCondition="id = ?" dataParams="[3]">
<Fields>
<Field name="name"/>
<Field name="age"/>
</Fields>
<Actions>
<Action type="Submit" label="提交" after="Refresh" layout="Footer"
logicFunction="item_DynamicSubmitFunc"/>
</Actions>
</Form>
<!-- 加载动态表单生成dsl的元数据
logicFlow 或者 logicFunc 二选一
dynamicLookupFrom 取主容器key
dataParams 可选,可传入pageRecord(上一个页面传过来的上下文),或者env
dataParams 用法和其他数据容器类似,不需要写成表达式格式,会作为后端func/flow的入参
-->
<DynamicView logicFunc="item_DynamicViewFunc"
dynamicLookupFrom="user"
dataParams="{id: pageRecord.id}"
/>
</View>

主容器模型继承 DynamicView

主容器需继承 DynamicModel , 这样会拥有动态数据 默认提交和回显 能力。

@Data
@Model(name = "用户", mainField = "name")
@EqualsAndHashCode(callSuper = true)
// 需要继承 DynamicModel, 拥有 dynamicFields 字段, 用于提交和回显数据
public class MyUser extends DynamicModel<Long> {
@Field(name = "名称")
private String name;
@Field(name = "年龄")
private Integer age;
}

定义接口响应动态视图模型数据

需要先简单介绍下动态模型数据,以下为他们与 dsl 的对应关系。

模型对应XML作用
DynamicView数据容器,如<Form/>/<TableForm/>对数据容器的抽象,可以封装 <Fields/>
DynamicViewGroup对应 <GroupField/><GroupField/> 的抽象,不需要时使用默认组便可
DynamicViewField对应到 <Field/><Field/> 的抽象,一般要定义视图项的名称和类型

使用常规逻辑流或逻辑函数便可, 参数看 标签上的 dataParams ,可空, 响应值必须为 List<DynamicView>,表示包含多个数据容器。

@FunctionImpl
public class DynamicViewFuncImpl implements DynamicViewFunc {
/**
* 响应动态模型描述数据, list 表示包含多个容器
*/
@Override
public List<DynamicView> execute() {
List<DynamicView> list = new ArrayList<>();
// 添加一个 Form 数据容器
DynamicView form = generateForm();
list.add(form);
// 添加一个 TableForm 数据容器
DynamicView tableForm = generateTableForm();
list.add(tableForm);
return list;
}
/**
* 响应 Form
*/
@NotNull
private DynamicView generateForm() {
DynamicView form = new DynamicView();
form.setTitle("学生");
form.setModel("student");
form.setDataContainer(DataContainer.Form);
DynamicViewGroup g1 = new DynamicViewGroup();
g1.setTitle("小分组");
g1.setSingleColumn(false);
form.setGroups(Collections.singletonList(g1));
// 字符串类型
DynamicViewField f1 = new DynamicViewField();
f1.setName("name");
f1.setLabel(名称);
f1.setType(FieldType.Text);
f1.setTypeMeta(TextType.DEFAULT.get());
// 数字类型
DynamicViewField f2 = new DynamicViewField();
f2.setName("age");
f2.setLabel("年龄");
f2.setType(FieldType.Int);
f2.setTypeMeta(IntType.DEFAULT.get());
g1.setFields(Arrays.asList(f1, f2));
return form;
}
/**
* 响应 TableForm
*/
@NotNull
private DynamicView generateTableForm() {
DynamicView tableForm = new DynamicView();
tableForm.setTitle("班级");
tableForm.setModel("class");
tableForm.setDataContainer(DataContainer.TableForm);
DynamicViewGroup defaultGroup = new DynamicViewGroup();
tableForm.setDefaultGroup(defaultGroup);
DynamicViewField f1 = generateField("name", "名称", 0);
DynamicViewField f2 = generateField("teacher", "老师", 1);
defaultGroup.setFields(Arrays.asList(f1, f2));
return tableForm;
}
@NotNull
private DynamicViewField generateField(String name, String label, int order) {
DynamicViewField dynamicViewField = new DynamicViewField();
dynamicViewField.setName(name);
dynamicViewField.setLabel(label);
dynamicViewField.setType(FieldType.Text);
dynamicViewField.setTypeMeta(TextType.DEFAULT.get());
dynamicViewField.setOrder(order);
return dynamicViewField;
}
}

以上实现便能渲染出动态模型页面了, 与常规页面区别不大。

数据提交和回显

动态数据提交

我们可以通过以下方式对将要 保存到数据库的动态数据 进行预处理。

@FunctionImpl
public class DynamicViewSumitFuncImpl implements DynamicViewSumitFunc {
@Override
public MyUser execute(MyUser myUser) {
Map<String, Object> dynamicFields = myUser.getDynamicFields();
return myUser;
}
}

动态数据回显

我们也可以使用 postFunc 的方式对将要 回显的动态数据 进行后置处理。

@FunctionImpl
public class DynamicViewLoadPostFuncImpl implements DynamicViewLoadPostFunc {
@Override
public MyUser execute(MyUser myUser) {
Map<String, Object> dynamicFields = myUser.getDynamicFields();
// do something..
return myUser;
}
}

一些特殊动态项的定义

图片类型

DynamicViewField dynamicViewField = new DynamicViewField();
dynamicViewField.setName("picture");
dynamicViewField.setLabel("图片");
dynamicViewField.setType(FieldType.Image);
ImageType imageType = ImageType.DEFAULT.get();
// 如果需要调整格式的话,可以设置下
imageType.setAllowedTypes(Lists
.newArrayList(AllowedTypes.getTypes(AllowedTypes.IMAGE)));
dynamicViewField.setTypeMeta(imageType);
return dynamicViewField;

枚举类型

  • 定义枚举类型
DynamicViewField f5 = new DynamicViewField();
f5.setName("type");
f5.setLabel("类型");
f5.setType(FieldType.MultiDictionary);
DictionaryType dictionaryTypeMeta = new DictionaryType("custom_dict", DictType.String);
dictionaryTypeMeta.setOptions(Arrays.asList(
new DictItem("a", "第一个字母"),
new DictItem("b", "第二个字母"),
new DictItem("c", "第三个字母")));
f5.setTypeMeta(dictionaryTypeMeta);
  • 使用对应元数据的枚举类型, 这样子表单项可以省略,其值从 ms 拿
DynamicViewField f5 = new DynamicViewField();
f5.setName("type");
f5.setLabel("类型");
f5.setType(FieldType.MultiDictionary);
DictionaryType dictionaryTypeMeta = new DictionaryType("base_Unit", DictType.String);
f5.setTypeMeta(dictionaryTypeMeta);

所有类型参考

类型含义
TextType文本类型
NumberType数字类型
IntType整数类型
FloatType小数类型
CurrencyType金钱类型
PercentType百分比类型
TimeType时间类型
DateTimeType日期时间类型
BooleanType布尔类型
ImageType图片类型
AttachmentType附件类型
JsonTypejson类型
DictionaryType字典类型
EnumType枚举类型
AddressType地址类型