S8ResponsibilityCatalog.cs 3.7 KB

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