mirror of
https://github.com/fantastic-admin/basic.git
synced 2026-10-07 15:48:05 +08:00
增加外链路由跳转提示页面,重构外链路由的配置方式
This commit is contained in:
Vendored
+2
@@ -220,6 +220,7 @@ declare module 'vue-router' {
|
||||
breadcrumb?: boolean
|
||||
activeMenu?: string
|
||||
cache?: boolean | string | string[]
|
||||
link?: string
|
||||
breadcrumbNeste?: Route.breadcrumb[]
|
||||
}
|
||||
}
|
||||
@@ -250,6 +251,7 @@ declare namespace Menu {
|
||||
defaultOpened?: boolean
|
||||
auth?: string | string[]
|
||||
sidebar?: boolean
|
||||
link?: string
|
||||
}
|
||||
children?: recordRaw[]
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ onMounted(() => {
|
||||
})
|
||||
|
||||
function open(url: string) {
|
||||
window.open(url, 'top')
|
||||
window.open(url, '_blank')
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import hotkeys from 'hotkeys-js'
|
||||
import type { RouteRecordRaw } from 'vue-router'
|
||||
import { isExternalLink } from '@/utils'
|
||||
import eventBus from '@/utils/eventBus'
|
||||
import useSettingsStore from '@/store/modules/settings'
|
||||
import useRouteStore from '@/store/modules/route'
|
||||
@@ -16,10 +15,11 @@ const routeStore = useRouteStore()
|
||||
const menuStore = useMenuStore()
|
||||
|
||||
interface listTypes {
|
||||
path: string
|
||||
icon?: string
|
||||
title?: string | Function
|
||||
link?: string
|
||||
breadcrumb: (string | Function | undefined)[]
|
||||
path: string
|
||||
}
|
||||
|
||||
const isShow = ref(false)
|
||||
@@ -151,18 +151,12 @@ function getSourceList(arr: RouteRecordRaw[], basePath?: string, icon?: string,
|
||||
}
|
||||
else {
|
||||
breadcrumbTemp.push(item.meta?.title)
|
||||
let path = ''
|
||||
if (isExternalLink(item.path)) {
|
||||
path = item.path
|
||||
}
|
||||
else {
|
||||
path = basePath ? [basePath, item.path].join('/') : item.path
|
||||
}
|
||||
sourceList.value.push({
|
||||
path: basePath ? [basePath, item.path].join('/') : item.path,
|
||||
icon: item.meta?.icon ?? icon,
|
||||
title: item.meta?.title,
|
||||
link: item.meta?.link,
|
||||
breadcrumb: breadcrumbTemp,
|
||||
path,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -230,12 +224,12 @@ function handleScroll() {
|
||||
})
|
||||
}
|
||||
|
||||
function pageJump(url: string) {
|
||||
if (isExternalLink(url)) {
|
||||
window.open(url, 'top')
|
||||
function pageJump(path: listTypes['path'], link: listTypes['link']) {
|
||||
if (link) {
|
||||
window.open(link, '_blank')
|
||||
}
|
||||
else {
|
||||
router.push(url)
|
||||
router.push(path)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -284,7 +278,7 @@ function pageJump(url: string) {
|
||||
</div>
|
||||
</div>
|
||||
<div ref="searchResultRef" class="result" :class="{ mobile: settingsStore.mode === 'mobile' }">
|
||||
<a v-for="(item, index) in resultList" :key="item.path" :ref="setSearchResultItemRef" class="item" :class="{ actived: index === actived }" @click="pageJump(item.path)" @mouseover="actived = index">
|
||||
<a v-for="(item, index) in resultList" :key="item.path" :ref="setSearchResultItemRef" class="item" :class="{ actived: index === actived }" @click="pageJump(item.path, item.link)" @mouseover="actived = index">
|
||||
<el-icon class="icon">
|
||||
<svg-icon v-if="item.icon" :name="item.icon" />
|
||||
</el-icon>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts" setup name="SidebarItem">
|
||||
// import SidebarItem from './index.vue'
|
||||
import { isExternalLink, resolveRoutePath } from '@/utils'
|
||||
import { resolveRoutePath } from '@/utils'
|
||||
import useSettingsStore from '@/store/modules/settings'
|
||||
import type { Menu } from '@/global'
|
||||
|
||||
@@ -33,8 +33,8 @@ const hasChildren = computed(() => {
|
||||
|
||||
<template>
|
||||
<div class="sidebar-item">
|
||||
<router-link v-if="!hasChildren" v-slot="{ href, navigate, isActive, isExactActive }" custom :to="resolveRoutePath(basePath, item.path || '')">
|
||||
<a :href="isExternalLink(resolveRoutePath(basePath, item.path || '')) ? resolveRoutePath(basePath, item.path || '') : href" :class="[isActive && 'router-link-active', isExactActive && 'router-link-exact-active']" :target="isExternalLink(resolveRoutePath(basePath, item.path || '')) ? '_blank' : '_self'" @click="navigate">
|
||||
<router-link v-if="!hasChildren" v-slot="{ navigate, isActive, isExactActive }" custom :to="resolveRoutePath(basePath, item.path)">
|
||||
<a :href="item.meta?.link ? item.meta.link : resolveRoutePath(basePath, item.path)" :class="[isActive && 'router-link-active', isExactActive && 'router-link-exact-active']" :target="item.meta?.link ? '_blank' : '_self'" @click="navigate">
|
||||
<el-menu-item :title="item.meta?.title ?? '[ 无标题 ]'" :index="resolveRoutePath(basePath, item.path || '')">
|
||||
<el-icon v-if="item.meta?.icon" class="title-icon">
|
||||
<svg-icon :name="item.meta.icon" />
|
||||
@@ -43,7 +43,7 @@ const hasChildren = computed(() => {
|
||||
</el-menu-item>
|
||||
</a>
|
||||
</router-link>
|
||||
<el-sub-menu v-else :title="item.meta?.title ?? '[ 无标题 ]'" :index="settingsStore.app.routeBaseOn !== 'filesystem' ? resolveRoutePath(basePath, item.path || '') : JSON.stringify(item)">
|
||||
<el-sub-menu v-else :title="item.meta?.title ?? '[ 无标题 ]'" :index="settingsStore.app.routeBaseOn !== 'filesystem' ? resolveRoutePath(basePath, item.path) : JSON.stringify(item)">
|
||||
<template #title>
|
||||
<el-icon v-if="item.meta?.icon" class="title-icon">
|
||||
<svg-icon :name="item.meta.icon" />
|
||||
@@ -51,7 +51,7 @@ const hasChildren = computed(() => {
|
||||
<span class="title">{{ item.meta?.title ?? '[ 无标题 ]' }}</span>
|
||||
</template>
|
||||
<template v-for="route in item.children">
|
||||
<SidebarItem v-if="route.meta?.sidebar !== false" :key="route.path" :item="route" :base-path="resolveRoutePath(basePath, item.path || '')" />
|
||||
<SidebarItem v-if="route.meta?.sidebar !== false" :key="route.path" :item="route" :base-path="resolveRoutePath(basePath, item.path)" />
|
||||
</template>
|
||||
</el-sub-menu>
|
||||
</div>
|
||||
|
||||
@@ -37,7 +37,7 @@ function userCommand(command: 'home' | 'setting' | 'hotkeys' | 'logout') {
|
||||
}
|
||||
}
|
||||
function pro() {
|
||||
window.open('https://hooray.gitee.io/fantastic-admin-pro-example/', 'top')
|
||||
window.open('https://hooray.gitee.io/fantastic-admin-pro-example/', '_blank')
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
<script lang="ts" setup name="LinkView">
|
||||
const route = useRoute()
|
||||
|
||||
function open() {
|
||||
window.open(route.meta.link, '_blank')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="link-view">
|
||||
<transition name="link" mode="out-in" appear>
|
||||
<page-main :key="route.meta.link" title="⚠️访问提醒">
|
||||
<div class="container">
|
||||
<div class="title">
|
||||
是否访问此链接
|
||||
</div>
|
||||
<div class="link">
|
||||
{{ route.meta.link }}
|
||||
</div>
|
||||
<el-button type="primary" plain round @click="open">
|
||||
<template #icon>
|
||||
<el-icon>
|
||||
<svg-icon name="ep:link" />
|
||||
</el-icon>
|
||||
</template>
|
||||
立即访问
|
||||
</el-button>
|
||||
</div>
|
||||
</page-main>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.link-view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.page-main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
margin: 0 50px;
|
||||
|
||||
.title {
|
||||
margin: 10px 0;
|
||||
font-size: 22px;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
|
||||
.link {
|
||||
margin: 10px 0;
|
||||
max-width: 300px;
|
||||
font-size: 14px;
|
||||
color: var(--el-text-color-disabled);
|
||||
|
||||
@include text-overflow(3);
|
||||
}
|
||||
|
||||
.el-button {
|
||||
margin: 20px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// link 区动画
|
||||
.link-enter-active {
|
||||
transition: 0.2s;
|
||||
}
|
||||
|
||||
.link-leave-active {
|
||||
transition: 0.15s;
|
||||
}
|
||||
|
||||
.link-enter-from {
|
||||
opacity: 0;
|
||||
transform: translateX(-20px);
|
||||
}
|
||||
|
||||
.link-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(20px);
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts" setup name="Layout">
|
||||
import hotkeys from 'hotkeys-js'
|
||||
import LinkView from './components/views/link.vue'
|
||||
import Header from './components/Header/index.vue'
|
||||
import MainSidebar from './components/MainSidebar/index.vue'
|
||||
import SubSidebar from './components/SubSidebar/index.vue'
|
||||
@@ -18,6 +19,8 @@ const settingsStore = useSettingsStore()
|
||||
const keepAliveStore = useKeepAliveStore()
|
||||
const menuStore = useMenuStore()
|
||||
|
||||
const isLink = computed(() => !!routeInfo.meta.link)
|
||||
|
||||
watch(() => settingsStore.menu.subMenuCollapse, (val) => {
|
||||
if (settingsStore.mode === 'mobile') {
|
||||
if (!val) {
|
||||
@@ -73,10 +76,11 @@ onUnmounted(() => {
|
||||
<router-view v-slot="{ Component, route }">
|
||||
<transition name="main" mode="out-in" appear>
|
||||
<keep-alive :include="keepAliveStore.list">
|
||||
<component :is="Component" :key="route.fullPath" />
|
||||
<component :is="Component" v-show="!isLink" :key="route.fullPath" />
|
||||
</keep-alive>
|
||||
</transition>
|
||||
</router-view>
|
||||
<LinkView v-if="isLink" />
|
||||
</div>
|
||||
<Copyright />
|
||||
</div>
|
||||
|
||||
@@ -5,46 +5,56 @@ const Layout = () => import('@/layouts/index.vue')
|
||||
const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
path: '/official',
|
||||
redirect: '/official/fantastic-startkit',
|
||||
meta: {
|
||||
title: '官方周边',
|
||||
icon: 'ep:grid',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'https://hooray.gitee.io/fantastic-startkit/',
|
||||
path: 'fantastic-startkit',
|
||||
redirect: '',
|
||||
name: 'officialFantasticStartkit',
|
||||
meta: {
|
||||
title: 'Fantastic-startkit 项目启动套件',
|
||||
link: 'https://hooray.gitee.io/fantastic-startkit/',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'https://hooray.gitee.io/one-step-admin/',
|
||||
path: 'one-step-admin',
|
||||
redirect: '',
|
||||
name: 'officialOneStepAdmin',
|
||||
meta: {
|
||||
title: 'One-step-admin 干啥都快人一步的中后台框架',
|
||||
link: 'https://hooray.gitee.io/one-step-admin/',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/cooperation',
|
||||
redirect: '/cooperation/vform',
|
||||
meta: {
|
||||
title: '战略合作',
|
||||
icon: 'sidebar-cooperation',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'https://www.vform666.com',
|
||||
path: 'vform',
|
||||
redirect: '',
|
||||
name: 'cooperationVform',
|
||||
meta: {
|
||||
title: 'VForm 低代码表单',
|
||||
link: 'https://www.vform666.com',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'https://gitee.com/sciqtw/quickadmin',
|
||||
path: 'quickadmin',
|
||||
redirect: '',
|
||||
name: 'cooperationQuickadmin',
|
||||
meta: {
|
||||
title: 'QuickAdmin 快速开发管理框架',
|
||||
link: 'https://gitee.com/sciqtw/quickadmin',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -5,6 +5,7 @@ const Layout = () => import('@/layouts/index.vue')
|
||||
const routes: RouteRecordRaw = {
|
||||
path: '/link',
|
||||
component: Layout,
|
||||
redirect: '/link/gitee',
|
||||
name: 'externalLinkExample',
|
||||
meta: {
|
||||
title: '外链',
|
||||
@@ -12,17 +13,21 @@ const routes: RouteRecordRaw = {
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'https://gitee.com/hooray/fantastic-admin',
|
||||
path: 'gitee',
|
||||
redirect: '',
|
||||
name: 'externalLinkGitee',
|
||||
meta: {
|
||||
title: 'Gitee 仓库',
|
||||
link: 'https://gitee.com/hooray/fantastic-admin',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'https://github.com/hooray/fantastic-admin',
|
||||
path: 'github',
|
||||
redirect: '',
|
||||
name: 'externalLinkGithub',
|
||||
meta: {
|
||||
title: 'Github 仓库',
|
||||
link: 'https://github.com/hooray/fantastic-admin',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -10,24 +10,18 @@ import menu from '@/menu'
|
||||
|
||||
function getDeepestPath(menu: Menu.recordRaw, rootPath = '') {
|
||||
let retnPath = ''
|
||||
if (menu.path !== undefined) {
|
||||
if (menu.children) {
|
||||
if (menu.children.some(item => item.meta?.sidebar !== false)) {
|
||||
for (let i = 0; i < menu.children.length; i++) {
|
||||
if (menu.children[i].meta?.sidebar !== false) {
|
||||
retnPath = getDeepestPath(menu.children[i], resolveRoutePath(rootPath, menu.path))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
retnPath = getDeepestPath(menu.children[0], resolveRoutePath(rootPath, menu.path))
|
||||
}
|
||||
if (menu.children) {
|
||||
const item = menu.children.find(item => item.meta?.sidebar !== false)
|
||||
if (item) {
|
||||
retnPath = getDeepestPath(item, resolveRoutePath(rootPath, menu.path))
|
||||
}
|
||||
else {
|
||||
retnPath = resolveRoutePath(rootPath, menu.path)
|
||||
retnPath = getDeepestPath(menu.children[0], resolveRoutePath(rootPath, menu.path))
|
||||
}
|
||||
}
|
||||
else {
|
||||
retnPath = resolveRoutePath(rootPath, menu.path)
|
||||
}
|
||||
return retnPath
|
||||
}
|
||||
|
||||
@@ -68,7 +62,7 @@ function filterAsyncMenus<T extends Menu.recordMainRaw[] | Menu.recordRaw[]>(men
|
||||
function getDefaultOpenedPaths(menus: Menu.recordRaw[], rootPath = '') {
|
||||
const defaultOpenedPaths: string[] = []
|
||||
menus.forEach((item) => {
|
||||
if (item.path && item.meta?.defaultOpened && item.children) {
|
||||
if (item.meta?.defaultOpened && item.children) {
|
||||
defaultOpenedPaths.push(resolveRoutePath(rootPath, item.path))
|
||||
const childrenDefaultOpenedPaths = getDefaultOpenedPaths(item.children, resolveRoutePath(rootPath, item.path))
|
||||
if (childrenDefaultOpenedPaths.length > 0) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import router from '@/router'
|
||||
import useSettingsStore from '@/store/modules/settings'
|
||||
import useMenuStore from '@/store/modules/menu'
|
||||
import { isExternalLink } from '@/utils'
|
||||
|
||||
export default function useMenu() {
|
||||
const settingsStore = useSettingsStore()
|
||||
@@ -10,12 +9,7 @@ export default function useMenu() {
|
||||
function switchTo(index: number | string) {
|
||||
menuStore.setActived(index)
|
||||
if (settingsStore.menu.switchMainMenuAndPageJump) {
|
||||
if (isExternalLink(menuStore.sidebarMenusFirstDeepestPath)) {
|
||||
window.open(menuStore.sidebarMenusFirstDeepestPath, '_blank')
|
||||
}
|
||||
else {
|
||||
void router.push(menuStore.sidebarMenusFirstDeepestPath)
|
||||
}
|
||||
void router.push(menuStore.sidebarMenusFirstDeepestPath)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-12
@@ -1,15 +1,5 @@
|
||||
import path from 'path-browserify'
|
||||
|
||||
export function isExternalLink(path: string) {
|
||||
return /^(https?:|mailto:|tel:)/.test(path)
|
||||
}
|
||||
|
||||
export function resolveRoutePath(basePath: string, routePath: string) {
|
||||
if (isExternalLink(routePath)) {
|
||||
return routePath
|
||||
}
|
||||
if (isExternalLink(basePath)) {
|
||||
return basePath
|
||||
}
|
||||
return basePath ? path.resolve(basePath, routePath) : routePath
|
||||
export function resolveRoutePath(basePath: string, routePath?: string) {
|
||||
return basePath ? path.resolve(basePath, routePath ?? '') : routePath ?? ''
|
||||
}
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ meta:
|
||||
|
||||
<script lang="ts" setup>
|
||||
function open(url: string) {
|
||||
window.open(url, 'top')
|
||||
window.open(url, '_blank')
|
||||
}
|
||||
|
||||
const fantasticStartkitInfo = ref({
|
||||
|
||||
@@ -19,7 +19,7 @@ function getPermission() {
|
||||
}
|
||||
|
||||
function open(url: string) {
|
||||
window.open(url, 'top')
|
||||
window.open(url, '_blank')
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user