using Admin.NET.Plugin.AiDOP.Entity.S8; using Admin.NET.Plugin.AiDOP.Infrastructure.S8; using Admin.NET.Plugin.ApprovalFlow.Service; namespace Admin.NET.Plugin.AiDOP.Service.S8; public class S8TaskFlowService : ITransient { private readonly SqlSugarRepository _rep; private readonly SqlSugarRepository _timelineRep; private readonly FlowEngineService _flowEngine; public S8TaskFlowService( SqlSugarRepository rep, SqlSugarRepository timelineRep, FlowEngineService flowEngine) { _rep = rep; _timelineRep = timelineRep; _flowEngine = flowEngine; } public async Task ClaimAsync(long id, long tenantId, long factoryId, long assigneeId, string? remark) { if (assigneeId <= 0) throw new S8BizException("认领需指定处理人 AssigneeId"); var e = await LoadAsync(id, tenantId, factoryId) ?? throw new S8BizException("异常不存在"); if (!S8StatusRules.IsAllowedTransition(e.Status, "ASSIGNED")) throw new S8BizException($"状态 {e.Status} 不可认领"); var fromStatus = e.Status; e.Status = "ASSIGNED"; e.AssigneeId = assigneeId; e.AssignedAt = DateTime.Now; e.UpdatedAt = DateTime.Now; await _rep.AsTenant().UseTranAsync(async () => { await _rep.UpdateAsync(e); await InsertTimelineAsync(e.Id, "CLAIM", "认领", fromStatus, "ASSIGNED", assigneeId, null, remark); }, ex => throw ex); return e; } public async Task TransferAsync(long id, long tenantId, long factoryId, long newAssigneeId, string? remark) { if (newAssigneeId <= 0) throw new S8BizException("转派目标无效"); var e = await LoadAsync(id, tenantId, factoryId) ?? throw new S8BizException("异常不存在"); if (S8StatusRules.IsTerminal(e.Status)) throw new S8BizException("已关闭不可转派"); e.AssigneeId = newAssigneeId; e.UpdatedAt = DateTime.Now; await _rep.AsTenant().UseTranAsync(async () => { await _rep.UpdateAsync(e); await InsertTimelineAsync(e.Id, "TRANSFER", "转派", e.Status, e.Status, newAssigneeId, null, remark); }, ex => throw ex); return e; } public async Task UpgradeAsync(long id, long tenantId, long factoryId, string? remark) { var e = await LoadAsync(id, tenantId, factoryId) ?? throw new S8BizException("异常不存在"); if (e.ActiveFlowInstanceId.HasValue) throw new S8BizException("该异常已有进行中的审批流程,请等待审批完成"); if (!S8StatusRules.IsAllowedTransition(e.Status, "ESCALATED")) throw new S8BizException($"状态 {e.Status} 不可升级"); await _flowEngine.StartFlow(new StartFlowInput { BizType = "EXCEPTION_ESCALATION", BizId = e.Id, Title = $"异常升级审批 - {e.ExceptionCode}", Comment = remark, BizData = new Dictionary { ["severity"] = e.Severity, ["sceneCode"] = e.SceneCode, ["priorityLevel"] = e.PriorityLevel, } }); // 状态和时间线由 ExceptionEscalationBizHandler.OnFlowStarted 回调更新 return await LoadAsync(id, tenantId, factoryId) ?? e; } public async Task RejectAsync(long id, long tenantId, long factoryId, string? remark) { var e = await LoadAsync(id, tenantId, factoryId) ?? throw new S8BizException("异常不存在"); if (!S8StatusRules.IsAllowedTransition(e.Status, "REJECTED")) throw new S8BizException($"状态 {e.Status} 不可驳回"); var from = e.Status; e.Status = "REJECTED"; e.UpdatedAt = DateTime.Now; await _rep.AsTenant().UseTranAsync(async () => { await _rep.UpdateAsync(e); await InsertTimelineAsync(e.Id, "REJECT", "驳回", from, "REJECTED", null, null, remark); }, ex => throw ex); return e; } public async Task CloseAsync(long id, long tenantId, long factoryId, string? remark) { var e = await LoadAsync(id, tenantId, factoryId) ?? throw new S8BizException("异常不存在"); if (e.ActiveFlowInstanceId.HasValue) throw new S8BizException("该异常已有进行中的审批流程,请等待审批完成"); if (!S8StatusRules.IsAllowedTransition(e.Status, "CLOSED")) throw new S8BizException($"状态 {e.Status} 不可关闭"); await _flowEngine.StartFlow(new StartFlowInput { BizType = "EXCEPTION_CLOSURE", BizId = e.Id, Title = $"异常关闭确认 - {e.ExceptionCode}", Comment = remark, BizData = new Dictionary { ["sceneCode"] = e.SceneCode, } }); // 状态和时间线由 ExceptionClosureBizHandler.OnFlowStarted 回调更新 return await LoadAsync(id, tenantId, factoryId) ?? e; } public async Task CommentAsync(long id, string? remark) { var e = await _rep.GetFirstAsync(x => x.Id == id && !x.IsDeleted) ?? throw new S8BizException("异常不存在"); await InsertTimelineAsync(e.Id, "COMMENT", "补充说明", e.Status, e.Status, null, null, remark); } private Task LoadAsync(long id, long tenantId, long factoryId) => _rep.GetFirstAsync(x => x.Id == id && x.TenantId == tenantId && x.FactoryId == factoryId && !x.IsDeleted); private async Task InsertTimelineAsync(long exceptionId, string code, string label, string? from, string? to, long? operatorId, string? operatorName, string? remark) => await _timelineRep.InsertAsync(new AdoS8ExceptionTimeline { ExceptionId = exceptionId, ActionCode = code, ActionLabel = label, FromStatus = from, ToStatus = to, OperatorId = operatorId, OperatorName = operatorName, ActionRemark = remark, CreatedAt = DateTime.Now }); }