Просмотр исходного кода

fix(s8): filter soft-deleted rows in generated expressions

YY968XX 4 месяцев назад
Родитель
Сommit
64e590f130

+ 16 - 2
server/Plugins/Admin.NET.Plugin.AiDOP/Service/S8/S8ConfigDraftService.cs

@@ -459,6 +459,18 @@ public class S8ConfigDraftService : ITransient
     private const string ValuePlaceholderExpression =
         "SELECT 'DEMO-OBJECT-001' AS related_object_code, 'DEMO-OBJECT-001' AS source_object_id, 'DEMO-OBJECT-001' AS related_object_name, 0 AS measured_value WHERE 1=0";
 
+    /// <summary>
+    /// 含逻辑删除字段的源表追加过滤,避免规则启用后误命中已软删行。
+    /// 当前仅 ic_item_stock 含 IsDeleted bit(1);其他表无 schema 元数据,不追加。
+    /// </summary>
+    private static string BuildSoftDeletePredicate(string? sourceTable)
+    {
+        if (string.IsNullOrWhiteSpace(sourceTable)) return string.Empty;
+        if (sourceTable.Equals("ic_item_stock", StringComparison.OrdinalIgnoreCase))
+            return " AND IsDeleted = 0";
+        return string.Empty;
+    }
+
     private static string BuildExpression(string mechanism, AdoS8MonitorObject monitorObject, AdoS8MonitorMetric metric, S8WizardFormV1 form)
     {
         var sourceTable = NormalizeOrNull(monitorObject.SourceTable);
@@ -493,7 +505,8 @@ public class S8ConfigDraftService : ITransient
                 stateClause = $" AND {statusCol} NOT IN ({quoted})";
             }
 
-            return $"SELECT {idCol} AS source_object_id, {codeCol} AS related_object_code, {nameCol} AS related_object_name, {dueCol} AS due_at, {statusCol} AS status FROM {table} WHERE {dueCol} IS NOT NULL AND {dueCol} < {graceClause}{stateClause}";
+            var softDeleteClause = BuildSoftDeletePredicate(table);
+            return $"SELECT {idCol} AS source_object_id, {codeCol} AS related_object_code, {nameCol} AS related_object_name, {dueCol} AS due_at, {statusCol} AS status FROM {table} WHERE {dueCol} IS NOT NULL AND {dueCol} < {graceClause}{stateClause}{softDeleteClause}";
         }
 
         if (mechanism == "VALUE_RANGE")
@@ -507,7 +520,8 @@ public class S8ConfigDraftService : ITransient
             if (upper.HasValue) preds.Add($"{mvCol} > {upper.Value.ToString(CultureInfo.InvariantCulture)}");
             var oorClause = preds.Count > 0 ? " AND (" + string.Join(" OR ", preds) + ")" : string.Empty;
 
-            return $"SELECT {idCol} AS source_object_id, {codeCol} AS related_object_code, {nameCol} AS related_object_name, {mvCol} AS measured_value FROM {table} WHERE {mvCol} IS NOT NULL{oorClause}";
+            var softDeleteClause = BuildSoftDeletePredicate(table);
+            return $"SELECT {idCol} AS source_object_id, {codeCol} AS related_object_code, {nameCol} AS related_object_name, {mvCol} AS measured_value FROM {table} WHERE {mvCol} IS NOT NULL{oorClause}{softDeleteClause}";
         }
 
         // RATIO 在上游已被拒绝(metric.Enabled=false 触发 400),此处兜底返回数值占位。