@mldong/jeeflow 1.0.0 → 1.2.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.js ADDED
@@ -0,0 +1,582 @@
1
+ // 统一门面(v1.1.0)——"接口即 POST + JSON body"风格的单入口
2
+ //
3
+ // 集成方只实现一个转发端点:把 body JSON 转成对象传入 flow(),所有流程能力按
4
+ // action(boot2/boot3 端点短名)路由。返回统一结构 {code, msg, data}
5
+ // (code=0 成功 / 99999999 失败)。操作人约定:args.operator 显式传入。
6
+ // submitType 枚举(对齐 boot3)
7
+ const SUBMIT_APPLY = 0;
8
+ const SUBMIT_AGREE = 1;
9
+ const SUBMIT_REJECT = 2;
10
+ const SUBMIT_ROLLBACK = 3;
11
+ const SUBMIT_JUMP = 4;
12
+ const SUBMIT_ROLLBACK_TO_OPERATOR = 6;
13
+ const SUBMIT_COUNTERSIGN_DISAGREE = 20;
14
+ export class JeeflowFacade {
15
+ engine;
16
+ repo;
17
+ extRepo;
18
+ userSearch;
19
+ constructor(engine, repo, extRepo) {
20
+ this.engine = engine;
21
+ this.repo = repo;
22
+ this.extRepo = extRepo;
23
+ }
24
+ // 注入用户搜索钩子(candidatePage 无模型候选时的用户分页搜索)
25
+ setUserSearch(fn) {
26
+ this.userSearch = fn;
27
+ return this;
28
+ }
29
+ async flow(action, args = {}) {
30
+ try {
31
+ const data = await this.dispatch(action, args);
32
+ return { code: 0, msg: '成功', data: data ?? null };
33
+ }
34
+ catch (e) {
35
+ return { code: 99999999, msg: e?.message ?? String(e) };
36
+ }
37
+ }
38
+ async dispatch(action, args) {
39
+ switch (action) {
40
+ case 'processDefine/startAndExecute':
41
+ case 'processInstance/startAndExecute':
42
+ return this.startAndExecute(args);
43
+ case 'processDefine/deploy':
44
+ case 'processDesign/deploy':
45
+ return this.deploy(args, action === 'processDesign/deploy');
46
+ case 'processDefine/redeploy':
47
+ return this.redeploy(args);
48
+ case 'processDefine/remove':
49
+ return this.repo.removeDefine(toId(args.id));
50
+ case 'processDefine/upAndDown':
51
+ return this.repo.updateDefineState(toId(args.id), toInt(args.state));
52
+ case 'processInstance/withdraw':
53
+ return this.withdraw(args);
54
+ case 'processTask/execute':
55
+ return this.execute(args);
56
+ case 'processDesign/page':
57
+ return this.designPage(args);
58
+ case 'processDesign/detail':
59
+ return this.designDetail(args);
60
+ case 'processDesign/save':
61
+ return this.designSave(args);
62
+ case 'processDesign/remove':
63
+ return this.ext().removeDesign(toId(args.id));
64
+ case 'processSurrogate/page':
65
+ return this.surrogatePage(args);
66
+ case 'processSurrogate/save':
67
+ return this.surrogateSave(args);
68
+ case 'processSurrogate/remove':
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
+ throw new Error('ccList 需要核心分页 SPI(pageCcInstances),当前语言 1.3.0 补齐');
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);
95
+ default:
96
+ throw new Error(`未知 action: ${action}`);
97
+ }
98
+ }
99
+ // ── 流程定义 / 实例 ──────────────────────────────────────────────────────
100
+ async startAndExecute(args) {
101
+ const defineId = toId(args.processDefineId);
102
+ const operator = String(args.operator ?? 'user1');
103
+ const flowArgs = {};
104
+ for (const [k, v] of Object.entries(args)) {
105
+ if (k === 'processDefineId' || k === 'operator')
106
+ continue;
107
+ flowArgs[k] = v;
108
+ }
109
+ const inst = await this.engine.startProcessInstanceById(defineId, operator, flowArgs);
110
+ // startAndExecute:自动完成申请节点(assignee="applicant" → 发起人)
111
+ const doing = await this.repo.findDoingTasks(inst.id);
112
+ for (const task of doing) {
113
+ await this.repo.addTaskActor(task.id, [operator]);
114
+ flowArgs.submitType = SUBMIT_APPLY;
115
+ await this.engine.executeProcessTask(task.id, operator, flowArgs);
116
+ }
117
+ return { processInstanceId: inst.id };
118
+ }
119
+ // deploy 版本管理(对齐 boot3):按 name 查最新定义,存在 version+1 插新记录,否则从 0 起
120
+ async deploy(args, fromDesign) {
121
+ let content;
122
+ if (fromDesign) {
123
+ const designId = toId(args.id);
124
+ const ext = this.ext();
125
+ const design = await ext.findDesignById(designId);
126
+ if (!design)
127
+ throw new Error('流程设计不存在');
128
+ const hisList = await ext.listDesignHis(designId);
129
+ if (hisList.length === 0)
130
+ throw new Error('流程设计没有内容,无法发布');
131
+ content = toStr(hisList[0].content);
132
+ const defineId = await this.saveDeployedDefine(content, args);
133
+ design.isDeployed = 1;
134
+ design.updateUser = String(args.operator ?? 'system');
135
+ await ext.updateDesign(design);
136
+ return { processDefineId: defineId };
137
+ }
138
+ content = toStr(args.content);
139
+ const defineId = await this.saveDeployedDefine(content, args);
140
+ return { processDefineId: defineId };
141
+ }
142
+ async saveDeployedDefine(content, args) {
143
+ let flow;
144
+ try {
145
+ flow = JSON.parse(content);
146
+ }
147
+ catch {
148
+ throw new Error('流程定义 JSON 解析失败');
149
+ }
150
+ const name = flow?.name;
151
+ if (!name)
152
+ throw new Error('流程定义缺少 name');
153
+ let version = 0;
154
+ const latest = await this.repo.findDefineByName(name);
155
+ if (latest)
156
+ version = (latest.version ?? 0) + 1;
157
+ const operator = String(args.operator ?? 'system');
158
+ const def = {
159
+ id: 0, name, displayName: flow.displayName ?? '', type: flow.type ?? 'approval',
160
+ state: 1, content, version, createTime: new Date(), createUser: operator,
161
+ updateTime: new Date(), updateUser: operator,
162
+ };
163
+ await this.repo.saveDefine(def);
164
+ return def.id;
165
+ }
166
+ async redeploy(args) {
167
+ const defineId = toId(args.processDefineId);
168
+ const content = toStr(args.content);
169
+ let flow;
170
+ try {
171
+ flow = JSON.parse(content);
172
+ }
173
+ catch {
174
+ throw new Error('流程定义 JSON 解析失败');
175
+ }
176
+ await this.repo.updateDefine({
177
+ id: defineId, name: flow?.name ?? '', displayName: flow?.displayName ?? '',
178
+ type: flow?.type ?? 'approval', state: 1, content, version: 0,
179
+ createTime: new Date(), createUser: '', updateTime: new Date(),
180
+ updateUser: String(args.operator ?? 'system'),
181
+ });
182
+ }
183
+ async withdraw(args) {
184
+ const instanceId = toId(args.id);
185
+ const inst = await this.repo.findInstanceById(instanceId);
186
+ if (!inst)
187
+ throw new Error('流程实例不存在');
188
+ // 撤回:废弃全部 doing 任务 + 实例状态(v1.0.1:updateInstance 级联落库)
189
+ const operator = String(args.operator ?? 'user1');
190
+ const now = new Date();
191
+ const abandoned = inst.abandonAllDoing(now);
192
+ inst.reject(now);
193
+ inst.updateUser = operator;
194
+ for (const t of abandoned)
195
+ await this.repo.updateTask(t);
196
+ await this.repo.updateInstance(inst);
197
+ }
198
+ // ── 流程任务 ─────────────────────────────────────────────────────────────
199
+ async execute(args) {
200
+ const taskId = toId(args.processTaskId);
201
+ const operator = String(args.operator ?? 'user1');
202
+ const submitType = toInt(args.submitType ?? SUBMIT_AGREE);
203
+ const flowArgs = {};
204
+ for (const [k, v] of Object.entries(args)) {
205
+ if (k === 'processTaskId' || k === 'operator')
206
+ continue;
207
+ flowArgs[k] = v;
208
+ }
209
+ flowArgs.submitType = submitType;
210
+ // boot3 execute 分发(spec §11.2)
211
+ switch (submitType) {
212
+ case SUBMIT_REJECT:
213
+ await this.engine.executeAndJumpToEnd(taskId, operator, flowArgs);
214
+ break;
215
+ case SUBMIT_ROLLBACK:
216
+ await this.engine.executeAndJumpTask(taskId, operator, flowArgs, '');
217
+ break;
218
+ case SUBMIT_JUMP:
219
+ await this.engine.executeAndJumpTask(taskId, operator, flowArgs, String(args.taskName ?? ''));
220
+ break;
221
+ case SUBMIT_ROLLBACK_TO_OPERATOR:
222
+ await this.engine.executeAndJumpToFirstTaskNode(taskId, operator, flowArgs);
223
+ break;
224
+ case SUBMIT_COUNTERSIGN_DISAGREE:
225
+ flowArgs.countersignDisagreeFlag = 1;
226
+ await this.engine.executeProcessTask(taskId, operator, flowArgs);
227
+ break;
228
+ default: // 0 APPLY / 1 AGREE / 5 重新提交
229
+ await this.engine.executeProcessTask(taskId, operator, flowArgs);
230
+ }
231
+ }
232
+ // ── 流程设计(需扩展仓储) ───────────────────────────────────────────────
233
+ async designPage(args) {
234
+ const [rows, total] = await this.ext().pageDesigns(toInt(args.pageNum ?? 1), toInt(args.pageSize ?? 10));
235
+ return { rows, recordCount: total };
236
+ }
237
+ async designDetail(args) {
238
+ const ext = this.ext();
239
+ const design = await ext.findDesignById(toId(args.id));
240
+ if (!design)
241
+ throw new Error('流程设计不存在');
242
+ const data = {
243
+ id: design.id, name: design.name, displayName: design.displayName,
244
+ type: design.type, icon: design.icon, isDeployed: design.isDeployed, remark: design.remark,
245
+ };
246
+ const hisList = await ext.listDesignHis(design.id);
247
+ if (hisList.length > 0) {
248
+ try {
249
+ data.jsonObject = JSON.parse(toStr(hisList[0].content));
250
+ }
251
+ catch { /* ignore */ }
252
+ }
253
+ data.his = hisList;
254
+ return data;
255
+ }
256
+ async designSave(args) {
257
+ const ext = this.ext();
258
+ const operator = String(args.operator ?? 'user1');
259
+ const designId = args.id != null ? toId(args.id) : 0;
260
+ let design;
261
+ if (!designId) {
262
+ design = {
263
+ id: 0, name: String(args.name ?? ''), displayName: String(args.displayName ?? ''),
264
+ type: String(args.type ?? 'approval'), icon: String(args.icon ?? ''),
265
+ isDeployed: 0, remark: String(args.remark ?? ''),
266
+ createTime: new Date(), createUser: operator,
267
+ updateTime: new Date(), updateUser: operator,
268
+ };
269
+ await ext.saveDesign(design);
270
+ }
271
+ else {
272
+ const found = await ext.findDesignById(designId);
273
+ if (!found)
274
+ throw new Error('流程设计不存在');
275
+ if (args.displayName != null)
276
+ found.displayName = String(args.displayName);
277
+ if (args.type != null)
278
+ found.type = String(args.type);
279
+ if (args.icon != null)
280
+ found.icon = String(args.icon);
281
+ if (args.remark != null)
282
+ found.remark = String(args.remark);
283
+ found.updateUser = operator;
284
+ await ext.updateDesign(found);
285
+ design = found;
286
+ }
287
+ // 内容快照(设计稿内容存历史表)
288
+ if (args.content != null) {
289
+ await ext.saveDesignHis({
290
+ id: 0, processDesignId: design.id, content: String(args.content),
291
+ createTime: new Date(), createUser: operator,
292
+ });
293
+ }
294
+ return { id: design.id };
295
+ }
296
+ // ── 委托代理(需扩展仓储) ───────────────────────────────────────────────
297
+ async surrogatePage(args) {
298
+ 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);
300
+ return { rows, recordCount: total };
301
+ }
302
+ async surrogateSave(args) {
303
+ const ext = this.ext();
304
+ const operator = String(args.operator ?? 'user1');
305
+ const surrogateId = args.id != null ? toId(args.id) : 0;
306
+ let surrogate;
307
+ if (!surrogateId) {
308
+ surrogate = {
309
+ id: 0, operator, // 授权人 = 操作人
310
+ surrogate: String(args.surrogate ?? ''), processName: String(args.processName ?? ''),
311
+ enabled: toInt(args.enabled ?? 1),
312
+ createTime: new Date(), createUser: operator,
313
+ updateTime: new Date(), updateUser: operator,
314
+ };
315
+ await ext.saveSurrogate(surrogate);
316
+ }
317
+ else {
318
+ const found = await ext.findSurrogateById(surrogateId);
319
+ if (!found)
320
+ throw new Error('委托记录不存在');
321
+ if (args.surrogate != null)
322
+ found.surrogate = String(args.surrogate);
323
+ if (args.processName != null)
324
+ found.processName = String(args.processName);
325
+ if (args.enabled != null)
326
+ found.enabled = toInt(args.enabled);
327
+ found.updateUser = operator;
328
+ await ext.updateSurrogate(found);
329
+ surrogate = found;
330
+ }
331
+ return { id: surrogate.id };
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
+ async taskDetail(args) {
423
+ const taskId = toId(args.id);
424
+ const operator = String(args.operator ?? 'user1');
425
+ const task = await this.repo.findTaskById(taskId);
426
+ if (!task)
427
+ throw new Error('任务不存在');
428
+ const actors = await this.repo.findTaskActors(taskId);
429
+ const vo = {
430
+ id: task.id, processInstanceId: task.processInstanceId, taskName: task.taskName,
431
+ displayName: task.displayName, taskType: task.taskType ?? null,
432
+ performType: task.performType ?? null, taskState: task.taskState,
433
+ operator: task.actorId ?? '', formKey: task.formKey ?? '',
434
+ taskActorIdList: actors, executable: task.isAllowed(operator),
435
+ };
436
+ // taskModel:流程定义中对应节点
437
+ const inst = await this.repo.findInstanceById(task.processInstanceId);
438
+ if (inst) {
439
+ const def = await this.repo.findDefineById(inst.defineId);
440
+ if (def) {
441
+ try {
442
+ const flow = JSON.parse(toStr(def.content));
443
+ for (const n of flow.nodes ?? []) {
444
+ if (n.id === task.taskName) {
445
+ vo.taskModel = { name: n.id, displayName: n.text?.value ?? '', type: n.type };
446
+ break;
447
+ }
448
+ }
449
+ }
450
+ catch { /* ignore */ }
451
+ }
452
+ }
453
+ return vo;
454
+ }
455
+ async jumpAbleTaskNameList(args) {
456
+ const instanceId = toId(args.processInstanceId);
457
+ const done = await this.repo.findDoneTasks(instanceId);
458
+ const rows = [];
459
+ const seen = new Set();
460
+ for (const t of done) {
461
+ if ((t.performType ?? 0) === 1)
462
+ continue; // COUNTERSIGN
463
+ if (!seen.has(t.taskName)) {
464
+ seen.add(t.taskName);
465
+ rows.push({ label: t.displayName, value: t.taskName });
466
+ }
467
+ }
468
+ return rows;
469
+ }
470
+ async candidatePage(args) {
471
+ const taskId = toId(args.processTaskId ?? args.id);
472
+ const task = await this.repo.findTaskById(taskId);
473
+ if (!task)
474
+ throw new Error('任务不存在');
475
+ const inst = await this.repo.findInstanceById(task.processInstanceId);
476
+ if (!inst)
477
+ throw new Error('流程实例不存在');
478
+ // 模型候选解析:后继任务节点的 candidateUsers 配置
479
+ let candidates = [];
480
+ const def = await this.repo.findDefineById(inst.defineId);
481
+ if (def) {
482
+ try {
483
+ const flow = JSON.parse(toStr(def.content));
484
+ candidates = this.nextTaskCandidates(flow, task.taskName);
485
+ }
486
+ catch { /* ignore */ }
487
+ }
488
+ if (candidates.length > 0) {
489
+ const rows = candidates.map(c => ({ userId: c, realName: c }));
490
+ return { rows, recordCount: rows.length };
491
+ }
492
+ // 无模型候选 → 用户分页搜索(依赖 userSearch 钩子)
493
+ if (!this.userSearch)
494
+ throw new Error('未配置 userSearch(用户搜索钩子)');
495
+ const [rows, total] = await this.userSearch(args);
496
+ return { rows, recordCount: total };
497
+ }
498
+ nextTaskCandidates(flow, taskName) {
499
+ const result = [];
500
+ const visited = new Set();
501
+ const collect = (node) => {
502
+ const v = node.properties?.candidateUsers;
503
+ if (v) {
504
+ for (const s of String(v).split(',')) {
505
+ const t = s.trim();
506
+ if (t && !result.includes(t))
507
+ result.push(t);
508
+ }
509
+ }
510
+ };
511
+ const walk = (nodeId) => {
512
+ if (visited.has(nodeId))
513
+ return;
514
+ visited.add(nodeId);
515
+ for (const e of flow.edges ?? []) {
516
+ if (e.sourceNodeId !== nodeId)
517
+ continue;
518
+ const target = (flow.nodes ?? []).find((n) => n.id === e.targetNodeId);
519
+ if (!target)
520
+ continue;
521
+ if (target.type === 'snaker:task' || target.type === 'snaker:custom') {
522
+ collect(target);
523
+ continue;
524
+ }
525
+ if (['snaker:fork', 'snaker:join', 'snaker:decision'].includes(target.type)) {
526
+ walk(target.id);
527
+ }
528
+ }
529
+ };
530
+ walk(taskName);
531
+ return result;
532
+ }
533
+ async taskAddActor(args) {
534
+ const taskId = toId(args.processTaskId);
535
+ const actors = toStringList2(args.actorIds);
536
+ if (actors.length === 0)
537
+ throw new Error('actorIds 缺失');
538
+ await this.repo.addTaskActor(taskId, actors);
539
+ }
540
+ async taskLatest(args) {
541
+ const instanceId = toId(args.processInstanceId);
542
+ const doing = await this.repo.findDoingTasks(instanceId);
543
+ if (doing.length === 0)
544
+ return null;
545
+ const t = doing[0];
546
+ return { id: t.id, taskName: t.taskName, displayName: t.displayName, taskState: t.taskState, operator: t.actorId ?? '' };
547
+ }
548
+ ext() {
549
+ if (!this.extRepo)
550
+ throw new Error('未配置 ProcessExtRepository(扩展仓储)');
551
+ return this.extRepo;
552
+ }
553
+ }
554
+ // ── 工具 ──────────────────────────────────────────────────────────────────────
555
+ function toStr(v) {
556
+ if (v == null)
557
+ return '';
558
+ if (typeof v === 'string')
559
+ return v;
560
+ if (v instanceof Uint8Array || Buffer.isBuffer(v))
561
+ return Buffer.from(v).toString('utf8');
562
+ return String(v);
563
+ }
564
+ function toId(v) {
565
+ const n = Number(v);
566
+ if (!Number.isFinite(n) || n <= 0)
567
+ throw new Error('id 缺失或非法');
568
+ return n;
569
+ }
570
+ function toStringList2(v) {
571
+ if (Array.isArray(v))
572
+ return v.map(String);
573
+ if (typeof v === 'string')
574
+ return v.split(',').map(s => s.trim()).filter(Boolean);
575
+ return [];
576
+ }
577
+ function toInt(v) {
578
+ const n = Number(v);
579
+ if (!Number.isFinite(n))
580
+ throw new Error('数值缺失或非法');
581
+ return n;
582
+ }
@@ -0,0 +1,29 @@
1
+ import { ProcessDesign, ProcessDesignHis, ProcessSurrogate } from '../model.js';
2
+ import type { IDGenerator, ProcessExtRepository } from '../spi.js';
3
+ import { type SqlAdapter } from './shared.js';
4
+ export declare class JdbcProcessExtRepository implements ProcessExtRepository {
5
+ private readonly adapter;
6
+ private readonly idGen;
7
+ constructor(adapter: SqlAdapter, idGen?: IDGenerator);
8
+ private sql;
9
+ private c;
10
+ private done;
11
+ private static DESIGN_COLS;
12
+ findDesignById(id: number): Promise<ProcessDesign | null>;
13
+ saveDesign(d: ProcessDesign): Promise<void>;
14
+ updateDesign(d: ProcessDesign): Promise<void>;
15
+ removeDesign(id: number): Promise<void>;
16
+ pageDesigns(pageNum?: number, pageSize?: number, filters?: Record<string, any>): Promise<[ProcessDesign[], number]>;
17
+ saveDesignHis(his: ProcessDesignHis): Promise<void>;
18
+ listDesignHis(designId: number): Promise<ProcessDesignHis[]>;
19
+ private static SURROGATE_COLS;
20
+ findSurrogateById(id: number): Promise<ProcessSurrogate | null>;
21
+ saveSurrogate(s: ProcessSurrogate): Promise<void>;
22
+ updateSurrogate(s: ProcessSurrogate): Promise<void>;
23
+ removeSurrogate(id: number): Promise<void>;
24
+ pageSurrogates(pageNum?: number, pageSize?: number, filters?: Record<string, any>): Promise<[ProcessSurrogate[], number]>;
25
+ getSurrogate(operator: string, processName: string, at?: Date): Promise<ProcessSurrogate | null>;
26
+ private querySurrogate;
27
+ private mapDesign;
28
+ private mapSurrogate;
29
+ }