identificationOfCultivatedL.../OpenAuth.App/workflow/WorkflowEngineApp.cs

1393 lines
58 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using Microsoft.AspNetCore.Http;
using OpenAuth.App.BaseApp.Base;
using OpenAuth.App.FormScheme.FormHelpers;
using OpenAuth.App.Interface;
using OpenAuth.Repository;
using OpenAuth.Repository.Domain;
using OpenAuth.Repository.Domain.workflow;
using SqlSugar;
namespace OpenAuth.App.workflow;
/// <summary>
/// 完整工作流引擎适配区县→执法监督科→5个审核科会签→汇总归档/退回)
/// 包含:流程发起/处理 + 拟办/待办/已办/未办结/已完成/全部事项查询
/// </summary>
public class WorkflowEngineApp : SqlSugarBaseApp<SysCategoryType, SugarDbContext>
{
private readonly ISqlSugarClient _sqlSugar;
private readonly BusinessNoGenerator _businessNoGenerator;
private readonly string prefix = "wfjszl";
public WorkflowEngineApp(ISugarUnitOfWork<SugarDbContext> unitWork, ISimpleClient<SysCategoryType> repository,
IAuth auth, BusinessNoGenerator businessNoGenerator) : base(unitWork, repository, auth)
{
_sqlSugar = Repository.AsSugarClient();
_businessNoGenerator = businessNoGenerator;
}
#region 一、核心业务:流程发起/处理
/// <summary>
/// 发起流程(区县提交→流转至执法监督科)
/// </summary>
/// <param name="userId">发起人ID</param>
/// <param name="userName">发起人姓名</param>
/// <param name="requestDto">发起流程请求参数</param>
/// <returns>流程实例ID</returns>
public long InitiateFlow(long userId, string userName, InitiateFlowRequestDto requestDto)
{
var org = _auth.GetCurrentUser().Orgs.First();
// 参数校验
/*if (string.IsNullOrEmpty(requestDto.FlowCode) || string.IsNullOrEmpty(requestDto.BusinessNo))
throw new Exception("流程编码和业务编号不能为空");*/
if (userId <= 0 || string.IsNullOrEmpty(userName))
throw new Exception("发起人ID和姓名不能为空");
var instanceId = 0L;
try
{
// 步骤1查询启用的流程模板违法建设认定流程
var template = _sqlSugar.Queryable<ZyFlowTemplate>()
.Where(t => t.FlowCode == requestDto.FlowCode && t.IsEnabled == true)
.First();
if (template == null)
throw new Exception($"流程模板【{requestDto.FlowCode}】不存在或未启用");
var startNode = _sqlSugar.Queryable<ZyFlowNode>()
.Where(n => n.TemplateId == template.TemplateId && n.NodeType == "Start" && n.NodeName == "区县提交")
.First();
if (startNode == null)
throw new Exception("流程开始节点【区县提交】不存在,请配置节点");
// 是否存在拟办数据
if (!string.IsNullOrEmpty(requestDto.BusinessNo) && _sqlSugar
.Queryable<IllegalConstructionAssessment>()
.Any(a => a.BusinessNumber == requestDto.BusinessNo))
{
// 开启事务基于UnitWork保障数据一致性
UnitWork.Db.Ado.BeginTran();
// 关于直接提交拟办,并提交,并未保存的处理
var illegal = _sqlSugar.Queryable<IllegalConstructionAssessment>()
.Where(a => a.Id == requestDto.BusinessNo).First();
illegal.UpdateTime = DateTime.Now;
illegal.Status = "Submitted";
// 字段是否有更新
if (!string.IsNullOrEmpty(requestDto.Title))
{
illegal.Title = requestDto.Title;
}
if (!requestDto.Attachments.IsEmpty())
{
var attachmentPaths = string.Join(",", requestDto.Attachments);
illegal.Attachments = attachmentPaths;
}
if (requestDto.Type != null)
{
illegal.Type = requestDto.Type;
}
// 方案1明确指定要更新的列避免主键冲突
_sqlSugar.Updateable(illegal)
.IgnoreNullColumns().ExecuteCommand();
// 或者方案2使用 Where 条件更新
// _sqlSugar.Updateable<IllegalConstructionAssessment>()
// .SetColumns(it => new { it.UpdateTime = DateTime.Now, it.Status = "Submitted" })
// .Where(it => it.Id == requestDto.BusinessNo)
// .ExecuteCommand();
var flowInstance = _sqlSugar.Queryable<ZyFlowInstance>()
.Where(a => a.BusinessNo == requestDto.BusinessNo).First();
instanceId = flowInstance.InstanceId;
flowInstance.InstanceId = instanceId;
flowInstance.Status = "Submitted";
_sqlSugar.Updateable(flowInstance).IgnoreNullColumns().ExecuteCommand();
var flowWorkItem = _sqlSugar.Queryable<ZyFlowWorkitem>()
.Where(a => a.InstanceId == instanceId
&& a.NodeId == startNode.NodeId
&& a.Status == "Draft").First();
if (flowWorkItem == null)
{
throw new Exception("流程工作项不存在");
}
flowWorkItem.WorkitemId = flowWorkItem.WorkitemId;
flowWorkItem.Status = "Done";
flowWorkItem.HandleTime = DateTime.Now;
flowWorkItem.Comment = "区县提交";
flowWorkItem.OrgId = org.Id;
flowWorkItem.OrgName = org.Name;
_sqlSugar.Updateable(flowWorkItem).IgnoreNullColumns().ExecuteCommand();
}
else
{
// 取号
var businessNo = _businessNoGenerator.GenerateBusinessNo(prefix);
requestDto.BusinessNo = businessNo;
// 开启事务基于UnitWork保障数据一致性
UnitWork.Db.Ado.BeginTran();
var illegal = new IllegalConstructionAssessment()
{
Id = requestDto.BusinessNo,
Title = requestDto.Title,
BusinessNumber = requestDto.BusinessNo,
Type = requestDto.Type,
CreateTime = DateTime.Now,
CreateUser = userName,
UpdateTime = DateTime.Now,
};
if (!requestDto.Attachments.IsEmpty())
{
var attachmentPaths = string.Join(",", requestDto.Attachments);
illegal.Attachments = attachmentPaths;
}
_sqlSugar.Insertable(illegal).ExecuteCommand();
// 步骤2查询流程开始节点区县提交
// 步骤3插入流程实例返回自增主键
var flowInstance = new ZyFlowInstance
{
TemplateId = template.TemplateId,
FlowCode = template.FlowCode,
BusinessNo = requestDto.BusinessNo,
Status = "Submitted", // 已提交
CurrentNodeId = startNode.NodeId,
InitiatorId = userId,
InitiatorName = userName,
CreateTime = DateTime.Now
};
instanceId = _sqlSugar.Insertable(flowInstance).ExecuteReturnIdentity();
// 步骤4插入开始节点工作项直接标记为已完成
// 开始节点无ToDo
var startWorkitem = new ZyFlowWorkitem
{
InstanceId = instanceId,
NodeId = startNode.NodeId,
NodeName = startNode.NodeName,
HandlerId = userId,
HandlerName = userName,
Status = "Done", // 已完成
ReceiveTime = DateTime.Now,
HandleTime = DateTime.Now,
Comment = "提交材料",
OrgId = org.Id,
OrgName = org.Name
};
_sqlSugar.Insertable(startWorkitem).ExecuteCommand();
// 步骤5保存流程变量标题、附件路径等
//var attachmentPaths = SaveAttachments(requestDto.Attachments);
}
// 避免驳回提交数据影响
_sqlSugar.Deleteable<ZyFlowVariable>().Where(a => a.InstanceId == instanceId).ExecuteCommand();
var flowVariables = new List<ZyFlowVariable>
{
new() { InstanceId = instanceId, VarKey = "Title", VarValue = requestDto.Title },
new()
{
InstanceId = instanceId, VarKey = "SubmitTime",
VarValue = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
},
new() { InstanceId = instanceId, VarKey = "Type", VarValue = requestDto.Type.ToString() },
};
if (!requestDto.Attachments.IsEmpty())
{
var attachmentPaths = string.Join(",", requestDto.Attachments);
var x = new ZyFlowVariable()
{ InstanceId = instanceId, VarKey = "AttachmentPaths", VarValue = attachmentPaths };
flowVariables.Add(x);
}
_sqlSugar.Insertable(flowVariables).ExecuteCommand();
// 步骤6核心流转从区县提交节点流转至执法监督科节点
FlowToNextNode(instanceId, startNode, userId, userName, "区县提交完成,流转至执法监督科");
// 提交事务
UnitWork.Db.Ado.CommitTran();
}
catch (Exception ex)
{
// 回滚事务
UnitWork.Db.Ado.RollbackTran();
throw new Exception($"发起流程失败:{ex.Message}", ex);
}
return instanceId;
}
/// <summary>
/// 处理工作项(执法监督科转发/审核科会签/汇总处理)
/// </summary>
/// <param name="userId">处理人ID</param>
/// <param name="userName">处理人姓名</param>
/// <param name="requestDto">处理工作项请求参数</param>
/// <returns>处理结果(成功/失败)</returns>
public bool HandleWorkitem(long userId, string userName, HandleWorkitemRequestDto requestDto)
{
var orgs = _auth.GetCurrentUser().Orgs.First();
// 参数校验
if (requestDto.WorkitemId <= 0)
throw new Exception("工作项ID无效");
if (userId <= 0 || string.IsNullOrEmpty(userName))
throw new Exception("处理人ID和姓名不能为空");
try
{
// 开启事务
UnitWork.Db.Ado.BeginTran();
// 步骤1查询待处理的工作项仅待办状态可处理
var workitem = _sqlSugar.Queryable<ZyFlowWorkitem>()
.Where(w => w.WorkitemId == requestDto.WorkitemId && w.Status == "ToDo")
.First();
if (workitem == null)
throw new Exception("工作项不存在、已处理或状态异常");
// 步骤2查询关联的流程实例和当前节点
var flowInstance = _sqlSugar.Queryable<ZyFlowInstance>()
.Where(i => i.InstanceId == workitem.InstanceId)
.First();
var currentNode = _sqlSugar.Queryable<ZyFlowNode>()
.Where(n => n.NodeId == workitem.NodeId)
.First();
if (flowInstance == null || currentNode == null)
throw new Exception("流程实例或流程节点不存在");
// 步骤3更新当前工作项为已完成
workitem.Status = "Done";
workitem.HandleTime = DateTime.Now;
workitem.HandlerId = userId;
workitem.HandlerName = userName;
// 当前处理人的部门 一个人只有一个部门, 一个角色不一定只有一个部门
workitem.OrgId = orgs.Id;
workitem.OrgName = orgs.Name;
// 默认Pass
workitem.AuditResult = string.IsNullOrEmpty(requestDto.AuditResult) ? "Pass" : requestDto.AuditResult;
var comment = requestDto.Comment;
_sqlSugar.Updateable(workitem).ExecuteCommand();
// 生成下一节点数据
// 步骤4按节点类型分支处理核心逻辑
switch (currentNode.NodeType)
{
// 普通节点:执法监督科转发
//case "Common" when currentNode.NodeName == "执法监督科转发":
case "Common":
comment = "下发到审核科室";
FlowToNextNode(flowInstance.InstanceId,
currentNode, userId, userName, workitem.Comment, requestDto);
break;
case "Parallel":
if (requestDto.AuditResult == "Pass")
{
comment = "审核通过";
}
ProcessParallelAudit(flowInstance.InstanceId, currentNode.NodeId, userId, userName, requestDto);
/*var nextNodeId = long.Parse(currentNode.NextNodeIds.Split(',')[0]);
var hasNextWorkItem = _sqlSugar.Queryable<ZyFlowWorkitem>()
.Where(w => w.InstanceId == flowInstance.InstanceId
&& w.Status == "ToDo"
&& w.NodeId == nextNodeId).First();
if (hasNextWorkItem != null)
{
var nextNode = _sqlSugar.Queryable<ZyFlowNode>()
.Where(a => a.NodeId == nextNodeId).First();
// 更新脚本节点
var scriptNodeWorkItem = new ZyFlowWorkitem()
{
WorkitemId = hasNextWorkItem.WorkitemId,
Status = "Done"
};
//_sqlSugar.Updateable(scriptNodeWorkItem).ExecuteCommand();
_sqlSugar.Updateable<ZyFlowWorkitem>()
.SetColumns(t => new ZyFlowWorkitem() { Status = "Done" })
.Where(t => t.WorkitemId == hasNextWorkItem.WorkitemId).ExecuteCommand();
// 判断是归档还是驳回
ProcessSummaryNode(flowInstance, nextNode, userId, userName);
}*/
break;
// 分支节点:汇总(归档/退回区县)
case "Branch" when currentNode.NodeName == "汇总判断":
if (requestDto.AuditResult == "Pass")
{
comment = "归档";
}
ProcessSummaryNode(flowInstance, currentNode, userId, userName, requestDto);
break;
// 结束节点:流程归档完成
case "End":
CompleteFlowInstance(flowInstance);
break;
}
workitem.Comment = comment;
_sqlSugar.Updateable(workitem).ExecuteCommand();
// 提交事务
UnitWork.Db.Ado.CommitTran();
return true;
}
catch (Exception ex)
{
// 回滚事务
UnitWork.Db.Ado.RollbackTran();
throw new Exception($"处理工作项失败:{ex.Message}", ex);
}
}
#endregion
#region 二、完整查询:拟办/待办/已办/未办结/已完成/全部事项
/// <summary>
/// 我的拟办(未认领/待分配给当前用户的事项)
/// </summary>
/// <param name="userId">当前用户ID</param>
/// <param name="pageQueryDto">分页参数</param>
/// <returns>分页结果</returns>
public PageQueryResultDto<FlowQuerySingleResultDto> QueryMyDraft(long userId, PageQueryRequestDto pageQueryDto)
{
// 参数初始化
if (userId <= 0)
return new PageQueryResultDto<FlowQuerySingleResultDto>();
pageQueryDto ??= new PageQueryRequestDto();
var pageIndex = pageQueryDto.page < 1 ? 1 : pageQueryDto.page;
var pageSize = pageQueryDto.limit < 1 ? 10 : pageQueryDto.limit;
// 一个实例,工作项中只有一个拟办,不用去重
// 拟办不应该是针对个人的吗?
// 拟办逻辑:工作项状态为"Draft"(拟办)、对应角色匹配当前用户、未分配具体处理人
var draftQuery = _sqlSugar
.Queryable<IllegalConstructionAssessment>()
.LeftJoin<ZyFlowInstance>((t, i)
=> t.BusinessNumber == i.BusinessNo)
.LeftJoin<ZyFlowNode>((t, i, n)
=> i.CurrentNodeId == n.NodeId)
.LeftJoin<ZyFlowWorkitem>((t, i, n, w)
=> i.InstanceId == w.InstanceId)
.WhereIF(!string.IsNullOrEmpty(pageQueryDto.key), (t, i, n, w)
=> t.BusinessNumber.Contains(pageQueryDto.key))
.Where((t, i, n, w) =>
w.Status == "Draft" && i.InitiatorId == userId)
.OrderByDescending((t, i, n, w) =>
t.CreateTime)
.Select((t, i, n, w)
=> new FlowQuerySingleResultDto
{
workitemId = w.WorkitemId,
InstanceId = i.InstanceId,
NodeName = n.NodeName,
Status = i.Status, // 工作项状态
WorkStatus = w.Status,
BusinessNo = t.BusinessNumber,
Title = t.Title,
Type = t.Type,
CreateTime = t.CreateTime,
HandleTime = w.HandleTime,
InitiatorName = t.CreateUser //发起人姓名
});
// 分页查询
var totalCount = draftQuery.Count();
var dataList = draftQuery
.Skip((pageIndex - 1) * pageSize)
.Take(pageSize)
.ToList();
return new PageQueryResultDto<FlowQuerySingleResultDto>
{
Page = pageIndex,
Limit = pageSize,
Total = totalCount,
TotalPages = (int)Math.Ceiling((double)totalCount / pageSize),
Items = dataList
};
}
/// <summary>
/// 我的待办(已分配给当前用户、待处理的事项)
/// </summary>
/// <param name="userId">当前用户ID</param>
/// <param name="pageQueryDto">分页参数</param>
/// <returns>分页结果</returns>
public PageQueryResultDto<FlowQuerySingleResultDto> QueryMyToDo(long userId, PageQueryRequestDto pageQueryDto)
{
var orgs = _auth.GetCurrentUser().Orgs.Select(a => a.Id).ToList();
// 参数初始化
if (userId <= 0)
return new PageQueryResultDto<FlowQuerySingleResultDto>();
pageQueryDto ??= new PageQueryRequestDto();
var pageIndex = pageQueryDto.page < 1 ? 1 : pageQueryDto.page;
var pageSize = pageQueryDto.limit < 1 ? 10 : pageQueryDto.limit;
// 当是区县用户时: 没有ToDo 只有拟办 及已办
// 当时监督科用户时工作项状态ToDo 且用户角色能处理的节点 且 handler_id == null
// 当时审核科用户时handler_id 必须等于用户id
// 现添加部门限制 主要针对审核角色存在多个部门用户的情况
var nodeIdList = _sqlSugar.Queryable<ZyFlowNode>()
// 核心In(主表字段, 子查询Lambda表达式)
.In(
zy => zy.RoleId, // 主表 zy_flow_node 的 role_id 字段
// 子查询:从 sys_userrole 中查询 UserId=2 的 RoleId
_sqlSugar.Queryable<SysUserRole>()
.Where(ur => ur.UserId == userId) // 条件UserId=2注意这里直接用数值避免字符串拼接
.Select(ur => ur.RoleId) // 子查询只返回 RoleId 字段
)
// 主查询只返回 node_id 字段(提升查询性能,避免查询全表字段)
.Select(zy => zy.NodeId)
// 执行查询,返回 List<long> 结果
.ToList();
var toDoQuery = _sqlSugar
.Queryable<ZyFlowWorkitem>()
.LeftJoin<ZyFlowNode>((w, n) => w.NodeId == n.NodeId)
.LeftJoin<ZyFlowInstance>((w, n, i)
=> w.InstanceId == i.InstanceId)
.LeftJoin<IllegalConstructionAssessment>((w, n, i, t)
=> i.BusinessNo == t.BusinessNumber)
.WhereIF(!string.IsNullOrEmpty(pageQueryDto.key), (w, n, i, t)
=> t.BusinessNumber.Contains(pageQueryDto.key))
.Where((w, n, i, t)
=> nodeIdList.Contains(w.NodeId) && w.Status == "ToDo")
.Where((w, n, i, t) => orgs.Contains(w.OrgId))
.Where((w, n, i, t)
=> w.HandlerId == null || w.HandlerId == userId)
.OrderByDescending((w, n, i, t) =>
t.CreateTime)
.Select((w, n, i, t)
=> new FlowQuerySingleResultDto
{
workitemId = w.WorkitemId,
InstanceId = i.InstanceId,
BusinessNo = t.BusinessNumber,
Title = t.Title,
Type = t.Type,
NodeName = n.NodeName,
//Status = SqlFunc.IIF(i.Status == "Rejected", "Rejected", w.Status),
Status = i.Status,
WorkStatus = w.Status,
CreateTime = i.CreateTime,
InitiatorName = i.InitiatorName,
NodeType = n.NodeType
});
// 分页查询
var totalCount = toDoQuery.Count();
var toDoWorkItems = toDoQuery
.Skip((pageIndex - 1) * pageSize)
.Take(pageSize)
.ToList();
return new PageQueryResultDto<FlowQuerySingleResultDto>
{
Page = pageIndex,
Limit = pageSize,
Total = totalCount,
TotalPages = (int)Math.Ceiling((double)totalCount / pageSize),
Items = toDoWorkItems
};
}
/// <summary>
/// 我的已办(当前用户已处理完成的事项)
/// </summary>
/// <param name="userId">当前用户ID</param>
/// <param name="pageQueryDto">分页参数</param>
/// <returns>分页结果</returns>
public PageQueryResultDto<FlowQuerySingleResultDto> QueryMyDone(long userId, PageQueryRequestDto pageQueryDto)
{
// 参数初始化
if (userId <= 0)
return new PageQueryResultDto<FlowQuerySingleResultDto>();
pageQueryDto ??= new PageQueryRequestDto();
var pageIndex = pageQueryDto.page < 1 ? 1 : pageQueryDto.page;
var pageSize = pageQueryDto.limit < 1 ? 10 : pageQueryDto.limit;
// 已办逻辑:工作项状态为"Done"、处理人ID为当前用户去重流程实例
var doneInstanceIds = _sqlSugar
.Queryable<ZyFlowWorkitem>()
.LeftJoin<ZyFlowNode>((w, n) => w.NodeId == n.NodeId)
.LeftJoin<ZyFlowInstance>((w, n, i)
=> w.InstanceId == i.InstanceId)
.LeftJoin<IllegalConstructionAssessment>((w, n, i, t)
=> i.BusinessNo == t.BusinessNumber)
.WhereIF(!string.IsNullOrEmpty(pageQueryDto.key), (w, n, i, t)
=> t.BusinessNumber.Contains(pageQueryDto.key))
.Where((w, n, i, t)
=> w.Status == "Done" && w.HandlerId == userId)
.OrderByDescending((w, n, i, t) =>
t.CreateTime)
.Select((w, n, i, t)
=> new FlowQuerySingleResultDto
{
workitemId = w.WorkitemId,
InstanceId = i.InstanceId,
BusinessNo = t.BusinessNumber,
Title = t.Title,
Type = t.Type,
NodeName = n.NodeName,
Status = i.Status,
WorkStatus = w.Status,
CreateTime = i.CreateTime,
InitiatorName = i.InitiatorName
});
// 分页处理实例ID
var dataList = doneInstanceIds
.Skip((pageIndex - 1) * pageSize)
.Take(pageSize)
.ToList();
var totalCount = doneInstanceIds.Count();
return new PageQueryResultDto<FlowQuerySingleResultDto>
{
Page = pageIndex,
Limit = pageSize,
Total = totalCount,
TotalPages = (int)Math.Ceiling((double)totalCount / pageSize),
Items = dataList
};
}
/// <summary>
/// 我的未办结(当前用户参与过、流程尚未完成的事项)
/// </summary>
/// <param name="userId">当前用户ID</param>
/// <param name="pageQueryDto">分页参数</param>
/// <returns>分页结果</returns>
public PageQueryResultDto<FlowQuerySingleResultDto> QueryMyUnfinished(long userId, PageQueryRequestDto pageQueryDto)
{
// 参数初始化
if (userId <= 0)
return new PageQueryResultDto<FlowQuerySingleResultDto>();
pageQueryDto = pageQueryDto ?? new PageQueryRequestDto();
var pageIndex = pageQueryDto.page < 1 ? 1 : pageQueryDto.page;
var pageSize = pageQueryDto.limit < 1 ? 10 : pageQueryDto.limit;
// 未办结逻辑:
// 1. 当前用户参与过(处理过/待处理)
// 2. 流程状态不是"Completed"(未完成)
// Draft拟办、Submitted已提交、Forwarded已转发、Auditing审核中、Summarized已汇总、Completed已完成、Rejected已驳回
var doneInstanceIds = _sqlSugar
.Queryable<ZyFlowWorkitem>()
.LeftJoin<ZyFlowNode>((w, n) => w.NodeId == n.NodeId)
.LeftJoin<ZyFlowInstance>((w, n, i)
=> w.InstanceId == i.InstanceId)
.LeftJoin<IllegalConstructionAssessment>((w, n, i, t)
=> i.BusinessNo == t.BusinessNumber)
.WhereIF(!string.IsNullOrEmpty(pageQueryDto.key), (w, n, i, t)
=> t.BusinessNumber.Contains(pageQueryDto.key))
.Where((w, n, i, t)
=> w.Status == "Done" && i.Status != "Completed")
.Where((w, n, i, t)
=> w.HandlerId == userId)
.OrderByDescending((w, n, i, t) =>
t.CreateTime)
.Select((w, n, i, t)
=> new FlowQuerySingleResultDto
{
workitemId = w.WorkitemId,
InstanceId = i.InstanceId,
BusinessNo = t.BusinessNumber,
Title = t.Title,
Type = t.Type,
NodeName = n.NodeName,
Status = i.Status,
WorkStatus = w.Status,
CreateTime = i.CreateTime,
InitiatorName = i.InitiatorName
});
// 分页处理实例ID
var pagedInstanceIds = doneInstanceIds
.Skip((pageIndex - 1) * pageSize)
.Take(pageSize)
.ToList();
var totalCount = doneInstanceIds.Count();
return new PageQueryResultDto<FlowQuerySingleResultDto>
{
Page = pageIndex,
Limit = pageSize,
Total = totalCount,
TotalPages = (int)Math.Ceiling((double)totalCount / pageSize),
Items = pagedInstanceIds
};
}
/// <summary>
/// 我的已完成(当前用户参与过、流程已归档完成的事项)
/// </summary>
/// <param name="userId">当前用户ID</param>
/// <param name="pageQueryDto">分页参数</param>
/// <returns>分页结果</returns>
public PageQueryResultDto<FlowQuerySingleResultDto> QueryMyCompleted(long userId, PageQueryRequestDto pageQueryDto)
{
// 参数初始化
if (userId <= 0)
return new PageQueryResultDto<FlowQuerySingleResultDto>();
pageQueryDto = pageQueryDto ?? new PageQueryRequestDto();
var pageIndex = pageQueryDto.page < 1 ? 1 : pageQueryDto.page;
var pageSize = pageQueryDto.limit < 1 ? 10 : pageQueryDto.limit;
// 已完成逻辑:
// 1. 当前用户参与过
// 2. 流程状态是"Completed"(已完成)
var completedInstanceIds = _sqlSugar
.Queryable<ZyFlowWorkitem>()
.LeftJoin<ZyFlowNode>((w, n) => w.NodeId == n.NodeId)
.LeftJoin<ZyFlowInstance>((w, n, i)
=> w.InstanceId == i.InstanceId)
.LeftJoin<IllegalConstructionAssessment>((w, n, i, t)
=> i.BusinessNo == t.BusinessNumber)
.WhereIF(!string.IsNullOrEmpty(pageQueryDto.key), (w, n, i, t)
=> t.BusinessNumber.Contains(pageQueryDto.key))
.Where((w, n, i, t)
=> w.Status == "Done" && i.Status == "Completed")
.Where((w, n, i, t)
=> w.HandlerId == userId)
.OrderByDescending((w, n, i, t) =>
t.CreateTime)
.Select((w, n, i, t)
=> new FlowQuerySingleResultDto
{
workitemId = w.WorkitemId,
InstanceId = i.InstanceId,
BusinessNo = t.BusinessNumber,
Title = t.Title,
Type = t.Type,
NodeName = n.NodeName ?? "流程结束",
Status = i.Status,
WorkStatus = w.Status,
CreateTime = i.CreateTime,
InitiatorName = i.InitiatorName
});
// 分页处理实例ID
var dataList = completedInstanceIds
.Skip((pageIndex - 1) * pageSize)
.Take(pageSize)
.ToList();
var totalCount = completedInstanceIds.Count();
return new PageQueryResultDto<FlowQuerySingleResultDto>
{
Page = pageIndex,
Limit = pageSize,
Total = totalCount,
TotalPages = (int)Math.Ceiling((double)totalCount / pageSize),
Items = dataList
};
}
/// <summary>
/// 我的全部事项(拟办+待办+已办+未办结+已完成,去重整合)
/// </summary>
/// <param name="userId">当前用户ID</param>
/// <param name="pageQueryDto">分页参数</param>
/// <returns>分页结果</returns>
public PageQueryResultDto<FlowQuerySingleResultDto> QueryMyAllItems(long userId, PageQueryRequestDto pageQueryDto)
{
// 参数初始化
if (userId <= 0)
return new PageQueryResultDto<FlowQuerySingleResultDto>();
pageQueryDto = pageQueryDto ?? new PageQueryRequestDto();
var pageIndex = pageQueryDto.page < 1 ? 1 : pageQueryDto.page;
var pageSize = pageQueryDto.limit < 1 ? 10 : pageQueryDto.limit;
var orgIds = _auth.GetCurrentUser().Orgs.Select(o => o.Id).ToList();
// todo 拟办 发起人 InitiatorId 要经手的 角色绑定的节点 handler_id = null 或者 已经手的handler_id = user
var nodeIdList = _sqlSugar.Queryable<ZyFlowNode>()
// 核心In(主表字段, 子查询Lambda表达式)
.In(
zy => zy.RoleId, // 主表 zy_flow_node 的 role_id 字段
// 子查询:从 sys_userrole 中查询 UserId=2 的 RoleId
_sqlSugar.Queryable<SysUserRole>()
.Where(ur => ur.UserId == userId) // 条件UserId=2注意这里直接用数值避免字符串拼接
.Select(ur => ur.RoleId) // 子查询只返回 RoleId 字段
)
// 主查询只返回 node_id 字段(提升查询性能,避免查询全表字段)
.Select(zy => zy.NodeId)
// 执行查询,返回 List<long> 结果
.ToList();
var allQuery = _sqlSugar.Queryable<IllegalConstructionAssessment, ZyFlowInstance, ZyFlowNode>((t, i, n) =>
new JoinQueryInfos(
// 第一个左联t(违建表) LEFT JOIN i(流程实例表) ON 业务编号匹配
JoinType.Left, t.BusinessNumber == i.BusinessNo,
// 第二个左联i(流程实例表) LEFT JOIN n(流程节点表) ON 当前节点ID匹配
JoinType.Left, i.CurrentNodeId == n.NodeId
))
.Where((t, i, n) => i.Status != "Draft")
.Where((t, i, n) =>
i.InitiatorId == userId //区县
|| SqlFunc.Exists(
SqlFunc.Subqueryable<ZyFlowWorkitem>()
.GroupBy(w => w.InstanceId)
// 子查询过滤条件仅修改Contains + 加nodeIdList非空判断
.Where(w => w.HandlerId == userId
|| w.HandlerId == null
&& w.Status == "ToDo"
&& SqlFunc.ContainsArray(nodeIdList, w.NodeId)
&& orgIds.Contains(w.OrgId))
// 主查询与子查询的实例ID关联原有逻辑不变
.Where(w => w.InstanceId == i.InstanceId)
.Select(w => w.InstanceId)
)
)
.WhereIF(!string.IsNullOrEmpty(pageQueryDto.key), (t, i, n)
=> t.BusinessNumber.Contains(pageQueryDto.key))
.OrderByDescending((t, i, n) =>
t.CreateTime)
// 你的指定Select完全按FlowQuerySingleResultDto赋值保留原空值处理逻辑
.Select((t, i, n) => new FlowQuerySingleResultDto
{
InstanceId = i.InstanceId,
BusinessNo = i.BusinessNo,
Title = t.Title,
Type = t.Type, // 保留原空值默认转0的处理
NodeName = n.NodeName, // 左联可能为nullDto中若需默认值可加??"未知节点"
NodeType = n.NodeType,
Status = i.Status,
CreateTime = i.CreateTime,
InitiatorName = i.InitiatorName
});
var totalCount = allQuery.Count();
var dataList = allQuery
.Skip((pageIndex - 1) * pageSize)
.Take(pageSize)
.ToList();
return new PageQueryResultDto<FlowQuerySingleResultDto>
{
Page = pageIndex,
Limit = pageSize,
Total = totalCount,
TotalPages = (int)Math.Ceiling((double)totalCount / pageSize),
Items = dataList
};
}
#endregion
#region 三、内部核心辅助方法(仅内部调用,不对外暴露)
/// <summary>
/// 流程节点流转核心方法
/// </summary>
private void FlowToNextNode(long instanceId,
ZyFlowNode currentNode, long userId,
string userName, string comment, HandleWorkitemRequestDto requestDto = null)
{
// 解析下一节点IDs
var nextNodeIds = currentNode.NextNodeIds?.Split(',', StringSplitOptions.RemoveEmptyEntries)
.Select(long.Parse)
.ToList() ?? new List<long>();
if (!nextNodeIds.Any())
return;
// 查询流程实例
var flowInstance = _sqlSugar.Queryable<ZyFlowInstance>()
.Where(i => i.InstanceId == instanceId)
.First();
if (flowInstance == null)
throw new Exception("流程实例不存在");
// 遍历处理每个下一节点
foreach (var nextNodeId in nextNodeIds)
{
var nextNode = _sqlSugar.Queryable<ZyFlowNode>()
.Where(n => n.NodeId == nextNodeId)
.First();
if (nextNode == null)
continue;
// 更新流程实例当前节点和状态
flowInstance.CurrentNodeId = nextNode.NodeId;
// 流程状态更新
// 区县提交之后 Submitted -> 转发之后 Forwarded -> 审核之后 Auditing -> 汇总判断之后 Summarized -> 归档之后 Completed
// 区县提交之后 Submitted -> 转发之后 Forwarded -> 审核之后 Auditing -> 汇总判断之后 Summarized-> 驳回之后 Rejected
flowInstance.Status = GetFlowStatusByNodeType(nextNode.NodeType);
_sqlSugar.Updateable(flowInstance).IgnoreNullColumns().ExecuteCommand();
// 并行节点5个审核科为每个审核科创建工作项
if (nextNode.NodeType == "Parallel")
{
CreateAuditDeptWorkitem(instanceId, nextNode, requestDto?.OrgIds);
}
// 普通节点/分支节点:创建单个工作项
else
{
var roleId = nextNode.RoleId;
var dept = _sqlSugar
.Queryable<SysOrg>()
.LeftJoin<SysUserOrg>((o, uo)
=> o.Id == uo.OrgId)
.LeftJoin<SysUserRole>((o, uo, ur)
=> uo.UserId == ur.UserId)
.Where((o, uo, ur) => ur.RoleId == roleId)
.First();
//var userInfo = GetRoleFirstUserInfo(nextNode.RoleId);
// 执法监督科角色可能存在多个用户,不指定处理人
var nextWorkitem = new ZyFlowWorkitem
{
InstanceId = instanceId,
NodeId = nextNode.NodeId,
NodeName = nextNode.NodeName,
//HandlerId = userInfo.userId,
//HandlerName = userInfo.userName,
Status = "ToDo",
ReceiveTime = DateTime.Now,
Comment = comment,
OrgId = dept.Id,
OrgName = dept.Name
};
_sqlSugar.Insertable(nextWorkitem).ExecuteCommand();
}
}
}
/// <summary>
/// 处理并行会签(保存结果+判断是否全部完成)
/// </summary>
private void ProcessParallelAudit(long instanceId, long nodeId, long userId, string userName,
HandleWorkitemRequestDto requestDto)
{
// 校验会签结果
if (string.IsNullOrEmpty(requestDto.AuditResult))
throw new Exception("会签需选择审核结果Pass/Reject");
// 步骤1获取当前用户所属科室名称
var deptName = GetUserDeptName(userId);
// 步骤2保存会签记录
var parallelAudit = new ZyFlowParallelAudit
{
InstanceId = instanceId,
NodeId = nodeId,
DeptName = deptName,
AuditResult = requestDto.AuditResult,
AuditComment = requestDto.Comment,
AuditorId = userId,
AuditorName = userName,
AuditTime = DateTime.Now
};
_sqlSugar.Insertable(parallelAudit).ExecuteCommand();
// 步骤3判断是否所有审核科都已完成会签
if (IsAllAuditCompleted(instanceId, nodeId))
{
// 步骤4流转至汇总节点
var parallelNode = _sqlSugar.Queryable<ZyFlowNode>()
.Where(n => n.NodeId == nodeId && n.NodeType == "Parallel")
.First();
FlowToNextNode(instanceId, parallelNode, userId, userName, "所有审核科会签完成,流转至汇总节点");
}
}
private bool IsAllAuditCompleted(long instanceId, long nodeId)
{
// 有一个 Pending
var auditsCount = _sqlSugar.Queryable<ZyFlowWorkitem>()
.Any(a => a.InstanceId == instanceId && a.NodeId == nodeId && a.Status == "ToDo");
return !auditsCount;
}
/// <summary>
/// 处理汇总节点(归档/退回区县)
/// </summary>
private void ProcessSummaryNode(ZyFlowInstance flowInstance, ZyFlowNode summaryNode, long userId, string userName,
HandleWorkitemRequestDto requestDto)
{
// 步骤1判断是否全部审核通过
/*var hasReject = _sqlSugar.Queryable<ZyFlowParallelAudit>()
.Where(a => a.InstanceId == flowInstance.InstanceId)
.Any(a => a.AuditResult == "Reject");
var isAllPass = !hasReject;*/
// 步骤2解析汇总节点下一节点归档/退回)
var nextNodeIds = summaryNode.NextNodeIds?.Split(',', StringSplitOptions.RemoveEmptyEntries)
.Select(long.Parse)
.ToList() ?? new List<long>();
if (nextNodeIds.Count < 2)
throw new Exception("汇总节点需配置2个后续节点归档/退回区县)");
var isAllPass = requestDto.AuditResult == "Pass";
// 步骤3确定目标节点通过→归档[下标0],不通过→退回区县[下标1]
var targetNodeId = isAllPass ? nextNodeIds[0] : nextNodeIds[1];
var targetNode = _sqlSugar.Queryable<ZyFlowNode>()
.Where(n => n.NodeId == targetNodeId)
.First();
if (targetNode == null)
throw new Exception($"汇总节点目标节点【{(isAllPass ? "" : "退")}】不存在");
// todo 关于同一角色存在于多个部门问题
// todo 一个是区县,一个是审核部门
// 步骤4创建目标节点工作项 驳回 or 归档
var summaryWorkitem = new ZyFlowWorkitem
{
InstanceId = flowInstance.InstanceId,
NodeId = targetNode.NodeId,
NodeName = targetNode.NodeName,
HandlerId = isAllPass ? userId : null,
HandlerName = isAllPass ? userName : null,
Status = isAllPass ? "Done" : "ToDo",
ReceiveTime = DateTime.Now,
HandleTime = DateTime.Now,
Comment = isAllPass
? "归档完成"
: (string.IsNullOrEmpty(requestDto.Comment) ? "审核不通过,退回区县修改补充材料" : requestDto.Comment)
};
// 如果是驳回节点,需要退回原部门
if (!isAllPass)
{
var startWorkItem = _sqlSugar
.Queryable<ZyFlowWorkitem>()
.Where(w => w.InstanceId == flowInstance.InstanceId)
.OrderBy(w => w.WorkitemId).First();
summaryWorkitem.HandlerId = flowInstance.InstanceId;
summaryWorkitem.HandlerName = flowInstance.InitiatorName;
summaryWorkitem.OrgId = startWorkItem.OrgId;
summaryWorkitem.OrgName = startWorkItem.OrgName;
}
else
{
// 获取目标角色的部门名称
var roleId = targetNode.RoleId;
var dept = _sqlSugar
.Queryable<SysOrg>()
.LeftJoin<SysUserOrg>((o, uo)
=> o.Id == uo.OrgId)
.LeftJoin<SysUserRole>((o, uo, ur)
=> uo.UserId == ur.UserId)
.Where((o, uo, ur) => ur.RoleId == roleId)
.First();
summaryWorkitem.OrgId = dept.Id;
summaryWorkitem.OrgName = dept.Name;
}
_sqlSugar.Insertable(summaryWorkitem).ExecuteCommand();
// 步骤5更新流程实例最终状态
flowInstance.CurrentNodeId = targetNode.NodeId;
flowInstance.Status = isAllPass ? "Completed" : "Rejected";
flowInstance.FinishTime = isAllPass ? DateTime.Now : null;
_sqlSugar.Updateable(flowInstance).ExecuteCommand();
// 表单状态更新
var illegalConstructionAssessmentUpdate = new IllegalConstructionAssessment()
{
Id = flowInstance.BusinessNo,
Status = isAllPass ? "Completed" : "Rejected"
};
//_sqlSugar.Updateable(illegalConstructionAssessmentUpdate).IgnoreNullColumns().ExecuteCommand();
_sqlSugar.Updateable<IllegalConstructionAssessment>()
.SetColumns(t => new IllegalConstructionAssessment() { Status = isAllPass ? "Completed" : "Rejected" })
.Where(t => t.Id == flowInstance.BusinessNo).ExecuteCommand();
}
/// <summary>
/// 完成流程实例(结束节点)
/// </summary>
private void CompleteFlowInstance(ZyFlowInstance flowInstance)
{
flowInstance.Status = "Completed";
flowInstance.FinishTime = DateTime.Now;
_sqlSugar.Updateable(flowInstance).ExecuteCommand();
}
/// <summary>
/// 为审核科创建工作项
/// </summary>
private void CreateAuditDeptWorkitem(long instanceId, ZyFlowNode parallelNode, List<long> orgIds)
{
var orgs = _sqlSugar.Queryable<SysOrg>()
.Where(a => orgIds.Contains(a.Id)).ToList();
// 获取科室用户信息
/*var userInfos = _sqlSugar
.Queryable<SysUser>()
.LeftJoin<SysUserRole>((u, ur) => u.Id == ur.UserId)
.LeftJoin<SysUserOrg>((u, ur, uo) => u.Id == uo.UserId)
.LeftJoin<SysOrg>((u, ur, uo, o) => uo.OrgId == o.Id)
.Where((u, ur, uo, o) => ur.RoleId == parallelNode.RoleId)
.Select((u, ur, uo, o) => new
{
userName = u.Name,
userId = u.Id,
deptName = o.Name
})
.ToList();*/
foreach (var org in orgs)
{
// 创建工作项
var workitem = new ZyFlowWorkitem
{
InstanceId = instanceId,
NodeId = parallelNode.NodeId,
NodeName = $"{parallelNode.NodeName}",
Status = "ToDo",
ReceiveTime = DateTime.Now,
Comment = "请完成违法建设认定相关审核工作",
OrgId = org.Id,
OrgName = org.Name
};
_sqlSugar.Insertable(workitem).ExecuteCommand();
}
}
/// <summary>
/// 保存附件并返回路径
/// </summary>
private string SaveAttachments(List<IFormFile> attachments)
{
if (attachments == null || !attachments.Any())
return string.Empty;
// 定义附件存储目录
var uploadDir = Path
.Combine(AppContext.BaseDirectory, "Attachments/FlowAttachments");
if (!Directory.Exists(uploadDir))
Directory.CreateDirectory(uploadDir);
var attachmentPaths = new List<string>();
foreach (var file in attachments)
{
if (file.Length <= 0)
continue;
// 生成唯一文件名
var fileName = $"{Guid.NewGuid()}{Path.GetExtension(file.FileName)}";
var filePath = Path.Combine(uploadDir, fileName);
// 保存文件
using (var stream = new FileStream(filePath, FileMode.Create))
{
file.CopyTo(stream);
}
// 保存相对路径(用于前端访问)
attachmentPaths.Add($"/Attachments/FlowAttachments/{fileName}");
}
return string.Join(",", attachmentPaths);
}
/// <summary>
/// 根据节点类型获取流程状态
/// </summary>
private string GetFlowStatusByNodeType(string nodeType)
{
//执法监督科转发 Common
//审核科审核 Parallel
//汇总判断 Branch
//流程归档 End
//退回区县修改 End
return nodeType switch
{
/*"Common" => "Submitted", // 转发
"Parallel" => "Forwarded", // 审核
"Branch" => "Auditing", // 汇总
"End" => "Completed", // 已完成
_ => "Submitted" // 已提交(这个状态只要一瞬间,前端不可见)*/
"Common" => "Forwarded", // 将要转发
"Parallel" => "Auditing", // 将要审核
"Branch" => "Summarized", // 将要汇总
"End" => "Completed", // 已完成
_ => "Submitted" // 已提交(这个状态只要一瞬间,前端不可见)
};
}
/// <summary>
/// 获取用户所属科室名称
/// </summary>
private string GetUserDeptName(long userId)
{
var deptName = _sqlSugar.Queryable<SysUserOrg, SysOrg>((uo, o) => new JoinQueryInfos(
JoinType.Inner, uo.OrgId == o.Id))
.Where((uo, o) => uo.UserId == userId)
.Select((uo, o) => o.Name)
.First();
return deptName ?? "未知科室";
}
/// <summary>
/// 获取角色下第一个用户的完整信息
/// </summary>
private (long userId, string userName, string deptName) GetRoleFirstUserInfo(long roleId)
{
var userInfo = _sqlSugar
.Queryable<SysUserRole, SysUser, SysUserOrg, SysOrg>((ur, u, uo, o)
=> new JoinQueryInfos(
JoinType.Inner, ur.UserId == u.Id && u.Id == uo.UserId && uo.OrgId == o.Id))
.Where((ur, u, uo, o) => ur.RoleId == roleId)
.Select((ur, u, uo, o) => 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);
}
#endregion
/// <summary>
/// 保存拟办
/// </summary>
/// <param name="requestDto"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public bool SaveDraft(InitiateFlowRequestDto requestDto)
{
try
{
if (string.IsNullOrEmpty(requestDto.BusinessNo))
{
var businessNo = _businessNoGenerator.GenerateBusinessNo(prefix);
UnitWork.Db.Ado.BeginTran();
var user = _auth.GetCurrentUser().User;
var illegalConstructionAssessment = new IllegalConstructionAssessment
{
Id = businessNo,
Title = requestDto.Title,
BusinessNumber = businessNo,
AcceptanceTime = DateTime.Now,
Status = "Draft",
Type = requestDto.Type,
CreateTime = DateTime.Now,
CreateUser = user.Name,
UpdateTime = DateTime.Now,
CreateUserId = user.Id
};
if (!requestDto.Attachments.IsEmpty())
{
var attachmentPaths = string.Join(",", requestDto.Attachments);
illegalConstructionAssessment.Attachments = attachmentPaths;
}
_sqlSugar.Insertable(illegalConstructionAssessment).ExecuteCommand();
var template = _sqlSugar.Queryable<ZyFlowTemplate>()
.Where(t => t.FlowCode == requestDto.FlowCode && t.IsEnabled == true)
.First();
if (template == null)
throw new Exception($"流程模板【{requestDto.FlowCode}】不存在或未启用");
// 步骤2查询流程开始节点区县提交
var startNode = _sqlSugar.Queryable<ZyFlowNode>()
.Where(n => n.TemplateId == template.TemplateId && n.NodeType == "Start" && n.NodeName == "区县提交")
.First();
if (startNode == null)
throw new Exception("流程开始节点【区县提交】不存在,请配置节点");
var flowInstance = new ZyFlowInstance
{
TemplateId = template.TemplateId,
FlowCode = template.FlowCode,
BusinessNo = businessNo,
Status = "Draft", // 已提交
CurrentNodeId = startNode.NodeId,
InitiatorId = user.Id,
InitiatorName = user.Name,
CreateTime = DateTime.Now
};
var instanceId = _sqlSugar.Insertable(flowInstance).ExecuteReturnIdentity();
// 步骤4插入开始节点工作项直接标记为已完成
// 开始节点无ToDo
var startWorkitem = new ZyFlowWorkitem
{
InstanceId = instanceId,
NodeId = startNode.NodeId,
NodeName = startNode.NodeName,
HandlerId = user.Id,
HandlerName = user.Name,
Status = "Draft", // 已完成
ReceiveTime = DateTime.Now,
HandleTime = DateTime.Now,
Comment = "提交材料"
};
_sqlSugar.Insertable(startWorkitem).ExecuteCommand();
return true;
}
else
{
UnitWork.Db.Ado.BeginTran();
var illegalConstructionAssessment = _sqlSugar.Queryable<IllegalConstructionAssessment>()
.Where(i => i.Id == requestDto.BusinessNo)
.First();
if (illegalConstructionAssessment == null)
{
throw new Exception($"该拟办不存在");
}
illegalConstructionAssessment.Title = requestDto.Title;
illegalConstructionAssessment.AcceptanceTime = DateTime.Now;
//Status = "Draft",
illegalConstructionAssessment.Type = requestDto.Type;
illegalConstructionAssessment.UpdateTime = DateTime.Now;
if (!requestDto.Attachments.IsEmpty())
{
var attachmentPaths = string.Join(",", requestDto.Attachments);
illegalConstructionAssessment.Attachments = attachmentPaths;
}
_sqlSugar.Updateable(illegalConstructionAssessment).IgnoreNullColumns().ExecuteCommand();
return true;
}
}
catch (Exception ex)
{
UnitWork.Db.Ado.RollbackTran();
throw;
}
finally
{
UnitWork.Db.Ado.CommitTran();
}
}
public dynamic Detail(string businessNo)
{
var instance = _sqlSugar
.Queryable<ZyFlowInstance>()
.Where(i => i.BusinessNo == businessNo)
.First();
if (instance == null)
{
throw new Exception($"流程实例不存在");
}
var workItems = _sqlSugar
.Queryable<ZyFlowWorkitem>()
.LeftJoin<ZyFlowParallelAudit>((w, a)
=> w.InstanceId == a.InstanceId && w.HandlerId == a.AuditorId)
.LeftJoin<ZyFlowNode>((w, a, n) => w.NodeId == n.NodeId)
.Where(w => w.InstanceId == instance.InstanceId && w.Status == "Done")
.OrderByDescending(w => w.WorkitemId)
.Select((w, a, n) => new
ZyFlowWorkitem
{
WorkitemId = w.WorkitemId,
Comment = w.Comment,
AuditComment = a.AuditComment, // 并行节点审核意见
AuditResult = SqlFunc.IIF(string.IsNullOrEmpty(w.AuditResult), a.AuditResult, w.AuditResult),
Status = w.Status,
ReceiveTime = w.ReceiveTime,
HandleTime = w.HandleTime,
HandlerName = w.HandlerName,
HandlerId = w.HandlerId,
NodeName = w.NodeName,
NodeType = n.NodeType,
OrgName = w.OrgName
})
.ToList();
var illegalConstructionAssessment = _sqlSugar
.Queryable<IllegalConstructionAssessment>()
.LeftJoin<ZyFlowInstance>((t, i) => t.BusinessNumber == i.BusinessNo)
.Where((t, i) => t.Id == businessNo)
.Select((t, i) => new IllegalConstructionAssessment()
{
Id = t.Id,
Title = t.Title,
BusinessNumber = t.BusinessNumber,
Attachments = t.Attachments,
AcceptanceTime = t.AcceptanceTime,
ReceiveTime = t.ReceiveTime,
Type = t.Type,
CreateTime = t.CreateTime,
CreateUser = t.CreateUser,
UpdateTime = t.UpdateTime,
CreateUserId = t.CreateUserId,
UpdateUser = t.UpdateUser,
Status = i.Status,
Remark = t.Remark
})
.First();
illegalConstructionAssessment.Workitems = workItems;
return illegalConstructionAssessment;
}
public dynamic GetUserInfoWithDept(long workitemId)
{
// todo 查询下一节点绑定的角色,获取角色下所有用户及部门信息
var workitem = _sqlSugar
.Queryable<ZyFlowWorkitem>()
.Where(w => w.WorkitemId == workitemId)
.First();
if (workitem == null)
{
throw new Exception($"工作项不存在");
}
var node = _sqlSugar
.Queryable<ZyFlowNode>()
.Where(n => n.NodeId == workitem.NodeId)
.First();
var nodeStr = node.NextNodeIds;
var firstNode = long.Parse(nodeStr.Split(",")[0]);
var nextNode = _sqlSugar
.Queryable<ZyFlowNode>()
.Where(n => n.NodeId == firstNode)
.First();
var roleId = nextNode.RoleId;
// var (userId, userName, deptName) = GetRoleFirstUserInfo(roleId);
var usrInfo = _sqlSugar
.Queryable<SysUser>()
.LeftJoin<SysUserRole>((u, ur) => u.Id == ur.UserId)
.LeftJoin<SysUserOrg>((u, ur, uo) => u.Id == uo.UserId)
.LeftJoin<SysOrg>((u, ur, uo, o) => uo.OrgId == o.Id)
.Where((u, ur, uo, o) => ur.RoleId == roleId)
.Select((u, ur, uo, o) => new
{
UserId = u.Id,
UserName = u.Name,
Dept = o.Name
}).ToList();
return usrInfo;
}
public dynamic ListSupervisionOrg()
{
// 监督
// 取得roleId // 取得角色下的用户及部门信息,部门信息去重
var orgs = _sqlSugar
.Queryable<SysOrg>()
.LeftJoin<SysUserOrg>((o, uo) => o.Id == uo.OrgId)
.LeftJoin<SysUserRole>((o, uo, ur) => uo.UserId == ur.UserId)
.LeftJoin<SysRole>((o, uo, ur, r) => ur.RoleId == r.Id)
.Where((o, uo, ur, r) => r.Id == 770508474880069L)
.GroupBy((o, uo, ur, r) => o.Id)
.Select((o, uo, ur, r) => new
{
o.Name,
o.Id
})
.ToList();
return orgs;
}
}