namespace Admin.NET.Plugin.AiDOP.Const.S8; /// /// S8-RESPONSIBILITY-POOL-1:规则的三种责任类型。 /// /// 与角色严格分离SysRole 回答「这个账号能做什么」 /// (认领 / 转派 / 审核 / 升级这类动作权限);责任池回答「这个账号负责什么」 /// (哪一条规则产生的异常归他)。最终允许 = 动作权限 ∩ 规则责任 ∩ 状态机。 /// /// 刻意不引入 Supervisor / 部门负责人 / L1-L2-L3 三层虚拟层级: /// 系统里不存在组织主管关系(SysOrg.DirectorIdSysUser.ManagerUserId /// 实测填充率均为 0),拿它当产品主模型只会配出一条永远解析为空的责任链。 /// 将来业务真需要层级升级时,另建真正的 Escalation Policy,不在这里假装。 /// public static class S8ResponsibilityType { /// 处理账号池:谁负责处理这条规则产生的异常。存量表 ado_s8_rule_handler_user public const string Handler = "HANDLER"; /// 复核账号池:谁有资格被选为这条规则的复核人。 public const string Reviewer = "REVIEWER"; /// 升级账号池:异常超时 / 触发升级时找谁。 public const string Escalation = "ESCALATION"; } /// 责任类型的展示元信息。后端校验、配置接口、前端 UI 三方共用同一份。 /// 类型编码。 /// 业务用户看到的名字(不出现任何技术术语)。 /// 页面上的一句话说明。 /// 展示顺序。 public sealed record S8ResponsibilityDefinition(string Code, string DisplayName, string Description, int OrderNo); /// 责任类型目录。 public static class S8ResponsibilityCatalog { public static readonly IReadOnlyList All = new List { new(S8ResponsibilityType.Handler, "处理人员", "以下账号负责处理该规则产生的异常。", 10), new(S8ResponsibilityType.Reviewer, "复核人员", "处理人提交复核时,只能从以下账号中选择复核人。", 20), new(S8ResponsibilityType.Escalation, "升级人员", "异常超时或触发升级时通知以下账号。", 30), }; private static readonly HashSet TypeSet = All.Select(x => x.Code).ToHashSet(StringComparer.OrdinalIgnoreCase); public static bool IsKnown(string? code) => !string.IsNullOrWhiteSpace(code) && TypeSet.Contains(code!); public static S8ResponsibilityDefinition? Find(string? code) => string.IsNullOrWhiteSpace(code) ? null : All.FirstOrDefault(x => string.Equals(x.Code, code, StringComparison.OrdinalIgnoreCase)); /// /// 存储在新表 ado_s8_rule_responsibility_user 里的类型。 /// /// HANDLER 不在其中:它有稳定的存量表与生产读路径(就绪门禁 / 认领资格 / /// 可见性收敛 / 通知解析都已依赖),为了"三张表长得一样"去迁它,收益是审美、 /// 代价是动四条已验证的链路。调用方通过统一 reader 拿到一致的 API, /// 存储差异被收敛在一处。 /// public static bool IsStoredInResponsibilityTable(string? code) => string.Equals(code, S8ResponsibilityType.Reviewer, StringComparison.OrdinalIgnoreCase) || string.Equals(code, S8ResponsibilityType.Escalation, StringComparison.OrdinalIgnoreCase); }