| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830 | 
							- using AutoMapper;
 
- using Newtonsoft.Json;
 
- using OASystem.Domain;
 
- using OASystem.Domain.Dtos.Groups;
 
- using OASystem.Domain.Entities.Groups;
 
- using System.Reflection;
 
- namespace OASystem.Infrastructure.Repositories.Groups
 
- {
 
-     /// <summary>
 
-     /// 团组流程总览表仓储
 
-     /// </summary>
 
-     public class ProcessOverviewRepository : BaseRepository<Grp_ProcessOverview, Grp_ProcessOverview>
 
-     {
 
-         private readonly IMapper _mapper;
 
-         private readonly DelegationInfoRepository _groupRep;
 
-         public ProcessOverviewRepository(SqlSugarClient sqlSugar, IMapper mapper, DelegationInfoRepository groupRep) : base(sqlSugar)
 
-         {
 
-             _mapper = mapper;
 
-             _groupRep = groupRep;
 
-         }
 
-         /// <summary>
 
-         /// 团组流程初始化
 
-         /// </summary>
 
-         /// <param name="request">创建流程请求参数</param>
 
-         /// <returns>创建的流程信息</returns>
 
-         public async Task<Result> ProcessInitAsync(int groupId, int currUserId)
 
-         {
 
-             //团组验证
 
-             var groupInfo = await _sqlSugar.Queryable<Grp_DelegationInfo>().FirstAsync(g => g.Id == groupId);
 
-             if (groupInfo == null)
 
-             {
 
-                 return new Result { Code = 400, Msg = "团组不存在" };
 
-             }
 
-             // 检查是否已存在流程
 
-             var existingProcesses = await _sqlSugar.Queryable<Grp_ProcessOverview>().Where(p => p.GroupId == groupId).ToListAsync();
 
-             if (existingProcesses.Any())
 
-             {
 
-                 return new Result { Code = 400, Msg = "该团组的流程已存在" };
 
-             }
 
-             //处理签证国家
 
-             var visaCountries = _groupRep.GroupSplitCountry(groupInfo.VisitCountry);
 
-             // 定义默认的流程节点
 
-             var processs = Grp_ProcessOverview.ProcessInit(groupId, currUserId, visaCountries);
 
-             _sqlSugar.BeginTran();
 
-             foreach (var item in processs)
 
-             {
 
-                 var processId = await _sqlSugar.Insertable(item).ExecuteReturnIdentityAsync();
 
-                 if (processId < 1)
 
-                 {
 
-                     _sqlSugar.RollbackTran();
 
-                     return new Result { Code = 400, Msg = "团组流程进度总览表添加失败!" };
 
-                 }
 
-                 // 记录流程日志
 
-                 await LogProcessOpAsync(null, item, "Create", currUserId);
 
-                 var nodes = item.Nodes.Select((nodeDto, index) => new Grp_ProcessNode
 
-                 {
 
-                     ProcessId = processId,
 
-                     NodeName = nodeDto.NodeName,
 
-                     NodeOrder = nodeDto.NodeOrder,
 
-                     OverallStatus = nodeDto.OverallStatus,
 
-                     //Country = nodeDto.Country,
 
-                     IsCurrent = nodeDto.IsCurrent,
 
-                     Remark = nodeDto.Remark
 
-                 }).ToList();
 
-                 var nodeIds = await _sqlSugar.Insertable(nodes).ExecuteCommandAsync();
 
-                 if (nodeIds < 1)
 
-                 {
 
-                     _sqlSugar.RollbackTran();
 
-                     return new Result { Code = 400, Msg = "团组流程进度流程节点添加失败!" };
 
-                 }
 
-                 //记录节点日志
 
-                 foreach (var node in nodes)
 
-                 {
 
-                     await LogNodeOpAsync(null, node, "Create", currUserId);
 
-                 }
 
-                 
 
-             }
 
-             _sqlSugar.CommitTran();
 
-             return new Result { Code = 200, Msg = "添加成功!" }; ;
 
-         }
 
-         /// <summary>
 
-         /// 获取团组的所有流程及流程详情
 
-         /// </summary>
 
-         /// <param name="request">创建流程请求参数</param>
 
-         /// <returns>创建的流程信息</returns>
 
-         public async Task<Result> ProcessesDetailsAsync(int groupId)
 
-         {
 
-             //团组验证
 
-             var groupInfo = await _sqlSugar.Queryable<Grp_DelegationInfo>().FirstAsync(g => g.Id == groupId);
 
-             if (groupInfo == null)
 
-             {
 
-                 return new Result { Code = 400, Msg = "团组不存在" };
 
-             }
 
-             // 检查是否已存在流程
 
-             var existingProcesses = await _sqlSugar.Queryable<Grp_ProcessOverview>().Where(p => p.GroupId == groupId).ToListAsync();
 
-             if (!existingProcesses.Any())
 
-             {
 
-                 //新建团组流程
 
-                 var res = await ProcessInitAsync(groupId, 4);
 
-                 if (res.Code != 200)
 
-                 {
 
-                     return res;
 
-                 }
 
-             }
 
-             var users = await _sqlSugar.Queryable<Sys_Users>().ToListAsync();
 
-             var processData = await _sqlSugar.Queryable<Grp_ProcessOverview>()
 
-                 .Where(p => p.GroupId == groupId && p.IsDel == 0)
 
-                 .Mapper(p => p.Nodes, p => p.Nodes.First().ProcessId)
 
-                 .ToListAsync();
 
-             var processes = processData.Select(p => new
 
-             {
 
-                 p.Id,
 
-                 p.GroupId,
 
-                 p.ProcessType,
 
-                 ProcessName = p.ProcessType.GetEnumDescription(),
 
-                 //p.OverallStatus,
 
-                 //StatusText = p.OverallStatus.GetDescription(),
 
-                 Nodes = p.Nodes.Select(n =>
 
-                 {
 
-                     //单独处理签证板块
 
-                     var visaSubNodes = new List<VisaProcessNode>();
 
-                     string remark = string.Empty;
 
-                     if (p.ProcessType == GroupProcessType.Visa)
 
-                     {
 
-                         visaSubNodes = JsonConvert.DeserializeObject<List<VisaProcessNode>>(n.Remark);
 
-                     }
 
-                     return new
 
-                     {
 
-                         n.Id,
 
-                         n.ProcessId,
 
-                         n.NodeOrder,
 
-                         n.NodeName,
 
-                         n.OverallStatus,
 
-                         StatusText = n.OverallStatus.GetEnumDescription(),
 
-                         Operator = users.FirstOrDefault(u => u.Id == n.Operator)?.CnName ?? "-",
 
-                         OpeateTime = n.OperationTime.HasValue ? n.OperationTime.Value.ToString("yyyy-MM-dd HH:mm:ss") : "-",
 
-                         //节点类型为签证时使用
 
-                         visaSubNodes
 
-                     };
 
-                 }).OrderBy(n => n.NodeOrder).ToList()
 
-             }).ToList();
 
-             return new Result { Code = 200, Data = processes, Msg = "查询成功!" };
 
-         }
 
-         /// <summary>
 
-         /// 更新节点状态
 
-         /// </summary>
 
-         /// <param name="nodeId">节点ID</param>
 
-         /// <param name="currUserId">当前用户ID</param>
 
-         /// <param name="processStatus">流程状态,默认为已完成</param>
 
-         /// <returns>操作结果</returns>
 
-         public async Task<Result> UpdateNodeStatusAsync(int nodeId, int currUserId, ProcessStatus processStatus = ProcessStatus.Completed)
 
-         {
 
-             try
 
-             {
 
-                 // 使用事务确保数据一致性
 
-                 var result = await _sqlSugar.Ado.UseTranAsync(async () =>
 
-                 {
 
-                     // 1. 获取并验证节点
 
-                     var node = await _sqlSugar.Queryable<Grp_ProcessNode>()
 
-                         .FirstAsync(n => n.Id == nodeId && n.IsDel == 0);
 
-                     if (node == null)
 
-                     {
 
-                         throw new BusinessException("当前节点不存在或已被删除。");
 
-                     }
 
-                     // 新增验证:当前节点已完成,不可操作
 
-                     ValidateNodeOperation(node, processStatus);
 
-                     //存储更新前的值
 
-                     var before = new Grp_ProcessNode() { 
 
-                         Id = node.Id,
 
-                         ProcessId = node.ProcessId,
 
-                         NodeName = node.NodeName,
 
-                         NodeOrder = node.NodeOrder,
 
-                         OverallStatus = node.OverallStatus,
 
-                         Operator = node.Operator,
 
-                         OperationTime = node.OperationTime,
 
-                         IsCurrent = node.IsCurrent,
 
-                     };
 
-                     // 2. 更新节点状态
 
-                     node.OverallStatus = processStatus;
 
-                     node.Operator = currUserId;
 
-                     node.OperationTime = DateTime.Now;
 
-                     var updateCount = await _sqlSugar.Updateable(node)
 
-                         .UpdateColumns(n => new
 
-                         {
 
-                             n.OverallStatus,
 
-                             n.Operator,
 
-                             n.OperationTime
 
-                         })
 
-                         .ExecuteCommandAsync();
 
-                     if (updateCount == 0)
 
-                     {
 
-                         throw new BusinessException("节点状态更新失败。");
 
-                     }
 
-                     //记录节点日志
 
-                     await LogNodeOpAsync(before, node, "Update", currUserId);
 
-                     // 3. 如果是完成当前节点,处理流程流转
 
-                     if (processStatus == ProcessStatus.Completed && node.IsCurrent)
 
-                     {
 
-                         await ProcessCurrentNodeCompletionAsync(node, currUserId);
 
-                     }
 
-                     return new Result { Code = StatusCodes.Status200OK, Msg = "操作成功。" };
 
-                 });
 
-                 return result.IsSuccess ? result.Data : new Result
 
-                 {
 
-                     Code = StatusCodes.Status500InternalServerError,
 
-                     Msg = result.ErrorMessage
 
-                 };
 
-             }
 
-             catch (BusinessException ex)
 
-             {
 
-                 // 业务异常
 
-                 return new Result { Code = StatusCodes.Status400BadRequest, Msg = ex.Message };
 
-             }
 
-             catch (Exception ex)
 
-             {
 
-                 // 系统异常
 
-                 return new Result { Code = StatusCodes.Status500InternalServerError, Msg = "系统错误,请稍后重试" };
 
-             }
 
-         }
 
-         /// <summary>
 
-         /// 验证节点操作权限
 
-         /// </summary>
 
-         /// <param name="node">流程节点</param>
 
-         /// <param name="targetStatus">目标状态</param>
 
-         private static void ValidateNodeOperation(Grp_ProcessNode node, ProcessStatus targetStatus)
 
-         {
 
-             // 验证节点是否已完成
 
-             if (node.OverallStatus == ProcessStatus.Completed)
 
-             {
 
-                 throw new BusinessException("当前节点已完成,不可重复操作。");
 
-             }
 
-             // 验证状态流转是否合法(可选)
 
-             if (targetStatus != ProcessStatus.Completed)
 
-             {
 
-                 throw new BusinessException("未开始或者进行中的节点只能重新完成,不可进行其他操作。");
 
-             }
 
-             // 验证是否尝试将已完成节点改为其他状态
 
-             if (node.OverallStatus == ProcessStatus.Completed && targetStatus != ProcessStatus.Completed)
 
-             {
 
-                 throw new BusinessException("已完成节点不可修改状态。");
 
-             }
 
-         }
 
-         /// <summary>
 
-         /// 处理当前节点完成后的流程流转
 
-         /// </summary>
 
-         private async Task ProcessCurrentNodeCompletionAsync(Grp_ProcessNode currentNode, int currUserId)
 
-         {
 
-             // 1. 获取流程信息
 
-             var process = await _sqlSugar.Queryable<Grp_ProcessOverview>()
 
-                 .FirstAsync(p => p.Id == currentNode.ProcessId && p.IsDel == 0);
 
-             if (process == null)
 
-             {
 
-                 throw new BusinessException("关联的流程不存在。");
 
-             }
 
-             var processBefore = new Grp_ProcessOverview()
 
-             {
 
-                 Id = process.Id,
 
-                 GroupId = process.GroupId,
 
-                 ProcessOrder = process.ProcessOrder,
 
-                 ProcessType = process.ProcessType,
 
-                 OverallStatus = process.OverallStatus,
 
-                 StartTime = process.StartTime,
 
-                 EndTime = process.EndTime,
 
-                 UpdatedUserId = process.UpdatedUserId,
 
-                 UpdatedTime = process.UpdatedTime
 
-             };
 
-             // 2. 取消当前节点的当前状态
 
-             var before = new Grp_ProcessNode()
 
-             {
 
-                 Id = currentNode.Id,
 
-                 ProcessId = currentNode.ProcessId,
 
-                 NodeName = currentNode.NodeName,
 
-                 NodeOrder = currentNode.NodeOrder,
 
-                 OverallStatus = currentNode.OverallStatus,
 
-                 Operator = currentNode.Operator,
 
-                 OperationTime = currentNode.OperationTime,
 
-                 IsCurrent = currentNode.IsCurrent,
 
-             };
 
-             currentNode.IsCurrent = false;
 
-             await _sqlSugar.Updateable(currentNode)
 
-                 .UpdateColumns(n => new { n.IsCurrent })
 
-                 .ExecuteCommandAsync();
 
-             // 2.1 记录节点日志 取消当前节点状态
 
-             await LogNodeOpAsync(before, currentNode, "Update", currUserId);
 
-             // 3. 查找并激活下一个节点
 
-             var nextNode = await _sqlSugar.Queryable<Grp_ProcessNode>()
 
-                 .Where(n => n.ProcessId == currentNode.ProcessId
 
-                          && n.NodeOrder == currentNode.NodeOrder + 1
 
-                          && n.IsDel == 0)
 
-                 .FirstAsync();
 
-             if (nextNode != null)
 
-             {
 
-                 var nextNodeBefore = new Grp_ProcessNode()
 
-                 {
 
-                     Id = nextNode.Id,
 
-                     ProcessId = nextNode.ProcessId,
 
-                     NodeName = nextNode.NodeName,
 
-                     NodeOrder = nextNode.NodeOrder,
 
-                     OverallStatus = nextNode.OverallStatus,
 
-                     Operator = nextNode.Operator,
 
-                     OperationTime = nextNode.OperationTime,
 
-                     IsCurrent = nextNode.IsCurrent,
 
-                 };
 
-                 // 激活下一个节点
 
-                 nextNode.IsCurrent = true;
 
-                 nextNode.OverallStatus = ProcessStatus.InProgress;
 
-                 //nextNode.Operator = currUserId;
 
-                 //nextNode.OperationTime = DateTime.Now;
 
-                 var updateCount = await _sqlSugar.Updateable(nextNode)
 
-                     .UpdateColumns(n => new
 
-                     {
 
-                         n.IsCurrent,
 
-                         n.OverallStatus,
 
-                         n.Operator,
 
-                         n.OperationTime
 
-                     })
 
-                     .ExecuteCommandAsync();
 
-                 if (updateCount == 0)
 
-                 {
 
-                     throw new BusinessException("激活下一节点失败");
 
-                 }
 
-                 // 1.1 记录节点日志 激活下一节点当前节点状态
 
-                 await LogNodeOpAsync(nextNodeBefore, nextNode, "Start", currUserId);
 
-                 // 更新流程状态为进行中
 
-                 process.OverallStatus = ProcessStatus.InProgress;
 
-             }
 
-             else
 
-             {
 
-                 // 下一节点不存在,整个流程完成
 
-                 process.OverallStatus = ProcessStatus.Completed;
 
-                 process.EndTime = DateTime.Now;
 
-             }
 
-             // 4. 更新流程信息
 
-             process.UpdatedUserId = currUserId;
 
-             process.UpdatedTime = DateTime.Now;
 
-             var processUpdateCount = await _sqlSugar.Updateable(process)
 
-                 .UpdateColumns(p => new
 
-                 {
 
-                     p.OverallStatus,
 
-                     p.EndTime,
 
-                     p.UpdatedUserId,
 
-                     p.UpdatedTime
 
-                 })
 
-                 .ExecuteCommandAsync();
 
-             if (processUpdateCount == 0)
 
-             {
 
-                 throw new BusinessException("流程状态更新失败。");
 
-             }
 
-             //记录流程日志
 
-             await LogProcessOpAsync(processBefore, process, "Update", currUserId);
 
-         }
 
-         /// <summary>
 
-         /// 更新签证节点信息及状态
 
-         /// </summary>
 
-         /// <param name="dto">签证节点更新数据传输对象</param>
 
-         /// <returns>操作结果</returns>
 
-         public async Task<Result> UpdateVisaNodeDetailsAsync(GroupProcessUpdateVisaNodeDetailsDto dto)
 
-         {
 
-             // 1. 获取并验证节点和流程
 
-             var node = await _sqlSugar.Queryable<Grp_ProcessNode>()
 
-                 .FirstAsync(n => n.Id == dto.NodeId && n.IsDel == 0)
 
-                 ?? throw new BusinessException("当前节点不存在或已被删除。");
 
-             var process = await _sqlSugar.Queryable<Grp_ProcessOverview>()
 
-                 .FirstAsync(p => p.Id == node.ProcessId && p.IsDel == 0)
 
-                 ?? throw new BusinessException("当前流程不存在或已被删除。");
 
-             if (process.ProcessType != GroupProcessType.Visa)
 
-             {
 
-                 throw new BusinessException("当前流程节点不为签证流程,不可编辑。");
 
-             }
 
-             // 2. 检查签证子节点 字段信息是否全部填写
 
-             var allSubNodesCompleted = dto.VisaSubNodes?.All(subNode => EntityExtensions.IsCompleted(subNode)) ?? false;
 
-             // 2.1 存储更新前流程及节点信息
 
-             var nodeBefore = new Grp_ProcessNode()
 
-             {
 
-                 Id = node.Id,
 
-                 ProcessId = node.ProcessId,
 
-                 NodeName = node.NodeName,
 
-                 NodeOrder = node.NodeOrder,
 
-                 OverallStatus = node.OverallStatus,
 
-                 Operator = node.Operator,
 
-                 OperationTime = node.OperationTime,
 
-                 IsCurrent = node.IsCurrent,
 
-             };
 
-             var processBefore = new Grp_ProcessOverview()
 
-             {
 
-                 Id = process.Id,
 
-                 GroupId = process.GroupId,
 
-                 ProcessOrder = process.ProcessOrder,
 
-                 ProcessType = process.ProcessType,
 
-                 OverallStatus = process.OverallStatus,
 
-                 StartTime = process.StartTime,
 
-                 EndTime = process.EndTime,
 
-                 UpdatedUserId = process.UpdatedUserId,
 
-                 UpdatedTime = process.UpdatedTime
 
-             };
 
-             // 3. 更新节点信息
 
-             node.Remark = JsonConvert.SerializeObject(dto.VisaSubNodes);
 
-             node.Operator = dto.CurrUserId;
 
-             node.OperationTime = DateTime.Now;
 
-             if (allSubNodesCompleted)
 
-             {
 
-                 node.OverallStatus = ProcessStatus.Completed;
 
-                 process.OverallStatus = ProcessStatus.Completed;
 
-                 process.EndTime = DateTime.Now;
 
-                 process.UpdatedUserId = dto.CurrUserId;
 
-                 process.UpdatedTime = DateTime.Now;
 
-                 // 更新流程状态
 
-                 await _sqlSugar.Updateable(process)
 
-                     .UpdateColumns(p => new
 
-                     {
 
-                         p.OverallStatus,
 
-                         p.EndTime,
 
-                         p.UpdatedUserId,
 
-                         p.UpdatedTime
 
-                     })
 
-                     .ExecuteCommandAsync();
 
-                 //记录流程日志
 
-                 await LogProcessOpAsync(processBefore, process, "Update", dto.CurrUserId);
 
-             }
 
-             // 4. 保存节点更新
 
-             await _sqlSugar.Updateable(node)
 
-                 .UpdateColumns(n => new
 
-                 {
 
-                     n.Remark,
 
-                     n.Operator,
 
-                     n.OperationTime,
 
-                     n.OverallStatus
 
-                 })
 
-                 .ExecuteCommandAsync();
 
-             //记录节点日志
 
-             await LogNodeOpAsync(nodeBefore, node, "Update", dto.CurrUserId);
 
-             return new Result { Code = 200, Msg = "节点信息更新成功。" };
 
-         }
 
-         #region 操作日志
 
-         /// <summary>
 
-         /// 记录流程操作日志
 
-         /// </summary>
 
-         /// <param name="before">操作前</param>
 
-         /// <param name="after">操作后</param>
 
-         /// <param name="opType">操作类型(Create - 创建、Update - 更新、Complete - 完成)</param>
 
-         /// <param name="operId">操作人ID</param>
 
-         /// <returns>异步任务</returns>
 
-         public async Task LogProcessOpAsync(Grp_ProcessOverview before, Grp_ProcessOverview after,string opType, int operId)
 
-         {
 
-             var chgDetails = GetProcessChgDetails(before, after);
 
-             var log = new Grp_ProcessLog
 
-             {
 
-                 ProcessId = after?.Id ?? before?.Id,
 
-                 GroupId = after?.GroupId ?? before?.GroupId ?? 0,
 
-                 OpType = opType,
 
-                 OpDesc = GenerateProcessOpDesc(opType, before, after, chgDetails),
 
-                 BeforeData = before != null ? JsonConvert.SerializeObject(before, GetJsonSettings()) : null,
 
-                 AfterData = after != null ? JsonConvert.SerializeObject(after, GetJsonSettings()) : null,
 
-                 ChgFields = string.Join(",", chgDetails.Select(x => x.FieldName)),
 
-                 CreateUserId = operId
 
-             };
 
-             await _sqlSugar.Insertable(log).ExecuteCommandAsync();
 
-         }
 
-         /// <summary>
 
-         /// 记录节点操作日志
 
-         /// </summary>
 
-         /// <param name="before">操作前</param>
 
-         /// <param name="after">操作后</param>
 
-         /// <param name="opType">操作类型(Create - 创建、Update - 更新、Start - 启动、Complete - 完成)</param>
 
-         /// <param name="operId">操作人ID</param>
 
-         /// <returns>异步任务</returns>
 
-         public async Task LogNodeOpAsync(Grp_ProcessNode before, Grp_ProcessNode after,string opType, int operId)
 
-         {
 
-             var chgDetails = GetNodeChgDetails(before, after);
 
-             var log = new Grp_ProcessLog
 
-             {
 
-                 NodeId = after?.Id ?? before?.Id,
 
-                 ProcessId = after?.ProcessId ?? before?.ProcessId,
 
-                 GroupId = 0, // 通过流程ID关联获取
 
-                 OpType = opType,
 
-                 OpDesc = GenerateNodeOpDesc(opType, before, after, chgDetails),
 
-                 BeforeData = before != null ? JsonConvert.SerializeObject(before, GetJsonSettings()) : null,
 
-                 AfterData = after != null ? JsonConvert.SerializeObject(before, GetJsonSettings()) : null,
 
-                 ChgFields = string.Join(",", chgDetails.Select(x => x.FieldName)),
 
-                 CreateUserId = operId
 
-             };
 
-             await _sqlSugar.Insertable(log).ExecuteCommandAsync();
 
-         }
 
-         /// <summary>
 
-         /// 获取流程变更详情
 
-         /// </summary>
 
-         /// <param name="before">变更前</param>
 
-         /// <param name="after">变更后</param>
 
-         /// <returns>变更详情</returns>
 
-         private List<FieldChgDetail> GetProcessChgDetails(Grp_ProcessOverview before, Grp_ProcessOverview after)
 
-         {
 
-             var chgDetails = new List<FieldChgDetail>();
 
-             if (before == null || after == null) return chgDetails;
 
-             var props = typeof(Grp_ProcessOverview).GetProperties(BindingFlags.Public | BindingFlags.Instance)
 
-                 .Where(p => p.CanRead && p.CanWrite && !IsExclField(p.Name));
 
-             foreach (var prop in props)
 
-             {
 
-                 var beforeVal = prop.GetValue(before);
 
-                 var afterVal = prop.GetValue(after);
 
-                 if (!Equals(beforeVal, afterVal))
 
-                 {
 
-                     chgDetails.Add(new FieldChgDetail
 
-                     {
 
-                         FieldName = prop.Name,
 
-                         BeforeValue = FormatVal(beforeVal),
 
-                         AfterValue = FormatVal(afterVal)
 
-                     });
 
-                 }
 
-             }
 
-             return chgDetails;
 
-         }
 
-         /// <summary>
 
-         /// 获取节点变更详情
 
-         /// </summary>
 
-         /// <param name="before">变更前</param>
 
-         /// <param name="after">变更后</param>
 
-         /// <returns>变更详情</returns>
 
-         private List<FieldChgDetail> GetNodeChgDetails(Grp_ProcessNode before, Grp_ProcessNode after)
 
-         {
 
-             var chgDetails = new List<FieldChgDetail>();
 
-             if (before == null || after == null) return chgDetails;
 
-             var props = typeof(Grp_ProcessNode).GetProperties(BindingFlags.Public | BindingFlags.Instance)
 
-                 .Where(p => p.CanRead && p.CanWrite && !IsExclField(p.Name));
 
-             foreach (var prop in props)
 
-             {
 
-                 var beforeVal = prop.GetValue(before);
 
-                 var afterVal = prop.GetValue(after);
 
-                 if (!Equals(beforeVal, afterVal))
 
-                 {
 
-                     chgDetails.Add(new FieldChgDetail
 
-                     {
 
-                         FieldName = prop.Name,
 
-                         BeforeValue = FormatVal(beforeVal),
 
-                         AfterValue = FormatVal(afterVal)
 
-                     });
 
-                 }
 
-             }
 
-             return chgDetails;
 
-         }
 
-         /// <summary>
 
-         /// 生成流程操作描述
 
-         /// </summary>
 
-         /// <param name="opType">操作类型</param>
 
-         /// <param name="before">操作前</param>
 
-         /// <param name="after">操作后</param>
 
-         /// <param name="chgDetails">变更详情</param>
 
-         /// <returns>操作描述</returns>
 
-         private string GenerateProcessOpDesc(string opType, Grp_ProcessOverview before,
 
-             Grp_ProcessOverview after, List<FieldChgDetail> chgDetails)
 
-         {
 
-             var processType = after?.ProcessType ?? before?.ProcessType;
 
-             var processName = GetProcessTypeName(processType);
 
-             if (!chgDetails.Any())
 
-             {
 
-                 return opType switch
 
-                 {
 
-                     "Create" => $"创建流程:{processName}",
 
-                     "Update" => $"更新流程:{processName} - 无变更",
 
-                     //"Start" => $"启动流程:{processName}",
 
-                     "Complete" => $"完成流程:{processName}",
 
-                     //"Delete" => $"删除流程:{processName}",
 
-                     _ => $"{opType}:{processName}"
 
-                 };
 
-             }
 
-             var chgDesc = string.Join("; ", chgDetails.Select(x =>
 
-                 $"{GetFieldDisplayName(x.FieldName)} ({x.BeforeValue} -> {x.AfterValue})"));
 
-             return $"{GetOpTypeDisplay(opType)}:{processName} - {chgDesc}";
 
-         }
 
-         /// <summary>
 
-         /// 获取JSON序列化设置
 
-         /// </summary>
 
-         /// <returns>JSON设置</returns>
 
-         private static JsonSerializerSettings GetJsonSettings()
 
-         {
 
-             return new JsonSerializerSettings
 
-             {
 
-                 ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
 
-                 NullValueHandling = NullValueHandling.Ignore,
 
-                 DateFormatString = "yyyy-MM-dd HH:mm:ss",
 
-                 Formatting = Formatting.None
 
-             };
 
-         }
 
-         /// <summary>
 
-         /// 生成节点操作描述
 
-         /// </summary>
 
-         /// <param name="opType">操作类型</param>
 
-         /// <param name="before">操作前</param>
 
-         /// <param name="after">操作后</param>
 
-         /// <param name="chgDetails">变更详情</param>
 
-         /// <returns>操作描述</returns>
 
-         private string GenerateNodeOpDesc(string opType, Grp_ProcessNode before,
 
-             Grp_ProcessNode after, List<FieldChgDetail> chgDetails)
 
-         {
 
-             var nodeName = after?.NodeName ?? before?.NodeName;
 
-             if (!chgDetails.Any())
 
-             {
 
-                 return opType switch
 
-                 {
 
-                     "Create" => $"创建节点:{nodeName}",
 
-                     "Update" => $"更新节点:{nodeName} - 无变更",
 
-                     "Start" => $"启动节点:{nodeName}",
 
-                     "Complete" => $"完成节点:{nodeName}",
 
-                     //"Delete" => $"删除节点:{nodeName}",
 
-                     _ => $"{opType}:{nodeName}"
 
-                 };
 
-             }
 
-             var chgDesc = string.Join("; ", chgDetails.Select(x =>
 
-                 $"{GetFieldDisplayName(x.FieldName)} ({x.BeforeValue} -> {x.AfterValue})"));
 
-             return $"{GetOpTypeDisplay(opType)}:{nodeName} - {chgDesc}";
 
-         }
 
-         /// <summary>
 
-         /// 获取流程类型名称
 
-         /// </summary>
 
-         /// <param name="processType">流程类型</param>
 
-         /// <returns>流程名称</returns>
 
-         private static string GetProcessTypeName(GroupProcessType? processType)
 
-         {
 
-             return processType switch
 
-             {
 
-                 GroupProcessType.Invitation => "商邀报批",
 
-                 GroupProcessType.Visa => "签证",
 
-                 GroupProcessType.AirTicket => "机票",
 
-                 GroupProcessType.Hotel => "酒店",
 
-                 GroupProcessType.LocalGuide => "地接",
 
-                 GroupProcessType.FeeSettle => "费用结算",
 
-                 _ => "未知流程"
 
-             };
 
-         }
 
-         /// <summary>
 
-         /// 获取操作类型显示
 
-         /// </summary>
 
-         /// <param name="opType">操作类型</param>
 
-         /// <returns>显示名称</returns>
 
-         private static string GetOpTypeDisplay(string opType)
 
-         {
 
-             return opType switch
 
-             {
 
-                 "Create" => "创建",
 
-                 "Update" => "更新",
 
-                 "Start" => "启动",
 
-                 "Complete" => "完成",
 
-                 "Delete" => "删除",
 
-                 "StatusChg" => "状态变更",
 
-                 _ => opType
 
-             };
 
-         }
 
-         /// <summary>
 
-         /// 获取字段显示名称
 
-         /// </summary>
 
-         /// <param name="fieldName">字段名</param>
 
-         /// <returns>显示名称</returns>
 
-         private string GetFieldDisplayName(string fieldName)
 
-         {
 
-             return fieldName switch
 
-             {
 
-                 "OverallStatus" => "状态",
 
-                 "ProcessOrder" => "流程顺序",
 
-                 "StartTime" => "开始时间",
 
-                 "EndTime" => "结束时间",
 
-                 "NodeOrder" => "节点顺序",
 
-                 "NodeName" => "节点名称",
 
-                 "IsCurrent" => "当前节点",
 
-                 "Operator" => "操作人",
 
-                 "OperationTime" => "操作时间",
 
-                 _ => fieldName
 
-             };
 
-         }
 
-         /// <summary>
 
-         /// 格式化值显示
 
-         /// </summary>
 
-         /// <param name="value">值</param>
 
-         /// <returns>格式化值</returns>
 
-         private string FormatVal(object value)
 
-         {
 
-             if (value == null) return "空";
 
-             if (value is ProcessStatus status)
 
-             {
 
-                 return status switch
 
-                 {
 
-                     ProcessStatus.UnStarted => "未开始",
 
-                     ProcessStatus.InProgress => "进行中",
 
-                     ProcessStatus.Completed => "已完成",
 
-                     _ => status.ToString()
 
-                 };
 
-             }
 
-             if (value is bool boolVal) return boolVal ? "是" : "否";
 
-             if (value is DateTime dateVal) return dateVal.ToString("yyyy-MM-dd HH:mm");
 
-             var strVal = value.ToString();
 
-             return string.IsNullOrEmpty(strVal) ? "空" : strVal;
 
-         }
 
-         /// <summary>
 
-         /// 检查是否排除字段
 
-         /// </summary>
 
-         /// <param name="fieldName">字段名</param>
 
-         /// <returns>是否排除</returns>
 
-         private bool IsExclField(string fieldName)
 
-         {
 
-             var exclFields = new List<string>
 
-             {
 
-                 "Id", "CreateTime", "CreateUserId", "UpdatedTime", "UpdatedUserId",
 
-                 "Nodes", "Process" // 导航属性
 
-             };
 
-             return exclFields.Contains(fieldName);
 
-         }
 
-         /// <summary>
 
-         /// 获取流程日志
 
-         /// </summary>
 
-         /// <param name="processId">流程ID</param>
 
-         /// <returns>日志列表</returns>
 
-         public async Task<List<Grp_ProcessLog>> GetProcessLogsAsync(int processId)
 
-         {
 
-             return await _sqlSugar.Queryable<Grp_ProcessLog>()
 
-                 .Where(x => x.ProcessId == processId)
 
-                 .OrderByDescending(x => x.CreateTime)
 
-                 .ToListAsync();
 
-         }
 
-         /// <summary>
 
-         /// 获取团组流程日志
 
-         /// </summary>
 
-         /// <param name="groupId">团组ID</param>
 
-         /// <returns>日志列表</returns>
 
-         public async Task<List<Grp_ProcessLog>> GetGroupLogsAsync(int groupId)
 
-         {
 
-             return await _sqlSugar.Queryable<Grp_ProcessLog>()
 
-                 .Where(x => x.GroupId == groupId)
 
-                 .OrderByDescending(x => x.CreateTime)
 
-                 .ToListAsync();
 
-         }
 
-         #endregion
 
-     }
 
- }
 
 
  |