namespace Admin.NET.Plugin.AiDOP.Dto.S8;
///
/// S8-RULE-GOVERNANCE-BATCH4:监控规则配置页的**只读行模型**。
///
/// 为什么需要它:在此之前 GET /config/watch-rules 直接返回实体
/// AdoS8WatchRule,前端只能拿到数据库投影列。而规则的业务语义
/// (规则名称、业务说明、异常类型、判定口径)自 Batch 1 起只存在于代码定义里,
/// 数据库上根本没有对应列 —— 页面想把「基础定义」做成只读展示,就无处取数。
/// 唯一的替代是前端按 ruleCode 硬编码,那等于把代码定义抄了第二份,必然漂移。
///
/// 结构刻意分三段,与页面的三个区一一对应,让「谁能改什么」在类型上就看得见:
///
/// - Definition:代码定义投影,全只读;
/// - Parameters:租户可调的白名单参数;
/// - Runtime:调度运行态,系统写、页面只读。
///
///
/// 刻意不含的字段:LockToken / LockedBy / LockUntil /
/// RunningStartedAt —— 调度租约是内部实现细节,规则管理员不需要,
/// 暴露出去只会让人以为可以手动干预。ParamsJson 原文同理不外发:
/// 页面拿到的是解析后的强类型参数,不是那段自由文本。
///
public sealed class S8WatchRuleRowDto
{
// ─────────────── 身份与归属 ───────────────
public long Id { get; init; }
public long TenantId { get; init; }
/// 历史兼容列。Tenant-only 改造(Batch 5/6)后将退出全部隔离语义。
public long FactoryId { get; init; }
/// 规则编码。定义与运行策略共同的身份。
public string RuleCode { get; init; } = string.Empty;
// ─────────────── 代码定义投影(全只读)───────────────
///
/// 该规则在当前代码版本中没有定义(孤儿行)。
/// 页面据此禁用参数保存 / 启用 / 预演,并提示"当前版本未找到规则定义",
/// 而不是拿着一堆 null 崩掉或假装它是条正常规则。
///
public bool DefinitionMissing { get; init; }
/// 规则名称。孤儿行为 null,页面回落显示 。
public string? DisplayName { get; init; }
/// 业务说明。
public string? Description { get; init; }
/// 数据集编码(内部编码,详情页可见)。
public string? DatasetCode { get; init; }
/// 数据集业务名称。优先展示它而不是编码。
public string? DatasetDisplayName { get; init; }
public string? RuleType { get; init; }
public string? RuleMechanism { get; init; }
/// 业务对象类型。
public string? SourceObjectType { get; init; }
public string? SceneCode { get; init; }
public string? StageCode { get; init; }
public string? OrderFlowCode { get; init; }
/// 命中后建立的异常类型。自 Batch 1 起只存在于代码定义,数据库上已无此信息。
public string? ExceptionTypeCode { get; init; }
/// 判定口径的业务语言说明。不含表名 / 列名 / SQL。
public string? JudgementSummary { get; init; }
/// 视为「已完成」的状态集合。
public IReadOnlyList CompletedStates { get; init; } = Array.Empty();
/// 去重身份的业务语言说明。
public string? DedupIdentitySummary { get; init; }
/// 该规则开放调整的参数取值域。孤儿行为 null。
public S8RuleParameterPolicyDto? AllowedParameters { get; init; }
// ─────────────── 租户运行参数(可调)───────────────
public bool Enabled { get; init; }
public string Severity { get; init; } = string.Empty;
public int PollIntervalSeconds { get; init; }
public int TriggerCountRequired { get; init; }
public int RecoverCountRequired { get; init; }
/// 宽限分钟。解析自 params_json 的 B 类参数,页面无需接触原文。
public int GraceMinutes { get; init; }
public long? DefaultOccurrenceDeptId { get; init; }
public long? DefaultResponsibleDeptId { get; init; }
// ─────────────── 运行态(只读)───────────────
public DateTime? NextRunAt { get; init; }
public DateTime? LastRunAt { get; init; }
public string? LastStatus { get; init; }
public string? LastError { get; init; }
public int? LastDurationMs { get; init; }
public string? LastRunId { get; init; }
public int ConsecutiveFailureCount { get; init; }
public DateTime? PausedUntil { get; init; }
public string? PauseReason { get; init; }
public DateTime CreatedAt { get; init; }
public DateTime? UpdatedAt { get; init; }
}
///
/// 参数取值域,供页面渲染输入控件的 min / max / 默认值与可选项。
///
/// 下发取值域而不是让前端写死:取值域随规则定义走
/// (不同规则对"宽限多久算合理"的判断本就不同),前端写死会在新增规则时静默不一致。
/// 服务端仍然是唯一权威 —— 这里只是让 UI 能提前拦住明显越界,不是把校验外包给前端。
///
public sealed class S8RuleParameterPolicyDto
{
public int PollIntervalSecondsMin { get; init; }
public int PollIntervalSecondsMax { get; init; }
public int TriggerCountRequiredMin { get; init; }
public int TriggerCountRequiredMax { get; init; }
public int RecoverCountRequiredMin { get; init; }
public int RecoverCountRequiredMax { get; init; }
public int GraceMinutesMin { get; init; }
/// 宽限分钟无业务上限;下发 int.MaxValue 时前端不应渲染成有意义的上界。
public int GraceMinutesMax { get; init; }
public IReadOnlyList AllowedSeverities { get; init; } = Array.Empty();
/// 是否允许配置部门兜底。
public bool AllowsDepartmentDefaults { get; init; }
///
/// S8-RULE-READINESS-1:两个默认部门是否为启用前置条件。
/// 前端据此在启用前拦截并提示具体缺项;**后端仍独立校验**,前端只是 UX。
///
public bool RequiresDepartmentDefaultsForEnable { get; init; }
}