diff --git a/src/components/main/components/tags-nav/tags-nav.vue b/src/components/main/components/tags-nav/tags-nav.vue index e87f7b4..5f97f60 100644 --- a/src/components/main/components/tags-nav/tags-nav.vue +++ b/src/components/main/components/tags-nav/tags-nav.vue @@ -197,8 +197,12 @@ export default { } }, mounted () { - // 默认关闭所有的标签 - this.handleTagsOption('all') + // 默认关闭所有的标签(仅在进入首页时重置)。 + // 注意:直接输入地址/刷新进入子页面时不能重置,因为 handleTagsOption('all') 会触发 + // 父组件的 handleCloseTag(res, 'all'),进而 turnToPage('home') 把页面弹回首页,导致深链接失效。 + if (this.$route.name === this.$config.homeName) { + this.handleTagsOption('all') + } setTimeout(() => { this.getTagElementByName(this.$route) }, 200) diff --git a/src/components/main/main.vue b/src/components/main/main.vue index adc2469..5ea902a 100644 --- a/src/components/main/main.vue +++ b/src/components/main/main.vue @@ -154,6 +154,13 @@ export default { this.addTag({ route: this.$store.state.app.homeRoute }) + // 直接输入地址/刷新进入时,localStorage 恢复的标签栏里没有当前页面, + // 这里把它补进标签栏,而不是直接跳回首页,否则深链接会被弹回首页 + if (this.$route.name && this.$route.name !== this.$config.homeName) { + this.addTag({ + route: this.$route + }) + } this.setBreadCrumb(this.$route) // 如果当前打开页面不在标签栏中,跳到homeName页 if (!this.tagNavList.find(item => item.name === this.$route.name)) { diff --git a/src/router/index.js b/src/router/index.js index 1c84c8f..fa833b4 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -24,6 +24,7 @@ const router = new Router({ routes, mode: 'history' }) + const LOGIN_PAGE_NAME = 'login' const turnTo = (to, access, next) => { @@ -31,6 +32,36 @@ const turnTo = (to, access, next) => { else next({replace: true, name: 'error_401'}) // 无权限,重定向到401页面 } +// 应用首次加载时的地址(此时 vue-router 尚未改写 URL),作为深链接兜底 +const ENTRY_PATH = window.location.pathname + window.location.search + window.location.hash + +/** + * 修正「直接输入地址 / 刷新页面」时深链接失效的问题。 + * + * 动态菜单路由是在首次导航的守卫里才 addRoutes 的,而 vue-router 在进入守卫之前 + * 就已经用通配符路由(path: '*' → redirect: '/home')把未注册的地址重定向掉了, + * 所以守卫里拿到的 to 已经是 /home,原始地址只保留在 to.redirectedFrom 中 + * (vue-router 3.x 存的是 fullPath 字符串),表现为访问 /delta/gun-code 后停在首页「无反应」。 + * + * 这里在动态路由注册完成后,用新的 matcher 重新匹配原始地址:命中真实路由则再跳一次。 + * @returns {Boolean} 是否已重新发起跳转(true 时调用方不要再调用 next) + */ +const turnToRedirectedFrom = (to, next) => { + const redirectedFrom = to.redirectedFrom + // 兼容字符串(vue-router 3.x 实际类型)与对象两种形态,取不到时回退到入口地址 + const fromPath = typeof redirectedFrom === 'string' + ? redirectedFrom + : (redirectedFrom && redirectedFrom.path) || ENTRY_PATH + // 根路径本身就会重定向到首页;已经停在目标地址也无需再跳 + if (!fromPath || fromPath === '/' || fromPath === to.fullPath) return false + const matched = router.match(fromPath) + if (matched.matched.length > 0 && matched.name !== '_no_match') { + next({ path: fromPath, replace: true }) + return true + } + return false +} + router.beforeEach((to, from, next) => { iView.LoadingBar.start() const token = getToken() @@ -67,7 +98,8 @@ router.beforeEach((to, from, next) => { // 刷新界面菜单 store.commit('updateMenuList', list) - next() + // 动态路由已注册,若本次是深链接(被通配符重定向过)则回到原始地址 + if (!turnToRedirectedFrom(to, next)) next() }).catch(() => { // 获取权限失败,直接放行(保留基础路由),避免卡死 next() @@ -75,7 +107,8 @@ router.beforeEach((to, from, next) => { } else { let list = formatMenuList(JSON.parse(menuListStr)) store.commit('updateMenuList', list) - next() + // 动态路由已注册,若本次是深链接(被通配符重定向过)则回到原始地址 + if (!turnToRedirectedFrom(to, next)) next() } }).catch(() => { diff --git a/src/view/delta/delta-gun-code-entry.vue b/src/view/delta/delta-gun-code-entry.vue new file mode 100644 index 0000000..977bb4c --- /dev/null +++ b/src/view/delta/delta-gun-code-entry.vue @@ -0,0 +1,315 @@ + + + + + + 录入后立即生效,公开复制页无需登录即可查看(仅「显示」状态的记录)。 + 复制公开页地址 + + + + + + + + 改枪码录入 + + + + + + + + + + + + + + + + + + + + {{ item }} + + + + + + + + + + + + 显示 + + + 隐藏 + + + + + + 保存并继续录入 + + 重置 + 快捷键:Ctrl + Enter + + + + + + + + + + 最近录入 + 刷新 + 暂无记录 + + + + {{ item.category || '未分类' }} + {{ item.name }} + {{ item.gunName }} + + {{ item.code }} + {{ item.createBy || '-' }} · {{ formatDate(item.createDate) }} + + 复制 + + + + + + + + + + +
改枪码录入
最近录入