Skip to content

fix: 添加内部 iframe 展示网页,优化 permission.js 逻辑 #1989

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions web/src/components/commandMenu/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@
const options = reactive([])
const deepMenus = (menus) => {
const arr = []
menus.forEach((menu) => {
menus?.forEach((menu) => {
if (!menu?.children) return
if (menu.children && menu.children.length > 0) {
arr.push(...deepMenus(menu.children))
} else {
Expand All @@ -77,7 +78,7 @@
label: '跳转',
children: []
}
const menus = deepMenus(routerStore.asyncRouters[0].children)
const menus = deepMenus(routerStore.asyncRouters[0]?.children || [])
option.children.push(...menus)
options.push(option)
}
Expand Down
1 change: 1 addition & 0 deletions web/src/pathInfo.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"/src/view/layout/aside/normalMode.vue": "GvaAside",
"/src/view/layout/header/index.vue": "Index",
"/src/view/layout/header/tools.vue": "Tools",
"/src/view/layout/iframe.vue": "GvaLayoutIframe",
"/src/view/layout/index.vue": "GvaLayout",
"/src/view/layout/screenfull/index.vue": "Screenfull",
"/src/view/layout/search/search.vue": "BtnBox",
Expand Down
195 changes: 102 additions & 93 deletions web/src/permission.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,134 +4,143 @@ import getPageTitle from '@/utils/page'
import router from '@/router'
import Nprogress from 'nprogress'
import 'nprogress/nprogress.css'
Nprogress.configure({ showSpinner: false, ease: 'ease', speed: 500 })

const whiteList = ['Login', 'Init']
// 配置 NProgress
Nprogress.configure({
showSpinner: false,
ease: 'ease',
speed: 500
})

const getRouter = async (userStore) => {
const routerStore = useRouterStore()
await routerStore.SetAsyncRouter()
await userStore.GetUserInfo()
const asyncRouters = routerStore.asyncRouters
asyncRouters.forEach((asyncRouter) => {
router.addRoute(asyncRouter)
})
// 白名单路由
const WHITE_LIST = ['Login', 'Init', 'Iframe']

// 处理路由加载
const setupRouter = async (userStore) => {
try {
const routerStore = useRouterStore()
await Promise.all([routerStore.SetAsyncRouter(), userStore.GetUserInfo()])

routerStore.asyncRouters.forEach((route) => router.addRoute(route))
return true
} catch (error) {
console.error('Setup router failed:', error)
return false
}
}

// 移除加载动画
const removeLoading = () => {
const element = document.getElementById('gva-loading-box')
if (element) {
element.remove()
}
element?.remove()
}

async function handleKeepAlive(to) {
if (to.matched.some((item) => item.meta.keepAlive)) {
if (to.matched && to.matched.length > 2) {
for (let i = 1; i < to.matched.length; i++) {
const element = to.matched[i - 1]
if (element.name === 'layout') {
to.matched.splice(i, 1)
await handleKeepAlive(to)
}
// 如果没有按需加载完成则等待加载
if (typeof element.components.default === 'function') {
await element.components.default()
await handleKeepAlive(to)
}
// 处理组件缓存
const handleKeepAlive = async (to) => {
if (!to.matched.some((item) => item.meta.keepAlive)) return

if (to.matched?.length > 2) {
for (let i = 1; i < to.matched.length; i++) {
const element = to.matched[i - 1]

if (element.name === 'layout') {
to.matched.splice(i, 1)
await handleKeepAlive(to)
continue
}

if (typeof element.components.default === 'function') {
await element.components.default()
await handleKeepAlive(to)
}
}
}
}

// 处理路由重定向
const handleRedirect = (to, userStore) => {
if (router.hasRoute(userStore.userInfo.authority.defaultRouter)) {
return { ...to, replace: true }
}
return { path: '/layout/404' }
}

// 路由守卫
router.beforeEach(async (to, from) => {
const userStore = useUserStore()
const routerStore = useRouterStore()
const token = userStore.token

Nprogress.start()
const userStore = useUserStore()

// 处理元数据和缓存
to.meta.matched = [...to.matched]
handleKeepAlive(to)
const token = userStore.token
// 在白名单中的判断情况
await handleKeepAlive(to)

// 设置页面标题
document.title = getPageTitle(to.meta.title, to)

if (to.meta.client) {
return true
}
if (whiteList.indexOf(to.name) > -1) {
if (token) {
if (!routerStore.asyncRouterFlag && whiteList.indexOf(from.name) < 0) {
await getRouter(userStore)
}
// token 可以解析但是却是不存在的用户 id 或角色 id 会导致无限调用
if (userStore.userInfo?.authority?.defaultRouter != null) {
if (router.hasRoute(userStore.userInfo.authority.defaultRouter)) {
return { name: userStore.userInfo.authority.defaultRouter }
} else {
return { path: '/layout/404' }
}
} else {
// 强制退出账号
userStore.ClearStorage()
return {
name: 'Login',
query: {
redirect: document.location.hash
}
}
}
} else {
return true

// 白名单路由处理
if (WHITE_LIST.includes(to.name)) {
if (
token &&
!routerStore.asyncRouterFlag &&
!WHITE_LIST.includes(from.name)
) {
await setupRouter(userStore)
}
} else {
// 不在白名单中并且已经登录的时候
if (token) {
if (sessionStorage.getItem('needToHome') === 'true') {
sessionStorage.removeItem('needToHome')
return { path: '/' }
}
// 添加flag防止多次获取动态路由和栈溢出
if (!routerStore.asyncRouterFlag && whiteList.indexOf(from.name) < 0) {
await getRouter(userStore)
if (userStore.token) {
if (router.hasRoute(userStore.userInfo.authority.defaultRouter)) {
return { ...to, replace: true }
} else {
return { path: '/layout/404' }
}
} else {
return {
name: 'Login',
query: { redirect: to.href }
}
}
} else {
if (to.matched.length) {
return true
} else {
return { path: '/layout/404' }
}
}
return true
}

// 需要登录的路由处理
if (token) {
// 处理需要跳转到首页的情况
if (sessionStorage.getItem('needToHome') === 'true') {
sessionStorage.removeItem('needToHome')
return { path: '/' }
}
// 不在白名单中并且未登录的时候
if (!token) {

// 处理异步路由
if (!routerStore.asyncRouterFlag && !WHITE_LIST.includes(from.name)) {
const setupSuccess = await setupRouter(userStore)

if (setupSuccess && userStore.token) {
return handleRedirect(to, userStore)
}

return {
name: 'Login',
query: {
redirect: document.location.hash
}
query: { redirect: to.href }
}
}

return to.matched.length ? true : { path: '/layout/404' }
}

// 未登录跳转登录页
return {
name: 'Login',
query: {
redirect: document.location.hash
}
}
})

// 路由加载完成
router.afterEach(() => {
// 路由加载完成后关闭进度条
document.getElementsByClassName('main-cont main-right')[0]?.scrollTo(0, 0)
document.querySelector('.main-cont.main-right')?.scrollTo(0, 0)
Nprogress.done()
})

router.onError(() => {
// 路由发生错误后销毁进度条
// 路由错误处理
router.onError((error) => {
console.error('Router error:', error)
Nprogress.remove()
})

// 移除初始加载动画
removeLoading()
5 changes: 5 additions & 0 deletions web/src/router/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ const routes = [
closeTab: true
},
component: () => import('@/view/error/index.vue')
},
{
path: '/iframe',
name: 'Iframe',
component: () => import('@/view/layout/iframe.vue')
}
]

Expand Down
8 changes: 4 additions & 4 deletions web/src/view/dashboard/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@
<div
class="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-7 py-2 gap-4 md:gap-2 gva-container2"
>
<gva-card custom-class="col-span-1 lg:col-span-2 h-32">
<gva-card custom-class="col-span-1 lg:col-span-2 ">
<gva-chart :type="1" title="访问人数" />
</gva-card>
<gva-card custom-class="col-span-1 lg:col-span-2 h-32 ">
<gva-card custom-class="col-span-1 lg:col-span-2 ">
<gva-chart :type="2" title="新增客户" />
</gva-card>
<gva-card custom-class="col-span-1 lg:col-span-2 h-32">
<gva-card custom-class="col-span-1 lg:col-span-2 ">
<gva-chart :type="3" title="解决数量" />
</gva-card>
<gva-card
title="快捷功能"
show-action
custom-class="col-start-1 md:col-start-3 lg:col-start-7 row-span-2 h-38"
custom-class="col-start-1 md:col-start-3 lg:col-start-7 row-span-2 "
>
<gva-quick-link />
</gva-card>
Expand Down
17 changes: 16 additions & 1 deletion web/src/view/layout/aside/combinationMode.vue
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@
})

watchEffect(() => {
if (route.name === 'Iframe') {
active.value = decodeURIComponent(route.query.url)
return
}
active.value = route.meta.activeName || route.name
})

Expand All @@ -123,7 +127,18 @@
})
if (index === route.name) return
if (index.indexOf('http://') > -1 || index.indexOf('https://') > -1) {
window.open(index)
if (index === 'Iframe') {
query.url = decodeURIComponent(index)
router.push({
name: 'Iframe',
query,
params
})
return
} else {
window.open(index, '_blank')
return
}
} else {
if (!top) {
router.push({ name: index, query, params })
Expand Down
17 changes: 16 additions & 1 deletion web/src/view/layout/aside/headMode.vue
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
const isCollapse = ref(false)
const active = ref('')
watchEffect(() => {
if (route.name === 'Iframe') {
active.value = decodeURIComponent(route.query.url)
return
}
active.value = route.meta.activeName || route.name
})

Expand All @@ -66,7 +70,18 @@
})
if (index === route.name) return
if (index.indexOf('http://') > -1 || index.indexOf('https://') > -1) {
window.open(index)
if (index === 'Iframe') {
query.url = decodeURIComponent(index)
router.push({
name: 'Iframe',
query,
params
})
return
} else {
window.open(index, '_blank')
return
}
} else {
router.push({ name: index, query, params })
}
Expand Down
Loading
Loading