S8RuleParametersPayload.cs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. namespace Admin.NET.Plugin.AiDOP.Service.S8;
  2. /// <summary>
  3. /// S8-RULE-GOVERNANCE-BATCH1:监控规则**运行参数**的部分更新载荷。
  4. ///
  5. /// <para><b>PATCH 语义(G1 的直接修复)</b>:每个字段都是可空的,
  6. /// <b>null / 未提供 = 保持原值</b>。旧的 <c>S8WatchRuleParamsPayload</c> 用的是
  7. /// "整块覆盖 + 缺字段即置 NULL",于是一次 <c>{"enabled":false}</c> 就把 params_json 抹成 NULL,
  8. /// 规则的全部业务配置随之消失(本地 Rule 01 已实测发生:13:34 还在正常命中,
  9. /// 13:40 一次关开关之后 params_json = NULL)。
  10. /// 这里绝不再依赖"前端每次把整块数据带回来"这种客户端自觉。</para>
  11. ///
  12. /// <para><b>本批不支持"清空"语义</b>:两个部门兜底字段传 null 表示"不改",
  13. /// 而不是"清空"。要清空需要能区分「没传」与「显式传 null」,
  14. /// 而 MVC 这里走的是 Newtonsoft 管线,可靠地做出这个区分需要额外的 Optional 包装 +
  15. /// 自定义转换器。本批不引入 —— 清空能力没有当前需求,为它加一层反序列化魔法
  16. /// 反而制造新的静默失败面。缺口已登记,需要时单独做。</para>
  17. ///
  18. /// <para><b>Definition 字段一律拒绝,而不是忽略</b>:见 <see cref="RejectedDefinitionFields"/>。
  19. /// 静默忽略会让调用方以为改成功了 —— 那是比报错更糟的失败形态。</para>
  20. /// </summary>
  21. public sealed class S8RuleParametersPayload
  22. {
  23. // ───────────────── 白名单:真正的运行策略 ─────────────────
  24. /// <summary>轮询间隔(秒)。取值域由该规则的 Definition 声明。</summary>
  25. public int? PollIntervalSeconds { get; set; }
  26. /// <summary>连续命中 N 次才建单。</summary>
  27. public int? TriggerCountRequired { get; set; }
  28. /// <summary>连续未命中 N 次才标 recovered。</summary>
  29. public int? RecoverCountRequired { get; set; }
  30. /// <summary>宽限分钟。</summary>
  31. public int? GraceMinutes { get; set; }
  32. /// <summary>严重度。必须在 Definition 的 AllowedSeverities 内。</summary>
  33. public string? Severity { get; set; }
  34. /// <summary>发生部门兜底。</summary>
  35. public long? DefaultOccurrenceDeptId { get; set; }
  36. /// <summary>责任部门兜底。</summary>
  37. public long? DefaultResponsibleDeptId { get; set; }
  38. // ───────────────── 毒丸:出现即拒绝 ─────────────────
  39. //
  40. // 这些属性存在的**唯一**目的是让旧客户端(或试图绕过治理的调用)得到明确的 400,
  41. // 而不是一个"成功但什么都没发生"的 200。
  42. //
  43. // 为什么用显式属性而不是依赖序列化器的 unknown-member 拒绝:
  44. // 本仓 MVC 走 AddNewtonsoftJson(Admin.NET.Web.Core/Startup.cs),
  45. // System.Text.Json 的 [JsonUnmappedMemberHandling] 在此不生效;
  46. // Newtonsoft 的 MissingMemberHandling 又是全局设置,改它会外溢到 S0–S7 所有接口。
  47. // 声明毒丸属性是唯一既精确、又不依赖序列化器配置的做法。
  48. /// <summary>已退役。params_json 不再由本接口整块写入。</summary>
  49. public string? ParamsJson { get; set; }
  50. /// <summary>已退役。启停走 /enable 与 /disable,见 <c>AdoS8ConfigWatchRulesController</c>。</summary>
  51. public bool? Enabled { get; set; }
  52. /// <summary>已退役:由代码定义。</summary>
  53. public string? DatasetCode { get; set; }
  54. /// <summary>已退役:由代码定义。</summary>
  55. public string? RuleType { get; set; }
  56. /// <summary>已退役:由代码定义。</summary>
  57. public string? SourceObjectType { get; set; }
  58. /// <summary>已退役:由代码定义。</summary>
  59. public string? ExceptionTypeCode { get; set; }
  60. /// <summary>已退役:由代码定义。</summary>
  61. public string? SceneCode { get; set; }
  62. /// <summary>已退役:由代码定义(原可经 /params 修改)。</summary>
  63. public string? StageCode { get; set; }
  64. /// <summary>已退役:由代码定义(原可经 /params 修改)。</summary>
  65. public string? OrderFlowCode { get; set; }
  66. /// <summary>已退役:由代码定义(原可经 /params 修改)。</summary>
  67. public string? RuleMechanism { get; set; }
  68. /// <summary>已退役:由代码定义。</summary>
  69. public string? DueAtField { get; set; }
  70. /// <summary>已退役:由代码定义。</summary>
  71. public string? StatusField { get; set; }
  72. /// <summary>已退役:由代码定义(它决定去重身份)。</summary>
  73. public string? ObjectIdField { get; set; }
  74. /// <summary>已退役:由代码定义。</summary>
  75. public string? ObjectCodeField { get; set; }
  76. /// <summary>已退役:由代码定义。</summary>
  77. public string[]? CompletedStates { get; set; }
  78. /// <summary>
  79. /// 本次请求中出现的、已退役的 Definition 字段名。为空表示载荷合法。
  80. /// </summary>
  81. public IReadOnlyList<string> RejectedDefinitionFields
  82. {
  83. get
  84. {
  85. var found = new List<string>();
  86. void Check(string name, bool present) { if (present) found.Add(name); }
  87. Check("paramsJson", ParamsJson != null);
  88. Check("enabled", Enabled.HasValue);
  89. Check("datasetCode", DatasetCode != null);
  90. Check("ruleType", RuleType != null);
  91. Check("sourceObjectType", SourceObjectType != null);
  92. Check("exceptionTypeCode", ExceptionTypeCode != null);
  93. Check("sceneCode", SceneCode != null);
  94. Check("stageCode", StageCode != null);
  95. Check("orderFlowCode", OrderFlowCode != null);
  96. Check("ruleMechanism", RuleMechanism != null);
  97. Check("dueAtField", DueAtField != null);
  98. Check("statusField", StatusField != null);
  99. Check("objectIdField", ObjectIdField != null);
  100. Check("objectCodeField", ObjectCodeField != null);
  101. Check("completedStates", CompletedStates != null);
  102. return found;
  103. }
  104. }
  105. }
  106. /// <summary>
  107. /// S8-SCHED-FRONTEND-1:调度参数安全更新载荷(保留兼容)。
  108. /// 三个字段现已并入 <see cref="S8RuleParametersPayload"/>,本类型仅供既有
  109. /// <c>PUT /{id}/schedule</c> 路由继续工作;服务端实现已委托到同一条参数写入路径。
  110. /// </summary>
  111. public sealed class S8WatchRuleSchedulePayload
  112. {
  113. public int PollIntervalSeconds { get; set; } = 300;
  114. public int TriggerCountRequired { get; set; } = 1;
  115. public int RecoverCountRequired { get; set; } = 1;
  116. }