lan-low-code-cli 2.6.0 → 2.7.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 +70 -0
- package/dist/api/flow.js +119 -0
- package/dist/commands/flow.js +755 -0
- 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 +13 -3
- package/skills/lan-low-code-cli/SKILL.zh-CN.md +12 -2
- package/skills/lan-low-code-cli/references/cli-contract.md +73 -3
- package/skills/lan-low-code-cli/references/cli-contract.zh-CN.md +69 -2
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
|
|
|
@@ -309,6 +310,65 @@ new Function('context', fdJavaScript)({
|
|
|
309
310
|
[skills/lan-low-code-cli/references/operation-script-context.md](skills/lan-low-code-cli/references/operation-script-context.md)
|
|
310
311
|
|
|
311
312
|
|
|
313
|
+
### 动作流(`llc flow`)
|
|
314
|
+
|
|
315
|
+
动作流是**应用级**对象(`--app-code` 即 `fdAppCode`),不是表单级。用声明式 JSON(Flow Spec)描述节点与连线,
|
|
316
|
+
CLI 负责补齐开始/结束节点、生成符合 IDE 编排习惯的坐标、按节点类型白名单裁剪字段,最后编译成
|
|
317
|
+
`fdDesign`(JSON 字符串)与平台 `addPublish` / `addDraft` 所需的扁平 VO。
|
|
318
|
+
|
|
319
|
+
```bash
|
|
320
|
+
# 1. 纯离线:生成模板 → 校验 → 编译(不联网)
|
|
321
|
+
llc flow spec --app-code cli-test --name 示例流程 --code flow_demo --out flow.json
|
|
322
|
+
llc flow validate --spec @flow.json --json
|
|
323
|
+
llc flow compile --spec @flow.json --json
|
|
324
|
+
|
|
325
|
+
# 2. 只读查询
|
|
326
|
+
llc flow list --app-code cli-test --json
|
|
327
|
+
llc flow get --id <flowId> --with-design
|
|
328
|
+
llc flow templates --from @compile-result.json --out templates.json # 抽取 golden 骨架(剥离坐标)
|
|
329
|
+
llc flow schema --kind jsonSchema --entity-id <fdId>
|
|
330
|
+
|
|
331
|
+
# 3. 写入(默认预览;必须 --yes + 显式 --app-code)
|
|
332
|
+
llc flow apply --spec @flow.json --app-code cli-test --resolve-schema # 预览 payload
|
|
333
|
+
llc flow apply --spec @flow.json --app-code cli-test --resolve-schema --yes --enable --json
|
|
334
|
+
llc flow diff --id <flowId> --spec @flow.json --resolve-schema # 回读比对(默认忽略坐标)
|
|
335
|
+
llc flow script --id <flowId> --out call-flow.js # 生成 MKXFORM.flow_<code> 脚本
|
|
336
|
+
llc flow disable --id <flowId> --yes
|
|
337
|
+
llc flow delete --id <flowId> --yes
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
**Flow Spec 关键字段**:`appCode` / `name` / `code`(`^[a-zA-Z0-9_]{1,30}$`)/ `startWay` /
|
|
341
|
+
`trigger`(`fdRunType`、`inParam`…)/ `nodes`(`id`、`type`、`config`、`context`、`subProcess`)/ `edges`
|
|
342
|
+
(`from`、`to`、`name`、`default`、`formula`)。节点 `id` 需匹配 `^[0-9a-zA-Z_]{2,32}$`。
|
|
343
|
+
|
|
344
|
+
**布局**由编译器生成,不要手写 `drawAttr.bounds`:
|
|
345
|
+
|
|
346
|
+
- `--layout ide`(默认):主链以 `--center-x`(默认 679)居中;`BranchNode` 为 56×56,其余节点 180×38;
|
|
347
|
+
分支后继与分支节点同层、泳道 ±1 左右对称;汇聚下移一层;层距 = 该层最高节点 + 52。
|
|
348
|
+
这与平台 mxGraph 编辑器「向下插入 / 左右插入」累积出的编排一致。
|
|
349
|
+
- `--layout layered`:分支后继放到下一层,可读性更强但与平台手工习惯略有差异。
|
|
350
|
+
- `--layout passthrough`:沿用 spec 里的 `bounds`(用于回写平台导出的流程)。
|
|
351
|
+
- `passthrough` 之外的模式下,`relative:false`、节点尺寸、连线 `sourceRef/targetRef` 与
|
|
352
|
+
`formulaConfig.branchFormulas`(引用真实连线 ID)、分支线 `exitX=0/1` 锚点均自动生成。
|
|
353
|
+
|
|
354
|
+
**Schema 注入**:`--resolve-schema` 会为引用数据模型的节点调 `getSourceJsonSchema` /
|
|
355
|
+
`getProcessDataOutJsonSchema` 补齐 `extraAttr.context_outputParam` / `context_bindFormId`。
|
|
356
|
+
这两个端点要求 `entityId` 带 `sys-modeling#` 前缀(CLI 自动补),裸 id 会返回 500。
|
|
357
|
+
失败默认只告警,`--strict-schema` 升级为错误。
|
|
358
|
+
|
|
359
|
+
**边界与已知限制**:
|
|
360
|
+
|
|
361
|
+
- `AddDataNode` / `AddOrUpdateNode` 的 `fields` 是平台真实结构
|
|
362
|
+
(`{field:{...},value:{format,valueJson}}`,公式引用形如 `${data.node.N1.xxx}`);
|
|
363
|
+
CLI **原样透传并只校验字段名,不臆造公式**。请用 `flow templates` / `flow get` 取 golden 骨架。
|
|
364
|
+
- 发布时后端从 `startNodeDef` 派生 `fdProcessActive`;`fdStatus=1` 即已启用。
|
|
365
|
+
- 运行日志端点因部署而异:源码声明 `ModelingProcessLog/findAll`,新版页面用
|
|
366
|
+
`sysModelingLog/findAllWithAppId`;`flow logs` 已内置候选回退,可用 `--endpoint` 指定抓包结果。
|
|
367
|
+
- 运行时触发端点 `executeFlowForAjax` 位于 `sys-xform` 运行时包(无文档化 REST 路径);
|
|
368
|
+
CLI 生成的按钮脚本走 `MKXFORM.flow_<fdCode>`,用 `operation create --type script` + `operation attach` 挂载。
|
|
369
|
+
- 完整命令与 Flow Spec 语法见
|
|
370
|
+
[skills/lan-low-code-cli/references/cli-contract.md](skills/lan-low-code-cli/references/cli-contract.md) 第 10 节。
|
|
371
|
+
|
|
312
372
|
### 控件类型
|
|
313
373
|
|
|
314
374
|
**先查环境再选控件**:
|
|
@@ -945,6 +1005,16 @@ llc config show | set | clear
|
|
|
945
1005
|
| 外部表字段 | `POST sys-xform/sysXFormDataModelField/loadFieldMeta` |
|
|
946
1006
|
| 字段库 | `POST sys-xform/sysXFormWordsField/list` |
|
|
947
1007
|
| 字段编码生成 | `POST sys-xform/sysXFormWordsField/generateFdKey` |
|
|
1008
|
+
| 动作流定义 CRUD / 列表 / 详情 | `POST sys-modeling/process/define/{list,get,add,update,delete,checkCodeUniqueness}` |
|
|
1009
|
+
| 动作流草稿与发布 | `POST sys-modeling/process/define/{addDraft,updateDraft,addPublish,updatePublish,saveDraft,publish}` |
|
|
1010
|
+
| 动作流启停 | `POST sys-modeling/process/define/{startup,stop}` |
|
|
1011
|
+
| 动作流引用关系 | `POST sys-modeling/modelingProcessDefineReferList/listByRefer` |
|
|
1012
|
+
| 动作流 Schema / 元数据 | `POST sys-modeling/process/define/{getSourceFields,getConditionFields,getSourceJsonSchema,getProcessDataOutJsonSchema,loadDataModel,businessNodes,nextN,…}`、`POST sys-modeling/processNode/define/*` |
|
|
1013
|
+
| 动作流分类 | `POST sys-modeling/sysModelingProcessCategory/{list,get,add,update,delete}` |
|
|
1014
|
+
| 动作流运行日志 | `POST sys-modeling/ModelingProcessLog/{findAll,get,relation}`(环境差异时可用 `--endpoint` 覆盖) |
|
|
1015
|
+
|
|
1016
|
+
> `getSourceJsonSchema` / `getProcessDataOutJsonSchema` 的 `entityId` 必须带 `sys-modeling#` 前缀;
|
|
1017
|
+
> `getSourceFields` / `getConditionFields` / `loadDataModel` 用裸 id。详见动作流章节。
|
|
948
1018
|
|
|
949
1019
|
## 五、生成的表单配置结构(`fdConfig`,**持久化格式**)
|
|
950
1020
|
|
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
|
+
};
|