多页签中的visitedViews只存储部分字段

代码简化
移除path-to-regexp
master
toesbieya 6 years ago
parent 04f098842d
commit d125fba250
  1. 5
      vue/package-lock.json
  2. 1
      vue/package.json
  3. 2
      vue/src/config/index.js
  4. 13
      vue/src/layout/mixin/tagsViewPersistent.js
  5. 17
      vue/src/layout/store/tagsView.js
  6. 8
      vue/src/main.js
  7. 20
      vue/src/router/guardian/accessControl.js
  8. 8
      vue/src/router/guardian/avoidReuse.js
  9. 8
      vue/src/router/guardian/index.js
  10. 0
      vue/src/router/guardian/setTitle.js
  11. 27
      vue/src/router/index.js
  12. 2
      vue/src/router/util.js
  13. 4
      vue/src/store/index.js
  14. 2
      vue/src/store/module/app.js
  15. 24
      vue/src/store/module/socket.js
  16. 2
      vue/src/store/module/user.js
  17. 4
      vue/src/util/storage.js
  18. 2
      vue/src/view/app/login/LoginForm.vue
  19. 6
      vue/src/view/app/login/RegisterForm.vue
  20. 2
      vue/src/view/system/user/indexPage.vue

@ -10092,11 +10092,6 @@
"integrity": "sha1-1i27VnlAXXLEc37FhgDp3c8G0kw=", "integrity": "sha1-1i27VnlAXXLEc37FhgDp3c8G0kw=",
"dev": true "dev": true
}, },
"path-to-regexp": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.1.0.tgz",
"integrity": "sha512-h9DqehX3zZZDCEm+xbfU0ZmwCGFCAAraPJWMXJ4+v32NjZJilVg3k1TcKsRgIb8IQ/izZSaydDc1OhJCZvs2Dw=="
},
"path-type": { "path-type": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",

@ -17,7 +17,6 @@
"normalize.css": "^8.0.1", "normalize.css": "^8.0.1",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"pako": "^1.0.11", "pako": "^1.0.11",
"path-to-regexp": "^6.1.0",
"socket.io-client": "^2.3.0", "socket.io-client": "^2.3.0",
"vue": "^2.6.11", "vue": "^2.6.11",
"vue-count-to": "^1.0.13", "vue-count-to": "^1.0.13",

@ -8,7 +8,7 @@ module.exports = {
//项目的部署路径,始终以'/'开头,以'/'结束 //项目的部署路径,始终以'/'开头,以'/'结束
contextPath, contextPath,
//页面标题、登注册页的标题 //页面标题、登注册页的标题
title: 'BiuBiuBiu~', title: 'BiuBiuBiu~',
//全局axios的baseUrl、devServer的路由前缀 //全局axios的baseUrl、devServer的路由前缀

@ -10,9 +10,7 @@ import {getTagsView, setTagsView} from "@/util/storage"
export default { export default {
computed: { computed: {
shouldPersistent() { shouldPersistent: () => tagsViewGetters.persistent
return tagsViewGetters.persistent
}
}, },
watch: { watch: {
@ -36,15 +34,8 @@ export default {
} }
}, },
methods: {
persistentTagsView(v) {
//只提取部分属性
setTagsView(v.map(({name, path, fullPath, meta}) => ({name, path, fullPath, meta})))
}
},
beforeCreate() { beforeCreate() {
this.persistentTagsView = debounce(this.persistentTagsView) this.persistentTagsView = debounce(setTagsView)
}, },
mounted() { mounted() {

@ -35,23 +35,30 @@ export const mutations = bindThis({
enabled(v) { enabled(v) {
store.enabled = v store.enabled = v
//多页签停用时清除所有页面缓存 //多页签停用时清除所有页面缓存
!v && this.delAllViews() !v && this.delAllViews()
}, },
addVisitedView(view) { addVisitedView({name, path, fullPath, meta = {}}) {
if (store.visitedViews.some(v => v.path === view.path)) return if (store.visitedViews.some(v => v.path === path)) {
return
}
store.visitedViews.push(view) store.visitedViews.push({name, path, fullPath, meta: {...meta}})
}, },
addCachedView(view) { addCachedView(view) {
const {noCache, iframe, usePathKey, useFullPathKey} = view.meta || {} const {noCache, iframe, usePathKey, useFullPathKey} = view.meta || {}
if (noCache || iframe || !view.name && !usePathKey && !useFullPathKey) return if (noCache || iframe || !view.name && !usePathKey && !useFullPathKey) {
return
}
const key = getRouterViewCacheKey(view) const key = getRouterViewCacheKey(view)
if (store.cachedViews.includes(key)) return if (store.cachedViews.includes(key)) {
return
}
store.cachedViews.push(key) store.cachedViews.push(key)
}, },

@ -27,10 +27,4 @@ new Vue({
}) })
//页面刷新时socket重连 //页面刷新时socket重连
store.dispatch('socket/init', store.state.user).catch() store.dispatch('socket/init').catch()
window.addEventListener('unhandledrejection', event => {
if (event.reason.stack.startsWith('Error: Redirected when going from')) {
event.preventDefault()
}
})

@ -1,18 +1,17 @@
import {pathToRegexp} from 'path-to-regexp'
import store from "@/store" import store from "@/store"
import {isEmpty} from "@/util"
import {auth, needAuth} from "@/util/auth" import {auth, needAuth} from "@/util/auth"
import {isUserExist} from "@/util/storage"
const whiteList = ['/login', '/register', '/403', '/404', '/500'].map(url => pathToRegexp(url)) const noLoginList = ['/login', '/register', '/403', '/404', '/500']
const beforeEach = async (to, from, next) => { const beforeEach = async (to, from, next) => {
//白名单内不需要进行权限控制 //放行不需要登录即可访问的路由
if (whiteList.some(reg => reg.test(to.path))) { if (noLoginList.includes(to.path)) {
return next() return next()
} }
//未登录时返回登录页 //未登录时返回登录页
if (!isUserExist()) { if (isEmpty(store.state.user.id, store.state.user.token)) {
return next({path: '/login', query: {redirect: to.fullPath}}) return next({path: '/login', query: {redirect: to.fullPath}})
} }
@ -31,11 +30,12 @@ const beforeEach = async (to, from, next) => {
next('/403') next('/403')
} }
//获取进行权限验证的路由地址,使用了动态路由的会用到 //获取进行权限验证的路由地址
function getAuthorizedPath(route) { function getAuthorizedPath(route) {
const {params, path, matched} = route const {path, matched} = route, len = matched.length
const isDynamic = Object.values(params).some(v => path.includes(v))
return isDynamic ? matched[matched.length - 1].path : path //可能会有路由使用动态路径(诸如/:id),matched中的path是routeConfig中声明的原始路径
return len > 0 ? matched[len - 1].path : path
} }
export default function (router) { export default function (router) {

@ -5,7 +5,7 @@ const beforeEach = (to, from, next) => {
const a = to.meta.commonModule, b = from.meta.commonModule const a = to.meta.commonModule, b = from.meta.commonModule
const isComponentReuse = !isEmpty(a) && a === b const isComponentReuse = !isEmpty(a) && a === b
if (isComponentReuse) { if (isComponentReuse) {
//这里vue-router会报redirect错误,已在main.js中忽略 //这里vue-router会报redirect错误,已在下方忽略
return next(`/redirect${to.fullPath}`) return next(`/redirect${to.fullPath}`)
} }
next() next()
@ -14,3 +14,9 @@ const beforeEach = (to, from, next) => {
export default function (router) { export default function (router) {
router.beforeEach(beforeEach) router.beforeEach(beforeEach)
} }
window.addEventListener('unhandledrejection', event => {
if (event.reason.stack.startsWith('Error: Redirected when going from')) {
event.preventDefault()
}
})

@ -1,13 +1,13 @@
import nprogress from './nprogress' import nprogress from './nprogress'
import avoidReuse from './avoidReuse' import avoidReuse from './avoidReuse'
import setInfo from './setInfo' import setTitle from './setTitle'
import security from './security' import accessControl from './accessControl'
import iframe from './iframe' import iframe from './iframe'
export default function (router) { export default function (router) {
nprogress(router) nprogress(router)
avoidReuse(router) avoidReuse(router)
setInfo(router) accessControl(router)
security(router) setTitle(router)
iframe(router) iframe(router)
} }

@ -1,16 +1,17 @@
/* /**
* 路由配置 * 路由配置说明
* *
* 需要鉴权的路由!meta.noAuth * 不需要鉴权的路由meta.noAuth
* 左侧菜单显示name && !meta.hidden && meta.title * 左侧菜单显示name && !meta.hidden && meta.title
* 左侧菜单排序能在左侧菜单中显示 && meta.sort升序排列 * 左侧菜单排序能在左侧菜单中显示 && meta.sort升序排列
* 左侧菜单不折叠只有一个children的路由meta.alwaysShow * 左侧菜单不折叠只有一个children的路由meta.alwaysShow
* 页头显示meta.pageHeader !== false && (meta.title || meta.dynamicTitle) * 页头显示meta.pageHeader !== false && (meta.title || meta.dynamicTitle)
* tab栏显示meta.title || meta.dynamicTitle * tab栏显示meta.title || meta.dynamicTitle
* tab栏固定显示meta.title && meta.affix * tab栏固定显示meta.title && meta.affix
* 页面不缓存!name && !meta.usePathKey && !meta.useFullPathKey || meta.noCache * 页面不缓存!name && !meta.usePathKey && !meta.useFullPathKey || meta.noCache
* 打开iframemeta.iframe不会重复打开相同src的iframe * 打开iframemeta.iframe不会重复打开相同src的iframe
* */ */
import Vue from 'vue' import Vue from 'vue'
import Router from 'vue-router' import Router from 'vue-router'
import {route as routeConfig} from '@/config' import {route as routeConfig} from '@/config'

@ -128,7 +128,7 @@ export function generateRoutes(jsonTree) {
return jsonTree return jsonTree
} }
//子路由继承父路由meta上的{noAuth,noCache},优先使用子路由的值 //子路由继承父路由meta上的{noAuth, noCache},优先使用子路由的值
export function metaExtend(routes, parentMeta) { export function metaExtend(routes, parentMeta) {
const keys = ['noAuth', 'noCache'] const keys = ['noAuth', 'noCache']
routes.forEach(route => { routes.forEach(route => {

@ -15,6 +15,4 @@ const modules = modulesFiles.keys().reduce((modules, modulePath) => {
return modules return modules
}, {}) }, {})
export default new Vuex.Store({ export default new Vuex.Store({modules})
modules
})

@ -1,7 +1,7 @@
import {createMutations} from "@/store/util" import {createMutations} from "@/store/util"
const state = { const state = {
//登页背景动画 //登页背景动画
loginBackgroundAnimation: 'sparkRain', loginBackgroundAnimation: 'sparkRain',
} }

@ -13,21 +13,19 @@ const state = {
const mutations = createMutations(state) const mutations = createMutations(state)
const actions = { const actions = {
init(context, user) { init(context) {
if (useMock || isEmpty(user, user.id, user.token)) return const {id, token} = context.rootState.user
socket = initSocket(user) if (useMock || isEmpty(id, token)) return
defaultEventBind(socket, context) socket = initSocket({id, token})
customEventBind(socket, context)
bindDefaultEvent(socket, context)
bindCustomEvent(socket, context)
}, },
close() { close() {
return new Promise(resolve => { socket && socket.close()
if (!socket) return resolve()
socket.close()
resolve()
})
} }
} }
@ -35,7 +33,7 @@ function initSocket({id, token}) {
return new SocketIO(socketUrl, {query: {id, token}, transports: ['websocket']}) return new SocketIO(socketUrl, {query: {id, token}, transports: ['websocket']})
} }
function defaultEventBind(socket, {state, commit, dispatch}) { function bindDefaultEvent(socket, {state, commit, dispatch}) {
socket.on('connect', () => { socket.on('connect', () => {
commit('online', true) commit('online', true)
console.log('socket连接成功') console.log('socket连接成功')
@ -72,10 +70,10 @@ function defaultEventBind(socket, {state, commit, dispatch}) {
}) })
} }
function customEventBind(socket, {state, commit, dispatch, rootState}) { function bindCustomEvent(socket, {state, commit, dispatch, rootState}) {
socket.on('logout', msg => { socket.on('logout', msg => {
if (rootState.user.prepareLogout) return if (rootState.user.prepareLogout) return
MessageBox.alert(msg || '你已被强制下线,请重新登', { MessageBox.alert(msg || '你已被强制下线,请重新登', {
type: 'warning', type: 'warning',
beforeClose: (action, instance, done) => { beforeClose: (action, instance, done) => {
dispatch('user/logout', null, {root: true}).finally(done) dispatch('user/logout', null, {root: true}).finally(done)

@ -35,7 +35,7 @@ const actions = {
user.avatar = autoCompleteUrl(user.avatar) user.avatar = autoCompleteUrl(user.avatar)
commit('$all', user) commit('$all', user)
setUser(user) setUser(user)
return dispatch('socket/init', user, {root: true}) return dispatch('socket/init', null, {root: true})
}) })
}, },

@ -59,10 +59,6 @@ const sessionUserKey = 'SESS-USER'
const localPersonalSettingsKey = 'LOCAL-PERSONAL-SETTINGS' const localPersonalSettingsKey = 'LOCAL-PERSONAL-SETTINGS'
const sessionTagsViewKey = 'SESS-TAGS-VIEW' const sessionTagsViewKey = 'SESS-TAGS-VIEW'
export function isUserExist() {
return exist(sessionUserKey)
}
export function getUser() { export function getUser() {
let user = get(sessionUserKey) let user = get(sessionUserKey)
if (isEmpty(user)) { if (isEmpty(user)) {

@ -104,7 +104,7 @@ export default {
}, },
success() { success() {
elSuccess('登成功') elSuccess('登成功')
const redirect = this.$route.query.redirect || '/' const redirect = this.$route.query.redirect || '/'
//0.2s //0.2s
window.setTimeout(() => this.$router.replace(redirect), 200) window.setTimeout(() => this.$router.replace(redirect), 200)

@ -4,7 +4,7 @@
<span class="svg-container"> <span class="svg-container">
<v-icon icon="svg-user"/> <v-icon icon="svg-user"/>
</span> </span>
<el-input ref="username" v-model="form.username" :maxlength="20" placeholder="请输入登名称"/> <el-input ref="username" v-model="form.username" :maxlength="20" placeholder="请输入登名称"/>
</el-form-item> </el-form-item>
<el-form-item prop="nick"> <el-form-item prop="nick">
@ -47,7 +47,7 @@
<div class="flex" style="margin-top: 20px"> <div class="flex" style="margin-top: 20px">
<p/> <p/>
<el-button type="text" @click="login">已有账户登</el-button> <el-button type="text" @click="login">已有账户登</el-button>
</div> </div>
</el-form> </el-form>
</template> </template>
@ -86,7 +86,7 @@ export default {
}, },
rules: { rules: {
username: [ username: [
{required: true, message: '请输入登名称', trigger: 'change'}, {required: true, message: '请输入登名称', trigger: 'change'},
{validator: validateLoginName, trigger: 'change'} {validator: validateLoginName, trigger: 'change'}
], ],
nick: [ nick: [

@ -50,7 +50,7 @@
@click.stop="() => previewAvatar(row.avatar)" @click.stop="() => previewAvatar(row.avatar)"
> >
</el-table-column> </el-table-column>
<el-table-column align="center" label="登名" prop="loginName" show-overflow-tooltip/> <el-table-column align="center" label="登名" prop="loginName" show-overflow-tooltip/>
<el-table-column align="center" label="昵称" prop="nickName" show-overflow-tooltip/> <el-table-column align="center" label="昵称" prop="nickName" show-overflow-tooltip/>
<el-table-column align="center" label="角 色" show-overflow-tooltip> <el-table-column align="center" label="角 色" show-overflow-tooltip>
<template v-slot="{row}"> <template v-slot="{row}">

Loading…
Cancel
Save