上次说到的是动态表单的模型配置的后端的内容
本次来补充的是UI部分,也就是管理端部分的页面的改动
由于是动态创建表单,所以我直接复制PasteForm框架中的view模块出来
整一个dynamicform文件夹,包含对应的view.less,view.html,view.js
然后重命名下,至于后续要不要合并后面再说,原则上是先实现后调整优化!
之前的view中,默认页面打开后会基于path向后台API获取对应的数据结构模型,请求的大概如下
可以看到主要的信息是获得当前数据模型的基本资料,比如desc keyType,title等
然后是这个模型的特性集合attributes
最重要的是获得字段的信息properties
新的动态的已经没有这个信息了,先修改下这个请求
修改下window.ready的请求,如下
_apiget(`/api/app/dynamicHelper/read${location.search}`, true, (c, o) => {
if (c == 200) {
loadHeader(o);
if(o.code){
_classPath = o.code;
_config.className = o.code;
}
if (o.title) {
this.document.title = "更新" + o.title;
}
if (o.properties) {
_setting_data_properties = o.properties;
} else {
_setting_data_properties = new Array();
}
_global_data_properties = new Array();
if (o.data) {
dynamicBuildPropertyInfo(o.data, "", -1);
}
//组合goup
if (!o.attributes) {
o.attributes = new Array();
}
//处理分组的问题
var groups = new Array();
_global_data_properties.forEach(_property => {
if (_property.attributes) {
for (var _attribute of _property.attributes) {
if (_attribute.name == 'group') {
if (groups.indexOf(_attribute.args1) == -1) {
groups.push(_attribute.args1);
}
}
}
}
});
if (groups.length > 0) {
groups.forEach(igroup => {
var _find =false;
for(var _oa of o.attributes){
if(_oa.name == igroup){
_find=true;
break;
}
}
if(!_find){
//这里要做成动态的,可能有配置信息
o.attributes.push(dynamicBuildGroupAttribute(igroup));
}
});
_global_class_attributes = o.attributes;
}
//使用pasteform模式加载表单内容到UI
LoadModelProperity(_global_data_properties);
}
});
获取到的信息大概如下
可以看到,还是和之前的尽量配合,多了data表示当前要编辑的JSON的数据内容
{
"name":"张三",
"age":18,
"info":{
"create":"2024",
"score":95
}
}
数据下载后,先要经过数据处理,
主要的就是需要把多层级的JSON转化成单层级的,
为啥单层级呢?便于UI的渲染!
主要的核心思想是数据处理后,改成PasteForm可用的格式,然后使用PasteForm的渲染模式把Propertys的Json数据渲染成UI表单的样子!
上面的大概转化后是如下的样子
可以看到层级的分隔符是__,为啥用这个呢?符号点是直接不能用的,因为这个name到时候要写入到UI中!
所以这里有一个隐藏的*,那就是字段的名称不能包含双_符号!
如果遇到array的咋处理?
新手写一个JSON信息如下
{
"name":"张三",
"age":18,
"info":{
"create":"2024",
"score":95
},
"items":[
{
"name":"123",
"val":70
},
{
"name":"456",
"val":80
}
]
}
提交上面的信息到
http://localhost:22222/api/app/dynamicHelper/test?code=abc
会得到一串代码,本次的是
4ec5f0c24192442b800e4471ae37bcc7
打开浏览器我们访问下这个数据
http://localhost:22222/page/dynamicform/index.html?datakey=4ec5f0c24192442b800e4471ae37bcc7&path=abc
获取到数据后,在F12控制台打印下globaldata_properties转化成单层的数据为
也就是说和所在的array的index有关系,同样的也采用进行分割!
看到上面的信息,这里主要还有一个问题就是多层级的问题,
我给他加了一个group分组的概念,也就是如果层级是多级的,则给他套一个group的信息,
最后PasteForm的渲染逻辑会基于这个group进行分组,渲染后如下
从上面可以看到有2个items,和对应的name,val,仔细看他们还是有区别的val不同,因为上面的JSON数据源中items就是有2个子内容的!
由上可见,已经进行分组了,从第一个字段title已经有格式信息,显示为姓名了,那么分组是否也可以?
注意上面的分组的组代码的定义是抹除最后一个信息位,比如
infousername
则组的代码为infouser
info0age
组的代码为info0
回顾下group这个特性的知识
有时候字段太多,我们希望能否分组显示,这就需要使用group,如果第一个字段就是group,则表示最顶部使用瞄点模式
当前特性可以用于Class也可以用于Property,为了区分,封装后
PasteGroup用于Class,允许配置多个
PasteGroupItem用于Property,只允许单个,毕竟一个字段只能放于一个区块中
字段 | 类型 | 示例 | 说明 |
---|---|---|---|
args1 | str | gr1 | 分组依据,分组代码 |
args2 | str | 基础配置 | 分组名称 |
args3 | str | hide | 默认收缩还是展开,hide为收缩,其他为展开 |
从上面的规则,我么配置下表abc的特性如下
点击保存后,我们回到动态表单中,
http://localhost:22222/page/dynamicform/index.html?datakey=4ec5f0c24192442b800e4471ae37bcc7&path=abc
可以看到如下内容
可以看到分组的名称已经变了,也就是分组的信息,字段的信息都可以通过动态表,动态字段信息来配置了!
上面其实已经把数据,或者说多层级的JSON数据转化成单层的,并且在表单中显示了,用户编辑完成后,如何收集?
如上图表单的修改,我提交后,按照之前的PasteForm的处理(form转JSON)会获得如上的信息!
但是这个信息是不符合我们预期的,所以需要转化下
/**
* 基于递归方法,把一级数据拆分为多级
* @param {*} flattenedData
* @returns
*/
function convertFlattenedToNested(flattenedData) {
const result = {};
for (const key in flattenedData) {
if (flattenedData.hasOwnProperty(key)) {
const value = flattenedData[key];
const parts = key.split('__');
// 递归构建嵌套结构
buildNestedStructure(result, parts, value);
}
}
return result;
}
/**
*
* @param {*} current
* @param {*} parts
* @param {*} value
* @returns
*/
function buildNestedStructure(current, parts, value) {
const part = parts[0]; // 当前处理的键部分
// 如果是最后一个部分,直接赋值
if (parts.length === 1) {
current[part] = value;
return;
}
// 判断下一级是否是数组
if (!isNaN(parts[1])) {
const index = parseInt(parts[1]);
// 如果当前部分不存在,创建一个新的数组
if (!current[part]) {
current[part] = [];
}
// 获取或创建数组元素
while (current[part].length <= index) {
current[part].push({});
}
// 递归处理剩余部分
buildNestedStructure(current[part][index], parts.slice(2), value);
} else {
// 如果当前部分不存在,创建一个新的对象
if (!current[part]) {
current[part] = {};
}
// 递归处理剩余部分
buildNestedStructure(current[part], parts.slice(1), value);
}
}
经过上面一转化,得到如下数据
可以说符合预期!
看看和数据源对比下
{
"name":"张三",
"age":18,
"info":{
"create":"2024",
"score":95
},
"items":[
{
"name":"123",
"val":70
},
{
"name":"456",
"val":80
}
]
}
是不是数据结构没变,数据编辑修改了!
剩下的就是提交给API,然后API提交给IIS了
上面的说明中,已经实现了随意的一个JSON内容,转化成表单显示,甚至可以针对性的配置UI部分,比如名称搞成中文,添加一个说明等!
不过还有部分问题需要搞定
1.默认值的问题,如果结构配置中有默认值,而当前JSON有数据,那肯定是显示当前数据,如果没有数据呢?显示默认数据???
那对于用户来说,他咋知道当前数据就是数据源的数据,还是当前数据是默认值?也就是他点不点保存的问题?
2.如果一个JSON数据,标准来说有内容name,age,desc,这个标准是从动态表的动态字段的结构推出的,如果当前提交的数据只有name,age,而desc又是必填项,那是否需要渲染到UI让用户编辑?
也就是数据为准还是结构为准、还是两者互补?
我估计最后会采用结构的要求而定,如果必填的,这个时候应该显示在UI让用户填写
如果不是必填的呢?显示还是不显示?
不显示的话,要添加还没法加,显示的话,如果有默认值…
提交数据是否会符合预期呢???