@mldong/jeeflow 1.5.1 → 1.6.1

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.
@@ -0,0 +1,59 @@
1
+ import type { FlowNode, ProcessInstance } from './model.js';
2
+ import type { IAssignmentHandler } from './registry.js';
3
+ import type { OrgUserProvider, UserProvider } from './spi.js';
4
+ export declare const HANDLER_OPERATOR_ASSIGNMENT = "com.mldong.jeeflow.interceptor.impl.OperatorAssignmentHandler";
5
+ export declare const HANDLER_FORM_FIELD_ASSIGNEE = "com.mldong.jeeflow.interceptor.impl.FormFieldAssigneeHandler";
6
+ export declare const HANDLER_DEPT_LEADER: string;
7
+ export declare const HANDLER_DEPT_MAIN_LEADER: string;
8
+ export declare const HANDLER_APPLICANT_DEPT_LEADER: string;
9
+ export declare const HANDLER_APPLICANT_DEPT_MAIN_LEADER: string;
10
+ export declare const HANDLER_TASK_ROLE_ASSIGNEE: string;
11
+ /** 流程发起人(兜底 "apply.operator") */
12
+ export declare class OperatorAssignmentHandler implements IAssignmentHandler {
13
+ assign(_node: FlowNode, inst: ProcessInstance | null, _operator: string): Promise<string[]>;
14
+ }
15
+ /** 按表单字段值分配参与者:精确匹配 node.id → vars 字段;_数字 后缀去后缀再匹配。 */
16
+ export declare class FormFieldAssigneeHandler implements IAssignmentHandler {
17
+ assign(node: FlowNode, inst: ProcessInstance | null, _operator: string): Promise<string[]>;
18
+ private findFieldValue;
19
+ private collect;
20
+ private add;
21
+ }
22
+ /** 组织维度 handler 公共依赖 */
23
+ declare class OrgBase {
24
+ protected userProv?: UserProvider | undefined;
25
+ protected orgProv?: OrgUserProvider | undefined;
26
+ constructor(userProv?: UserProvider | undefined, orgProv?: OrgUserProvider | undefined);
27
+ protected byDept(deptId: string, main: boolean): Promise<string[]>;
28
+ protected deptIdOf(userId: string): Promise<string>;
29
+ }
30
+ /** 当前用户(任务操作人)部门领导 */
31
+ export declare class DeptLeaderAssignmentHandler extends OrgBase implements IAssignmentHandler {
32
+ assign(_node: FlowNode, _inst: ProcessInstance | null, operator: string): Promise<string[]>;
33
+ }
34
+ /** 当前用户(任务操作人)部门分管领导 */
35
+ export declare class DeptMainLeaderAssignmentHandler extends OrgBase implements IAssignmentHandler {
36
+ assign(_node: FlowNode, _inst: ProcessInstance | null, operator: string): Promise<string[]>;
37
+ }
38
+ /** 发起人部门领导 */
39
+ export declare class ApplicantDeptLeaderAssignmentHandler extends OrgBase implements IAssignmentHandler {
40
+ assign(_node: FlowNode, inst: ProcessInstance | null, _operator: string): Promise<string[]>;
41
+ }
42
+ /** 发起人部门分管领导 */
43
+ export declare class ApplicantDeptMainLeaderAssignmentHandler extends OrgBase implements IAssignmentHandler {
44
+ assign(_node: FlowNode, inst: ProcessInstance | null, _operator: string): Promise<string[]>;
45
+ }
46
+ /** 任务节点唯一编码关联角色(roleCode = 节点 id) */
47
+ export declare class TaskRoleAssigneeHandler implements IAssignmentHandler {
48
+ private orgProv?;
49
+ constructor(orgProv?: OrgUserProvider | undefined);
50
+ assign(node: FlowNode, _inst: ProcessInstance | null, _operator: string): Promise<string[]>;
51
+ }
52
+ /**
53
+ * 注册内置通用参与者处理器到注册表(组织维度 handler 依赖 userProv/orgProv)。
54
+ * 与 HandlerRegistry.registerAssignment 组合使用。
55
+ */
56
+ export declare function registerBuiltinAssignments(reg: {
57
+ registerAssignment(name: string, handler: IAssignmentHandler): void;
58
+ }, userProv?: UserProvider, orgProv?: OrgUserProvider): void;
59
+ export {};
@@ -0,0 +1,135 @@
1
+ // ─── 内置通用参与者处理器(issues/16)───────────────────────────────────────────
2
+ // 注册名与 Java 类全限定名一致,跨语言流程 JSON 通用(前端设计器配置天然兼容)。
3
+ // OperatorAssignmentHandler / FormFieldAssigneeHandler 为纯引擎语义,零外部依赖;
4
+ // 组织维度 handler 通过 OrgUserProvider SPI 取数据,业务方只实现数据接口。
5
+ export const HANDLER_OPERATOR_ASSIGNMENT = 'com.mldong.jeeflow.interceptor.impl.OperatorAssignmentHandler';
6
+ export const HANDLER_FORM_FIELD_ASSIGNEE = 'com.mldong.jeeflow.interceptor.impl.FormFieldAssigneeHandler';
7
+ const ORG_HANDLERS_PREFIX = 'com.mldong.jeeflow.interceptor.impl.OrgUserAssignmentHandlers$';
8
+ export const HANDLER_DEPT_LEADER = ORG_HANDLERS_PREFIX + 'DeptLeaderAssignmentHandler';
9
+ export const HANDLER_DEPT_MAIN_LEADER = ORG_HANDLERS_PREFIX + 'DeptMainLeaderAssignmentHandler';
10
+ export const HANDLER_APPLICANT_DEPT_LEADER = ORG_HANDLERS_PREFIX + 'ApplicantDeptLeaderAssignmentHandler';
11
+ export const HANDLER_APPLICANT_DEPT_MAIN_LEADER = ORG_HANDLERS_PREFIX + 'ApplicantDeptMainLeaderAssignmentHandler';
12
+ export const HANDLER_TASK_ROLE_ASSIGNEE = ORG_HANDLERS_PREFIX + 'TaskRoleAssigneeHandler';
13
+ // 表单字段编号后缀正则(task_01 → task)
14
+ const NUMBER_SUFFIX_PATTERN = /^(.+?)_(\d+)$/;
15
+ // ─── 纯引擎语义 ────────────────────────────────────────────────────────────────
16
+ /** 流程发起人(兜底 "apply.operator") */
17
+ export class OperatorAssignmentHandler {
18
+ async assign(_node, inst, _operator) {
19
+ if (inst?.operator)
20
+ return [inst.operator];
21
+ return ['apply.operator'];
22
+ }
23
+ }
24
+ /** 按表单字段值分配参与者:精确匹配 node.id → vars 字段;_数字 后缀去后缀再匹配。 */
25
+ export class FormFieldAssigneeHandler {
26
+ async assign(node, inst, _operator) {
27
+ if (!inst || !node)
28
+ return [];
29
+ const value = this.findFieldValue(inst.variables, node.id);
30
+ if (value == null)
31
+ return [];
32
+ return this.collect(value);
33
+ }
34
+ findFieldValue(variables, fieldName) {
35
+ if (fieldName in variables)
36
+ return variables[fieldName];
37
+ const m = NUMBER_SUFFIX_PATTERN.exec(fieldName);
38
+ if (m && m[1] in variables)
39
+ return variables[m[1]];
40
+ return null;
41
+ }
42
+ collect(value) {
43
+ const ids = [];
44
+ if (Array.isArray(value)) {
45
+ for (const item of value)
46
+ this.add(ids, String(item));
47
+ }
48
+ else {
49
+ this.add(ids, String(value));
50
+ }
51
+ return ids;
52
+ }
53
+ add(ids, token) {
54
+ for (const s of token.split(',')) {
55
+ const t = s.trim();
56
+ if (t && !ids.includes(t))
57
+ ids.push(t);
58
+ }
59
+ }
60
+ }
61
+ // ─── 组织维度(OrgUserProvider SPI)───────────────────────────────────────────
62
+ /** 组织维度 handler 公共依赖 */
63
+ class OrgBase {
64
+ userProv;
65
+ orgProv;
66
+ constructor(userProv, orgProv) {
67
+ this.userProv = userProv;
68
+ this.orgProv = orgProv;
69
+ }
70
+ async byDept(deptId, main) {
71
+ if (!deptId || !this.orgProv)
72
+ return [];
73
+ return main ? await this.orgProv.findDeptMainLeaders(deptId) ?? [] : await this.orgProv.findDeptLeaders(deptId) ?? [];
74
+ }
75
+ async deptIdOf(userId) {
76
+ if (!userId || !this.userProv)
77
+ return '';
78
+ const u = await this.userProv.getUser(userId);
79
+ return u?.deptId ?? '';
80
+ }
81
+ }
82
+ /** 当前用户(任务操作人)部门领导 */
83
+ export class DeptLeaderAssignmentHandler extends OrgBase {
84
+ async assign(_node, _inst, operator) {
85
+ return this.byDept(await this.deptIdOf(operator), false);
86
+ }
87
+ }
88
+ /** 当前用户(任务操作人)部门分管领导 */
89
+ export class DeptMainLeaderAssignmentHandler extends OrgBase {
90
+ async assign(_node, _inst, operator) {
91
+ return this.byDept(await this.deptIdOf(operator), true);
92
+ }
93
+ }
94
+ /** 发起人部门领导 */
95
+ export class ApplicantDeptLeaderAssignmentHandler extends OrgBase {
96
+ async assign(_node, inst, _operator) {
97
+ if (!inst)
98
+ return [];
99
+ return this.byDept(await this.deptIdOf(inst.operator), false);
100
+ }
101
+ }
102
+ /** 发起人部门分管领导 */
103
+ export class ApplicantDeptMainLeaderAssignmentHandler extends OrgBase {
104
+ async assign(_node, inst, _operator) {
105
+ if (!inst)
106
+ return [];
107
+ return this.byDept(await this.deptIdOf(inst.operator), true);
108
+ }
109
+ }
110
+ /** 任务节点唯一编码关联角色(roleCode = 节点 id) */
111
+ export class TaskRoleAssigneeHandler {
112
+ orgProv;
113
+ constructor(orgProv) {
114
+ this.orgProv = orgProv;
115
+ }
116
+ async assign(node, _inst, _operator) {
117
+ if (!node || !this.orgProv)
118
+ return [];
119
+ return await this.orgProv.findByRole(node.id) ?? [];
120
+ }
121
+ }
122
+ // ─── 注册 ──────────────────────────────────────────────────────────────────────
123
+ /**
124
+ * 注册内置通用参与者处理器到注册表(组织维度 handler 依赖 userProv/orgProv)。
125
+ * 与 HandlerRegistry.registerAssignment 组合使用。
126
+ */
127
+ export function registerBuiltinAssignments(reg, userProv, orgProv) {
128
+ reg.registerAssignment(HANDLER_OPERATOR_ASSIGNMENT, new OperatorAssignmentHandler());
129
+ reg.registerAssignment(HANDLER_FORM_FIELD_ASSIGNEE, new FormFieldAssigneeHandler());
130
+ reg.registerAssignment(HANDLER_DEPT_LEADER, new DeptLeaderAssignmentHandler(userProv, orgProv));
131
+ reg.registerAssignment(HANDLER_DEPT_MAIN_LEADER, new DeptMainLeaderAssignmentHandler(userProv, orgProv));
132
+ reg.registerAssignment(HANDLER_APPLICANT_DEPT_LEADER, new ApplicantDeptLeaderAssignmentHandler(userProv, orgProv));
133
+ reg.registerAssignment(HANDLER_APPLICANT_DEPT_MAIN_LEADER, new ApplicantDeptMainLeaderAssignmentHandler(userProv, orgProv));
134
+ reg.registerAssignment(HANDLER_TASK_ROLE_ASSIGNEE, new TaskRoleAssigneeHandler(orgProv));
135
+ }
package/dist/engine.d.ts CHANGED
@@ -11,6 +11,7 @@ export declare const KeyDeptName = "u_deptName";
11
11
  export declare const KeyPostID = "u_postId";
