h3factory 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +223 -2
- package/bin/h3factory.js +87 -0
- package/cli.py +880 -0
- package/config.example.json +8 -0
- package/docs/platform_gotchas.md +118 -0
- package/docs/requirement_checklist.md +54 -0
- package/docs/schema_doc.md +216 -0
- package/docs/workflow.md +146 -0
- package/h3design/__init__.py +0 -0
- package/h3design/controls.py +414 -0
- package/h3design/dsl.py +553 -0
- package/h3design/newbuilder.py +852 -0
- package/h3platform/__init__.py +0 -0
- package/h3platform/api.py +214 -0
- package/h3platform/h3console.py +99 -0
- package/h3platform/settings.py +74 -0
- package/h3verify/__init__.py +0 -0
- package/h3verify/verify.py +217 -0
- package/package.json +51 -4
- package/projects/demo/dicts.json +10 -0
- package/projects/demo/generated/product.cs +82 -0
- package/projects/demo/groups.json +3 -0
- package/projects/demo/sheets/product.json +24 -0
- package/scripts/postinstall.js +107 -0
- package/skills/h3factory/SKILL.md +136 -0
- package/skills/h3yun-dev-assistant/BACKEND_GUIDELINES.md +120 -0
- package/skills/h3yun-dev-assistant/DEV_DOC_ROUTING.md +39 -0
- package/skills/h3yun-dev-assistant/FORM_ACTIONS_GUIDELINES.md +116 -0
- package/skills/h3yun-dev-assistant/FRONTEND_GUIDELINES.md +47 -0
- package/skills/h3yun-dev-assistant/OPENAPI_GUIDELINES.md +8 -0
- package/skills/h3yun-dev-assistant/PLATFORM_CONSTRAINTS.md +160 -0
- package/skills/h3yun-dev-assistant/POST_GUIDELINES.md +47 -0
- package/skills/h3yun-dev-assistant/PRACTICE_NOTES.md +626 -0
- package/skills/h3yun-dev-assistant/SKILL.md +70 -0
- package/skills/h3yun-dev-assistant/SQL_GUIDELINES.md +9 -0
- package/skills/h3yun-dev-assistant/TOOL_FUNCTIONS.md +96 -0
- package/templates/controller.cs.tpl +78 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# 氚云 new-engine 平台坑位清单(实证记录,2026-09 料号项目)
|
|
2
|
+
|
|
3
|
+
改平台层(controls/newbuilder/dsl)前必读。全是线上样本逐字实证,别凭旧文档猜。
|
|
4
|
+
|
|
5
|
+
## 建表端点与认证
|
|
6
|
+
- 真实建表端点是控制台 `POST {base}/Console/SheetDesigner/OnAction`(x-www-form-urlencoded,`PostData=<JSON>`),header 带 `Authorization` + `EngineCode`;不是老的 `v1/formdesign/save`。
|
|
7
|
+
- LoadForm 回读的 `DesignModeContent` 是 **PascalCase**(`Options`/`ChildControls`/`NameSchema`);SaveForm 载荷 camelCase(`options`/`childControls`)。比对一律大小写不敏感。
|
|
8
|
+
- 表单编码 = appCode 前 7 位 + 32 hex,随机生成后注册在 registry.json;**重存必须复用编码**(换码 = 断关联引用)。
|
|
9
|
+
- 数据接口走 `OpenApi/Invoke`(EngineCode+EngineSecret):CreateBizObject(s)/LoadBizObjects/RemoveBizObject。
|
|
10
|
+
|
|
11
|
+
## SaveForm 载荷(controls.py/newbuilder.py 已固化)
|
|
12
|
+
- SchemaStr.Properties 每字段:`ControlKey` 用**新枚举**(FormTextBox=14、FormNumber=7、FormTextArea=13、FormDateTime=5、FormCheckbox=1、FormUser/Dept=26、Multi=27、FormQuery=50、MultiQuery=51);FormLayout.type 用**老枚举**(同 controls.py 常量)。
|
|
13
|
+
- 表单下拉/单选/复选:**存储并回显所选文本本身**(不是 code/value 对)。料号拼接要代码 → 另建字典表 名称→代码 后端转换。
|
|
14
|
+
- 复选无默认值 = ""/null;下拉/单选默认 null;开关(是/否)存字符串 "true"/"false"。
|
|
15
|
+
- 必填/只读/默认值规则(DefaultValueRule)等 **UI 侧另存**,SaveForm 载荷无对应键 —— 重存会丢,所以 build 默认跳过已存在表单,`--force` 才整体重存。
|
|
16
|
+
- 成员/部门控件在 FormLayout 里 key 用 **uuid + DataFieldEditable=true**(11-14 类型);普通控件 key=字段编码。
|
|
17
|
+
|
|
18
|
+
## DisplayRule 显隐(唯一支持的"规则"通道)
|
|
19
|
+
- 控件 Options.DisplayRule = `{"Rule": "条件串"}`;Properties.DisplayRule = 纯字符串。
|
|
20
|
+
- 条件串语法:`{字段}=="值"`;**OR** 连接;多值不属于 = `AND {f}!="v"` 链。**语义:匹配即隐藏**,默认显示——"仅 A/B 显示"要写成 NOT∈{A,B} 链。
|
|
21
|
+
- 样本里 OR 分隔带 NBSP,生成/比对时规整为普通空格。
|
|
22
|
+
- UI 保存后引擎会复写规则文本(`!=` 加空格、追加 ` OR TRUE`),verify 会抓这类漂移——是 UI 痕迹不是 bug。
|
|
23
|
+
- 关联表单控件(FormQuery)与文本比较:**按记录显示名(NameSchema)的语义写的,未 100% 实证**;AND 关键字未实证(推导,料号表 4 在用)。新项目先在小表单试一条再铺开。
|
|
24
|
+
|
|
25
|
+
## 一行多列(fourCols)
|
|
26
|
+
- 行节点 = `{key: uuid, type: 102, parentKey: "", options: {Layout: "fourCols", PercentageBlock: "fourCols-1111", DisplayName: "一行多列"}, columns: [子项], childControls: [子项]}`;子项 parentKey=行 key,≤4 个。
|
|
27
|
+
- LoadForm 回读只有 `ChildControls` 没有 `columns`;HTML 里行 div `data-controlkey="layout_fourcols"`,列 div 数据属性 `data-layoutitem="Col1..4"`。
|
|
28
|
+
|
|
29
|
+
## NameSchema(表单数据标题)2026-09-10 实证
|
|
30
|
+
- **可拼接多个字段占位**:`{pname}{chgtype}` SaveForm 成功并保留。
|
|
31
|
+
- **不能夹字面量**:`{pname}-{chgtype}` 被拒,报 `表单数据标题中配置的字段不正确,请检查`(平台把占位之外的字面文本也当字段解析)。要分隔符就靠占位本身,别写 `-`/空格/斜杠。
|
|
32
|
+
- 失败时 SaveForm 返回 `{Successful:false, ErrorMessage:...}`,**不抛异常** —— `cli.build_one` 的 `except` 分支捕获不到,只落 `err=""`、`detail=""`(本机日志看不出原因)。排障要手工重放 save_form_console 打印响应。
|
|
33
|
+
|
|
34
|
+
## 系统拥有者字段(申请人/申请部门)
|
|
35
|
+
- 用户界面把申请改成系统字段后实证:FormLayout type 203(OwnerId)/204(OwnerDeptId),Options.ControlKey 仍 `FormUser`/`FormDepartment`;**不进 Properties**;OwnerId 带 `MappingControls: '{"ParentId":"OwnerDeptId"}'`。DSL 里用 `useOwner` + layout 引用(见 dsl.owner_presets,Options 逐字对照线上)。
|
|
36
|
+
- v1 SchemaStr controlType = FormOwner/FormOwnerDepartment(dataType 26),SaveForm 通道不需显式给。
|
|
37
|
+
|
|
38
|
+
## 布局项与新控件(2026-09-11 类型试验表 D001599e98… UI 保存载荷逐字)
|
|
39
|
+
- **类型号(FormLayout.type,老枚举)**:地址 9 / 位置 10 / 附件 15 / 图片 16 / 分组标题 101 / 一行多列 102 / 描述 103 / 子表 104 / 流水号 201。**Properties.ControlKey(新枚举)**:流水号 14(与下拉同码)、图片 23、附件 24、位置 55、地址 56;分组标题/描述**根本不进 Properties**(布局项不是字段,FormLayout 里 key 是 uuid、无 DataField)。
|
|
40
|
+
- **键集比普通控件窄**:流水号无 `DisplayRule`/`ComputationRule`(且 **FormLayout options 里就没有 DisplayRule 键**);图片/附件/地址无 `ComputationRule`;位置无 `ComputationRule`/`LocationRangeLimit`(其余四类都保留 `LocationRangeLimit:null`);地址多 `AreaMode`、`DefaultValue` 是 **JSON 串**;流水号/图片/附件/位置 `DefaultValue` 是空串 `""`(普通文本框也是 "",下拉类才是 null)。
|
|
41
|
+
- **第三段 `ControlSettingsStr`**(与 SchemaStr/BizSheetStr 并列的**独立顶层段**):只有位置控件落这里 ——
|
|
42
|
+
`[{"key":"F0000024","dataField":"F0000024","options":{"LocationPCEnabled":"true","Meters":"500","LocationEditable":"false"}}]`,值全字符串、compact JSON。这三个键在 FormLayout 和 Properties 里**都没有**;不发这段 → 位置控件按默认值建。
|
|
43
|
+
- **LoadForm 回读的 ControlSettings 是 PascalCase**(`Key`/`DataField`/`Options`),而 SaveForm 收的是小写 `key`/`dataField`/`options` —— 与 DesignModeContent/其它段同款大小写差异;verify 用大小写不敏感取值兜住。
|
|
44
|
+
- LoadForm **不返回** `EnableSeqNo`/`SeqNoDateFormat`/`SeqNoPrefix`/`SeqNoLength`(返回 null)——流水号表单级设置改了也**回读不出来**,只能看控件 options 与 `SeqNoStructure`(这个回读有)。所以 verify 不比这组键。
|
|
45
|
+
- **JSON 值进 HTML 属性只做实体转义,不留反斜杠**:线上 `data-seqnostructure="[{"Type":1,…}]"`、
|
|
46
|
+
`data-defaultvalue="{"adcode"…}"`。用 `json.dumps(s)[1:-1]`(newbuilder 的 `hq`/`_esc`)会把内部 `\"` 原样带出去,写出 `{\"` —— 属性值里多出字面反斜杠。JSON 串一律用 `_escj`。
|
|
47
|
+
- **流水号运行态 HTML 的 `data-seqnostructure` 是设计器的 JS 拼串瑕疵** `"[object Object],[object Object]"`(设计态才是真 JSON)。运行态 HTML 只是渲染模板(结构以 FormLayout/Properties 为准),工厂照抄这串。
|
|
48
|
+
- 地址运行态那条 `data-defaultvalue` 线上**没有 `=` 两侧空格**(设计器单独拼串),其余属性都是 `data-x = "v"` 形态——工厂逐字照抄;这是唯一残留的空白差异(HTML 语义无影响)。
|
|
49
|
+
- 分组标题的删除按钮图标是 `icon-remove-block`、描述是 `icon-delete`;两者的**设计态** class 带 `row`、**运行态**去掉 `row`(线上如此)。
|
|
50
|
+
|
|
51
|
+
## 布局项的 key 必须是 GUID(2026-09-11 线上实证,工厂建试验表 D001599132f51bd09ee9c2613ac37e5ddcfc1f7)
|
|
52
|
+
- **短码当 key 会被平台吞掉**:SaveForm 用 `"key": "g_base"` 保存分组标题,回读 `Key=null`
|
|
53
|
+
→ 该布局项在设计树里整个消失,`verify` 报 `缺字段: ['g_base','d_note']`。换成
|
|
54
|
+
`uuid5(固定命名空间, 短码)` 出的 GUID 后回读 `Key="5ad722f6-a176-598e-…"` 原样保留、PASS。
|
|
55
|
+
(UI 每加一个布局项都发新 GUID;工厂用定值 uuid5 是为了 verify 能复算期望键。)
|
|
56
|
+
- **布局项是 FormLayout 顶层条目**(`ParentKey=""`、`DataField` 缺、`ChildControls: null`),不在
|
|
57
|
+
102 行里。工厂把**单独一行"的布局项**照此输出(普通单控件行仍包 1 子项 102 行,不动既有表)。
|
|
58
|
+
- 同一张表的其余实证(与线上逐字一致):`ControlSettings` 按定义值落库
|
|
59
|
+
`[{"Key":"loc_here","DataField":"loc_here","Options":{"LocationPCEnabled":"true","Meters":"300","LocationEditable":"true"}}]`
|
|
60
|
+
(PascalCase 回读);行组 3/3 `[1,2,3]`;8 字段(6 字段控件 + 2 布局项)全数回读 —— 7 类新控件
|
|
61
|
+
线上建表链路(DSL → 三段载荷 → SaveForm → LoadForm → verify)整条走通。
|
|
62
|
+
- **参数不写 = 平台默认**(2026-09-11 全默认版试验表线上 PASS,与 UI 拖入即默认一致):图片
|
|
63
|
+
`UploadMultiple/CameraOnly/HasWatermark/Compression` 全 false、附件 `MaxUploadSize` 10、
|
|
64
|
+
位置 `Meters 500` + PC 可用 + 不可编辑、地址 `AreaMode P-C-T` + `ShowDetailAddr true`、
|
|
65
|
+
流水号 `YYYY` + 8 位。定义里只写 `type/key/label` 就能建出这些默认;流水号连 key 都能省
|
|
66
|
+
(编码恒为 `SeqNo`,见 schema_doc)。
|
|
67
|
+
- **`cli.py build --force` 曾经换码**(`code = None if force else rec.get("code")`):force 会新发一个
|
|
68
|
+
表单编码,线上留一张孤儿表、断掉所有关联引用。已改成**编码一律复用**,force 只跳过"已存在即跳过"
|
|
69
|
+
的短路。要真正重建新表:先删 registry 里该表的记录。
|
|
70
|
+
|
|
71
|
+
## 设计态/运行态 HTML 是装饰,结构以 FormLayout + Properties 为准(2026-09-11 复核)
|
|
72
|
+
- 佐证:奥驰 table4 的 **38 条隐藏规则全部挂在 FormDropDownList 上**,而现有生成器下拉分支的
|
|
73
|
+
`data-displayrule` 一直写的是空规则常量(规则文本没进 HTML)——线上表照样按规则隐藏。
|
|
74
|
+
另有 `style="width: 100%%;"` 这类字面 `%%`(字符串没走 `%` 格式化)也照样能用。
|
|
75
|
+
→ **改 HTML 生成只会影响与 UI 样本的逐字一致性,不影响表单行为**;别为了"修 HTML"去动已上线表的生成路径。
|
|
76
|
+
- 新控件(流水号/图片/附件/位置/地址)的 HTML 已按 UI 样本逐字生成 + 离线比对(设计态 7/7 一致,
|
|
77
|
+
运行态仅剩地址那条属性前的空格差异)。**参照载荷**:`logs/types7_ui_save_payload.json`
|
|
78
|
+
(UI 真保存 PostData,无凭据);离线比对脚本与用例在 `D:\AI\自动编号\_cmp_types7.py`(`cmp`/`htmlcmp`/`e2e`)。
|
|
79
|
+
|
|
80
|
+
## 项目缺 config.json 会静默回落到根 config.json —— 落到**另一个应用**(2026-09-11 踩坑)
|
|
81
|
+
- `cfg_for(proj)` 的项目级 config 不存在时回落根 `config.json`。根配置指向哪个应用是**会变的**
|
|
82
|
+
(调试期临时指到试验应用、事后又改回业务应用),于是同一个 `projects/<名>/` 隔天 `build`
|
|
83
|
+
可能整批建到别的应用里。
|
|
84
|
+
- 症状有迷惑性:SaveForm 返回 **`ParentInvalid:父对象必须为OU或公司`**,看着像认证/组织问题,
|
|
85
|
+
实际是 `ParentCode`(那个应用的 appCode)对不上目标应用。**401 反而是好事**(token 过期,一眼能认)。
|
|
86
|
+
- 判据:表编码前 7 位 = appCode 前 7 位,两个应用**同前缀时看不出来**。稳妥做法——
|
|
87
|
+
`projects/<名>/config.json` 一律自己放一份,别依赖根配置;试验类项目(`_types7_online`)同理。
|
|
88
|
+
- 反向坑:**改项目 config 前先确认它没被别的东西复用**;`projects/_types7_online` 建表时用的是
|
|
89
|
+
`projects/aochi/config.json`(试验表都建在物料编码应用里),别误以为试验表在根配置的应用里。
|
|
90
|
+
|
|
91
|
+
## 环境
|
|
92
|
+
- Windows 控制台 GBK:`python -X utf8` 全命令前缀;报告文件 UTF-8。
|
|
93
|
+
- 请求间 sleep 0.3-0.5s;表单保存后回读前 sleep 0.5s(一致性)。
|
|
94
|
+
- 接口响应统一 `{Successful, ErrorMessage/ErrorCode, ReturnData}`;LoadForm 查不到表时 ErrorCode 含 "isnull"。
|
|
95
|
+
|
|
96
|
+
## 表单分组(v1/functionnode,2026-09-09 线上实证)
|
|
97
|
+
- 建组 `POST {base}/v1/functionnode`,body `{appCode, parentCode(=appCode 即顶层), displayName, nodeType: 230, icon: ""}` → 响应 **`{id: GUID, code: 32位hex}`**。分组码是裸 32hex,**不是**表单那种 `appCode前7位+hex` 格式。
|
|
98
|
+
- 改名/落定 `POST v1/functionnode/update`:create 全字段 + `code` + `objectId` + `summary:""`。UI 建组是两步(先 create 默认名再 update 真名),客户端照抄两步最稳;update 的 `objectId` 就是 create 响应里的 `id`(同一个 GUID)。
|
|
99
|
+
- 归组 `PUT v1/functionnode/sort`,body `{code: 表单编码, parentCode: 分组码}`;表单置回顶层 = `parentCode: appCode`。**请求只发 code+parentCode**,组内先后 = 移动顺序(拖拽排序参数未抓到)。
|
|
100
|
+
- 认证同 SaveForm 通道:`Authorization`(Bearer)+ `EngineCode` 头即可,无 cookie;三接口均返回 `True` 或简单对象。成功与否看 HTTP 无 4xx/5xx + 非错误 JSON。
|
|
101
|
+
- **没有分组读列表/删除接口**(GET list/tree、DELETE/POST delete 探测均 405 或 HTML 错误页)——分组码只能持久化在 registry `_groups` 段;多余分组只能在界面删。因此:工厂认不出界面手工建的同名组(会再建一个),别手工和工厂抢建同名组。
|
|
102
|
+
- 分组属应用菜单层,不进表单设计树 —— `verify` 不查分组;分组信息改动不触发表单重存。
|
|
103
|
+
|
|
104
|
+
## 联动下拉(选项来源=表单数据,2026-09-09 类型试验 实证)
|
|
105
|
+
- 下拉框原生支持"选项来自另一张表 + 级联过滤",字段仍是 FormDropDownList(ControlKey 14),只是 DataSource 从 `Custom` 切到 `Association`。
|
|
106
|
+
- **三处落点键集(权威:类型试验 F0000021 SaveForm 载荷逐字)**:
|
|
107
|
+
- Properties(ControlKey 14 + 标准空键集):`AssociationSchemaCode` = 源表编码、`MappingField` = 存值列、`AssociationFilter` = **纯文本**(不带 Rule 包壳);**无** DataSource/BOSchemaCode/BOSchemaInfo/AssociationFields 键;
|
|
108
|
+
- FormLayout type-7 options:`DataSource="Association"` + `BOSchemaCode` + `BOSchemaInfo`(JSON串:AppPackage/AppGroup/AppMenu=源表码/IsChildSchema) + `MappingField` + `AssociationFilter={"Rule":文本}` + `AssociationFields`(JSON串 {"isDefault":true,"fieldSetting":[]}) + `MappingControls=""`/`MappingProperties="{}"`;DefaultItems/ItemColors 残留占位项(UI 改型不清,见下);
|
|
109
|
+
- 设计 HTML:`data-datasource="Association"` + `data-boschemacode=..` `data-boschemainfo="{".."}"` `data-mappingfield=..` `data-associationfilter="{"Rule":"..\".."}"`(双层转义,同 DisplayRule 的 _rule_attr 生成法)+ `data-mappingcontrols=""` `data-associationfields=..`。
|
|
110
|
+
- JSON 串一律 compact(无空格):`{"isDefault":true,"fieldSetting":[]}` 这种,带空格会跟样本逐字漂移。
|
|
111
|
+
- `MappingField` = **存值列**:选中记录后把源行该列文本存入本字段(试验存 code 列;想保持老口径可存 name 列——存值是选列不是锁死)。
|
|
112
|
+
- `AssociationFilter` 规则:右值裸写本表单字段编码做动态引用,**级联就靠它**(切上级 → 选项池按条件实时过滤)。
|
|
113
|
+
- 切 Association 后 Properties `OptionalValues`/FormLayout `DefaultItems` 残留创建时占位选项(选项1/2/3)——UI 不清空;**工厂直建不带**(OptionalValues=""/DefaultItems=[],干净)——引擎对残留的取舍未单独观察,**大类别为空时的选项池表现仍待确认**。
|
|
114
|
+
- **h3factory DSL 已支持(同日落)**:sheets JSON dropdown 声明 `assoc/assocField/filter`(细则见 schema_doc「联动下拉」章节),构建自动落三处 + verify 规整比对;filter 只开放 `=`/`contains` 实证集合,radio/checkbox_list/子表列内 assoc 直接报错。
|
|
115
|
+
- **实证进展(同日晚第二轮)**:AND 连接多条件成立;checkbox_list 多值列(分号串)的"包含"匹配用函数式 `CONTAINS({源表.字段},{本表控件})`,第二参数同样支持动态控件引用;一条规则可同时引用多个本表控件。UI 会在 Rule 文本里插 NBSP、给 `==`/`!=` 两侧加空格(与 DisplayRule 同款漂移,生成/比对先规整)。
|
|
116
|
+
- **运行实证(同日,类型试验 运行时)**:过滤条件 `dictcategory=="特性代码" AND CONTAINS(applyto,{大类别下拉})` **运行时真实生效**——切 磁性材料 下拉出 4 条、电子料 出 13 条,与字典表行数一致;常量等值 / AND / CONTAINS + 动态引用全部按预期对源表执行。机制可下生产(料号申请表的大类别→特性代码/品类级联直接照此形态配)。
|
|
117
|
+
- **未实证(剩 2 项,非阻塞)**:①存值口径——MappingField=code 是否真存 code 文本,保存记录后抓 CreateBizObject 一次即可钉死(决定 .cs 拼接取 code 还是再查名称);②重开记录回显(显示列 vs 存值列)。大类别若设必填,空池兜底行为可不关心。
|
|
118
|
+
- **语义坑**:奥驰字典表里 分类列 存的是「特性代码/品类/大类别…」,大类别在 适用类别 列(44 行特性代码为单值、品类 11 行为多值)——探测轮用的 `dictcategory=={大类别}` 映射不到真实结构;正确形态应为 `dictcategory=="特性代码" AND CONTAINS(applyto,{已选大类别})`。
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# 需求澄清清单 —— AI 层每次接需求先过一遍
|
|
2
|
+
|
|
3
|
+
用途:给需求文档后,Claude Code 按此逐条问清,产出表单 JSON + 设计稿 JSON(人工过目)再建表。**歧义不澄清就建表 = 返工**(历史教训:显示名/代码口径反复、申请类型三分类来回确认)。
|
|
4
|
+
|
|
5
|
+
## 1. 表单盘点
|
|
6
|
+
- [ ] 共几张表?每张的业务角色(主数据/配置/单据/档案/计数)?能否合并?(档案与申请单重复时评估砍表)
|
|
7
|
+
- [ ] 字段清单:编码(短语义码)、名称、类型、必填、唯一、默认值
|
|
8
|
+
- [ ] 字段类型怎么映射:文本/多行/数字(小数位)/日期/开关/单选/下拉/复选/人员/部门/关联表/流水号/图片/附件/位置/地址
|
|
9
|
+
- [ ] 要不要**流水号**(平台自动发号)?→ 前缀/日期段(YYYY、YYYYMM…)/序号位数;分组计数与并发防重要不要另做(平台发号不分组)
|
|
10
|
+
- [ ] 图片/附件:几个附件位?上限多大(MB)?要不要多选上传/仅拍照/水印/压缩?(后四项界面另存,定义只标 maxSize)
|
|
11
|
+
- [ ] 哪张是唯一录入入口?其余表谁写入(流程/后端/导入/人维护)?
|
|
12
|
+
|
|
13
|
+
## 2. 枚举与字典
|
|
14
|
+
- [ ] 所有下拉/单选/复选的取值表(Excel 或文字)
|
|
15
|
+
- [ ] **存「名称」还是「代码」?**——显示名与存储值的关系(料号等拼接场景要代码,表单显示要名称;跨表转换谁来做:后端查字典?)
|
|
16
|
+
- [ ] 启停状态、排序有没有意义(维护表是否需要 启用/排序号 列)
|
|
17
|
+
|
|
18
|
+
## 3. 编号/编码规则(有自动编号时)
|
|
19
|
+
- [ ] 号段结构:前缀/分类码/流水(位数/补零)/版本/变更,逐段来源
|
|
20
|
+
- [ ] 流水按什么分组计数?并发防重机制(计数表键设计)
|
|
21
|
+
- [ ] 升版/变更/作废怎么表达?父号追溯?
|
|
22
|
+
- [ ] 查重范围:已作废/驳回的记录占不占号?
|
|
23
|
+
|
|
24
|
+
## 4. 规则与联动
|
|
25
|
+
- [ ] 显隐规则(选 A 显示哪些字段)——用 hideWhen 反写
|
|
26
|
+
- [ ] 联动带出(选规则带出前缀/模板)
|
|
27
|
+
- [ ] 校验:格式、必填条件、唯一性
|
|
28
|
+
|
|
29
|
+
## 5. 状态与流程
|
|
30
|
+
- [ ] 有审批吗?提交流程?驳回后数据怎么处理(已生成的号要不要收回)
|
|
31
|
+
- [ ] 状态机:新建/提交/生效/停用…每态可做什么
|
|
32
|
+
- [ ] 数据修谁改:申请单能改吗?走变更还是直接改?
|
|
33
|
+
|
|
34
|
+
## 6. 人与权限
|
|
35
|
+
- [ ] 创建人/创建部门(系统字段)够用吗?还是要独立申请人字段(代录场景)?
|
|
36
|
+
- [ ] 谁能看/谁能改:数据权限、部门隔离
|
|
37
|
+
|
|
38
|
+
## 7. 布局与体验
|
|
39
|
+
- [ ] 一行多列排布(4 列一排,哪些字段同行)?字段很多时**分组标题**分区/加**描述**说明文字?(布局项只能单独成行)
|
|
40
|
+
- [ ] 位置/地址控件要用吗?(位置:定位精度多少米、PC 端可否定位、可否手改;地址:省-市-县 + 详细地址)
|
|
41
|
+
- [ ] 生成结果字段展示(只读/整行)?
|
|
42
|
+
- [ ] 录入顺序与可见性(哪步先填)
|
|
43
|
+
|
|
44
|
+
## 8. 配套物
|
|
45
|
+
- [ ] 初始数据(字典/规则行)谁提供,数量级多大
|
|
46
|
+
- [ ] 界面手工配置清单(必填/只读/审批流/联动)——API 配不了,交付时单列
|
|
47
|
+
- [ ] 报表/列表视图/菜单挂载要求
|
|
48
|
+
|
|
49
|
+
## 交付物模板
|
|
50
|
+
|
|
51
|
+
1. `projects/<名>/sheets/*.json` + `dicts.json`(表单 JSON,dsl 校验 `cli.py check`)
|
|
52
|
+
2. 设计说明一页(表关系、编号规则、口径决定)
|
|
53
|
+
3. 界面配置清单(操作员照着点)
|
|
54
|
+
4. `.cs` 代码(TODO 补业务规则后交付)
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# 表单定义格式(sheets/*.json)
|
|
2
|
+
|
|
3
|
+
每个文件 = 一张表单,文件名即表单 key(registry 键、跨表 assoc 引用名)。`projects/demo/sheets/product.json` 是最小完整样例。
|
|
4
|
+
|
|
5
|
+
## 顶层键
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"title": "产品登记表", // 显示名
|
|
10
|
+
"nameSchema": "{pname}", // 记录显示名模板,{} 包字段编码
|
|
11
|
+
"useOwner": true, // 是否要系统拥有者字段(创建人/创建人部门)
|
|
12
|
+
"layout": "auto4", // 见下方「布局」
|
|
13
|
+
"controls": [ ... ] // 字段列表,顺序即定义顺序
|
|
14
|
+
}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## layout
|
|
18
|
+
|
|
19
|
+
| 写法 | 效果 |
|
|
20
|
+
|---|---|
|
|
21
|
+
| 省略 | 每控件一行(flat) |
|
|
22
|
+
| `"auto4"` | 每 4 个控件一行一行多列;`useOwner:true` 时首行 = [创建人, 创建部门] + 前 2 字段 |
|
|
23
|
+
| `[["k1","k2","k3","k4"], ["k5"], ...]` | 显式行:每行 1–4 个字段 key;owner 用字面量 `"OwnerId"`/`"OwnerDeptId"` |
|
|
24
|
+
|
|
25
|
+
一行多列控件最多 4 个。`useOwner:true` 时必须显式 layout(或 auto4),owner 不占 controls。
|
|
26
|
+
**布局项(分组标题/描述)只能单独成行**(`["g1"]`),写进一行多列直接报错——线上它们就是整行 div。
|
|
27
|
+
|
|
28
|
+
## 控件 type 一览
|
|
29
|
+
|
|
30
|
+
通用键(所有类型):`key`(编码,短语义码如 `pname`,已实证可持久化)、`label`(显示名)、`required`/`readonly`(**仅定义标注**,界面另存,SaveForm 不携带)、`hideWhen`(隐藏条件串,见下)。
|
|
31
|
+
|
|
32
|
+
| type | 额外键 | 说明 |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| `text` | `default`, `placeholder` | 单行文本 |
|
|
35
|
+
| `textarea` | `rows`(默认3), `default` | 多行文本 |
|
|
36
|
+
| `number` | `decimal`(小数位), `default` | 数字 |
|
|
37
|
+
| `date` | `datetime`(默认 `yyyy-MM-dd`) | 日期时间 |
|
|
38
|
+
| `switch` | `checked`(bool) | 开关(是/否) |
|
|
39
|
+
| `radio` | `dict` 或 `options`, `default` | 单选 |
|
|
40
|
+
| `dropdown` | `dict` 或 `options`, `default`, `hideWhen` | 下拉(**存储所选文本本身**);或 `assoc` 联动形态(选项来自另一张表,见「联动下拉」) |
|
|
41
|
+
| `checkbox_list` | `dict` 或 `options`, `defaults`(数组) | 复选,存储分号串 |
|
|
42
|
+
| `member` | `multi`(bool) | 人员单选/多选 |
|
|
43
|
+
| `department` | `multi`(bool) | 部门单选/多选 |
|
|
44
|
+
| `query` | `assoc`(另一个表单 key), `multi` | 关联表单控件;assoc 编码构建时从 registry 自动解析 |
|
|
45
|
+
| `seq_no` | `prefix`(默认空), `datetime`(默认 `YYYY`), `increment`(序号位数,默认 8);**`key` 可省(编码恒为 `SeqNo`)** | 流水号(type 201),平台按规则发号,**不能给 default/dict/options** |
|
|
46
|
+
| `image` | `multiple`, `cameraOnly`, `watermark`, `compression`(均 bool) | 图片(type 16),多选上传/仅拍照/水印/压缩 |
|
|
47
|
+
| `attachment` | `maxSize`(单附件上限 MB,默认 10) | 附件(type 15) |
|
|
48
|
+
| `location` | `meters`(定位精度默认 500), `pcEnabled`, `editable` | 位置(type 10);PC 端定位/是否可改由 ControlSettingsStr 承载 |
|
|
49
|
+
| `address` | `areaMode`(默认 `P-C-T`), `showDetail` | 地址(type 9);省-市-县三级 + 详细地址 |
|
|
50
|
+
| `group_title` | `label`(=标题文字), `align`(`left`/`center`/`right`) | **布局项**,不是字段 |
|
|
51
|
+
| `description` | `content`(HTML,缺省用 `<p>label</p>`), `title`(设计器显示名) | **布局项**,说明文字 |
|
|
52
|
+
|
|
53
|
+
`dict` = 引用 `dicts.json` 的分类名;`options` = 字面量数组。两者必有其一(单选/下拉/复选)。
|
|
54
|
+
|
|
55
|
+
`seq_no` / `image` / `attachment` / `location` / `address` 五类的载荷(FormLayout options 键、
|
|
56
|
+
Properties 键集、设计态/运行态 HTML、ControlSettingsStr)**逐字对照 UI 真实保存载荷**
|
|
57
|
+
(`logs/types7_ui_save_payload.json`,2026-09-11 类型试验表实测);`verify` 会回读比对位置控件的
|
|
58
|
+
ControlSettings(不符打印「位置设置不符」)。
|
|
59
|
+
|
|
60
|
+
## 子表(明细表) — type `subtable`
|
|
61
|
+
|
|
62
|
+
整行占据表单底部,不参与一行多列打包。JSON:
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{ "type": "subtable", "key": "specs", "label": "规格参数明细", "fixed": 1,
|
|
66
|
+
"columns": [
|
|
67
|
+
{ "type": "text", "key": "param", "label": "参数名" },
|
|
68
|
+
{ "type": "dropdown", "key": "unit", "label": "单位", "options": ["mm", "kg"] },
|
|
69
|
+
{ "type": "number", "key": "val", "label": "数值", "decimal": 2 }
|
|
70
|
+
] }
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
| 键 | 说明 |
|
|
74
|
+
|---|---|
|
|
75
|
+
| `key` / `label` | 子表编码引用名 / 显示名(不写 label 时界面即显示为 key) |
|
|
76
|
+
| `columns` | 列数组,列 spec 同普通控件(仅列内类型受限,见下) |
|
|
77
|
+
| `fixed` | 固定列数(默认 1;须配显隐与列宽等 UI 手工设置) |
|
|
78
|
+
|
|
79
|
+
- 列支持类型:**text / textarea / number / date / switch / radio / dropdown / checkbox_list / attachment / image**。成员/部门/关联/嵌套子表/位置/地址/流水号/布局项作列仍未开放,会直接报错(没有可照抄的实证样本)。
|
|
80
|
+
- **附件/图片列(2026-09-11 开放,线上实证待补)**:列节点走 `newbuilder.grid_layout_entry` 的 `col_entry`,它把主表同款 Options **原样搬运**、只改 `DataField` 为 `<子表码>.<列编码>`(这条约定来自 `logs/child_ref_payload.json` UI 真样本);而附件/图片的主表 Options 已逐字对齐 `logs/types7_ui_save_payload.json`。所以形状是"两个已实证样本拼起来的",**不是直接抓到的子表附件列 UI 样本**。
|
|
81
|
+
→ 验法:`projects/_types7_online/sheets/trial8.json` 已就绪(子表带 附件列 + 图片列),刷新 `projects/aochi/config.json` 的 `authorization` 后
|
|
82
|
+
`h3factory build _types7_online trial8` + 回读比对列节点逐键;通过即可从"待补"改为"已实证"。
|
|
83
|
+
- 子表**编码自动注册**:registry 里 `reg[key]["subs"][子表key] = {"code": "<appCode前7位>F+32位hex"}`(40 位,平台子表编码规则,与主表单 39 位不同)。**首次 build 前无需手工分配**——`cli.py build` 自动预注册;只跑 `check`(离线)时编码为空属正常。
|
|
84
|
+
- 布局约束:`layout` 的显式行数组里**不要写子表 key**(报错提示)——子表永远自动排在主字段行之后。
|
|
85
|
+
- 子表 UI 侧能配、定义里没有的(列宽/移动端/编辑子表对话框选项)照旧走**界面手工配置清单**。
|
|
86
|
+
- `.cs` 里取子表行集合:`List<BizObject> rows = (List<BizObject>)form[GRID_SPECS];` 每行 `row["param"]`。
|
|
87
|
+
|
|
88
|
+
## 布局项(分组标题 / 描述)
|
|
89
|
+
|
|
90
|
+
只占版面,**不是字段**:不进 `SchemaStr.Properties`、不进 NameSchema 可选字段、`verify` 按 key 单独比对。
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{ "type": "group_title", "key": "g1", "label": "基础信息", "align": "left" },
|
|
94
|
+
{ "type": "description", "key": "d1", "content": "<p>填表前请阅读…</p>" }
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
- 分组标题(FormGroupTitle,type 101)载荷里**连 ControlKey 都没有**,只有 `{DisplayName, Title, Alignment}`;
|
|
98
|
+
描述(FormDescription,type 103)带 `ControlKey` + `Content`(富文本 HTML)+ `DisplayRule: {}`。
|
|
99
|
+
- 两者在 FormLayout 里的 key 是 **uuid**、没有 `DataField`——定义侧写的 `key` 只是引用名,工厂用
|
|
100
|
+
`uuid5(固定命名空间, 定义 key)` 定值成 GUID(`controls.layout_key`),同一布局项每次构建同号,
|
|
101
|
+
verify 才能复算期望键。**别拿短码当 key**:2026-09-11 线上实证,短码保存后平台把 key 吞成
|
|
102
|
+
`null`,回读时该布局项整个消失、verify 报缺字段(详见 platform_gotchas)。
|
|
103
|
+
- 布局项在 FormLayout / HTML 里是**顶层条目**(线上样本 `parentKey=""`、不在 102 行里),工厂照此输出;
|
|
104
|
+
普通"单独一行"的字段仍包 1 子项的 102 行(既有表就是这么建的,改了会让 verify 行组期望对不上)。
|
|
105
|
+
- 子表仍然永远排在最后;布局项可与字段混排在各行之间,顺序即定义/layout 顺序。
|
|
106
|
+
|
|
107
|
+
## 流水号(type `seq_no`)
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
{ "type": "seq_no" } // 全默认:编码 SeqNo、标题"流水号"、YYYY+8 位
|
|
111
|
+
{ "type": "seq_no", "datetime": "YYYYMM", "increment": 6 }
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
- **`key` 可省,编码固定就是 `SeqNo`**(平台/界面的惯例,别另起名);`label` 省了默认"流水号"。
|
|
115
|
+
layout 行里引用的就是 `"SeqNo"`。一张表只能有一个(多个会因编码重复被拦)。
|
|
116
|
+
- 值是**表单级**设置(`SchemaStr`):`EnableSeqNo=true` / `SeqNoDateFormat` / `SeqNoPrefix` /
|
|
117
|
+
`SeqNoLength`(= 前缀长 + 日期段长 + 序号位数) / `SeqNoStructure`(JSON 串
|
|
118
|
+
`[{"Type":1,"Value":"YYYY"},{"Type":2,"IncreNum":8,"Value":"1"}]`)。工厂按控件**自动推导**,
|
|
119
|
+
无需在顶层另写;`datetime: "YYYY"` + `increment: 8` → `SeqNoLength=12`。
|
|
120
|
+
- `datetime` 段长按字符串长度算:支持 `YYYY`/`YYYYMM`/`YYYYMMDD` 等(线上样本为 `YYYY`)。
|
|
121
|
+
- 控件本体 Options 另有 `Prefix`/`DateTimeMode`/`SeqNoStructure`/`IncrementNum`;**没有 `DisplayRule` 键**
|
|
122
|
+
(线上如此,隐藏规则配不上)。
|
|
123
|
+
- `default`/`dict`/`options` 会被报错拦下——值由平台发。
|
|
124
|
+
- 序号位数用满后平台自动进位加宽,定义侧不用管。
|
|
125
|
+
|
|
126
|
+
## 位置 / 地址 / 图片 / 附件
|
|
127
|
+
|
|
128
|
+
- **位置(FormMap)**:`Meters`/`LocationPCEnabled`/`LocationEditable` 三个键**不在 FormLayout,也不在
|
|
129
|
+
Properties**——走载荷顶层独立的第三段 `ControlSettingsStr`
|
|
130
|
+
(`[{"key","dataField","options":{...}}]`,值全是字符串)。`cli.py build` 自动带上;
|
|
131
|
+
改定义后 `verify` 会连这段一起回读比对。`data-locationrangelimit` 线上写死 `"undefined"`。
|
|
132
|
+
- **地址(FormAreaSelect)**:`Properties` 侧多一个 `AreaMode` 键,`DefaultValue` 是 **JSON 串**
|
|
133
|
+
(`{"adcode":"","adname":"","Detail":""}`),不是普通文本;`areaMode` 目前只实证 `P-C-T`。
|
|
134
|
+
- **图片/附件**:`Properties` 里 `DefaultValue` 是空串、无 `ComputationRule` 键(与文本框不同);
|
|
135
|
+
附件 `MaxUploadSize` 单位 MB。多附件/必填/只读、拍照/水印等由界面另存(见界面手工配置清单)。
|
|
136
|
+
- 这几类在 FormLayout options 里键集**比普通控件窄**(无 `PlaceHolder`/`DataLink*`),工厂按类型裁剪。
|
|
137
|
+
|
|
138
|
+
## 表单分组(应用菜单归类)
|
|
139
|
+
|
|
140
|
+
表多了把应用菜单按模块分组。**分组属于应用菜单层,不影响表单设计**:建表照旧,全部建完跑一条命令归组。
|
|
141
|
+
|
|
142
|
+
```json
|
|
143
|
+
// sheets/xxx.json 顶层加一行
|
|
144
|
+
{ "title": "产品登记表", "group": "主数据", "controls": [ ... ] }
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
- `group` = 归入分组的显示名,多表单可同组;表单定义时**不必**提前建组(group 命令会自动建)。
|
|
148
|
+
- 项目可选 `groups.json` —— 有序分组清单(顺序 = 应用菜单从上到下的创建顺序,也即最终展示顺序):
|
|
149
|
+
|
|
150
|
+
```json
|
|
151
|
+
[ "基础信息", { "name": "项目管理" }, "合同收支", "数据分析" ]
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
- **有 groups.json 时**,表单的 `group` 必须在清单里,拼写错了 `check`/`build` 直接报错早拦;
|
|
155
|
+
**没有** groups.json 时分组不校验、按表单出现顺序归组(推荐大项目都建 groups.json)。
|
|
156
|
+
- 归组命令(建好表后):`h3factory group <项目> [表..]`
|
|
157
|
+
- 幂等:分组编码 + objectId 存 registry `_groups` 段;已有组跳过不重建,重复运行安全
|
|
158
|
+
- 每次运行都会把声明的表**重新移回**所属分组(界面上被人拖走的会拉回来)
|
|
159
|
+
- 平台**没有分组读列表/删除接口**(已实证),分组码只认 registry —— 手删 `_groups` 段后,组会以新码重建
|
|
160
|
+
- 工厂认不出界面手工建的同名组(无读接口),会再建一个同名的 → 手工建过同名组就把界面上那个删掉,让工厂自建
|
|
161
|
+
- legacy forms.py 定义不支持 group(只对 sheets/*.json 生效)。
|
|
162
|
+
|
|
163
|
+
## dicts.json(枚举)
|
|
164
|
+
|
|
165
|
+
```json
|
|
166
|
+
{
|
|
167
|
+
"申请类型": ["新料号", "升版", "变更"], // 简写:仅名称(显示即存储)
|
|
168
|
+
"大类别": [ {"code": "SJ", "name": "塑胶件"}, // 全写:有代码(如料号中段要代码)
|
|
169
|
+
{"code": "DZ", "name": "电子料", "enabled": false} ] // enabled:false 跳过
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
数组顺序 = 下拉排序。代码为空的条目显示名即代码。
|
|
174
|
+
|
|
175
|
+
## hideWhen —— 显隐条件(DisplayRule)
|
|
176
|
+
|
|
177
|
+
语义:**条件匹配时隐藏**,默认显示。只支持这套语法(引擎实证,别写别的):
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
{字段编码}=="值" 等于 → 隐藏
|
|
181
|
+
{字段编码}!="a" AND {字段编码}!="b" 不属于集合 → 隐藏(多值 NOT∈S 用 AND != 链)
|
|
182
|
+
条件A OR 条件B 任一满足 → 隐藏
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
已知边界:**关联表单控件与文本比较是否按显示名未最终实证**(奥驰 rulecfg 按记录显示名语义写的,新项目若遇异常先在界面试一条)。隐藏规则由界面另存/引擎复写后可能与定义漂移 —— `cli.py verify` 会抓出来。
|
|
186
|
+
|
|
187
|
+
## 跨表引用(assoc)
|
|
188
|
+
|
|
189
|
+
`query` 的 `assoc` 写目标表单 key(如 `"table1"`),构建时从 registry.json 取目标编码。**先建被引用表**。若用 legacy forms.py 定义,assoc 依赖 `table1`/`table4` 两个 key 在 registry 中存在(奥驰约定),新 JSON 项目则支持任意 key。
|
|
190
|
+
|
|
191
|
+
## 联动下拉(下拉选项来自另一张表 + 级联过滤)
|
|
192
|
+
|
|
193
|
+
下拉框原生支持把选项池接到另一张表单的数据上,并按别的字段值实时过滤 —— 级联下拉。**运行时已实证**(2026-09-09 类型试验:大类别→特性代码 切换过滤,出选项数与源表行数一致),可下生产。`assoc` 源表必须是同项目 registry 里已注册的表(编码在 build 时解析;跨项目的旧表如奥驰通用字典表,手工往 registry.json 补一条 `"字典key": {"code": "<线上编码>"}` 即可引用)。
|
|
194
|
+
|
|
195
|
+
```json
|
|
196
|
+
{ "type": "dropdown", "key": "proptype", "label": "特性代码",
|
|
197
|
+
"assoc": "dictionary", // 选项来源表单 key(registry 已注册,先建被引用表)
|
|
198
|
+
"assocField": "code", // 存值列 = 源表字段编码:选中后把源行该列文本存入本字段
|
|
199
|
+
"filter": [ // 级联过滤,AND 连接;可空 = 不过滤(整表选项)
|
|
200
|
+
{ "field": "dictcategory", "value": "特性代码" }, // 常量等值 → {源表.字段}=="特性代码"
|
|
201
|
+
{ "field": "applyto", "op": "contains", "ref": "bigcat" } // → CONTAINS({源表.applyto},{bigcat})
|
|
202
|
+
] }
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
- `assoc` 与 `dict`/`options` **互斥**(选项来自表不是枚举);`default` 暂不支持(联动存值/回显语义未实证);`hideWhen` 照常可用。
|
|
206
|
+
- `assocField` **必填**(存 code 还是 name 由料号拼接口径定——存什么字段,库里就是那列文本)。
|
|
207
|
+
- `filter` 条目:`field` = 源表字段编码;`op` = `=`(缺省)或 `contains`,二选一搭配:
|
|
208
|
+
- `=` + `value`(字符串常量,须带引号形态序列化)、`=` + `ref`(本表字段 key,动态引用,引擎按 ref 当前值实时过滤——**级联就靠它**);
|
|
209
|
+
- `contains` + `ref`:源表该列是分号串多值(如 适用类别=电子料;磁性材料),按"包含"匹配。
|
|
210
|
+
- 生成的规则文本:常量带双引号、`==` 无空格、条件间 ` AND ` 连接、源表引用带编码前缀 `{源表编码.字段}`、本表引用裸写 `{key}`。UI 重存会在规则里插 NBSP/给符号加空格——`verify` 自动规整比对,定义侧永远写干净文本。
|
|
211
|
+
- **受限**(未实证,`check` 直接报错):radio/checkbox_list 不支持 assoc;子表列内不支持;filter 只开放 `=`/`contains` 两 op;常量只能是字符串(数字列等值未实证)。
|
|
212
|
+
- 存值只有一列文本;要展示/换算另一列(如显示名↔代码),业务代码里按存值查一次源表。
|
|
213
|
+
|
|
214
|
+
## legacy 兼容
|
|
215
|
+
|
|
216
|
+
`projects/<名>/forms.py`(奥驰样式:`BUILDERS` 字典 + `build(key, app_code, rule_table_code=, apply_table_code=)` 返回 `{key,title,name_schema,fields,layout,assoc}`)会被自动加载并和 sheets/*.json 合并。新项目请用 JSON,forms.py 仅迁移用。
|
package/docs/workflow.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# h3factory 使用流程(SOP)
|
|
2
|
+
|
|
3
|
+
氚云表单工厂的完整操作手册。**一句话:** 需求文档 →(AI 层)设计出 JSON →(你)过目 →(工厂)一条命令建表 → 只读核对 → 补代码交付。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 0. 概念与角色
|
|
8
|
+
|
|
9
|
+
| 层 | 谁 | 干什么 |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| AI 层 | Claude Code | 读需求 → 澄清 → 产出表单 JSON + 设计说明;**每次新需求都开新会话做** |
|
|
12
|
+
| 工厂层 | `h3factory` CLI(纯 Python 内核) | 建表/核对/导数据/生成代码骨架,不依赖 AI |
|
|
13
|
+
| 你 | 人 | **过目设计**(唯一不能省的环节)、填凭据、界面手工配置 |
|
|
14
|
+
|
|
15
|
+
目录必须分清:
|
|
16
|
+
- **工作区**(你运行命令的当前目录,如 `D:\h3work`)—— 放 `config.json` 和 `projects/<名>/`
|
|
17
|
+
- **安装目录**(npm 全局包) —— 只读代码与文档,不要往里写业务文件;`h3factory doctor` 会显示位置
|
|
18
|
+
- 旧工程 `D:\AI\自动编号\auto_build_h3\` —— 历史留档,新需求别用
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 1. 一次性准备(每台机器只做一次)
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install -g git+ssh://git@github.com/<账号>/h3factory.git # 或本地 tgz
|
|
26
|
+
mkdir D:\h3work && cd /d D:\h3work
|
|
27
|
+
|
|
28
|
+
h3factory init # 生成 ./config.json,按提示填;--no-input 则只复制模板
|
|
29
|
+
h3factory doctor # 检查 Python / 配置字段 / JWT 是否过期 / 技能
|
|
30
|
+
```
|
|
31
|
+
- 凭据键:`baseUrl`(氚云域名 api 地址)、`engineCode/engineSecret`(引擎凭据,长期有效)、`authorization`(JWT,**会过期**,过期去后台重新生成粘回)、`appCode`(**目标应用**,决定表建到哪个应用)
|
|
32
|
+
- `projects/<名>/config.json` 可覆盖工作区配置(不同 app 用不同 config 时)
|
|
33
|
+
- 也可用 `H3FACTORY_CONFIG` 指定配置、`H3FACTORY_HOME` 指定工作区
|
|
34
|
+
- ⚠️ config.json 含凭据:**不提交、不分享、不让 AI 打印**
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 2. 每轮新需求的 8 步(核心流程)
|
|
39
|
+
|
|
40
|
+
### ① 丢需求 → AI 澄清
|
|
41
|
+
新窗口对 Claude Code 说:
|
|
42
|
+
```
|
|
43
|
+
用 h3factory 帮我做这个需求:[需求文档/链接/贴文本]
|
|
44
|
+
按 docs/requirement_checklist.md 先澄清,产出设计后停下来等我过目。
|
|
45
|
+
config.json 只读取使用,不要打印内容。
|
|
46
|
+
```
|
|
47
|
+
Claude 按 `docs/requirement_checklist.md` 逐条澄清(实体/枚举/编号规则/状态/审批/口径)。
|
|
48
|
+
|
|
49
|
+
### ② AI 产出 → 你过目(不可省)
|
|
50
|
+
Claude 在工作区 `projects/<新项目名>/` 下产出:
|
|
51
|
+
- `sheets/*.json` —— 每张表单一个文件(格式见 `docs/schema_doc.md`)
|
|
52
|
+
- `dicts.json` —— 枚举字典
|
|
53
|
+
- `groups.json` —— 表单分组清单(要按模块分组的项目才需要;顺序 = 菜单顺序)
|
|
54
|
+
- 一页设计说明(表关系/编号规则/口径决定)
|
|
55
|
+
|
|
56
|
+
**你检查**:表数量对不对、字段齐不齐、下拉取值、编号规则、显示/存储口径。
|
|
57
|
+
|
|
58
|
+
### ③ 本地校验(离线,秒级)
|
|
59
|
+
```bash
|
|
60
|
+
h3factory check <项目名> [表..]
|
|
61
|
+
# 输出示例: product 字段=7 隐藏规则=1 行组(fourCols)=3 关联=- 子表=1(列4) 布局项=2 标题=产品登记表 分组=主数据
|
|
62
|
+
```
|
|
63
|
+
只看字段数/规则数/行组/分组对不对,语法错误(含 group 不在 groups.json 声明)会直接报。
|
|
64
|
+
想先体验流程: `h3factory demo && h3factory check demo`。
|
|
65
|
+
|
|
66
|
+
### ④ 建表
|
|
67
|
+
```bash
|
|
68
|
+
h3factory build <项目名> # 全部表,或 build <名> table1 table2 指定
|
|
69
|
+
```
|
|
70
|
+
- 表单编码 = appCode前7位+32位随机,自动注册到 `projects/<名>/registry.json`
|
|
71
|
+
- **重复运行安全**:已注册且线上存在的表自动跳过(防止重存抹掉界面配置);要强制重存加 `--force`(会整体替换,UI 必填/联动会丢,慎用!)
|
|
72
|
+
- 关联表(下拉选另一张表)要先建被引用的表
|
|
73
|
+
|
|
74
|
+
### ⑤ 只读核对
|
|
75
|
+
```bash
|
|
76
|
+
h3factory verify <项目名>
|
|
77
|
+
```
|
|
78
|
+
回读线上表单逐字段比对:字段数、每条显隐规则文本、一行多列行组数、子表(编码+列)、布局项(分组标题/描述,按 key)、
|
|
79
|
+
联动下拉过滤规则、位置控件设置(ControlSettingsStr:定位精度/PC 定位/可否手改)、NameSchema。输出 PASS/FAIL,报告存 `projects/<名>/logs/verify_report.txt`。**只读不写,可反复跑**——上线后定期跑能抓"界面改了但定义没同步"的漂移。
|
|
80
|
+
|
|
81
|
+
### ⑥ 表单归组(有分组的项目才需要)
|
|
82
|
+
```bash
|
|
83
|
+
h3factory group <项目名>
|
|
84
|
+
```
|
|
85
|
+
- 按各表 JSON 的 `group` 建分组并把表移进去;**重复运行安全**(分组码存 registry,已有组跳过)
|
|
86
|
+
- 每次运行会把声明组的表拉回所属分组 —— 界面拖乱了一跑就归位
|
|
87
|
+
- 平台没有分组读/删接口,多余分组只能界面上删
|
|
88
|
+
|
|
89
|
+
### ⑦ 导初始数据(有字典/规则行时)
|
|
90
|
+
```bash
|
|
91
|
+
h3factory import <项目名> <表> data.json [--submit]
|
|
92
|
+
# data.json = 行数组,字段 key 用表单编码
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### ⑧ 代码与界面清单
|
|
96
|
+
```bash
|
|
97
|
+
h3factory gen <项目名> <表>
|
|
98
|
+
# 生成 .cs 提交时代码骨架 → projects/<名>/generated/<表>.cs
|
|
99
|
+
```
|
|
100
|
+
- Claude/AI 按骨架里 TODO 补业务规则(计数/拼接/校验/跨表逻辑)
|
|
101
|
+
- 代码粘到:氚云表单设计器 → 业务规则/后端事件 → 提交时(**类名必须 = 表单 SchemaCode**,骨架已填)
|
|
102
|
+
- **界面手工配置清单**(AI 配不了,交付时单独列):必填项、只读、审批流、字段联动、列表视图
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## 3. 日常操作速查
|
|
107
|
+
|
|
108
|
+
| 想干什么 | 命令 |
|
|
109
|
+
|---|---|
|
|
110
|
+
| 看运行时/配置/JWT 状态 | `h3factory doctor` |
|
|
111
|
+
| 复制示例项目 | `h3factory demo` |
|
|
112
|
+
| 看某项目各表编码/状态 | `h3factory list <项目名>` |
|
|
113
|
+
| 只读核对线上与定义 | `h3factory verify <项目名>` |
|
|
114
|
+
| 建新表/补建表 | `h3factory build <项目名> <表>` |
|
|
115
|
+
| 重新生成某表(会覆盖 UI 配置) | `h3factory build <项目名> <表> --force` |
|
|
116
|
+
| 表单归组(建分组+移入) | `h3factory group <项目名>` |
|
|
117
|
+
| 批量导数据 | `h3factory import <名> <表> data.json` |
|
|
118
|
+
| 生成代码骨架 | `h3factory gen <项目名> <表>` |
|
|
119
|
+
| 查看内置文档 | `h3factory docs [名称]` |
|
|
120
|
+
| 重装技能 | `h3factory skill install` |
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## 4. 常见问题
|
|
125
|
+
|
|
126
|
+
| 现象 | 原因/处理 |
|
|
127
|
+
|---|---|
|
|
128
|
+
| `verify` 报规则不符/多字段 | 界面上手工改过 → 定义与线上漂移。确认 UI 改动是否要回写定义(改 sheets/*.json 或 forms.py) |
|
|
129
|
+
| `authorization` 过期 | `h3factory doctor` 会报 FAIL → 氚云后台重新生成 JWT,粘回 config.json |
|
|
130
|
+
| 建表报引擎错误 | engineCode 绑应用 → 用目标应用自己后台的 engineCode/engineSecret |
|
|
131
|
+
| 想换目标应用 | 只改 config.json 的 `appCode` |
|
|
132
|
+
| registry.json 删了/丢了 | 编码失忆 → 表还在但找不到编码;有 `list` 前的备份可恢复,否则只能用 LoadForm 已知编码找回 |
|
|
133
|
+
| 编码不显示中文 | 用 `h3factory` 命令(自动 UTF-8);源码方式跑必须 `python -X utf8 cli.py` |
|
|
134
|
+
| 提示找不到 Python | 安装 Python 3.10+ 并加入 PATH,或设 `H3FACTORY_PYTHON` |
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## 5. 真实演练验收清单(新窗口测试用)
|
|
139
|
+
|
|
140
|
+
1. 新窗口 Claude 按 README 走,产出设计 JSON 先给你过目
|
|
141
|
+
2. `h3factory check` 通过(离线无报错)
|
|
142
|
+
3. 表建到**测试 app**(appCode 已换),不是生产 app
|
|
143
|
+
4. `h3factory verify` 输出 PASS
|
|
144
|
+
5. `h3factory gen` 生成 .cs,类名 = SchemaCode
|
|
145
|
+
6. 交付包含「界面手工配置清单」
|
|
146
|
+
7. config.json 内容没有被打印/写进任何文档
|
|
File without changes
|