lan-low-code-cli 2.5.0 → 2.6.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 +113 -0
- package/dist/api/formDefine.js +31 -1
- package/dist/api/operation.js +27 -0
- package/dist/api/template.js +76 -0
- package/dist/api/view.js +23 -0
- package/dist/commands/form.js +181 -1
- package/dist/commands/operation.js +730 -0
- package/dist/commands/template.js +541 -0
- package/dist/index.js +9 -1
- package/package.json +49 -49
- package/skills/lan-low-code-cli/SKILL.md +8 -3
- package/skills/lan-low-code-cli/SKILL.zh-CN.md +8 -3
- package/skills/lan-low-code-cli/references/cli-contract.md +95 -6
- package/skills/lan-low-code-cli/references/cli-contract.zh-CN.md +94 -6
- package/skills/lan-low-code-cli/references/mkxform-api.md +2652 -2652
- package/skills/lan-low-code-cli/references/operation-script-context.md +220 -0
package/README.md
CHANGED
|
@@ -77,6 +77,70 @@ llc form create --name <名称> [选项]
|
|
|
77
77
|
| `--fd-run-entity-name <name>` | 表单运行时实体名称 |
|
|
78
78
|
| `--table-name <name>` | 主表名(不传则调用对应接口自动生成) |
|
|
79
79
|
|
|
80
|
+
**表单类型**(`--type`):
|
|
81
|
+
|
|
82
|
+
| 类型 | 说明 | 表结构 |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| 缺省 / `common` | 普通表单(应用下默认走 `modeling` 族) | 主表 |
|
|
85
|
+
| `category` | 分类表单:分类树 + 多个模板 | 分类表 + 模板表 + 主表 |
|
|
86
|
+
| `simpleCategory` | 简单分类表单:分类与模板合一,强制多层级 | 聚合表 + 主表 |
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# 分类表单:自动生成三张表名,创建后立即发布
|
|
90
|
+
llc form create --name "采购分类表单" --app-id <appId> --type category --publish
|
|
91
|
+
|
|
92
|
+
# 简单分类表单
|
|
93
|
+
llc form create --name "简版分类表单" --app-id <appId> --type simpleCategory --publish
|
|
94
|
+
|
|
95
|
+
# 共享已有分类表单的分类(沿用对方的分类表与层级设置)
|
|
96
|
+
llc form create --name "共享分类表单" --app-id <appId> --type category --share-category purchaseCategory
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
- 分类表单走 `categoryModel/init → add →(--publish 时 save → publish)`,与普通表单接口完全不同;
|
|
100
|
+
- 表名可用 `--table-name`(主表)、`--category-table-name`、`--template-table-name`(分类)、
|
|
101
|
+
`--polymers-table-name`(简单分类聚合表)显式指定,缺省逐个调用 `generateTableName`;
|
|
102
|
+
- 分类表单本身**不含业务字段**,`--add-field` / `--fields` / `--from-model` 会被拒绝——字段属于「模板」;
|
|
103
|
+
- 默认多层级分类,`--no-support-hierarchy` 改单层级;简单分类强制多层级、不支持共享分类;
|
|
104
|
+
- 模板(模板表单)用下面的 `llc template create` 创建;
|
|
105
|
+
- 分类表单的删除只能在平台操作(后端 `categoryModel/delete` 禁止前端直接调用),
|
|
106
|
+
`form get --id` 已能识别分类表单并展示 `fdType` / 三张表名。
|
|
107
|
+
|
|
108
|
+
**分类表单模板**(`llc template`):
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
# 列出分类表单下的模板(运行时分类树)
|
|
112
|
+
llc template list --category-code <categoryCode>
|
|
113
|
+
|
|
114
|
+
# 创建模板,并把既有表单的字段 / 视图 / 权限移植进来,然后发布
|
|
115
|
+
llc template create --category-code <categoryCode> --name "合作模板" \
|
|
116
|
+
--from-form <来源表单 fdId> --publish
|
|
117
|
+
|
|
118
|
+
# 给已有模板追加字段(默认重建栅格布局让新字段可见;--keep-layout 保留原布局)
|
|
119
|
+
llc template add-fields --template-id <templateId> --category-code <categoryCode> \
|
|
120
|
+
--add-field "fd_budget:合作预算:moneytext" \
|
|
121
|
+
--add-field "fd_contact:对接人:address" --publish
|
|
122
|
+
|
|
123
|
+
# 删除模板(--all 清空该分类表单下的模板,需 --yes)
|
|
124
|
+
llc template delete --category-code <categoryCode> --all --yes
|
|
125
|
+
llc template delete --category-code <categoryCode> --template-id <templateId> --yes
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
- 分类表单 `fdType=1` 走 `categoryTemplate/add`,简单分类 `fdType=2` 走 `virtualPolymers/add`;
|
|
129
|
+
- **跳过官方 `init`**:模板表元数据未就绪时 `init` 会空指针,改为 `add` + `mechanisms['sys-xform'].fdBuildNew=true`
|
|
130
|
+
由后端建表并注册元数据,再 `sys-xform/sysXFormDesign/save` 写入设计;
|
|
131
|
+
- `--from-form` 会克隆来源表单的主表业务字段、视图布局(页签/栅格)与字段权限,表名替换为模板表;
|
|
132
|
+
**明细表节点会被剔除**(模板表结构不支持直接挂明细),可用 `--fields` 只取部分字段;
|
|
133
|
+
- 分类表单的模板必须挂在分类节点下:不传 `--category-node` 时自动建一个分类节点(名称默认取模板名,可用
|
|
134
|
+
`--category-name` 指定);
|
|
135
|
+
- 创建后 `template list` 能看到,平台发起页即可选择该模板填写。
|
|
136
|
+
- 注意区分两份设计:`template add-fields` 改的是**模板实体**的表单设计(落模板表/聚合表);
|
|
137
|
+
而简单分类表单「自身的模板表单」(前台新建模板时默认使用的那份)用
|
|
138
|
+
`llc form autofill --id <分类表单 fdId> --add-field ... --apply --publish` 维护,两者互不影响。
|
|
139
|
+
- 模板编辑器打开时会拿分类表单的**发布配置**(`categoryModel/getReleaseConfig`)做字段合并,
|
|
140
|
+
该配置缺 `sign` 时会报 `Cannot read properties of undefined (reading 'formula')`;
|
|
141
|
+
`template create` 会自动检查并用分类表单自身设计重新发布补齐
|
|
142
|
+
(等价于对分类表单执行 `form autofill --id <分类表单 fdId> --apply --publish`)。
|
|
143
|
+
|
|
80
144
|
其余选项:
|
|
81
145
|
|
|
82
146
|
| 选项 | 说明 |
|
|
@@ -196,6 +260,55 @@ llc field library [--keyword <kw>] # 字段库
|
|
|
196
260
|
llc field gen-key --name <名称> # 生成字段编码
|
|
197
261
|
```
|
|
198
262
|
|
|
263
|
+
### 表单业务操作
|
|
264
|
+
|
|
265
|
+
在表单的列表页/查看页上增加按钮(对应平台「表单 → 业务操作」Tab)。
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
llc operation list --form-id <fdId>
|
|
269
|
+
llc operation create --form-id <fdId> --name 打开帮助 --code openHelp \
|
|
270
|
+
--type link --position view --url https://example.com
|
|
271
|
+
llc operation create --form-id <fdId> --name 批量归档 --code archive \
|
|
272
|
+
--type script --script @archive.js
|
|
273
|
+
llc operation create --form-id <fdId> --name 转办 --code transfer \
|
|
274
|
+
--type dialog --dialog-id <对话框id>
|
|
275
|
+
llc operation get --id <operationId>
|
|
276
|
+
llc operation update --id <operationId> --type script \
|
|
277
|
+
--script @examples/operation-script-modal-table.js # 把已有按钮改成脚本模式
|
|
278
|
+
llc operation attach --form-id <fdId> --operation-id <operationId> # 挂到列表视图(desktop/top)
|
|
279
|
+
llc operation attach --form-id <fdId> --operation-id <operationId> --target view --position rightHand
|
|
280
|
+
llc operation detach --form-id <fdId> --operation-id <operationId> # 从视图移除
|
|
281
|
+
llc operation delete --id <operationId> --yes # 被页面引用时拒绝
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
- `--type`:`link`(fdType=2 / fdViewType=4,需 `--url`)、`script`(3 / 5,需 `--script`,支持 `@文件`)、
|
|
285
|
+
`dialog`(3 / 1,需 `--dialog-id`)
|
|
286
|
+
- `--position`:`list`(默认,列表视图)/ `view`(查看视图)
|
|
287
|
+
- 默认不要求勾选数据;需要“先勾选数据再执行”时加 `--need-select`(链接会按接口调用,`fdUrlType=2`)
|
|
288
|
+
- `--dry-run` 只打印请求体;新建操作默认仅管理员可用
|
|
289
|
+
- `update` 基于现有操作合并:显式 `--type` 才切换类型(会重建类型相关配置,保留权限/默认值配置),
|
|
290
|
+
省略时保持原类型;`--script` 支持 `@文件`,配套示例见
|
|
291
|
+
`examples/operation-script-modal-table.js`(弹窗 + 表格)
|
|
292
|
+
- `attach` / `detach` 修改视图的 `operationList`:列表视图写 `fdExtendConfig`,查看视图写 `fdConfig`;
|
|
293
|
+
`--view-id` 省略时自动定位该表单唯一的视图,重复挂载幂等
|
|
294
|
+
|
|
295
|
+
脚本模式(fdType=3 / fdViewType=5)的脚本在页面中这样执行:
|
|
296
|
+
|
|
297
|
+
```js
|
|
298
|
+
new Function('context', fdJavaScript)({
|
|
299
|
+
...context,
|
|
300
|
+
fdOprId, fdIds, fdBtnCfg, destroyLoading,
|
|
301
|
+
})
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
- `context.fdIds` 仅在行内按钮/标准行操作时有值(当前行 id);工具栏按钮的勾选在 `context.selectedId`(数组),
|
|
305
|
+
当前行 id 另有 `context.docId`
|
|
306
|
+
- 弹窗能力来自宿主页面的 `window.MKXFORM`(`tableModal` / `modal` / `HTMLModal`)
|
|
307
|
+
- 脚本内调用 `context.destroyLoading()` 可主动关闭「执行中...」提示
|
|
308
|
+
- 完整上下文清单(选中数据、刷新列表、查询、跳转、事件总线、移动端差异)见
|
|
309
|
+
[skills/lan-low-code-cli/references/operation-script-context.md](skills/lan-low-code-cli/references/operation-script-context.md)
|
|
310
|
+
|
|
311
|
+
|
|
199
312
|
### 控件类型
|
|
200
313
|
|
|
201
314
|
**先查环境再选控件**:
|
package/dist/api/formDefine.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.dataSetApi = exports.modelingAppApi = exports.modelingXFormApi = exports.designApi = exports.wordsFieldApi = exports.dataModelApi = exports.formCategoryApi = exports.formDefineApi = void 0;
|
|
3
|
+
exports.dataSetApi = exports.modelingAppApi = exports.categoryModelApi = exports.modelingXFormApi = exports.designApi = exports.wordsFieldApi = exports.dataModelApi = exports.formCategoryApi = exports.formDefineApi = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* 表单定义接口(后端 SysGeneralFormDefineController)
|
|
6
6
|
* 基础路径:/data/sys-xform/generalFormDefine/
|
|
@@ -141,6 +141,36 @@ exports.modelingXFormApi = {
|
|
|
141
141
|
/** 删除业务表单的运行时数据(保留表单定义) */
|
|
142
142
|
removeData: (client, fdId) => client.post(`${MODELING_XFORM_BASE}/deleteData`, { fdId }),
|
|
143
143
|
};
|
|
144
|
+
/**
|
|
145
|
+
* 分类表单 / 简单分类表单(后端 SysModelingCategoryModelController)
|
|
146
|
+
*
|
|
147
|
+
* 基础路径:/data/sys-modeling/categoryModel/
|
|
148
|
+
* 流程:init(预生成 fdId 与机制)→ add(建档并建主表)→ save/publish(发布态)
|
|
149
|
+
*
|
|
150
|
+
* fdType:1=分类表单(分类表 + 模板表 + 主表)、2=简单分类表单(聚合表 + 主表)
|
|
151
|
+
*/
|
|
152
|
+
const CATEGORY_MODEL_BASE = 'sys-modeling/categoryModel';
|
|
153
|
+
exports.categoryModelApi = {
|
|
154
|
+
/** 初始化:返回预生成 fdId 与机制(sys-xform 等) */
|
|
155
|
+
init: (client) => client.post(`${CATEGORY_MODEL_BASE}/init`, {}),
|
|
156
|
+
/** 新建分类表单,返回 { fdId } */
|
|
157
|
+
add: (client, payload) => client.post(`${CATEGORY_MODEL_BASE}/add`, payload),
|
|
158
|
+
/** 详情(含 mechanisms) */
|
|
159
|
+
get: (client, fdId) => client.post(`${CATEGORY_MODEL_BASE}/get`, {
|
|
160
|
+
fdId,
|
|
161
|
+
mechanisms: { load: '*' },
|
|
162
|
+
}),
|
|
163
|
+
/** 保存(草稿) */
|
|
164
|
+
save: (client, payload) => client.post(`${CATEGORY_MODEL_BASE}/save`, payload),
|
|
165
|
+
/** 发布 */
|
|
166
|
+
publish: (client, payload) => client.post(`${CATEGORY_MODEL_BASE}/publish`, payload),
|
|
167
|
+
/** 列表(按编码/名称等条件查询) */
|
|
168
|
+
list: (client, request = {}) => client.post(`${CATEGORY_MODEL_BASE}/list`, {
|
|
169
|
+
pageNo: 1,
|
|
170
|
+
pageSize: 20,
|
|
171
|
+
...request,
|
|
172
|
+
}),
|
|
173
|
+
};
|
|
144
174
|
/** 业务建模应用接口 */
|
|
145
175
|
const MODELING_APP_BASE = 'sys-modeling/sysModelingApplication';
|
|
146
176
|
exports.modelingAppApi = {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.operationApi = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* 表单业务操作接口(后端 SysModelingOperationController)
|
|
6
|
+
* 基础路径:/data/sys-modeling/sysModelingOperation/
|
|
7
|
+
* 所有接口均为 POST + JSON
|
|
8
|
+
*/
|
|
9
|
+
const BASE = 'sys-modeling/sysModelingOperation';
|
|
10
|
+
exports.operationApi = {
|
|
11
|
+
/** 业务操作列表(按表单:conditions.fdXForm) */
|
|
12
|
+
list: (client, request = {}) => client.post(`${BASE}/list`, request),
|
|
13
|
+
/** 业务操作详情 */
|
|
14
|
+
get: (client, fdId) => client.post(`${BASE}/get`, { fdId }),
|
|
15
|
+
/** 新建业务操作,返回 { fdId } */
|
|
16
|
+
add: (client, vo) => client.post(`${BASE}/add`, vo),
|
|
17
|
+
/** 修改业务操作(请求体为完整 VO,未提交的字段会被保留) */
|
|
18
|
+
update: (client, vo) => client.post(`${BASE}/update`, vo),
|
|
19
|
+
/** 删除业务操作 */
|
|
20
|
+
remove: (client, fdId) => client.post(`${BASE}/delete`, { fdId }),
|
|
21
|
+
/** 查询业务操作被引用的情况(删除前校验) */
|
|
22
|
+
listByRefer: (client, fdId) => client.post(`${BASE}/listByRefer`, {
|
|
23
|
+
conditions: { fdReferId: fdId },
|
|
24
|
+
offset: 0,
|
|
25
|
+
pageSize: 1000,
|
|
26
|
+
}),
|
|
27
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.templateApi = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* 分类表单模板(发起页模板)接口。
|
|
6
|
+
*
|
|
7
|
+
* 模板不是普通表单:分类表单下挂的是「虚拟模板」
|
|
8
|
+
* - 分类表单(fdType=1):`/data/sys-modeling/categoryTemplate/*`
|
|
9
|
+
* - 简单分类表单(fdType=2):`/data/sys-modeling/virtualPolymers/*`
|
|
10
|
+
* 两者都可通过 `virtualCommonTemplate/*` 统一 get / save / publish。
|
|
11
|
+
*
|
|
12
|
+
* 注意:官方 `init` 接口在模板表元数据未就绪时会空指针(FormTemplateVirtualMetaEntityListener),
|
|
13
|
+
* 因此这里直接 `add`(带 `mechanisms['sys-xform'].fdBuildNew=true`),由后端建表并生成元数据,
|
|
14
|
+
* 再用 `sys-xform/sysXFormDesign/save` 写入字段与视图。
|
|
15
|
+
*/
|
|
16
|
+
const CATEGORY_MODEL_BASE = 'sys-modeling/categoryModel';
|
|
17
|
+
const CATEGORY_TEMPLATE_BASE = 'sys-modeling/categoryTemplate';
|
|
18
|
+
const POLYMERS_BASE = 'sys-modeling/virtualPolymers';
|
|
19
|
+
const VIRTUAL_COMMON_BASE = 'sys-modeling/virtualCommonTemplate';
|
|
20
|
+
const VIRTUAL_CATEGORY_BASE = 'sys-modeling/virtualCategory';
|
|
21
|
+
exports.templateApi = {
|
|
22
|
+
/** 按编码查分类表单(分类表单与简单分类表单都在 categoryModel 表) */
|
|
23
|
+
findCategoryByCode: (client, code) => client.post(`${CATEGORY_MODEL_BASE}/list`, {
|
|
24
|
+
conditions: { fdCode: code },
|
|
25
|
+
pageNo: 1,
|
|
26
|
+
pageSize: 1,
|
|
27
|
+
count: true,
|
|
28
|
+
}),
|
|
29
|
+
/** 创建模板:简单分类走 virtualPolymers,普通分类走 categoryTemplate */
|
|
30
|
+
create: (client, kind, payload) => client.post(kind === 'simple' ? `${POLYMERS_BASE}/add` : `${CATEGORY_TEMPLATE_BASE}/add`, payload),
|
|
31
|
+
/** 读取模板(统一入口,按分类表单类型分流) */
|
|
32
|
+
get: (client, fdId, categoryCode) => client.post(`${VIRTUAL_COMMON_BASE}/get`, {
|
|
33
|
+
fdId,
|
|
34
|
+
fdCategoryModelCode: categoryCode,
|
|
35
|
+
mechanisms: { load: '*' },
|
|
36
|
+
}),
|
|
37
|
+
/** 保存模板 */
|
|
38
|
+
save: (client, payload) => client.post(`${VIRTUAL_COMMON_BASE}/save`, payload),
|
|
39
|
+
/** 发布模板 */
|
|
40
|
+
publish: (client, payload) => client.post(`${VIRTUAL_COMMON_BASE}/publish`, payload),
|
|
41
|
+
/** 更新模板(用于挂分类节点等) */
|
|
42
|
+
update: (client, payload) => client.post(`${VIRTUAL_COMMON_BASE}/update`, payload),
|
|
43
|
+
/** 模板列表(运行时分类树,含模板卡片) */
|
|
44
|
+
tree: (client, categoryCode) => client.post(`${VIRTUAL_CATEGORY_BASE}/tree`, { fdCategoryModelCode: categoryCode, mechanisms: { load: '*' } }),
|
|
45
|
+
/** 新建分类节点(分类表单的模板必须挂在分类节点下才会出现在发起页) */
|
|
46
|
+
addCategoryNode: (client, payload) => client.post(`${VIRTUAL_CATEGORY_BASE}/add`, {
|
|
47
|
+
hasChild: false,
|
|
48
|
+
...payload,
|
|
49
|
+
}),
|
|
50
|
+
/** 列出分类表单下的模板:简单分类走运行时树,分类表单走 listAll */
|
|
51
|
+
listByCategory: (client, kind, categoryCode) => kind === 'simple'
|
|
52
|
+
? client.post(`${VIRTUAL_CATEGORY_BASE}/tree`, { fdCategoryModelCode: categoryCode, mechanisms: { load: '*' } })
|
|
53
|
+
: client.post(`${CATEGORY_TEMPLATE_BASE}/listAll`, {
|
|
54
|
+
fdCategoryModelCode: categoryCode,
|
|
55
|
+
mechanisms: { load: '*' },
|
|
56
|
+
}),
|
|
57
|
+
/** 批量删除模板 */
|
|
58
|
+
deleteTemplates: (client, kind, categoryCode, fdIds) => kind === 'simple'
|
|
59
|
+
? client.post(`${POLYMERS_BASE}/batchDelete`, {
|
|
60
|
+
fdIds,
|
|
61
|
+
fdCategoryModelCode: categoryCode,
|
|
62
|
+
})
|
|
63
|
+
: client.post(`${CATEGORY_TEMPLATE_BASE}/batchDelete`, {
|
|
64
|
+
fdIds,
|
|
65
|
+
fdCategoryModelCode: categoryCode,
|
|
66
|
+
}),
|
|
67
|
+
/** 删除分类节点 */
|
|
68
|
+
deleteCategoryNode: (client, categoryCode, fdId) => client.post(`${VIRTUAL_CATEGORY_BASE}/delete`, {
|
|
69
|
+
fdId,
|
|
70
|
+
fdCategoryModelCode: categoryCode,
|
|
71
|
+
}),
|
|
72
|
+
/** 读取模板的表单设计(xform 设计器接口) */
|
|
73
|
+
loadDesign: (client, fdId) => client.post(`sys-xform/sysXFormDesign/load`, { fdId }),
|
|
74
|
+
/** 保存模板的表单设计 */
|
|
75
|
+
saveDesign: (client, payload) => client.post(`sys-xform/sysXFormDesign/save`, payload),
|
|
76
|
+
};
|
package/dist/api/view.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formViewApi = exports.listViewApi = void 0;
|
|
4
|
+
/** 列表视图:按钮配置在 fdExtendConfig[platform].operationList */
|
|
5
|
+
const LIST_VIEW_BASE = 'sys-modeling/sysModelingListView';
|
|
6
|
+
/** 查看/新建视图:按钮配置在 fdConfig[platform].operationList */
|
|
7
|
+
const VIEW_BASE = 'sys-modeling/sysModelingView';
|
|
8
|
+
exports.listViewApi = {
|
|
9
|
+
list: (client, request = {}) => client.post(`${LIST_VIEW_BASE}/list`, request),
|
|
10
|
+
get: (client, fdId) => client.post(`${LIST_VIEW_BASE}/get`, {
|
|
11
|
+
fdId,
|
|
12
|
+
mechanisms: { load: '*' },
|
|
13
|
+
}),
|
|
14
|
+
update: (client, vo) => client.post(`${LIST_VIEW_BASE}/update`, vo),
|
|
15
|
+
};
|
|
16
|
+
exports.formViewApi = {
|
|
17
|
+
list: (client, request = {}) => client.post(`${VIEW_BASE}/list`, request),
|
|
18
|
+
get: (client, fdId) => client.post(`${VIEW_BASE}/get`, {
|
|
19
|
+
fdId,
|
|
20
|
+
mechanisms: { load: '*' },
|
|
21
|
+
}),
|
|
22
|
+
update: (client, vo) => client.post(`${VIEW_BASE}/update`, vo),
|
|
23
|
+
};
|
package/dist/commands/form.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.injectNewFields = injectNewFields;
|
|
3
4
|
exports.registerFormCommand = registerFormCommand;
|
|
4
5
|
const fs_1 = require("fs");
|
|
5
6
|
const path_1 = require("path");
|
|
@@ -674,6 +675,155 @@ async function loadModels(client, formId, fromModel) {
|
|
|
674
675
|
}
|
|
675
676
|
return (await formDefine_1.dataModelApi.loadByFormId(client, formId)) ?? [];
|
|
676
677
|
}
|
|
678
|
+
/** 分类表单默认图标(与平台分类表单弹窗一致) */
|
|
679
|
+
const CATEGORY_FORM_ICON = {
|
|
680
|
+
category: '{"name":"iconCommon_line_16_classificationTemplateModel","type":"vector","style":{"backgroundColor":"","color":"#F6940A","borderRadius":0,"fontSize":""},"normalize":true}',
|
|
681
|
+
simpleCategory: '{"name":"iconCommon_line_16_simpleClassificationModel","type":"vector","style":{"backgroundColor":"","color":"#5D4DD5","borderRadius":0,"fontSize":""},"normalize":true}',
|
|
682
|
+
};
|
|
683
|
+
function normalizeCategoryType(raw) {
|
|
684
|
+
if (!raw)
|
|
685
|
+
return undefined;
|
|
686
|
+
const key = raw.trim().toLowerCase().replace(/[-_\s]/g, '');
|
|
687
|
+
if (key === 'category' || key === 'categoryform')
|
|
688
|
+
return 'category';
|
|
689
|
+
if (key === 'simplecategory' || key === 'simplecategoryform')
|
|
690
|
+
return 'simpleCategory';
|
|
691
|
+
return undefined;
|
|
692
|
+
}
|
|
693
|
+
/**
|
|
694
|
+
* 构造分类表单的 mechanisms:init 返回的每个机制补上 fdName / fdTableName(主表名),
|
|
695
|
+
* 与前端 categoryModal 的 mergeData 保持一致。
|
|
696
|
+
*/
|
|
697
|
+
function buildCategoryMechanisms(source, fdName, fdTableName) {
|
|
698
|
+
const result = {};
|
|
699
|
+
Object.keys(source ?? {}).forEach((key) => {
|
|
700
|
+
const value = source?.[key];
|
|
701
|
+
result[key] = {
|
|
702
|
+
...(value && typeof value === 'object' ? value : {}),
|
|
703
|
+
fdName,
|
|
704
|
+
fdTableName,
|
|
705
|
+
};
|
|
706
|
+
});
|
|
707
|
+
return result;
|
|
708
|
+
}
|
|
709
|
+
/**
|
|
710
|
+
* 创建分类表单 / 简单分类表单:categoryModel/init → add →(--publish 时 save + publish)。
|
|
711
|
+
*
|
|
712
|
+
* 注意:分类表单本身不含业务字段,字段属于「模板(模板表单)」;
|
|
713
|
+
* 模板表元数据由平台设计器首次保存时生成,CLI 侧 template 创建需在该操作之后。
|
|
714
|
+
*/
|
|
715
|
+
async function createCategoryForm(client, opts, type) {
|
|
716
|
+
const appId = String(opts.appId ?? '').trim();
|
|
717
|
+
if (!appId)
|
|
718
|
+
throw new Error('分类表单(--type category|simpleCategory)必须提供 --app-id');
|
|
719
|
+
if (opts.addField?.length || opts.fields || opts.fromModel) {
|
|
720
|
+
throw new Error('分类表单本身没有业务字段,不支持 --add-field / --fields / --from-model;字段请在模板(模板表单)中配置');
|
|
721
|
+
}
|
|
722
|
+
const name = String(opts.name ?? '').trim();
|
|
723
|
+
if (!name)
|
|
724
|
+
throw new Error('--name 不能为空');
|
|
725
|
+
if (name.length > 20)
|
|
726
|
+
throw new Error('分类表单名称最长 20 个字符');
|
|
727
|
+
const app = await formDefine_1.modelingAppApi.get(client, appId);
|
|
728
|
+
const appCode = String(app.fdAppCode ?? '').trim();
|
|
729
|
+
if (!appCode)
|
|
730
|
+
throw new Error(`未能读取应用编码(appId=${appId})`);
|
|
731
|
+
logger_1.logger.step('初始化分类表单(categoryModel/init)');
|
|
732
|
+
const init = await formDefine_1.categoryModelApi.init(client);
|
|
733
|
+
if (!init?.fdId)
|
|
734
|
+
throw new Error('categoryModel/init 未返回 fdId');
|
|
735
|
+
const takeTableName = async (given, label) => {
|
|
736
|
+
const explicit = String(given ?? '').trim();
|
|
737
|
+
if (explicit)
|
|
738
|
+
return explicit;
|
|
739
|
+
logger_1.logger.step(`生成${label}(sysModelingXForm/generateTableName)`);
|
|
740
|
+
return formDefine_1.modelingXFormApi.generateTableName(client);
|
|
741
|
+
};
|
|
742
|
+
const isSimple = type === 'simpleCategory';
|
|
743
|
+
const fdType = isSimple ? 2 : 1;
|
|
744
|
+
const fdMainTableName = await takeTableName(opts.tableName, '主表名');
|
|
745
|
+
let fdCategoryTableName = '';
|
|
746
|
+
let fdTemplateTableName = '';
|
|
747
|
+
let fdPolymersTableName = '';
|
|
748
|
+
let fdSupportHierarchy = opts.supportHierarchy !== false;
|
|
749
|
+
if (isSimple) {
|
|
750
|
+
fdPolymersTableName = await takeTableName(opts.polymersTableName, '聚合表名');
|
|
751
|
+
// 简单分类表单固定多层级
|
|
752
|
+
fdSupportHierarchy = true;
|
|
753
|
+
}
|
|
754
|
+
else {
|
|
755
|
+
fdCategoryTableName = await takeTableName(opts.categoryTableName, '分类表名');
|
|
756
|
+
fdTemplateTableName = await takeTableName(opts.templateTableName, '模板表名');
|
|
757
|
+
}
|
|
758
|
+
// 共享已有分类:沿用对方的分类表与层级配置
|
|
759
|
+
const shareCategory = String(opts.shareCategory ?? '').trim();
|
|
760
|
+
if (shareCategory) {
|
|
761
|
+
if (isSimple)
|
|
762
|
+
throw new Error('简单分类表单不支持共享已有分类');
|
|
763
|
+
const shared = await formDefine_1.categoryModelApi.list(client, {
|
|
764
|
+
conditions: { fdCode: shareCategory, fdType: { $eq: 1 } },
|
|
765
|
+
pageSize: 1,
|
|
766
|
+
});
|
|
767
|
+
const target = shared?.content?.[0];
|
|
768
|
+
if (!target?.fdCategoryTableName)
|
|
769
|
+
throw new Error(`未找到可共享的分类表单:${shareCategory}`);
|
|
770
|
+
fdCategoryTableName = String(target.fdCategoryTableName);
|
|
771
|
+
fdSupportHierarchy = Boolean(target.fdSupportHierarchy);
|
|
772
|
+
}
|
|
773
|
+
const payload = stripUndefined({
|
|
774
|
+
fdId: init.fdId,
|
|
775
|
+
fdType,
|
|
776
|
+
fdAppId: appId,
|
|
777
|
+
fdAppCode: appCode,
|
|
778
|
+
fdName: name,
|
|
779
|
+
fdCode: String(opts.code ?? '').trim() || `category_${Date.now().toString(36).slice(-6)}`,
|
|
780
|
+
fdIcon: opts.icon ? (0, icon_1.normalizeIcon)(opts.icon) : CATEGORY_FORM_ICON[type],
|
|
781
|
+
fdShareCategory: Boolean(shareCategory),
|
|
782
|
+
fdSupportHierarchy,
|
|
783
|
+
fdCategoryTableName: fdCategoryTableName || undefined,
|
|
784
|
+
fdTemplateTableName: fdTemplateTableName || undefined,
|
|
785
|
+
fdPolymersTableName: fdPolymersTableName || undefined,
|
|
786
|
+
fdMainTableName,
|
|
787
|
+
mechanisms: buildCategoryMechanisms(init.mechanisms, name, fdMainTableName),
|
|
788
|
+
});
|
|
789
|
+
logger_1.logger.info(logger_1.color.gray(`类型:${isSimple ? '简单分类表单' : '分类表单'} 应用:${appCode} 主表:${fdMainTableName} ` +
|
|
790
|
+
(isSimple
|
|
791
|
+
? `聚合表:${fdPolymersTableName}`
|
|
792
|
+
: `分类表:${fdCategoryTableName} 模板表:${fdTemplateTableName}`)));
|
|
793
|
+
if (opts.dryRun) {
|
|
794
|
+
logger_1.logger.title('【dry-run】将提交(categoryModel/add)');
|
|
795
|
+
logger_1.logger.json(payload);
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
798
|
+
logger_1.logger.step(`创建分类表单:${name}`);
|
|
799
|
+
const created = await formDefine_1.categoryModelApi.add(client, payload);
|
|
800
|
+
const fdId = created?.fdId ?? init.fdId;
|
|
801
|
+
logger_1.logger.success(`分类表单创建成功,fdId = ${fdId}`);
|
|
802
|
+
if (opts.publish) {
|
|
803
|
+
logger_1.logger.step('发布分类表单(categoryModel/save → publish)');
|
|
804
|
+
const detail = await formDefine_1.categoryModelApi.get(client, fdId);
|
|
805
|
+
const fdConfig = detail.fdConfig ?? JSON.stringify({ PC: {}, mobile: {} });
|
|
806
|
+
await formDefine_1.categoryModelApi.save(client, { ...detail, fdConfig });
|
|
807
|
+
await formDefine_1.categoryModelApi.publish(client, { ...detail, fdConfig, fdStatus: 'official' });
|
|
808
|
+
logger_1.logger.success('分类表单已发布');
|
|
809
|
+
}
|
|
810
|
+
if (opts.json) {
|
|
811
|
+
logger_1.logger.json({
|
|
812
|
+
fdId,
|
|
813
|
+
type,
|
|
814
|
+
fdType,
|
|
815
|
+
tables: {
|
|
816
|
+
main: fdMainTableName,
|
|
817
|
+
category: fdCategoryTableName || undefined,
|
|
818
|
+
template: fdTemplateTableName || undefined,
|
|
819
|
+
polymers: fdPolymersTableName || undefined,
|
|
820
|
+
},
|
|
821
|
+
});
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
824
|
+
logger_1.logger.info(logger_1.color.gray('提示:分类表单的模板(模板表单)需在平台「发起页设计器」中创建;' +
|
|
825
|
+
'模板表元数据由设计器首次保存时生成,CLI 直接调用 categoryTemplate/init 会报空指针。'));
|
|
826
|
+
}
|
|
677
827
|
function registerFormCommand(program) {
|
|
678
828
|
const form = program.command('form').description('表单相关操作(创建 / 查询 / 发布 / 自动完善字段)');
|
|
679
829
|
// ------------------------------------------------------------------ create
|
|
@@ -682,13 +832,20 @@ function registerFormCommand(program) {
|
|
|
682
832
|
.description('创建表单,并(可选)根据数据模型自动完善字段配置')
|
|
683
833
|
.requiredOption('--name <name>', '表单名称')
|
|
684
834
|
.option('--code <code>', '表单业务编码,默认自动生成')
|
|
685
|
-
.option('--type <type>', '表单类型:common|general|config|modal|template|refer
|
|
835
|
+
.option('--type <type>', '表单类型:common|general|config|modal|template|refer,' +
|
|
836
|
+
'或 category(分类表单)| simpleCategory(简单分类表单)。' +
|
|
837
|
+
'缺省时 general 族用 general、其余用 common')
|
|
686
838
|
.option('--app-id <appId>', '表单所属应用 id(应用主键 fdId)。给出后默认走 modeling 族,写入 fdAppId')
|
|
687
839
|
.option('--fd-entity-id <id>', '业务建模对应 appId / 应用模块对应 templateId(默认取 --app-id)')
|
|
688
840
|
.option('--fd-entity-name <name>', '所属实体 model 名称,例如 com.xxx.YourEntity')
|
|
689
841
|
.option('--fd-entity-key <key>', '实体扩展键(预留)')
|
|
690
842
|
.option('--fd-run-entity-name <name>', '表单运行时实体名称')
|
|
691
843
|
.option('--table-name <name>', '主表名(不传则调用对应接口自动生成)')
|
|
844
|
+
.option('--category-table-name <name>', '分类表名(--type category,不传自动生成)')
|
|
845
|
+
.option('--template-table-name <name>', '模板表名(--type category,不传自动生成)')
|
|
846
|
+
.option('--polymers-table-name <name>', '聚合表名(--type simpleCategory,不传自动生成)')
|
|
847
|
+
.option('--share-category <code>', '共享已有分类表单的分类(--type category,传对方 fdCode)')
|
|
848
|
+
.option('--no-support-hierarchy', '分类层级为单层级(默认多层级;简单分类强制多层级)')
|
|
692
849
|
.option('--api <family>', '接口族:auto(默认)| modeling | general | design')
|
|
693
850
|
.option('--group-id <fdGroupId>', '表单所属分组 id(modeling 族)')
|
|
694
851
|
.option('--edit-draft', '草稿状态允许编辑(modeling 族,默认 true)')
|
|
@@ -736,6 +893,12 @@ function registerFormCommand(program) {
|
|
|
736
893
|
const client = createClient(opts);
|
|
737
894
|
const appId = opts.appId;
|
|
738
895
|
const explicitType = opts.type;
|
|
896
|
+
// 分类表单 / 简单分类表单:走 categoryModel 链路(与普通表单完全不同的接口与表结构)
|
|
897
|
+
const categoryType = normalizeCategoryType(explicitType);
|
|
898
|
+
if (categoryType) {
|
|
899
|
+
await createCategoryForm(client, opts, categoryType);
|
|
900
|
+
return;
|
|
901
|
+
}
|
|
739
902
|
const parsedType = explicitType ? parseFormType(explicitType) : undefined;
|
|
740
903
|
const { family, mechanismEntityName, mechanismEntityCode } = generatorOptions(opts, parsedType, appId);
|
|
741
904
|
// 未显式指定类型时:审批意见表单(general) 用 2,其余(含建模应用表单)用 1(普通表单)
|
|
@@ -1055,6 +1218,23 @@ function registerFormCommand(program) {
|
|
|
1055
1218
|
.option('--json', '以 JSON 输出')
|
|
1056
1219
|
.action(async (opts) => {
|
|
1057
1220
|
const client = createClient(opts);
|
|
1221
|
+
// 分类表单 / 简单分类表单与普通表单不在同一张表,优先按分类表单读取
|
|
1222
|
+
let categoryVo;
|
|
1223
|
+
try {
|
|
1224
|
+
categoryVo = await formDefine_1.categoryModelApi.get(client, opts.id);
|
|
1225
|
+
}
|
|
1226
|
+
catch {
|
|
1227
|
+
categoryVo = undefined;
|
|
1228
|
+
}
|
|
1229
|
+
if (categoryVo?.fdId) {
|
|
1230
|
+
logger_1.logger.json(categoryVo);
|
|
1231
|
+
const isSimple = categoryVo.fdType === 2;
|
|
1232
|
+
logger_1.logger.info(logger_1.color.gray(`类型:${isSimple ? '简单分类表单' : '分类表单'} 主表:${categoryVo.fdMainTableName ?? ''}` +
|
|
1233
|
+
(isSimple
|
|
1234
|
+
? ` 聚合表:${categoryVo.fdPolymersTableName ?? ''}`
|
|
1235
|
+
: ` 分类表:${categoryVo.fdCategoryTableName ?? ''} 模板表:${categoryVo.fdTemplateTableName ?? ''}`)));
|
|
1236
|
+
return;
|
|
1237
|
+
}
|
|
1058
1238
|
let vo;
|
|
1059
1239
|
// 依次尝试 建模应用接口 -> 审批意见表单接口 -> 表单引擎接口
|
|
1060
1240
|
try {
|