permUtils.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import { pinyin } from 'pinyin-pro';
  2. // ---- 类型 ----
  3. export interface PermGroup {
  4. modelName: string;
  5. apiPerms: API.PermItem[];
  6. dataPerms: API.PermItem[];
  7. fieldPerms: API.PermItem[];
  8. }
  9. // ---- 排序 ----
  10. export const sortPerms = (perms: API.PermItem[]): API.PermItem[] =>
  11. [...perms].sort((a, b) => {
  12. const partsA = a.code.split(':');
  13. const partsB = b.code.split(':');
  14. const modelA = partsA[1] ?? '';
  15. const modelB = partsB[1] ?? '';
  16. if (modelA !== modelB) return modelA.localeCompare(modelB);
  17. const isFieldA = partsA.length === 4;
  18. const isFieldB = partsB.length === 4;
  19. if (isFieldA !== isFieldB) return isFieldA ? 1 : -1;
  20. return a.code.localeCompare(b.code);
  21. });
  22. // ---- 分组 ----
  23. export const groupPerms = (perms: API.PermItem[]): PermGroup[] => {
  24. const map = new Map<string, PermGroup>();
  25. for (const p of perms) {
  26. const parts = p.code.split(':');
  27. const type = parts[0];
  28. const model = parts[1] ?? 'unknown';
  29. if (!map.has(model)) {
  30. map.set(model, { modelName: model, apiPerms: [], dataPerms: [], fieldPerms: [] });
  31. }
  32. const g = map.get(model)!;
  33. if (type === 'api') {
  34. g.apiPerms.push(p);
  35. } else if (parts.length === 4) {
  36. g.fieldPerms.push(p);
  37. } else {
  38. g.dataPerms.push(p);
  39. }
  40. }
  41. return [...map.values()].sort((a, b) => a.modelName.localeCompare(b.modelName));
  42. };
  43. // ---- 搜索(缓存拼音结果) ----
  44. const pinyinCache = new Map<string, { full: string; initials: string }>();
  45. const getPermPinyin = (name: string) => {
  46. let cached = pinyinCache.get(name);
  47. if (!cached) {
  48. cached = {
  49. full: pinyin(name, { toneType: 'none', type: 'array' }).join('').toLowerCase(),
  50. initials: pinyin(name, { pattern: 'first', toneType: 'none', type: 'array' })
  51. .join('')
  52. .toLowerCase(),
  53. };
  54. pinyinCache.set(name, cached);
  55. }
  56. return cached;
  57. };
  58. export const matchesPerm = (perm: API.PermItem, keyword: string): boolean => {
  59. if (!keyword) return true;
  60. const k = keyword.toLowerCase();
  61. if (perm.code.toLowerCase().includes(k)) return true;
  62. if (perm.name.toLowerCase().includes(k)) return true;
  63. const py = getPermPinyin(perm.name);
  64. return py.full.includes(k) || py.initials.includes(k);
  65. };
  66. // ---- 用户权限 delta 计算 ----
  67. export const calcUserPermDelta = (
  68. checkedIds: number[],
  69. roleInheritedIds: number[],
  70. ): API.UserPermItem[] => {
  71. const checked = new Set(checkedIds);
  72. const inherited = new Set(roleInheritedIds);
  73. return [
  74. ...checkedIds
  75. .filter((id) => !inherited.has(id))
  76. .map((id) => ({ permId: id, effect: 'ALLOW' as const })),
  77. ...[...inherited]
  78. .filter((id) => !checked.has(id))
  79. .map((id) => ({ permId: id, effect: 'DENY' as const })),
  80. ];
  81. };
  82. // ---- pair 查找(Map 预构建,O(1) 查找) ----
  83. export const buildPairMap = (allPerms: API.PermItem[]): Map<string, number> => {
  84. const map = new Map<string, number>();
  85. for (const p of allPerms) {
  86. map.set(p.code, p.id);
  87. }
  88. return map;
  89. };
  90. export const getPairId = (perm: API.PermItem, pairMap: Map<string, number>): number | undefined => {
  91. const parts = perm.code.split(':');
  92. if (parts.length !== 3) return undefined;
  93. const [type, model, action] = parts;
  94. const pairType = type === 'api' ? 'data' : 'api';
  95. return pairMap.get(`${pairType}:${model}:${action}`);
  96. };