40-委托:DelegateRecord的时间窗口设计
处长出差两周——这期间的待办自动给副处长处理。52行DelegateService管委派记录的增删查,核心是DelegateRecord表的时间窗口+状态双条件生效模型。与任务级delegateTask(第36篇)的区别:这是规则级委托——设置一次,窗口内所有新任务自动流转。
文章目录
- 40-委托:DelegateRecord的时间窗口设计
-
- 一、两种“委托”的区分
- 二、DelegateRecord的字段模型
- 三、52行的四个方法
- 四、待办怎么合并:调用方的职责
- 五、roleId/procDefId的范围限定的真实用途
- 六、assignee冗余字段的历史
源码:browise-workflow/src/main/java/com/browise/workflow/service/DelegateService.java(52行) 实体:entity/DelegateRecord.java 前端:browise-vue/src/components/workflow/DelegateManager.vue
一、两种“委托”的区分
| 粒度 | 一个具体任务 | 一段时间的所有任务 |
| 引擎行为 | 任务转移到受托人(原处理人脱离) | 待办查询时合并计算 |
| 撤销 | 不可逆(转出去转回来要再转) | 改状态即可 |
| 典型场景 | “这个单子让小王替我批” | “我休假两周,全部给老李” |
任务级是引擎API(taskService.delegateTask)——browise的FlowableProcessService透传。规则级是自己的表——引擎不知道委托存在,在待办查询时把受托人查进来。
二、DelegateRecord的字段模型
DelegateRecord {
id // UUID
client // 委托人(出发者)
assignee // 冗余=client(兼容历史查询)
attorney // 受托人(接收者)
roleId // 可选:限定某类角色范围
procDefId // 可选:限定某个流程定义
startTime // 窗口起
endTime // 窗口止
status // 0=生效 1=撤销
}
生效条件是三维的——status=0 AND now BETWEEN startTime AND endTime,再加上可选的范围过滤(roleId/procDefId空=不限定):
— selectActiveByAttorney的语义
SELECT * FROM DELEGATE_RECORD
WHERE ATTORNEY = ? — 委托给我
AND STATUS = '0' — 未撤销
AND ? BETWEEN START_TIME AND END_TIME — 时间窗口内
时间窗口是防呆设计——出差回来忘了撤销?endTime一到自动失效。免维护的过期机制——不用记得回来撤销(政务系统的处长们不会记得的)。
三、52行的四个方法
// 我发出的委托(管理界面列表)
getMyDelegations(userId)
→ selectByClient(userId)
// 当前生效的委托给我的(待办合并的核心查询)
getActiveDelegationsForAttorney(userId)
→ selectActiveByAttorney(userId, new Date()) // now作为参数
// 设置委托
@Transactional addDelegation(client, attorney, roleId, procDefId, start, end)
→ insert + status="0"
// 撤销
@Transactional revokeDelegation(id)
→ deactivate(id) // status改1——不delete,留痕
撤销是软删——deactivate改状态不删行。审计诉求:“去年3月那段时间谁替谁处理过任务”必须可查——委托期的审批责任追溯(受托人批错的单子,委托关系是追责链的一环)。
四、待办怎么合并:调用方的职责
DelegateService只管记录——合并发生在查询侧:
// 待办查询的伪代码(TodoList.vue + workflowApi)
List<Task> mine = processService.getTodoTasks(userId); // 直接分给我的
List<DelegateRecord> delegations = delegateService
.getActiveDelegationsForMe(userId); // 生效的委托
for (DelegateRecord d : delegations) {
List<Task> clientTasks = processService.getTodoTasks(d.getClient());
// 按roleId/procDefId过滤后合并
mine.addAll(filtered(clientTasks));
}
引擎的assignee没变——任务还在原处理人名下,受托人查询时“捎带”看到。这带来三个特性:
五、roleId/procDefId的范围限定的真实用途
addDelegation(client, attorney, roleId, procDefId, ...)
处长委托给副处长——roleId限定“只有处长角色的流程任务转”——个人事务(请假流程)不跟着转。
procDefId限定——“参保审批流程的给老李,待遇核定的还留给我(电话批)”——按流程类型分拆委托——出差期间轻重缓急不同的业务分给不同的人。
两个都空=全权委托——最常用也最简单的形态。
六、assignee冗余字段的历史
assignee和client存同一个值——兼容字段。早期版本表结构只有assignee(谁的任务),后来语义化改名client(委托人)——老查询/报表还引用assignee,删掉要改一片。冗余两个字段换迁移零成本——等报表改造完再清理的“临时”方案(每个老系统都懂)。
✅ 亮点:任务级与规则级委托的对照、时间窗口+状态+可选范围的三维生效模型、endTime自动到期的免维护设计、软删留痕服务追责、待办合并查询让引擎无感知委托、roleId/procDefId分拆委托的实际场景。适合做审批委托的人。扩展方向:第36篇delegateTask、第43篇处理人配置、第52篇WebSocket待办推送。
网硕互联帮助中心

评论前必须登录!
注册