S8OutOfRangeParams.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. using System.Text.Json;
  2. namespace Admin.NET.Plugin.AiDOP.Service.S8.Rules;
  3. /// <summary>
  4. /// R3 OUT_OF_RANGE 类规则 params_json 解析结果。internal 可见,供测试覆盖。
  5. /// 兼容两种协议形态:
  6. /// 1. 新协议:measuredValueField / lowerBound / upperBound / lowerBoundField / upperBoundField / objectCodeField / objectIdField / toleranceAbs / toleranceRatio / exceptionTypeCode
  7. /// 2. 旧 G01 兼容:mode=single_threshold / operator=&quot;&gt;&quot;|&quot;&gt;=&quot;|&quot;&lt;&quot;|&quot;&lt;=&quot; / threshold / valueField / objectCodeField / compatAlertRuleCode
  8. /// 字段缺失或非法 JSON:调用方负责降级(evaluator 静默返空命中),不在此抛出业务异常。
  9. /// </summary>
  10. internal sealed class S8OutOfRangeParams
  11. {
  12. public string? MeasuredValueField { get; set; }
  13. public string? ObjectCodeField { get; set; }
  14. public string? ObjectIdField { get; set; }
  15. public string? LowerBoundField { get; set; }
  16. public string? UpperBoundField { get; set; }
  17. public decimal? LowerBound { get; set; }
  18. public decimal? UpperBound { get; set; }
  19. public decimal ToleranceAbs { get; set; }
  20. public decimal ToleranceRatio { get; set; }
  21. public string? ExceptionTypeCode { get; set; }
  22. /// <summary>解析 params_json;非法 JSON 抛 <see cref="JsonException"/>,由上游捕获。</summary>
  23. public static S8OutOfRangeParams Parse(string json)
  24. {
  25. using var doc = JsonDocument.Parse(json);
  26. var root = doc.RootElement;
  27. var p = new S8OutOfRangeParams();
  28. // 新协议字段
  29. if (root.TryGetProperty("measuredValueField", out var v1)) p.MeasuredValueField = v1.GetString();
  30. if (root.TryGetProperty("objectCodeField", out var v2)) p.ObjectCodeField = v2.GetString();
  31. if (root.TryGetProperty("objectIdField", out var v3)) p.ObjectIdField = v3.GetString();
  32. if (root.TryGetProperty("lowerBoundField", out var v4)) p.LowerBoundField = v4.GetString();
  33. if (root.TryGetProperty("upperBoundField", out var v5)) p.UpperBoundField = v5.GetString();
  34. if (root.TryGetProperty("lowerBound", out var v6) && v6.ValueKind == JsonValueKind.Number) p.LowerBound = v6.GetDecimal();
  35. if (root.TryGetProperty("upperBound", out var v7) && v7.ValueKind == JsonValueKind.Number) p.UpperBound = v7.GetDecimal();
  36. if (root.TryGetProperty("toleranceAbs", out var v8) && v8.ValueKind == JsonValueKind.Number) p.ToleranceAbs = v8.GetDecimal();
  37. if (root.TryGetProperty("toleranceRatio", out var v9) && v9.ValueKind == JsonValueKind.Number) p.ToleranceRatio = v9.GetDecimal();
  38. if (root.TryGetProperty("exceptionTypeCode", out var v10)) p.ExceptionTypeCode = v10.GetString();
  39. // G01 兼容:valueField → measuredValueField
  40. if (string.IsNullOrWhiteSpace(p.MeasuredValueField)
  41. && root.TryGetProperty("valueField", out var legacyVal))
  42. p.MeasuredValueField = legacyVal.GetString();
  43. // G01 兼容:mode=single_threshold + operator + threshold → upperBound 或 lowerBound
  44. if (root.TryGetProperty("mode", out var modeEl)
  45. && string.Equals(modeEl.GetString(), "single_threshold", StringComparison.OrdinalIgnoreCase)
  46. && root.TryGetProperty("operator", out var opEl)
  47. && root.TryGetProperty("threshold", out var thrEl)
  48. && thrEl.ValueKind == JsonValueKind.Number)
  49. {
  50. var op = opEl.GetString()?.Trim();
  51. var thr = thrEl.GetDecimal();
  52. // operator '>' 或 '>=' → measured 超过 threshold 命中 → 等价 upperBound=threshold
  53. // operator '<' 或 '<=' → measured 低于 threshold 命中 → 等价 lowerBound=threshold
  54. if (op == ">" || op == ">=") p.UpperBound ??= thr;
  55. else if (op == "<" || op == "<=") p.LowerBound ??= thr;
  56. }
  57. return p;
  58. }
  59. }