后端业务模块接入
后端业务模块接入
本文面向后端开发,说明新增业务模块需要提供的实体、常量、接口和回调。
1. 新增业务模块常量
路径:Admin.NET/Admin.NET.Application/Const/BusinessModuleConst.cs
public class BusinessModuleConst
{
public const string Leave = "Leave";
public const string Purchase = "Purchase";
}常量值必须与前端 workflowForm/*.ts 中的 value 完全一致。
2. 业务实体字段
请假实体路径:Admin.NET/Admin.NET.Application/Entity/Leave.cs
业务实体至少建议包含以下工作流字段:
public string? WorkflowInstanceCodes { get; set; }
public int? WorkflowStatus { get; set; }
public string? WorkflowComment { get; set; }
public DateTime? WorkflowCompleteTime { get; set; }
public int Status { get; set; }其中 Status 是业务状态,由业务模块自己定义。WorkflowStatus 是审批状态,建议保持:
| 值 | 含义 |
|---|---|
0 | 未提交 |
1 | 审批中 |
2 | 已通过 |
3 | 已拒绝 |
如果流程条件需要用到业务字段,可在实体字段上加 WorkflowFieldAttribute:
[WorkflowField("请假天数", WorkflowFieldTypeEnum.Number)]
public decimal Days { get; set; }后端接口 /api/workflow/businessModule/{businessModule}/fields 会读取这些标记字段,作为流程设计器条件字段的后备来源。当前前端优先使用 workflowForm/*.ts 中的 conditionFields。
3. 业务服务接口
请假服务路径:Admin.NET/Admin.NET.Application/Service/Workflow/Leave/LeaveService.cs
推荐接口:
| 接口 | 方法 | 作用 |
|---|---|---|
/api/demo/{module}/add | POST | 创建业务草稿 |
/api/demo/{module}/page | POST | 查询业务列表 |
/api/demo/{module}/detail | GET | 查询业务详情,供业务页和工作流详情展示 |
/api/demo/{module}/update | POST | 修改业务草稿 |
/api/demo/{module}/delete | POST | 删除业务数据,必要时终止或清理流程实例 |
/api/demo/{module}/submit | POST | 业务提交审批,内部启动工作流 |
/api/demo/{module}/workflow/callback | POST | 工作流完成或拒绝后的业务回调 |
/api/demo/{module}/getBusinessData | GET | 获取业务数据快照,当前主要用于兼容和调试 |
detail 接口要返回工作流详情页展示所需的业务字段和状态字段。前端业务详情组件通过 getDetailApiName 调用它。
4. submit 接口
submit 接口是业务和工作流的边界,必须由业务模块提供。以请假为例:
[HttpPost("submit")]
public async Task<StartWorkflowOutput> SubmitLeave([FromBody] SubmitLeaveInput input)
{
var leave = await _leaveRep.GetByIdAsync(input.BusinessId)
?? throw Oops.Bah("请假单不存在");
if (leave.Status != 0)
throw Oops.Bah("请假单已提交,不能重复提交");
leave.Status = 1;
leave.WorkflowStatus = 1;
await _leaveRep.UpdateAsync(leave);
var formData = new
{
LeaveType = leave.LeaveType,
Days = leave.Days,
ApplicantName = leave.ApplicantName,
DeptName = leave.DeptName
};
var result = await _workflowInstanceService.StartWorkflow(new StartWorkflowInput
{
DefinitionId = input.DefinitionId,
WorkflowCode = input.WorkflowCode,
BusinessModule = BusinessModuleConst.Leave,
BusinessId = leave.Id,
FormData = JsonSerializer.Serialize(formData),
Remark = input.Remark
});
leave.WorkflowInstanceCodes = result.InstanceCode;
await _leaveRep.UpdateAsync(leave);
return result;
}注意事项:
- 先做业务权限和状态校验,再启动流程。
BusinessModule、BusinessId必须写入StartWorkflowInput,否则审批结束后无法回调业务模块。FormData应包含条件判断和展示需要的字段。DefinitionId和WorkflowCode二选一。前端弹窗通常会传definitionId,也会补充workflowCode。- 启动失败时要恢复业务状态。请假示例在
catch中恢复原始状态。
5. 完成回调
工作流通过或拒绝时,WorkflowApprovalService 会按以下优先级通知业务模块:
- 依赖注入处理器(优先):从 DI 容器查找所有
IWorkflowCompletedHandler实现,匹配BusinessModule后调用HandleAsync。 - HTTP 回调(兜底):按
BusinessModuleCallbackRouteTemplate配置的地址发起 HTTP 请求。
方式一:实现 IWorkflowCompletedHandler(推荐)
路径:Admin.NET/Plugins/Admin.NET.Plugin.WorkFlow/Service/IWorkflowCompletedHandler.cs
public interface IWorkflowCompletedHandler
{
string BusinessModule { get; }
Task HandleAsync(WorkflowCompletedContext context);
}
public class WorkflowCompletedContext
{
public string InstanceCode { get; set; }
public string BusinessModule { get; set; }
public long BusinessId { get; set; }
public bool Approved { get; set; }
public string? Comment { get; set; }
}业务模块在服务中实现此接口并注册到 DI 容器:
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 回调接口,无需处理鉴权,类型安全。
方式二:HTTP 回调(传统方式)
默认模板在 Admin.NET/Plugins/Admin.NET.Plugin.WorkFlow/Configuration/WorkFlow.json:
"BusinessModuleCallbackRouteTemplate": "/api/demo/{businessModuleLower}/workflow/callback"Leave 会被解析为 /api/demo/leave/workflow/callback。
回调输入 DTO:
public class WorkflowCallbackInput
{
public string InstanceCode { get; set; } = string.Empty;
public string BusinessModule { get; set; } = string.Empty;
public long? BusinessId { get; set; }
public bool Approved { get; set; }
public string? Comment { get; set; }
}业务模块在回调中应:
- 校验
BusinessModule是否匹配。 - 校验
BusinessId是否存在。 - 查询业务数据,找不到时记录日志并返回。
- 根据
Approved更新业务状态和审批状态。 - 保存审批意见和完成时间。
6. 回调安全
示例代码为了便于本机演示使用了 [AllowAnonymous]。生产环境不要直接裸露内部回调接口,至少选择一种保护方式:
- 只允许内网服务访问。
- 在反向代理或网关层限制来源。
- 回调请求携带签名、时间戳和随机串,业务接口校验签名。
- 使用服务账号 token 或 mTLS。
如果增加签名,建议同时修改 WorkflowApprovalService.NotifyBusinessModuleAsync 的请求头生成逻辑。
7. 删除业务数据
业务数据删除要考虑流程实例:
- 草稿:直接删除业务数据。
- 审批中:先终止 WorkflowCore 实例,再删除或禁止删除。
- 已完成/已拒绝:可按业务规则保留流程历史或同步删除关联实例。
请假前端当前禁止删除审批中的单据,后端 DeleteLeave 仍保留了终止和清理逻辑,防止接口被绕过。