业务流程前后端集成指南
大约 5 分钟约 1629 字
业务流程前后端集成指南
本文是新增业务流程的主指南。请假流程 Leave 是当前标准示例,其他业务流程按同一模式复制后改名。
一句话流程
业务模块先创建自己的业务单据,用户在业务列表点击“提交审批”,前端弹出流程选择框,后端业务 submit 接口更新业务状态并调用工作流启动服务。审批结束后工作流服务回调业务模块,业务模块再回写通过或拒绝状态。
请假流程现状
后端:
Leave实体:Admin.NET/Admin.NET.Application/Entity/Leave.csLeaveService:Admin.NET/Admin.NET.Application/Service/Workflow/Leave/LeaveService.csLeaveDto:Admin.NET/Admin.NET.Application/Service/Workflow/Leave/Dto/LeaveDto.cs- 业务模块常量:
BusinessModuleConst.Leave = "Leave"
前端:
- 业务页面:
Web/src/views/demo/leave/index.vue - 详情组件:
Web/src/views/demo/leave/LeaveDetail.vue - API:
Web/src/api/demo/leave.ts - 工作流模块配置:
Web/src/views/workFlow/workflowForm/leave.ts - 发起弹窗:
Web/src/views/workFlow/components/BusinessWorkflowStartDialog.vue
业务状态模型
请假示例同时维护业务状态和工作流状态:
| 字段 | 含义 | 请假示例取值 |
|---|---|---|
Status | 业务单据状态 | 0 草稿,1 已提交,2 已通过,3 已拒绝,4 已取消 |
WorkflowStatus | 审批状态 | 0 未提交,1 审批中,2 已通过,3 已拒绝 |
WorkflowInstanceCodes | 关联工作流实例编码 | 请假示例只允许草稿提交一次,所以保存一个实例编码 |
WorkflowComment | 审批意见 | 审批拒绝时写入 comment,通过时可为空 |
WorkflowCompleteTime | 审批完成时间 | 回调业务模块时写入 |
其他业务模块可以使用自己的业务状态枚举,但必须保留能关联工作流实例和审批结果的字段。
端到端调用链
- 用户在
Web/src/views/demo/leave/index.vue新增请假单。 - 前端调用
POST /api/demo/leave/add创建草稿,后端写入Status = 0、WorkflowStatus = 0。 - 用户点击“提交审批”。
- 页面打开
BusinessWorkflowStartDialog:
<BusinessWorkflowStartDialog
v-if="state.workflowDialogRow"
v-model:visible="state.workflowDialogVisible"
business-module="Leave"
:business-id="state.workflowDialogRow.id"
@success="handleWorkflowStartSuccess"
/>- 弹窗按
businessModule = "Leave"查询已启用且最新的流程定义。 - 用户选择流程后,弹窗读取
workflowForm/leave.ts注册的submitApiName = "submitLeave",调用业务模块提交接口。 POST /api/demo/leave/submit做业务校验、状态变更和工作流启动。WorkflowInstanceService.StartWorkflow创建WorkFlowInstance、WorkFlowFormRecord、WorkFlowTodo等工作流数据。- 审批人在待办页面审批。
- 流程完成或拒绝时,
WorkflowApprovalService优先查找 DI 容器中的IWorkflowCompletedHandler实现,未找到时按回调模板请求/api/demo/leave/workflow/callback。 - 业务模块根据审批结果更新业务单据状态。
后端 submit 接口必须做的事
请假示例在 SubmitLeave 中做了 5 件事:
- 按
BusinessId查询业务单据。 - 校验当前状态是否允许提交,例如请假单只允许草稿提交。
- 先把业务状态改成已提交和审批中。
- 组装
StartWorkflowInput,写入DefinitionId或WorkflowCode、BusinessModule、BusinessId、FormData、Remark。 - 调用
_workflowInstanceService.StartWorkflow(workflowInput),成功后把result.InstanceCode保存到业务表。
关键代码形态:
var workflowInput = new StartWorkflowInput
{
DefinitionId = input.DefinitionId,
WorkflowCode = input.WorkflowCode,
BusinessModule = BusinessModuleConst.Leave,
BusinessId = leave.Id,
FormData = JsonSerializer.Serialize(formData),
Remark = string.IsNullOrWhiteSpace(input.Remark)
? $"请假单审批:{leave.LeaveType},{leave.Days}天"
: input.Remark
};
var result = await _workflowInstanceService.StartWorkflow(workflowInput);
leave.WorkflowInstanceCodes = result.InstanceCode;
await _leaveRep.UpdateAsync(leave);不要让前端直接调用 /api/workflow/startWorkflow 作为业务提交流程的主路径。直接调用会绕过业务状态校验、权限校验和业务字段快照。
FormData 的作用
FormData 是流程实例启动时保存的业务字段快照,后续用于:
- 条件网关表达式判断,例如
Days > 3。 - 工作流表单记录展示。
- 节点 HTTP 回调变量替换,例如
{{formData.Days}}。
请假示例传入:
var formData = new
{
LeaveType = leave.LeaveType,
StartTime = leave.StartTime.ToString("yyyy-MM-dd HH:mm:ss"),
EndTime = leave.EndTime.ToString("yyyy-MM-dd HH:mm:ss"),
Days = leave.Days,
Reason = leave.Reason,
ApplicantName = leave.ApplicantName,
DeptName = leave.DeptName
};字段命名建议与前端 conditionFields 保持一致。当前条件表达式支持大小写不敏感匹配,但团队开发时不要混用多套字段名。
完成回调怎么回写业务状态
工作流通过或拒绝后会通知业务模块。WorkflowApprovalService 按以下优先级处理:
- 依赖注入处理器(优先):查找
IWorkflowCompletedHandler实现,匹配BusinessModule后调用。 - HTTP 回调(兜底):按
BusinessModuleCallbackRouteTemplate发起 HTTP 请求。
方式一:实现 IWorkflowCompletedHandler(推荐)
业务服务直接实现接口,无需暴露 HTTP 接口:
public class LeaveService : IDynamicApiController, ITransient, IWorkflowCompletedHandler
{
public string BusinessModule => BusinessModuleConst.Leave;
public async Task HandleAsync(WorkflowCompletedContext context)
{
var leave = await _leaveRep.GetByIdAsync(context.BusinessId);
if (leave == null) return;
leave.Status = context.Approved ? 2 : 3;
leave.WorkflowStatus = context.Approved ? 2 : 3;
leave.WorkflowComment = context.Comment;
leave.WorkflowCompleteTime = DateTime.Now;
await _leaveRep.UpdateAsync(leave);
}
}方式二:HTTP 回调
工作流通过或拒绝后会发送类似数据:
{
"instanceCode": "INST_Leave_202605271010001234",
"businessModule": "Leave",
"businessId": 123,
"approved": true,
"comment": "同意"
}请假示例回调接口:
[HttpPost("workflow/callback")]
public async Task OnWorkflowCompleted([FromBody] WorkflowCallbackInput input)
{
if (input.BusinessModule != BusinessModuleConst.Leave) return;
if (!input.BusinessId.HasValue) return;
var leave = await _leaveRep.GetByIdAsync(input.BusinessId.Value);
if (leave == null) return;
leave.Status = input.Approved ? 2 : 3;
leave.WorkflowStatus = input.Approved ? 2 : 3;
leave.WorkflowComment = input.Comment;
leave.WorkflowCompleteTime = DateTime.Now;
await _leaveRep.UpdateAsync(leave);
}示例代码中为了演示使用了 [AllowAnonymous]。生产环境应增加签名、内网网关、固定服务身份或其他服务间鉴权。
前端接入最小代码
业务列表页只需要在点击提交时设置当前行并打开弹窗:
const handleSubmitWorkflow = (row: any) => {
state.workflowDialogRow = row;
state.workflowDialogVisible = true;
};提交成功后刷新列表:
const handleWorkflowStartSuccess = () => {
state.workflowDialogVisible = false;
handleQuery();
};列表操作按钮按业务状态控制:
<el-button v-if="row.status === 0" text type="success" @click="handleSubmitWorkflow(row)">
提交审批
</el-button>
<el-button v-if="row.workflowInstanceCodes" text type="info" @click="viewWorkflow(row.workflowInstanceCodes?.split(',')[0])">
查看流程
</el-button>查看流程跳转到“我发起的流程”:
router.push({
path: '/workFlow/myInitiatedTasks',
query: { instanceCode },
});新业务流程接入步骤
- 新增业务实体,包含业务字段、业务状态字段和工作流关联字段。
- 在
BusinessModuleConst.cs中新增业务模块常量。 - 新增业务服务,至少提供
add、page、detail、submit、workflow/callback。 submit中调用WorkflowInstanceService.StartWorkflow,并保存InstanceCode。- 新增前端业务 API 文件,导出列表、详情、提交函数。
- 新增前端业务页面,使用
BusinessWorkflowStartDialog提交审批。 - 新增业务详情组件,用于待办、已办、我发起的流程中展示业务数据。
- 在
Web/src/views/workFlow/workflowForm新增配置文件,声明value、apiPath、apis、detailComponentPath、conditionFields。 - 在流程设计器创建业务模块流程,表单类型选择业务模块表单,并选择新业务模块。
- 发布流程后,从业务页面发起审批并完整验证通过、拒绝、查看流程、业务状态回写。
不再推荐的方式
- 不要按旧文档手动维护
businessModuleComponentMap或businessModuleApiMap。 - 不要把业务模块注册写到
dataApproval目录。 - 不要在业务页面里直接调用
/api/workflow/startWorkflow发起业务审批。 - 不要只更新工作流实例状态而不回写业务表状态。
- 不要让条件表达式依赖未进入
FormData的字段。