namespace Admin.NET.Plugin.AiDOP.Service.S8; /// /// S8-RULE-GOVERNANCE-BATCH1:监控规则**运行参数**的部分更新载荷。 /// /// PATCH 语义(G1 的直接修复):每个字段都是可空的, /// null / 未提供 = 保持原值。旧的 S8WatchRuleParamsPayload 用的是 /// "整块覆盖 + 缺字段即置 NULL",于是一次 {"enabled":false} 就把 params_json 抹成 NULL, /// 规则的全部业务配置随之消失(本地 Rule 01 已实测发生:13:34 还在正常命中, /// 13:40 一次关开关之后 params_json = NULL)。 /// 这里绝不再依赖"前端每次把整块数据带回来"这种客户端自觉。 /// /// 本批不支持"清空"语义:两个部门兜底字段传 null 表示"不改", /// 而不是"清空"。要清空需要能区分「没传」与「显式传 null」, /// 而 MVC 这里走的是 Newtonsoft 管线,可靠地做出这个区分需要额外的 Optional 包装 + /// 自定义转换器。本批不引入 —— 清空能力没有当前需求,为它加一层反序列化魔法 /// 反而制造新的静默失败面。缺口已登记,需要时单独做。 /// /// Definition 字段一律拒绝,而不是忽略:见 。 /// 静默忽略会让调用方以为改成功了 —— 那是比报错更糟的失败形态。 /// public sealed class S8RuleParametersPayload { // ───────────────── 白名单:真正的运行策略 ───────────────── /// 轮询间隔(秒)。取值域由该规则的 Definition 声明。 public int? PollIntervalSeconds { get; set; } /// 连续命中 N 次才建单。 public int? TriggerCountRequired { get; set; } /// 连续未命中 N 次才标 recovered。 public int? RecoverCountRequired { get; set; } /// 宽限分钟。 public int? GraceMinutes { get; set; } /// 严重度。必须在 Definition 的 AllowedSeverities 内。 public string? Severity { get; set; } /// 发生部门兜底。 public long? DefaultOccurrenceDeptId { get; set; } /// 责任部门兜底。 public long? DefaultResponsibleDeptId { get; set; } // ───────────────── 毒丸:出现即拒绝 ───────────────── // // 这些属性存在的**唯一**目的是让旧客户端(或试图绕过治理的调用)得到明确的 400, // 而不是一个"成功但什么都没发生"的 200。 // // 为什么用显式属性而不是依赖序列化器的 unknown-member 拒绝: // 本仓 MVC 走 AddNewtonsoftJson(Admin.NET.Web.Core/Startup.cs), // System.Text.Json 的 [JsonUnmappedMemberHandling] 在此不生效; // Newtonsoft 的 MissingMemberHandling 又是全局设置,改它会外溢到 S0–S7 所有接口。 // 声明毒丸属性是唯一既精确、又不依赖序列化器配置的做法。 /// 已退役。params_json 不再由本接口整块写入。 public string? ParamsJson { get; set; } /// 已退役。启停走 /enable 与 /disable,见 AdoS8ConfigWatchRulesController public bool? Enabled { get; set; } /// 已退役:由代码定义。 public string? DatasetCode { get; set; } /// 已退役:由代码定义。 public string? RuleType { get; set; } /// 已退役:由代码定义。 public string? SourceObjectType { get; set; } /// 已退役:由代码定义。 public string? ExceptionTypeCode { get; set; } /// 已退役:由代码定义。 public string? SceneCode { get; set; } /// 已退役:由代码定义(原可经 /params 修改)。 public string? StageCode { get; set; } /// 已退役:由代码定义(原可经 /params 修改)。 public string? OrderFlowCode { get; set; } /// 已退役:由代码定义(原可经 /params 修改)。 public string? RuleMechanism { get; set; } /// 已退役:由代码定义。 public string? DueAtField { get; set; } /// 已退役:由代码定义。 public string? StatusField { get; set; } /// 已退役:由代码定义(它决定去重身份)。 public string? ObjectIdField { get; set; } /// 已退役:由代码定义。 public string? ObjectCodeField { get; set; } /// 已退役:由代码定义。 public string[]? CompletedStates { get; set; } /// /// 本次请求中出现的、已退役的 Definition 字段名。为空表示载荷合法。 /// public IReadOnlyList RejectedDefinitionFields { get { var found = new List(); void Check(string name, bool present) { if (present) found.Add(name); } Check("paramsJson", ParamsJson != null); Check("enabled", Enabled.HasValue); Check("datasetCode", DatasetCode != null); Check("ruleType", RuleType != null); Check("sourceObjectType", SourceObjectType != null); Check("exceptionTypeCode", ExceptionTypeCode != null); Check("sceneCode", SceneCode != null); Check("stageCode", StageCode != null); Check("orderFlowCode", OrderFlowCode != null); Check("ruleMechanism", RuleMechanism != null); Check("dueAtField", DueAtField != null); Check("statusField", StatusField != null); Check("objectIdField", ObjectIdField != null); Check("objectCodeField", ObjectCodeField != null); Check("completedStates", CompletedStates != null); return found; } } } /// /// S8-SCHED-FRONTEND-1:调度参数安全更新载荷(保留兼容)。 /// 三个字段现已并入 ,本类型仅供既有 /// PUT /{id}/schedule 路由继续工作;服务端实现已委托到同一条参数写入路径。 /// public sealed class S8WatchRuleSchedulePayload { public int PollIntervalSeconds { get; set; } = 300; public int TriggerCountRequired { get; set; } = 1; public int RecoverCountRequired { get; set; } = 1; }