mirror of
https://github.com/chansee97/nova-admin.git
synced 2025-05-20 15:39:17 +08:00
feat(preoject): 增加页面缓存支持,外链菜单支持
This commit is contained in:
parent
d0d6a59491
commit
af8ceb0843
@ -183,6 +183,7 @@ const userRoutes = [
|
|||||||
title: '地图',
|
title: '地图',
|
||||||
requiresAuth: true,
|
requiresAuth: true,
|
||||||
icon: 'carbon:map',
|
icon: 'carbon:map',
|
||||||
|
keepAlive: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -271,6 +272,16 @@ const userRoutes = [
|
|||||||
icon: 'logos:vitejs',
|
icon: 'logos:vitejs',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'docments_vueuse',
|
||||||
|
path: '/docments/vueuse',
|
||||||
|
meta: {
|
||||||
|
title: 'VueUse(外链)',
|
||||||
|
requiresAuth: true,
|
||||||
|
icon: 'logos:vueuse',
|
||||||
|
herf: 'https://vueuse.org/guide/',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useAppRouter } from '@/hook';
|
import { useAppRouter } from '@/hooks';
|
||||||
|
|
||||||
type TipType = '403' | '404' | '500';
|
type TipType = '403' | '404' | '500';
|
||||||
defineProps<{
|
defineProps<{
|
||||||
|
@ -52,9 +52,11 @@
|
|||||||
'p-t-77px': appStore.fixedHeader && !appStore.showTabs,
|
'p-t-77px': appStore.fixedHeader && !appStore.showTabs,
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<router-view v-slot="{ Component }">
|
<router-view v-slot="{ Component, route }">
|
||||||
<transition name="fade-slide" appear mode="out-in">
|
<transition name="fade-slide" mode="out-in">
|
||||||
<component :is="Component" v-if="appStore.loadFlag" />
|
<keep-alive :include="routeStore.cacheRoutes">
|
||||||
|
<component :is="Component" v-if="appStore.loadFlag" :key="route.fullPath" />
|
||||||
|
</keep-alive>
|
||||||
</transition>
|
</transition>
|
||||||
</router-view>
|
</router-view>
|
||||||
</div>
|
</div>
|
||||||
@ -68,7 +70,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useAppStore } from '@/store';
|
|
||||||
import {
|
import {
|
||||||
Breadcrumb,
|
Breadcrumb,
|
||||||
CollapaseButton,
|
CollapaseButton,
|
||||||
@ -85,7 +86,9 @@ import {
|
|||||||
TabBar,
|
TabBar,
|
||||||
BackTop,
|
BackTop,
|
||||||
} from '../components';
|
} from '../components';
|
||||||
|
import { useAppStore, useRouteStore } from '@/store';
|
||||||
|
|
||||||
|
const routeStore = useRouteStore();
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { useRouteStore } from '@/store';
|
import { useRouteStore } from '@/store';
|
||||||
import { useAppRouter } from '@/hook';
|
import { useAppRouter } from '@/hooks';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const routeStore = useRouteStore();
|
const routeStore = useRouteStore();
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useAppStore } from '@/store';
|
import { useAppStore } from '@/store';
|
||||||
import { useAppRouter } from '@/hook';
|
import { useAppRouter } from '@/hooks';
|
||||||
const { toRoot } = useAppRouter();
|
const { toRoot } = useAppRouter();
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
</script>
|
</script>
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useAppStore } from '@/store';
|
import { useAppStore } from '@/store';
|
||||||
import { useAppRouter } from '@/hook';
|
import { useAppRouter } from '@/hooks';
|
||||||
import { useRouteStore } from '~/src/store/modules/route';
|
import { useRouteStore } from '~/src/store/modules/route';
|
||||||
import type { MenuOption } from 'naive-ui';
|
import type { MenuOption } from 'naive-ui';
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useTabStore, useAppStore } from '@/store';
|
import { useTabStore, useAppStore } from '@/store';
|
||||||
import { useAppRouter } from '~/src/hook';
|
import { useAppRouter } from '@/hooks';
|
||||||
import { RouteLocationNormalized } from 'vue-router';
|
import { RouteLocationNormalized } from 'vue-router';
|
||||||
import { ref, nextTick } from 'vue';
|
import { ref, nextTick } from 'vue';
|
||||||
import { renderIcon } from '@/utils';
|
import { renderIcon } from '@/utils';
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { RouteRecordRaw } from 'vue-router';
|
import { RouteRecordRaw } from 'vue-router';
|
||||||
import { BasicLayout } from '@/layouts/index';
|
import { BasicLayout } from '@/layouts/index';
|
||||||
|
import { useRouteStore } from '@/store';
|
||||||
|
|
||||||
// 引入所有页面
|
// 引入所有页面
|
||||||
const modules = import.meta.glob('../../views/**/*.vue');
|
const modules = import.meta.glob('../../views/**/*.vue');
|
||||||
@ -20,9 +21,20 @@ function FlatAuthRoutes(routes: AppRoute.Route[]) {
|
|||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createCatheRoutes(routes: AppRoute.Route[]) {
|
||||||
|
return routes
|
||||||
|
.filter((item) => {
|
||||||
|
return item.meta.keepAlive;
|
||||||
|
})
|
||||||
|
.map((item) => item.name);
|
||||||
|
}
|
||||||
export async function createDynamicRoutes(routes: AppRoute.Route[]) {
|
export async function createDynamicRoutes(routes: AppRoute.Route[]) {
|
||||||
// 数组降维成一维数组,然后删除所有的childen
|
// 数组降维成一维数组,然后删除所有的childen
|
||||||
const flatRoutes = FlatAuthRoutes(routes);
|
const flatRoutes = FlatAuthRoutes(routes);
|
||||||
|
// 对降维后的数组过滤需要缓存的路由name数组
|
||||||
|
const routeStore = useRouteStore();
|
||||||
|
routeStore.cacheRoutes = createCatheRoutes(flatRoutes);
|
||||||
// 生成路由,有redirect的不需要引入文件
|
// 生成路由,有redirect的不需要引入文件
|
||||||
const mapRoutes = flatRoutes.map((item) => {
|
const mapRoutes = flatRoutes.map((item) => {
|
||||||
if (!item.redirect) {
|
if (!item.redirect) {
|
||||||
|
@ -6,6 +6,11 @@ const appTitle = import.meta.env.VITE_APP_TITLE;
|
|||||||
|
|
||||||
export function setupRouterGuard(router: Router) {
|
export function setupRouterGuard(router: Router) {
|
||||||
router.beforeEach(async (to, from, next) => {
|
router.beforeEach(async (to, from, next) => {
|
||||||
|
// 判断是否是外链,如果是直接打开网页并拦截跳转
|
||||||
|
if (to.meta.herf) {
|
||||||
|
window.open(to.meta.herf);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// 开始 loadingBar
|
// 开始 loadingBar
|
||||||
window.$loadingBar?.start();
|
window.$loadingBar?.start();
|
||||||
// 权限操作
|
// 权限操作
|
||||||
|
@ -40,7 +40,6 @@ export async function createPermissionGuard(
|
|||||||
// if (to.name === 'not-found-page') {
|
// if (to.name === 'not-found-page') {
|
||||||
// next({ name: 'not-found-page', replace: true });
|
// next({ name: 'not-found-page', replace: true });
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// 设置菜单高亮
|
// 设置菜单高亮
|
||||||
if (to.meta.activeMenu) {
|
if (to.meta.activeMenu) {
|
||||||
routeStore.setActiveMenu(to.meta.activeMenu);
|
routeStore.setActiveMenu(to.meta.activeMenu);
|
||||||
|
@ -2,7 +2,7 @@ import { defineStore } from 'pinia';
|
|||||||
import { fetchLogin, fetchUserInfo } from '@/service';
|
import { fetchLogin, fetchUserInfo } from '@/service';
|
||||||
import { setUserInfo, getUserInfo, getToken, setToken, clearAuthStorage } from '@/utils/auth';
|
import { setUserInfo, getUserInfo, getToken, setToken, clearAuthStorage } from '@/utils/auth';
|
||||||
import { router } from '@/router';
|
import { router } from '@/router';
|
||||||
import { useAppRouter } from '@/hook';
|
import { useAppRouter } from '@/hooks';
|
||||||
import { unref } from 'vue';
|
import { unref } from 'vue';
|
||||||
import { useRouteStore } from './route';
|
import { useRouteStore } from './route';
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ interface RoutesStatus {
|
|||||||
userRoutes: AppRoute.Route[];
|
userRoutes: AppRoute.Route[];
|
||||||
activeMenu: string | null;
|
activeMenu: string | null;
|
||||||
authRouteMode: ImportMetaEnv['VITE_AUTH_ROUTE_MODE'];
|
authRouteMode: ImportMetaEnv['VITE_AUTH_ROUTE_MODE'];
|
||||||
|
cacheRoutes: string[];
|
||||||
}
|
}
|
||||||
export const useRouteStore = defineStore('route-store', {
|
export const useRouteStore = defineStore('route-store', {
|
||||||
state: (): RoutesStatus => {
|
state: (): RoutesStatus => {
|
||||||
@ -21,6 +22,7 @@ export const useRouteStore = defineStore('route-store', {
|
|||||||
menus: [],
|
menus: [],
|
||||||
activeMenu: null,
|
activeMenu: null,
|
||||||
authRouteMode: import.meta.env.VITE_AUTH_ROUTE_MODE,
|
authRouteMode: import.meta.env.VITE_AUTH_ROUTE_MODE,
|
||||||
|
cacheRoutes: [],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
@ -81,7 +83,7 @@ export const useRouteStore = defineStore('route-store', {
|
|||||||
const { data } = await fetchUserRoutes(userId);
|
const { data } = await fetchUserRoutes(userId);
|
||||||
// 根据用户返回的路由表来生成真实路由
|
// 根据用户返回的路由表来生成真实路由
|
||||||
const appRoutes = await createDynamicRoutes(data);
|
const appRoutes = await createDynamicRoutes(data);
|
||||||
// 更具返回的生成侧边菜单
|
// 生成侧边菜单
|
||||||
await this.createMenus(data);
|
await this.createMenus(data);
|
||||||
// 插入路由表
|
// 插入路由表
|
||||||
router.addRoute(appRoutes);
|
router.addRoute(appRoutes);
|
||||||
@ -90,7 +92,7 @@ export const useRouteStore = defineStore('route-store', {
|
|||||||
async initStaticRoute() {
|
async initStaticRoute() {
|
||||||
// 根据静态路由表来生成真实路由
|
// 根据静态路由表来生成真实路由
|
||||||
const appRoutes = await createDynamicRoutes(staticRoutes);
|
const appRoutes = await createDynamicRoutes(staticRoutes);
|
||||||
// 更具返回的生成侧边菜单
|
// 生成侧边菜单
|
||||||
await this.createMenus(staticRoutes);
|
await this.createMenus(staticRoutes);
|
||||||
// 插入路由表
|
// 插入路由表
|
||||||
router.addRoute(appRoutes);
|
router.addRoute(appRoutes);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { RouteLocationNormalized } from 'vue-router';
|
import { RouteLocationNormalized } from 'vue-router';
|
||||||
import { useAppRouter } from '@/hook';
|
import { useAppRouter } from '@/hooks';
|
||||||
|
|
||||||
interface TabState {
|
interface TabState {
|
||||||
inherentTab: {
|
inherentTab: {
|
||||||
|
8
src/typings/route.d.ts
vendored
8
src/typings/route.d.ts
vendored
@ -7,14 +7,6 @@ declare namespace AppRoute {
|
|||||||
path: string;
|
path: string;
|
||||||
/** 路由重定向 */
|
/** 路由重定向 */
|
||||||
redirect?: string;
|
redirect?: string;
|
||||||
/**
|
|
||||||
* 路由组件
|
|
||||||
* - basic: 基础布局,具有公共部分的布局
|
|
||||||
* - blank: 空白布局
|
|
||||||
* - multi: 多级路由布局(三级路由或三级以上时,除第一级路由和最后一级路由,其余的采用该布局)
|
|
||||||
* - self: 作为子路由,使用自身的布局(作为最后一级路由,没有子路由)
|
|
||||||
*/
|
|
||||||
component?: any;
|
|
||||||
/** 子路由 */
|
/** 子路由 */
|
||||||
children?: Route[];
|
children?: Route[];
|
||||||
/** 路由描述 */
|
/** 路由描述 */
|
||||||
|
@ -59,7 +59,7 @@ import { onMounted, ref, h } from 'vue';
|
|||||||
import { fetchUserList } from '@/service';
|
import { fetchUserList } from '@/service';
|
||||||
import type { DataTableColumns } from 'naive-ui';
|
import type { DataTableColumns } from 'naive-ui';
|
||||||
import { NButton, NPopconfirm, NSpace, NSwitch, NTag, FormInst } from 'naive-ui';
|
import { NButton, NPopconfirm, NSpace, NSwitch, NTag, FormInst } from 'naive-ui';
|
||||||
import { useLoading, useBoolean } from '@/hook';
|
import { useLoading, useBoolean } from '@/hooks';
|
||||||
import TableModal from './components/TableModal.vue';
|
import TableModal from './components/TableModal.vue';
|
||||||
|
|
||||||
const { loading, startLoading, endLoading } = useLoading(false);
|
const { loading, startLoading, endLoading } = useLoading(false);
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import type { Ref } from 'vue';
|
import type { Ref } from 'vue';
|
||||||
import { type ECOption, useEcharts } from '@/hook';
|
import { type ECOption, useEcharts } from '@/hooks';
|
||||||
|
|
||||||
const pieOptions = ref<ECOption>({
|
const pieOptions = ref<ECOption>({
|
||||||
title: {
|
title: {
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { useClipBoard } from '@/hook';
|
import { useClipBoard } from '@/hooks';
|
||||||
|
|
||||||
const { copy } = useClipBoard();
|
const { copy } = useClipBoard();
|
||||||
const text = ref('Hello Clipboard');
|
const text = ref('Hello Clipboard');
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<n-card title="地图示例">
|
<n-card title="地图示例(keepalive缓存)">
|
||||||
<n-tabs type="line" animated>
|
<n-tabs type="line" animated>
|
||||||
<n-tab-pane v-for="item in maps" :key="item.id" :name="item.id" :tab="item.label" class="h-600px">
|
<n-tab-pane v-for="item in maps" :key="item.id" :name="item.id" :tab="item.label" class="h-600px">
|
||||||
<component :is="item.component" />
|
<component :is="item.component" />
|
||||||
@ -7,7 +7,11 @@
|
|||||||
</n-tabs>
|
</n-tabs>
|
||||||
</n-card>
|
</n-card>
|
||||||
</template>
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'PluginMap', //此处的组件命需要和路由的name保持一致
|
||||||
|
};
|
||||||
|
</script>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import AMap from './components/AMap.vue';
|
import AMap from './components/AMap.vue';
|
||||||
import BMap from './components/BMap.vue';
|
import BMap from './components/BMap.vue';
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useAppRouter } from '@/hook';
|
import { useAppRouter } from '@/hooks';
|
||||||
const { routerPush } = useAppRouter();
|
const { routerPush } = useAppRouter();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user