表单三要素:控件、数据与业务逻辑
一、为什么先谈三要素
选设计器之前,先问一句:一张表单到底装了什么?
答案固定是三块——
| 要素 | 一句话 | 典型内容 |
|---|---|---|
| 控件 | 界面上能看见、能操作的东西 | 文本框、下拉框、单选、评分、从表、附件 |
| 数据 | 控件背后落库的内容 | 主表数据、从表数据、附件数据 |
| 业务逻辑 | 控件之间的交互与计算关系 | 级联、单价×数量=小计、Pop 弹窗回填 |
《五大设计器》讲的是造车厢的车间;本文讲的是车厢里三样货怎么摆。车间可以换,货的分类不变。
低代码轨道上,三要素全部落在数据库元数据表里:
Sys_MapData (No, PTable)
├─ Sys_MapAttr → 字段控件(主表/从表列)
├─ Sys_MapDtl → 从表容器
├─ Sys_FrmAttachment → 附件区
├─ Sys_GroupField → 布局分组(可挂 Dtl / Ath)
└─ Sys_MapExt → 挂在字段上的扩展逻辑
| 起点 | 作用 | 落点 |
|---|---|---|
| 控件 | 渲染 · 读写 | 数据 |
| 业务逻辑 | 级联 / 计算 / Pop | 控件 |
| 业务逻辑 | 填充 / 校验 | 数据 |
二、数据维度
数据是三要素里最稳的那一层:换设计器、换皮肤,物理表结构通常不动。
2.1 三层数据:主表 · 从表 · 附件
| 层级 | 元数据 | 物理落点 | 行键怎么挂 |
|---|---|---|---|
| 主表 | Sys_MapData(No + PTable) | PTable 上一行业务数据 | 主键多为 OID(流程 WorkID) |
| 从表 | Sys_MapDtl(FK_MapData + 自己的 PTable) | 多行明细 | OID + RefPK → 主表 OID;合流等用 FID |
| 附件 | Sys_FrmAttachment | 文件元数据在 Sys_FrmAttachmentDB | RefPKVal + 表单 + 附件标识 |
请假演示流程里:节点表单 ND101(填写请假申请单)的 PTable 是 ND1Rpt;后续节点 ND102~ND104 往往共用同一张物理表,差异在各节点自己的 MapAttr 与权限方案——业务数据仍然是 ND1Rpt 的一行。
口诀:
MapData.No是逻辑表单 ID,PTable才是真正 INSERT/UPDATE 的表名。 多节点可以「多张逻辑表单、一张物理表」。
2.2 字段怎么描述一列数据
每个字段是 Sys_MapAttr 的一行,三个正交维度一起定「这列是什么」:
| 维度 | 字段 | 作用 |
|---|---|---|
| 控件形态 | UIContralType | 用哪个界面组件渲染 |
| 存储类型 | MyDataType | 物理列类型(字符串/整型/日期/金额…) |
| 逻辑类型 | LGType(FieldTypeS) | 普通 0 / 枚举 1 / 外键 2,常配 UIBindKey |
MyDataType 常用值(与 wiki 一致):
| 值 | 常量 | 含义 |
|---|---|---|
| 1 | AppString | 字符串 |
| 2 | AppInt | 整型 |
| 3 | AppFloat | 浮点 |
| 4 | AppBoolean | 布尔 |
| 5 | AppDouble | 双精度 |
| 6 | AppDate | 日期 |
| 7 | AppDateTime | 日期时间 |
| 8 | AppMoney | 金额 |
| 9 | AppRate | 比率 |
例如请假 demo:QingJiaRiQiCong(请假日期从)是 UIContralType=0(TB)+ MyDataType=6(日期);QingJiaTianShu 是浮点天数;QingJiaYuanYin 是大块文本。
2.3 运行时谁去读写
GEEntity(frmID)/GEEntityOID:按MapData.GenerHisMap()把Sys_MapAttr投影成动态EnMap,读写PTable。GEDtl:从表行,带RefPK/FID/OID。- 附件不走「普通列」那条路,而是
FrmAttachmentDB.RefPKVal挂到主表主键。
从表、附件在布局上通过 Sys_GroupField.CtrlType = 'Dtl' | 'Ath' 挂到分组里——它们是容器级数据,不是普通文本框的一种 UIContralType。
2.4 数据维度小结
| 你在设计 | 实际在改 |
|---|---|
| 加一个「请假天数」 | Sys_MapAttr 一行 + PTable 一列 |
| 加「行程明细」从表 | Sys_MapDtl + 从表自己的 MapAttr 集合 |
| 加「病假条」上传区 | Sys_FrmAttachment + 运行时写 FrmAttachmentDB |
| 节点换皮、字段显隐 | 多半只动元数据/权限,不动已落库的 ND1Rpt 行结构 |
三、控件元素
控件回答的是:用户看见什么、点什么。
3.1 权威枚举:UIContralType
服务端定义在 BP.En30/En/EnumLab.cs,前端有对应 TS 枚举;傻瓜设计器面板还会按业务再分组。
| 族 | 典型值 | 常量 | 说明 |
|---|---|---|---|
| 输入 | 0 | TB | 文本框(再由 MyDataType 分化成日期/金额/整数等) |
| 选择 | 1 / 2 / 3 | DDL / CheckBok / RadioBtn | 下拉、复选、单选 |
| 附件与手写 | 6 / 8 / 12 / 600 | AthShow / HandWriting / FrmImgAth / AthTable | 字段附件、签名、图片附件、附件表 |
| 展示 | 10 / 11 / 60 | Lab / FrmImg / BigText | 标签、图片、说明性大块 HTML |
| 流程与公文 | 14 / 15 / 17 / 110 / 50 / 200 | SignCheck / FlowBBS / DocWord / GovDocFile / JobSchedule / FlowRefLink | 签批、评论、文号、正文、进度、关联流程 |
| 其他 | 4 / 5 / 7 / 9 / 13 / 16 / 101 | MapPin / MicHot / MobilePhoto / HyperLink / IDCard / Location / Score | 定位、录音、拍照、链接、身份证、系统定位、评分 |
粗算:C# 命名常量约 26 种;前端/设计器面板再加按钮、色标等扩展后约 30+。产品上「能拖进画布的基础字段」不止枚举字面量——同一个 TB,配不同 MyDataType,就是不同输入体验。
3.2 从表与附件:容器,不是「多一个 TB」
| 类型 | 元数据 | 设计器分组(FormTypeMap) |
|---|---|---|
| 从表 Dtl | Sys_MapDtl | CtrlType='Dtl' → slave/table |
| 附件区 Ath | Sys_FrmAttachment | CtrlType='Ath' → appendix/table |
| 字段级附件 | MapAttr + AthShow(6) 等 | 仍是字段行 |
傻瓜设计器入口:
- 组件面板:
Vue3/.../FoolFormDesigner/props/form/FormComponents.ts - 拖入落库:
CreateFieldFunctions.ts→ 写Sys_MapAttr - 画布注册:
components/widgets/registry.ts
3.3 字段属性页按控件分流
右键字段属性不是一张万能表:EditPageMap 按 UIContralType 打开不同 EnMap(MapAttrString / MapAttrEnum / MapAttrSFTable / 评分 / 签批 / 公文…)。控件类型决定你能配哪些扩展入口——例如外键下拉才挂「级联 ActiveDDL」,文本框才挂「Pop / TBFullCtrl」。
3.4 控件维度小结
| 误区 | 实际 |
|---|---|
| 「控件 = 界面皮肤」 | 控件行同时决定渲染组件和落库列语义 |
| 「从表也是一种 UIContralType」 | 从表是 MapDtl + GroupField,字段在从表自己的 MapAttr 里 |
| 「五种设计器五种控件库」 | 设计器换车间;控件元数据仍是 MapAttr 这一套(开发者/VSTO 是换呈现,不是另起字段体系) |
四、业务逻辑
业务逻辑回答的是:改了 A,B 和 C 怎么办?
载体是 Sys_MapExt:挂在表单/字段上,用 ExtModel(及兼容字段 ExtType) 告诉运行时走哪条分支。CCForm 侧主解析在 OneMapAttr.vue(DealMapExtBySelect、NumberORDateChange 等);复杂 SQL/树数据进 Sys_GenerDBSrc。
常量清单见 MapExtXmlList(MapExtXml.cs),设计器向导见 GPN_ComponentMapExt.ts。
4.1 三类最常见的逻辑
(1)级联关系 —— ActiveDDL / 级联选择器
- 场景:省 → 市 → 区;部门 → 人员;请假类型 → 需不需要上传证明。
- 配置:外键/枚举字段右键 →
GPE_ActiveDDL;AttrOfOper为驱动字段,AttrsOfActive为被刷新字段。 - 运行时:选中变化 →
GetActionDLLData→ 刷新下游 DDL。 - 一键组合:向导里的「省份/城市/区县」级联,主字段存编号链,影子字段存名称链(见
GPN_ComponentMapExt.CityDesc)。
(2)计算公式 —— AutoFull / ReqDays
- 场景:单价 × 数量 = 小计;请假日期从/到 → 天数。
- 小计向导
XiaoJi:自动建名称/单价/数量/小计四列,并写入:
ExtModel = AutoFull
AttrOfOper = {前缀}Sum
Tag = @{前缀}Unit*@{前缀}Num
- 日期差
ReqDays:向导DTFromToDD(页面占位名就是「请假日期」)创建从、到、天数字段,并挂ExtModel=ReqDays。 - 从表聚合:
AutoFullDtlField把明细列汇总回主表。
产品提示词与 AI 工具里也沿用同一套表达式习惯:
@单价*@数量——逻辑写在元数据里,而不是散落在页面脚本。
(3)Pop 弹窗选值与回填 —— Pop / PopFullCtrl / TBFullCtrl
- 场景:选代理人、选物资、选合同号,带回编号、名称及相关字段。
- DoWay 形态:树(
PopBranches/PopTreeEns)、分组列表(PopGroupList)、表格(PopTable)、自定义 URL(PopSelfUrl)等。 - 运行时:
ExtModel为Pop/TBFullCtrl/DDLFullCtrl时走GetFullData,再ChangeParentAttr(..., 'FullData')回填其它控件。 - 文本自动完成:输入工号带出姓名、电话、邮件——向导「人员输入」一类,本质仍是 MapExt + 数据源。
4.2 其它常用 ExtModel(速查)
| ExtModel | 干什么 |
|---|---|
AutoFullDLL | 动态/过滤填充下拉选项 |
PageLoadFull / PageLoadFullMainTable / PageLoadFullDtl | 打开表单时预填 |
FullData / FullDataDtl | 填充其它控件或从表 |
RBAction / EnumHidItems | 单选/枚举联动显隐 |
BindFunction | 绑定 change/blur 等前端函数 |
RegularExpression / InputCheck | 校验 |
DateFieldInputRole | 日期输入约束(如禁止历史日) |
4.3 业务逻辑小结
| 你想表达的业务 | 优先落点 |
|---|---|
| A 变了 B 的选项要变 | ActiveDDL / 级联选择器 |
| A、B 算出 C | AutoFull / ReqDays |
| 弹窗选一条,填一串字段 | Pop + FullData |
| 打开单子就带默认值 | PageLoadFull* |
| 选了「病假」才显示附件 | RBAction / 枚举显隐 |
高代码轨道另有 EnMapExt(useMapExtHandler.ts),语义相近(联动、自动计算、弹窗填充),配置面在实体 EnMap 上——与低代码 Sys_MapExt 同属 BP.En30 家族,配置入口不同。
五、三要素怎么拧在一张请假单上
用「请假」把三层钉死(对照演示包与组合向导):
| # | 业务点 | 控件 | 数据 | 逻辑 |
|---|---|---|---|---|
| 1 | 请假日期从 | TB + 日期 | ND1Rpt 列 QingJiaRiQiCong | 可加 DateFieldInputRole |
| 2 | 请假到 + 天数 | 两日期 + 数值 TB | 三列 | ReqDays 自动算天 |
| 3 | 请假原因 | 大块文本 TB | 字符串列 | 可选 BindFunction 校验 |
| 4 | 所属部门 | DDL + 外键 | FK_Dept 等 | 可 ActiveDDL 到人员 |
| 5 | 请假类型 | 枚举 Radio/DDL | 枚举值列 | RBAction 控制证明材料显隐 |
| 6 | 代理人 | 文本 + Pop | 人员编号/名称 | PopTreeEns 回填 |
| 7 | 病假条 | 附件区 Ath | FrmAttachmentDB | 无计算,容器级数据 |
| 8 | (类比)明细小计 | 单价/数量/小计 | 三列金额/数值 | AutoFull:@Unit*@Num |
同一套三要素,换到合同/检验单只是字段更多、逻辑更密,不是另一套理论:合同用章节设计器排「章—节」,检验用 VSTO 扛公式——MapAttr / PTable / MapExt 仍然是三根柱子。
六、和姊妹文档怎么衔接
| 文档 | 回答的问题 |
|---|---|
| 本文 · 三要素 | 一张表单里面有什么(控件 / 数据 / 逻辑) |
| 三大范式 | 表单规则写在文件、数据库,还是实体规则里 |
| 五大设计器 | 用哪种车间把表单造出来(经典 / 开发者 / 章节 / VSTO / 手机) |
选型顺序建议:
- 先想清数据(主从附件、主键怎么挂);
- 再铺控件(字段类型与容器);
- 把交互收进 MapExt;
- 最后才选设计器——先用经典,装不下再换车厢。
七、小结
- 控件是
Sys_MapAttr(外加 Dtl/Ath 容器);形态看UIContralType,类型看MyDataType,字典/外键看LGType。 - 数据是
MapData.PTable+ 从表RefPK+ 附件RefPKVal;逻辑表单 ID 可以多个,物理表可以共用。 - 业务逻辑是
Sys_MapExt.ExtModel:级联、AutoFull、Pop/回填、装载填充、显隐与校验。 - 请假单是最小完整样例;合同、检验、公文只是三要素的密度与呈现车间不同。
附录:代码与文档索引
| 主题 | 路径 |
|---|---|
控件枚举 UIContralType | CCFlow/Components/BP.En30/En/EnumLab.cs |
字段实体 MapAttr | CCFlow/Components/BP.En30/Sys/MapAttr.cs |
表单 / GenerHisMap | CCFlow/Components/BP.En30/Sys/MapData.cs |
从表 MapDtl | CCFlow/Components/BP.En30/Sys/MapDtl.cs |
附件 FrmAttachment | CCFlow/Components/BP.En30/Sys/FrmAttachment.cs |
扩展 MapExt / MapExtXmlList | MapExt.cs、MapExtXml.cs |
| 运行时解析 | Vue3/src/WF/CCForm/OneMapAttr.vue |
| 组合向导(小计/请假日期/级联) | Vue3/src/WF/Admin/FrmLogic/GPN_ComponentMapExt.ts |
| 傻瓜设计器 | Vue3/src/WF/Admin/FoolFormDesigner/ |
| 三表说明 | JFlow.wiki/表单引擎/MapData、MapAttr、MapDtl说明.md |
延伸阅读
- 《驰骋表单引擎:表单的业务逻辑设计》:MapExt 主表/从表逻辑专篇(AutoFull、Pop、级联)。
- 《驰骋表单引擎:表单元素的分类与实现》:主表 / 从表 / 附件 / 扩展控件四层切片。
- 《表单引擎在应用系统中的位置与作用》:同一引擎在流程 / 实体 / 单据 / 活动中的四种角色。
- 《表单引擎三大范式与驰骋双轨实现》:文件 / 数据库 / 规则三种范式,低代码与高代码双轨。
- 《驰骋五大表单设计器:应用场景与设计特征》:请假 / 公文 / 合同与申报 / 检验检测如何选车间。
- 课程 A 第 02 讲:表单本质——车厢、货物与动力系统。
本文依据当前仓库 BP.En30 与 Vue3 表单运行时静态整理;具体菜单文案与向导页以你部署的版本为准。
364



被折叠的 条评论
为什么被折叠?



