@mldong/jeeflow 1.3.0 → 1.5.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/dist/engine.d.ts +2 -0
- package/dist/engine.js +6 -0
- package/dist/facade.d.ts +12 -0
- package/dist/facade.js +259 -9
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/jdbc/ext.d.ts +6 -3
- package/dist/jdbc/ext.js +61 -2
- package/dist/jdbc/shared.d.ts +26 -3
- package/dist/jdbc/shared.js +201 -4
- package/dist/memory-ext.d.ts +3 -3
- package/dist/memory-ext.js +35 -4
- package/dist/memory.d.ts +24 -3
- package/dist/memory.js +182 -3
- package/dist/metadata.d.ts +9 -0
- package/dist/metadata.js +41 -0
- package/dist/model.d.ts +94 -1
- package/dist/model.js +45 -0
- package/dist/registry.d.ts +21 -3
- package/dist/registry.js +26 -3
- package/dist/spi.d.ts +25 -4
- package/package.json +3 -1
package/dist/engine.d.ts
CHANGED
|
@@ -31,6 +31,8 @@ export declare class EngineImpl implements Engine {
|
|
|
31
31
|
setExtensions(ext: EngineExtensions): void;
|
|
32
32
|
setRegistry(reg: HandlerRegistry): void;
|
|
33
33
|
private firePre;
|
|
34
|
+
/** 表达式求值(v1.5.0,门面 highLight 决策分支过滤用) */
|
|
35
|
+
evalExpr(expr: string, vars: Record<string, any>): Promise<any>;
|
|
34
36
|
private firePost;
|
|
35
37
|
private fireEvent;
|
|
36
38
|
startProcessInstanceById(defineId: number, operator: string, args?: Record<string, any>): Promise<ProcessInstance>;
|
package/dist/engine.js
CHANGED
|
@@ -36,6 +36,12 @@ export class EngineImpl {
|
|
|
36
36
|
return false;
|
|
37
37
|
return true;
|
|
38
38
|
}
|
|
39
|
+
/** 表达式求值(v1.5.0,门面 highLight 决策分支过滤用) */
|
|
40
|
+
async evalExpr(expr, vars) {
|
|
41
|
+
if (!this.exprEval)
|
|
42
|
+
throw new Error('ExpressionEvaluator 未配置');
|
|
43
|
+
return this.exprEval.eval(expr, vars);
|
|
44
|
+
}
|
|
39
45
|
async firePost(node, inst) {
|
|
40
46
|
if (!this.ext?.interceptors)
|
|
41
47
|
return;
|
package/dist/facade.d.ts
CHANGED
|
@@ -24,6 +24,8 @@ export declare class JeeflowFacade {
|
|
|
24
24
|
private getLastByName;
|
|
25
25
|
private highLight;
|
|
26
26
|
private collectPath;
|
|
27
|
+
/** 决策输出边表达式求值(args = 实例变量 + 决策节点前置任务变量) */
|
|
28
|
+
private evalDecisionExpr;
|
|
27
29
|
private approvalRecord;
|
|
28
30
|
private getAssigneeTextData;
|
|
29
31
|
private createCCInstance;
|
|
@@ -36,4 +38,14 @@ export declare class JeeflowFacade {
|
|
|
36
38
|
private taskAddActor;
|
|
37
39
|
private taskLatest;
|
|
38
40
|
private ext;
|
|
41
|
+
private definePage;
|
|
42
|
+
private defineDetail;
|
|
43
|
+
private instancePage;
|
|
44
|
+
private instanceDetail;
|
|
45
|
+
/** 流程 JSON 中第一个任务节点 id(issues/05-4 isFirstTaskNode 用) */
|
|
46
|
+
private firstTaskNodeId;
|
|
47
|
+
private todoList;
|
|
48
|
+
private doneList;
|
|
49
|
+
/** 定义 content 解析为 LogicFlow JSON(issues/05 jsonObject) */
|
|
50
|
+
private parseGraph;
|
|
39
51
|
}
|
package/dist/facade.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// 集成方只实现一个转发端点:把 body JSON 转成对象传入 flow(),所有流程能力按
|
|
4
4
|
// action(boot2/boot3 端点短名)路由。返回统一结构 {code, msg, data}
|
|
5
5
|
// (code=0 成功 / 99999999 失败)。操作人约定:args.operator 显式传入。
|
|
6
|
+
import { TaskState, } from './model.js';
|
|
6
7
|
// submitType 枚举(对齐 boot3)
|
|
7
8
|
const SUBMIT_APPLY = 0;
|
|
8
9
|
const SUBMIT_AGREE = 1;
|
|
@@ -37,6 +38,10 @@ export class JeeflowFacade {
|
|
|
37
38
|
}
|
|
38
39
|
async dispatch(action, args) {
|
|
39
40
|
switch (action) {
|
|
41
|
+
case 'processDefine/page':
|
|
42
|
+
return this.definePage(args);
|
|
43
|
+
case 'processDefine/detail':
|
|
44
|
+
return this.defineDetail(args);
|
|
40
45
|
case 'processDefine/startAndExecute':
|
|
41
46
|
case 'processInstance/startAndExecute':
|
|
42
47
|
return this.startAndExecute(args);
|
|
@@ -49,8 +54,16 @@ export class JeeflowFacade {
|
|
|
49
54
|
return this.repo.removeDefine(toId(args.id));
|
|
50
55
|
case 'processDefine/upAndDown':
|
|
51
56
|
return this.repo.updateDefineState(toId(args.id), toInt(args.state));
|
|
57
|
+
case 'processInstance/page':
|
|
58
|
+
return this.instancePage(args);
|
|
59
|
+
case 'processInstance/detail':
|
|
60
|
+
return this.instanceDetail(args);
|
|
52
61
|
case 'processInstance/withdraw':
|
|
53
62
|
return this.withdraw(args);
|
|
63
|
+
case 'processTask/todoList':
|
|
64
|
+
return this.todoList(args);
|
|
65
|
+
case 'processTask/doneList':
|
|
66
|
+
return this.doneList(args);
|
|
54
67
|
case 'processTask/execute':
|
|
55
68
|
return this.execute(args);
|
|
56
69
|
case 'processDesign/page':
|
|
@@ -231,7 +244,7 @@ export class JeeflowFacade {
|
|
|
231
244
|
}
|
|
232
245
|
// ── 流程设计(需扩展仓储) ───────────────────────────────────────────────
|
|
233
246
|
async designPage(args) {
|
|
234
|
-
const [rows, total] = await this.ext().pageDesigns(toInt(args.pageNum ?? 1), toInt(args.pageSize ?? 10));
|
|
247
|
+
const [rows, total] = await this.ext().pageDesigns(toInt(args.pageNum ?? 1), toInt(args.pageSize ?? 10), undefined, parseMQuery(args));
|
|
235
248
|
return { rows, recordCount: total };
|
|
236
249
|
}
|
|
237
250
|
async designDetail(args) {
|
|
@@ -244,12 +257,25 @@ export class JeeflowFacade {
|
|
|
244
257
|
type: design.type, icon: design.icon, isDeployed: design.isDeployed, remark: design.remark,
|
|
245
258
|
};
|
|
246
259
|
const hisList = await ext.listDesignHis(design.id);
|
|
260
|
+
let jsonObject;
|
|
247
261
|
if (hisList.length > 0) {
|
|
248
262
|
try {
|
|
249
|
-
|
|
263
|
+
jsonObject = JSON.parse(toStr(hisList[0].content));
|
|
250
264
|
}
|
|
251
265
|
catch { /* ignore */ }
|
|
252
266
|
}
|
|
267
|
+
// issues/07:jsonObject 缺失基本信息时从设计表补齐(对齐 boot3 ProcessDesignServiceImpl.findById)
|
|
268
|
+
if (!jsonObject || typeof jsonObject !== 'object')
|
|
269
|
+
jsonObject = {};
|
|
270
|
+
if (!(jsonObject.name))
|
|
271
|
+
jsonObject.name = design.name;
|
|
272
|
+
if (!(jsonObject.displayName))
|
|
273
|
+
jsonObject.displayName = design.displayName;
|
|
274
|
+
if (!(jsonObject.type))
|
|
275
|
+
jsonObject.type = design.type;
|
|
276
|
+
if (!(jsonObject.processDesignId))
|
|
277
|
+
jsonObject.processDesignId = design.id;
|
|
278
|
+
data.jsonObject = jsonObject;
|
|
253
279
|
data.his = hisList;
|
|
254
280
|
return data;
|
|
255
281
|
}
|
|
@@ -296,7 +322,7 @@ export class JeeflowFacade {
|
|
|
296
322
|
// ── 委托代理(需扩展仓储) ───────────────────────────────────────────────
|
|
297
323
|
async surrogatePage(args) {
|
|
298
324
|
const filters = args.operator != null ? { operator: String(args.operator) } : undefined;
|
|
299
|
-
const [rows, total] = await this.ext().pageSurrogates(toInt(args.pageNum ?? 1), toInt(args.pageSize ?? 10), filters);
|
|
325
|
+
const [rows, total] = await this.ext().pageSurrogates(toInt(args.pageNum ?? 1), toInt(args.pageSize ?? 10), filters, parseMQuery(args));
|
|
300
326
|
return { rows, recordCount: total };
|
|
301
327
|
}
|
|
302
328
|
async surrogateSave(args) {
|
|
@@ -353,26 +379,33 @@ export class JeeflowFacade {
|
|
|
353
379
|
for (const t of his)
|
|
354
380
|
if (!active.includes(t.taskName) && !history.includes(t.taskName))
|
|
355
381
|
history.push(t.taskName);
|
|
356
|
-
// 路径补全:start
|
|
382
|
+
// 路径补全:start 沿边递归(遇活跃节点停止);决策分支按表达式求值过滤(issues/06)
|
|
357
383
|
const def = await this.repo.findDefineById(inst.defineId);
|
|
358
384
|
if (def) {
|
|
359
385
|
try {
|
|
360
386
|
const flow = JSON.parse(toStr(def.content));
|
|
361
|
-
this.collectPath(flow, 'start', '', active, history, edges, new Set());
|
|
387
|
+
await this.collectPath(flow, 'start', '', active, history, edges, new Set(), inst.variables ?? {}, his);
|
|
362
388
|
}
|
|
363
389
|
catch { /* ignore */ }
|
|
364
390
|
}
|
|
365
391
|
return { activeNodeNames: active, historyNodeNames: history, historyEdgeNames: edges };
|
|
366
392
|
}
|
|
367
|
-
collectPath(flow, nodeId, edgeName, active, history, edges, visited) {
|
|
393
|
+
async collectPath(flow, nodeId, edgeName, active, history, edges, visited, vars, historyTasks) {
|
|
368
394
|
if (visited.has(nodeId))
|
|
369
395
|
return;
|
|
370
396
|
visited.add(nodeId);
|
|
371
397
|
if (edgeName && !edges.includes(edgeName))
|
|
372
398
|
edges.push(edgeName);
|
|
399
|
+
const src = (flow.nodes ?? []).find((n) => n.id === nodeId);
|
|
373
400
|
for (const e of flow.edges ?? []) {
|
|
374
401
|
if (e.sourceNodeId !== nodeId)
|
|
375
402
|
continue;
|
|
403
|
+
// 决策节点:输出边表达式求值过滤(对齐 boot3 recursionModel,issues/06)
|
|
404
|
+
if (src?.type === 'snaker:decision') {
|
|
405
|
+
const expr = e.properties?.expr;
|
|
406
|
+
if (expr && !await this.evalDecisionExpr(flow, src, expr, vars, historyTasks))
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
376
409
|
const target = (flow.nodes ?? []).find((n) => n.id === e.targetNodeId);
|
|
377
410
|
if (!target)
|
|
378
411
|
continue;
|
|
@@ -381,7 +414,25 @@ export class JeeflowFacade {
|
|
|
381
414
|
history.push(tid);
|
|
382
415
|
if (active.includes(tid))
|
|
383
416
|
continue;
|
|
384
|
-
this.collectPath(flow, tid, e.id, active, history, edges, visited);
|
|
417
|
+
await this.collectPath(flow, tid, e.id, active, history, edges, visited, vars, historyTasks);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
/** 决策输出边表达式求值(args = 实例变量 + 决策节点前置任务变量) */
|
|
421
|
+
async evalDecisionExpr(flow, decision, expr, vars, historyTasks) {
|
|
422
|
+
const args = { ...(vars ?? {}) };
|
|
423
|
+
for (const e of flow.edges ?? []) {
|
|
424
|
+
if (e.targetNodeId === decision.id) {
|
|
425
|
+
const t = (historyTasks ?? []).find((x) => x.taskName === e.sourceNodeId);
|
|
426
|
+
if (t?.variables)
|
|
427
|
+
Object.assign(args, t.variables);
|
|
428
|
+
break;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
try {
|
|
432
|
+
return Boolean(await this.engine.evalExpr(expr, args));
|
|
433
|
+
}
|
|
434
|
+
catch {
|
|
435
|
+
return false;
|
|
385
436
|
}
|
|
386
437
|
}
|
|
387
438
|
async approvalRecord(args) {
|
|
@@ -424,8 +475,8 @@ export class JeeflowFacade {
|
|
|
424
475
|
const pageNum = toInt(args.pageNum ?? 1);
|
|
425
476
|
const pageSize = toInt(args.pageSize ?? 10);
|
|
426
477
|
const actorId = String(args.operator ?? 'user1');
|
|
427
|
-
const { rows, total } = await this.repo.pageCcInstances(pageNum, pageSize, actorId);
|
|
428
|
-
return { rows, recordCount: total };
|
|
478
|
+
const { rows, total } = await this.repo.pageCcInstances(pageNum, pageSize, actorId, parseMQuery(args));
|
|
479
|
+
return { rows: rows.map(r => ccRowToMap(r)), recordCount: total };
|
|
429
480
|
}
|
|
430
481
|
async taskDetail(args) {
|
|
431
482
|
const taskId = toId(args.id);
|
|
@@ -446,6 +497,7 @@ export class JeeflowFacade {
|
|
|
446
497
|
if (inst) {
|
|
447
498
|
const def = await this.repo.findDefineById(inst.defineId);
|
|
448
499
|
if (def) {
|
|
500
|
+
vo.jsonObject = this.parseGraph(def.content); // issues/05
|
|
449
501
|
try {
|
|
450
502
|
const flow = JSON.parse(toStr(def.content));
|
|
451
503
|
for (const n of flow.nodes ?? []) {
|
|
@@ -558,8 +610,206 @@ export class JeeflowFacade {
|
|
|
558
610
|
throw new Error('未配置 ProcessExtRepository(扩展仓储)');
|
|
559
611
|
return this.extRepo;
|
|
560
612
|
}
|
|
613
|
+
// ═══ 基础分页/详情(v1.5.0 补齐,对齐 Java 门面)═══
|
|
614
|
+
async definePage(args) {
|
|
615
|
+
const pageNum = toInt(args.pageNum ?? 1);
|
|
616
|
+
const pageSize = toInt(args.pageSize ?? 10);
|
|
617
|
+
const { rows, total } = await this.repo.pageDefines(pageNum, pageSize, parseMQuery(args));
|
|
618
|
+
return { rows: rows.map(r => defineRowToMap(r)), recordCount: total };
|
|
619
|
+
}
|
|
620
|
+
async defineDetail(args) {
|
|
621
|
+
const id = toId(args.id);
|
|
622
|
+
const def = await this.repo.findDefineById(id);
|
|
623
|
+
if (!def)
|
|
624
|
+
throw new Error('流程定义不存在');
|
|
625
|
+
return {
|
|
626
|
+
id: def.id, name: def.name, displayName: def.displayName,
|
|
627
|
+
type: def.type, state: def.state, version: def.version,
|
|
628
|
+
jsonObject: this.parseGraph(def.content), // issues/05
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
async instancePage(args) {
|
|
632
|
+
const pageNum = toInt(args.pageNum ?? 1);
|
|
633
|
+
const pageSize = toInt(args.pageSize ?? 10);
|
|
634
|
+
const operator = String(args.operator ?? 'user1');
|
|
635
|
+
const { rows, total } = await this.repo.pageInstances(pageNum, pageSize, operator, parseMQuery(args));
|
|
636
|
+
return { rows: rows.map(r => instanceRowToMap(r)), recordCount: total };
|
|
637
|
+
}
|
|
638
|
+
async instanceDetail(args) {
|
|
639
|
+
const id = toId(args.id);
|
|
640
|
+
const inst = await this.repo.findInstanceById(id);
|
|
641
|
+
if (!inst)
|
|
642
|
+
throw new Error('流程实例不存在');
|
|
643
|
+
const def0 = await this.repo.findDefineById(inst.defineId);
|
|
644
|
+
const graph = def0 ? this.parseGraph(def0.content) : undefined;
|
|
645
|
+
// 任务列表(issues/05-4):全量 tasks + activeTaskList(仅 DOING)+ 任务行 ext/isFirstTaskNode
|
|
646
|
+
const firstTaskNodeId = this.firstTaskNodeId(graph);
|
|
647
|
+
const tasks = [];
|
|
648
|
+
const activeTaskList = [];
|
|
649
|
+
for (const t of inst.tasks ?? []) {
|
|
650
|
+
const vo = {
|
|
651
|
+
id: t.id, processInstanceId: t.processInstanceId, taskName: t.taskName,
|
|
652
|
+
displayName: t.displayName, taskType: t.taskType ?? null,
|
|
653
|
+
performType: t.performType ?? null, taskState: t.taskState,
|
|
654
|
+
operator: t.actorId ?? '', finishTime: t.finishTime,
|
|
655
|
+
expireTime: t.expireTime, formKey: t.formKey ?? '', taskParentId: t.parentTaskId ?? null,
|
|
656
|
+
variable: JSON.stringify(t.variables ?? {}),
|
|
657
|
+
createTime: t.createTime, createUser: t.createUser,
|
|
658
|
+
updateTime: t.updateTime, updateUser: t.updateUser,
|
|
659
|
+
taskActorIdList: t.actorIds ?? [],
|
|
660
|
+
};
|
|
661
|
+
const ext = { ...(t.variables ?? {}) };
|
|
662
|
+
const doing = t.taskState === TaskState.Doing;
|
|
663
|
+
ext.isFirstTaskNode = doing && t.taskName === firstTaskNodeId;
|
|
664
|
+
vo.ext = ext;
|
|
665
|
+
tasks.push(vo);
|
|
666
|
+
if (doing)
|
|
667
|
+
activeTaskList.push(vo);
|
|
668
|
+
}
|
|
669
|
+
return {
|
|
670
|
+
id: inst.id, parentId: inst.parentId, processDefineId: inst.defineId,
|
|
671
|
+
state: inst.state, parentNodeName: inst.parentNodeName,
|
|
672
|
+
businessNo: inst.businessNo, operator: inst.operator,
|
|
673
|
+
variables: inst.variables, createTime: inst.createTime, createUser: inst.createUser,
|
|
674
|
+
jsonObject: graph, // issues/05
|
|
675
|
+
tasks,
|
|
676
|
+
activeTaskList,
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
/** 流程 JSON 中第一个任务节点 id(issues/05-4 isFirstTaskNode 用) */
|
|
680
|
+
firstTaskNodeId(graph) {
|
|
681
|
+
for (const n of graph?.nodes ?? []) {
|
|
682
|
+
if (n?.type === 'snaker:task')
|
|
683
|
+
return n.id;
|
|
684
|
+
}
|
|
685
|
+
return '';
|
|
686
|
+
}
|
|
687
|
+
async todoList(args) {
|
|
688
|
+
const pageNum = toInt(args.pageNum ?? 1);
|
|
689
|
+
const pageSize = toInt(args.pageSize ?? 10);
|
|
690
|
+
const actorId = String(args.operator ?? 'user1');
|
|
691
|
+
const { rows, total } = await this.repo.pageTodoTasks(pageNum, pageSize, actorId, parseMQuery(args));
|
|
692
|
+
return { rows: rows.map(r => taskRowToMap(r)), recordCount: total };
|
|
693
|
+
}
|
|
694
|
+
async doneList(args) {
|
|
695
|
+
const pageNum = toInt(args.pageNum ?? 1);
|
|
696
|
+
const pageSize = toInt(args.pageSize ?? 10);
|
|
697
|
+
const operator = String(args.operator ?? 'user1');
|
|
698
|
+
const { rows, total } = await this.repo.pageDoneTasks(pageNum, pageSize, operator, parseMQuery(args));
|
|
699
|
+
return { rows: rows.map(r => taskRowToMap(r)), recordCount: total };
|
|
700
|
+
}
|
|
701
|
+
/** 定义 content 解析为 LogicFlow JSON(issues/05 jsonObject) */
|
|
702
|
+
parseGraph(content) {
|
|
703
|
+
try {
|
|
704
|
+
const str = typeof content === 'string' ? content : new TextDecoder().decode(content);
|
|
705
|
+
const obj = JSON.parse(str);
|
|
706
|
+
return obj && typeof obj === 'object' ? obj : undefined;
|
|
707
|
+
}
|
|
708
|
+
catch {
|
|
709
|
+
return undefined;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
// ── 行转 Map(issues/05-2 列表字段契约 + 05-3 时间格式)─────────────────────
|
|
714
|
+
/** Date → 'yyyy-MM-dd HH:mm:ss'(null/undefined → null) */
|
|
715
|
+
function fmtTime(v) {
|
|
716
|
+
if (v == null)
|
|
717
|
+
return null;
|
|
718
|
+
const p = (n) => String(n).padStart(2, '0');
|
|
719
|
+
return `${v.getFullYear()}-${p(v.getMonth() + 1)}-${p(v.getDate())} ${p(v.getHours())}:${p(v.getMinutes())}:${p(v.getSeconds())}`;
|
|
720
|
+
}
|
|
721
|
+
/** JSON 字符串 → 对象(坏 JSON / 空返回空对象) */
|
|
722
|
+
function parseVarMap(json) {
|
|
723
|
+
if (!json)
|
|
724
|
+
return {};
|
|
725
|
+
try {
|
|
726
|
+
const o = JSON.parse(json);
|
|
727
|
+
return o && typeof o === 'object' ? o : {};
|
|
728
|
+
}
|
|
729
|
+
catch {
|
|
730
|
+
return {};
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
/** 定义行:时间格式化 */
|
|
734
|
+
function defineRowToMap(r) {
|
|
735
|
+
return {
|
|
736
|
+
id: r.id, name: r.name, displayName: r.displayName, type: r.type,
|
|
737
|
+
state: r.state, version: r.version,
|
|
738
|
+
createTime: fmtTime(r.createTime), createUser: r.createUser,
|
|
739
|
+
updateTime: fmtTime(r.updateTime), updateUser: r.updateUser,
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
/** 实例行:ext(实例变量对象)+ displayName/version(定义) */
|
|
743
|
+
function instanceRowToMap(r) {
|
|
744
|
+
return {
|
|
745
|
+
id: r.id, parentId: r.parentId ?? null, processDefineId: r.defineId,
|
|
746
|
+
state: r.state, parentNodeName: r.parentNodeName, businessNo: r.businessNo,
|
|
747
|
+
operator: r.operator, expireTime: fmtTime(r.expireTime),
|
|
748
|
+
variable: r.variables, createTime: fmtTime(r.createTime), createUser: r.createUser,
|
|
749
|
+
updateTime: fmtTime(r.updateTime), updateUser: r.updateUser,
|
|
750
|
+
processDefineName: r.defineName, processDefineDisplayName: r.defineDisplayName,
|
|
751
|
+
processDefineVersion: r.defineVersion,
|
|
752
|
+
ext: r.variables, displayName: r.defineDisplayName, version: r.defineVersion,
|
|
753
|
+
};
|
|
754
|
+
}
|
|
755
|
+
/** 抄送行:ext(实例变量对象)+ displayName/version(定义) */
|
|
756
|
+
function ccRowToMap(r) {
|
|
757
|
+
return {
|
|
758
|
+
id: r.id, parentId: r.parentId ?? null, processDefineId: r.defineId,
|
|
759
|
+
state: r.state, parentNodeName: r.parentNodeName, businessNo: r.businessNo,
|
|
760
|
+
operator: r.operator, expireTime: fmtTime(r.expireTime),
|
|
761
|
+
variable: r.variables, createTime: fmtTime(r.createTime), createUser: r.createUser,
|
|
762
|
+
updateTime: fmtTime(r.updateTime), updateUser: r.updateUser,
|
|
763
|
+
processDefineName: r.defineName, processDefineDisplayName: r.defineDisplayName,
|
|
764
|
+
processDefineVersion: r.defineVersion,
|
|
765
|
+
ext: r.variables, displayName: r.defineDisplayName, version: r.defineVersion,
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
/** 任务行:ext(任务变量,空回退实例变量)+ instanceExt + version */
|
|
769
|
+
function taskRowToMap(r) {
|
|
770
|
+
const instanceExt = parseVarMap(r.instanceVariable);
|
|
771
|
+
const ext = Object.keys(r.variables ?? {}).length > 0 ? r.variables : instanceExt;
|
|
772
|
+
return {
|
|
773
|
+
id: r.id, processInstanceId: r.processInstanceId, taskName: r.taskName,
|
|
774
|
+
displayName: r.displayName, taskType: r.taskType, performType: r.performType,
|
|
775
|
+
taskState: r.taskState, operator: r.operator, finishTime: fmtTime(r.finishTime),
|
|
776
|
+
expireTime: fmtTime(r.expireTime), formKey: r.formKey, taskParentId: r.taskParentId ?? null,
|
|
777
|
+
variable: r.variables, createTime: fmtTime(r.createTime), createUser: r.createUser,
|
|
778
|
+
updateTime: fmtTime(r.updateTime), updateUser: r.updateUser,
|
|
779
|
+
processDefineName: r.processDefineName, processDefineDisplayName: r.processDefineDisplayName,
|
|
780
|
+
instanceVariable: r.instanceVariable, instanceCreateTime: fmtTime(r.instanceCreateTime),
|
|
781
|
+
ext, instanceExt, version: r.defineVersion,
|
|
782
|
+
};
|
|
561
783
|
}
|
|
562
784
|
// ── 工具 ──────────────────────────────────────────────────────────────────────
|
|
785
|
+
/** m_ 前缀查询参数解析(issues/05-5,对齐 Java JeeflowQueryParser):
|
|
786
|
+
* m_EQ_taskName → t.task_name EQ;m_pd_LIKE_displayName → pd.display_name LIKE */
|
|
787
|
+
function parseMQuery(args) {
|
|
788
|
+
const out = [];
|
|
789
|
+
for (const [key, value] of Object.entries(args)) {
|
|
790
|
+
if (!key.startsWith('m_') || value == null || value === '')
|
|
791
|
+
continue;
|
|
792
|
+
const parts = key.slice(2).split('_');
|
|
793
|
+
if (parts.length < 2)
|
|
794
|
+
continue;
|
|
795
|
+
let column;
|
|
796
|
+
let operator;
|
|
797
|
+
if (parts.length === 2) {
|
|
798
|
+
// 无别名 → 默认主表别名 t(对齐 Java,白名单列均带表别名)
|
|
799
|
+
operator = parts[0];
|
|
800
|
+
column = 't.' + toUnderscore(parts[1]);
|
|
801
|
+
}
|
|
802
|
+
else {
|
|
803
|
+
operator = parts[1];
|
|
804
|
+
column = parts[0] + '.' + toUnderscore(parts[2]);
|
|
805
|
+
}
|
|
806
|
+
out.push({ column, operator: operator.toUpperCase(), value });
|
|
807
|
+
}
|
|
808
|
+
return out;
|
|
809
|
+
}
|
|
810
|
+
function toUnderscore(camel) {
|
|
811
|
+
return camel.replace(/[A-Z]/g, c => '_' + c.toLowerCase());
|
|
812
|
+
}
|
|
563
813
|
function toStr(v) {
|
|
564
814
|
if (v == null)
|
|
565
815
|
return '';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { EngineImpl, type Engine } from './engine.js';
|
|
2
2
|
export { MemoryRepository } from './memory.js';
|
|
3
|
-
export { HandlerRegistry, type IAssignmentHandler, type IDecisionHandler } from './registry.js';
|
|
3
|
+
export { HandlerRegistry, type IAssignmentHandler, type IDecisionHandler, type HandlerMeta } from './registry.js';
|
|
4
|
+
export { enumDict, enumDictKeys, type DictItem } from './metadata.js';
|
|
4
5
|
export * from './model.js';
|
|
5
6
|
export type { ProcessRepository, UserProvider, IDGenerator, ExpressionEvaluator } from './spi.js';
|
package/dist/index.js
CHANGED
package/dist/jdbc/ext.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ProcessDesign, ProcessDesignHis, ProcessSurrogate } from '../model.js';
|
|
2
|
-
import type { IDGenerator, ProcessExtRepository } from '../spi.js';
|
|
2
|
+
import type { IDGenerator, ProcessExtRepository, QueryCondition } from '../spi.js';
|
|
3
3
|
import { type SqlAdapter } from './shared.js';
|
|
4
4
|
export declare class JdbcProcessExtRepository implements ProcessExtRepository {
|
|
5
5
|
private readonly adapter;
|
|
@@ -13,7 +13,10 @@ export declare class JdbcProcessExtRepository implements ProcessExtRepository {
|
|
|
13
13
|
saveDesign(d: ProcessDesign): Promise<void>;
|
|
14
14
|
updateDesign(d: ProcessDesign): Promise<void>;
|
|
15
15
|
removeDesign(id: number): Promise<void>;
|
|
16
|
-
pageDesigns(pageNum?: number, pageSize?: number, filters?: Record<string, any
|
|
16
|
+
pageDesigns(pageNum?: number, pageSize?: number, filters?: Record<string, any>, conditions?: QueryCondition[]): Promise<[ProcessDesign[], number]>;
|
|
17
|
+
private buildExtWhere;
|
|
18
|
+
private static readonly DESIGN_WHITELIST;
|
|
19
|
+
private static readonly SURROGATE_WHITELIST;
|
|
17
20
|
saveDesignHis(his: ProcessDesignHis): Promise<void>;
|
|
18
21
|
listDesignHis(designId: number): Promise<ProcessDesignHis[]>;
|
|
19
22
|
private static SURROGATE_COLS;
|
|
@@ -21,7 +24,7 @@ export declare class JdbcProcessExtRepository implements ProcessExtRepository {
|
|
|
21
24
|
saveSurrogate(s: ProcessSurrogate): Promise<void>;
|
|
22
25
|
updateSurrogate(s: ProcessSurrogate): Promise<void>;
|
|
23
26
|
removeSurrogate(id: number): Promise<void>;
|
|
24
|
-
pageSurrogates(pageNum?: number, pageSize?: number, filters?: Record<string, any
|
|
27
|
+
pageSurrogates(pageNum?: number, pageSize?: number, filters?: Record<string, any>, conditions?: QueryCondition[]): Promise<[ProcessSurrogate[], number]>;
|
|
25
28
|
getSurrogate(operator: string, processName: string, at?: Date): Promise<ProcessSurrogate | null>;
|
|
26
29
|
private querySurrogate;
|
|
27
30
|
private mapDesign;
|
package/dist/jdbc/ext.js
CHANGED
|
@@ -76,7 +76,7 @@ export class JdbcProcessExtRepository {
|
|
|
76
76
|
await this.done(conn);
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
|
-
async pageDesigns(pageNum = 1, pageSize = 10, filters) {
|
|
79
|
+
async pageDesigns(pageNum = 1, pageSize = 10, filters, conditions) {
|
|
80
80
|
let sql = `SELECT ${JdbcProcessExtRepository.DESIGN_COLS} FROM wf_process_design t WHERE 1=1`;
|
|
81
81
|
let countSql = 'SELECT COUNT(*) FROM wf_process_design t WHERE 1=1';
|
|
82
82
|
const args = [];
|
|
@@ -89,6 +89,12 @@ export class JdbcProcessExtRepository {
|
|
|
89
89
|
args2.push(val);
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
|
+
// m_ 条件(issues/05-5):LIKE/EQ 等走白名单
|
|
93
|
+
const cond = this.buildExtWhere(conditions ?? [], JdbcProcessExtRepository.DESIGN_WHITELIST);
|
|
94
|
+
sql += cond.sql;
|
|
95
|
+
countSql += cond.sql;
|
|
96
|
+
args.push(...cond.params);
|
|
97
|
+
args2.push(...cond.params);
|
|
92
98
|
const conn = await this.c();
|
|
93
99
|
try {
|
|
94
100
|
const countRow = await conn.fetchOne(this.sql(countSql), args2);
|
|
@@ -102,6 +108,53 @@ export class JdbcProcessExtRepository {
|
|
|
102
108
|
await this.done(conn);
|
|
103
109
|
}
|
|
104
110
|
}
|
|
111
|
+
// m_ 条件 WHERE 构建(issues/05-5,白名单 + 参数化)
|
|
112
|
+
buildExtWhere(conditions, whitelist) {
|
|
113
|
+
let sql = '';
|
|
114
|
+
const params = [];
|
|
115
|
+
for (const c of conditions) {
|
|
116
|
+
if (!whitelist.has(c.column))
|
|
117
|
+
continue;
|
|
118
|
+
const val = c.value;
|
|
119
|
+
if (val == null || val === '')
|
|
120
|
+
continue;
|
|
121
|
+
switch (c.operator.toUpperCase()) {
|
|
122
|
+
case 'EQ':
|
|
123
|
+
sql += ` AND ${c.column} = ?`;
|
|
124
|
+
params.push(val);
|
|
125
|
+
break;
|
|
126
|
+
case 'LIKE':
|
|
127
|
+
sql += ` AND ${c.column} LIKE ?`;
|
|
128
|
+
params.push(`%${val}%`);
|
|
129
|
+
break;
|
|
130
|
+
case 'LLIKE':
|
|
131
|
+
sql += ` AND ${c.column} LIKE ?`;
|
|
132
|
+
params.push(`%${val}`);
|
|
133
|
+
break;
|
|
134
|
+
case 'RLIKE':
|
|
135
|
+
sql += ` AND ${c.column} LIKE ?`;
|
|
136
|
+
params.push(`${val}%`);
|
|
137
|
+
break;
|
|
138
|
+
case 'IN': {
|
|
139
|
+
if (Array.isArray(val) && val.length > 0) {
|
|
140
|
+
const marks = val.map(() => '?').join(',');
|
|
141
|
+
sql += ` AND ${c.column} IN (${marks})`;
|
|
142
|
+
params.push(...val);
|
|
143
|
+
}
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return { sql, params };
|
|
149
|
+
}
|
|
150
|
+
static DESIGN_WHITELIST = new Set([
|
|
151
|
+
't.id', 't.name', 't.display_name', 't.type', 't.is_deployed', 't.remark',
|
|
152
|
+
't.create_time', 't.update_time',
|
|
153
|
+
]);
|
|
154
|
+
static SURROGATE_WHITELIST = new Set([
|
|
155
|
+
't.id', 't.process_name', 't.operator', 't.surrogate', 't.enabled',
|
|
156
|
+
't.start_time', 't.end_time', 't.create_time', 't.update_time',
|
|
157
|
+
]);
|
|
105
158
|
// ── 设计历史 ─────────────────────────────────────────────────────────────
|
|
106
159
|
async saveDesignHis(his) {
|
|
107
160
|
if (!his.id)
|
|
@@ -182,7 +235,7 @@ export class JdbcProcessExtRepository {
|
|
|
182
235
|
await this.done(conn);
|
|
183
236
|
}
|
|
184
237
|
}
|
|
185
|
-
async pageSurrogates(pageNum = 1, pageSize = 10, filters) {
|
|
238
|
+
async pageSurrogates(pageNum = 1, pageSize = 10, filters, conditions) {
|
|
186
239
|
let sql = `SELECT ${JdbcProcessExtRepository.SURROGATE_COLS} FROM wf_process_surrogate t WHERE 1=1`;
|
|
187
240
|
let countSql = 'SELECT COUNT(*) FROM wf_process_surrogate t WHERE 1=1';
|
|
188
241
|
const args = [];
|
|
@@ -195,6 +248,12 @@ export class JdbcProcessExtRepository {
|
|
|
195
248
|
args2.push(val);
|
|
196
249
|
}
|
|
197
250
|
}
|
|
251
|
+
// m_ 条件(issues/05-5)
|
|
252
|
+
const cond = this.buildExtWhere(conditions ?? [], JdbcProcessExtRepository.SURROGATE_WHITELIST);
|
|
253
|
+
sql += cond.sql;
|
|
254
|
+
countSql += cond.sql;
|
|
255
|
+
args.push(...cond.params);
|
|
256
|
+
args2.push(...cond.params);
|
|
198
257
|
const conn = await this.c();
|
|
199
258
|
try {
|
|
200
259
|
const countRow = await conn.fetchOne(this.sql(countSql), args2);
|
package/dist/jdbc/shared.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ProcessInstance, ProcessTask, type ProcessDefine, type CcInstanceRow } from '../model.js';
|
|
2
|
-
import type { IDGenerator, ProcessRepository } from '../spi.js';
|
|
1
|
+
import { ProcessInstance, ProcessTask, type ProcessDefine, type CcInstanceRow, type DefineRow, type InstanceRow, type TaskRow } from '../model.js';
|
|
2
|
+
import type { IDGenerator, ProcessRepository, QueryCondition } from '../spi.js';
|
|
3
3
|
/** 默认 ID 生成器:时间戳毫秒 + 同毫秒递增序号(对齐 Java nextId 默认实现) */
|
|
4
4
|
export declare class TsIDGenerator implements IDGenerator {
|
|
5
5
|
private last;
|
|
@@ -63,7 +63,30 @@ export declare class JdbcRepository implements ProcessRepository {
|
|
|
63
63
|
removeTaskActor(taskId: number, actors: string[]): Promise<void>;
|
|
64
64
|
createCcInstance(instanceId: number, creator: string, ...actorIds: string[]): Promise<void>;
|
|
65
65
|
updateCcStatus(instanceId: number, actorId: string): Promise<void>;
|
|
66
|
-
|
|
66
|
+
pageDefines(pageNum: number, pageSize: number, conditions?: QueryCondition[]): Promise<{
|
|
67
|
+
rows: DefineRow[];
|
|
68
|
+
total: number;
|
|
69
|
+
}>;
|
|
70
|
+
pageInstances(pageNum: number, pageSize: number, operator: string, conditions?: QueryCondition[]): Promise<{
|
|
71
|
+
rows: InstanceRow[];
|
|
72
|
+
total: number;
|
|
73
|
+
}>;
|
|
74
|
+
pageTodoTasks(pageNum: number, pageSize: number, actorId: string, conditions?: QueryCondition[]): Promise<{
|
|
75
|
+
rows: TaskRow[];
|
|
76
|
+
total: number;
|
|
77
|
+
}>;
|
|
78
|
+
pageDoneTasks(pageNum: number, pageSize: number, operator: string, conditions?: QueryCondition[]): Promise<{
|
|
79
|
+
rows: TaskRow[];
|
|
80
|
+
total: number;
|
|
81
|
+
}>;
|
|
82
|
+
private pageTasks;
|
|
83
|
+
private mapInstanceRow;
|
|
84
|
+
protected buildWhere(conditions: QueryCondition[], whitelist: Set<string>): {
|
|
85
|
+
sql: string;
|
|
86
|
+
params: any[];
|
|
87
|
+
};
|
|
88
|
+
private mapTaskRow;
|
|
89
|
+
pageCcInstances(pageNum: number, pageSize: number, actorId: string, conditions?: QueryCondition[]): Promise<{
|
|
67
90
|
rows: CcInstanceRow[];
|
|
68
91
|
total: number;
|
|
69
92
|
}>;
|