Merge branch 'master' of https://gitee.com/y_project/RuoYi-Vue
Conflicts:
ruoyi-ui/package.json
ruoyi-ui/src/components/Breadcrumb/index.vue
ruoyi-ui/src/layout/components/AppMain.vue
ruoyi-ui/src/layout/components/Sidebar/index.vue
ruoyi-ui/src/layout/components/TagsView/index.vue
ruoyi-ui/src/store/getters.js
ruoyi-ui/src/store/modules/permission.js
ruoyi-ui/src/views/system/user/profile/resetPwd.vue
ruoyi-ui/src/views/system/user/profile/userInfo.vue
ruoyi-ui/src/views/tool/gen/editTable.vue
| | |
| | | "js-cookie": "2.2.1", |
| | | "jsencrypt": "3.0.0-rc.1", |
| | | "nprogress": "0.2.0", |
| | | "path-to-regexp": "6.2.0", |
| | | "quill": "1.3.7", |
| | | "screenfull": "5.0.2", |
| | | "sortablejs": "1.10.2", |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import pathToRegexp from 'path-to-regexp' |
| | | |
| | | export default { |
| | | data() { |
| | | return { |
| | |
| | | } |
| | | return name.trim() === '首页' |
| | | }, |
| | | pathCompile(path) { |
| | | const { params } = this.$route |
| | | var toPath = pathToRegexp.compile(path) |
| | | return toPath(params) |
| | | }, |
| | | handleLink(item) { |
| | | const { redirect, path } = item |
| | | if (redirect) { |
| | | this.$router.push(redirect) |
| | | return |
| | | } |
| | | this.$router.push(this.pathCompile(path)) |
| | | this.$router.push(path) |
| | | } |
| | | } |
| | | } |
| | |
| | | <!-- @author ruoyi 20201128 支持三级以上菜单缓存 --> |
| | | <template> |
| | | <section class="app-main"> |
| | | <transition name="fade-transform" mode="out-in"> |
| | | <keep-alive :max="20" :exclude="notCacheName"> |
| | | <keep-alive :include="cachedViews"> |
| | | <router-view :key="key" /> |
| | | </keep-alive> |
| | | </transition> |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import Global from "@/layout/components/global.js"; |
| | | |
| | | export default { |
| | | name: 'AppMain', |
| | | computed: { |
| | | notCacheName() { |
| | | var visitedViews = this.$store.state.tagsView.visitedViews; |
| | | var noCacheViews = []; |
| | | Object.keys(visitedViews).some((index) => { |
| | | if (visitedViews[index].meta.noCache) { |
| | | noCacheViews.push(visitedViews[index].name); |
| | | } |
| | | }); |
| | | return noCacheViews; |
| | | cachedViews() { |
| | | return this.$store.state.tagsView.cachedViews |
| | | }, |
| | | key() { |
| | | return this.$route.path; |
| | | }, |
| | | }, |
| | | mounted() { |
| | | // 关闭标签触发 |
| | | Global.$on("removeCache", (name, view) => { |
| | | this.removeCache(name, view); |
| | | }); |
| | | }, |
| | | methods: { |
| | | // 获取有keep-alive子节点的Vnode |
| | | getVnode() { |
| | | // 判断子集非空 |
| | | if (this.$children.length == 0) return false; |
| | | let vnode; |
| | | for (let item of this.$children) { |
| | | // 如果data中有key则代表找到了keep-alive下面的子集,这个key就是router-view上的key |
| | | if (item.$vnode.data.key) { |
| | | vnode = item.$vnode; |
| | | break; |
| | | return this.$route.path |
| | | } |
| | | } |
| | | return vnode ? vnode : false; |
| | | }, |
| | | // 移除keep-alive缓存 |
| | | removeCache(name, view = {}) { |
| | | let vnode = this.getVnode(); |
| | | if (!vnode) return false; |
| | | let componentInstance = vnode.parent.componentInstance; |
| | | // 这个key是用来获取前缀用来后面正则匹配用的 |
| | | let keyStart = vnode.key.split("/")[0]; |
| | | let thisKey = `${keyStart}${view.fullPath}`; |
| | | let regKey = `${keyStart}${view.path}`; |
| | | |
| | | this[name]({ componentInstance, thisKey, regKey }); |
| | | }, |
| | | // 移除其他 |
| | | closeOthersTags({ componentInstance, thisKey }) { |
| | | Object.keys(componentInstance.cache).forEach((key, index) => { |
| | | if (key != thisKey) { |
| | | // 销毁实例(这里存在多个key指向一个缓存的情况可能前面一个已经清除掉了所有要加判断) |
| | | if (componentInstance.cache[key]) { |
| | | componentInstance.cache[key].componentInstance.$destroy(); |
| | | } |
| | | // 删除缓存 |
| | | delete componentInstance.cache[key]; |
| | | // 移除key中对应的key |
| | | componentInstance.keys.splice(index, 1); |
| | | } |
| | | }); |
| | | }, |
| | | // 移除所有缓存 |
| | | closeAllTags({ componentInstance }) { |
| | | // 销毁实例 |
| | | Object.keys(componentInstance.cache).forEach((key) => { |
| | | if (componentInstance.cache[key]) { |
| | | componentInstance.cache[key].componentInstance.$destroy(); |
| | | } |
| | | }); |
| | | // 删除缓存 |
| | | componentInstance.cache = {}; |
| | | // 移除key中对应的key |
| | | componentInstance.keys = []; |
| | | }, |
| | | // 移除单个缓存 |
| | | closeSelectedTag({ componentInstance, regKey }) { |
| | | let reg = new RegExp(`^${regKey}`); |
| | | Object.keys(componentInstance.cache).forEach((key, i) => { |
| | | if (reg.test(key)) { |
| | | // 销毁实例 |
| | | if (componentInstance.cache[key]) { |
| | | componentInstance.cache[key].componentInstance.$destroy(); |
| | | } |
| | | // 删除缓存 |
| | | delete componentInstance.cache[key]; |
| | | // 移除key中对应的key |
| | | componentInstance.keys.splice(i, 1); |
| | | } |
| | | }); |
| | | }, |
| | | // 刷新单个缓存 |
| | | refreshSelectedTag({ componentInstance, thisKey }) { |
| | | Object.keys(componentInstance.cache).forEach((key, index) => { |
| | | if (null != thisKey && key.replace("/redirect", "") == thisKey) { |
| | | // 1 销毁实例(这里存在多个key指向一个缓存的情况可能前面一个已经清除掉了所有要加判断) |
| | | if (componentInstance.cache[key]) { |
| | | componentInstance.cache[key].componentInstance.$destroy(); |
| | | } |
| | | // 2 删除缓存 |
| | | delete componentInstance.cache[key]; |
| | | // 3 移除key中对应的key |
| | | componentInstance.keys.splice(index, 1); |
| | | } |
| | | }); |
| | | }, |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | |
| | | mode="vertical" |
| | | > |
| | | <sidebar-item |
| | | v-for="(route, index) in permission_routes" |
| | | v-for="(route, index) in sidebarRouters" |
| | | :key="route.path + index" |
| | | :item="route" |
| | | :base-path="route.path" |
| | |
| | | components: { SidebarItem, Logo }, |
| | | computed: { |
| | | ...mapState(["settings"]), |
| | | ...mapGetters(["permission_routes", "sidebar"]), |
| | | ...mapGetters(["sidebarRouters", "sidebar"]), |
| | | activeMenu() { |
| | | const route = this.$route; |
| | | const { meta, path } = route; |
| | |
| | | <script> |
| | | import ScrollPane from './ScrollPane' |
| | | import path from 'path' |
| | | import Global from "@/layout/components/global.js"; |
| | | |
| | | export default { |
| | | components: { ScrollPane }, |
| | |
| | | }) |
| | | }) |
| | | }) |
| | | Global.$emit("removeCache", "refreshSelectedTag", this.selectedTag); |
| | | }, |
| | | closeSelectedTag(view) { |
| | | this.$store.dispatch('tagsView/delView', view).then(({ visitedViews }) => { |
| | |
| | | this.toLastView(visitedViews, view) |
| | | } |
| | | }) |
| | | Global.$emit("removeCache", "closeSelectedTag", view); |
| | | }, |
| | | closeOthersTags() { |
| | | this.$router.push(this.selectedTag) |
| | | this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => { |
| | | this.moveToCurrentTag() |
| | | }) |
| | | Global.$emit("removeCache", "closeOthersTags", this.selectedTag); |
| | | }, |
| | | closeAllTags(view) { |
| | | this.$store.dispatch('tagsView/delAllViews').then(({ visitedViews }) => { |
| | |
| | | } |
| | | this.toLastView(visitedViews, view) |
| | | }) |
| | | Global.$emit("removeCache", "closeAllTags"); |
| | | }, |
| | | toLastView(visitedViews, view) { |
| | | const latestView = visitedViews.slice(-1)[0] |
| | |
| | | introduction: state => state.user.introduction, |
| | | roles: state => state.user.roles, |
| | | permissions: state => state.user.permissions, |
| | | permission_routes: state => state.permission.routes |
| | | permission_routes: state => state.permission.routes, |
| | | sidebarRouters:state => state.permission.sidebarRouters, |
| | | } |
| | | export default getters |
| | |
| | | const permission = { |
| | | state: { |
| | | routes: [], |
| | | addRoutes: [] |
| | | addRoutes: [], |
| | | sidebarRouters: [] |
| | | }, |
| | | mutations: { |
| | | SET_ROUTES: (state, routes) => { |
| | | state.addRoutes = routes |
| | | state.routes = constantRoutes.concat(routes) |
| | | } |
| | | }, |
| | | SET_SIDEBAR_ROUTERS: (state, routers) => { |
| | | state.sidebarRouters = routers |
| | | }, |
| | | }, |
| | | actions: { |
| | | // 生成路由 |
| | |
| | | return new Promise(resolve => { |
| | | // 向后端请求路由数据 |
| | | getRouters().then(res => { |
| | | const accessedRoutes = filterAsyncRouter(res.data) |
| | | accessedRoutes.push({ path: '*', redirect: '/404', hidden: true }) |
| | | commit('SET_ROUTES', accessedRoutes) |
| | | resolve(accessedRoutes) |
| | | const sdata = JSON.parse(JSON.stringify(res.data)) |
| | | const rdata = JSON.parse(JSON.stringify(res.data)) |
| | | const sidebarRoutes = filterAsyncRouter(sdata) |
| | | const rewriteRoutes = filterAsyncRouter(rdata, true) |
| | | rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true }) |
| | | commit('SET_ROUTES', rewriteRoutes) |
| | | commit('SET_SIDEBAR_ROUTERS', sidebarRoutes) |
| | | resolve(rewriteRoutes) |
| | | }) |
| | | }) |
| | | } |
| | |
| | | } |
| | | |
| | | // 遍历后台传来的路由字符串,转换为组件对象 |
| | | function filterAsyncRouter(asyncRouterMap) { |
| | | function filterAsyncRouter(asyncRouterMap, isRewrite = false) { |
| | | return asyncRouterMap.filter(route => { |
| | | if (isRewrite && route.children) { |
| | | route.children = filterChildren(route.children) |
| | | } |
| | | if (route.component) { |
| | | // Layout ParentView 组件特殊处理 |
| | | if (route.component === 'Layout') { |
| | |
| | | } |
| | | } |
| | | if (route.children != null && route.children && route.children.length) { |
| | | route.children = filterAsyncRouter(route.children) |
| | | route.children = filterAsyncRouter(route.children, route, isRewrite) |
| | | } |
| | | return true |
| | | }) |
| | | } |
| | | |
| | | function filterChildren(childrenMap) { |
| | | var children = [] |
| | | childrenMap.forEach((el, index) => { |
| | | if (el.children && el.children.length) { |
| | | if (el.component === 'ParentView') { |
| | | el.children.forEach(c => { |
| | | c.path = el.path + '/' + c.path |
| | | if (c.children && c.children.length) { |
| | | children = children.concat(filterChildren(c.children, c)) |
| | | return |
| | | } |
| | | children.push(c) |
| | | }) |
| | | childrenMap.splice(index, 1) |
| | | return |
| | | } |
| | | } |
| | | children = children.concat(el) |
| | | }) |
| | | return children |
| | | } |
| | | |
| | | export const loadView = (view) => { // 路由懒加载 |
| | | return (resolve) => require([`@/views/${view}`], resolve) |
| | | } |
| | |
| | | |
| | | <script> |
| | | import { updateUserPwd } from "@/api/system/user"; |
| | | import Global from "@/layout/components/global.js"; |
| | | |
| | | export default { |
| | | data() { |
| | |
| | | }); |
| | | }, |
| | | close() { |
| | | Global.$emit("removeCache", "closeSelectedTag", this.$route); |
| | | this.$store.dispatch("tagsView/delView", this.$route); |
| | | this.$router.push({ path: "/index" }); |
| | | } |
| | |
| | | |
| | | <script> |
| | | import { updateUserProfile } from "@/api/system/user"; |
| | | import Global from "@/layout/components/global.js"; |
| | | |
| | | export default { |
| | | props: { |
| | |
| | | }); |
| | | }, |
| | | close() { |
| | | Global.$emit("removeCache", "closeSelectedTag", this.$route); |
| | | this.$store.dispatch("tagsView/delView", this.$route); |
| | | this.$router.push({ path: "/index" }); |
| | | } |
| | |
| | | import { getGenTable, updateGenTable } from "@/api/tool/gen"; |
| | | import { optionselect as getDictOptionselect } from "@/api/system/dict/type"; |
| | | import { listMenu as getMenuTreeselect } from "@/api/system/menu"; |
| | | import Global from "@/layout/components/global.js"; |
| | | import basicInfoForm from "./basicInfoForm"; |
| | | import genInfoForm from "./genInfoForm"; |
| | | import Sortable from 'sortablejs' |
| | |
| | | }, |
| | | /** 关闭按钮 */ |
| | | close() { |
| | | Global.$emit("removeCache", "closeSelectedTag", this.$route); |
| | | this.$store.dispatch("tagsView/delView", this.$route); |
| | | this.$router.push({ path: "/tool/gen", query: { t: Date.now()}}) |
| | | } |