From cbe0e794db61115bae56fe0a6e0cd36c220be973 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E4=BC=9F?= <421281095@qq.com> Date: Thu, 5 Feb 2026 09:51:56 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=B4=E6=97=B6=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OpenAuth.App/WorkflowEngineApp.cs | 519 +++++++++++++++--- .../Domain/workflow/ApiResult.cs | 217 ++++++++ .../Domain/workflow/InitiateFlowRequest.cs | 91 --- .../Controllers/ServerController/ApiResult.cs | 95 ---- .../CustomWorkflowController.cs | 281 ++++++---- 5 files changed, 811 insertions(+), 392 deletions(-) create mode 100644 OpenAuth.Repository/Domain/workflow/ApiResult.cs delete mode 100644 OpenAuth.Repository/Domain/workflow/InitiateFlowRequest.cs delete mode 100644 OpenAuth.WebApi/Controllers/ServerController/ApiResult.cs diff --git a/OpenAuth.App/WorkflowEngineApp.cs b/OpenAuth.App/WorkflowEngineApp.cs index 0cb7e6f..2a51635 100644 --- a/OpenAuth.App/WorkflowEngineApp.cs +++ b/OpenAuth.App/WorkflowEngineApp.cs @@ -4,6 +4,7 @@ using OpenAuth.App.Interface; using OpenAuth.Repository; using OpenAuth.Repository.Domain; using OpenAuth.Repository.Domain.workflow; +using OpenAuth.WebApi.Controllers.ServerController; using SqlSugar; namespace workflow; @@ -18,9 +19,21 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using Microsoft.AspNetCore.Http; +using OpenAuth.App.BaseApp.Base; +using OpenAuth.App.Interface; +using OpenAuth.Repository; +using OpenAuth.Repository.Domain; +using OpenAuth.Repository.Domain.workflow; +using SqlSugar; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; /// /// 完整工作流引擎(适配:区县→执法监督科→5个审核科会签→汇总归档/退回) +/// 包含:流程发起/处理 + 拟办/待办/已办/未办结/已完成/全部事项查询 /// public class WorkflowEngineApp : SqlSugarBaseApp { @@ -45,12 +58,19 @@ public class WorkflowEngineApp : SqlSugarBaseApp + /// 发起流程(区县提交→流转至执法监督科) + /// + /// 发起人ID + /// 发起人姓名 + /// 发起流程请求参数 + /// 流程实例ID + public long InitiateFlow(long userId, string userName, InitiateFlowRequestDto requestDto) { // 参数校验 - if (string.IsNullOrEmpty(request.FlowCode) || string.IsNullOrEmpty(request.BusinessNo)) + if (string.IsNullOrEmpty(requestDto.FlowCode) || string.IsNullOrEmpty(requestDto.BusinessNo)) throw new Exception("流程编码和业务编号不能为空"); if (userId <= 0 || string.IsNullOrEmpty(userName)) throw new Exception("发起人ID和姓名不能为空"); @@ -64,10 +84,10 @@ public class WorkflowEngineApp : SqlSugarBaseApp() - .Where(t => t.FlowCode == request.FlowCode && t.IsEnabled == true) + .Where(t => t.FlowCode == requestDto.FlowCode && t.IsEnabled == true) .First(); if (template == null) - throw new Exception($"流程模板【{request.FlowCode}】不存在或未启用"); + throw new Exception($"流程模板【{requestDto.FlowCode}】不存在或未启用"); // 步骤2:查询流程开始节点(区县提交) var startNode = _sqlSugar.Queryable() @@ -81,7 +101,7 @@ public class WorkflowEngineApp : SqlSugarBaseApp { - new ZyFlowVariable { InstanceId = instanceId, VarKey = "Title", VarValue = request.Title }, + new ZyFlowVariable { InstanceId = instanceId, VarKey = "Title", VarValue = requestDto.Title }, new ZyFlowVariable { InstanceId = instanceId, VarKey = "AttachmentPaths", VarValue = attachmentPaths }, new ZyFlowVariable { @@ -135,14 +155,17 @@ public class WorkflowEngineApp : SqlSugarBaseApp + /// 处理工作项(执法监督科转发/审核科会签/汇总处理) + /// + /// 处理人ID + /// 处理人姓名 + /// 处理工作项请求参数 + /// 处理结果(成功/失败) + public bool HandleWorkitem(long userId, string userName, HandleWorkitemRequestDto requestDto) { // 参数校验 - if (request.WorkitemId <= 0) + if (requestDto.WorkitemId <= 0) throw new Exception("工作项ID无效"); if (userId <= 0 || string.IsNullOrEmpty(userName)) throw new Exception("处理人ID和姓名不能为空"); @@ -154,7 +177,7 @@ public class WorkflowEngineApp : SqlSugarBaseApp() - .Where(w => w.WorkitemId == request.WorkitemId && w.Status == "ToDo") + .Where(w => w.WorkitemId == requestDto.WorkitemId && w.Status == "ToDo") .First(); if (workitem == null) throw new Exception("工作项不存在、已处理或状态异常"); @@ -172,7 +195,7 @@ public class WorkflowEngineApp : SqlSugarBaseApp - /// 查询我的待办工作项 + /// 我的拟办(未认领/待分配给当前用户的事项) /// - public List QueryMyToDo(long userId) + /// 当前用户ID + /// 分页参数 + /// 分页结果 + public PageQueryResultDto QueryMyDraft(long userId, PageQueryRequestDto pageQueryDto) { + // 参数初始化 if (userId <= 0) - return new List(); + return new PageQueryResultDto(); + pageQueryDto = pageQueryDto ?? new PageQueryRequestDto(); + var pageIndex = pageQueryDto.PageIndex < 1 ? 1 : pageQueryDto.PageIndex; + var pageSize = pageQueryDto.PageSize < 1 ? 10 : pageQueryDto.PageSize; - // 步骤1:查询当前用户的待办工作项 - var toDoWorkitems = _sqlSugar.Queryable() - .Where(w => w.HandlerId == userId && w.Status == "ToDo") + // 拟办逻辑:工作项状态为"Draft"(拟办)、对应角色匹配当前用户、未分配具体处理人 + var draftQuery = _sqlSugar + .Queryable((w, n) => new JoinQueryInfos( + JoinType.Inner, w.NodeId == n.NodeId)) + .Where((w, n) => + w.Status == "Draft" && _auditDeptRoleIds.Contains(n.RoleId) + && (w.HandlerId == null || w.HandlerId == 0) + && w.HandlerName != "") + .OrderByDescending((w, n) => w.ReceiveTime); + + // 分页查询 + var totalCount = draftQuery.Count(); + var draftWorkitems = draftQuery + .Skip((pageIndex - 1) * pageSize) + .Take(pageSize) .ToList(); - // 步骤2:组装返回结果 - var queryResults = new List(); + // 组装返回结果 + var dataList = new List(); + foreach (var workitem in draftWorkitems) + { + var flowInstance = _sqlSugar.Queryable() + .Where(i => i.InstanceId == workitem.InstanceId) + .First(); + if (flowInstance == null) + continue; + + var flowTitle = _sqlSugar.Queryable() + .Where(v => v.InstanceId == flowInstance.InstanceId && v.VarKey == "Title") + .First()?.VarValue ?? string.Empty; + + dataList.Add(new FlowQuerySingleResultDto + { + InstanceId = flowInstance.InstanceId, + BusinessNo = flowInstance.BusinessNo, + Title = flowTitle, + NodeName = workitem.NodeName, + Status = "Draft", // 拟办状态 + CreateTime = flowInstance.CreateTime, + InitiatorName = flowInstance.InitiatorName + }); + } + + return new PageQueryResultDto + { + PageIndex = pageIndex, + PageSize = pageSize, + TotalCount = totalCount, + TotalPages = (int)Math.Ceiling((double)totalCount / pageSize), + DataList = dataList + }; + } + + /// + /// 我的待办(已分配给当前用户、待处理的事项) + /// + /// 当前用户ID + /// 分页参数 + /// 分页结果 + public PageQueryResultDto QueryMyToDo(long userId, PageQueryRequestDto pageQueryDto) + { + // 参数初始化 + if (userId <= 0) + return new PageQueryResultDto(); + pageQueryDto = pageQueryDto ?? new PageQueryRequestDto(); + var pageIndex = pageQueryDto.PageIndex < 1 ? 1 : pageQueryDto.PageIndex; + var pageSize = pageQueryDto.PageSize < 1 ? 10 : pageQueryDto.PageSize; + + // 待办逻辑:工作项状态为"ToDo"、处理人ID为当前用户 + var toDoQuery = _sqlSugar.Queryable() + .Where(w => w.HandlerId == userId && w.Status == "ToDo") + .OrderByDescending(w => w.ReceiveTime); + + // 分页查询 + var totalCount = toDoQuery.Count(); + var toDoWorkitems = toDoQuery + .Skip((pageIndex - 1) * pageSize) + .Take(pageSize) + .ToList(); + + // 组装返回结果 + var dataList = new List(); foreach (var workitem in toDoWorkitems) { var flowInstance = _sqlSugar.Queryable() @@ -238,12 +343,11 @@ public class WorkflowEngineApp : SqlSugarBaseApp() .Where(v => v.InstanceId == flowInstance.InstanceId && v.VarKey == "Title") .First()?.VarValue ?? string.Empty; - queryResults.Add(new FlowQueryResult + dataList.Add(new FlowQuerySingleResultDto { InstanceId = flowInstance.InstanceId, BusinessNo = flowInstance.BusinessNo, @@ -255,27 +359,51 @@ public class WorkflowEngineApp : SqlSugarBaseApp + { + PageIndex = pageIndex, + PageSize = pageSize, + TotalCount = totalCount, + TotalPages = (int)Math.Ceiling((double)totalCount / pageSize), + DataList = dataList + }; } /// - /// 查询我的已办工作项 + /// 我的已办(当前用户已处理完成的事项) /// - public List QueryMyDone(long userId) + /// 当前用户ID + /// 分页参数 + /// 分页结果 + public PageQueryResultDto QueryMyDone(long userId, PageQueryRequestDto pageQueryDto) { + // 参数初始化 if (userId <= 0) - return new List(); + return new PageQueryResultDto(); + pageQueryDto = pageQueryDto ?? new PageQueryRequestDto(); + var pageIndex = pageQueryDto.PageIndex < 1 ? 1 : pageQueryDto.PageIndex; + var pageSize = pageQueryDto.PageSize < 1 ? 10 : pageQueryDto.PageSize; - // 步骤1:查询当前用户已完成的工作项对应的流程实例ID(去重) + // 已办逻辑:工作项状态为"Done"、处理人ID为当前用户(去重流程实例) var doneInstanceIds = _sqlSugar.Queryable() .Where(w => w.HandlerId == userId && w.Status == "Done") .Select(w => w.InstanceId) .Distinct() .ToList(); - // 步骤2:组装返回结果 - var queryResults = new List(); - foreach (var instanceId in doneInstanceIds) + if (!doneInstanceIds.Any()) + return new PageQueryResultDto(); + + // 分页处理实例ID + var pagedInstanceIds = doneInstanceIds + .Skip((pageIndex - 1) * pageSize) + .Take(pageSize) + .ToList(); + var totalCount = doneInstanceIds.Count; + + // 组装返回结果 + var dataList = new List(); + foreach (var instanceId in pagedInstanceIds) { var flowInstance = _sqlSugar.Queryable() .Where(i => i.InstanceId == instanceId) @@ -283,18 +411,16 @@ public class WorkflowEngineApp : SqlSugarBaseApp() .Where(v => v.InstanceId == flowInstance.InstanceId && v.VarKey == "Title") .First()?.VarValue ?? string.Empty; - // 查询最新的已完成工作项 var lastWorkitem = _sqlSugar.Queryable() - .Where(w => w.InstanceId == instanceId && w.Status == "Done") + .Where(w => w.InstanceId == instanceId && w.HandlerId == userId && w.Status == "Done") .OrderByDescending(w => w.HandleTime) .First(); - queryResults.Add(new FlowQueryResult + dataList.Add(new FlowQuerySingleResultDto { InstanceId = flowInstance.InstanceId, BusinessNo = flowInstance.BusinessNo, @@ -306,12 +432,245 @@ public class WorkflowEngineApp : SqlSugarBaseApp + { + PageIndex = pageIndex, + PageSize = pageSize, + TotalCount = totalCount, + TotalPages = (int)Math.Ceiling((double)totalCount / pageSize), + DataList = dataList + }; + } + + /// + /// 我的未办结(当前用户参与过、流程尚未完成的事项) + /// + /// 当前用户ID + /// 分页参数 + /// 分页结果 + public PageQueryResultDto QueryMyUnfinished(long userId, PageQueryRequestDto pageQueryDto) + { + // 参数初始化 + if (userId <= 0) + return new PageQueryResultDto(); + pageQueryDto = pageQueryDto ?? new PageQueryRequestDto(); + var pageIndex = pageQueryDto.PageIndex < 1 ? 1 : pageQueryDto.PageIndex; + var pageSize = pageQueryDto.PageSize < 1 ? 10 : pageQueryDto.PageSize; + + // 未办结逻辑: + // 1. 当前用户参与过(处理过/待处理) + // 2. 流程状态不是"Completed"(未完成) + var unfinishedInstanceIds = _sqlSugar.Queryable((w, i) => new JoinQueryInfos( + JoinType.Inner, w.InstanceId == i.InstanceId)) + .Where((w, i) => (w.HandlerId == userId || (w.Status == "Draft" && _auditDeptRoleIds.Contains(w.NodeId))) + && i.Status != "Completed") + .Select((w, i) => i.InstanceId) + .Distinct() + .ToList(); + + if (!unfinishedInstanceIds.Any()) + return new PageQueryResultDto(); + + // 分页处理实例ID + var pagedInstanceIds = unfinishedInstanceIds + .Skip((pageIndex - 1) * pageSize) + .Take(pageSize) + .ToList(); + var totalCount = unfinishedInstanceIds.Count; + + // 组装返回结果 + var dataList = new List(); + foreach (var instanceId in pagedInstanceIds) + { + var flowInstance = _sqlSugar.Queryable() + .Where(i => i.InstanceId == instanceId) + .First(); + if (flowInstance == null) + continue; + + var flowTitle = _sqlSugar.Queryable() + .Where(v => v.InstanceId == flowInstance.InstanceId && v.VarKey == "Title") + .First()?.VarValue ?? string.Empty; + + var currentNode = _sqlSugar.Queryable() + .Where(n => n.NodeId == flowInstance.CurrentNodeId) + .First(); + + dataList.Add(new FlowQuerySingleResultDto + { + InstanceId = flowInstance.InstanceId, + BusinessNo = flowInstance.BusinessNo, + Title = flowTitle, + NodeName = currentNode?.NodeName ?? string.Empty, + Status = flowInstance.Status, + CreateTime = flowInstance.CreateTime, + InitiatorName = flowInstance.InitiatorName + }); + } + + return new PageQueryResultDto + { + PageIndex = pageIndex, + PageSize = pageSize, + TotalCount = totalCount, + TotalPages = (int)Math.Ceiling((double)totalCount / pageSize), + DataList = dataList + }; + } + + /// + /// 我的已完成(当前用户参与过、流程已归档完成的事项) + /// + /// 当前用户ID + /// 分页参数 + /// 分页结果 + public PageQueryResultDto QueryMyCompleted(long userId, PageQueryRequestDto pageQueryDto) + { + // 参数初始化 + if (userId <= 0) + return new PageQueryResultDto(); + pageQueryDto = pageQueryDto ?? new PageQueryRequestDto(); + var pageIndex = pageQueryDto.PageIndex < 1 ? 1 : pageQueryDto.PageIndex; + var pageSize = pageQueryDto.PageSize < 1 ? 10 : pageQueryDto.PageSize; + + // 已完成逻辑: + // 1. 当前用户参与过(处理过/待处理) + // 2. 流程状态是"Completed"(已完成) + var completedInstanceIds = _sqlSugar.Queryable((w, i) => new JoinQueryInfos( + JoinType.Inner, w.InstanceId == i.InstanceId)) + .Where((w, i) => (w.HandlerId == userId || (w.Status == "Draft" && _auditDeptRoleIds.Contains(w.NodeId))) + && i.Status == "Completed") + .Select((w, i) => i.InstanceId) + .Distinct() + .ToList(); + + if (!completedInstanceIds.Any()) + return new PageQueryResultDto(); + + // 分页处理实例ID + var pagedInstanceIds = completedInstanceIds + .Skip((pageIndex - 1) * pageSize) + .Take(pageSize) + .ToList(); + var totalCount = completedInstanceIds.Count; + + // 组装返回结果 + var dataList = new List(); + foreach (var instanceId in pagedInstanceIds) + { + var flowInstance = _sqlSugar.Queryable() + .Where(i => i.InstanceId == instanceId) + .First(); + if (flowInstance == null) + continue; + + var flowTitle = _sqlSugar.Queryable() + .Where(v => v.InstanceId == flowInstance.InstanceId && v.VarKey == "Title") + .First()?.VarValue ?? string.Empty; + + var lastNode = _sqlSugar.Queryable() + .Where(n => n.NodeId == flowInstance.CurrentNodeId) + .First(); + + dataList.Add(new FlowQuerySingleResultDto + { + InstanceId = flowInstance.InstanceId, + BusinessNo = flowInstance.BusinessNo, + Title = flowTitle, + NodeName = lastNode?.NodeName ?? "流程归档", + Status = flowInstance.Status, + CreateTime = flowInstance.CreateTime, + InitiatorName = flowInstance.InitiatorName + }); + } + + return new PageQueryResultDto + { + PageIndex = pageIndex, + PageSize = pageSize, + TotalCount = totalCount, + TotalPages = (int)Math.Ceiling((double)totalCount / pageSize), + DataList = dataList + }; + } + + /// + /// 我的全部事项(拟办+待办+已办+未办结+已完成,去重整合) + /// + /// 当前用户ID + /// 分页参数 + /// 分页结果 + public PageQueryResultDto QueryMyAllItems(long userId, PageQueryRequestDto pageQueryDto) + { + // 参数初始化 + if (userId <= 0) + return new PageQueryResultDto(); + pageQueryDto = pageQueryDto ?? new PageQueryRequestDto(); + var pageIndex = pageQueryDto.PageIndex < 1 ? 1 : pageQueryDto.PageIndex; + var pageSize = pageQueryDto.PageSize < 1 ? 10 : pageQueryDto.PageSize; + + // 全部事项逻辑:当前用户相关的所有流程实例(去重) + var allInstanceIds = _sqlSugar.Queryable((w, i) => new JoinQueryInfos( + JoinType.Inner, w.InstanceId == i.InstanceId)) + .Where((w, i) => w.HandlerId == userId || (w.Status == "Draft" && _auditDeptRoleIds.Contains(w.NodeId)) + || i.InitiatorId == userId) + .Select((w, i) => i.InstanceId) + .Distinct() + .ToList(); + + if (!allInstanceIds.Any()) + return new PageQueryResultDto(); + + // 分页处理实例ID + var pagedInstanceIds = allInstanceIds + .Skip((pageIndex - 1) * pageSize) + .Take(pageSize) + .ToList(); + var totalCount = allInstanceIds.Count; + + // 组装返回结果 + var dataList = new List(); + foreach (var instanceId in pagedInstanceIds) + { + var flowInstance = _sqlSugar.Queryable() + .Where(i => i.InstanceId == instanceId) + .First(); + if (flowInstance == null) + continue; + + var flowTitle = _sqlSugar.Queryable() + .Where(v => v.InstanceId == flowInstance.InstanceId && v.VarKey == "Title") + .First()?.VarValue ?? string.Empty; + + var currentNode = _sqlSugar.Queryable() + .Where(n => n.NodeId == flowInstance.CurrentNodeId) + .First(); + + dataList.Add(new FlowQuerySingleResultDto + { + InstanceId = flowInstance.InstanceId, + BusinessNo = flowInstance.BusinessNo, + Title = flowTitle, + NodeName = currentNode?.NodeName ?? string.Empty, + Status = flowInstance.Status, + CreateTime = flowInstance.CreateTime, + InitiatorName = flowInstance.InitiatorName + }); + } + + return new PageQueryResultDto + { + PageIndex = pageIndex, + PageSize = pageSize, + TotalCount = totalCount, + TotalPages = (int)Math.Ceiling((double)totalCount / pageSize), + DataList = dataList + }; } #endregion - #region 4. 核心辅助方法(流转/会签/汇总/附件等) + #region 三、内部核心辅助方法(仅内部调用,不对外暴露) /// /// 流程节点流转核心方法 @@ -377,10 +736,10 @@ public class WorkflowEngineApp : SqlSugarBaseApp private void ProcessParallelAudit(long instanceId, long nodeId, long userId, string userName, - HandleWorkitemRequest request) + HandleWorkitemRequestDto requestDto) { // 校验会签结果 - if (string.IsNullOrEmpty(request.AuditResult)) + if (string.IsNullOrEmpty(requestDto.AuditResult)) throw new Exception("会签需选择审核结果(Pass/Reject)"); // 步骤1:获取当前用户所属科室名称 @@ -392,8 +751,8 @@ public class WorkflowEngineApp : SqlSugarBaseApp() + var hasReject = _sqlSugar.Queryable() .Where(a => a.InstanceId == flowInstance.InstanceId) - .Any(a=> a.AuditResult != "Pass"); + .Any(a => a.AuditResult != "Pass"); + var isAllPass = !hasReject; - // todo // 步骤2:解析汇总节点下一节点(归档/退回) var nextNodeIds = summaryNode.NextNodeIds?.Split(',', StringSplitOptions.RemoveEmptyEntries) .Select(long.Parse) @@ -429,13 +788,13 @@ public class WorkflowEngineApp : SqlSugarBaseApp() .Where(n => n.NodeId == targetNodeId) .First(); if (targetNode == null) - return; + throw new Exception($"汇总节点目标节点【{(isAllPass ? "归档" : "退回区县")}】不存在"); // 步骤4:创建目标节点工作项 var summaryWorkitem = new ZyFlowWorkitem @@ -448,7 +807,7 @@ public class WorkflowEngineApp : SqlSugarBaseApp - /// 获取角色下第一个用户ID - /// - private long GetRoleFirstUserId(long roleId) - { - var userInfo = GetRoleFirstUserInfo(roleId); - return userInfo.userId; - } - - /// - /// 获取角色下第一个用户姓名 - /// - private string GetRoleFirstUserName(long roleId) - { - var userInfo = GetRoleFirstUserInfo(roleId); - return userInfo.userName; - } - /// /// 获取角色下第一个用户的完整信息 /// private (long userId, string userName, string deptName) GetRoleFirstUserInfo(long roleId) { - var sql = @" - SELECT - u.""Id"" as UserId, - u.""Name"" as UserName, - o.""Name"" as DeptName - FROM sys_user u - INNER JOIN sys_userrole r ON u.""Id"" = r.""UserId"" - INNER JOIN sys_userorg uo ON u.""Id"" = uo.""UserId"" - INNER JOIN sys_org o ON uo.""OrgId"" = o.""Id"" - WHERE r.""RoleId"" = @RoleId - LIMIT 1"; - - var userInfo = _sqlSugar.SqlQueryable(sql) - .AddParameters(new { RoleId = roleId }) + var userInfo = _sqlSugar + .Queryable((o, uo, u) => new JoinQueryInfos( + JoinType.Inner, o.Id == uo.OrgId && uo.UserId == u.Id)) + .Select((o, uo, u) => new + { + UserId = u.Id, + UserName = u.Name, + DeptName = o.Name + }) .First(); + if (userInfo == null) + return (0, string.Empty, string.Empty); + return (userInfo.UserId, userInfo.UserName ?? string.Empty, userInfo.DeptName ?? string.Empty); } diff --git a/OpenAuth.Repository/Domain/workflow/ApiResult.cs b/OpenAuth.Repository/Domain/workflow/ApiResult.cs new file mode 100644 index 0000000..8118d8c --- /dev/null +++ b/OpenAuth.Repository/Domain/workflow/ApiResult.cs @@ -0,0 +1,217 @@ +using Microsoft.AspNetCore.Http; + +namespace OpenAuth.WebApi.Controllers.ServerController; + +#region 一、接口入参DTO(所有请求参数,对应Controller接收的参数) + +/// +/// 发起流程请求参数 +/// +public class InitiateFlowRequestDto +{ + /// + /// 流程编码(唯一标识流程模板,如:IllegalConstructionFlow_2026) + /// + public string FlowCode { get; set; } = string.Empty; + + /// + /// 业务编号(唯一标识该笔业务,如:WJ20260205001、XZ20260205002) + /// + public string BusinessNo { get; set; } = string.Empty; + + /// + /// 流程标题(用于展示,如:"XX区域违法建设认定申请") + /// + public string Title { get; set; } = string.Empty; + + /// + /// 上传附件列表(业务相关证明材料、表单等) + /// + public List Attachments { get; set; } = new List(); +} + +/// +/// 处理工作项请求参数 +/// +public class HandleWorkitemRequestDto +{ + /// + /// 工作项ID(待处理事项的唯一标识,从待办查询接口获取) + /// + public long WorkitemId { get; set; } + + /// + /// 处理备注(可选,记录处理意见、流转说明等) + /// + public string? Comment { get; set; } + + /// + /// 审核结果(仅会签节点必填,可选值:Pass(通过)/Reject(驳回)) + /// + public string? AuditResult { get; set; } +} + +/// +/// 分页查询通用请求参数(所有查询接口共用) +/// +public class PageQueryRequestDto +{ + /// + /// 当前页码(默认1,从1开始计数) + /// + public int PageIndex { get; set; } = 1; + + /// + /// 每页显示条数(默认10,可自定义,建议不超过50) + /// + public int PageSize { get; set; } = 10; +} + +#endregion + +#region 二、接口出参DTO(所有返回结果,对应Controller返回的数据) + +/// +/// 流程查询单条结果返回值(所有查询接口的单条数据格式) +/// +public class FlowQuerySingleResultDto +{ + /// + /// 流程实例ID(唯一标识该流程实例,用于后续操作) + /// + public long InstanceId { get; set; } + + /// + /// 业务编号(对应发起流程时的BusinessNo) + /// + public string BusinessNo { get; set; } = string.Empty; + + /// + /// 流程标题(对应发起流程时的Title) + /// + public string Title { get; set; } = string.Empty; + + /// + /// 当前节点名称(如:"区县提交"、"政策法规科审核"、"汇总归档") + /// + public string NodeName { get; set; } = string.Empty; + + /// + /// 流程状态(枚举值:Draft(拟办)、Submitted(已提交)、Forwarded(已转发)、Auditing(审核中)、Summarized(已汇总)、Completed(已完成)、Rejected(已驳回)) + /// + public string Status { get; set; } = string.Empty; + + /// + /// 流程发起时间 + /// + public DateTime? CreateTime { get; set; } + + /// + /// 发起人姓名 + /// + public string InitiatorName { get; set; } = string.Empty; +} + +/// +/// 分页查询通用返回值(所有分页查询接口共用,泛型适配不同数据列表) +/// +/// 数据列表的泛型类型(如:FlowQuerySingleResultDto) +public class PageQueryResultDto +{ + /// + /// 当前页码(与请求参数的PageIndex对应) + /// + public int PageIndex { get; set; } + + /// + /// 每页显示条数(与请求参数的PageSize对应) + /// + public int PageSize { get; set; } + + /// + /// 总记录数(符合查询条件的所有数据条数) + /// + public long TotalCount { get; set; } + + /// + /// 总页数(自动计算:TotalCount / PageSize,向上取整) + /// + public int TotalPages { get; set; } + + /// + /// 当前页的数据列表 + /// + public List DataList { get; set; } = new List(); +} + +/// +/// 接口全局统一响应格式(所有接口返回结果的统一封装,提高前端对接效率) +/// +/// 响应数据的泛型类型(如:long、bool、PageQueryResultDto +public class ApiResponseDto +{ + /// + /// 响应状态码(200:操作成功,500:操作失败,400:参数错误/未登录,404:资源不存在) + /// + public int Code { get; set; } = 200; + + /// + /// 响应消息(成功时返回"操作成功",失败时返回具体错误信息) + /// + public string Message { get; set; } = "操作成功"; + + /// + /// 响应数据(成功时返回具体业务数据,失败时可返回null或附加说明数据) + /// + public T? Data { get; set; } + + /// + /// 构建成功响应(静态方法,简化Controller调用) + /// + /// 成功时的业务数据 + /// 自定义成功消息(可选,默认"操作成功") + /// 统一响应格式对象 + public static ApiResponseDto Success(T? data = default, string message = "操作成功") + { + return new ApiResponseDto + { + Code = 200, + Message = message, + Data = data + }; + } + + /// + /// 构建失败响应(静态方法,简化Controller调用) + /// + /// 具体错误消息 + /// 失败时的附加数据(可选,默认null) + /// 统一响应格式对象 + public static ApiResponseDto Fail(string message = "操作失败", T? data = default) + { + return new ApiResponseDto + { + Code = 500, + Message = message, + Data = data + }; + } + + /// + /// 构建参数错误/未登录响应(静态方法,适配400状态码场景) + /// + /// 具体错误消息 + /// 附加数据(可选) + /// 统一响应格式对象 + public static ApiResponseDto BadRequest(string message = "参数错误或未登录", T? data = default) + { + return new ApiResponseDto + { + Code = 400, + Message = message, + Data = data + }; + } +} + +#endregion \ No newline at end of file diff --git a/OpenAuth.Repository/Domain/workflow/InitiateFlowRequest.cs b/OpenAuth.Repository/Domain/workflow/InitiateFlowRequest.cs deleted file mode 100644 index c9f779f..0000000 --- a/OpenAuth.Repository/Domain/workflow/InitiateFlowRequest.cs +++ /dev/null @@ -1,91 +0,0 @@ -using Microsoft.AspNetCore.Http; - -namespace OpenAuth.Repository.Domain.workflow; - -/// -/// 发起流程请求DTO -/// -public class InitiateFlowRequest -{ - /// - /// 流程编码 - /// - public string FlowCode { get; set; } = string.Empty; - - /// - /// 业务编号 - /// - public string BusinessNo { get; set; } = string.Empty; - - /// - /// 流程标题 - /// - public string Title { get; set; } = string.Empty; - - /// - /// 附件列表 - /// - public List? Attachments { get; set; } -} - -/// -/// 处理工作项请求DTO -/// -public class HandleWorkitemRequest -{ - /// - /// 工作项ID - /// - public long WorkitemId { get; set; } - - /// - /// 处理意见 - /// - public string? Comment { get; set; } - - /// - /// 会签结果(Pass/Reject) - /// - public string? AuditResult { get; set; } -} - -/// -/// 流程查询结果DTO -/// -public class FlowQueryResult -{ - /// - /// 流程实例ID - /// - public long InstanceId { get; set; } - - /// - /// 业务编号 - /// - public string BusinessNo { get; set; } = string.Empty; - - /// - /// 流程标题 - /// - public string Title { get; set; } = string.Empty; - - /// - /// 当前节点名称 - /// - public string NodeName { get; set; } = string.Empty; - - /// - /// 流程状态 - /// - public string Status { get; set; } = string.Empty; - - /// - /// 创建时间 - /// - public DateTime? CreateTime { get; set; } - - /// - /// 发起人姓名 - /// - public string InitiatorName { get; set; } = string.Empty; -} \ No newline at end of file diff --git a/OpenAuth.WebApi/Controllers/ServerController/ApiResult.cs b/OpenAuth.WebApi/Controllers/ServerController/ApiResult.cs deleted file mode 100644 index c87cfd6..0000000 --- a/OpenAuth.WebApi/Controllers/ServerController/ApiResult.cs +++ /dev/null @@ -1,95 +0,0 @@ -namespace OpenAuth.WebApi.Controllers.ServerController; - -/// -/// 统一API返回结果 -/// -/// -public class ApiResult -{ - public bool Success { get; set; } - public string Message { get; set; } - public T Data { get; set; } - public int TotalCount { get; set; } // 分页总条数 - - public static ApiResult Ok(T data, int totalCount = 0, string message = "操作成功") - { - return new ApiResult - { - Success = true, - Message = message, - Data = data, - TotalCount = totalCount - }; - } - - public static ApiResult Error(string message = "操作失败") - { - return new ApiResult - { - Success = false, - Message = message, - Data = default(T), - TotalCount = 0 - }; - } -} - -// 通用分页输入 -public class PageInput -{ - public int PageIndex { get; set; } = 1; - public int PageSize { get; set; } = 10; -} - -// 通用分页输出 -public class PageOutput -{ - public int PageIndex { get; set; } - public int PageSize { get; set; } - public long TotalCount { get; set; } - public int TotalPages { get; set; } - public List Data { get; set; } = new List(); -} - -// 发起流程请求 -public class InitiateFlowRequest -{ - public string FlowCode { get; set; } = string.Empty; - public string BusinessNo { get; set; } = string.Empty; - public string Title { get; set; } = string.Empty; - public List? Attachments { get; set; } -} - -// 处理工作项请求 -public class HandleWorkitemRequest -{ - public long WorkitemId { get; set; } - public string? Comment { get; set; } - public string? AuditResult { get; set; } // Pass/Reject -} - -// 工作项查询结果(拟办/待办/已办) -public class FlowQueryResult -{ - public long InstanceId { get; set; } - public string BusinessNo { get; set; } = string.Empty; - public string Title { get; set; } = string.Empty; - public string NodeName { get; set; } = string.Empty; - public string Status { get; set; } = string.Empty; - public DateTime? CreateTime { get; set; } - public string InitiatorName { get; set; } = string.Empty; -} - -// 流程实例查询结果(未办结/已完成) -public class FlowInstanceQueryResult -{ - public long InstanceId { get; set; } - public string BusinessNo { get; set; } = string.Empty; - public string FlowName { get; set; } = string.Empty; - public string Title { get; set; } = string.Empty; - public string CurrentNodeName { get; set; } = string.Empty; - public string Status { get; set; } = string.Empty; - public string InitiatorName { get; set; } = string.Empty; - public DateTime? CreateTime { get; set; } - public DateTime? FinishTime { get; set; } -} \ No newline at end of file diff --git a/OpenAuth.WebApi/Controllers/ServerController/CustomWorkflowController.cs b/OpenAuth.WebApi/Controllers/ServerController/CustomWorkflowController.cs index b4cab19..382ed56 100644 --- a/OpenAuth.WebApi/Controllers/ServerController/CustomWorkflowController.cs +++ b/OpenAuth.WebApi/Controllers/ServerController/CustomWorkflowController.cs @@ -6,186 +6,235 @@ using workflow; namespace OpenAuth.WebApi.Controllers.ServerController; +using Microsoft.AspNetCore.Mvc; +using OpenAuth.App.Interface; + +/// +/// 工作流核心API接口(流程发起/处理 + 拟办/待办/已办/未办结/已完成/全部事项查询) +/// [ApiController] -[Route("api/[controller]")] -public class CustomWorkflowController : ControllerBase +[Route("api/[controller]/[action]")] +public class WorkflowController : ControllerBase { private readonly WorkflowEngineApp _workflowEngineApp; private readonly IAuth _auth; - public CustomWorkflowController(WorkflowEngineApp workflowEngineApp, IAuth auth) + // 构造函数注入依赖 + public WorkflowController(WorkflowEngineApp workflowEngineApp, IAuth auth) { _workflowEngineApp = workflowEngineApp; _auth = auth; } - #region 基础接口 + #region 一、流程操作接口 - [HttpGet("user/by-role/{roleId:long}")] - public IActionResult GetUserNameByRoleId(long roleId) + /// + /// 发起流程(区县提交) + /// + /// 发起流程请求参数 + /// 流程实例ID + [HttpPost] + public ActionResult> InitiateFlow([FromForm] InitiateFlowRequestDto requestDto) { try { - var userName = _workflowEngineApp.GetUserNameByRoleId(roleId); - return Ok(new { Success = true, Data = userName }); + // 获取当前登录用户(实际项目中从Token/IAuth中解析) + var currentUser = _auth.GetCurrentUser().User; + if (currentUser == null) + return BadRequest(ApiResponseDto.Fail("未登录或登录过期")); + + var instanceId = _workflowEngineApp.InitiateFlow( + currentUser.Id, + currentUser.Name, + requestDto); + + return Ok(ApiResponseDto.Success(instanceId, "流程发起成功")); } catch (Exception ex) { - return BadRequest(new { Success = false, Message = ex.Message }); + return StatusCode(500, ApiResponseDto.Fail(ex.Message)); + } + } + + /// + /// 处理工作项(执法监督科转发/审核科会签/汇总处理) + /// + /// 处理工作项请求参数 + /// 处理结果 + [HttpPost] + public ActionResult> HandleWorkitem([FromBody] HandleWorkitemRequestDto requestDto) + { + try + { + // 获取当前登录用户(实际项目中从Token/IAuth中解析) + var currentUser = _auth.GetCurrentUser().User; + if (currentUser == null) + return BadRequest(ApiResponseDto.Fail("未登录或登录过期")); + + var result = _workflowEngineApp.HandleWorkitem( + currentUser.Id, + currentUser.Name, + requestDto); + + return Ok(ApiResponseDto.Success(result, "工作项处理成功")); + } + catch (Exception ex) + { + return StatusCode(500, ApiResponseDto.Fail(ex.Message)); } } #endregion - #region 流程表单接口 + #region 二、完整查询接口(拟办/待办/已办/未办结/已完成/全部事项) - [HttpPost("flow/initiate")] - public IActionResult InitiateAssessmentFlow([FromBody] InitiateAssessmentFlowRequest request) + /// + /// 查询我的拟办(未认领/待分配事项) + /// + /// 分页查询参数 + /// 分页拟办结果 + [HttpGet] + public ActionResult>> QueryMyDraft( + [FromQuery] PageQueryRequestDto pageQueryDto) { try { - var currentUser = _auth.GetCurrentUser()?.User; + var currentUser = _auth.GetCurrentUser().User; if (currentUser == null) - return Unauthorized(new { Success = false, Message = "未登录" }); + return BadRequest(ApiResponseDto>.Fail("未登录或登录过期")); - var instanceId = _workflowEngineApp.InitiateAssessmentFlow(currentUser.Id, currentUser.Name, request); - return Ok(new { Success = true, Data = new { FlowInstanceId = instanceId } }); + var result = _workflowEngineApp.QueryMyDraft(currentUser.Id, pageQueryDto); + + return Ok(ApiResponseDto>.Success(result, "拟办查询成功")); } catch (Exception ex) { - return BadRequest(new { Success = false, Message = ex.Message }); + return StatusCode(500, ApiResponseDto>.Fail(ex.Message)); } } - [HttpGet("flow/by-business/{businessNumber}")] - public IActionResult QueryAssessmentFlowByBusinessNo(string businessNumber) + /// + /// 查询我的待办(已分配/待处理事项) + /// + /// 分页查询参数 + /// 分页待办结果 + [HttpGet] + public ActionResult>> QueryMyToDo( + [FromQuery] PageQueryRequestDto pageQueryDto) { try { - var result = _workflowEngineApp.QueryAssessmentFlowByBusinessNo(businessNumber); - return Ok(new { Success = true, Data = result }); - } - catch (Exception ex) - { - return BadRequest(new { Success = false, Message = ex.Message }); - } - } - - [HttpPut("form/update")] - public IActionResult UpdateAssessmentForm([FromBody] IllegalConstructionAssessment form) - { - try - { - var currentUser = _auth.GetCurrentUser()?.User; + var currentUser = _auth.GetCurrentUser().User; if (currentUser == null) - return Unauthorized(new { Success = false, Message = "未登录" }); + return BadRequest(ApiResponseDto>.Fail("未登录或登录过期")); - var success = _workflowEngineApp.UpdateAssessmentForm(form, currentUser.Id); - return Ok(new { Success = success, Message = success ? "更新成功" : "更新失败" }); + var result = _workflowEngineApp.QueryMyToDo(currentUser.Id, pageQueryDto); + + return Ok(ApiResponseDto>.Success(result, "待办查询成功")); } catch (Exception ex) { - return BadRequest(new { Success = false, Message = ex.Message }); + return StatusCode(500, ApiResponseDto>.Fail(ex.Message)); } } - [HttpPost("form/page")] - public IActionResult QueryAllAssessmentForms([FromBody] PageQueryInput pageInput) + /// + /// 查询我的已办(已处理完成事项) + /// + /// 分页查询参数 + /// 分页已办结果 + [HttpGet] + public ActionResult>> QueryMyDone( + [FromQuery] PageQueryRequestDto pageQueryDto) { try { - var result = _workflowEngineApp.QueryAllAssessmentForms(pageInput); - return Ok(new { Success = true, Data = result }); - } - catch (Exception ex) - { - return BadRequest(new { Success = false, Message = ex.Message }); - } - } - - #endregion - - #region 待办查询接口 - - [HttpPost("flow/draft/{userId:long}")] - public IActionResult QueryMyDraft(long userId, [FromBody] PageQueryInput pageInput) - { - try - { - var result = _workflowEngineApp.QueryMyDraft(userId, pageInput); - return Ok(new { Success = true, Data = result }); - } - catch (Exception ex) - { - return BadRequest(new { Success = false, Message = ex.Message }); - } - } - - [HttpPost("flow/todo/{userId:long}")] - public IActionResult QueryMyToDo(long userId, [FromBody] PageQueryInput pageInput) - { - try - { - var result = _workflowEngineApp.QueryMyToDo(userId, pageInput); - return Ok(new { Success = true, Data = result }); - } - catch (Exception ex) - { - return BadRequest(new { Success = false, Message = ex.Message }); - } - } - - [HttpPost("flow/done/{userId:long}")] - public IActionResult QueryMyDone(long userId, [FromBody] PageQueryInput pageInput) - { - try - { - var result = _workflowEngineApp.QueryMyDone(userId, pageInput); - return Ok(new { Success = true, Data = result }); - } - catch (Exception ex) - { - return BadRequest(new { Success = false, Message = ex.Message }); - } - } - - #endregion - - #region 待办处理接口 - - [HttpPost("flow/workitem/claim/{workitemId:long}/{userId:long}")] - public IActionResult ClaimDraftWorkitem(long workitemId, long userId) - { - try - { - var currentUser = _auth.GetCurrentUser()?.User; + var currentUser = _auth.GetCurrentUser().User; if (currentUser == null) - return Unauthorized(new { Success = false, Message = "未登录" }); + return BadRequest(ApiResponseDto>.Fail("未登录或登录过期")); - var success = _workflowEngineApp.ClaimDraftWorkitem(workitemId, userId, currentUser.Name); - return Ok(new { Success = success, Message = success ? "认领成功" : "认领失败" }); + var result = _workflowEngineApp.QueryMyDone(currentUser.Id, pageQueryDto); + + return Ok(ApiResponseDto>.Success(result, "已办查询成功")); } catch (Exception ex) { - return BadRequest(new { Success = false, Message = ex.Message }); + return StatusCode(500, ApiResponseDto>.Fail(ex.Message)); } } - [HttpPost("flow/workitem/handle/{userId:long}")] - public IActionResult HandleWorkitem(long userId, [FromBody] HandleWorkitemRequest request) + /// + /// 查询我的未办结(参与过/流程未完成事项) + /// + /// 分页查询参数 + /// 分页未办结结果 + [HttpGet] + public ActionResult>> QueryMyUnfinished( + [FromQuery] PageQueryRequestDto pageQueryDto) { try { - var currentUser = _auth.GetCurrentUser()?.User; + var currentUser = _auth.GetCurrentUser().User; if (currentUser == null) - return Unauthorized(new { Success = false, Message = "未登录" }); + return BadRequest(ApiResponseDto>.Fail("未登录或登录过期")); - var success = _workflowEngineApp.HandleWorkitem(userId, currentUser.Name, request); - return Ok(new { Success = success, Message = success ? "处理成功" : "处理失败" }); + var result = _workflowEngineApp.QueryMyUnfinished(currentUser.Id, pageQueryDto); + + return Ok(ApiResponseDto>.Success(result, "未办结查询成功")); } catch (Exception ex) { - return BadRequest(new { Success = false, Message = ex.Message }); + return StatusCode(500, ApiResponseDto>.Fail(ex.Message)); + } + } + + /// + /// 查询我的已完成(参与过/流程已归档事项) + /// + /// 分页查询参数 + /// 分页已完成结果 + [HttpGet] + public ActionResult>> QueryMyCompleted( + [FromQuery] PageQueryRequestDto pageQueryDto) + { + try + { + var currentUser = _auth.GetCurrentUser().User; + if (currentUser == null) + return BadRequest(ApiResponseDto>.Fail("未登录或登录过期")); + + var result = _workflowEngineApp.QueryMyCompleted(currentUser.Id, pageQueryDto); + + return Ok(ApiResponseDto>.Success(result, "已完成查询成功")); + } + catch (Exception ex) + { + return StatusCode(500, ApiResponseDto>.Fail(ex.Message)); + } + } + + /// + /// 查询我的全部事项(拟办+待办+已办+未办结+已完成) + /// + /// 分页查询参数 + /// 分页全部事项结果 + [HttpGet] + public ActionResult>> QueryMyAllItems( + [FromQuery] PageQueryRequestDto pageQueryDto) + { + try + { + var currentUser = _auth.GetCurrentUser().User; + if (currentUser == null) + return BadRequest(ApiResponseDto>.Fail("未登录或登录过期")); + + var result = _workflowEngineApp.QueryMyAllItems(currentUser.Id, pageQueryDto); + + return Ok(ApiResponseDto>.Success(result, "全部事项查询成功")); + } + catch (Exception ex) + { + return StatusCode(500, ApiResponseDto>.Fail(ex.Message)); } }