Bläddra i källkod

优化多级菜单之间切换无法缓存的问题

RuoYi 5 år sedan
förälder
incheckning
2ddf834552

+ 9 - 112
ruoyi-ui/src/layout/components/AppMain.vue

@@ -1,8 +1,7 @@
1
-<!-- @author ruoyi 20201128 支持三级以上菜单缓存 -->
2
 <template>
1
 <template>
3
   <section class="app-main">
2
   <section class="app-main">
4
     <transition name="fade-transform" mode="out-in">
3
     <transition name="fade-transform" mode="out-in">
5
-      <keep-alive :max="20" :exclude="notCacheName">
4
+      <keep-alive :include="cachedViews">
6
         <router-view :key="key" />
5
         <router-view :key="key" />
7
       </keep-alive>
6
       </keep-alive>
8
     </transition>
7
     </transition>
@@ -10,119 +9,17 @@
10
 </template>
9
 </template>
11
 
10
 
12
 <script>
11
 <script>
13
-import Global from "@/layout/components/global.js";
14
-
15
 export default {
12
 export default {
16
   name: 'AppMain',
13
   name: 'AppMain',
17
   computed: {
14
   computed: {
18
-    notCacheName() {
19
-      var visitedViews = this.$store.state.tagsView.visitedViews;
20
-      var noCacheViews = [];
21
-      Object.keys(visitedViews).some((index) => {
22
-        if (visitedViews[index].meta.noCache) {
23
-          noCacheViews.push(visitedViews[index].name);
24
-        }
25
-      });
26
-      return noCacheViews;
15
+    cachedViews() {
16
+      return this.$store.state.tagsView.cachedViews
27
     },
17
     },
28
     key() {
18
     key() {
29
-      return this.$route.path;
30
-    },
31
-  },
32
-  mounted() {
33
-    // 关闭标签触发
34
-    Global.$on("removeCache", (name, view) => {
35
-      this.removeCache(name, view);
36
-    });
37
-  },
38
-  methods: {
39
-    // 获取有keep-alive子节点的Vnode
40
-    getVnode() {
41
-      // 判断子集非空
42
-      if (this.$children.length == 0) return false;
43
-      let vnode;
44
-      for (let item of this.$children) {
45
-        // 如果data中有key则代表找到了keep-alive下面的子集,这个key就是router-view上的key
46
-        if (item.$vnode.data.key) {
47
-          vnode = item.$vnode;
48
-          break;
49
-        }
50
-      }
51
-      return vnode ? vnode : false;
52
-    },
53
-    // 移除keep-alive缓存
54
-    removeCache(name, view = {}) {
55
-      let vnode = this.getVnode();
56
-      if (!vnode) return false;
57
-      let componentInstance = vnode.parent.componentInstance;
58
-      // 这个key是用来获取前缀用来后面正则匹配用的
59
-      let keyStart = vnode.key.split("/")[0];
60
-      let thisKey = `${keyStart}${view.fullPath}`;
61
-      let regKey = `${keyStart}${view.path}`;
62
-
63
-      this[name]({ componentInstance, thisKey, regKey });
64
-    },
65
-    // 移除其他
66
-    closeOthersTags({ componentInstance, thisKey }) {
67
-      Object.keys(componentInstance.cache).forEach((key, index) => {
68
-        if (key != thisKey) {
69
-          // 销毁实例(这里存在多个key指向一个缓存的情况可能前面一个已经清除掉了所有要加判断)
70
-          if (componentInstance.cache[key]) {
71
-            componentInstance.cache[key].componentInstance.$destroy();
72
-          }
73
-          // 删除缓存
74
-          delete componentInstance.cache[key];
75
-          // 移除key中对应的key
76
-          componentInstance.keys.splice(index, 1);
77
-        }
78
-      });
79
-    },
80
-    // 移除所有缓存
81
-    closeAllTags({ componentInstance }) {
82
-      // 销毁实例
83
-      Object.keys(componentInstance.cache).forEach((key) => {
84
-        if (componentInstance.cache[key]) {
85
-          componentInstance.cache[key].componentInstance.$destroy();
86
-        }
87
-      });
88
-      // 删除缓存
89
-      componentInstance.cache = {};
90
-      // 移除key中对应的key
91
-      componentInstance.keys = [];
92
-    },
93
-    // 移除单个缓存
94
-    closeSelectedTag({ componentInstance, regKey }) {
95
-      let reg = new RegExp(`^${regKey}`);
96
-      Object.keys(componentInstance.cache).forEach((key, i) => {
97
-        if (reg.test(key)) {
98
-          // 销毁实例
99
-          if (componentInstance.cache[key]) {
100
-            componentInstance.cache[key].componentInstance.$destroy();
101
-          }
102
-          // 删除缓存
103
-          delete componentInstance.cache[key];
104
-          // 移除key中对应的key
105
-          componentInstance.keys.splice(i, 1);
106
-        }
107
-      });
108
-    },
109
-    // 刷新单个缓存
110
-    refreshSelectedTag({ componentInstance, thisKey }) {
111
-      Object.keys(componentInstance.cache).forEach((key, index) => {
112
-        if (null != thisKey && key.replace("/redirect", "") == thisKey) {
113
-          // 1 销毁实例(这里存在多个key指向一个缓存的情况可能前面一个已经清除掉了所有要加判断)
114
-          if (componentInstance.cache[key]) {
115
-            componentInstance.cache[key].componentInstance.$destroy();
116
-          }
117
-          // 2 删除缓存
118
-          delete componentInstance.cache[key];
119
-          // 3 移除key中对应的key
120
-          componentInstance.keys.splice(index, 1);
121
-        }
122
-      });
123
-    },
124
-  },
125
-};
19
+      return this.$route.path
20
+    }
21
+  }
22
+}
126
 </script>