12
12
  export declare const KeyPostName = "u_postName";
13
13
  export declare const KeyNextNodeOperator = "tf_nextNodeOperator";
14
+ export declare const KeyProcessStartNextNodeOperator = "f_nextNodeOperator";
14
15
  export declare const KeyAutoExecute = "flow.auto";
15
16
  export declare const KeyAdminID = "flow.admin";
16
17
  export interface Engine {
package/dist/engine.js CHANGED
@@ -10,6 +10,8 @@ export const KeyPostID = 'u_postId';
10
10
  export const KeyPostName = 'u_postName';
11
11
  // v1.0.1:下一节点处理人(对齐 boot3 tf_nextNodeOperator)
12
12
  export const KeyNextNodeOperator = 'tf_nextNodeOperator';
13
+ // v1.6.0:流程启动时预指派人(对齐 boot3 f_nextNodeOperator)——startAndExecute 时转换为 tf_
14
+ export const KeyProcessStartNextNodeOperator = 'f_nextNodeOperator';
13
15
  // v1.0.1:系统代执行 / 超级管理员(对齐 boot3 FlowConst)
14
16
  export const KeyAutoExecute = 'flow.auto';
15
17
  export const KeyAdminID = 'flow.admin';
@@ -303,7 +305,7 @@ export class EngineImpl {
303
305
  }
304
306
  }
