permission.ts 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. import { defineStore } from 'pinia';
  2. import router, { constantRoutes, dynamicRoutes } from '@/router';
  3. import store from '@/store';
  4. import { getRouters } from '@/api/menu';
  5. import auth from '@/plugins/auth';
  6. import { RouteRecordRaw } from 'vue-router';
  7. import Layout from '@/layout/index.vue';
  8. import ParentView from '@/components/ParentView/index.vue';
  9. import InnerLink from '@/layout/components/InnerLink/index.vue';
  10. import { createCustomNameComponent } from '@/utils/createCustomNameComponent';
  11. // 匹配views里面所有的.vue文件
  12. const modules = import.meta.glob('./../../views/**/*.vue');
  13. export const usePermissionStore = defineStore('permission', () => {
  14. const routes = ref<RouteRecordRaw[]>([]);
  15. const addRoutes = ref<RouteRecordRaw[]>([]);
  16. const defaultRoutes = ref<RouteRecordRaw[]>([]);
  17. const topbarRouters = ref<RouteRecordRaw[]>([]);
  18. const sidebarRouters = ref<RouteRecordRaw[]>([]);
  19. const getRoutes = (): RouteRecordRaw[] => {
  20. return routes.value as RouteRecordRaw[];
  21. };
  22. const getDefaultRoutes = (): RouteRecordRaw[] => {
  23. return defaultRoutes.value as RouteRecordRaw[];
  24. };
  25. const getSidebarRoutes = (): RouteRecordRaw[] => {
  26. return sidebarRouters.value as RouteRecordRaw[];
  27. };
  28. const getTopbarRoutes = (): RouteRecordRaw[] => {
  29. return topbarRouters.value as RouteRecordRaw[];
  30. };
  31. const setRoutes = (newRoutes: RouteRecordRaw[]): void => {
  32. addRoutes.value = newRoutes;
  33. routes.value = constantRoutes.concat(newRoutes);
  34. };
  35. const setDefaultRoutes = (routes: RouteRecordRaw[]): void => {
  36. defaultRoutes.value = constantRoutes.concat(routes);
  37. };
  38. const setTopbarRoutes = (routes: RouteRecordRaw[]): void => {
  39. topbarRouters.value = routes;
  40. };
  41. const setSidebarRouters = (routes: RouteRecordRaw[]): void => {
  42. sidebarRouters.value = routes;
  43. };
  44. const generateRoutes = async (): Promise<RouteRecordRaw[]> => {
  45. const res = await getRouters();
  46. const { data } = res;
  47. const sdata = JSON.parse(JSON.stringify(data));
  48. const rdata = JSON.parse(JSON.stringify(data));
  49. const defaultData = JSON.parse(JSON.stringify(data));
  50. const sidebarRoutes = filterAsyncRouter(sdata);
  51. const rewriteRoutes = filterAsyncRouter(rdata, undefined, true);
  52. const defaultRoutes = filterAsyncRouter(defaultData);
  53. const asyncRoutes = filterDynamicRoutes(dynamicRoutes);
  54. asyncRoutes.forEach((route) => {
  55. router.addRoute(route);
  56. });
  57. setRoutes(rewriteRoutes);
  58. setSidebarRouters(constantRoutes.concat(sidebarRoutes));
  59. setDefaultRoutes(sidebarRoutes);
  60. setTopbarRoutes(defaultRoutes);
  61. // 路由name重复检查
  62. duplicateRouteChecker(asyncRoutes, sidebarRoutes);
  63. return new Promise<RouteRecordRaw[]>((resolve) => resolve(rewriteRoutes));
  64. };
  65. /**
  66. * 遍历后台传来的路由字符串,转换为组件对象
  67. * @param asyncRouterMap 后台传来的路由字符串
  68. * @param lastRouter 上一级路由
  69. * @param type 是否是重写路由
  70. */
  71. const filterAsyncRouter = (asyncRouterMap: RouteRecordRaw[], lastRouter?: RouteRecordRaw, type = false): RouteRecordRaw[] => {
  72. return asyncRouterMap.filter((route) => {
  73. if (type && route.children) {
  74. route.children = filterChildren(route.children, undefined);
  75. }
  76. // Layout ParentView 组件特殊处理
  77. if (route.component?.toString() === 'Layout') {
  78. route.component = Layout;
  79. } else if (route.component?.toString() === 'ParentView') {
  80. route.component = ParentView;
  81. } else if (route.component?.toString() === 'InnerLink') {
  82. route.component = InnerLink;
  83. } else {
  84. route.component = loadView(route.component, route.name as string);
  85. }
  86. if (route.children != null && route.children && route.children.length) {
  87. route.children = filterAsyncRouter(route.children, route, type);
  88. } else {
  89. delete route.children;
  90. delete route.redirect;
  91. }
  92. return true;
  93. });
  94. };
  95. const filterChildren = (childrenMap: RouteRecordRaw[], lastRouter?: RouteRecordRaw): RouteRecordRaw[] => {
  96. let children: RouteRecordRaw[] = [];
  97. childrenMap.forEach(el => {
  98. el.path = lastRouter ? lastRouter.path + '/' + el.path : el.path;
  99. if (el.children && el.children.length && el.component?.toString() === 'ParentView') {
  100. children = children.concat(filterChildren(el.children, el));
  101. } else {
  102. children.push(el);
  103. }
  104. })
  105. return children;
  106. };
  107. return {
  108. routes,
  109. topbarRouters,
  110. sidebarRouters,
  111. defaultRoutes,
  112. getRoutes,
  113. getDefaultRoutes,
  114. getSidebarRoutes,
  115. getTopbarRoutes,
  116. setRoutes,
  117. generateRoutes,
  118. setSidebarRouters
  119. };
  120. });
  121. // 动态路由遍历,验证是否具备权限
  122. export const filterDynamicRoutes = (routes: RouteRecordRaw[]) => {
  123. const res: RouteRecordRaw[] = [];
  124. routes.forEach((route) => {
  125. if (route.permissions) {
  126. if (auth.hasPermiOr(route.permissions)) {
  127. res.push(route);
  128. }
  129. } else if (route.roles) {
  130. if (auth.hasRoleOr(route.roles)) {
  131. res.push(route);
  132. }
  133. }
  134. });
  135. return res;
  136. };
  137. export const loadView = (view: any, name: string) => {
  138. let res;
  139. for (const path in modules) {
  140. const viewsIndex = path.indexOf('/views/');
  141. let dir = path.substring(viewsIndex + 7);
  142. dir = dir.substring(0, dir.lastIndexOf('.vue'));
  143. if (dir === view) {
  144. res = createCustomNameComponent(modules[path], { name });
  145. return res;
  146. }
  147. }
  148. return res;
  149. };
  150. // 非setup
  151. export const usePermissionStoreHook = () => {
  152. return usePermissionStore(store);
  153. };
  154. interface Route {
  155. name?: string | symbol;
  156. path: string;
  157. children?: Route[];
  158. }
  159. /**
  160. * 检查路由name是否重复
  161. * @param localRoutes 本地路由
  162. * @param routes 动态路由
  163. */
  164. function duplicateRouteChecker(localRoutes: Route[], routes: Route[]) {
  165. // 展平
  166. function flatRoutes(routes: Route[]) {
  167. const res: Route[] = [];
  168. routes.forEach((route) => {
  169. if (route.children) {
  170. res.push(...flatRoutes(route.children));
  171. } else {
  172. res.push(route);
  173. }
  174. });
  175. return res;
  176. }
  177. const allRoutes = flatRoutes([...localRoutes, ...routes]);
  178. const nameList: string[] = [];
  179. allRoutes.forEach((route) => {
  180. const name = route.name.toString();
  181. if (name && nameList.includes(name)) {
  182. const message = `路由名称: [${name}] 重复, 会造成 404`;
  183. console.error(message);
  184. ElNotification({
  185. title: '路由名称重复',
  186. message,
  187. type: 'error'
  188. });
  189. return;
  190. }
  191. nameList.push(route.name.toString());
  192. });
  193. }
  194. export default usePermissionStore;