lan-low-code-cli 2.6.0 → 2.8.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 +78 -1
- package/dist/api/flow.js +119 -0
- package/dist/api/operation.js +8 -0
- package/dist/commands/flow.js +817 -0
- package/dist/commands/operation.js +123 -14
- package/dist/generator/flow/compiler.js +397 -0
- package/dist/generator/flow/index.js +22 -0
- package/dist/generator/flow/layout.js +136 -0
- package/dist/generator/flow/schema-resolver.js +133 -0
- package/dist/generator/flow/schema.js +96 -0
- package/dist/generator/flow/types.js +10 -0
- package/dist/generator/flow/validate.js +129 -0
- package/dist/index.js +12 -1
- package/package.json +1 -1
- package/skills/lan-low-code-cli/SKILL.md +14 -4
- package/skills/lan-low-code-cli/SKILL.zh-CN.md +13 -3
- package/skills/lan-low-code-cli/references/cli-contract.md +76 -5
- package/skills/lan-low-code-cli/references/cli-contract.zh-CN.md +72 -4
package/README.md
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
- **创建表单**:覆盖 6 种表单类型(普通 / 审批意见 / 全局配置项 / 弹窗 / 通用 / 引用者)
|
|
7
7
|
- **自动获取可用字段**:表单数据模型字段、外部映射表字段、字段库
|
|
8
8
|
- **自动完善表单字段**:依据数据模型自动生成完整表单配置(`fdConfig`:字段控件 + 场景 viewModel + 权限 + 多语言 + 全局规则)并保存
|
|
9
|
+
- **动作流建模**:用声明式 Flow Spec 从零编译出 `fdDesign`(含符合平台编排习惯的节点布局),支持草稿/发布/启停/删除、Schema 上下文注入、golden 模板抽取与按钮脚本生成
|
|
9
10
|
|
|
10
11
|
## 一、安装与构建
|
|
11
12
|
|
|
@@ -272,6 +273,9 @@ llc operation create --form-id <fdId> --name 批量归档 --code archive \
|
|
|
272
273
|
--type script --script @archive.js
|
|
273
274
|
llc operation create --form-id <fdId> --name 转办 --code transfer \
|
|
274
275
|
--type dialog --dialog-id <对话框id>
|
|
276
|
+
# 绑定动作流(按钮由后端执行动作流)
|
|
277
|
+
llc operation create --form-id <fdId> --name 运行闭环验证 --code runFlow \
|
|
278
|
+
--trigger-flow <动作流fdId>
|
|
275
279
|
llc operation get --id <operationId>
|
|
276
280
|
llc operation update --id <operationId> --type script \
|
|
277
281
|
--script @examples/operation-script-modal-table.js # 把已有按钮改成脚本模式
|
|
@@ -282,7 +286,10 @@ llc operation delete --id <operationId> --yes # 被页面引用时拒绝
|
|
|
282
286
|
```
|
|
283
287
|
|
|
284
288
|
- `--type`:`link`(fdType=2 / fdViewType=4,需 `--url`)、`script`(3 / 5,需 `--script`,支持 `@文件`)、
|
|
285
|
-
`dialog`(3 / 1,需 `--dialog-id
|
|
289
|
+
`dialog`(3 / 1,需 `--dialog-id`);或改用 `--trigger-flow <动作流fdId>` 绑定动作流
|
|
290
|
+
(写入 `fdTriggerType=3`、`fdTriggerId`、`fdTriggerCode`、`fdTriggerModel`,可配 `--inc-params`)
|
|
291
|
+
- `--trigger-flow` 只接受 `StartActiveNode` + 已启用(`fdStatus=1`)+ `fdOperateTrigger=true` 的动作流;
|
|
292
|
+
挂载后用 `llc flow run --operation-id <opId> --view-id <listViewId> --yes` 可实际执行并校验 `success`
|
|
286
293
|
- `--position`:`list`(默认,列表视图)/ `view`(查看视图)
|
|
287
294
|
- 默认不要求勾选数据;需要“先勾选数据再执行”时加 `--need-select`(链接会按接口调用,`fdUrlType=2`)
|
|
288
295
|
- `--dry-run` 只打印请求体;新建操作默认仅管理员可用
|
|
@@ -309,6 +316,66 @@ new Function('context', fdJavaScript)({
|
|
|
309
316
|
[skills/lan-low-code-cli/references/operation-script-context.md](skills/lan-low-code-cli/references/operation-script-context.md)
|
|
310
317
|
|
|
311
318
|
|
|
319
|
+
### 动作流(`llc flow`)
|
|
320
|
+
|
|
321
|
+
动作流是**应用级**对象(`--app-code` 即 `fdAppCode`),不是表单级。用声明式 JSON(Flow Spec)描述节点与连线,
|
|
322
|
+
CLI 负责补齐开始/结束节点、生成符合 IDE 编排习惯的坐标、按节点类型白名单裁剪字段,最后编译成
|
|
323
|
+
`fdDesign`(JSON 字符串)与平台 `addPublish` / `addDraft` 所需的扁平 VO。
|
|
324
|
+
|
|
325
|
+
```bash
|
|
326
|
+
# 1. 纯离线:生成模板 → 校验 → 编译(不联网)
|
|
327
|
+
llc flow spec --app-code cli-test --name 示例流程 --code flow_demo --out flow.json
|
|
328
|
+
llc flow validate --spec @flow.json --json
|
|
329
|
+
llc flow compile --spec @flow.json --json
|
|
330
|
+
|
|
331
|
+
# 2. 只读查询
|
|
332
|
+
llc flow list --app-code cli-test --json
|
|
333
|
+
llc flow get --id <flowId> --with-design
|
|
334
|
+
llc flow templates --from @compile-result.json --out templates.json # 抽取 golden 骨架(剥离坐标)
|
|
335
|
+
llc flow schema --kind jsonSchema --entity-id <fdId>
|
|
336
|
+
|
|
337
|
+
# 3. 写入(默认预览;必须 --yes + 显式 --app-code)
|
|
338
|
+
llc flow apply --spec @flow.json --app-code cli-test --resolve-schema # 预览 payload
|
|
339
|
+
llc flow apply --spec @flow.json --app-code cli-test --resolve-schema --yes --enable --json
|
|
340
|
+
llc flow diff --id <flowId> --spec @flow.json --resolve-schema # 回读比对(默认忽略坐标)
|
|
341
|
+
llc flow script --id <flowId> --out call-flow.js # 生成 MKXFORM.flow_<code> 脚本
|
|
342
|
+
llc flow run --operation-id <opId> --view-id <listViewId> --yes --json # 执行绑定动作流的按钮
|
|
343
|
+
llc flow disable --id <flowId> --yes
|
|
344
|
+
llc flow delete --id <flowId> --yes
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
**Flow Spec 关键字段**:`appCode` / `name` / `code`(`^[a-zA-Z0-9_]{1,30}$`)/ `startWay` /
|
|
348
|
+
`trigger`(`fdRunType`、`inParam`…)/ `nodes`(`id`、`type`、`config`、`context`、`subProcess`)/ `edges`
|
|
349
|
+
(`from`、`to`、`name`、`default`、`formula`)。节点 `id` 需匹配 `^[0-9a-zA-Z_]{2,32}$`。
|
|
350
|
+
|
|
351
|
+
**布局**由编译器生成,不要手写 `drawAttr.bounds`:
|
|
352
|
+
|
|
353
|
+
- `--layout ide`(默认):主链以 `--center-x`(默认 679)居中;`BranchNode` 为 56×56,其余节点 180×38;
|
|
354
|
+
分支后继与分支节点同层、泳道 ±1 左右对称;汇聚下移一层;层距 = 该层最高节点 + 52。
|
|
355
|
+
这与平台 mxGraph 编辑器「向下插入 / 左右插入」累积出的编排一致。
|
|
356
|
+
- `--layout layered`:分支后继放到下一层,可读性更强但与平台手工习惯略有差异。
|
|
357
|
+
- `--layout passthrough`:沿用 spec 里的 `bounds`(用于回写平台导出的流程)。
|
|
358
|
+
- `passthrough` 之外的模式下,`relative:false`、节点尺寸、连线 `sourceRef/targetRef` 与
|
|
359
|
+
`formulaConfig.branchFormulas`(引用真实连线 ID)、分支线 `exitX=0/1` 锚点均自动生成。
|
|
360
|
+
|
|
361
|
+
**Schema 注入**:`--resolve-schema` 会为引用数据模型的节点调 `getSourceJsonSchema` /
|
|
362
|
+
`getProcessDataOutJsonSchema` 补齐 `extraAttr.context_outputParam` / `context_bindFormId`。
|
|
363
|
+
这两个端点要求 `entityId` 带 `sys-modeling#` 前缀(CLI 自动补),裸 id 会返回 500。
|
|
364
|
+
失败默认只告警,`--strict-schema` 升级为错误。
|
|
365
|
+
|
|
366
|
+
**边界与已知限制**:
|
|
367
|
+
|
|
368
|
+
- `AddDataNode` / `AddOrUpdateNode` 的 `fields` 是平台真实结构
|
|
369
|
+
(`{field:{...},value:{format,valueJson}}`,公式引用形如 `${data.node.N1.xxx}`);
|
|
370
|
+
CLI **原样透传并只校验字段名,不臆造公式**。请用 `flow templates` / `flow get` 取 golden 骨架。
|
|
371
|
+
- 发布时后端从 `startNodeDef` 派生 `fdProcessActive`;`fdStatus=1` 即已启用。
|
|
372
|
+
- 运行日志端点因部署而异:源码声明 `ModelingProcessLog/findAll`,新版页面用
|
|
373
|
+
`sysModelingLog/findAllWithAppId`;`flow logs` 已内置候选回退,可用 `--endpoint` 指定抓包结果。
|
|
374
|
+
- 运行时触发端点 `executeFlowForAjax` 位于 `sys-xform` 运行时包(无文档化 REST 路径);
|
|
375
|
+
CLI 生成的按钮脚本走 `MKXFORM.flow_<fdCode>`,用 `operation create --type script` + `operation attach` 挂载。
|
|
376
|
+
- 完整命令与 Flow Spec 语法见
|
|
377
|
+
[skills/lan-low-code-cli/references/cli-contract.md](skills/lan-low-code-cli/references/cli-contract.md) 第 10 节。
|
|
378
|
+
|
|
312
379
|
### 控件类型
|
|
313
380
|
|
|
314
381
|
**先查环境再选控件**:
|
|
@@ -945,6 +1012,16 @@ llc config show | set | clear
|
|
|
945
1012
|
| 外部表字段 | `POST sys-xform/sysXFormDataModelField/loadFieldMeta` |
|
|
946
1013
|
| 字段库 | `POST sys-xform/sysXFormWordsField/list` |
|
|
947
1014
|
| 字段编码生成 | `POST sys-xform/sysXFormWordsField/generateFdKey` |
|
|
1015
|
+
| 动作流定义 CRUD / 列表 / 详情 | `POST sys-modeling/process/define/{list,get,add,update,delete,checkCodeUniqueness}` |
|
|
1016
|
+
| 动作流草稿与发布 | `POST sys-modeling/process/define/{addDraft,updateDraft,addPublish,updatePublish,saveDraft,publish}` |
|
|
1017
|
+
| 动作流启停 | `POST sys-modeling/process/define/{startup,stop}` |
|
|
1018
|
+
| 动作流引用关系 | `POST sys-modeling/modelingProcessDefineReferList/listByRefer` |
|
|
1019
|
+
| 动作流 Schema / 元数据 | `POST sys-modeling/process/define/{getSourceFields,getConditionFields,getSourceJsonSchema,getProcessDataOutJsonSchema,loadDataModel,businessNodes,nextN,…}`、`POST sys-modeling/processNode/define/*` |
|
|
1020
|
+
| 动作流分类 | `POST sys-modeling/sysModelingProcessCategory/{list,get,add,update,delete}` |
|
|
1021
|
+
| 动作流运行日志 | `POST sys-modeling/ModelingProcessLog/{findAll,get,relation}`(环境差异时可用 `--endpoint` 覆盖) |
|
|
1022
|
+
|
|
1023
|
+
> `getSourceJsonSchema` / `getProcessDataOutJsonSchema` 的 `entityId` 必须带 `sys-modeling#` 前缀;
|
|
1024
|
+
> `getSourceFields` / `getConditionFields` / `loadDataModel` 用裸 id。详见动作流章节。
|
|
948
1025
|
|
|
949
1026
|
## 五、生成的表单配置结构(`fdConfig`,**持久化格式**)
|
|
950
1027
|
|
package/dist/api/flow.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.flowApi = exports.FLOW_LIST_COLUMNS = exports.FLOW_LOG_ENDPOINTS = void 0;
|
|
4
|
+
exports.qualifyEntityId = qualifyEntityId;
|
|
5
|
+
/**
|
|
6
|
+
* 动作流(sysModelingActionFlow)接口
|
|
7
|
+
*
|
|
8
|
+
* 前端 `src/utils/http.ts:3` 使用 `Http.build({ modulePrefixName: 'sys-modeling' })`,
|
|
9
|
+
* `src/api/sysModelingActionFlow.ts:5-69` 以 `Api.build('process/define/xxx', http)` 声明端点。
|
|
10
|
+
* CLI 的 LcodeClient 拼接 `${baseUrl}/${relativePath}`(baseUrl 含 /data),
|
|
11
|
+
* 因此完整地址为 `http://<host>/data/sys-modeling/process/define/list`。
|
|
12
|
+
* 同构证据:`Api.build('sysModelingApplication/list', http)` 对应已验证的
|
|
13
|
+
* `sys-modeling/sysModelingApplication/list`。
|
|
14
|
+
*
|
|
15
|
+
* 所有接口均为 POST + JSON。
|
|
16
|
+
*/
|
|
17
|
+
const DEFINE_BASE = 'sys-modeling/process/define';
|
|
18
|
+
const NODE_DEFINE_BASE = 'sys-modeling/processNode/define';
|
|
19
|
+
const CATEGORY_BASE = 'sys-modeling/sysModelingProcessCategory';
|
|
20
|
+
const LOG_BASE = 'sys-modeling/ModelingProcessLog';
|
|
21
|
+
const REFER_BASE = 'sys-modeling/modelingProcessDefineReferList';
|
|
22
|
+
/**
|
|
23
|
+
* 真实环境实测:getSourceJsonSchema / getProcessDataOutJsonSchema 要求 entityId
|
|
24
|
+
* 带模块前缀 `sys-modeling#`,裸 id 会返回 HTTP 500;而 getSourceFields /
|
|
25
|
+
* getConditionFields / loadDataModel 用裸 id 正常。与真实数据里的
|
|
26
|
+
* extraAttr.context_bindFormId = "sys-modeling#<fdId>" 一致。
|
|
27
|
+
*/
|
|
28
|
+
function qualifyEntityId(entityId) {
|
|
29
|
+
return entityId.includes('#') ? entityId : `sys-modeling#${entityId}`;
|
|
30
|
+
}
|
|
31
|
+
/** 日志列表端点候选(按优先级);可用 --endpoint 覆盖 */
|
|
32
|
+
exports.FLOW_LOG_ENDPOINTS = [
|
|
33
|
+
`${LOG_BASE}/findAll`,
|
|
34
|
+
'sys-modeling/sysModelingLog/findAllWithAppId',
|
|
35
|
+
'sys-modeling/sysModelingLog/findAll',
|
|
36
|
+
];
|
|
37
|
+
exports.FLOW_LIST_COLUMNS = [
|
|
38
|
+
'fdId', 'fdName', 'fdDesc', 'fdCode', 'fdCreator', 'fdCreateTime',
|
|
39
|
+
'fdStatus', 'fdStartWay', 'fdProcessData', 'fdProcessActive', 'fdAppCode', 'fdCategory',
|
|
40
|
+
];
|
|
41
|
+
exports.flowApi = {
|
|
42
|
+
// ---- 定义 CRUD ----
|
|
43
|
+
list: (client, request = {}) => client.post(`${DEFINE_BASE}/list`, {
|
|
44
|
+
columns: exports.FLOW_LIST_COLUMNS,
|
|
45
|
+
pageNo: 1,
|
|
46
|
+
pageSize: 1000,
|
|
47
|
+
sorts: { fdCreateTime: 'desc' },
|
|
48
|
+
...request,
|
|
49
|
+
}),
|
|
50
|
+
get: (client, fdId) => client.post(`${DEFINE_BASE}/get`, { fdId }),
|
|
51
|
+
add: (client, vo) => client.post(`${DEFINE_BASE}/add`, vo),
|
|
52
|
+
update: (client, vo) => client.post(`${DEFINE_BASE}/update`, vo),
|
|
53
|
+
remove: (client, fdId) => client.post(`${DEFINE_BASE}/delete`, { fdId }),
|
|
54
|
+
checkCodeUniqueness: (client, fdCode, fdAppCode) => client.post(`${DEFINE_BASE}/checkCodeUniqueness`, { fdCode, fdAppCode }),
|
|
55
|
+
// ---- 草稿 / 发布 / 状态机(UI 保存与发布走的是这四个端点) ----
|
|
56
|
+
addDraft: (client, vo) => client.post(`${DEFINE_BASE}/addDraft`, vo),
|
|
57
|
+
updateDraft: (client, vo) => client.post(`${DEFINE_BASE}/updateDraft`, vo),
|
|
58
|
+
addPublish: (client, vo) => client.post(`${DEFINE_BASE}/addPublish`, vo),
|
|
59
|
+
updatePublish: (client, vo) => client.post(`${DEFINE_BASE}/updatePublish`, vo),
|
|
60
|
+
saveDraft: (client, vo) => client.post(`${DEFINE_BASE}/saveDraft`, vo),
|
|
61
|
+
publish: (client, vo) => client.post(`${DEFINE_BASE}/publish`, vo),
|
|
62
|
+
startup: (client, fdId) => client.post(`${DEFINE_BASE}/startup`, { fdId }),
|
|
63
|
+
stop: (client, fdId) => client.post(`${DEFINE_BASE}/stop`, { fdId }),
|
|
64
|
+
// ---- 引用关系(删除前检查) ----
|
|
65
|
+
listByRefer: (client, fdId) => client.post(`${REFER_BASE}/listByRefer`, {
|
|
66
|
+
conditions: { fdReferId: fdId },
|
|
67
|
+
pageNo: 1,
|
|
68
|
+
pageSize: 1000,
|
|
69
|
+
}),
|
|
70
|
+
// ---- Schema / 元数据(只读,SchemaResolver 使用) ----
|
|
71
|
+
businessNodes: (client) => client.post(`${DEFINE_BASE}/businessNodes`, {}),
|
|
72
|
+
getSourceFields: (client, entityId) => client.post(`${DEFINE_BASE}/getSourceFields`, { entityId, usingTableNameAlias: true }),
|
|
73
|
+
getConditionFields: (client, request) => client.post(`${DEFINE_BASE}/getConditionFields`, request),
|
|
74
|
+
getJsonSchema: (client, entityId) => client.post(`${DEFINE_BASE}/getSourceJsonSchema`, {
|
|
75
|
+
entityId: qualifyEntityId(entityId), usingTableNameAlias: true,
|
|
76
|
+
}),
|
|
77
|
+
getDataOutJsonSchema: (client, entityId) => client.post(`${DEFINE_BASE}/getProcessDataOutJsonSchema`, {
|
|
78
|
+
entityId: qualifyEntityId(entityId), usingTableNameAlias: true,
|
|
79
|
+
}),
|
|
80
|
+
getActionFlowSchema: (client, code, appCode) => client.post(`${NODE_DEFINE_BASE}/getActiveTriggerParamSchema`, { code, appCode }),
|
|
81
|
+
getEventSchema: (client, code) => client.post(`${NODE_DEFINE_BASE}/getEventSchema`, { code }),
|
|
82
|
+
getInterfaceSchema: (client, code) => client.post(`${NODE_DEFINE_BASE}/getInterfaceSchema`, { code }),
|
|
83
|
+
getApiMethodSchema: (client, request) => client.post(`${NODE_DEFINE_BASE}/getApiMethodSchema`, request),
|
|
84
|
+
getFlowBotsSchema: (client, code) => client.post(`${NODE_DEFINE_BASE}/getFlowBotsSchema`, { code }),
|
|
85
|
+
getProcessEntityDetail: (client, request) => client.post(`${DEFINE_BASE}/getProcessEntityDetail`, request),
|
|
86
|
+
getQueryStatisticsSchema: (client, request) => client.post(`${DEFINE_BASE}/getQueryStatisticsSchema`, request),
|
|
87
|
+
getMetaJsonSchema: (client, request) => client.post(`${DEFINE_BASE}/getMetaJsonSchema`, request),
|
|
88
|
+
loadDataModel: (client, request) => client.post(`${DEFINE_BASE}/loadDataModel`, request),
|
|
89
|
+
getProcessDataEventInfo: (client) => client.post(`${DEFINE_BASE}/getProcessDataEventInfo`, {}),
|
|
90
|
+
getRecycleState: (client, entityId) => client.post('sys-modeling/sysModelingMechConfig/findByEntityId', { entityId }),
|
|
91
|
+
previewScheduled: (client, request) => client.post(`${DEFINE_BASE}/nextN`, request),
|
|
92
|
+
// ---- 分类 ----
|
|
93
|
+
categoryList: (client, request = {}) => client.post(`${CATEGORY_BASE}/list`, request),
|
|
94
|
+
categoryGet: (client, fdId) => client.post(`${CATEGORY_BASE}/get`, { fdId }),
|
|
95
|
+
categoryAdd: (client, vo) => client.post(`${CATEGORY_BASE}/add`, vo),
|
|
96
|
+
categoryUpdate: (client, vo) => client.post(`${CATEGORY_BASE}/update`, vo),
|
|
97
|
+
categoryDelete: (client, fdId) => client.post(`${CATEGORY_BASE}/delete`, { fdId }),
|
|
98
|
+
// ---- 运行日志 ----
|
|
99
|
+
/**
|
|
100
|
+
* 源码 `sysModelingActionFlowLog.ts:7` 声明 ModelingProcessLog/findAll,
|
|
101
|
+
* 但实测环境返回 404;日志页另有 LogQuery 的 `/sysModelingLog/findAllWithAppId`。
|
|
102
|
+
* 因此按候选顺序回退,并允许 --endpoint 指定抓包得到的真实路径。
|
|
103
|
+
*/
|
|
104
|
+
logFindAll: async (client, request, endpoint) => {
|
|
105
|
+
const paths = endpoint ? [endpoint] : exports.FLOW_LOG_ENDPOINTS;
|
|
106
|
+
const failures = [];
|
|
107
|
+
for (const path of paths) {
|
|
108
|
+
try {
|
|
109
|
+
return await client.post(path, request);
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
failures.push(`${path} → ${err.message.split('\n')[0]}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
throw new Error(`动作流日志端点均不可用(环境版本可能与源码不同);可用 --endpoint 指定:\n ${failures.join('\n ')}`);
|
|
116
|
+
},
|
|
117
|
+
logGet: (client, request) => client.post(`${LOG_BASE}/get`, request),
|
|
118
|
+
logRelation: (client, request) => client.post(`${LOG_BASE}/relation`, request),
|
|
119
|
+
};
|
package/dist/api/operation.js
CHANGED
|
@@ -24,4 +24,12 @@ exports.operationApi = {
|
|
|
24
24
|
offset: 0,
|
|
25
25
|
pageSize: 1000,
|
|
26
26
|
}),
|
|
27
|
+
/**
|
|
28
|
+
* 执行业务操作(平台运行入口,`sysModelingMain/other`)。
|
|
29
|
+
*
|
|
30
|
+
* 实测:绑定动作流的按钮(`fdConfig.fdTriggerType=3`)会由后端执行动作流,
|
|
31
|
+
* 返回 `{ success, type:'msg', responseMsg, sysModelingOperationVO }`;
|
|
32
|
+
* 前端在 `desktop/operation/other.ts:348-357` 正是以 `data.success` 判定动作流执行成功。
|
|
33
|
+
*/
|
|
34
|
+
execute: (client, request) => client.post('sys-modeling/sysModelingMain/other', request),
|
|
27
35
|
};
|