permission.ts 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  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. // 菜单
  20. // type 1 系统内地址 2 外链
  21. const menuState = reactive({
  22. leftMenu: [
  23. { label: '全域地图', path: '/globalMap', path2: '/globalMap2', type: '1', checked: false },
  24. { label: '一图作战', path: '/', path2: '/index2', type: '1', checked: false },
  25. { label: '总体态势', path: 'http://19.155.220.218/#/considerable-web/overallSituation?type=full', path2: 'http://19.155.220.218/#/considerable-web/overallSituation?type=large', type: '2', checked: false },
  26. { label: '非煤矿山', path: 'http://19.155.220.218/#/considerable-web/noCoalMine?type=full', path2: 'http://19.155.220.218/#/considerable-web/noCoalMine?type=large', type: '2', checked: false },
  27. { label: '粉尘防爆', path: 'http://19.155.220.218/#/considerable-web/dustIgnitionPproof?type=full', path2: 'http://19.155.220.218/#/considerable-web/dustIgnitionPproof?type=large', type: '2', checked: false }
  28. ],
  29. rightMenu: [
  30. { label: '地质灾害', path: 'http://19.155.220.218/#/considerable-web/geologicalDisaster?type=full', path2: 'http://19.155.220.218/#/considerable-web/geologicalDisaster?type=large', type: '2', checked: false },
  31. { label: '森林防火', path: 'http://19.155.220.218/#/considerable-web/forestFireproof?type=full', path2: 'http://19.155.220.218/#/considerable-web/forestFireproof?type=large', type: '2', checked: false },
  32. { label: '三防', path: 'http://19.155.220.218/#/considerable-web/threeProofings?type=full', path2: 'http://19.155.220.218/#/considerable-web/threeProofings?type=large', type: '2', checked: false },
  33. { label: '危化品', path: 'http://19.155.220.218/#/considerable-web/hazardousChemicals?type=full', path2: 'http://19.155.220.218/#/considerable-web/hazardousChemicals?type=large', type: '2', checked: false }
  34. ]
  35. });
  36. const activeMenu = ref('left');
  37. const menuIndex = ref(1);
  38. const setMenu = (route) => {
  39. let direction = '';
  40. let index = -1;
  41. for (let i = 0; i < menuState.leftMenu.length; i++) {
  42. if (menuState.leftMenu[i].path === route.path || menuState.leftMenu[i].path2 === route.path) {
  43. index = i;
  44. direction = 'left';
  45. break;
  46. }
  47. }
  48. if (index === -1) {
  49. for (let k = 0; k < menuState.rightMenu.length; k++) {
  50. if (menuState.rightMenu[k].path === route.path) {
  51. index = k;
  52. direction = 'right';
  53. break;
  54. }
  55. }
  56. }
  57. if (index !== -1) {
  58. activeMenu.value = direction;
  59. menuIndex.value = index;
  60. }
  61. };
  62. const getRoutes = (): RouteRecordRaw[] => {
  63. return routes.value;
  64. };
  65. const getSidebarRoutes = (): RouteRecordRaw[] => {
  66. return sidebarRouters.value;
  67. };
  68. const getTopbarRoutes = (): RouteRecordRaw[] => {
  69. return topbarRouters.value;
  70. };
  71. const setRoutes = (newRoutes: RouteRecordRaw[]): void => {
  72. addRoutes.value = newRoutes;
  73. routes.value = constantRoutes.concat(newRoutes);
  74. };
  75. const setDefaultRoutes = (routes: RouteRecordRaw[]): void => {
  76. defaultRoutes.value = constantRoutes.concat(routes);
  77. };
  78. const setTopbarRoutes = (routes: RouteRecordRaw[]): void => {
  79. topbarRouters.value = routes;
  80. };
  81. const setSidebarRouters = (routes: RouteRecordRaw[]): void => {
  82. sidebarRouters.value = routes;
  83. };
  84. const generateRoutes = async (): Promise<RouteRecordRaw[]> => {
  85. const res = await getRouters();
  86. const { data } = res;
  87. const sdata = JSON.parse(JSON.stringify(data));
  88. const rdata = JSON.parse(JSON.stringify(data));
  89. const defaultData = JSON.parse(JSON.stringify(data));
  90. const sidebarRoutes = filterAsyncRouter(sdata);
  91. const rewriteRoutes = filterAsyncRouter(rdata, undefined, true);
  92. const defaultRoutes = filterAsyncRouter(defaultData);
  93. const asyncRoutes = filterDynamicRoutes(dynamicRoutes);
  94. asyncRoutes.forEach((route) => {
  95. router.addRoute(route);
  96. });
  97. setRoutes(rewriteRoutes);
  98. setSidebarRouters(constantRoutes.concat(sidebarRoutes));
  99. setDefaultRoutes(sidebarRoutes);
  100. setTopbarRoutes(defaultRoutes);
  101. // 路由name重复检查
  102. duplicateRouteChecker(asyncRoutes, sidebarRoutes);
  103. return new Promise<RouteRecordRaw[]>((resolve) => resolve(rewriteRoutes));
  104. };
  105. /**
  106. * 遍历后台传来的路由字符串,转换为组件对象
  107. * @param asyncRouterMap 后台传来的路由字符串
  108. * @param lastRouter 上一级路由
  109. * @param type 是否是重写路由
  110. */
  111. const filterAsyncRouter = (asyncRouterMap: RouteRecordRaw[], lastRouter?: RouteRecordRaw, type = false): RouteRecordRaw[] => {
  112. return asyncRouterMap.filter((route) => {
  113. if (type && route.children) {
  114. route.children = filterChildren(route.children, undefined);
  115. }
  116. // Layout ParentView 组件特殊处理
  117. if (route.component?.toString() === 'Layout') {
  118. route.component = Layout;
  119. } else if (route.component?.toString() === 'ParentView') {
  120. route.component = ParentView;
  121. } else if (route.component?.toString() === 'InnerLink') {
  122. route.component = InnerLink;
  123. } else {
  124. route.component = loadView(route.component, route.name as string);
  125. }
  126. if (route.children != null && route.children && route.children.length) {
  127. route.children = filterAsyncRouter(route.children, route, type);
  128. } else {
  129. delete route.children;
  130. delete route.redirect;
  131. }
  132. return true;
  133. });
  134. };
  135. const filterChildren = (childrenMap: RouteRecordRaw[], lastRouter?: RouteRecordRaw): RouteRecordRaw[] => {
  136. let children: RouteRecordRaw[] = [];
  137. childrenMap.forEach((el) => {
  138. if (el.children && el.children.length) {
  139. if (el.component?.toString() === 'ParentView' && !lastRouter) {
  140. el.children.forEach((c) => {
  141. c.path = el.path + '/' + c.path;
  142. if (c.children && c.children.length) {
  143. children = children.concat(filterChildren(c.children, c));
  144. return;
  145. }
  146. children.push(c);
  147. });
  148. return;
  149. }
  150. }
  151. if (lastRouter) {
  152. el.path = lastRouter.path + '/' + el.path;
  153. if (el.children && el.children.length) {
  154. children = children.concat(filterChildren(el.children, el));
  155. return;
  156. }
  157. }
  158. children = children.concat(el);
  159. });
  160. return children;
  161. };
  162. return {
  163. routes,
  164. topbarRouters,
  165. sidebarRouters,
  166. defaultRoutes,
  167. menuState,
  168. activeMenu,
  169. menuIndex,
  170. setMenu,
  171. getRoutes,
  172. getSidebarRoutes,
  173. getTopbarRoutes,
  174. setRoutes,
  175. generateRoutes,
  176. setSidebarRouters
  177. };
  178. });
  179. // 动态路由遍历,验证是否具备权限
  180. export const filterDynamicRoutes = (routes: RouteRecordRaw[]) => {
  181. const res: RouteRecordRaw[] = [];
  182. routes.forEach((route) => {
  183. if (route.permissions) {
  184. if (auth.hasPermiOr(route.permissions)) {
  185. res.push(route);
  186. }
  187. } else if (route.roles) {
  188. if (auth.hasRoleOr(route.roles)) {
  189. res.push(route);
  190. }
  191. }
  192. });
  193. return res;
  194. };
  195. export const loadView = (view: any, name: string) => {
  196. let res;
  197. for (const path in modules) {
  198. const dir = path.split('views/')[1].split('.vue')[0];
  199. if (dir === view) {
  200. res = createCustomNameComponent(modules[path], { name });
  201. }
  202. }
  203. return res;
  204. };
  205. // 非setup
  206. export const usePermissionStoreHook = () => {
  207. return usePermissionStore(store);
  208. };
  209. interface Route {
  210. name?: string | symbol;
  211. path: string;
  212. children?: Route[];
  213. }
  214. /**
  215. * 检查路由name是否重复
  216. * @param localRoutes 本地路由
  217. * @param routes 动态路由
  218. */
  219. function duplicateRouteChecker(localRoutes: Route[], routes: Route[]) {
  220. // 展平
  221. function flatRoutes(routes: Route[]) {
  222. const res: Route[] = [];
  223. routes.forEach((route) => {
  224. if (route.children) {
  225. res.push(...flatRoutes(route.children));
  226. } else {
  227. res.push(route);
  228. }
  229. });
  230. return res;
  231. }
  232. const allRoutes = flatRoutes([...localRoutes, ...routes]);
  233. const nameList: string[] = [];
  234. allRoutes.forEach((route) => {
  235. const name = route.name.toString();
  236. if (name && nameList.includes(name)) {
  237. const message = `路由名称: [${name}] 重复, 会造成 404`;
  238. console.error(message);
  239. ElNotification({
  240. title: '路由名称重复',
  241. message,
  242. type: 'error'
  243. });
  244. return;
  245. }
  246. nameList.push(route.name.toString());
  247. });
  248. }
  249. export default usePermissionStore;