@mldong/jeeflow 1.8.20 → 1.8.22
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 +9 -6
- package/dist/engine.js +21 -3
- package/dist/facade.d.ts +2 -0
- package/dist/facade.js +24 -22
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
[jeeflow](https://jeeflow-doc.mldong.com) 引擎规范的 **TypeScript 实现**。仅依赖 `node:*` 标准库,零外部依赖(引擎核心)。
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
统一门面 `JeeflowFacade.flow(action, args)`;支持管理扩展(流程设计/历史/委托)、
|
|
6
|
+
assignee 变量解析与 `flow.auto`/`flow.admin` 系统代执行。
|
|
7
7
|
|
|
8
8
|
```bash
|
|
9
|
-
npm install @mldong/jeeflow
|
|
9
|
+
npm install @mldong/jeeflow
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
## 快速开始
|
|
@@ -29,7 +29,7 @@ await engine.executeProcessTask(tasks[0].id, 'leader')
|
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
> ⚠️ **id 全程 string(issue 38 E9)**:引擎内部与 API 契约的 id(流程定义/实例/任务/设计)一律为**字符串**。
|
|
32
|
-
> Java 雪花 id(>2^53)超出 JS 安全整数,`Number()`
|
|
32
|
+
> Java 雪花 id(>2^53)超出 JS 安全整数,`Number()` 转换必丢精度;字符串可无损承载,保证多语言同库共享流程。
|
|
33
33
|
|
|
34
34
|
## JDBC(MySQL/PostgreSQL)
|
|
35
35
|
|
|
@@ -74,8 +74,11 @@ npm run demo # http://localhost:8082
|
|
|
74
74
|
|
|
75
75
|
## 节点支持
|
|
76
76
|
|
|
77
|
-
对齐 [
|
|
77
|
+
对齐 [jeeflow-doc](https://jeeflow-doc.mldong.com)——与其他语言实现行为一致。
|
|
78
78
|
|
|
79
79
|
## License
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
Copyright © 2025-2026 mldong
|
|
82
|
+
|
|
83
|
+
Licensed under the Apache License, Version 2.0.
|
|
84
|
+
See [LICENSE](./LICENSE) and [NOTICE](./NOTICE).
|
package/dist/engine.js
CHANGED
|
@@ -253,7 +253,10 @@ export class EngineImpl {
|
|
|
253
253
|
const def = await this.repo.findDefineById(inst.defineId);
|
|
254
254
|
const flow = JSON.parse(typeof def.content === 'string' ? def.content : new TextDecoder().decode(def.content));
|
|
255
255
|
args = filterFieldByPerm(args, findNode(flow, task.taskName));
|
|
256
|
-
|
|
256
|
+
// issues/97:捕获原始实例变量(start 注入的发起人 u_*)——操作人 u_* 只进执行上下文
|
|
257
|
+
// 与任务行,不得整体写回实例(对齐 Java completeTask=putAll(args),args 不含 u_*)。
|
|
258
|
+
const baseVars = inst.variables;
|
|
259
|
+
const vars = { ...baseVars, ...task.variables, ...args };
|
|
257
260
|
await this.addUserInfo(operator, vars);
|
|
258
261
|
const now = new Date();
|
|
259
262
|
// 聚合根:完成任务(子实体状态转换 + 实例变量合并)
|
|
@@ -263,7 +266,8 @@ export class EngineImpl {
|
|
|
263
266
|
// completeTask 改的是外部任务对象,需同步回聚合根
|
|
264
267
|
syncTaskToAggregate(inst, task);
|
|
265
268
|
await this.fireEvent({ type: EventType.TaskComplete, instanceId: inst.id, taskId: task.id, nodeId: task.taskName, operator });
|
|
266
|
-
|
|
269
|
+
// issues/97:实例变量写回排除操作人 u_*,保留 start 注入的发起人 u_*(u_realName 恒为发起人)
|
|
270
|
+
inst.variables = mergeExecIntoInstance(baseVars, vars);
|
|
267
271
|
await this.repo.updateInstance(inst);
|
|
268
272
|
return { task, inst, flow, vars };
|
|
269
273
|
}
|
|
@@ -407,7 +411,8 @@ export class EngineImpl {
|
|
|
407
411
|
else {
|
|
408
412
|
inst.finish(new Date());
|
|
409
413
|
}
|
|
410
|
-
|
|
414
|
+
// issues/97:结束节点写回同样排除操作人 u_*(保留发起人 u_*,与 prepareExecuteTask 一致)
|
|
415
|
+
inst.variables = mergeExecIntoInstance(inst.variables, vars);
|
|
411
416
|
await this.repo.updateInstance(inst);
|
|
412
417
|
await this.fireEvent({ type: EventType.ProcessFinish, instanceId: inst.id, operator });
|
|
413
418
|
return;
|
|
@@ -638,6 +643,19 @@ function syncTaskToAggregate(inst, task) {
|
|
|
638
643
|
}
|
|
639
644
|
}
|
|
640
645
|
}
|
|
646
|
+
/** 实例变量写回合并(issues/97 对齐 Java):以 base(start 注入的发起人 u_*)为底,
|
|
647
|
+
* 并入执行上下文中**非 u_*** 键(f_ 表单字段 / submitType 等流转数据)。
|
|
648
|
+
* addUserInfo 生成的操作人 u_* 只属于当次执行上下文与任务行 ext,不整体写回实例——
|
|
649
|
+
* 实例 u_realName 语义是「发起人」(与 autoGenTitle 一致),不随审批节点漂移。 */
|
|
650
|
+
function mergeExecIntoInstance(base, execVars) {
|
|
651
|
+
const out = { ...base };
|
|
652
|
+
for (const [k, v] of Object.entries(execVars)) {
|
|
653
|
+
if (k.startsWith('u_'))
|
|
654
|
+
continue;
|
|
655
|
+
out[k] = v;
|
|
656
|
+
}
|
|
657
|
+
return out;
|
|
658
|
+
}
|
|
641
659
|
function isTruthy(v) {
|
|
642
660
|
if (typeof v === 'boolean')
|
|
643
661
|
return v;
|
package/dist/facade.d.ts
CHANGED
|
@@ -48,6 +48,8 @@ export declare class JeeflowFacade {
|
|
|
48
48
|
private surrogateUpdate;
|
|
49
49
|
/** 委托详情(issues/77):按 id 查单条,返回行结构(时间格式化) */
|
|
50
50
|
private surrogateDetail;
|
|
51
|
+
/** 删除委托(issues/95:前端「我的委托」行内/批量删除统一发 {ids},与 define/design remove 同惯例) */
|
|
52
|
+
private surrogateRemove;
|
|
51
53
|
/** 委托写入公共字段。授权人(operator)仅在显式传入时覆盖,避免 update
|
|
52
54
|
* 时清空原授权人(前端编辑表单不带 operator;集成层注入时 operator=授权人,覆盖无害) */
|
|
53
55
|
private applySurrogateFields;
|
package/dist/facade.js
CHANGED
|
@@ -106,7 +106,7 @@ export class JeeflowFacade {
|
|
|
106
106
|
case 'processSurrogate/detail': // issues/77
|
|
107
107
|
return this.surrogateDetail(args);
|
|
108
108
|
case 'processSurrogate/remove':
|
|
109
|
-
return this.
|
|
109
|
+
return this.surrogateRemove(args);
|
|
110
110
|
case 'processDefine/getLastByName':
|
|
111
111
|
return this.getLastByName(args);
|
|
112
112
|
case 'processInstance/highLight':
|
|
@@ -364,36 +364,21 @@ export class JeeflowFacade {
|
|
|
364
364
|
/** 删除设计稿(issues/28:兼容 {ids} 批量与单 {id}) */
|
|
365
365
|
async designRemove(args) {
|
|
366
366
|
const ext = this.ext();
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
await ext.removeDesign(toId(id));
|
|
370
|
-
}
|
|
371
|
-
else {
|
|
372
|
-
await ext.removeDesign(toId(args.id));
|
|
373
|
-
}
|
|
367
|
+
for (const id of idListArgs(args))
|
|
368
|
+
await ext.removeDesign(id);
|
|
374
369
|
return {};
|
|
375
370
|
}
|
|
376
371
|
/** 删除定义(issues/28:兼容 {ids} 批量与单 {id}) */
|
|
377
372
|
async defineRemove(args) {
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
await this.repo.removeDefine(toId(id));
|
|
381
|
-
}
|
|
382
|
-
else {
|
|
383
|
-
await this.repo.removeDefine(toId(args.id));
|
|
384
|
-
}
|
|
373
|
+
for (const id of idListArgs(args))
|
|
374
|
+
await this.repo.removeDefine(id);
|
|
385
375
|
return {};
|
|
386
376
|
}
|
|
387
377
|
/** 启用/停用(issues/28:兼容 {ids, opType} 批量;opType/state 二选一) */
|
|
388
378
|
async defineUpAndDown(args) {
|
|
389
379
|
const state = toInt(args.opType ?? args.state);
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
await this.repo.updateDefineState(toId(id), state);
|
|
393
|
-
}
|
|
394
|
-
else {
|
|
395
|
-
await this.repo.updateDefineState(toId(args.id), state);
|
|
396
|
-
}
|
|
380
|
+
for (const id of idListArgs(args))
|
|
381
|
+
await this.repo.updateDefineState(id, state);
|
|
397
382
|
return {};
|
|
398
383
|
}
|
|
399
384
|
/** 按类型分组列出流程设计(issue 30,对齐 Java issues/28):不依赖框架字典 */
|
|
@@ -628,6 +613,13 @@ export class JeeflowFacade {
|
|
|
628
613
|
throw new Error('委托记录不存在');
|
|
629
614
|
return surrogateRowToMap(surrogate);
|
|
630
615
|
}
|
|
616
|
+
/** 删除委托(issues/95:前端「我的委托」行内/批量删除统一发 {ids},与 define/design remove 同惯例) */
|
|
617
|
+
async surrogateRemove(args) {
|
|
618
|
+
const ext = this.ext();
|
|
619
|
+
for (const id of idListArgs(args))
|
|
620
|
+
await ext.removeSurrogate(id);
|
|
621
|
+
return {};
|
|
622
|
+
}
|
|
631
623
|
/** 委托写入公共字段。授权人(operator)仅在显式传入时覆盖,避免 update
|
|
632
624
|
* 时清空原授权人(前端编辑表单不带 operator;集成层注入时 operator=授权人,覆盖无害) */
|
|
633
625
|
applySurrogateFields(s, args, operator) {
|
|
@@ -1280,6 +1272,16 @@ function toId(v) {
|
|
|
1280
1272
|
throw new Error('id 缺失或非法');
|
|
1281
1273
|
return s;
|
|
1282
1274
|
}
|
|
1275
|
+
/** 删除/启停类 action 的批量主键:mldong IdsParam 惯例下 {ids} 数组优先,兼容单 {id};
|
|
1276
|
+
* 两者皆缺失、空数组或含非法值一律报错(issues/95,对齐 Java idListArgs) */
|
|
1277
|
+
function idListArgs(args) {
|
|
1278
|
+
if (Array.isArray(args.ids)) {
|
|
1279
|
+
if (args.ids.length === 0)
|
|
1280
|
+
throw new Error('id 缺失或非法');
|
|
1281
|
+
return args.ids.map(toId);
|
|
1282
|
+
}
|
|
1283
|
+
return [toId(args.id)];
|
|
1284
|
+
}
|
|
1283
1285
|
function toStringList2(v) {
|
|
1284
1286
|
if (Array.isArray(v))
|
|
1285
1287
|
return v.map(String);
|