23
 </script>
127
 
24
 
128
 <style lang="scss" scoped>
25
 <style lang="scss" scoped>
@@ -134,7 +31,7 @@ export default {
134
   overflow: hidden;
31
   overflow: hidden;
135
 }
32
 }
136
 
33
 
137
-.fixed-header + .app-main {
34
+.fixed-header+.app-main {
138
   padding-top: 50px;
35
   padding-top: 50px;
139
 }
36
 }
140
 
37
 
@@ -144,7 +41,7 @@ export default {
144
     min-height: calc(100vh - 84px);
41
     min-height: calc(100vh - 84px);
145
   }
42
   }
146
 
43
 
147
-  .fixed-header + .app-main {
44
+  .fixed-header+.app-main {
148
     padding-top: 84px;
45
     padding-top: 84px;
149
   }
46
   }
150
 }
47
 }

+ 2 - 2
ruoyi-ui/src/layout/components/Sidebar/index.vue

@@ -13,7 +13,7 @@
13
                 mode="vertical"
13
                 mode="vertical"
14
             >
14
             >
15
                 <sidebar-item
15
                 <sidebar-item
16
-                    v-for="(route, index) in permission_routes"
16
+                    v-for="(route, index) in sidebarRouters"
17
                     :key="route.path  + index"
17
                     :key="route.path  + index"
18
                     :item="route"
18
                     :item="route"
19
                     :base-path="route.path"
19
                     :base-path="route.path"
@@ -33,7 +33,7 @@ export default {
33
     components: { SidebarItem, Logo },
33
     components: { SidebarItem, Logo },
34
     computed: {
34
     computed: {
35
         ...mapState(["settings"]),
35
         ...mapState(["settings"]),
36
-        ...mapGetters(["permission_routes", "sidebar"]),
36
+        ...mapGetters(["sidebarRouters", "sidebar"]),
37
         activeMenu() {
37
         activeMenu() {
38
             const route = this.$route;
38
             const route = this.$route;
39
             const { meta, path } = route;
39
             const { meta, path } = route;

+ 0 - 5
ruoyi-ui/src/layout/components/TagsView/index.vue

@@ -29,7 +29,6 @@
29
 <script>
29
 <script>
30
 import ScrollPane from './ScrollPane'
30
 import ScrollPane from './ScrollPane'
31
 import path from 'path'
31
 import path from 'path'
32
-import Global from "@/layout/components/global.js";
33
 
32
 
34
 export default {
33
 export default {
35
   components: { ScrollPane },
34
   components: { ScrollPane },
@@ -145,7 +144,6 @@ export default {
145
           })
144
           })
146
         })
145
         })
147
       })
146
       })
148
-      Global.$emit("removeCache", "refreshSelectedTag", this.selectedTag);
149
     },
147
     },
150
     closeSelectedTag(view) {
148
     closeSelectedTag(view) {
151
       this.$store.dispatch('tagsView/delView', view).then(({ visitedViews }) => {
149
       this.$store.dispatch('tagsView/delView', view).then(({ visitedViews }) => {
@@ -153,14 +151,12 @@ export default {
153
           this.toLastView(visitedViews, view)
151
           this.toLastView(visitedViews, view)
154
         }
152
         }
155
       })
153
       })
156
-      Global.$emit("removeCache", "closeSelectedTag", view);
157
     },
154
     },
158
     closeOthersTags() {
155
     closeOthersTags() {
159
       this.$router.push(this.selectedTag)
156
       this.$router.push(this.selectedTag)
160
       this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => {
157
       this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => {
161
         this.moveToCurrentTag()
158
         this.moveToCurrentTag()
162
       })
159
       })
