一.各个关键类和属性
由于只讨论表单设计器的数据验证以及高级搜索不扩展讨论其他属性和细节
流程图实体
public class Workflow : NamedEntity, ITenantScope, IWorkflow
{
...
/// <summary>
/// 流程组件集合
/// </summary>
public IList<Component> Components { get; set; }
}
流程组件
public class Component
{
...
/// <summary>
/// 关联的自定义表单(视图)
/// </summary>
public CustomView CustomView { get; set; }
}
自定义表单
由表单设计器设计生成
public class CustomView
{
public String Title{ get; set; }
public List<CustomColumn> CustomColumns{ get; set; }
}
自定义列
public class CustomColumn
{
public String Name{ get; set; }
public Enum CustomColumnType { get; set; }
public bool Require{ get; set; }
...
public List<Validator> Validators{ get; set; }
}
自定义验证
public class Validator
{
public Enum ValidatorType{ get; set; }//正则,长度,范围
public String Regex { get; set; }
public long Min { get; set; }
public long Max{ get; set; }
public String ErrorMessage { get; set; }
}
表单实体
public class Runtime : Entity
{
...
/// <summary>
/// 流程历史
/// </summary>
[DataMember]
public List<Process> Processes { get; set; }
/// <summary>
/// 所有数据汇总
/// </summary>
[BsonExtraElements]
[DataMember]
public IDictionary<string, object> MainData { get; set; }
}
流程
public class Process :IRecord
{
...
/// <summary>
/// 流程组件
/// </summary>
public Component Component { get; set; }
/// <summary>
/// 所有通过自定义表单提交的数据
/// </summary>
[BsonExtraElements]
[DataMember]
public IDictionary<string, object> data { get; set; }
}
二.原理说明
1.自定义表单的运作
由表单设计器预先配置好所有的字段和其验证方式,持久化到流程图中,当流程运转的时候,就会根据表单实体(Runtime)的 当前流程(CurrentComponent)来获取对应的自定义表单/视图(CustomView),循环其中所有的自定义列(CustomColumn)生成html代码,同时根据每个自定义列的自定义验证列表属性(Validators)循环生成对应的前端验证代码(Html5)或脚本(JS)
2.自定义验证的运作
有了前端的验证还要有后台的服务端验证.同样,根据提交过来的Form中的 CustomView信息 获取到对应的自定义表单 通过其中的 自定义列的自定义验证属性 对所有数据进行再次确认.到了后台的Form数据会被统一转换为 流程(Process)验证并保存 . 如何把Form转换成Bson/Process 以便于验证和保存 是需要尝试研究的.
3.工作流引擎的运作
沿用并改进北汽三期的工作流引擎
4.高级搜索的运作
之前写过的 高级搜索规则,配合后台代码
var arr = new BsonArray();
foreach (var item in SearchStringList)
{
var operater = Regex.Match(item.Key, @"\$eq|\$lt|\$gt|\$regex|\$in|\$nin").Value;
var key = item.Key;
if (!string.IsNullOrEmpty(operater))
{
key = item.Key.Replace(operater, "");
}
var dataType = Regex.Match(item.Value, @"\$date|\$num").Value;
var value = item.Value;
if (!string.IsNullOrEmpty(dataType))
{
value = item.Value.Replace(dataType, "");
}
BsonDocument temp;
if (dataType == "$date")
{
temp = new BsonDocument
{
{
key, new BsonDocument
{
{operater == "" ? "$eq" : operater, BsonDateTime.Create(value)}
}
}
};
}
else if (dataType == "$num")
{
temp = new BsonDocument
{
{
key, new BsonDocument
{
{operater == "" ? "$eq" : operater, Convert.ToInt32(value)}
}
}
};
}
else if (operater == "$in" || operater == "$nin")
{
temp = new BsonDocument
{
{
key, new BsonDocument
{
{
operater, value.ToBsonArray()
}
}
}
};
}
else
{
temp = new BsonDocument
{
{
key, new BsonDocument
{
{
operater == "" ? "$eq" : operater, value
}
}
}
};
}
arr.Add(temp);
}
网友评论