Bladeren bron

feat(s8): trigger TB001 intake approval flow on exception create

Hooks all three S8 exception create paths (manual report + R1 watch + R2
auto-create) into a soft-triggered EXCEPTION_REPORT approval flow.
StartFlow failures are logged and swallowed so an unpublished/missing
TB001 definition cannot break exception creation.

Also fixes the empty 发生部门/责任部门 dropdown in 主动提报 by adding
.ClearFilter() on DepartmentMaster/LineMaster — same pattern as
BUG-S8-EMPLOYEES-TENANT-FILTER (S0 master tenant_id != login token
TenantId; factory_ref_id is the actual safe boundary).
YY968XX 3 weken geleden
bovenliggende
commit
20d7b8bb2e
1 gewijzigde bestanden met toevoegingen van 46 en 3 verwijderingen
  1. 46 3
      server/Plugins/Admin.NET.Plugin.AiDOP/Service/S8/S8ManualReportService.cs

+ 46 - 3
server/Plugins/Admin.NET.Plugin.AiDOP/Service/S8/S8ManualReportService.cs

@@ -4,6 +4,8 @@ using Admin.NET.Plugin.AiDOP.Entity.S0.Warehouse;
 using Admin.NET.Plugin.AiDOP.Entity.S8;
 using Admin.NET.Plugin.AiDOP.Infrastructure.S8;
 using Admin.NET.Plugin.AiDOP.Service.S8.Rules;
+using Admin.NET.Plugin.ApprovalFlow.Service;
+using Microsoft.Extensions.Logging;
 
 namespace Admin.NET.Plugin.AiDOP.Service.S8;
 
@@ -22,6 +24,8 @@ public class S8ManualReportService : ITransient
     private readonly SqlSugarRepository<AdoS0DepartmentMaster> _deptRep;
     private readonly SqlSugarRepository<AdoS0LineMaster> _lineRep;
     private readonly UserManager _userManager;
+    private readonly FlowEngineService _flowEngine;
+    private readonly ILogger<S8ManualReportService> _logger;
 
     public S8ManualReportService(
         SqlSugarRepository<AdoS8Exception> rep,
@@ -30,7 +34,9 @@ public class S8ManualReportService : ITransient
         SqlSugarRepository<AdoS8SceneConfig> sceneRep,
         SqlSugarRepository<AdoS0DepartmentMaster> deptRep,
         SqlSugarRepository<AdoS0LineMaster> lineRep,
-        UserManager userManager)
+        UserManager userManager,
+        FlowEngineService flowEngine,
+        ILogger<S8ManualReportService> logger)
     {
         _rep = rep;
         _timelineRep = timelineRep;
@@ -39,6 +45,35 @@ public class S8ManualReportService : ITransient
         _deptRep = deptRep;
         _lineRep = lineRep;
         _userManager = userManager;
+        _flowEngine = flowEngine;
+        _logger = logger;
+    }
+
+    /// <summary>
+    /// TB001 异常提报审批流:自动监控 + 主动提报后软触发,失败仅 warn 日志,不阻断建单。
+    /// </summary>
+    private async Task TryStartIntakeFlowAsync(AdoS8Exception entity)
+    {
+        try
+        {
+            await _flowEngine.StartFlow(new StartFlowInput
+            {
+                BizType = "EXCEPTION_REPORT",
+                BizId = entity.Id,
+                Title = $"异常提报 - {entity.ExceptionCode}",
+                Comment = entity.SourceType == "AUTO_WATCH" ? "自动监控触发" : "主动提报触发",
+                BizData = new Dictionary<string, object>
+                {
+                    ["sceneCode"] = entity.SceneCode ?? "",
+                    ["exceptionTypeCode"] = entity.ExceptionTypeCode ?? "",
+                    ["sourceType"] = entity.SourceType ?? ""
+                }
+            });
+        }
+        catch (Exception ex)
+        {
+            _logger.LogWarning(ex, "TB001 异常提报审批流触发失败 ExceptionId={Id} ExceptionCode={Code}", entity.Id, entity.ExceptionCode);
+        }
     }
 
     public async Task<object> GetFormOptionsAsync(long tenantId, long factoryId)
@@ -48,13 +83,15 @@ public class S8ManualReportService : ITransient
             .OrderBy(x => x.SortNo)
             .Select(x => new { value = x.SceneCode, label = x.SceneName })
             .ToListAsync();
-        var departments = await _deptRep.AsQueryable()
+        // ClearFilter:DepartmentMaster.tenant_id 属 S0 域租户,不与登录 token TenantId 一致;
+        // 用 factory_ref_id 做硬边界,安全等价。同 BUG-S8-EMPLOYEES-TENANT-FILTER 协议。
+        var departments = await _deptRep.AsQueryable().ClearFilter()
             .Where(x => x.FactoryRefId == factoryId)
             .OrderBy(x => x.Department)
             .Take(500)
             .Select(x => new { value = x.Id, label = x.Descr ?? x.Department })
             .ToListAsync();
-        var lines = await _lineRep.AsQueryable()
+        var lines = await _lineRep.AsQueryable().ClearFilter()
             .Where(x => x.FactoryRefId == factoryId)
             .OrderBy(x => x.Line)
             .Take(500)
@@ -127,6 +164,8 @@ public class S8ManualReportService : ITransient
             });
         }, ex => throw ex);
 
+        await TryStartIntakeFlowAsync(entity);
+
         return new AdoS8ManualReportResultDto
         {
             ExceptionId = entity.Id,
@@ -204,6 +243,8 @@ public class S8ManualReportService : ITransient
             });
         }, ex => throw ex);
 
+        await TryStartIntakeFlowAsync(entity);
+
         return entity;
     }
 
@@ -274,6 +315,8 @@ public class S8ManualReportService : ITransient
             });
         }, ex => throw ex);
 
+        await TryStartIntakeFlowAsync(entity);
+
         return entity;
     }