163
-      Global.$emit("removeCache", "closeOthersTags", this.selectedTag);
164
     },
160
     },
165
     closeAllTags(view) {
161
     closeAllTags(view) {
166
       this.$store.dispatch('tagsView/delAllViews').then(({ visitedViews }) => {
162
       this.$store.dispatch('tagsView/delAllViews').then(({ visitedViews }) => {
@@ -169,7 +165,6 @@ export default {
169
         }
165
         }
170
         this.toLastView(visitedViews, view)
166
         this.toLastView(visitedViews, view)
171
       })
167
       })
172
-      Global.$emit("removeCache", "closeAllTags");
173
     },
168
     },
174
     toLastView(visitedViews, view) {
169
     toLastView(visitedViews, view) {
175
       const latestView = visitedViews.slice(-1)[0]
170
       const latestView = visitedViews.slice(-1)[0]

+ 2 - 1
ruoyi-ui/src/store/getters.js

@@ -10,6 +10,7 @@ const getters = {
10
   introduction: state => state.user.introduction,
10
   introduction: state => state.user.introduction,
11
   roles: state => state.user.roles,
11
   roles: state => state.user.roles,
12
   permissions: state => state.user.permissions,
12
   permissions: state => state.user.permissions,
13
-  permission_routes: state => state.permission.routes
13
+  permission_routes: state => state.permission.routes,
14
+  sidebarRouters:state => state.permission.sidebarRouters,
14
 }
15
 }
15
 export default getters
16
 export default getters

+ 42 - 9
ruoyi-ui/src/store/modules/permission.js

@@ -6,13 +6,17 @@ import ParentView from '@/components/ParentView';
6
 const permission = {
6
 const permission = {
7
   state: {
7
   state: {
8
     routes: [],
8
     routes: [],
9
-    addRoutes: []
9
+    addRoutes: [],
10
+    sidebarRouters: []
10
   },
11
   },
11
   mutations: {
12
   mutations: {
12
     SET_ROUTES: (state, routes) => {
13
     SET_ROUTES: (state, routes) => {
13
       state.addRoutes = routes
14
       state.addRoutes = routes
14
       state.routes = constantRoutes.concat(routes)
15
       state.routes = constantRoutes.concat(routes)
15
-    }
16
+    },
17
+    SET_SIDEBAR_ROUTERS: (state, routers) => {
18
+      state.sidebarRouters = routers
19
+    },
16
   },
20
   },
17
   actions: {
21
   actions: {
18
     // 生成路由
22
     // 生成路由
@@ -20,10 +24,14 @@ const permission = {
20
       return new Promise(resolve => {
24
       return new Promise(resolve => {
21
         // 向后端请求路由数据
25
         // 向后端请求路由数据
22
         getRouters().then(res => {
26
         getRouters().then(res => {
23
-          const accessedRoutes = filterAsyncRouter(res.data)
24
-          accessedRoutes.push({ path: '*', redirect: '/404', hidden: true })
25
-          commit('SET_ROUTES', accessedRoutes)
26
-          resolve(accessedRoutes)
27
+          const sdata = JSON.parse(JSON.stringify(res.data))
28
+          const rdata = JSON.parse(JSON.stringify(res.data))
29
+          const sidebarRoutes = filterAsyncRouter(sdata)
30
+          const rewriteRoutes = filterAsyncRouter(rdata, true)
31
+          rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true })
32
+          commit('SET_ROUTES', rewriteRoutes)
33
+          commit('SET_SIDEBAR_ROUTERS', sidebarRoutes)
34
+          resolve(rewriteRoutes)
27
         })
35
         })
28
       })
36
       })
29
     }
37
     }
@@ -31,8 +39,11 @@ const permission = {
31
 }
39
 }
32
 
40
 
33
 // 遍历后台传来的路由字符串,转换为组件对象
41
 // 遍历后台传来的路由字符串,转换为组件对象
34
-function filterAsyncRouter(asyncRouterMap) {
42
+function filterAsyncRouter(asyncRouterMap, isRewrite = false) {
35
   return asyncRouterMap.filter(route => {
43
   return asyncRouterMap.filter(route => {
44
+    if (isRewrite && route.children) {
45
+      route.children = filterChildren(route.children)
46
+    }
36
     if (route.component) {
47
     if (route.component) {
37
       // Layout ParentView 组件特殊处理
48
       // Layout ParentView 组件特殊处理
38
       if (route.component === 'Layout') {
49
       if (route.component === 'Layout') {
@@ -44,14 +55,36 @@ function filterAsyncRouter(asyncRouterMap) {
44
       }
55
       }
45
     }
56
     }
46
     if (route.children != null && route.children && route.children.length) {
57
     if (route.children != null && route.children && route.children.length) {
47
-      route.children = filterAsyncRouter(route.children)
58
+      route.children = filterAsyncRouter(route.children, route, isRewrite)
48
     }
59
     }
49
     return true
60
     return true
50
   })
61
   })
51
 }
62
 }
52
 
63
 
64
+function filterChildren(childrenMap) {
65
+  var children = []
66
+  childrenMap.forEach((el, index) => {
67
+    if (el.children && el.children.length) {
68
+      if (el.component === 'ParentView') {
69
+        el.children.forEach(c => {
70
+          c.path = el.path + '/' + c.path
71
+          if (c.children && c.children.length) {
72
+            children = children.concat(filterChildren(c.children, c))
73
+            return
74
+          }
75
+          children.push(c)
76
+        })
77
+        childrenMap.splice(index, 1)
78
+        return
79
+      }
80
+    }
81
+    children = children.concat(el)
82
+  })
83
+  return children
84
+}
85
+
53
 export const loadView = (view) => { // 路由懒加载
86
 export const loadView = (view) => { // 路由懒加载
54
-  return (resolve) =>  require([`@/views/${view}`], resolve)
87
+  return (resolve) => require([`@/views/${view}`], resolve)
55
 }
88
 }
56
 
89
 
57
 export default permission
90
 export default permission

+ 0 - 2
ruoyi-ui/src/views/system/user/profile/resetPwd.vue

@@ -18,7 +18,6 @@
18
 
18
 
19
 <script>
19
 <script>
20
 import { updateUserPwd } from "@/api/system/user";
20
 import { updateUserPwd } from "@/api/system/user";
21
-import Global from "@/layout/components/global.js";
22
 
21
 
23
 export default {
22
 export default {
24
   data() {
23
   data() {
@@ -65,7 +64,6 @@ export default {
65
       });
64
       });
66
     },
65
     },
67
     close() {
66
     close() {
68
-      Global.$emit("removeCache", "closeSelectedTag", this.$route);
69
       this.$store.dispatch("tagsView/delView", this.$route);
67
       this.$store.dispatch("tagsView/delView", this.$route);
70
       this.$router.push({ path: "/index" });
68
       this.$router.push({ path: "/index" });
71
     }
69
     }

+ 0 - 2
ruoyi-ui/src/views/system/user/profile/userInfo.vue

@@ -24,7 +24,6 @@
24
 
24
 
25
 <script>
25
 <script>
26
 import { updateUserProfile } from "@/api/system/user";
26
 import { updateUserProfile } from "@/api/system/user";
27
-import Global from "@/layout/components/global.js";
28
 
27
 
29
 export default {
28
 export default {
30
   props: {
29
   props: {
@@ -69,7 +68,6 @@ export default {
69
       });
68
       });
70
     },
69
     },
