infra-parent

请假申请示例

范围与菜单

本示例位于 flow-api、flow-core 的独立 leave 包,业务表为 flow_ext_leave。不修改引擎原生表,不依赖 UPM 实体和 Service;申请人身份通过 WorkflowIdentityProvider 获取。

OA审批的默认菜单顺序为:流程定义(1)、我的待办(2)、我的已办(3)、我发起的(4)、请假申请(5)。后续业务页面从5及之后排序,不插到前四个公共入口中;本次只固定默认排序,不更改既有菜单的 operable 或授权状态。

页面支持本人申请列表、状态筛选、新建、编辑草稿、删除草稿、提交申请、退回修改及原实例重新提交、业务详情和审批进度。审批人在“我的待办”打开实例时,可通过“请假申请”页签读取正文;正文不存放在流程变量中,也不根据客户端URL加载。

数据库与配置

已有库在完成审批中心菜单和操作权限迁移后,停写、备份,再执行对应的 sql/migration/20261019_flow_leave.mysql.sql 或 .postgres.sql 一次。脚本创建业务表,为模板租户新增菜单和五个按钮,并校正公共入口的默认排序;其他租户同步应用菜单、授权后重新登录。MySQL 5.7兼容,不使用窗口函数,也不在一条语句中重复引用临时表。

新库只执行最新全量脚本。脚本不创建、发布或修改任何流程定义,也不自动创建测试单据。必须在当前租户存在已发布、启用且有有效办理人的流程。

请假示例需宿主显式启用,infra-start 已默认开启。只依赖通用 flow-core 的其他服务默认不加载请假接口和业务关联,不会因为查看通用实例而访问请假表。需要接入示例时配置:

flow.leave.enabled=true
flow.leave.flow-code=leave

相同编码的定义按租户隔离,不共享另一租户的流程。流程编码由服务端在创建草稿时写入,浏览器不能指定或覆盖;调整配置不改变已有草稿的绑定。

表单与校验

本版不推算节假日、午休或排班,也不把“自然时长”自动当作“工作时长”。例如09:00至18:00可以按排班填8小时。暂不包含余额扣减、附件和通知。动态部门主管已通过通用办理人规则接入,配置步骤见动态办理人配置。

申请提交与退回配置

需要退回修改的请假流程,配置为:开始 → 提交申请 → 本部门审核 → 上一级部门审核 → 结束。

  1. 在开始后添加一个普通审批节点,名称可填“提交申请”。办理人只选“动态规则 → 申请人”,不混选固定用户、角色、部门或其他规则;节点名称不是识别依据。
  2. 整个定义只能有一个这样的申请节点,并且必须是开始后的唯一首个办理任务,不能与其他任务并行。
  3. 后续审核节点按需选择固定办理人,或“本部门副主管(无则主管)”“上一级部门主管”。多人任意一人通过时选择“或签”。
  4. 需要退回的审核节点在仿钉钉设计器中设置“驳回到指定节点”,目标选择“提交申请”;经典模式可配置对应的退回路线。不能退回开始节点。
  5. 复制已使用的定义生成新版本,配置后发布;本功能不会修改已有实例绑定的定义版本,也不自动改写已发布流程。

首次在业务表单点击“提交申请”,后端在启动流程的同一事务中自动完成该申请节点,直接进入审核,无需申请人再去待办“审核自己”。只自动完成这一节点,绝不因为后续办理人恰好是申请人而自动跳过审核。

审核退回申请节点后,申请人可从“请假申请”列表或“我的待办 → 办理申请”打开表单,修改后“保存修改”或“重新提交”。保存只更新单据,不推进流程;重新提交继续原实例并保留此前审批记录,不另建实例。通用详情在此节点不展示“通过 / 退回”,服务端也会拒绝使用通用审批接口绕过业务校验。

审批进行中,申请人可在“我发起的”使用“拿回”,将流程退回到本人最近完成的节点;拿回到“提交申请”后即可修改并重新提交原实例。对仍在办理中的申请也可“撤销”,实例随后标记为已撤销且不能继续审批;撤销不等同于拿回,不保留可编辑的待办申请节点。是否显示按钮由实例当前状态决定,后端仍会校验发起人身份和活动状态。

旧的“开始 → 审批 → 结束”流程仍可直接提交;没有申请节点的定义不会自动增加节点。只回到审核节点的退回仍是审核,不会开放业务表单编辑。

接口与权限

