permission.ts 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. import type { AppRouteRecordRaw, Menu } from '/@/router/types';
  2. import { defineStore } from 'pinia';
  3. import { store } from '/@/store';
  4. import { useI18n } from '/@/hooks/web/useI18n';
  5. import { useUserStore } from './user';
  6. import { useAppStoreWithOut } from './app';
  7. import { toRaw } from 'vue';
  8. import { transformObjToRoute, flatMultiLevelRoutes } from '/@/router/helper/routeHelper';
  9. import { transformRouteToMenu } from '/@/router/helper/menuHelper';
  10. import projectSetting from '/@/settings/projectSetting';
  11. import { PermissionModeEnum } from '/@/enums/appEnum';
  12. import { asyncRoutes } from '/@/router/routes';
  13. import { ERROR_LOG_ROUTE, PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic';
  14. import { filter } from '/@/utils/helper/treeHelper';
  15. import { getMenuList } from '/@/api/sys/menu';
  16. import { getPermCode } from '/@/api/sys/user';
  17. import { isArray } from '/@/utils/is';
  18. import { useMessage } from '/@/hooks/web/useMessage';
  19. import { PageEnum } from '/@/enums/pageEnum';
  20. import { intersection } from 'lodash-es';
  21. interface PermissionState {
  22. // Permission code list
  23. permCodeList: string[] ;
  24. // Whether the route has been dynamically added
  25. isDynamicAddedRoute: boolean;
  26. // To trigger a menu update
  27. lastBuildMenuTime: number;
  28. // Backstage menu list
  29. backMenuList: Menu[];
  30. frontMenuList: Menu[];
  31. }
  32. export const usePermissionStore = defineStore({
  33. id: 'app-permission',
  34. state: (): PermissionState => ({
  35. permCodeList: [],
  36. // Whether the route has been dynamically added
  37. isDynamicAddedRoute: false,
  38. // To trigger a menu update
  39. lastBuildMenuTime: 0,
  40. // Backstage menu list
  41. backMenuList: [],
  42. // menu List
  43. frontMenuList: [],
  44. }),
  45. getters: {
  46. getPermCodeList(): string[] | number[] {
  47. return this.permCodeList;
  48. },
  49. getBackMenuList(): Menu[] {
  50. return this.backMenuList;
  51. },
  52. getFrontMenuList(): Menu[] {
  53. return this.frontMenuList;
  54. },
  55. getLastBuildMenuTime(): number {
  56. return this.lastBuildMenuTime;
  57. },
  58. getIsDynamicAddedRoute(): boolean {
  59. return this.isDynamicAddedRoute;
  60. },
  61. },
  62. actions: {
  63. setPermCodeList(codeList: string[]) {
  64. this.permCodeList = codeList;
  65. },
  66. getCheckPerm(value:string|string[]): boolean{
  67. const permCodeList = this.permCodeList;
  68. if (!value) {
  69. return false;
  70. }
  71. if (!isArray(value)) {
  72. return permCodeList?.includes(value);
  73. }
  74. return (intersection(value, permCodeList)).length > 0;
  75. },
  76. setBackMenuList(list: Menu[]) {
  77. this.backMenuList = list;
  78. list?.length > 0 && this.setLastBuildMenuTime();
  79. },
  80. setFrontMenuList(list: Menu[]) {
  81. this.frontMenuList = list;
  82. },
  83. setLastBuildMenuTime() {
  84. this.lastBuildMenuTime = new Date().getTime();
  85. },
  86. setDynamicAddedRoute(added: boolean) {
  87. this.isDynamicAddedRoute = added;
  88. },
  89. resetState(): void {
  90. this.isDynamicAddedRoute = false;
  91. this.permCodeList = [];
  92. this.backMenuList = [];
  93. this.lastBuildMenuTime = 0;
  94. },
  95. async changePermissionCode() {
  96. const codeList = await getPermCode();
  97. const permsList = codeList.map(ele => ele.perms)
  98. this.setPermCodeList(permsList);
  99. },
  100. async buildRoutesAction(): Promise<AppRouteRecordRaw[]> {
  101. const { t } = useI18n();
  102. const userStore = useUserStore();
  103. const appStore = useAppStoreWithOut();
  104. let routes: AppRouteRecordRaw[] = [];
  105. const roleList = toRaw(userStore.getRoleList) || [];
  106. const { permissionMode = projectSetting.permissionMode } = appStore.getProjectConfig;
  107. const routeFilter = (route: AppRouteRecordRaw) => {
  108. const { meta } = route;
  109. const { roles } = meta || {};
  110. if (!roles) return true;
  111. return roleList.some((role) => roles.includes(role));
  112. };
  113. const routeRemoveIgnoreFilter = (route: AppRouteRecordRaw) => {
  114. const { meta } = route;
  115. const { ignoreRoute } = meta || {};
  116. return !ignoreRoute;
  117. };
  118. /**
  119. * @description 根据设置的首页path,修正routes中的affix标记(固定首页)
  120. * */
  121. const patchHomeAffix = (routes: AppRouteRecordRaw[]) => {
  122. if (!routes || routes.length === 0) return;
  123. let homePath: string = userStore.getUserInfo.homePath || PageEnum.BASE_HOME;
  124. function patcher(routes: AppRouteRecordRaw[], parentPath = '') {
  125. if (parentPath) parentPath = parentPath + '/';
  126. routes.forEach((route: AppRouteRecordRaw) => {
  127. const { path, children, redirect } = route;
  128. const currentPath = path.startsWith('/') ? path : parentPath + path;
  129. if (currentPath === homePath) {
  130. if (redirect) {
  131. homePath = route.redirect! as string;
  132. } else {
  133. route.meta = Object.assign({}, route.meta, { affix: true });
  134. throw new Error('end');
  135. }
  136. }
  137. children && children.length > 0 && patcher(children, currentPath);
  138. });
  139. }
  140. try {
  141. patcher(routes);
  142. } catch (e) {
  143. // 已处理完毕跳出循环
  144. }
  145. return;
  146. };
  147. switch (permissionMode) {
  148. case PermissionModeEnum.ROLE:
  149. routes = filter(asyncRoutes, routeFilter);
  150. routes = routes.filter(routeFilter);
  151. // Convert multi-level routing to level 2 routing
  152. routes = flatMultiLevelRoutes(routes);
  153. break;
  154. case PermissionModeEnum.ROUTE_MAPPING:
  155. routes = filter(asyncRoutes, routeFilter);
  156. routes = routes.filter(routeFilter);
  157. const menuList = transformRouteToMenu(routes, true);
  158. routes = filter(routes, routeRemoveIgnoreFilter);
  159. routes = routes.filter(routeRemoveIgnoreFilter);
  160. menuList.sort((a, b) => {
  161. return (a.meta?.orderNo || 0) - (b.meta?.orderNo || 0);
  162. });
  163. this.setFrontMenuList(menuList);
  164. // Convert multi-level routing to level 2 routing
  165. routes = flatMultiLevelRoutes(routes);
  166. break;
  167. // If you are sure that you do not need to do background dynamic permissions, please comment the entire judgment below
  168. case PermissionModeEnum.BACK:
  169. const { createMessage } = useMessage();
  170. createMessage.loading({
  171. content: t('sys.app.menuLoading'),
  172. duration: 1,
  173. });
  174. // !Simulate to obtain permission codes from the background,
  175. // this function may only need to be executed once, and the actual project can be put at the right time by itself
  176. let routeList: AppRouteRecordRaw[] = [];
  177. try {
  178. routeList = (await getMenuList()) as AppRouteRecordRaw[];
  179. this.changePermissionCode();
  180. } catch (error) {
  181. console.error(error);
  182. }
  183. // Dynamically introduce components
  184. routeList = transformObjToRoute(routeList);
  185. routeList.sort((a, b) => {
  186. return (a.sort || 0) - (b.sort || 0);
  187. });
  188. // Background routing to menu structure
  189. const backMenuList = transformRouteToMenu(routeList);
  190. this.setBackMenuList(backMenuList);
  191. // remove meta.ignoreRoute item
  192. routeList = filter(routeList, routeRemoveIgnoreFilter);
  193. routeList = routeList.filter(routeRemoveIgnoreFilter);
  194. routeList = flatMultiLevelRoutes(routeList);
  195. routes = [PAGE_NOT_FOUND_ROUTE, ...routeList];
  196. break;
  197. }
  198. // routes.push(ERROR_LOG_ROUTE);
  199. patchHomeAffix(routes);
  200. return routes;
  201. },
  202. },
  203. });
  204. // Need to be used outside the setup
  205. export function usePermissionStoreWithOut() {
  206. return usePermissionStore(store);
  207. }