@mldong/jeeflow 1.1.0 → 1.3.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/facade.d.ts +17 -0
- package/dist/facade.js +261 -0
- package/dist/jdbc/shared.d.ts +6 -1
- package/dist/jdbc/shared.js +51 -1
- package/dist/memory.d.ts +8 -3
- package/dist/memory.js +37 -2
- package/dist/model.d.ts +18 -0
- package/dist/spi.d.ts +5 -1
- package/package.json +45 -45
package/dist/facade.d.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import type { ProcessExtRepository, ProcessRepository } from './spi.js';
|
|
2
2
|
import type { EngineImpl } from './engine.js';
|
|
3
|
+
export type UserSearch = (query: Record<string, any>) => Promise<[Record<string, any>[], number]> | [Record<string, any>[], number];
|
|
3
4
|
export declare class JeeflowFacade {
|
|
4
5
|
private readonly engine;
|
|
5
6
|
private readonly repo;
|
|
6
7
|
private readonly extRepo?;
|
|
8
|
+
private userSearch?;
|
|
7
9
|
constructor(engine: EngineImpl, repo: ProcessRepository, extRepo?: ProcessExtRepository | undefined);
|
|
10
|
+
setUserSearch(fn: UserSearch): this;
|
|
8
11
|
flow(action: string, args?: Record<string, any>): Promise<Record<string, any>>;
|
|
9
12
|
private dispatch;
|
|
10
13
|
private startAndExecute;
|
|
@@ -18,5 +21,19 @@ export declare class JeeflowFacade {
|
|
|
18
21
|
private designSave;
|
|
19
22
|
private surrogatePage;
|
|
20
23
|
private surrogateSave;
|
|
24
|
+
private getLastByName;
|
|
25
|
+
private highLight;
|
|
26
|
+
private collectPath;
|
|
27
|
+
private approvalRecord;
|
|
28
|
+
private getAssigneeTextData;
|
|
29
|
+
private createCCInstance;
|
|
30
|
+
private updateCCStatus;
|
|
31
|
+
private ccList;
|
|
32
|
+
private taskDetail;
|
|
33
|
+
private jumpAbleTaskNameList;
|
|
34
|
+
private candidatePage;
|
|
35
|
+
private nextTaskCandidates;
|
|
36
|
+
private taskAddActor;
|
|
37
|
+
private taskLatest;
|
|
21
38
|
private ext;
|
|
22
39
|
}
|
package/dist/facade.js
CHANGED
|
@@ -15,11 +15,17 @@ export class JeeflowFacade {
|
|
|
15
15
|
engine;
|
|
16
16
|
repo;
|
|
17
17
|
extRepo;
|
|
18
|
+
userSearch;
|
|
18
19
|
constructor(engine, repo, extRepo) {
|
|
19
20
|
this.engine = engine;
|
|
20
21
|
this.repo = repo;
|
|
21
22
|
this.extRepo = extRepo;
|
|
22
23
|
}
|
|
24
|
+
// 注入用户搜索钩子(candidatePage 无模型候选时的用户分页搜索)
|
|
25
|
+
setUserSearch(fn) {
|
|
26
|
+
this.userSearch = fn;
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
23
29
|
async flow(action, args = {}) {
|
|
24
30
|
try {
|
|
25
31
|
const data = await this.dispatch(action, args);
|
|
@@ -61,6 +67,31 @@ export class JeeflowFacade {
|
|
|
61
67
|
return this.surrogateSave(args);
|
|
62
68
|
case 'processSurrogate/remove':
|
|
63
69
|
return this.ext().removeSurrogate(toId(args.id));
|
|
70
|
+
case 'processDefine/getLastByName':
|
|
71
|
+
return this.getLastByName(args);
|
|
72
|
+
case 'processInstance/highLight':
|
|
73
|
+
return this.highLight(args);
|
|
74
|
+
case 'processInstance/approvalRecord':
|
|
75
|
+
return this.approvalRecord(args);
|
|
76
|
+
case 'processInstance/getAssigneeTextData':
|
|
77
|
+
return this.getAssigneeTextData(args);
|
|
78
|
+
case 'processInstance/createCCInstance':
|
|
79
|
+
return this.createCCInstance(args);
|
|
80
|
+
case 'processInstance/updateCCStatus':
|
|
81
|
+
return this.updateCCStatus(args);
|
|
82
|
+
case 'processInstance/ccList':
|
|
83
|
+
return this.ccList(args);
|
|
84
|
+
case 'processTask/detail':
|
|
85
|
+
return this.taskDetail(args);
|
|
86
|
+
case 'processTask/jumpAbleTaskNameList':
|
|
87
|
+
return this.jumpAbleTaskNameList(args);
|
|
88
|
+
case 'processTask/candidatePage':
|
|
89
|
+
return this.candidatePage(args);
|
|
90
|
+
case 'processTask/surrogate':
|
|
91
|
+
case 'processTask/addCandidate':
|
|
92
|
+
return this.taskAddActor(args);
|
|
93
|
+
case 'processTask/latest':
|
|
94
|
+
return this.taskLatest(args);
|
|
64
95
|
default:
|
|
65
96
|
throw new Error(`未知 action: ${action}`);
|
|
66
97
|
}
|
|
@@ -299,6 +330,229 @@ export class JeeflowFacade {
|
|
|
299
330
|
}
|
|
300
331
|
return { id: surrogate.id };
|
|
301
332
|
}
|
|
333
|
+
// ── 视图端点(v1.2.0) ──────────────────────────────────────────────────
|
|
334
|
+
async getLastByName(args) {
|
|
335
|
+
const def = await this.repo.findDefineByName(String(args.processDefineName ?? ''));
|
|
336
|
+
if (!def)
|
|
337
|
+
throw new Error(`流程定义不存在: ${args.processDefineName}`);
|
|
338
|
+
return { id: def.id, name: def.name, displayName: def.displayName, type: def.type, state: def.state, version: def.version };
|
|
339
|
+
}
|
|
340
|
+
async highLight(args) {
|
|
341
|
+
const instanceId = toId(args.id);
|
|
342
|
+
const inst = await this.repo.findInstanceById(instanceId);
|
|
343
|
+
if (!inst)
|
|
344
|
+
throw new Error('流程实例不存在');
|
|
345
|
+
const active = [];
|
|
346
|
+
const history = [];
|
|
347
|
+
const edges = [];
|
|
348
|
+
const doing = await this.repo.findDoingTasks(instanceId);
|
|
349
|
+
for (const t of doing)
|
|
350
|
+
if (!active.includes(t.taskName))
|
|
351
|
+
active.push(t.taskName);
|
|
352
|
+
const his = await this.repo.findHistoryTasks(instanceId);
|
|
353
|
+
for (const t of his)
|
|
354
|
+
if (!active.includes(t.taskName) && !history.includes(t.taskName))
|
|
355
|
+
history.push(t.taskName);
|
|
356
|
+
// 路径补全:start 沿边递归(遇活跃节点停止)
|
|
357
|
+
const def = await this.repo.findDefineById(inst.defineId);
|
|
358
|
+
if (def) {
|
|
359
|
+
try {
|
|
360
|
+
const flow = JSON.parse(toStr(def.content));
|
|
361
|
+
this.collectPath(flow, 'start', '', active, history, edges, new Set());
|
|
362
|
+
}
|
|
363
|
+
catch { /* ignore */ }
|
|
364
|
+
}
|
|
365
|
+
return { activeNodeNames: active, historyNodeNames: history, historyEdgeNames: edges };
|
|
366
|
+
}
|
|
367
|
+
collectPath(flow, nodeId, edgeName, active, history, edges, visited) {
|
|
368
|
+
if (visited.has(nodeId))
|
|
369
|
+
return;
|
|
370
|
+
visited.add(nodeId);
|
|
371
|
+
if (edgeName && !edges.includes(edgeName))
|
|
372
|
+
edges.push(edgeName);
|
|
373
|
+
for (const e of flow.edges ?? []) {
|
|
374
|
+
if (e.sourceNodeId !== nodeId)
|
|
375
|
+
continue;
|
|
376
|
+
const target = (flow.nodes ?? []).find((n) => n.id === e.targetNodeId);
|
|
377
|
+
if (!target)
|
|
378
|
+
continue;
|
|
379
|
+
const tid = target.id;
|
|
380
|
+
if (!active.includes(tid) && !history.includes(tid))
|
|
381
|
+
history.push(tid);
|
|
382
|
+
if (active.includes(tid))
|
|
383
|
+
continue;
|
|
384
|
+
this.collectPath(flow, tid, e.id, active, history, edges, visited);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
async approvalRecord(args) {
|
|
388
|
+
const instanceId = toId(args.id);
|
|
389
|
+
const his = await this.repo.findHistoryTasks(instanceId);
|
|
390
|
+
return his.map(t => ({
|
|
391
|
+
taskName: t.taskName, displayName: t.displayName, taskType: t.taskType ?? null,
|
|
392
|
+
performType: t.performType ?? null, taskState: t.taskState, operator: t.actorId ?? '',
|
|
393
|
+
finishTime: t.finishTime ?? null, variable: t.variables ?? {},
|
|
394
|
+
}));
|
|
395
|
+
}
|
|
396
|
+
async getAssigneeTextData(args) {
|
|
397
|
+
const instanceId = toId(args.id);
|
|
398
|
+
const includeNodeName = args.includeNodeName !== false;
|
|
399
|
+
const rows = [];
|
|
400
|
+
const doing = await this.repo.findDoingTasks(instanceId);
|
|
401
|
+
for (const t of doing) {
|
|
402
|
+
const actors = await this.repo.findTaskActors(t.id);
|
|
403
|
+
for (const actor of actors) {
|
|
404
|
+
rows.push({ label: includeNodeName ? `${t.displayName}:${actor}` : actor, value: actor });
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
return rows;
|
|
408
|
+
}
|
|
409
|
+
async createCCInstance(args) {
|
|
410
|
+
const instanceId = toId(args.processInstanceId);
|
|
411
|
+
const operator = String(args.operator ?? 'user1');
|
|
412
|
+
const actors = toStringList2(args.actorIds);
|
|
413
|
+
if (actors.length === 0)
|
|
414
|
+
throw new Error('actorIds 缺失');
|
|
415
|
+
await this.repo.createCcInstance(instanceId, operator, ...actors);
|
|
416
|
+
}
|
|
417
|
+
async updateCCStatus(args) {
|
|
418
|
+
const instanceId = toId(args.processInstanceId);
|
|
419
|
+
const operator = String(args.operator ?? 'user1');
|
|
420
|
+
await this.repo.updateCcStatus(instanceId, operator);
|
|
421
|
+
}
|
|
422
|
+
// ccList 我的抄送分页(v1.3.0):operator 作为抄送人过滤
|
|
423
|
+
async ccList(args) {
|
|
424
|
+
const pageNum = toInt(args.pageNum ?? 1);
|
|
425
|
+
const pageSize = toInt(args.pageSize ?? 10);
|
|
426
|
+
const actorId = String(args.operator ?? 'user1');
|
|
427
|
+
const { rows, total } = await this.repo.pageCcInstances(pageNum, pageSize, actorId);
|
|
428
|
+
return { rows, recordCount: total };
|
|
429
|
+
}
|
|
430
|
+
async taskDetail(args) {
|
|
431
|
+
const taskId = toId(args.id);
|
|
432
|
+
const operator = String(args.operator ?? 'user1');
|
|
433
|
+
const task = await this.repo.findTaskById(taskId);
|
|
434
|
+
if (!task)
|
|
435
|
+
throw new Error('任务不存在');
|
|
436
|
+
const actors = await this.repo.findTaskActors(taskId);
|
|
437
|
+
const vo = {
|
|
438
|
+
id: task.id, processInstanceId: task.processInstanceId, taskName: task.taskName,
|
|
439
|
+
displayName: task.displayName, taskType: task.taskType ?? null,
|
|
440
|
+
performType: task.performType ?? null, taskState: task.taskState,
|
|
441
|
+
operator: task.actorId ?? '', formKey: task.formKey ?? '',
|
|
442
|
+
taskActorIdList: actors, executable: task.isAllowed(operator),
|
|
443
|
+
};
|
|
444
|
+
// taskModel:流程定义中对应节点
|
|
445
|
+
const inst = await this.repo.findInstanceById(task.processInstanceId);
|
|
446
|
+
if (inst) {
|
|
447
|
+
const def = await this.repo.findDefineById(inst.defineId);
|
|
448
|
+
if (def) {
|
|
449
|
+
try {
|
|
450
|
+
const flow = JSON.parse(toStr(def.content));
|
|
451
|
+
for (const n of flow.nodes ?? []) {
|
|
452
|
+
if (n.id === task.taskName) {
|
|
453
|
+
vo.taskModel = { name: n.id, displayName: n.text?.value ?? '', type: n.type };
|
|
454
|
+
break;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
catch { /* ignore */ }
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
return vo;
|
|
462
|
+
}
|
|
463
|
+
async jumpAbleTaskNameList(args) {
|
|
464
|
+
const instanceId = toId(args.processInstanceId);
|
|
465
|
+
const done = await this.repo.findDoneTasks(instanceId);
|
|
466
|
+
const rows = [];
|
|
467
|
+
const seen = new Set();
|
|
468
|
+
for (const t of done) {
|
|
469
|
+
if ((t.performType ?? 0) === 1)
|
|
470
|
+
continue; // COUNTERSIGN
|
|
471
|
+
if (!seen.has(t.taskName)) {
|
|
472
|
+
seen.add(t.taskName);
|
|
473
|
+
rows.push({ label: t.displayName, value: t.taskName });
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
return rows;
|
|
477
|
+
}
|
|
478
|
+
async candidatePage(args) {
|
|
479
|
+
const taskId = toId(args.processTaskId ?? args.id);
|
|
480
|
+
const task = await this.repo.findTaskById(taskId);
|
|
481
|
+
if (!task)
|
|
482
|
+
throw new Error('任务不存在');
|
|
483
|
+
const inst = await this.repo.findInstanceById(task.processInstanceId);
|
|
484
|
+
if (!inst)
|
|
485
|
+
throw new Error('流程实例不存在');
|
|
486
|
+
// 模型候选解析:后继任务节点的 candidateUsers 配置
|
|
487
|
+
let candidates = [];
|
|
488
|
+
const def = await this.repo.findDefineById(inst.defineId);
|
|
489
|
+
if (def) {
|
|
490
|
+
try {
|
|
491
|
+
const flow = JSON.parse(toStr(def.content));
|
|
492
|
+
candidates = this.nextTaskCandidates(flow, task.taskName);
|
|
493
|
+
}
|
|
494
|
+
catch { /* ignore */ }
|
|
495
|
+
}
|
|
496
|
+
if (candidates.length > 0) {
|
|
497
|
+
const rows = candidates.map(c => ({ userId: c, realName: c }));
|
|
498
|
+
return { rows, recordCount: rows.length };
|
|
499
|
+
}
|
|
500
|
+
// 无模型候选 → 用户分页搜索(依赖 userSearch 钩子)
|
|
501
|
+
if (!this.userSearch)
|
|
502
|
+
throw new Error('未配置 userSearch(用户搜索钩子)');
|
|
503
|
+
const [rows, total] = await this.userSearch(args);
|
|
504
|
+
return { rows, recordCount: total };
|
|
505
|
+
}
|
|
506
|
+
nextTaskCandidates(flow, taskName) {
|
|
507
|
+
const result = [];
|
|
508
|
+
const visited = new Set();
|
|
509
|
+
const collect = (node) => {
|
|
510
|
+
const v = node.properties?.candidateUsers;
|
|
511
|
+
if (v) {
|
|
512
|
+
for (const s of String(v).split(',')) {
|
|
513
|
+
const t = s.trim();
|
|
514
|
+
if (t && !result.includes(t))
|
|
515
|
+
result.push(t);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
};
|
|
519
|
+
const walk = (nodeId) => {
|
|
520
|
+
if (visited.has(nodeId))
|
|
521
|
+
return;
|
|
522
|
+
visited.add(nodeId);
|
|
523
|
+
for (const e of flow.edges ?? []) {
|
|
524
|
+
if (e.sourceNodeId !== nodeId)
|
|
525
|
+
continue;
|
|
526
|
+
const target = (flow.nodes ?? []).find((n) => n.id === e.targetNodeId);
|
|
527
|
+
if (!target)
|
|
528
|
+
continue;
|
|
529
|
+
if (target.type === 'snaker:task' || target.type === 'snaker:custom') {
|
|
530
|
+
collect(target);
|
|
531
|
+
continue;
|
|
532
|
+
}
|
|
533
|
+
if (['snaker:fork', 'snaker:join', 'snaker:decision'].includes(target.type)) {
|
|
534
|
+
walk(target.id);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
walk(taskName);
|
|
539
|
+
return result;
|
|
540
|
+
}
|
|
541
|
+
async taskAddActor(args) {
|
|
542
|
+
const taskId = toId(args.processTaskId);
|
|
543
|
+
const actors = toStringList2(args.actorIds);
|
|
544
|
+
if (actors.length === 0)
|
|
545
|
+
throw new Error('actorIds 缺失');
|
|
546
|
+
await this.repo.addTaskActor(taskId, actors);
|
|
547
|
+
}
|
|
548
|
+
async taskLatest(args) {
|
|
549
|
+
const instanceId = toId(args.processInstanceId);
|
|
550
|
+
const doing = await this.repo.findDoingTasks(instanceId);
|
|
551
|
+
if (doing.length === 0)
|
|
552
|
+
return null;
|
|
553
|
+
const t = doing[0];
|
|
554
|
+
return { id: t.id, taskName: t.taskName, displayName: t.displayName, taskState: t.taskState, operator: t.actorId ?? '' };
|
|
555
|
+
}
|
|
302
556
|
ext() {
|
|
303
557
|
if (!this.extRepo)
|
|
304
558
|
throw new Error('未配置 ProcessExtRepository(扩展仓储)');
|
|
@@ -321,6 +575,13 @@ function toId(v) {
|
|
|
321
575
|
throw new Error('id 缺失或非法');
|
|
322
576
|
return n;
|
|
323
577
|
}
|
|
578
|
+
function toStringList2(v) {
|
|
579
|
+
if (Array.isArray(v))
|
|
580
|
+
return v.map(String);
|
|
581
|
+
if (typeof v === 'string')
|
|
582
|
+
return v.split(',').map(s => s.trim()).filter(Boolean);
|
|
583
|
+
return [];
|
|
584
|
+
}
|
|
324
585
|
function toInt(v) {
|
|
325
586
|
const n = Number(v);
|
|
326
587
|
if (!Number.isFinite(n))
|
package/dist/jdbc/shared.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ProcessInstance, ProcessTask, type ProcessDefine } from '../model.js';
|
|
1
|
+
import { ProcessInstance, ProcessTask, type ProcessDefine, type CcInstanceRow } from '../model.js';
|
|
2
2
|
import type { IDGenerator, ProcessRepository } from '../spi.js';
|
|
3
3
|
/** 默认 ID 生成器:时间戳毫秒 + 同毫秒递增序号(对齐 Java nextId 默认实现) */
|
|
4
4
|
export declare class TsIDGenerator implements IDGenerator {
|
|
@@ -63,4 +63,9 @@ 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
|
+
pageCcInstances(pageNum: number, pageSize: number, actorId: string): Promise<{
|
|
67
|
+
rows: CcInstanceRow[];
|
|
68
|
+
total: number;
|
|
69
|
+
}>;
|
|
70
|
+
private mapCcRow;
|
|
66
71
|
}
|
package/dist/jdbc/shared.js
CHANGED
|
@@ -349,9 +349,17 @@ export class JdbcRepository {
|
|
|
349
349
|
}
|
|
350
350
|
}
|
|
351
351
|
async addTaskActor(taskId, actors) {
|
|
352
|
+
if (actors.length === 0)
|
|
353
|
+
return;
|
|
354
|
+
// 追加语义(对齐 boot2/boot3,issues/03):查已有参与者,去重后仅插入新增,不清空原参与者
|
|
355
|
+
const existing = await this.findTaskActors(taskId);
|
|
356
|
+
const seen = new Set(existing);
|
|
357
|
+
const toAdd = actors.filter(a => !seen.has(a));
|
|
358
|
+
if (toAdd.length === 0)
|
|
359
|
+
return;
|
|
352
360
|
const conn = await this.c();
|
|
353
361
|
try {
|
|
354
|
-
await this.insertTaskActors(conn, taskId,
|
|
362
|
+
await this.insertTaskActors(conn, taskId, toAdd);
|
|
355
363
|
}
|
|
356
364
|
finally {
|
|
357
365
|
await this.done(conn);
|
|
@@ -391,4 +399,46 @@ export class JdbcRepository {
|
|
|
391
399
|
await this.done(conn);
|
|
392
400
|
}
|
|
393
401
|
}
|
|
402
|
+
// pageCcInstances 我的抄送分页(v1.3.0):cc 表 join 实例 + 定义,按抄送人过滤(对齐 Java pageCcInstances)
|
|
403
|
+
async pageCcInstances(pageNum, pageSize, actorId) {
|
|
404
|
+
const where = ' FROM wf_process_instance t' +
|
|
405
|
+
' LEFT JOIN wf_process_define pd ON t.process_define_id = pd.id' +
|
|
406
|
+
' LEFT JOIN wf_process_cc_instance cc ON t.id = cc.process_instance_id' +
|
|
407
|
+
' WHERE cc.actor_id = ?';
|
|
408
|
+
const cols = 't.id, t.parent_id, t.process_define_id, t.state, t.parent_node_name, t.business_no,' +
|
|
409
|
+
' t.operator, t.expire_time, t.variable, t.create_time, t.create_user, t.update_time, t.update_user,' +
|
|
410
|
+
' pd.name, pd.display_name, pd.version';
|
|
411
|
+
const conn = await this.c();
|
|
412
|
+
try {
|
|
413
|
+
const countRow = await conn.fetchOne(this.sql('SELECT COUNT(*) ' + where), [actorId]);
|
|
414
|
+
const total = Number(Object.values(countRow)[0] ?? 0);
|
|
415
|
+
const rows = await conn.fetchAll(this.sql(`SELECT ${cols}${where} ORDER BY t.id ASC LIMIT ? OFFSET ?`), [actorId, pageSize, (pageNum - 1) * pageSize]);
|
|
416
|
+
return {
|
|
417
|
+
rows: rows.map(r => this.mapCcRow(r)),
|
|
418
|
+
total,
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
finally {
|
|
422
|
+
await this.done(conn);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
mapCcRow(r) {
|
|
426
|
+
let variables = {};
|
|
427
|
+
if (r.variable) {
|
|
428
|
+
try {
|
|
429
|
+
variables = JSON.parse(r.variable);
|
|
430
|
+
}
|
|
431
|
+
catch { /* 忽略坏 JSON */ }
|
|
432
|
+
}
|
|
433
|
+
return {
|
|
434
|
+
id: Number(r.id), parentId: r.parent_id != null ? Number(r.parent_id) : undefined,
|
|
435
|
+
defineId: Number(r.process_define_id), state: r.state,
|
|
436
|
+
parentNodeName: r.parent_node_name ?? '', businessNo: r.business_no ?? '', operator: r.operator ?? '',
|
|
437
|
+
expireTime: r.expire_time ?? undefined, variables,
|
|
438
|
+
createTime: r.create_time, createUser: r.create_user ?? '',
|
|
439
|
+
updateTime: r.update_time, updateUser: r.update_user ?? '',
|
|
440
|
+
defineName: r.name ?? '', defineDisplayName: r.display_name ?? '',
|
|
441
|
+
defineVersion: Number(r.version ?? 0),
|
|
442
|
+
};
|
|
443
|
+
}
|
|
394
444
|
}
|
package/dist/memory.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ProcessDefine } from './model.js';
|
|
1
|
+
import type { CcInstanceRow, ProcessDefine } from './model.js';
|
|
2
2
|
import { type ProcessInstance, type ProcessTask } from './model.js';
|
|
3
3
|
import type { ProcessRepository } from './spi.js';
|
|
4
4
|
export declare class MemoryRepository implements ProcessRepository {
|
|
@@ -6,6 +6,7 @@ export declare class MemoryRepository implements ProcessRepository {
|
|
|
6
6
|
private instances;
|
|
7
7
|
private tasks;
|
|
8
8
|
private actors;
|
|
9
|
+
private ccInstances;
|
|
9
10
|
private seq;
|
|
10
11
|
addDefine(def: ProcessDefine): void;
|
|
11
12
|
findDefineById(id: number): Promise<ProcessDefine | null>;
|
|
@@ -26,8 +27,12 @@ export declare class MemoryRepository implements ProcessRepository {
|
|
|
26
27
|
findTaskActors(taskId: number): Promise<string[]>;
|
|
27
28
|
addTaskActor(taskId: number, actors: string[]): Promise<void>;
|
|
28
29
|
removeTaskActor(taskId: number, actors: string[]): Promise<void>;
|
|
29
|
-
createCcInstance(...
|
|
30
|
-
updateCcStatus(
|
|
30
|
+
createCcInstance(instanceId: number, _creator: string, ...actorIds: string[]): Promise<void>;
|
|
31
|
+
updateCcStatus(_instanceId: number, _actorId: string): Promise<void>;
|
|
32
|
+
pageCcInstances(pageNum: number | undefined, pageSize: number | undefined, actorId: string): Promise<{
|
|
33
|
+
rows: CcInstanceRow[];
|
|
34
|
+
total: number;
|
|
35
|
+
}>;
|
|
31
36
|
allDefines(): ProcessDefine[];
|
|
32
37
|
allInstances(): ProcessInstance[];
|
|
33
38
|
allTasks(): ProcessTask[];
|
package/dist/memory.js
CHANGED
|
@@ -4,6 +4,7 @@ export class MemoryRepository {
|
|
|
4
4
|
instances = new Map();
|
|
5
5
|
tasks = new Map();
|
|
6
6
|
actors = new Map();
|
|
7
|
+
ccInstances = new Map();
|
|
7
8
|
seq = 1;
|
|
8
9
|
addDefine(def) {
|
|
9
10
|
if (!def.id)
|
|
@@ -149,8 +150,42 @@ export class MemoryRepository {
|
|
|
149
150
|
const remove = new Set(actors);
|
|
150
151
|
this.actors.set(taskId, (this.actors.get(taskId) ?? []).filter(a => !remove.has(a)));
|
|
151
152
|
}
|
|
152
|
-
async createCcInstance(...
|
|
153
|
-
|
|
153
|
+
async createCcInstance(instanceId, _creator, ...actorIds) {
|
|
154
|
+
const existing = this.ccInstances.get(instanceId) ?? [];
|
|
155
|
+
const seen = new Set(existing);
|
|
156
|
+
for (const a of actorIds) {
|
|
157
|
+
if (!seen.has(a)) {
|
|
158
|
+
existing.push(a);
|
|
159
|
+
seen.add(a);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
this.ccInstances.set(instanceId, existing);
|
|
163
|
+
}
|
|
164
|
+
async updateCcStatus(_instanceId, _actorId) { }
|
|
165
|
+
// pageCcInstances 我的抄送分页(v1.3.0):按抄送人 actorId 过滤,join 实例 + 定义
|
|
166
|
+
async pageCcInstances(pageNum = 1, pageSize = 10, actorId) {
|
|
167
|
+
const rows = [];
|
|
168
|
+
for (const [instId, actors] of this.ccInstances) {
|
|
169
|
+
if (actorId && !actors.includes(actorId))
|
|
170
|
+
continue;
|
|
171
|
+
const inst = this.instances.get(instId);
|
|
172
|
+
if (!inst)
|
|
173
|
+
continue;
|
|
174
|
+
const def = this.defines.get(inst.defineId);
|
|
175
|
+
rows.push({
|
|
176
|
+
id: inst.id, parentId: inst.parentId, defineId: inst.defineId, state: inst.state,
|
|
177
|
+
parentNodeName: inst.parentNodeName, businessNo: inst.businessNo, operator: inst.operator,
|
|
178
|
+
expireTime: inst.expireTime, variables: { ...inst.variables },
|
|
179
|
+
createTime: inst.createTime, createUser: inst.createUser,
|
|
180
|
+
updateTime: inst.updateTime, updateUser: inst.updateUser,
|
|
181
|
+
defineName: def?.name ?? '', defineDisplayName: def?.displayName ?? '',
|
|
182
|
+
defineVersion: def?.version ?? 0,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
const total = rows.length;
|
|
186
|
+
const start = (pageNum - 1) * pageSize;
|
|
187
|
+
return { rows: rows.slice(start, start + pageSize), total };
|
|
188
|
+
}
|
|
154
189
|
allDefines() { return [...this.defines.values()]; }
|
|
155
190
|
allInstances() { return [...this.instances.values()]; }
|
|
156
191
|
allTasks() {
|
package/dist/model.d.ts
CHANGED
|
@@ -168,3 +168,21 @@ export interface UserInfo {
|
|
|
168
168
|
postId?: string;
|
|
169
169
|
postName?: string;
|
|
170
170
|
}
|
|
171
|
+
export interface CcInstanceRow {
|
|
172
|
+
id: number;
|
|
173
|
+
parentId?: number;
|
|
174
|
+
defineId: number;
|
|
175
|
+
state: InstanceState;
|
|
176
|
+
parentNodeName: string;
|
|
177
|
+
businessNo: string;
|
|
178
|
+
operator: string;
|
|
179
|
+
expireTime?: Date;
|
|
180
|
+
variables: Record<string, any>;
|
|
181
|
+
createTime: Date;
|
|
182
|
+
createUser: string;
|
|
183
|
+
updateTime: Date;
|
|
184
|
+
updateUser: string;
|
|
185
|
+
defineName: string;
|
|
186
|
+
defineDisplayName: string;
|
|
187
|
+
defineVersion: number;
|
|
188
|
+
}
|
package/dist/spi.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ProcessDefine, ProcessDesign, ProcessDesignHis, ProcessInstance, ProcessSurrogate, ProcessTask, UserInfo } from './model.js';
|
|
1
|
+
import type { CcInstanceRow, ProcessDefine, ProcessDesign, ProcessDesignHis, ProcessInstance, ProcessSurrogate, ProcessTask, UserInfo } from './model.js';
|
|
2
2
|
export interface ProcessRepository {
|
|
3
3
|
findDefineById(id: number): Promise<ProcessDefine | null>;
|
|
4
4
|
findDefineByName(name: string): Promise<ProcessDefine | null>;
|
|
@@ -20,6 +20,10 @@ export interface ProcessRepository {
|
|
|
20
20
|
removeTaskActor(taskId: number, actors: string[]): Promise<void>;
|
|
21
21
|
createCcInstance(instanceId: number, creator: string, ...actorIds: string[]): Promise<void>;
|
|
22
22
|
updateCcStatus(instanceId: number, actorId: string): Promise<void>;
|
|
23
|
+
pageCcInstances(pageNum: number, pageSize: number, actorId: string): Promise<{
|
|
24
|
+
rows: CcInstanceRow[];
|
|
25
|
+
total: number;
|
|
26
|
+
}>;
|
|
23
27
|
}
|
|
24
28
|
export interface UserProvider {
|
|
25
29
|
getUser(userId: string): Promise<UserInfo | null>;
|
package/package.json
CHANGED
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@mldong/jeeflow",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "jeeflow workflow engine — Node.js / TypeScript implementation",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "./dist/index.js",
|
|
7
|
-
"types": "./dist/index.d.ts",
|
|
8
|
-
"exports": {
|
|
9
|
-
".": "./dist/index.js",
|
|
10
|
-
"./engine": "./dist/engine.js",
|
|
11
|
-
"./model": "./dist/model.js",
|
|
12
|
-
"./spi": "./dist/spi.js",
|
|
13
|
-
"./memory": "./dist/memory.js",
|
|
14
|
-
"./jdbc": "./dist/jdbc/index.js",
|
|
15
|
-
"./mysql": "./dist/jdbc/mysql.js",
|
|
16
|
-
"./postgres": "./dist/jdbc/postgres.js"
|
|
17
|
-
},
|
|
18
|
-
"scripts": {
|
|
19
|
-
"build": "tsc",
|
|
20
|
-
"test": "node --import tsx __tests__/spec.test.ts",
|
|
21
|
-
"demo": "node --import tsx demo/main.ts",
|
|
22
|
-
"prepublishOnly": "npm run build"
|
|
23
|
-
},
|
|
24
|
-
"keywords": [
|
|
25
|
-
"workflow",
|
|
26
|
-
"engine",
|
|
27
|
-
"jeeflow",
|
|
28
|
-
"typescript"
|
|
29
|
-
],
|
|
30
|
-
"license": "Apache-2.0",
|
|
31
|
-
"devDependencies": {
|
|
32
|
-
"@types/pg": "^8.20.3",
|
|
33
|
-
"tsx": "^4.19.0",
|
|
34
|
-
"typescript": "^5.5.0"
|
|
35
|
-
},
|
|
36
|
-
"optionalDependencies": {
|
|
37
|
-
"mysql2": "^3.11.0",
|
|
38
|
-
"pg": "^8.13.0"
|
|
39
|
-
},
|
|
40
|
-
"files": [
|
|
41
|
-
"dist",
|
|
42
|
-
"LICENSE",
|
|
43
|
-
"README.md"
|
|
44
|
-
]
|
|
45
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@mldong/jeeflow",
|
|
3
|
+
"version": "1.3.0",
|
|
4
|
+
"description": "jeeflow workflow engine — Node.js / TypeScript implementation",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./dist/index.js",
|
|
10
|
+
"./engine": "./dist/engine.js",
|
|
11
|
+
"./model": "./dist/model.js",
|
|
12
|
+
"./spi": "./dist/spi.js",
|
|
13
|
+
"./memory": "./dist/memory.js",
|
|
14
|
+
"./jdbc": "./dist/jdbc/index.js",
|
|
15
|
+
"./mysql": "./dist/jdbc/mysql.js",
|
|
16
|
+
"./postgres": "./dist/jdbc/postgres.js"
|
|
17
|
+
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc",
|
|
20
|
+
"test": "node --import tsx __tests__/spec.test.ts",
|
|
21
|
+
"demo": "node --import tsx demo/main.ts",
|
|
22
|
+
"prepublishOnly": "npm run build"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"workflow",
|
|
26
|
+
"engine",
|
|
27
|
+
"jeeflow",
|
|
28
|
+
"typescript"
|
|
29
|
+
],
|
|
30
|
+
"license": "Apache-2.0",
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/pg": "^8.20.3",
|
|
33
|
+
"tsx": "^4.19.0",
|
|
34
|
+
"typescript": "^5.5.0"
|
|
35
|
+
},
|
|
36
|
+
"optionalDependencies": {
|
|
37
|
+
"mysql2": "^3.11.0",
|
|
38
|
+
"pg": "^8.13.0"
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"dist",
|
|
42
|
+
"LICENSE",
|
|
43
|
+
"README.md"
|
|
44
|
+
]
|
|
45
|
+
}
|