接口 权限 用途
GET /flow/leave/page flow:leave:list 本人分页,status可为DRAFT或引擎状态
GET /flow/leave/detail/{id} 请假列表或任一审批中心查询权限 查看正文,仍校验本人或实例参与身份
POST /flow/leave/add flow:leave:add 保存新草稿,不启动流程
POST /flow/leave/edit/{id} flow:leave:edit 修改本人草稿或当前申请节点单据,须携带version;后者还须携带submissionTaskId
POST /flow/leave/submit/{id} flow:leave:submit 首次提交或原实例重提,须携带version;重提还须携带submissionTaskId
POST /flow/leave/delete/{id} flow:leave:delete 物理删除本人草稿,须携带version

新建示例:

{
  "leaveType": "PERSONAL",
  "startTime": "2026-10-20 09:00:00",
  "endTime": "2026-10-20 18:00:00",
  "durationHours": 8,
  "reason": "外出办事"
}

响应中保留 id、version。编辑时提交完整业务字段及当前版本;首次提交和删除的请求体为 {"version": 1}。每次编辑、提交后版本都会更新,不能一直复用旧版本。

详情和列表通过 editable、submissionTaskId 告知当前是否可编辑及对应申请任务。退回修改时,编辑请求在上述完整业务字段基础上增加 submissionTaskId;使用编辑响应中的新版本重新提交,例如:

{
  "version": 3,
  "submissionTaskId": "2100000000000000001"
}

editable 只用于界面展示,不是授权凭证。写入时服务端重新校验当前任务、租户、本人、候选身份和版本;缺少或过期的任务ID会被拒绝。任务已进入审核、实例已完成或挂起时不能修改;有实例的单据始终不能删除。非本人读取正文时,必须属于该实例当前候选人或历史办理人;平台管理员不默认绕过参与身份。列表始终只显示当前租户本人记录。

事务与状态

首次提交在READ_COMMITTED事务中锁定本人草稿,校验版本和未提交状态,调用 WorkflowService.start、绑定实例ID,再自动完成申请节点。任一步失败整笔回滚,草稿保留、实例不残留;包括自动完成后无法生成有效审核任务的情况。同一草稿并发提交最多启动一个实例。

修改已发起单据和重新提交时,先锁流程实例,再锁业务单据,与通用审批遵循一致的实例串行化边界;重提同时增加单据版本并推进原任务,失败共同回滚。外层业务事务也必须使用READ_COMMITTED,共用数据源及事务管理器。重提更新类型、时长等业务路由变量,但不覆盖发起时固化的动态办理人快照。

instance_id 为空即草稿;提交后的状态实时关联 flow_instance.flow_status,不在业务表重复维护一份审批状态。无需额外编写“每个节点完成就审批通过”的监听器。流程变量仅包含业务类型、申请人ID、请假类型、时长等必要路由数据,不包含请假原因。

业务通过 WorkflowBusinessProvider 向审批中心提供受信任的类型、单据ID和标题;findSubmissionTask 额外识别该业务的申请任务,控制待办入口及通用审批拦截。业务Service校验和保存表单后,在同一事务内调用 WorkflowService.submitBusinessTask,该方法仍校验实际候选身份及业务类型,不开放通用HTTP提交入口。新增其他业务时可提供自己的关联实现和受保护正文接口,不需要在通用引擎表中追加业务字段。

本次退回重提不新增表、字段或权限按钮;已完成请假表及菜单迁移的数据库无需重复执行SQL。申请人需要原有的编辑、提交按钮权限;不需要通用审批通过权限来提交业务申请。

验证步骤

  1. 执行增量,重启包含 flow-core 的宿主,重新登录并确认菜单排序及权限。
  2. 在当前租户确认编码 leave 已发布,审批节点已配置有效办理人。
  3. 新建请假,先保存草稿,确认其他用户看不到草稿,再编辑并确认版本更新。
  4. 提交后确认直接到审核任务;审批人从“我的待办”查看正文并退回申请节点。
  5. 申请人在待办中看到“办理申请”而非审核按钮;修改并保存后版本更新,重新提交后实例ID不变,审批人能看到最新正文。
  6. 审核通过后确认完成状态及原有历史记录,不能再编辑;重复提交、重复办理、过期任务或版本、跨租户及非本人修改均被拒绝。

集成测试覆盖完整退回重提、自动提交失败的事务回滚及并发重提只成功一次;前端组件测试覆盖首次动态打开表单、不可编辑状态、提交失败重试不重复保存。浏览器模拟接口回归覆盖创建、审核退回、原表单修改重提、最新正文及移动端抽屉,不读写真实业务库。