305
307
  async createTask(node, inst, operator, vars) {
306
- const actors = await this.resolveActors(node, inst, vars);
308
+ const actors = await this.resolveActors(node, inst, operator, vars);
307
309
  if (!actors.length)
308
310
  return;
309
311
  const performType = parseInt(String(node.properties?.performType ?? '0'));
@@ -338,14 +340,14 @@ export class EngineImpl {
338
340
  nt.actorIds = actors;
339
341
  await this.repo.saveTask(nt);
340
342
  }
341
- async resolveActors(node, inst, vars) {
343
+ async resolveActors(node, inst, operator, vars) {
342
344
  // 1a. Registry 按名称解析(推荐)
343
345
  if (this.registry) {
344
346
  const handlerName = node.properties?.assignmentHandler ?? '';
345
347
  if (handlerName) {
346
348
  const h = this.registry.resolveAssignment(handlerName);
347
349
  if (h)
348
- return await h.assign(node, inst);
350
+ return await h.assign(node, inst, operator);
349
351
  }
350
352
  }
351
353
  // 1b. Extensions 兼容
package/dist/facade.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ProcessExtRepository, ProcessRepository } from './spi.js';
1
+ import type { OrgUserProvider, ProcessExtRepository, ProcessRepository } from './spi.js';
2
2
  import type { EngineImpl } from './engine.js';
3
3
  export type UserSearch = (query: Record<string, any>) => Promise<[Record<string, any>[], number]> | [Record<string, any>[], number];
4
4
  export declare class JeeflowFacade {
@@ -6,8 +6,10 @@ export declare class JeeflowFacade {
6
6
  private readonly repo;
7
7
  private readonly extRepo?;
8
8
  private userSearch?;
9
+ private orgProv?;
9
10
  constructor(engine: EngineImpl, repo: ProcessRepository, extRepo?: ProcessExtRepository | undefined);
10
11
  setUserSearch(fn: UserSearch): this;
12
+ setOrgProvider(orgProv: OrgUserProvider): this;
11
13
  flow(action: string, args?: Record<string, any>): Promise<Record<string, any>>;
12
14
  private dispatch;
13
15
  private startAndExecute;
package/dist/facade.js CHANGED
@@ -4,6 +4,7 @@
4
4
  // action(boot2/boot3 端点短名)路由。返回统一结构 {code, msg, data}
5
5
  // (code=0 成功 / 99999999 失败)。操作人约定:args.operator 显式传入。
6
6
  import { TaskState, } from './model.js';
7
+ import { KeyNextNodeOperator, KeyProcessStartNextNodeOperator } from './engine.js';
7
8
  // submitType 枚举(对齐 boot3)
8
9
  const SUBMIT_APPLY = 0;
9
10
  const SUBMIT_AGREE = 1;
@@ -17,6 +18,7 @@ export class JeeflowFacade {
17
18
  repo;
18
19
  extRepo;
19
20
  userSearch;
21
+ orgProv;
20
22
  constructor(engine, repo, extRepo) {
21
23
  this.engine = engine;
22
24
  this.repo = repo;
@@ -27,6 +29,11 @@ export class JeeflowFacade {
27
29
  this.userSearch = fn;
28
30
  return this;
29
31
  }
32
+ // 注入组织用户提供者(candidatePage candidateGroups 角色取人,v1.6.0)
33
+ setOrgProvider(orgProv) {
34
+ this.orgProv = orgProv;
35
+ return this;
36
+ }
30
37
  async flow(action, args = {}) {
31
38
  try {
32
39
  const data = await this.dispatch(action, args);
@@ -131,6 +138,11 @@ export class JeeflowFacade {
131
138
  for (const task of doing) {
132
139
  await this.repo.addTaskActor(task.id, [operator]);
133
140
  flowArgs.submitType = SUBMIT_APPLY;
141
+ // 对齐 boot3:f_nextNodeOperator(发起时预指派人)→ tf_nextNodeOperator(引擎执行参数)
142
+ const startNextOp = flowArgs[KeyProcessStartNextNodeOperator];
143
+ if (startNextOp != null && String(startNextOp) !== '') {
144
+ flowArgs[KeyNextNodeOperator] = startNextOp;
145
+ }
134
146
  await this.engine.executeProcessTask(task.id, operator, flowArgs);
135
147
  }
136
148
  return { processInstanceId: inst.id };
@@ -544,7 +556,8 @@ export class JeeflowFacade {
544
556
  return his.map(t => ({
545
557
  taskName: t.taskName, displayName: t.displayName, taskType: t.taskType ?? null,
546
558
  performType: t.performType ?? null, taskState: t.taskState, operator: t.actorId ?? '',
547
- finishTime: t.finishTime ?? null, variable: t.variables ?? {},
559
+ finishTime: fmtTime(t.finishTime), variable: t.variables ?? {},
560
+ ext: t.variables ?? {}, // issues/15:前端读 ext.tf_approvalComment
548
561
  }));
549
562
  }
550
563
  async getAssigneeTextData(args) {
@@ -594,6 +607,7 @@ export class JeeflowFacade {
594
607
  performType: task.performType ?? null, taskState: task.taskState,
595
608
  operator: task.actorId ?? '', formKey: task.formKey ?? '',
596
609
  taskActorIdList: actors, executable: task.isAllowed(operator),
610
+ taskFormData: formDataOf(task.variables, 'tf_'), // issues/15
597
611
  };
598
612
  // taskModel:流程定义中对应节点
599
613
  const inst = await this.repo.findInstanceById(task.processInstanceId);
@@ -638,13 +652,13 @@ export class JeeflowFacade {
638
652
  const inst = await this.repo.findInstanceById(task.processInstanceId);
639
653
  if (!inst)
640
654
  throw new Error('流程实例不存在');
641
- // 模型候选解析:后继任务节点的 candidateUsers 配置
655
+ // 模型候选解析:后继任务节点的 candidateUsers / candidateGroups 配置
642
656
  let candidates = [];
643
657
  const def = await this.repo.findDefineById(inst.defineId);
644
658
  if (def) {
645
659
  try {
646
660
  const flow = JSON.parse(toStr(def.content));
647
- candidates = this.nextTaskCandidates(flow, task.taskName);
661
+ candidates = await this.nextTaskCandidates(flow, task.taskName);
648
662
  }
649
663
  catch { /* ignore */ }
650
664
  }
@@ -658,10 +672,10 @@ export class JeeflowFacade {
658
672
  const [rows, total] = await this.userSearch(args);
659
673
  return { rows, recordCount: total };
660
674
  }
661
- nextTaskCandidates(flow, taskName) {
675
+ async nextTaskCandidates(flow, taskName) {
662
676
  const result = [];
663
677
  const visited = new Set();
664
- const collect = (node) => {
678
+ const collect = async (node) => {
665
679
  const v = node.properties?.candidateUsers;
666
680
  if (v) {
667
681
  for (const s of String(v).split(',')) {
@@ -670,8 +684,22 @@ export class JeeflowFacade {
670
684
  result.push(t);
671
685
  }
672
686
  }
687
+ // candidateGroups:按角色取人(v1.6.0,对齐 boot4 GlobalCandidateHandler)
688
+ const g = node.properties?.candidateGroups;
689
+ if (g && this.orgProv) {
690
+ for (const rc of String(g).split(',')) {
691
+ const role = rc.trim();
692
+ if (!role)
693
+ continue;
694
+ const ids = await this.orgProv.findByRole(role);
695
+ for (const uid of ids ?? []) {
696
+ if (uid && !result.includes(uid))
697
+ result.push(uid);
698
+ }
699
+ }
700
+ }
673
701
  };
674
- const walk = (nodeId) => {
702
+ const walk = async (nodeId) => {
675
703
  if (visited.has(nodeId))
676
704
  return;
677
705
  visited.add(nodeId);
@@ -682,15 +710,15 @@ export class JeeflowFacade {
682
710
  if (!target)
683
711
  continue;
684
712
  if (target.type === 'snaker:task' || target.type === 'snaker:custom') {
685
- collect(target);
713
+ await collect(target);
686
714
  continue;
687
715
  }
688
716
  if (['snaker:fork', 'snaker:join', 'snaker:decision'].includes(target.type)) {
689
- walk(target.id);
717
+ await walk(target.id);
690
718
  }
691
719
  }
692
720
  };
693
- walk(taskName);
721
+ await walk(taskName);
694
722
  return result;
695
723
  }
696
724
  async taskAddActor(args) {
@@ -760,6 +788,7 @@ export class JeeflowFacade {
760
788
  createTime: t.createTime, createUser: t.createUser,
761
789
  updateTime: t.updateTime, updateUser: t.updateUser,
762
790
  taskActorIdList: t.actorIds ?? [],
791
+ taskFormData: formDataOf(t.variables, 'tf_'), // issues/15
763
792
  };
764
793
  const ext = { ...(t.variables ?? {}) };
765
794
  const doing = t.taskState === TaskState.Doing;
@@ -769,15 +798,23 @@ export class JeeflowFacade {
769
798
  if (doing)
770
799
  activeTaskList.push(vo);
771
800
  }
772
- return {
801
+ const data = {
773
802
  id: inst.id, parentId: inst.parentId, processDefineId: inst.defineId,
774
803
  state: inst.state, parentNodeName: inst.parentNodeName,
775
804
  businessNo: inst.businessNo, operator: inst.operator,
776
- variables: inst.variables, createTime: inst.createTime, createUser: inst.createUser,
805
+ variables: inst.variables,
806
+ formData: formDataOf(inst.variables, 'f_'), // issues/15
807
+ createTime: inst.createTime, createUser: inst.createUser,
777
808
  jsonObject: graph, // issues/05
778
809
  tasks,
779
810
  activeTaskList,
780
811
  };
812
+ if (def0) {
813
+ data.displayName = def0.displayName; // issues/15
814
+ data.name = def0.name;
815
+ data.version = def0.version;
816
+ }
817
+ return data;
781
818
  }
782
819
  /** 流程 JSON 中第一个任务节点 id(issues/05-4 isFirstTaskNode 用) */
783
820
  firstTaskNodeId(graph) {
@@ -814,6 +851,17 @@ export class JeeflowFacade {
814
851
  }
815
852
  }
816
853
  // ── 行转 Map(issues/05-2 列表字段契约 + 05-3 时间格式)─────────────────────
854
+ /** issues/15:取 vars 中 prefix 前缀字段,输出「带前缀 + 去前缀副本」(对齐 boot3 getFormData) */
855
+ function formDataOf(vars, prefix) {
856
+ const out = {};
857
+ for (const [k, v] of Object.entries(vars ?? {})) {
858
+ if (k.startsWith(prefix)) {
859
+ out[k] = v;
860
+ out[k.slice(prefix.length)] = v;
861
+ }
862
+ }
863
+ return out;
864
+ }
817
865
  /** Date → 'yyyy-MM-dd HH:mm:ss'(null/undefined → null) */
818
866
  function fmtTime(v) {
819
867
  if (v == null)
@@ -882,6 +930,7 @@ function taskRowToMap(r) {
882
930
  processDefineName: r.processDefineName, processDefineDisplayName: r.processDefineDisplayName,
883
931
  instanceVariable: r.instanceVariable, instanceCreateTime: fmtTime(r.instanceCreateTime),
884
932
  ext, instanceExt, version: r.defineVersion,
933
+ taskFormData: formDataOf(r.variables, 'tf_'), // issues/15
885
934
  };
886
935
  }
887
936
  // ── 工具 ──────────────────────────────────────────────────────────────────────
package/dist/index.d.ts CHANGED
@@ -3,4 +3,5 @@ export { MemoryRepository } from './memory.js';
3
3
  export { HandlerRegistry, type IAssignmentHandler, type IDecisionHandler, type HandlerMeta } from './registry.js';
4
4
  export { enumDict, enumDictKeys, type DictItem } from './metadata.js';
5
5
  export * from './model.js';
6
- export type { ProcessRepository, UserProvider, IDGenerator, ExpressionEvaluator } from './spi.js';
6
+ export type { ProcessRepository, UserProvider, OrgUserProvider, IDGenerator, ExpressionEvaluator } from './spi.js';
7
+ export { registerBuiltinAssignments, OperatorAssignmentHandler, FormFieldAssigneeHandler, DeptLeaderAssignmentHandler, DeptMainLeaderAssignmentHandler, ApplicantDeptLeaderAssignmentHandler, ApplicantDeptMainLeaderAssignmentHandler, TaskRoleAssigneeHandler, HANDLER_OPERATOR_ASSIGNMENT, HANDLER_FORM_FIELD_ASSIGNEE, HANDLER_DEPT_LEADER, HANDLER_DEPT_MAIN_LEADER, HANDLER_APPLICANT_DEPT_LEADER, HANDLER_APPLICANT_DEPT_MAIN_LEADER, HANDLER_TASK_ROLE_ASSIGNEE, } from './builtin.js';
package/dist/index.js CHANGED
@@ -3,3 +3,4 @@ export { MemoryRepository } from './memory.js';
3
3
  export { HandlerRegistry } from './registry.js';
4
4
  export { enumDict, enumDictKeys } from './metadata.js';
5
5
  export * from './model.js';
6
+ export { registerBuiltinAssignments, OperatorAssignmentHandler, FormFieldAssigneeHandler, DeptLeaderAssignmentHandler, DeptMainLeaderAssignmentHandler, ApplicantDeptLeaderAssignmentHandler, ApplicantDeptMainLeaderAssignmentHandler, TaskRoleAssigneeHandler, HANDLER_OPERATOR_ASSIGNMENT, HANDLER_FORM_FIELD_ASSIGNEE, HANDLER_DEPT_LEADER, HANDLER_DEPT_MAIN_LEADER, HANDLER_APPLICANT_DEPT_LEADER, HANDLER_APPLICANT_DEPT_MAIN_LEADER, HANDLER_TASK_ROLE_ASSIGNEE, } from './builtin.js';
@@ -1,7 +1,8 @@
1
1
  import type { FlowNode, ProcessInstance } from './model.js';
2
2
  /** 参与者指派处理器接口——对标 Java AssignmentHandler */
3
3
  export interface IAssignmentHandler {
4
- assign(node: FlowNode, inst: ProcessInstance): string[] | Promise<string[]>;
4
+ /** 返回参与者列表(operator: 当前任务操作人,issues/16 对齐 Java Execution.getOperator) */
5
+ assign(node: FlowNode, inst: ProcessInstance, operator: string): string[] | Promise<string[]>;
5
6
  }
6
7
  /** 决策处理器接口——对标 Java DecisionHandler */
7
8
  export interface IDecisionHandler {
@@ -18,11 +19,15 @@ export interface HandlerMeta {
18
19
  /** 分组(拦截器 pre/post 显式声明;其余可为空) */
19
20
  group?: string;
20
21
  }
22
+ /** 内置通用 AssignmentHandler 元数据(v1.6.0 issues/16,注册名与 Java 类全限定名一致,四语言通用) */
23
+ export declare const BUILTIN_ASSIGNMENT_METAS: HandlerMeta[];
21
24
  /** 处理器注册表——按名称注册/解析 + 元数据清单(对标 Spring IoC / Java HandlerRegistry) */
22
25
  export declare class HandlerRegistry {
23
26
  private assignments;
24
27
  private decisions;
25
28
  private metas;
29
+ /** 构造即内置 7 个通用 AssignmentHandler 元数据(v1.6.0 issues/16,注册名与 Java 类全限定名一致) */
30
+ constructor();
26
31
  registerAssignment(name: string, handler: IAssignmentHandler, meta?: Omit<HandlerMeta, 'name'>): void;
27
32
  registerDecision(name: string, handler: IDecisionHandler, meta?: Omit<HandlerMeta, 'name'>): void;
28
33
  resolveAssignment(name: string): IAssignmentHandler | undefined;
package/dist/registry.js CHANGED
@@ -1,8 +1,24 @@
1
+ /** 内置通用 AssignmentHandler 元数据(v1.6.0 issues/16,注册名与 Java 类全限定名一致,四语言通用) */
2
+ export const BUILTIN_ASSIGNMENT_METAS = [
3
+ { name: 'com.mldong.jeeflow.interceptor.impl.OperatorAssignmentHandler', displayName: '流程发起人', order: -9999 },
4
+ { name: 'com.mldong.jeeflow.interceptor.impl.OrgUserAssignmentHandlers$ApplicantDeptLeaderAssignmentHandler', displayName: '发起人所属部门经理', order: 10 },
5
+ { name: 'com.mldong.jeeflow.interceptor.impl.OrgUserAssignmentHandlers$ApplicantDeptMainLeaderAssignmentHandler', displayName: '发起人所属部门分管领导', order: 20 },
6
+ { name: 'com.mldong.jeeflow.interceptor.impl.OrgUserAssignmentHandlers$DeptLeaderAssignmentHandler', displayName: '当前用户所属部门经理', order: 30 },
7
+ { name: 'com.mldong.jeeflow.interceptor.impl.OrgUserAssignmentHandlers$DeptMainLeaderAssignmentHandler', displayName: '当前用户所属部门分管领导', order: 40 },
8
+ { name: 'com.mldong.jeeflow.interceptor.impl.FormFieldAssigneeHandler', displayName: '根据表单字段值分配参与者', order: 50 },
9
+ { name: 'com.mldong.jeeflow.interceptor.impl.OrgUserAssignmentHandlers$TaskRoleAssigneeHandler', displayName: '根据任务节点唯一编码关联角色分配参与者', order: 60 },
10
+ ];
1
11
  /** 处理器注册表——按名称注册/解析 + 元数据清单(对标 Spring IoC / Java HandlerRegistry) */
2
12
  export class HandlerRegistry {
3
13
  assignments = new Map();
4
14
  decisions = new Map();
5
15
  metas = new Map();
16
+ /** 构造即内置 7 个通用 AssignmentHandler 元数据(v1.6.0 issues/16,注册名与 Java 类全限定名一致) */
17
+ constructor() {
18
+ for (const meta of BUILTIN_ASSIGNMENT_METAS) {
19
+ this.metas.set(meta.name, meta);
20
+ }
21
+ }
6
22
  registerAssignment(name, handler, meta) {
7
23
  this.assignments.set(name, handler);
8
24
  if (meta)
@@ -23,9 +39,11 @@ export class HandlerRegistry {
23
39
  /** 按处理器类型列出可用实现的元数据(typeName: AssignmentHandler / DecisionHandler,按 order 升序) */
24
40
  listHandlers(typeName) {
25
41
  const names = typeName === 'AssignmentHandler'
26
- ? [...this.assignments.keys()]
27
- : [...this.decisions.keys()];
28
- return names
42
+ ? [...this.assignments.keys(), ...this.metas.keys()]
43
+ : [...this.decisions.keys(), ...this.metas.keys()];
44
+ // 内置 meta 属于 AssignmentHandler 类型——DecisionHandler 只列注册过的
45
+ const unique = typeName === 'AssignmentHandler' ? names : this.decisions.keys();
46
+ return [...new Set(unique)]
29
47
  .map(n => this.metas.get(n) ?? { name: n })
30
48
  .sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
31
49
  }
package/dist/spi.d.ts CHANGED
@@ -49,6 +49,14 @@ export interface ProcessRepository {
49
49
  export interface UserProvider {
50
50
  getUser(userId: string): Promise<UserInfo | null>;
51
51
  }
52
+ export interface OrgUserProvider {
53
+ /** 部门领导(deptId → 领导 userId 列表) */
54
+ findDeptLeaders(deptId: string): Promise<string[]>;
55
+ /** 部门分管领导(deptId → 分管领导 userId 列表) */
56
+ findDeptMainLeaders(deptId: string): Promise<string[]>;
57
+ /** 按角色取人(roleCode → userId 列表) */
58
+ findByRole(roleCode: string): Promise<string[]>;
59
+ }
52
60
  export interface IDGenerator {
53
61
  nextId(): number;
54
62
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mldong/jeeflow",
3
- "version": "1.5.1",
3
+ "version": "1.6.1",
4
4
  "description": "jeeflow workflow engine — Node.js / TypeScript implementation",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",