diff --git a/src/cache.js b/src/cache.js new file mode 100644 index 0000000..78d9ef4 --- /dev/null +++ b/src/cache.js @@ -0,0 +1,33 @@ +import Vue from 'vue' +import store from './store'; +Vue.mixin({ + beforeRouteLeave: function (to, from, next) { + if (this.$route.meta.keepAlive === true) { + const result = this.$route.meta.keepAlive === true && store.state.tags.tagList.some(ele => { + return ele.value === this.$route.fullPath; + }) + if (this.$vnode && !result) { + if (this.$vnode.parent && this.$vnode.parent.componentInstance && this.$vnode.parent.componentInstance.cache) { + if (this.$vnode.componentOptions) { + var key = this.$vnode.key == null + ? this.$vnode.componentOptions.Ctor.cid + (this.$vnode.componentOptions.tag ? `::${this.$vnode.componentOptions.tag}` : '') + : this.$vnode.key; + var cache = this.$vnode.parent.componentInstance.cache; + var keys = this.$vnode.parent.componentInstance.keys; + if (cache[key]) { + if (keys.length) { + var index = keys.indexOf(key); + if (index > -1) { + keys.splice(index, 1); + } + } + delete cache[key]; + } + } + } + } + } + + next(); + }, +}); \ No newline at end of file diff --git a/src/lang/en.js b/src/lang/en.js index 98ff77f..0738fbb 100644 --- a/src/lang/en.js +++ b/src/lang/en.js @@ -59,6 +59,7 @@ export default { logs: 'logs', table: 'table', form: 'form', + top: 'backtop', data: 'data', error: 'error', test: 'test' diff --git a/src/lang/zh.js b/src/lang/zh.js index 5e67fad..a8579f0 100644 --- a/src/lang/zh.js +++ b/src/lang/zh.js @@ -58,6 +58,7 @@ export default { logs: '日志监控', table: '表格', form: '表单', + top: '返回顶部', data: '数据展示', permission: '权限', error: '异常页面', diff --git a/src/main.js b/src/main.js index 54da379..f04636d 100644 --- a/src/main.js +++ b/src/main.js @@ -5,6 +5,7 @@ import App from './App'; import router from './router/router'; import './permission'; // 权限 import './error'; // 日志 +import './cache';//页面缓存 import store from './store'; import {loadStyle} from './util/util' import * as urls from '@/config/env'; diff --git a/src/page/index/index.vue b/src/page/index/index.vue index 1705d3c..c1ed423 100644 --- a/src/page/index/index.vue +++ b/src/page/index/index.vue @@ -1,110 +1,100 @@ diff --git a/src/page/index/layout.vue b/src/page/index/layout.vue index ba32c22..ec204c1 100644 --- a/src/page/index/layout.vue +++ b/src/page/index/layout.vue @@ -1,3 +1,10 @@ \ No newline at end of file +
+ + + + +
+ diff --git a/src/permission.js b/src/permission.js index 3993c17..40f253a 100644 --- a/src/permission.js +++ b/src/permission.js @@ -4,78 +4,65 @@ */ import router from './router/router' import store from './store' -import { validatenull } from '@/util/validate' -import { getToken } from '@/util/auth' +import {validatenull} from '@/util/validate' +import {getToken} from '@/util/auth' import NProgress from 'nprogress' // progress bar import 'nprogress/nprogress.css' // progress bar style -NProgress.configure({ showSpinner: false }); +NProgress.configure({showSpinner: false}); const lockPage = store.getters.website.lockPage; //锁屏页 router.beforeEach((to, from, next) => { - //缓冲设置 - if (to.meta.keepAlive === true && store.state.tags.tagList.some(ele => { - return ele.value === to.fullPath; - })) { - to.meta.$keepAlive = true; + const meta = to.meta || {}; + if (getToken()) { + if (store.getters.isLock && to.path != lockPage) { //如果系统激活锁屏,全部跳转到锁屏页 + next({path: lockPage}) + } else if (to.path === '/login') { //如果登录成功访问登录页跳转到主页 + next({path: '/'}) } else { - NProgress.start() - if (to.meta.keepAlive === true && validatenull(to.meta.$keepAlive)) { - to.meta.$keepAlive = true; - } else { - to.meta.$keepAlive = false; + //如果用户信息为空则获取用户信息,获取用户信息失败,跳转到登录页 + if (store.getters.token.length === 0) { + store.dispatch('FedLogOut').then(() => { + next({path: '/login'}) + }) + } else { + const value = to.query.src || to.fullPath; + const label = to.query.name || to.name; + const meta = to.meta || router.$avueRouter.meta || {}; + const i18n = to.query.i18n; + if (meta.isTab !== false && !validatenull(value) && !validatenull(label)) { + store.commit('ADD_TAG', { + label: label, + value: value, + params: to.params, + query: to.query, + meta: (() => { + if (!i18n) { + return meta + } + return { + i18n: i18n + } + })(), + group: router.$avueRouter.group || [] + }); } + next() + } } - const meta = to.meta || {}; - if (getToken()) { - if (store.getters.isLock && to.path != lockPage) { //如果系统激活锁屏,全部跳转到锁屏页 - next({ path: lockPage }) - } else if (to.path === '/login') { //如果登录成功访问登录页跳转到主页 - next({ path: '/' }) - } else { - //如果用户信息为空则获取用户信息,获取用户信息失败,跳转到登录页 - if (store.getters.token.length === 0) { - store.dispatch('FedLogOut').then(() => { - next({ path: '/login' }) - }) - } else { - const value = to.query.src || to.fullPath; - const label = to.query.name || to.name; - const meta = to.meta || router.$avueRouter.meta || {}; - const i18n = to.query.i18n; - if (meta.isTab !== false && !validatenull(value) && !validatenull(label)) { - store.commit('ADD_TAG', { - label: label, - value: value, - params: to.params, - query: to.query, - meta: (() => { - if (!i18n) { - return meta - } - return { - i18n: i18n - } - })(), - group: router.$avueRouter.group || [] - }); - } - next() - } - } + } else { + //判断是否需要认证,没有登录访问去登录页 + if (meta.isAuth === false) { + next() } else { - //判断是否需要认证,没有登录访问去登录页 - if (meta.isAuth === false) { - next() - } else { - next('/login') - } + next('/login') } + } }) router.afterEach(() => { - NProgress.done(); - let title = store.getters.tag.label; - let i18n = store.getters.tag.meta.i18n; - title = router.$avueRouter.generateTitle(title, i18n) - //根据当前的标签也获取label的值动态设置浏览器标题 - router.$avueRouter.setTitle(title); + NProgress.done(); + let title = store.getters.tag.label; + let i18n = store.getters.tag.meta.i18n; + title = router.$avueRouter.generateTitle(title, i18n) + //根据当前的标签也获取label的值动态设置浏览器标题 + router.$avueRouter.setTitle(title); }); diff --git a/src/router/avue-router.js b/src/router/avue-router.js index 039861e..950c861 100644 --- a/src/router/avue-router.js +++ b/src/router/avue-router.js @@ -1,166 +1,178 @@ - let RouterPlugin = function () { - this.$router = null; - this.$store = null; + this.$router = null; + this.$store = null; }; RouterPlugin.install = function (vue, router, store, i18n) { - this.$router = router; - this.$store = store; - this.$vue = new vue({ i18n }); - function isURL(s) { - return /^http[s]?:\/\/.*/.test(s) - } - function objToform(obj) { - let result = []; - Object.keys(obj).forEach(ele => { - result.push(`${ele}=${obj[ele]}`); - }) - return result.join('&'); - } - this.$router.$avueRouter = { - //全局配置 - $website: this.$store.getters.website, - routerList: [], - group: '', - meta: {}, - safe: this, - // 设置标题 - setTitle: (title) => { - const defaultTitle = this.$vue.$t('title'); - title = title ? `${title}-${defaultTitle}` : defaultTitle; - document.title = title; - }, - closeTag: (value) => { - let tag = value || this.$store.getters.tag; - if (typeof value === 'string') { - tag = this.$store.getters.tagList.filter(ele => ele.value === value)[0] - } - this.$store.commit('DEL_TAG', tag) - }, - generateTitle: (title, key) => { - if (!key) return title; - const hasKey = this.$vue.$te('route.' + key) - if (hasKey) { - // $t :this method from vue-i18n, inject in @/lang/index.js - const translatedTitle = this.$vue.$t('route.' + key) + this.$router = router; + this.$store = store; + this.$vue = new vue({i18n}); - return translatedTitle - } - return title - }, - //处理路由 - getPath: function (params) { - let { src } = params; - let result = src || '/'; - if (src.includes("http") || src.includes("https")) { - result = `/myiframe/urlPath?${objToform(params)}`; - } - return result; - }, - //正则处理路由 - vaildPath: function (list, path) { - let result = false; - list.forEach(ele => { - if (new RegExp("^" + ele + ".*", "g").test(path)) { - result = true - } + function isURL(s) { + return /^http[s]?:\/\/.*/.test(s) + } + + function objToform(obj) { + let result = []; + Object.keys(obj).forEach(ele => { + result.push(`${ele}=${obj[ele]}`); + }) + return result.join('&'); + } + + this.$router.$avueRouter = { + //全局配置 + $website: this.$store.getters.website, + routerList: [], + group: '', + meta: {}, + safe: this, + // 设置标题 + setTitle: (title) => { + const defaultTitle = this.$vue.$t('title'); + title = title ? `${title}-${defaultTitle}` : defaultTitle; + document.title = title; + }, + closeTag: (value) => { + let tag = value || this.$store.getters.tag; + if (typeof value === 'string') { + tag = this.$store.getters.tagList.filter(ele => ele.value === value)[0] + } + this.$store.commit('DEL_TAG', tag) + }, + generateTitle: (title, key) => { + if (!key) return title; + const hasKey = this.$vue.$te('route.' + key) + if (hasKey) { + // $t :this method from vue-i18n, inject in @/lang/index.js + const translatedTitle = this.$vue.$t('route.' + key) + + return translatedTitle + } + return title + }, + //处理路由 + getPath: function (params) { + let {src} = params; + let result = src || '/'; + if (src.includes("http") || src.includes("https")) { + result = `/myiframe/urlPath?${objToform(params)}`; + } + return result; + }, + //正则处理路由 + vaildPath: function (list, path) { + let result = false; + list.forEach(ele => { + if (new RegExp("^" + ele + ".*", "g").test(path)) { + result = true + } - }) - return result; - }, - //设置路由值 - getValue: function (route) { - let value = ""; - if (route.query.src) { - value = route.query.src; + }) + return result; + }, + //设置路由值 + getValue: function (route) { + let value = ""; + if (route.query.src) { + value = route.query.src; + } else { + value = route.path; + } + return value; + }, + //动态路由 + formatRoutes: function (aMenu = [], first) { + const aRouter = [] + const propsConfig = this.$website.menu.props; + const propsDefault = { + label: propsConfig.label || 'name', + path: propsConfig.path || 'path', + icon: propsConfig.icon || 'icon', + children: propsConfig.children || 'children', + meta: propsConfig.meta || 'meta', + } + if (aMenu.length === 0) return; + for (let i = 0; i < aMenu.length; i++) { + const oMenu = aMenu[i]; + if (this.routerList.includes(oMenu[propsDefault.path])) return; + let path = (() => { + if (first) { + return oMenu[propsDefault.path].replace('/index', '') } else { - value = route.path; - } - return value; - }, - //动态路由 - formatRoutes: function (aMenu = [], first) { - const aRouter = [] - const propsConfig = this.$website.menu.props; - const propsDefault = { - label: propsConfig.label || 'name', - path: propsConfig.path || 'path', - icon: propsConfig.icon || 'icon', - children: propsConfig.children || 'children', - meta: propsConfig.meta || 'meta', + return oMenu[propsDefault.path] } - if (aMenu.length === 0) return; - for (let i = 0; i < aMenu.length; i++) { - const oMenu = aMenu[i]; - if (this.routerList.includes(oMenu[propsDefault.path])) return; - const path = (() => { - if (first) { - return oMenu[propsDefault.path].replace('/index', '') - } else { - return oMenu[propsDefault.path] - } - })(), - //特殊处理组件 - component = 'views' + oMenu.path, - name = oMenu[propsDefault.label], - icon = oMenu[propsDefault.icon], - children = oMenu[propsDefault.children], - meta = oMenu[propsDefault.meta] || {}; + })(), + //特殊处理组件 + component = 'views' + oMenu.path, + name = oMenu[propsDefault.label], + icon = oMenu[propsDefault.icon], + children = oMenu[propsDefault.children], + meta = oMenu[propsDefault.meta] || {}; - const isChild = children.length !== 0; - const oRouter = { - path: path, - component(resolve) { - // 判断是否为首路由 - if (first) { - require(['../page/index'], resolve) - return - // 判断是否为多层路由 - } else if (isChild && !first) { - require(['../page/index/layout'], resolve) - return - // 判断是否为最终的页面视图 - } else { - require([`../${component}.vue`], resolve) - } - }, - name: name, - icon: icon, - meta: meta, - redirect: (() => { - if (!isChild && first && !isURL(path)) return `${path}/index` - else return ''; - })(), - // 处理是否为一级路由 - children: !isChild ? (() => { - if (first) { - if (!isURL(path)) oMenu[propsDefault.path] = `${path}/index`; - return [{ - component(resolve) { require([`../${component}.vue`], resolve) }, - icon: icon, - name: name, - meta: meta, - path: 'index' - }] - } - return []; - })() : (() => { - return this.formatRoutes(children, false) - })() - } - aRouter.push(oRouter) + meta = Object.assign(meta, (function () { + if (meta.keepAlive === true) { + return { + $keepAlive: true } + } + })()); + + const isChild = children.length !== 0; + const oRouter = { + path: path, + component(resolve) { + // 判断是否为首路由 if (first) { - if (!this.routerList.includes(aRouter[0][propsDefault.path])) { - this.safe.$router.addRoutes(aRouter) - this.routerList.push(aRouter[0][propsDefault.path]) - } + require(['../page/index'], resolve) + return + // 判断是否为多层路由 + } else if (isChild && !first) { + require(['../page/index/layout'], resolve) + return + // 判断是否为最终的页面视图 } else { - return aRouter + require([`../${component}.vue`], resolve) } - + }, + name: name, + icon: icon, + meta: meta, + redirect: (() => { + if (!isChild && first && !isURL(path)) return `${path}/index` + else return ''; + })(), + // 处理是否为一级路由 + children: !isChild ? (() => { + if (first) { + if (!isURL(path)) oMenu[propsDefault.path] = `${path}/index`; + return [{ + component(resolve) { + require([`../${component}.vue`], resolve) + }, + icon: icon, + name: name, + meta: meta, + path: 'index' + }] + } + return []; + })() : (() => { + return this.formatRoutes(children, false) + })() } + aRouter.push(oRouter) + } + if (first) { + if (!this.routerList.includes(aRouter[0][propsDefault.path])) { + this.safe.$router.addRoutes(aRouter) + this.routerList.push(aRouter[0][propsDefault.path]) + } + } else { + return aRouter + } + } + } } export default RouterPlugin; diff --git a/src/router/router.js b/src/router/router.js index 023a516..4919ffb 100644 --- a/src/router/router.js +++ b/src/router/router.js @@ -14,22 +14,29 @@ import Vue from 'vue'; import i18n from '@/lang' // Internationalization import Store from '../store/'; let Router = new VueRouter({ - scrollBehavior(to, from, savedPosition) { - if (savedPosition) { - return savedPosition - } else { - if (from.meta.keepAlive) { - from.meta.savedPosition = document.body.scrollTop; - } - return { - x: 0, - y: to.meta.savedPosition || 0 - } - } - }, - routes: [] + scrollBehavior(to, from, savedPosition) { + const avueView = document.getElementById('avue-view'); + if (!avueView) { + return { + x: 0, + y: 0 + } + } + if (savedPosition) { + return savedPosition + } else { + if (from.meta.keepAlive) { + from.meta.savedPosition = avueView.scrollTop + } else { + from.meta.savedPosition = 0; + } + avueView.scrollTop = to.meta.savedPosition + + } + }, + routes: [] }); AvueRouter.install(Vue, Router, Store, i18n); Router.$avueRouter.formatRoutes(Store.state.user.menu, true); Router.addRoutes([...PageRouter, ...ViewsRouter]); -export default Router; \ No newline at end of file +export default Router; diff --git a/src/util/util.js b/src/util/util.js index 3bb9172..cea6377 100644 --- a/src/util/util.js +++ b/src/util/util.js @@ -26,6 +26,9 @@ export const getObjType = obj => { } return map[toString.call(obj)]; }; +export const getViewDom = () => { + return window.document.getElementById('avue-view').getElementsByClassName('el-scrollbar__wrap')[0] +} /** * 对象深拷贝 */ @@ -285,4 +288,4 @@ export const openWindow = (url, title, w, h) => { if (window.focus) { newWindow.focus() } -} \ No newline at end of file +} diff --git a/src/views/util/affix.vue b/src/views/util/affix.vue new file mode 100644 index 0000000..21ff38e --- /dev/null +++ b/src/views/util/affix.vue @@ -0,0 +1,46 @@ + + + + + diff --git a/src/views/util/cache.vue b/src/views/util/cache.vue new file mode 100644 index 0000000..b7a6e12 --- /dev/null +++ b/src/views/util/cache.vue @@ -0,0 +1,22 @@ + + + diff --git a/src/views/util/crud-form.vue b/src/views/util/crud-form.vue new file mode 100644 index 0000000..2e1e0de --- /dev/null +++ b/src/views/util/crud-form.vue @@ -0,0 +1,59 @@ + + + + + diff --git a/src/views/util/form-detail.vue b/src/views/util/form-detail.vue new file mode 100644 index 0000000..e9ea21f --- /dev/null +++ b/src/views/util/form-detail.vue @@ -0,0 +1,40 @@ + + + + + diff --git a/src/views/util/top.vue b/src/views/util/top.vue new file mode 100644 index 0000000..f524cc9 --- /dev/null +++ b/src/views/util/top.vue @@ -0,0 +1,28 @@ + + + + +