AdoS8WatchRuleRowDtos.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. namespace Admin.NET.Plugin.AiDOP.Dto.S8;
  2. /// <summary>
  3. /// S8-RULE-GOVERNANCE-BATCH4:监控规则配置页的**只读行模型**。
  4. ///
  5. /// <para><b>为什么需要它</b>:在此之前 <c>GET /config/watch-rules</c> 直接返回实体
  6. /// <c>AdoS8WatchRule</c>,前端只能拿到数据库投影列。而规则的业务语义
  7. /// (规则名称、业务说明、异常类型、判定口径)自 Batch 1 起只存在于代码定义里,
  8. /// 数据库上根本没有对应列 —— 页面想把「基础定义」做成只读展示,就无处取数。
  9. /// 唯一的替代是前端按 ruleCode 硬编码,那等于把代码定义抄了第二份,必然漂移。</para>
  10. ///
  11. /// <para><b>结构刻意分三段</b>,与页面的三个区一一对应,让「谁能改什么」在类型上就看得见:</para>
  12. /// <list type="bullet">
  13. /// <item><b>Definition</b>:代码定义投影,全只读;</item>
  14. /// <item><b>Parameters</b>:租户可调的白名单参数;</item>
  15. /// <item><b>Runtime</b>:调度运行态,系统写、页面只读。</item>
  16. /// </list>
  17. ///
  18. /// <para><b>刻意不含的字段</b>:<c>LockToken</c> / <c>LockedBy</c> / <c>LockUntil</c> /
  19. /// <c>RunningStartedAt</c> —— 调度租约是内部实现细节,规则管理员不需要,
  20. /// 暴露出去只会让人以为可以手动干预。<c>ParamsJson</c> 原文同理不外发:
  21. /// 页面拿到的是解析后的强类型参数,不是那段自由文本。</para>
  22. /// </summary>
  23. public sealed class S8WatchRuleRowDto
  24. {
  25. // ─────────────── 身份与归属 ───────────────
  26. public long Id { get; init; }
  27. public long TenantId { get; init; }
  28. /// <summary>历史兼容列。Tenant-only 改造(Batch 5/6)后将退出全部隔离语义。</summary>
  29. public long FactoryId { get; init; }
  30. /// <summary>规则编码。定义与运行策略共同的身份。</summary>
  31. public string RuleCode { get; init; } = string.Empty;
  32. // ─────────────── 代码定义投影(全只读)───────────────
  33. /// <summary>
  34. /// 该规则在当前代码版本中没有定义(孤儿行)。
  35. /// 页面据此禁用参数保存 / 启用 / 预演,并提示"当前版本未找到规则定义",
  36. /// 而不是拿着一堆 null 崩掉或假装它是条正常规则。
  37. /// </summary>
  38. public bool DefinitionMissing { get; init; }
  39. /// <summary>规则名称。孤儿行为 null,页面回落显示 <see cref="RuleCode"/>。</summary>
  40. public string? DisplayName { get; init; }
  41. /// <summary>业务说明。</summary>
  42. public string? Description { get; init; }
  43. /// <summary>数据集编码(内部编码,详情页可见)。</summary>
  44. public string? DatasetCode { get; init; }
  45. /// <summary>数据集业务名称。优先展示它而不是编码。</summary>
  46. public string? DatasetDisplayName { get; init; }
  47. public string? RuleType { get; init; }
  48. public string? RuleMechanism { get; init; }
  49. /// <summary>业务对象类型。</summary>
  50. public string? SourceObjectType { get; init; }
  51. public string? SceneCode { get; init; }
  52. public string? StageCode { get; init; }
  53. public string? OrderFlowCode { get; init; }
  54. /// <summary>命中后建立的异常类型。自 Batch 1 起只存在于代码定义,数据库上已无此信息。</summary>
  55. public string? ExceptionTypeCode { get; init; }
  56. /// <summary>判定口径的业务语言说明。不含表名 / 列名 / SQL。</summary>
  57. public string? JudgementSummary { get; init; }
  58. /// <summary>视为「已完成」的状态集合。</summary>
  59. public IReadOnlyList<string> CompletedStates { get; init; } = Array.Empty<string>();
  60. /// <summary>去重身份的业务语言说明。</summary>
  61. public string? DedupIdentitySummary { get; init; }
  62. /// <summary>该规则开放调整的参数取值域。孤儿行为 null。</summary>
  63. public S8RuleParameterPolicyDto? AllowedParameters { get; init; }
  64. // ─────────────── 租户运行参数(可调)───────────────
  65. public bool Enabled { get; init; }
  66. public string Severity { get; init; } = string.Empty;
  67. public int PollIntervalSeconds { get; init; }
  68. public int TriggerCountRequired { get; init; }
  69. public int RecoverCountRequired { get; init; }
  70. /// <summary>宽限分钟。解析自 params_json 的 B 类参数,页面无需接触原文。</summary>
  71. public int GraceMinutes { get; init; }
  72. public long? DefaultOccurrenceDeptId { get; init; }
  73. public long? DefaultResponsibleDeptId { get; init; }
  74. // ─────────────── 运行态(只读)───────────────
  75. public DateTime? NextRunAt { get; init; }
  76. public DateTime? LastRunAt { get; init; }
  77. public string? LastStatus { get; init; }
  78. public string? LastError { get; init; }
  79. public int? LastDurationMs { get; init; }
  80. public string? LastRunId { get; init; }
  81. public int ConsecutiveFailureCount { get; init; }
  82. public DateTime? PausedUntil { get; init; }
  83. public string? PauseReason { get; init; }
  84. public DateTime CreatedAt { get; init; }
  85. public DateTime? UpdatedAt { get; init; }
  86. }
  87. /// <summary>
  88. /// 参数取值域,供页面渲染输入控件的 min / max / 默认值与可选项。
  89. ///
  90. /// <para>下发取值域而不是让前端写死:取值域随规则定义走
  91. /// (不同规则对"宽限多久算合理"的判断本就不同),前端写死会在新增规则时静默不一致。
  92. /// 服务端仍然是唯一权威 —— 这里只是让 UI 能提前拦住明显越界,不是把校验外包给前端。</para>
  93. /// </summary>
  94. public sealed class S8RuleParameterPolicyDto
  95. {
  96. public int PollIntervalSecondsMin { get; init; }
  97. public int PollIntervalSecondsMax { get; init; }
  98. public int TriggerCountRequiredMin { get; init; }
  99. public int TriggerCountRequiredMax { get; init; }
  100. public int RecoverCountRequiredMin { get; init; }
  101. public int RecoverCountRequiredMax { get; init; }
  102. public int GraceMinutesMin { get; init; }
  103. /// <summary>宽限分钟无业务上限;下发 <c>int.MaxValue</c> 时前端不应渲染成有意义的上界。</summary>
  104. public int GraceMinutesMax { get; init; }
  105. public IReadOnlyList<string> AllowedSeverities { get; init; } = Array.Empty<string>();
  106. /// <summary>是否允许配置部门兜底。</summary>
  107. public bool AllowsDepartmentDefaults { get; init; }
  108. /// <summary>
  109. /// S8-RULE-READINESS-1:两个默认部门是否为启用前置条件。
  110. /// 前端据此在启用前拦截并提示具体缺项;**后端仍独立校验**,前端只是 UX。
  111. /// </summary>
  112. public bool RequiresDepartmentDefaultsForEnable { get; init; }
  113. }