71
     close() {
70
     close() {
72
-      Global.$emit("removeCache", "closeSelectedTag", this.$route);
73
       this.$store.dispatch("tagsView/delView", this.$route);
71
       this.$store.dispatch("tagsView/delView", this.$route);
74
       this.$router.push({ path: "/index" });
72
       this.$router.push({ path: "/index" });
75
     }
73
     }

+ 0 - 2
ruoyi-ui/src/views/tool/gen/editTable.vue

@@ -127,7 +127,6 @@
127
 import { getGenTable, updateGenTable } from "@/api/tool/gen";
127
 import { getGenTable, updateGenTable } from "@/api/tool/gen";
128
 import { optionselect as getDictOptionselect } from "@/api/system/dict/type";
128
 import { optionselect as getDictOptionselect } from "@/api/system/dict/type";
129
 import { listMenu as getMenuTreeselect } from "@/api/system/menu";
129
 import { listMenu as getMenuTreeselect } from "@/api/system/menu";
130
-import Global from "@/layout/components/global.js";
131
 import basicInfoForm from "./basicInfoForm";
130
 import basicInfoForm from "./basicInfoForm";
132
 import genInfoForm from "./genInfoForm";
131
 import genInfoForm from "./genInfoForm";
133
 import Sortable from 'sortablejs'
132
 import Sortable from 'sortablejs'
@@ -208,7 +207,6 @@ export default {
208
     },
207
     },
209
     /** 关闭按钮 */
208
     /** 关闭按钮 */
210
     close() {
209
     close() {
211
-      Global.$emit("removeCache", "closeSelectedTag", this.$route);
212
       this.$store.dispatch("tagsView/delView", this.$route);
210
       this.$store.dispatch("tagsView/delView", this.$route);
213
       this.$router.push({ path: "/tool/gen", query: { t: Date.now()}})
211
       this.$router.push({ path: "/tool/gen", query: { t: Date.now()}})
214
     }
212
     }