mirror of
				https://github.com/soybeanjs/soybean-admin.git
				synced 2025-11-04 15:53:43 +08:00 
			
		
		
		
	refactor(projects): 路由声明重构,添加composables,BaseLayout进行中,文件夹规范
This commit is contained in:
		
							
								
								
									
										1
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							@@ -62,6 +62,7 @@
 | 
			
		||||
	"material-icon-theme.folders.associations": {
 | 
			
		||||
		"enum": "typescript",
 | 
			
		||||
		"store": "context",
 | 
			
		||||
		"composables": "hook",
 | 
			
		||||
		"business": "core",
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								src/composables/common/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/composables/common/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
export * from './route';
 | 
			
		||||
export * from './router';
 | 
			
		||||
export * from './system';
 | 
			
		||||
export * from './layout';
 | 
			
		||||
							
								
								
									
										49
									
								
								src/composables/common/layout.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/composables/common/layout.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
import { computed } from 'vue';
 | 
			
		||||
import { useThemeStore, useAppStore } from '@/store';
 | 
			
		||||
 | 
			
		||||
export function useLayoutConfig() {
 | 
			
		||||
  const theme = useThemeStore();
 | 
			
		||||
  const app = useAppStore();
 | 
			
		||||
 | 
			
		||||
  /** 反转sider */
 | 
			
		||||
  const siderInverted = computed(() => theme.navStyle.theme !== 'light');
 | 
			
		||||
 | 
			
		||||
  /** 侧边菜单宽度 */
 | 
			
		||||
  const siderMenuWidth = computed(() => {
 | 
			
		||||
    const { collapsed } = app.menu;
 | 
			
		||||
    const { collapsedWidth, width } = theme.menuStyle;
 | 
			
		||||
    return collapsed ? collapsedWidth : width;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  /** 反转header */
 | 
			
		||||
  const headerInverted = computed(() => (theme.navStyle.theme !== 'dark' ? siderInverted.value : !siderInverted.value));
 | 
			
		||||
 | 
			
		||||
  /** 头部定位 */
 | 
			
		||||
  const headerPosition = computed(() => (theme.fixedHeaderAndTab ? 'absolute' : 'static'));
 | 
			
		||||
 | 
			
		||||
  /** 全局头部的高度(px) */
 | 
			
		||||
  const headerHeight = computed(() => `${theme.headerStyle.height}px`);
 | 
			
		||||
 | 
			
		||||
  /** 多页签Tab的高度(px) */
 | 
			
		||||
  const multiTabHeight = computed(() => `${theme.multiTabStyle.height}px`);
 | 
			
		||||
 | 
			
		||||
  /** 全局头部和多页签的总高度 */
 | 
			
		||||
  const headerAndMultiTabHeight = computed(() => {
 | 
			
		||||
    const {
 | 
			
		||||
      multiTabStyle: { visible, height: tH },
 | 
			
		||||
      headerStyle: { height: hH }
 | 
			
		||||
    } = theme;
 | 
			
		||||
    const height = visible ? tH + hH : hH;
 | 
			
		||||
    return `${height}px`;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    siderInverted,
 | 
			
		||||
    siderMenuWidth,
 | 
			
		||||
    headerInverted,
 | 
			
		||||
    headerPosition,
 | 
			
		||||
    headerHeight,
 | 
			
		||||
    multiTabHeight,
 | 
			
		||||
    headerAndMultiTabHeight
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										63
									
								
								src/composables/common/route.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/composables/common/route.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
			
		||||
import { computed, watch } from 'vue';
 | 
			
		||||
import { useRoute } from 'vue-router';
 | 
			
		||||
import { routeName } from '@/router';
 | 
			
		||||
import type { RouteKey } from '@/interface';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 路由属性
 | 
			
		||||
 * @description - 必须要在setup里面调用
 | 
			
		||||
 */
 | 
			
		||||
export function useRouteProps() {
 | 
			
		||||
  const route = useRoute();
 | 
			
		||||
  const props = computed(() => {
 | 
			
		||||
    /** 路由名称 */
 | 
			
		||||
    const name = route.name as string;
 | 
			
		||||
    /** 缓存页面 */
 | 
			
		||||
    const keepAlive = Boolean(route.meta?.keepAlive);
 | 
			
		||||
    /** 视高100% */
 | 
			
		||||
    const fullPage = Boolean(route.meta?.fullPage);
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      name,
 | 
			
		||||
      keepAlive,
 | 
			
		||||
      fullPage
 | 
			
		||||
    };
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return props;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 路由查询参数
 | 
			
		||||
 * @description - 必须要在setup里面调用
 | 
			
		||||
 */
 | 
			
		||||
export function useRouteQuery() {
 | 
			
		||||
  const route = useRoute();
 | 
			
		||||
 | 
			
		||||
  /** 登录跳转链接 */
 | 
			
		||||
  const loginRedirectUrl = computed(() => {
 | 
			
		||||
    let url: string | undefined;
 | 
			
		||||
    if (route.name === routeName('login')) {
 | 
			
		||||
      url = (route.query?.redirectUrl as string) || '';
 | 
			
		||||
    }
 | 
			
		||||
    return url;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    loginRedirectUrl
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 路由名称变化后的回调
 | 
			
		||||
 * @param callback
 | 
			
		||||
 */
 | 
			
		||||
export function routeNameWatcher(callback: (name: RouteKey) => void) {
 | 
			
		||||
  const route = useRoute();
 | 
			
		||||
  watch(
 | 
			
		||||
    () => route.name,
 | 
			
		||||
    newValue => {
 | 
			
		||||
      callback(newValue as RouteKey);
 | 
			
		||||
    }
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
@@ -1,20 +1,13 @@
 | 
			
		||||
import { useRouter, useRoute } from 'vue-router';
 | 
			
		||||
import type { RouteLocationRaw } from 'vue-router';
 | 
			
		||||
import { EnumRoutePath } from '@/enum';
 | 
			
		||||
import { router as globalRouter } from '@/router';
 | 
			
		||||
import { router as globalRouter, routePath } from '@/router';
 | 
			
		||||
import type { LoginModuleType } from '@/interface';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 重定向地址
 | 
			
		||||
 * - current: 取当前的path作为重定向地址
 | 
			
		||||
 */
 | 
			
		||||
type LoginRedirect = 'current' | EnumRoutePath;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 路由跳转
 | 
			
		||||
 * @param inSetup - 是否在vue页面/组件的setup里面调用
 | 
			
		||||
 */
 | 
			
		||||
export default function useRouterChange(inSetup: boolean = true) {
 | 
			
		||||
export function useRouterPush(inSetup: boolean = true) {
 | 
			
		||||
  const router = inSetup ? useRouter() : globalRouter;
 | 
			
		||||
  const route = inSetup ? useRoute() : null;
 | 
			
		||||
 | 
			
		||||
@@ -23,6 +16,11 @@ export default function useRouterChange(inSetup: boolean = true) {
 | 
			
		||||
    router.push('/');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 重定向地址
 | 
			
		||||
   * - current: 取当前的path作为重定向地址
 | 
			
		||||
   */
 | 
			
		||||
  type LoginRedirect = 'current' | string;
 | 
			
		||||
  /**
 | 
			
		||||
   * 跳转登录页面(通过vue路由)
 | 
			
		||||
   * @param module - 展示的登录模块
 | 
			
		||||
@@ -30,13 +28,13 @@ export default function useRouterChange(inSetup: boolean = true) {
 | 
			
		||||
   */
 | 
			
		||||
  function toLogin(module: LoginModuleType = 'pwd-login', redirectUrl: LoginRedirect = 'current') {
 | 
			
		||||
    const routeLocation: RouteLocationRaw = {
 | 
			
		||||
      path: EnumRoutePath.login,
 | 
			
		||||
      path: routePath('login'),
 | 
			
		||||
      query: { module }
 | 
			
		||||
    };
 | 
			
		||||
    if (redirectUrl) {
 | 
			
		||||
      let url = redirectUrl;
 | 
			
		||||
      if (redirectUrl === 'current') {
 | 
			
		||||
        url = router.currentRoute.value.fullPath as EnumRoutePath;
 | 
			
		||||
        url = router.currentRoute.value.fullPath;
 | 
			
		||||
      }
 | 
			
		||||
      routeLocation.query!.redirectUrl = url;
 | 
			
		||||
    }
 | 
			
		||||
@@ -51,12 +49,12 @@ export default function useRouterChange(inSetup: boolean = true) {
 | 
			
		||||
  function toCurrentLogin(module: LoginModuleType) {
 | 
			
		||||
    if (route) {
 | 
			
		||||
      const { query } = route;
 | 
			
		||||
      router.push({ path: EnumRoutePath.login, query: { ...query, module } });
 | 
			
		||||
      router.push({ path: routePath('login'), query: { ...query, module } });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** 登录后跳转重定向的地址 */
 | 
			
		||||
  function toLoginRedirectUrl(path: EnumRoutePath) {
 | 
			
		||||
  function toLoginRedirectUrl(path: string) {
 | 
			
		||||
    router.push(path);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -1,11 +1,13 @@
 | 
			
		||||
import { useBreakpoints, breakpointsTailwind } from '@vueuse/core';
 | 
			
		||||
 | 
			
		||||
/** 项目名称 */
 | 
			
		||||
export function useAppTitle() {
 | 
			
		||||
  return import.meta.env.VITE_APP_TITLE as string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 是否是移动端 */
 | 
			
		||||
export default function useIsMobile() {
 | 
			
		||||
export function useIsMobile() {
 | 
			
		||||
  const breakpoints = useBreakpoints(breakpointsTailwind);
 | 
			
		||||
  const isMobile = breakpoints.smaller('lg');
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    isMobile
 | 
			
		||||
  };
 | 
			
		||||
  return isMobile;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								src/composables/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/composables/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
export * from './common';
 | 
			
		||||
							
								
								
									
										5
									
								
								src/enum/common/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/enum/common/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
export * from './system';
 | 
			
		||||
export * from './theme';
 | 
			
		||||
export * from './animate';
 | 
			
		||||
export * from './typeof';
 | 
			
		||||
export * from './storage';
 | 
			
		||||
@@ -5,21 +5,6 @@ export enum ContentType {
 | 
			
		||||
  formData = 'multipart/form-data'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 数据类型 */
 | 
			
		||||
export enum EnumDataType {
 | 
			
		||||
  number = '[object Number]',
 | 
			
		||||
  string = '[object String]',
 | 
			
		||||
  boolean = '[object Boolean]',
 | 
			
		||||
  null = '[object Null]',
 | 
			
		||||
  undefined = '[object Undefined]',
 | 
			
		||||
  object = '[object Object]',
 | 
			
		||||
  array = '[object Array]',
 | 
			
		||||
  date = '[object Date]',
 | 
			
		||||
  regexp = '[object RegExp]',
 | 
			
		||||
  set = '[object Set]',
 | 
			
		||||
  map = '[object Map]'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 登录模块 */
 | 
			
		||||
export enum EnumLoginModule {
 | 
			
		||||
  'pwd-login' = '账密登录',
 | 
			
		||||
							
								
								
									
										14
									
								
								src/enum/common/typeof.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/enum/common/typeof.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
/** 数据类型 */
 | 
			
		||||
export enum EnumDataType {
 | 
			
		||||
  number = '[object Number]',
 | 
			
		||||
  string = '[object String]',
 | 
			
		||||
  boolean = '[object Boolean]',
 | 
			
		||||
  null = '[object Null]',
 | 
			
		||||
  undefined = '[object Undefined]',
 | 
			
		||||
  object = '[object Object]',
 | 
			
		||||
  array = '[object Array]',
 | 
			
		||||
  date = '[object Date]',
 | 
			
		||||
  regexp = '[object RegExp]',
 | 
			
		||||
  set = '[object Set]',
 | 
			
		||||
  map = '[object Map]'
 | 
			
		||||
}
 | 
			
		||||
@@ -1,5 +1 @@
 | 
			
		||||
export * from './common';
 | 
			
		||||
export * from './animate';
 | 
			
		||||
export * from './theme';
 | 
			
		||||
export * from './route';
 | 
			
		||||
export * from './storage';
 | 
			
		||||
 
 | 
			
		||||
@@ -1,71 +0,0 @@
 | 
			
		||||
export enum EnumRoutePath {
 | 
			
		||||
  'root' = '/',
 | 
			
		||||
  'login' = '/login',
 | 
			
		||||
  'not-found' = '/404',
 | 
			
		||||
  'no-permission' = '/403',
 | 
			
		||||
  'service-error' = '/500',
 | 
			
		||||
  'reload' = '/reload',
 | 
			
		||||
  // 自定义路由
 | 
			
		||||
  'dashboard' = '/dashboard',
 | 
			
		||||
  'dashboard_analysis' = '/dashboard/analysis',
 | 
			
		||||
  'dashboard_workbench' = '/dashboard/workbench',
 | 
			
		||||
  'document' = '/document',
 | 
			
		||||
  'document_vue' = '/document/vue',
 | 
			
		||||
  'document_vite' = '/document/vite',
 | 
			
		||||
  'document_naive' = '/document/naive',
 | 
			
		||||
  'component' = '/component',
 | 
			
		||||
  'component_map' = '/component/map',
 | 
			
		||||
  'component_video' = '/component/video',
 | 
			
		||||
  'component_editor' = '/component/editor',
 | 
			
		||||
  'component_editor_quill' = '/component/editor/quill',
 | 
			
		||||
  'component_editor_markdown' = '/component/editor/markdown',
 | 
			
		||||
  'component_swiper' = '/component/swiper',
 | 
			
		||||
  'feat' = '/feat',
 | 
			
		||||
  'feat_copy' = '/feat/copy',
 | 
			
		||||
  'feat_icon' = '/feat/icon',
 | 
			
		||||
  'feat_print' = '/feat/print',
 | 
			
		||||
  'multi-menu' = '/multi-menu',
 | 
			
		||||
  'multi-menu_first' = '/multi-menu/first',
 | 
			
		||||
  'multi-menu_first_second' = '/multi-menu/first/second',
 | 
			
		||||
  'exception' = '/exception',
 | 
			
		||||
  'exception_403' = '/exception/403',
 | 
			
		||||
  'exception_404' = '/exception/404',
 | 
			
		||||
  'exception_500' = '/exception/500',
 | 
			
		||||
  'about' = '/about'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export enum EnumRouteTitle {
 | 
			
		||||
  'root' = 'root',
 | 
			
		||||
  'login' = '登录',
 | 
			
		||||
  'not-found' = '未找到',
 | 
			
		||||
  'no-permission' = '无权限',
 | 
			
		||||
  'service-error' = '服务器错误',
 | 
			
		||||
  'reload' = '重载',
 | 
			
		||||
  // 自定义路由
 | 
			
		||||
  'dashboard' = '仪表盘',
 | 
			
		||||
  'dashboard_analysis' = '分析页',
 | 
			
		||||
  'dashboard_workbench' = '工作台',
 | 
			
		||||
  'document' = '文档',
 | 
			
		||||
  'document_vue' = 'vue文档',
 | 
			
		||||
  'document_vite' = 'vite文档',
 | 
			
		||||
  'document_naive' = 'naive文档',
 | 
			
		||||
  'component' = '组件插件',
 | 
			
		||||
  'component_map' = '地图插件',
 | 
			
		||||
  'component_video' = '视频插件',
 | 
			
		||||
  'component_editor' = '编辑器',
 | 
			
		||||
  'component_editor_quill' = '富文本编辑器',
 | 
			
		||||
  'component_editor_markdown' = 'markdown编辑器',
 | 
			
		||||
  'component_swiper' = 'Swiper插件',
 | 
			
		||||
  'feat' = '功能示例',
 | 
			
		||||
  'feat_copy' = '剪贴板',
 | 
			
		||||
  'feat_icon' = '图标',
 | 
			
		||||
  'feat_print' = '打印',
 | 
			
		||||
  'multi-menu' = '多级菜单',
 | 
			
		||||
  'multi-menu_first' = '一级菜单',
 | 
			
		||||
  'multi-menu_first_second' = '二级菜单',
 | 
			
		||||
  'exception' = '异常页',
 | 
			
		||||
  'exception_403' = '异常页-403',
 | 
			
		||||
  'exception_404' = '异常页-404',
 | 
			
		||||
  'exception_500' = '异常页-500',
 | 
			
		||||
  'about' = '关于'
 | 
			
		||||
}
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
import { ref, computed } from 'vue';
 | 
			
		||||
import useBoolean from '../common/useBoolean';
 | 
			
		||||
import { useBoolean } from '../common';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 倒计时
 | 
			
		||||
@@ -9,10 +9,10 @@ export default function useCountDown(second: number) {
 | 
			
		||||
  if (second <= 0 && second % 1 !== 0) {
 | 
			
		||||
    throw Error('倒计时的时间应该为一个正整数!');
 | 
			
		||||
  }
 | 
			
		||||
  const { bool: isComplete, setTrue, setFalse } = useBoolean(false);
 | 
			
		||||
 | 
			
		||||
  const counts = ref(0);
 | 
			
		||||
  const isCounting = computed(() => Boolean(counts.value));
 | 
			
		||||
  // 完成一轮倒计时
 | 
			
		||||
  const { bool: isComplete, setTrue, setFalse } = useBoolean(false);
 | 
			
		||||
 | 
			
		||||
  let intervalId: any;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,23 +1,5 @@
 | 
			
		||||
import useAppTitle from './useAppTitle';
 | 
			
		||||
import useContext from './useContext';
 | 
			
		||||
import useRouterChange from './useRouterChange';
 | 
			
		||||
import useRouteParam from './useRouteParam';
 | 
			
		||||
import useRouteQuery from './useRouteQuery';
 | 
			
		||||
import useRouteProps from './useRouteProps';
 | 
			
		||||
import useBoolean from './useBoolean';
 | 
			
		||||
import useLoading from './useLoading';
 | 
			
		||||
import useScrollBehavior from './useScrollBehavior';
 | 
			
		||||
import useIsMobile from './useIsMobile';
 | 
			
		||||
 | 
			
		||||
export {
 | 
			
		||||
  useAppTitle,
 | 
			
		||||
  useContext,
 | 
			
		||||
  useRouterChange,
 | 
			
		||||
  useRouteParam,
 | 
			
		||||
  useRouteQuery,
 | 
			
		||||
  useRouteProps,
 | 
			
		||||
  useBoolean,
 | 
			
		||||
  useLoading,
 | 
			
		||||
  useScrollBehavior,
 | 
			
		||||
  useIsMobile
 | 
			
		||||
};
 | 
			
		||||
export { useContext, useBoolean, useLoading };
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +0,0 @@
 | 
			
		||||
/** 项目名称 */
 | 
			
		||||
export default function useAppTitle() {
 | 
			
		||||
  const title = import.meta.env.VITE_APP_TITLE as string;
 | 
			
		||||
 | 
			
		||||
  return title;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +0,0 @@
 | 
			
		||||
// import { computed } from 'vue';
 | 
			
		||||
// import { useRoute } from 'vue-router';
 | 
			
		||||
// import { ROUTE_NAME_MAP } from '@/utils';
 | 
			
		||||
 | 
			
		||||
export default function useRouteParam() {
 | 
			
		||||
  // const route = useRoute();
 | 
			
		||||
}
 | 
			
		||||
@@ -1,22 +0,0 @@
 | 
			
		||||
import { computed } from 'vue';
 | 
			
		||||
import { useRoute } from 'vue-router';
 | 
			
		||||
 | 
			
		||||
export default function useRouteProps() {
 | 
			
		||||
  const route = useRoute();
 | 
			
		||||
  const props = computed(() => {
 | 
			
		||||
    /** 路由名称 */
 | 
			
		||||
    const name = route.name as string;
 | 
			
		||||
    /** 混存页面 */
 | 
			
		||||
    const keepAlive = Boolean(route.meta?.keepAlive);
 | 
			
		||||
    /** 视高100% */
 | 
			
		||||
    const fullPage = Boolean(route.meta?.fullPage);
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      name,
 | 
			
		||||
      keepAlive,
 | 
			
		||||
      fullPage
 | 
			
		||||
    };
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return props;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,21 +0,0 @@
 | 
			
		||||
import { computed } from 'vue';
 | 
			
		||||
import { useRoute } from 'vue-router';
 | 
			
		||||
import { EnumRoutePath } from '@/enum';
 | 
			
		||||
import { ROUTE_NAME_MAP } from '@/utils';
 | 
			
		||||
 | 
			
		||||
export default function useRouteQuery() {
 | 
			
		||||
  const route = useRoute();
 | 
			
		||||
 | 
			
		||||
  /** 登录跳转链接 */
 | 
			
		||||
  const loginRedirectUrl = computed(() => {
 | 
			
		||||
    let url: EnumRoutePath | undefined;
 | 
			
		||||
    if (route.name === ROUTE_NAME_MAP.get('login')) {
 | 
			
		||||
      url = (route.query?.redirectUrl as EnumRoutePath) || '';
 | 
			
		||||
    }
 | 
			
		||||
    return url;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    loginRedirectUrl
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
@@ -1,16 +0,0 @@
 | 
			
		||||
import { ref } from 'vue';
 | 
			
		||||
 | 
			
		||||
/** 滚动行为 */
 | 
			
		||||
export default function useScrollBehavior() {
 | 
			
		||||
  const scrollbar = ref<HTMLElement | null>(null);
 | 
			
		||||
 | 
			
		||||
  /** 重置滚动条行为 */
 | 
			
		||||
  function resetScrollBehavior() {
 | 
			
		||||
    scrollbar.value?.scrollTo({ left: 0, top: 0 });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    scrollbar,
 | 
			
		||||
    resetScrollBehavior
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								src/interface/business/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/interface/business/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
export * from './auth';
 | 
			
		||||
@@ -1,40 +0,0 @@
 | 
			
		||||
import type { RouteRecordRaw } from 'vue-router';
 | 
			
		||||
import type { MenuOption } from 'naive-ui';
 | 
			
		||||
import { EnumRoutePath, EnumLoginModule } from '@/enum';
 | 
			
		||||
 | 
			
		||||
/** 路由描述 */
 | 
			
		||||
interface RouteMeta {
 | 
			
		||||
  /** 路由名称 */
 | 
			
		||||
  title?: string;
 | 
			
		||||
  /** 缓存页面 */
 | 
			
		||||
  keepAlive?: boolean;
 | 
			
		||||
  /** 页面100%视高 */
 | 
			
		||||
  fullPage?: boolean;
 | 
			
		||||
  /** 不作为菜单 */
 | 
			
		||||
  isNotMenu?: boolean;
 | 
			
		||||
  /** 菜单和面包屑对应的图标 */
 | 
			
		||||
  icon?: string;
 | 
			
		||||
  /** 路由作为菜单时的排序 */
 | 
			
		||||
  order?: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 路由配置 */
 | 
			
		||||
export type CustomRoute = RouteRecordRaw & { meta: RouteMeta };
 | 
			
		||||
 | 
			
		||||
/** 路由路径 */
 | 
			
		||||
export type RoutePathKey = keyof typeof EnumRoutePath;
 | 
			
		||||
 | 
			
		||||
/** 菜单项配置 */
 | 
			
		||||
export type GlobalMenuOption = MenuOption & {
 | 
			
		||||
  routeName: string;
 | 
			
		||||
  routePath: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** 登录模块 */
 | 
			
		||||
export type LoginModuleType = keyof typeof EnumLoginModule;
 | 
			
		||||
 | 
			
		||||
/** npm依赖包版本信息 */
 | 
			
		||||
export interface VersionInfo {
 | 
			
		||||
  name: string;
 | 
			
		||||
  version: string;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								src/interface/common/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								src/interface/common/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
export * from './system';
 | 
			
		||||
export * from './route';
 | 
			
		||||
							
								
								
									
										55
									
								
								src/interface/common/route.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/interface/common/route.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
			
		||||
import type { RouteRecordRaw } from 'vue-router';
 | 
			
		||||
 | 
			
		||||
/** 路由描述 */
 | 
			
		||||
interface RouteMeta {
 | 
			
		||||
  /** 路由名称 */
 | 
			
		||||
  title?: string;
 | 
			
		||||
  /** 缓存页面 */
 | 
			
		||||
  keepAlive?: boolean;
 | 
			
		||||
  /** 页面100%视高 */
 | 
			
		||||
  fullPage?: boolean;
 | 
			
		||||
  /** 不作为菜单 */
 | 
			
		||||
  isNotMenu?: boolean;
 | 
			
		||||
  /** 菜单和面包屑对应的图标 */
 | 
			
		||||
  icon?: string;
 | 
			
		||||
  /** 路由作为菜单时的排序 */
 | 
			
		||||
  order?: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 路由配置 */
 | 
			
		||||
export type CustomRoute = RouteRecordRaw & { meta: RouteMeta };
 | 
			
		||||
 | 
			
		||||
/** 路由声明的key */
 | 
			
		||||
export type RouteKey =
 | 
			
		||||
  | 'root'
 | 
			
		||||
  | 'login'
 | 
			
		||||
  | 'not-found'
 | 
			
		||||
  | 'no-permission'
 | 
			
		||||
  | 'service-error'
 | 
			
		||||
  // 自定义路由
 | 
			
		||||
  | 'dashboard'
 | 
			
		||||
  | 'dashboard_analysis'
 | 
			
		||||
  | 'dashboard_workbench'
 | 
			
		||||
  | 'document'
 | 
			
		||||
  | 'document_vue'
 | 
			
		||||
  | 'document_vite'
 | 
			
		||||
  | 'document_naive'
 | 
			
		||||
  | 'component'
 | 
			
		||||
  | 'component_map'
 | 
			
		||||
  | 'component_video'
 | 
			
		||||
  | 'component_editor'
 | 
			
		||||
  | 'component_editor_quill'
 | 
			
		||||
  | 'component_editor_markdown'
 | 
			
		||||
  | 'component_swiper'
 | 
			
		||||
  | 'feat'
 | 
			
		||||
  | 'feat_copy'
 | 
			
		||||
  | 'feat_icon'
 | 
			
		||||
  | 'feat_print'
 | 
			
		||||
  | 'multi-menu'
 | 
			
		||||
  | 'multi-menu_first'
 | 
			
		||||
  | 'multi-menu_first_second'
 | 
			
		||||
  | 'exception'
 | 
			
		||||
  | 'exception_403'
 | 
			
		||||
  | 'exception_404'
 | 
			
		||||
  | 'exception_500'
 | 
			
		||||
  | 'about';
 | 
			
		||||
							
								
								
									
										17
									
								
								src/interface/common/system.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/interface/common/system.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
import type { MenuOption } from 'naive-ui';
 | 
			
		||||
import { EnumLoginModule } from '@/enum';
 | 
			
		||||
 | 
			
		||||
/** 菜单项配置 */
 | 
			
		||||
export type GlobalMenuOption = MenuOption & {
 | 
			
		||||
  routeName: string;
 | 
			
		||||
  routePath: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** 登录模块 */
 | 
			
		||||
export type LoginModuleType = keyof typeof EnumLoginModule;
 | 
			
		||||
 | 
			
		||||
/** npm依赖包版本信息 */
 | 
			
		||||
export interface VersionInfo {
 | 
			
		||||
  name: string;
 | 
			
		||||
  version: string;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,3 +1,3 @@
 | 
			
		||||
export * from './common';
 | 
			
		||||
export * from './business';
 | 
			
		||||
export * from './theme';
 | 
			
		||||
export * from './common';
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,34 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div>
 | 
			
		||||
    <div class="flex">
 | 
			
		||||
      <h3>horizontal</h3>
 | 
			
		||||
    </div>
 | 
			
		||||
    <router-view />
 | 
			
		||||
  </div>
 | 
			
		||||
  <n-layout class="h-full">
 | 
			
		||||
    <n-layout-content
 | 
			
		||||
      :native-scrollbar="false"
 | 
			
		||||
      :content-style="{ height: routeProps.fullPage ? '100%' : 'auto' }"
 | 
			
		||||
      class="bg-[#f6f9f8] dark:bg-deep-dark"
 | 
			
		||||
    >
 | 
			
		||||
      <n-layout-header :inverted="headerInverted" :position="headerPosition" class="z-11">
 | 
			
		||||
        <global-header :show-logo="true" :show-menu-collape="false" :show-menu="true" class="relative z-2" />
 | 
			
		||||
        <global-tab v-if="theme.multiTabStyle.visible" />
 | 
			
		||||
      </n-layout-header>
 | 
			
		||||
      <header-placeholder />
 | 
			
		||||
      <global-content />
 | 
			
		||||
      <global-footer />
 | 
			
		||||
    </n-layout-content>
 | 
			
		||||
  </n-layout>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts"></script>
 | 
			
		||||
<style scoped></style>
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { NLayout, NLayoutContent, NLayoutHeader } from 'naive-ui';
 | 
			
		||||
import { useThemeStore } from '@/store';
 | 
			
		||||
import { useRouteProps, useLayoutConfig } from '@/composables';
 | 
			
		||||
import { GlobalHeader, GlobalContent, GlobalFooter, GlobalTab, HeaderPlaceholder } from '../common';
 | 
			
		||||
 | 
			
		||||
const theme = useThemeStore();
 | 
			
		||||
 | 
			
		||||
const routeProps = useRouteProps();
 | 
			
		||||
const { headerInverted, headerPosition } = useLayoutConfig();
 | 
			
		||||
</script>
 | 
			
		||||
<style scoped>
 | 
			
		||||
.global-sider {
 | 
			
		||||
  box-shadow: 2px 0 8px 0 rgb(29 35 41 / 5%);
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,5 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div>
 | 
			
		||||
    <div class="flex">
 | 
			
		||||
      <h3>horizontal-mix</h3>
 | 
			
		||||
    </div>
 | 
			
		||||
    <router-view />
 | 
			
		||||
  </div>
 | 
			
		||||
  <div></div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts"></script>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,18 +1,18 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <n-layout :has-sider="true" class="h-full">
 | 
			
		||||
    <n-layout-sider
 | 
			
		||||
      class="global-sider z-12"
 | 
			
		||||
      :inverted="inverted"
 | 
			
		||||
      class="global-sider z-12 transition-all duration-200 ease-in-out"
 | 
			
		||||
      :inverted="siderInverted"
 | 
			
		||||
      collapse-mode="width"
 | 
			
		||||
      :collapsed="app.menu.collapsed"
 | 
			
		||||
      :collapsed-width="theme.menuStyle.collapsedWidth"
 | 
			
		||||
      :width="menuWidth"
 | 
			
		||||
      :width="siderMenuWidth"
 | 
			
		||||
      :native-scrollbar="false"
 | 
			
		||||
      @collapse="handleMenuCollapse(true)"
 | 
			
		||||
      @expand="handleMenuCollapse(false)"
 | 
			
		||||
    >
 | 
			
		||||
      <global-logo :show-title="!app.menu.collapsed" class="header-height absolute-lt w-full z-2" />
 | 
			
		||||
      <global-menu class="header-padding" />
 | 
			
		||||
      <global-logo :show-title="!app.menu.collapsed" class="absolute-lt z-2" />
 | 
			
		||||
      <global-menu :style="{ paddingTop: headerHeight }" />
 | 
			
		||||
    </n-layout-sider>
 | 
			
		||||
    <n-layout-content
 | 
			
		||||
      :native-scrollbar="false"
 | 
			
		||||
@@ -20,15 +20,10 @@
 | 
			
		||||
      class="bg-[#f6f9f8] dark:bg-deep-dark"
 | 
			
		||||
    >
 | 
			
		||||
      <n-layout-header :inverted="headerInverted" :position="headerPosition" class="z-11">
 | 
			
		||||
        <global-header
 | 
			
		||||
          :show-logo="false"
 | 
			
		||||
          :show-menu-collape="true"
 | 
			
		||||
          :show-menu="false"
 | 
			
		||||
          class="header-height relative z-2"
 | 
			
		||||
        />
 | 
			
		||||
        <global-tab v-if="theme.multiTabStyle.visible" class="tab-height" />
 | 
			
		||||
        <global-header :show-logo="false" :show-menu-collape="true" :show-menu="false" class="relative z-2" />
 | 
			
		||||
        <global-tab v-if="theme.multiTabStyle.visible" />
 | 
			
		||||
      </n-layout-header>
 | 
			
		||||
      <div v-if="theme.fixedHeaderAndTab" class="header-tab_height"></div>
 | 
			
		||||
      <header-placeholder />
 | 
			
		||||
      <global-content />
 | 
			
		||||
      <global-footer />
 | 
			
		||||
    </n-layout-content>
 | 
			
		||||
@@ -36,66 +31,27 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { computed } from 'vue';
 | 
			
		||||
import { NLayout, NLayoutSider, NLayoutContent, NLayoutHeader } from 'naive-ui';
 | 
			
		||||
import { useThemeStore, useAppStore } from '@/store';
 | 
			
		||||
import { useRouteProps } from '@/hooks';
 | 
			
		||||
import { GlobalHeader, GlobalContent, GlobalFooter, GlobalTab, GlobalLogo, GlobalMenu } from '../common';
 | 
			
		||||
import { useRouteProps, useLayoutConfig } from '@/composables';
 | 
			
		||||
import {
 | 
			
		||||
  GlobalHeader,
 | 
			
		||||
  GlobalContent,
 | 
			
		||||
  GlobalFooter,
 | 
			
		||||
  GlobalTab,
 | 
			
		||||
  HeaderPlaceholder,
 | 
			
		||||
  GlobalLogo,
 | 
			
		||||
  GlobalMenu
 | 
			
		||||
} from '../common';
 | 
			
		||||
 | 
			
		||||
const theme = useThemeStore();
 | 
			
		||||
const app = useAppStore();
 | 
			
		||||
const routeProps = useRouteProps();
 | 
			
		||||
 | 
			
		||||
const { handleMenuCollapse } = useAppStore();
 | 
			
		||||
 | 
			
		||||
const inverted = computed(() => {
 | 
			
		||||
  return theme.navStyle.theme !== 'light';
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const menuWidth = computed(() => {
 | 
			
		||||
  const { collapsed } = app.menu;
 | 
			
		||||
  const { collapsedWidth, width } = theme.menuStyle;
 | 
			
		||||
  return collapsed ? collapsedWidth : width;
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const headerInverted = computed(() => {
 | 
			
		||||
  return theme.navStyle.theme !== 'dark' ? inverted.value : !inverted.value;
 | 
			
		||||
});
 | 
			
		||||
const headerPosition = computed(() => (theme.fixedHeaderAndTab ? 'absolute' : 'static'));
 | 
			
		||||
const headerHeight = computed(() => {
 | 
			
		||||
  const { height } = theme.headerStyle;
 | 
			
		||||
  return `${height}px`;
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const tabHeight = computed(() => {
 | 
			
		||||
  const { height } = theme.multiTabStyle;
 | 
			
		||||
  return `${height}px`;
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const headerAndTabHeight = computed(() => {
 | 
			
		||||
  const {
 | 
			
		||||
    multiTabStyle: { visible, height: tH },
 | 
			
		||||
    headerStyle: { height: hH }
 | 
			
		||||
  } = theme;
 | 
			
		||||
  const height = visible ? tH + hH : hH;
 | 
			
		||||
  return `${height}px`;
 | 
			
		||||
});
 | 
			
		||||
const routeProps = useRouteProps();
 | 
			
		||||
const { siderInverted, siderMenuWidth, headerInverted, headerPosition, headerHeight } = useLayoutConfig();
 | 
			
		||||
</script>
 | 
			
		||||
<style scoped>
 | 
			
		||||
.global-sider {
 | 
			
		||||
  transition: all 0.2s ease-in-out;
 | 
			
		||||
  box-shadow: 2px 0 8px 0 rgb(29 35 41 / 5%);
 | 
			
		||||
}
 | 
			
		||||
.header-height {
 | 
			
		||||
  height: v-bind(headerHeight);
 | 
			
		||||
}
 | 
			
		||||
.header-padding {
 | 
			
		||||
  padding-top: v-bind(headerHeight);
 | 
			
		||||
}
 | 
			
		||||
.tab-height {
 | 
			
		||||
  height: v-bind(tabHeight);
 | 
			
		||||
}
 | 
			
		||||
.header-tab_height {
 | 
			
		||||
  height: v-bind(headerAndTabHeight);
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,50 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div>
 | 
			
		||||
    <div class="flex">
 | 
			
		||||
      <h3>vertical-mix</h3>
 | 
			
		||||
    </div>
 | 
			
		||||
    <router-view />
 | 
			
		||||
  </div>
 | 
			
		||||
  <n-layout :has-sider="true" class="h-full">
 | 
			
		||||
    <n-layout-sider
 | 
			
		||||
      class="global-sider z-12 transition-all duration-200 ease-in-out"
 | 
			
		||||
      :inverted="siderInverted"
 | 
			
		||||
      collapse-mode="width"
 | 
			
		||||
      :collapsed="app.menu.collapsed"
 | 
			
		||||
      :collapsed-width="theme.menuStyle.collapsedWidth"
 | 
			
		||||
      :width="siderMenuWidth"
 | 
			
		||||
      :native-scrollbar="false"
 | 
			
		||||
      @collapse="handleMenuCollapse(true)"
 | 
			
		||||
      @expand="handleMenuCollapse(false)"
 | 
			
		||||
    >
 | 
			
		||||
      <global-logo :show-title="!app.menu.collapsed" class="absolute-lt z-2" />
 | 
			
		||||
      <global-menu :style="{ paddingTop: headerHeight }" />
 | 
			
		||||
    </n-layout-sider>
 | 
			
		||||
    <n-layout-content
 | 
			
		||||
      :native-scrollbar="false"
 | 
			
		||||
      :content-style="{ height: routeProps.fullPage ? '100%' : 'auto' }"
 | 
			
		||||
      class="bg-[#f6f9f8] dark:bg-deep-dark"
 | 
			
		||||
    >
 | 
			
		||||
      <n-layout-header :inverted="headerInverted" :position="headerPosition" class="z-11">
 | 
			
		||||
        <global-header :show-logo="false" :show-menu-collape="true" :show-menu="false" class="relative z-2" />
 | 
			
		||||
        <global-tab v-if="theme.multiTabStyle.visible" />
 | 
			
		||||
      </n-layout-header>
 | 
			
		||||
      <div v-if="theme.fixedHeaderAndTab" :style="{ height: headerAndMultiTabHeight }"></div>
 | 
			
		||||
      <global-content />
 | 
			
		||||
      <global-footer />
 | 
			
		||||
    </n-layout-content>
 | 
			
		||||
  </n-layout>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts"></script>
 | 
			
		||||
<style scoped></style>
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { NLayout, NLayoutSider, NLayoutContent, NLayoutHeader } from 'naive-ui';
 | 
			
		||||
import { useThemeStore, useAppStore } from '@/store';
 | 
			
		||||
import { useRouteProps, useLayoutConfig } from '@/composables';
 | 
			
		||||
import { GlobalHeader, GlobalContent, GlobalFooter, GlobalTab, GlobalLogo, GlobalMenu } from '../common';
 | 
			
		||||
 | 
			
		||||
const theme = useThemeStore();
 | 
			
		||||
const app = useAppStore();
 | 
			
		||||
const { handleMenuCollapse } = useAppStore();
 | 
			
		||||
const routeProps = useRouteProps();
 | 
			
		||||
const { siderInverted, siderMenuWidth, headerInverted, headerPosition, headerHeight, headerAndMultiTabHeight } =
 | 
			
		||||
  useLayoutConfig();
 | 
			
		||||
</script>
 | 
			
		||||
<style scoped>
 | 
			
		||||
.global-sider {
 | 
			
		||||
  box-shadow: 2px 0 8px 0 rgb(29 35 41 / 5%);
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ import { computed } from 'vue';
 | 
			
		||||
import { useThemeStore } from '@/store';
 | 
			
		||||
import { useReloadInject } from '@/context';
 | 
			
		||||
import { cacheRoutes } from '@/router';
 | 
			
		||||
import { useRouteProps } from '@/hooks';
 | 
			
		||||
import { useRouteProps } from '@/composables';
 | 
			
		||||
 | 
			
		||||
const theme = useThemeStore();
 | 
			
		||||
const { reload } = useReloadInject();
 | 
			
		||||
 
 | 
			
		||||
@@ -32,15 +32,15 @@ import type { RouteLocationMatched } from 'vue-router';
 | 
			
		||||
import { NBreadcrumb, NBreadcrumbItem, NDropdown } from 'naive-ui';
 | 
			
		||||
import type { DropdownOption } from 'naive-ui';
 | 
			
		||||
import { Icon } from '@iconify/vue';
 | 
			
		||||
import { EnumRoutePath } from '@/enum';
 | 
			
		||||
import { routePath } from '@/router';
 | 
			
		||||
import { useThemeStore } from '@/store';
 | 
			
		||||
import type { RoutePathKey } from '@/interface';
 | 
			
		||||
import type { RouteKey } from '@/interface';
 | 
			
		||||
 | 
			
		||||
type Breadcrumb = DropdownOption & {
 | 
			
		||||
  key: string;
 | 
			
		||||
  label: string;
 | 
			
		||||
  disabled: boolean;
 | 
			
		||||
  routeName: RoutePathKey;
 | 
			
		||||
  routeName: RouteKey;
 | 
			
		||||
  hasChildren: boolean;
 | 
			
		||||
  iconName?: string;
 | 
			
		||||
  children?: Breadcrumb[];
 | 
			
		||||
@@ -62,11 +62,11 @@ function recursionBreadcrumb(routeMatched: RouteLocationMatched[]) {
 | 
			
		||||
  const list: Breadcrumb[] = [];
 | 
			
		||||
  routeMatched.forEach(item => {
 | 
			
		||||
    if (!item.meta?.isNotMenu) {
 | 
			
		||||
      const routeName = item.name as RoutePathKey;
 | 
			
		||||
      const routeName = item.name as RouteKey;
 | 
			
		||||
      const breadcrumItem: Breadcrumb = {
 | 
			
		||||
        key: routeName,
 | 
			
		||||
        label: (item.meta?.title as string) || '',
 | 
			
		||||
        disabled: item.path === EnumRoutePath.root,
 | 
			
		||||
        disabled: item.path === routePath('root'),
 | 
			
		||||
        routeName,
 | 
			
		||||
        hasChildren: false
 | 
			
		||||
      };
 | 
			
		||||
@@ -84,7 +84,7 @@ function recursionBreadcrumb(routeMatched: RouteLocationMatched[]) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function dropdownSelect(optionKey: string) {
 | 
			
		||||
  const key = optionKey as RoutePathKey;
 | 
			
		||||
  const key = optionKey as RouteKey;
 | 
			
		||||
  router.push({ name: key });
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -10,13 +10,13 @@
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { NDropdown, useDialog } from 'naive-ui';
 | 
			
		||||
import { HoverContainer } from '@/components';
 | 
			
		||||
import { useRouterChange } from '@/hooks';
 | 
			
		||||
import { useRouterPush } from '@/composables';
 | 
			
		||||
import { iconifyRender, resetAuthStorage } from '@/utils';
 | 
			
		||||
import avatar from '@/assets/svg/avatar/avatar01.svg';
 | 
			
		||||
 | 
			
		||||
type DropdownKey = 'user-center' | 'logout';
 | 
			
		||||
 | 
			
		||||
const { toLogin } = useRouterChange();
 | 
			
		||||
const { toLogin } = useRouterPush();
 | 
			
		||||
const dialog = useDialog();
 | 
			
		||||
 | 
			
		||||
const options = [
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,12 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="global-header flex-y-center w-full">
 | 
			
		||||
  <div class="global-header flex-y-center w-full" :style="{ height: headerHeight }">
 | 
			
		||||
    <global-logo v-if="showLogo" :show-title="true" class="h-full" :style="{ width: theme.menuStyle.width + 'px' }" />
 | 
			
		||||
    <div class="flex-1-hidden flex-y-center h-full">
 | 
			
		||||
    <div v-if="!showMenu" class="flex-1-hidden flex-y-center h-full">
 | 
			
		||||
      <menu-collapse v-if="showMenuCollape" />
 | 
			
		||||
      <global-breadcrumb v-if="theme.crumbsStyle.visible" />
 | 
			
		||||
    </div>
 | 
			
		||||
    <div
 | 
			
		||||
      v-if="showMenu"
 | 
			
		||||
      v-else
 | 
			
		||||
      class="flex-1-hidden flex-y-center h-full"
 | 
			
		||||
      :style="{ justifyContent: theme.menuStyle.horizontalPosition }"
 | 
			
		||||
    >
 | 
			
		||||
@@ -24,6 +24,7 @@
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { useThemeStore } from '@/store';
 | 
			
		||||
import { useLayoutConfig } from '@/composables';
 | 
			
		||||
import {
 | 
			
		||||
  HeaderMenu,
 | 
			
		||||
  GlobalBreadcrumb,
 | 
			
		||||
@@ -48,6 +49,7 @@ interface Props {
 | 
			
		||||
defineProps<Props>();
 | 
			
		||||
 | 
			
		||||
const theme = useThemeStore();
 | 
			
		||||
const { headerHeight } = useLayoutConfig();
 | 
			
		||||
 | 
			
		||||
const showSettingButton = import.meta.env.DEV || import.meta.env.VITE_HTTP_ENV === 'STAGING';
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@
 | 
			
		||||
    href="/"
 | 
			
		||||
    class="
 | 
			
		||||
      flex-center
 | 
			
		||||
      w-full
 | 
			
		||||
      nowrap-hidden
 | 
			
		||||
      bg-light
 | 
			
		||||
      dark:bg-dark
 | 
			
		||||
@@ -11,6 +12,7 @@
 | 
			
		||||
      ease-in-out
 | 
			
		||||
      cursor-pointer
 | 
			
		||||
    "
 | 
			
		||||
    :style="{ height: headerHeight }"
 | 
			
		||||
  >
 | 
			
		||||
    <system-logo class="w-32px h-32px" :color="theme.themeColor" />
 | 
			
		||||
    <h2 v-show="showTitle" class="text-primary pl-8px text-16px font-bold">{{ title }}</h2>
 | 
			
		||||
@@ -20,7 +22,7 @@
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { SystemLogo } from '@/components';
 | 
			
		||||
import { useThemeStore } from '@/store';
 | 
			
		||||
import { useAppTitle } from '@/hooks';
 | 
			
		||||
import { useAppTitle, useLayoutConfig } from '@/composables';
 | 
			
		||||
 | 
			
		||||
interface Props {
 | 
			
		||||
  /** 显示名字 */
 | 
			
		||||
@@ -31,5 +33,6 @@ defineProps<Props>();
 | 
			
		||||
 | 
			
		||||
const theme = useThemeStore();
 | 
			
		||||
const title = useAppTitle();
 | 
			
		||||
const { headerHeight } = useLayoutConfig();
 | 
			
		||||
</script>
 | 
			
		||||
<style scoped></style>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="multi-tab flex-center w-full pl-16px">
 | 
			
		||||
  <div class="multi-tab flex-center w-full pl-16px" :style="{ height: multiTabHeight }">
 | 
			
		||||
    <div class="flex-1-hidden h-full">
 | 
			
		||||
      <better-scroll :options="{ scrollX: true, scrollY: false, click: true }">
 | 
			
		||||
        <multi-tab />
 | 
			
		||||
@@ -13,11 +13,13 @@
 | 
			
		||||
import { watch } from 'vue';
 | 
			
		||||
import { useRoute } from 'vue-router';
 | 
			
		||||
import { useAppStore } from '@/store';
 | 
			
		||||
import { useLayoutConfig } from '@/composables';
 | 
			
		||||
import { BetterScroll } from '@/components';
 | 
			
		||||
import { MultiTab, ReloadButton } from './components';
 | 
			
		||||
 | 
			
		||||
const route = useRoute();
 | 
			
		||||
const { initMultiTab, addMultiTab, setActiveMultiTab } = useAppStore();
 | 
			
		||||
const { multiTabHeight } = useLayoutConfig();
 | 
			
		||||
 | 
			
		||||
function init() {
 | 
			
		||||
  initMultiTab();
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,12 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div v-if="theme.fixedHeaderAndTab" :style="{ height: headerAndMultiTabHeight }"></div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { useThemeStore } from '@/store';
 | 
			
		||||
import { useLayoutConfig } from '@/composables';
 | 
			
		||||
 | 
			
		||||
const theme = useThemeStore();
 | 
			
		||||
const { headerAndMultiTabHeight } = useLayoutConfig();
 | 
			
		||||
</script>
 | 
			
		||||
<style scoped></style>
 | 
			
		||||
@@ -4,6 +4,16 @@ import GlobalFooter from './GlobalFooter/index.vue';
 | 
			
		||||
import GlobalLogo from './GlobalLogo/index.vue';
 | 
			
		||||
import GlobalMenu from './GlobalMenu/index.vue';
 | 
			
		||||
import GlobalTab from './GlobalTab/index.vue';
 | 
			
		||||
import HeaderPlaceholder from './HeaderPlaceholder/index.vue';
 | 
			
		||||
import SettingDrawer from './SettingDrawer/index.vue';
 | 
			
		||||
 | 
			
		||||
export { GlobalHeader, GlobalContent, GlobalFooter, GlobalLogo, GlobalMenu, GlobalTab, SettingDrawer };
 | 
			
		||||
export {
 | 
			
		||||
  GlobalHeader,
 | 
			
		||||
  GlobalContent,
 | 
			
		||||
  GlobalFooter,
 | 
			
		||||
  GlobalLogo,
 | 
			
		||||
  GlobalMenu,
 | 
			
		||||
  GlobalTab,
 | 
			
		||||
  HeaderPlaceholder,
 | 
			
		||||
  SettingDrawer
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,14 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div
 | 
			
		||||
    class="flex-1 flex-col-stretch p-16px bg-[#F6F9F8] dark:bg-black"
 | 
			
		||||
    class="
 | 
			
		||||
      flex-1 flex-col-stretch
 | 
			
		||||
      p-16px
 | 
			
		||||
      bg-[#f6f9f8]
 | 
			
		||||
      dark:bg-deep-dark
 | 
			
		||||
      transition-backgorund-color
 | 
			
		||||
      duration-300
 | 
			
		||||
      ease-in-out
 | 
			
		||||
    "
 | 
			
		||||
    :class="{ 'overflow-hidden': routeProps.fullPage }"
 | 
			
		||||
  >
 | 
			
		||||
    <router-view v-slot="{ Component, route }">
 | 
			
		||||
@@ -17,7 +25,7 @@
 | 
			
		||||
import { useThemeStore } from '@/store';
 | 
			
		||||
import { useReloadInject } from '@/context';
 | 
			
		||||
import { cacheRoutes } from '@/router';
 | 
			
		||||
import { useRouteProps } from '@/hooks';
 | 
			
		||||
import { useRouteProps } from '@/composables';
 | 
			
		||||
 | 
			
		||||
const theme = useThemeStore();
 | 
			
		||||
const { reload } = useReloadInject();
 | 
			
		||||
 
 | 
			
		||||
@@ -32,15 +32,15 @@ import type { RouteLocationMatched } from 'vue-router';
 | 
			
		||||
import { NBreadcrumb, NBreadcrumbItem, NDropdown } from 'naive-ui';
 | 
			
		||||
import type { DropdownOption } from 'naive-ui';
 | 
			
		||||
import { Icon } from '@iconify/vue';
 | 
			
		||||
import { EnumRoutePath } from '@/enum';
 | 
			
		||||
import { routePath } from '@/router';
 | 
			
		||||
import { useThemeStore } from '@/store';
 | 
			
		||||
import type { RoutePathKey } from '@/interface';
 | 
			
		||||
import type { RouteKey } from '@/interface';
 | 
			
		||||
 | 
			
		||||
type Breadcrumb = DropdownOption & {
 | 
			
		||||
  key: string;
 | 
			
		||||
  label: string;
 | 
			
		||||
  disabled: boolean;
 | 
			
		||||
  routeName: RoutePathKey;
 | 
			
		||||
  routeName: RouteKey;
 | 
			
		||||
  hasChildren: boolean;
 | 
			
		||||
  iconName?: string;
 | 
			
		||||
  children?: Breadcrumb[];
 | 
			
		||||
@@ -62,11 +62,11 @@ function recursionBreadcrumb(routeMatched: RouteLocationMatched[]) {
 | 
			
		||||
  const list: Breadcrumb[] = [];
 | 
			
		||||
  routeMatched.forEach(item => {
 | 
			
		||||
    if (!item.meta?.isNotMenu) {
 | 
			
		||||
      const routeName = item.name as RoutePathKey;
 | 
			
		||||
      const routeName = item.name as RouteKey;
 | 
			
		||||
      const breadcrumItem: Breadcrumb = {
 | 
			
		||||
        key: routeName,
 | 
			
		||||
        label: (item.meta?.title as string) || '',
 | 
			
		||||
        disabled: item.path === EnumRoutePath.root,
 | 
			
		||||
        disabled: item.path === routePath('root'),
 | 
			
		||||
        routeName,
 | 
			
		||||
        hasChildren: false
 | 
			
		||||
      };
 | 
			
		||||
@@ -84,7 +84,7 @@ function recursionBreadcrumb(routeMatched: RouteLocationMatched[]) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function dropdownSelect(optionKey: string) {
 | 
			
		||||
  const key = optionKey as RoutePathKey;
 | 
			
		||||
  const key = optionKey as RouteKey;
 | 
			
		||||
  router.push({ name: key });
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -10,13 +10,13 @@
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { NDropdown, useDialog } from 'naive-ui';
 | 
			
		||||
import { HoverContainer } from '@/components';
 | 
			
		||||
import { useRouterChange } from '@/hooks';
 | 
			
		||||
import { useRouterPush } from '@/composables';
 | 
			
		||||
import { iconifyRender, resetAuthStorage } from '@/utils';
 | 
			
		||||
import avatar from '@/assets/svg/avatar/avatar01.svg';
 | 
			
		||||
 | 
			
		||||
type DropdownKey = 'user-center' | 'logout';
 | 
			
		||||
 | 
			
		||||
const { toLogin } = useRouterChange();
 | 
			
		||||
const { toLogin } = useRouterPush();
 | 
			
		||||
const dialog = useDialog();
 | 
			
		||||
 | 
			
		||||
const options = [
 | 
			
		||||
 
 | 
			
		||||
@@ -35,7 +35,7 @@ import { useRouter, useRoute } from 'vue-router';
 | 
			
		||||
import { NScrollbar, NMenu } from 'naive-ui';
 | 
			
		||||
import type { MenuOption } from 'naive-ui';
 | 
			
		||||
import { useThemeStore, useAppStore } from '@/store';
 | 
			
		||||
import { useAppTitle } from '@/hooks';
 | 
			
		||||
import { useAppTitle } from '@/composables';
 | 
			
		||||
import { menus } from '@/router';
 | 
			
		||||
import type { GlobalMenuOption } from '@/interface';
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,19 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div v-if="fixedHeaderAndTab && theme.navStyle.mode !== 'horizontal-mix'" class="multi-tab-height w-full"></div>
 | 
			
		||||
  <div
 | 
			
		||||
    class="multi-tab flex-center justify-between w-full pl-10px"
 | 
			
		||||
    :class="[theme.darkMode ? 'bg-[#18181c]' : 'bg-white', { 'multi-tab-top absolute': fixedHeaderAndTab }]"
 | 
			
		||||
    class="
 | 
			
		||||
      multi-tab
 | 
			
		||||
      flex-center
 | 
			
		||||
      justify-between
 | 
			
		||||
      w-full
 | 
			
		||||
      pl-10px
 | 
			
		||||
      bg-light
 | 
			
		||||
      dark:bg-dark
 | 
			
		||||
      transition-backgorund-color
 | 
			
		||||
      duration-300
 | 
			
		||||
      ease-in-out
 | 
			
		||||
    "
 | 
			
		||||
    :class="{ 'multi-tab-top absolute': fixedHeaderAndTab }"
 | 
			
		||||
    :style="{ zIndex }"
 | 
			
		||||
    :align="'center'"
 | 
			
		||||
    justify="space-between"
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
import { computed } from 'vue';
 | 
			
		||||
import { SystemLogo } from '@/components';
 | 
			
		||||
import { useAppStore, useThemeStore } from '@/store';
 | 
			
		||||
import { useAppTitle } from '@/hooks';
 | 
			
		||||
import { useAppTitle } from '@/composables';
 | 
			
		||||
 | 
			
		||||
const app = useAppStore();
 | 
			
		||||
const theme = useThemeStore();
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
    <global-header v-if="isHorizontalMix" :z-index="14" />
 | 
			
		||||
    <div class="flex-1-hidden flex h-full">
 | 
			
		||||
      <global-sider v-if="isHorizontalMix" :z-index="13" />
 | 
			
		||||
      <n-scrollbar ref="scrollbar" class="h-full" :content-class="routeProps.fullPage ? 'h-full' : ''">
 | 
			
		||||
      <n-scrollbar class="h-full" :content-class="routeProps.fullPage ? 'h-full' : ''">
 | 
			
		||||
        <div
 | 
			
		||||
          class="inline-flex-col-stretch w-full"
 | 
			
		||||
          :class="[{ 'content-padding': isHorizontalMix }, routeProps.fullPage ? 'h-full' : 'min-h-100vh']"
 | 
			
		||||
@@ -21,16 +21,13 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { computed, watch } from 'vue';
 | 
			
		||||
import { useRoute } from 'vue-router';
 | 
			
		||||
import { computed } from 'vue';
 | 
			
		||||
import { NLayout, NScrollbar } from 'naive-ui';
 | 
			
		||||
import { useThemeStore } from '@/store';
 | 
			
		||||
import { useRouteProps, useScrollBehavior } from '@/hooks';
 | 
			
		||||
import { useRouteProps } from '@/composables';
 | 
			
		||||
import { GlobalSider, GlobalHeader, GlobalTab, GlobalContent, GlobalFooter, SettingDrawer } from './components';
 | 
			
		||||
 | 
			
		||||
const route = useRoute();
 | 
			
		||||
const theme = useThemeStore();
 | 
			
		||||
const { scrollbar, resetScrollBehavior } = useScrollBehavior();
 | 
			
		||||
const routeProps = useRouteProps();
 | 
			
		||||
 | 
			
		||||
const isHorizontalMix = computed(() => theme.navStyle.mode === 'horizontal-mix');
 | 
			
		||||
@@ -42,13 +39,6 @@ const headerAndMultiTabHeight = computed(() => {
 | 
			
		||||
  } = theme;
 | 
			
		||||
  return `${hHeight + mHeight}px`;
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
watch(
 | 
			
		||||
  () => route.name,
 | 
			
		||||
  () => {
 | 
			
		||||
    resetScrollBehavior();
 | 
			
		||||
  }
 | 
			
		||||
);
 | 
			
		||||
</script>
 | 
			
		||||
<style scoped>
 | 
			
		||||
:deep(.n-scrollbar-rail) {
 | 
			
		||||
 
 | 
			
		||||
@@ -18,26 +18,15 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { watch } from 'vue';
 | 
			
		||||
import { useRoute } from 'vue-router';
 | 
			
		||||
import { NScrollbar } from 'naive-ui';
 | 
			
		||||
import { useRouteProps, useScrollBehavior } from '@/hooks';
 | 
			
		||||
import { useThemeStore } from '@/store';
 | 
			
		||||
import { useReloadInject } from '@/context';
 | 
			
		||||
import { cacheRoutes } from '@/router';
 | 
			
		||||
import { useRouteProps } from '@/composables';
 | 
			
		||||
 | 
			
		||||
const theme = useThemeStore();
 | 
			
		||||
const { reload } = useReloadInject();
 | 
			
		||||
 | 
			
		||||
const route = useRoute();
 | 
			
		||||
const { scrollbar, resetScrollBehavior } = useScrollBehavior();
 | 
			
		||||
const routeProps = useRouteProps();
 | 
			
		||||
 | 
			
		||||
watch(
 | 
			
		||||
  () => route.name,
 | 
			
		||||
  () => {
 | 
			
		||||
    resetScrollBehavior();
 | 
			
		||||
  }
 | 
			
		||||
);
 | 
			
		||||
</script>
 | 
			
		||||
<style scoped></style>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										68
									
								
								src/router/const/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								src/router/const/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
import type { RouteKey } from '@/interface';
 | 
			
		||||
 | 
			
		||||
interface RouteConst {
 | 
			
		||||
  /** 路由名称 */
 | 
			
		||||
  name: RouteKey;
 | 
			
		||||
  /** 路由路径 */
 | 
			
		||||
  path: string;
 | 
			
		||||
  /** 路由标题 */
 | 
			
		||||
  title: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 声明的路由名称、路径和标题 */
 | 
			
		||||
const routeConstMap = new Map<RouteKey, RouteConst>([
 | 
			
		||||
  ['root', { name: 'root', path: '/', title: 'Root' }],
 | 
			
		||||
  ['login', { name: 'login', path: '/login', title: '登录' }],
 | 
			
		||||
  ['no-permission', { name: 'no-permission', path: '/403', title: '无权限' }],
 | 
			
		||||
  ['not-found', { name: 'not-found', path: '/404', title: '未找到' }],
 | 
			
		||||
  ['service-error', { name: 'service-error', path: '/500', title: '服务器错误' }],
 | 
			
		||||
  ['dashboard', { name: 'dashboard', path: '/dashboard', title: '仪表盘' }],
 | 
			
		||||
  ['dashboard_analysis', { name: 'dashboard_analysis', path: '/dashboard/analysis', title: '分析页' }],
 | 
			
		||||
  ['dashboard_workbench', { name: 'dashboard_workbench', path: '/dashboard/workbench', title: '工作台' }],
 | 
			
		||||
  ['document', { name: 'document', path: '/document', title: '文档' }],
 | 
			
		||||
  ['document_vue', { name: 'document_vue', path: '/document/vue', title: 'vue文档' }],
 | 
			
		||||
  ['document_vite', { name: 'document_vite', path: '/document/vite', title: 'vite文档' }],
 | 
			
		||||
  ['document_naive', { name: 'document_naive', path: '/document/naive', title: 'naive文档' }],
 | 
			
		||||
  ['component', { name: 'component', path: '/component', title: '组件插件' }],
 | 
			
		||||
  ['component_map', { name: 'component_map', path: '/component/map', title: '地图插件' }],
 | 
			
		||||
  ['component_video', { name: 'component_video', path: '/component/video', title: '视频插件' }],
 | 
			
		||||
  ['component_editor', { name: 'component_editor', path: '/component/editor', title: '编辑器' }],
 | 
			
		||||
  [
 | 
			
		||||
    'component_editor_quill',
 | 
			
		||||
    { name: 'component_editor_quill', path: '/component/editor/quill', title: '富文本编辑器' }
 | 
			
		||||
  ],
 | 
			
		||||
  [
 | 
			
		||||
    'component_editor_markdown',
 | 
			
		||||
    { name: 'component_editor_markdown', path: '/component/editor/markdown', title: 'markdown编辑器' }
 | 
			
		||||
  ],
 | 
			
		||||
  ['component_swiper', { name: 'component_swiper', path: '/component/swiper', title: 'Swiper插件' }],
 | 
			
		||||
  ['feat', { name: 'feat', path: '/feat', title: '功能示例' }],
 | 
			
		||||
  ['feat_copy', { name: 'feat_copy', path: '/feat/copy', title: '剪贴板' }],
 | 
			
		||||
  ['feat_icon', { name: 'feat_icon', path: '/feat/icon', title: '图标' }],
 | 
			
		||||
  ['feat_print', { name: 'feat_print', path: '/feat/print', title: '打印' }],
 | 
			
		||||
  ['multi-menu', { name: 'multi-menu', path: '/multi-menu', title: '多级菜单' }],
 | 
			
		||||
  ['multi-menu_first', { name: 'multi-menu_first', path: '/multi-menu/first', title: '一级菜单' }],
 | 
			
		||||
  ['multi-menu_first_second', { name: 'multi-menu_first_second', path: '/multi-menu/first/second', title: '二级菜单' }],
 | 
			
		||||
  ['exception', { name: 'exception', path: '/exception', title: '异常页' }],
 | 
			
		||||
  ['exception_403', { name: 'exception_403', path: '/exception/403', title: '异常页-403' }],
 | 
			
		||||
  ['exception_404', { name: 'exception_404', path: '/exception/404', title: '异常页-404' }],
 | 
			
		||||
  ['exception_500', { name: 'exception_500', path: '/exception/500', title: '异常页-500' }],
 | 
			
		||||
  ['about', { name: 'about', path: '/about', title: '关于' }]
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
/** 获取路由的声明(name、path、title) */
 | 
			
		||||
export function getRouteConst(key: RouteKey) {
 | 
			
		||||
  return routeConstMap.get(key)!;
 | 
			
		||||
}
 | 
			
		||||
/** 路由名称 */
 | 
			
		||||
export function routeName(key: RouteKey) {
 | 
			
		||||
  return routeConstMap.get(key)!.name;
 | 
			
		||||
}
 | 
			
		||||
/** 路由路径 */
 | 
			
		||||
export function routePath(key: RouteKey) {
 | 
			
		||||
  return routeConstMap.get(key)!.path;
 | 
			
		||||
}
 | 
			
		||||
/** 路由标题 */
 | 
			
		||||
export function routeTitle(key: RouteKey) {
 | 
			
		||||
  return routeConstMap.get(key)!.title;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										5
									
								
								src/router/export/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/router/export/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
import { getCacheRoutes, transformRouteToMenu } from '@/utils';
 | 
			
		||||
import { customRoutes, routes } from '../routes';
 | 
			
		||||
 | 
			
		||||
export const cacheRoutes = getCacheRoutes(routes);
 | 
			
		||||
export const menus = transformRouteToMenu(customRoutes);
 | 
			
		||||
@@ -1,8 +1,4 @@
 | 
			
		||||
import { getCacheRoutes, transformRouteToMenu } from '@/utils';
 | 
			
		||||
import { customRoutes, routes, ROUTE_HOME } from './routes';
 | 
			
		||||
import { router, setupRouter } from './setup';
 | 
			
		||||
 | 
			
		||||
const cacheRoutes = getCacheRoutes(routes);
 | 
			
		||||
const menus = transformRouteToMenu(customRoutes);
 | 
			
		||||
 | 
			
		||||
export { customRoutes, routes, ROUTE_HOME, router, setupRouter, cacheRoutes, menus };
 | 
			
		||||
export * from './const';
 | 
			
		||||
export * from './routes';
 | 
			
		||||
export * from './setup';
 | 
			
		||||
export * from './export';
 | 
			
		||||
 
 | 
			
		||||
@@ -1,18 +1,19 @@
 | 
			
		||||
import type { CustomRoute } from '@/interface';
 | 
			
		||||
import { EnumRoutePath, EnumRouteTitle } from '@/enum';
 | 
			
		||||
import { ROUTE_NAME_MAP, setRouterCacheName, setSingleRoute } from '@/utils';
 | 
			
		||||
import { setRouterCacheName, setSingleRoute } from '@/utils';
 | 
			
		||||
import { BasicLayout } from '@/layouts';
 | 
			
		||||
import About from '@/views/about/index.vue';
 | 
			
		||||
import { getRouteConst } from '../const';
 | 
			
		||||
 | 
			
		||||
setRouterCacheName(About, ROUTE_NAME_MAP.get('about'));
 | 
			
		||||
const { name, path, title } = getRouteConst('about');
 | 
			
		||||
setRouterCacheName(About, name);
 | 
			
		||||
 | 
			
		||||
const ABOUT: CustomRoute = setSingleRoute(BasicLayout, {
 | 
			
		||||
  name: ROUTE_NAME_MAP.get('about'),
 | 
			
		||||
  path: EnumRoutePath.about,
 | 
			
		||||
  name,
 | 
			
		||||
  path,
 | 
			
		||||
  component: About,
 | 
			
		||||
  meta: {
 | 
			
		||||
    requiresAuth: true,
 | 
			
		||||
    title: EnumRouteTitle.about,
 | 
			
		||||
    title,
 | 
			
		||||
    icon: 'fluent:book-information-24-regular'
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,90 +1,90 @@
 | 
			
		||||
import type { CustomRoute } from '@/interface';
 | 
			
		||||
import { EnumRoutePath, EnumRouteTitle } from '@/enum';
 | 
			
		||||
import { BasicLayout, RouterViewLayout } from '@/layouts';
 | 
			
		||||
import { ROUTE_NAME_MAP, setRouterCacheName } from '@/utils';
 | 
			
		||||
import { setRouterCacheName } from '@/utils';
 | 
			
		||||
import ComponentMap from '@/views/component/map/index.vue';
 | 
			
		||||
import ComponentVideo from '@/views/component/video/index.vue';
 | 
			
		||||
import EditorQuill from '@/views/component/editor/quill/index.vue';
 | 
			
		||||
import EditorMarkdown from '@/views/component/editor/markdown/index.vue';
 | 
			
		||||
import ComponentSwiper from '@/views/component/swiper/index.vue';
 | 
			
		||||
import { routeName, routePath, routeTitle } from '../const';
 | 
			
		||||
 | 
			
		||||
setRouterCacheName(ComponentMap, ROUTE_NAME_MAP.get('component_map'));
 | 
			
		||||
setRouterCacheName(ComponentVideo, ROUTE_NAME_MAP.get('component_video'));
 | 
			
		||||
setRouterCacheName(EditorQuill, ROUTE_NAME_MAP.get('component_editor_quill'));
 | 
			
		||||
setRouterCacheName(EditorMarkdown, ROUTE_NAME_MAP.get('component_editor_markdown'));
 | 
			
		||||
setRouterCacheName(ComponentSwiper, ROUTE_NAME_MAP.get('component_swiper'));
 | 
			
		||||
setRouterCacheName(ComponentMap, routeName('component_map'));
 | 
			
		||||
setRouterCacheName(ComponentVideo, routeName('component_video'));
 | 
			
		||||
setRouterCacheName(EditorQuill, routeName('component_editor_quill'));
 | 
			
		||||
setRouterCacheName(EditorMarkdown, routeName('component_editor_markdown'));
 | 
			
		||||
setRouterCacheName(ComponentSwiper, routeName('component_swiper'));
 | 
			
		||||
 | 
			
		||||
const COMPONENT: CustomRoute = {
 | 
			
		||||
  name: ROUTE_NAME_MAP.get('component'),
 | 
			
		||||
  path: EnumRoutePath.component,
 | 
			
		||||
  name: routeName('component'),
 | 
			
		||||
  path: routePath('component'),
 | 
			
		||||
  component: BasicLayout,
 | 
			
		||||
  redirect: { name: ROUTE_NAME_MAP.get('component_map') },
 | 
			
		||||
  redirect: { name: routeName('component_map') },
 | 
			
		||||
  meta: {
 | 
			
		||||
    requiresAuth: true,
 | 
			
		||||
    title: EnumRouteTitle.component,
 | 
			
		||||
    title: routeTitle('component'),
 | 
			
		||||
    icon: 'fluent:app-store-24-regular'
 | 
			
		||||
  },
 | 
			
		||||
  children: [
 | 
			
		||||
    {
 | 
			
		||||
      name: ROUTE_NAME_MAP.get('component_map'),
 | 
			
		||||
      path: EnumRoutePath.component_map,
 | 
			
		||||
      name: routeName('component_map'),
 | 
			
		||||
      path: routePath('component_map'),
 | 
			
		||||
      component: ComponentMap,
 | 
			
		||||
      meta: {
 | 
			
		||||
        requiresAuth: true,
 | 
			
		||||
        title: EnumRouteTitle.component_map,
 | 
			
		||||
        title: routeTitle('component_map'),
 | 
			
		||||
        fullPage: true
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: ROUTE_NAME_MAP.get('component_video'),
 | 
			
		||||
      path: EnumRoutePath.component_video,
 | 
			
		||||
      name: routeName('component_video'),
 | 
			
		||||
      path: routePath('component_video'),
 | 
			
		||||
      component: ComponentVideo,
 | 
			
		||||
      meta: {
 | 
			
		||||
        requiresAuth: true,
 | 
			
		||||
        title: EnumRouteTitle.component_video,
 | 
			
		||||
        title: routeTitle('component_video'),
 | 
			
		||||
        fullPage: true
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: ROUTE_NAME_MAP.get('component_editor'),
 | 
			
		||||
      path: EnumRoutePath.component_editor,
 | 
			
		||||
      name: routeName('component_editor'),
 | 
			
		||||
      path: routePath('component_editor'),
 | 
			
		||||
      component: RouterViewLayout,
 | 
			
		||||
      redirect: { name: ROUTE_NAME_MAP.get('component_editor_quill') },
 | 
			
		||||
      redirect: { name: routeName('component_editor_quill') },
 | 
			
		||||
      meta: {
 | 
			
		||||
        requiresAuth: true,
 | 
			
		||||
        title: EnumRouteTitle.component_editor,
 | 
			
		||||
        title: routeTitle('component_editor'),
 | 
			
		||||
        fullPage: true
 | 
			
		||||
      },
 | 
			
		||||
      children: [
 | 
			
		||||
        {
 | 
			
		||||
          name: ROUTE_NAME_MAP.get('component_editor_quill'),
 | 
			
		||||
          path: EnumRoutePath.component_editor_quill,
 | 
			
		||||
          name: routeName('component_editor_quill'),
 | 
			
		||||
          path: routePath('component_editor_quill'),
 | 
			
		||||
          component: EditorQuill,
 | 
			
		||||
          meta: {
 | 
			
		||||
            requiresAuth: true,
 | 
			
		||||
            title: EnumRouteTitle.component_editor_quill,
 | 
			
		||||
            title: routeTitle('component_editor_quill'),
 | 
			
		||||
            fullPage: true
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          name: ROUTE_NAME_MAP.get('component_editor_markdown'),
 | 
			
		||||
          path: EnumRoutePath.component_editor_markdown,
 | 
			
		||||
          name: routeName('component_editor_markdown'),
 | 
			
		||||
          path: routePath('component_editor_markdown'),
 | 
			
		||||
          component: EditorMarkdown,
 | 
			
		||||
          meta: {
 | 
			
		||||
            requiresAuth: true,
 | 
			
		||||
            title: EnumRouteTitle.component_editor_markdown,
 | 
			
		||||
            title: routeTitle('component_editor_markdown'),
 | 
			
		||||
            fullPage: true
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: ROUTE_NAME_MAP.get('component_swiper'),
 | 
			
		||||
      path: EnumRoutePath.component_swiper,
 | 
			
		||||
      name: routeName('component_swiper'),
 | 
			
		||||
      path: routePath('component_swiper'),
 | 
			
		||||
      component: ComponentSwiper,
 | 
			
		||||
      meta: {
 | 
			
		||||
        requiresAuth: true,
 | 
			
		||||
        title: EnumRouteTitle.component_swiper
 | 
			
		||||
        title: routeTitle('component_swiper')
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
 
 | 
			
		||||
@@ -1,31 +1,31 @@
 | 
			
		||||
import type { CustomRoute } from '@/interface';
 | 
			
		||||
import { EnumRoutePath, EnumRouteTitle } from '@/enum';
 | 
			
		||||
import { BaseLayout } from '@/layouts';
 | 
			
		||||
import { ROUTE_NAME_MAP, setRouterCacheName } from '@/utils';
 | 
			
		||||
import { ROUTE_HOME } from '../routes';
 | 
			
		||||
import { BasicLayout } from '@/layouts';
 | 
			
		||||
import { setRouterCacheName } from '@/utils';
 | 
			
		||||
import DashboardWorkbench from '@/views/dashboard/workbench/index.vue';
 | 
			
		||||
import { ROUTE_HOME } from '../routes';
 | 
			
		||||
import { routeName, routePath, routeTitle } from '../const';
 | 
			
		||||
 | 
			
		||||
setRouterCacheName(DashboardWorkbench, ROUTE_NAME_MAP.get('dashboard_workbench'));
 | 
			
		||||
setRouterCacheName(DashboardWorkbench, routeName('dashboard_workbench'));
 | 
			
		||||
 | 
			
		||||
const DASHBOARD: CustomRoute = {
 | 
			
		||||
  name: ROUTE_NAME_MAP.get('dashboard'),
 | 
			
		||||
  path: EnumRoutePath.dashboard,
 | 
			
		||||
  component: BaseLayout,
 | 
			
		||||
  redirect: { name: ROUTE_NAME_MAP.get('dashboard_analysis') },
 | 
			
		||||
  name: routeName('dashboard'),
 | 
			
		||||
  path: routePath('dashboard'),
 | 
			
		||||
  component: BasicLayout,
 | 
			
		||||
  redirect: { name: routeName('dashboard_analysis') },
 | 
			
		||||
  meta: {
 | 
			
		||||
    title: EnumRouteTitle.dashboard,
 | 
			
		||||
    title: routeTitle('dashboard_analysis'),
 | 
			
		||||
    icon: 'carbon:dashboard'
 | 
			
		||||
  },
 | 
			
		||||
  children: [
 | 
			
		||||
    ROUTE_HOME,
 | 
			
		||||
    {
 | 
			
		||||
      name: ROUTE_NAME_MAP.get('dashboard_workbench'),
 | 
			
		||||
      path: EnumRoutePath.dashboard_workbench,
 | 
			
		||||
      name: routeName('dashboard_workbench'),
 | 
			
		||||
      path: routePath('dashboard_workbench'),
 | 
			
		||||
      component: DashboardWorkbench,
 | 
			
		||||
      meta: {
 | 
			
		||||
        keepAlive: true,
 | 
			
		||||
        requiresAuth: true,
 | 
			
		||||
        title: EnumRouteTitle.dashboard_workbench
 | 
			
		||||
        title: routeTitle('dashboard_workbench')
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
 
 | 
			
		||||
@@ -1,54 +1,54 @@
 | 
			
		||||
import type { CustomRoute } from '@/interface';
 | 
			
		||||
import { EnumRoutePath, EnumRouteTitle } from '@/enum';
 | 
			
		||||
import { BasicLayout } from '@/layouts';
 | 
			
		||||
import { ROUTE_NAME_MAP, setRouterCacheName } from '@/utils';
 | 
			
		||||
import { setRouterCacheName } from '@/utils';
 | 
			
		||||
import DocumentVue from '@/views/document/vue/index.vue';
 | 
			
		||||
import DocumentVite from '@/views/document/vite/index.vue';
 | 
			
		||||
import DocumentNaive from '@/views/document/naive/index.vue';
 | 
			
		||||
import { routeName, routePath, routeTitle } from '../const';
 | 
			
		||||
 | 
			
		||||
setRouterCacheName(DocumentVue, ROUTE_NAME_MAP.get('document_vue'));
 | 
			
		||||
setRouterCacheName(DocumentVite, ROUTE_NAME_MAP.get('document_vite'));
 | 
			
		||||
setRouterCacheName(DocumentNaive, ROUTE_NAME_MAP.get('document_naive'));
 | 
			
		||||
setRouterCacheName(DocumentVue, routeName('document_vue'));
 | 
			
		||||
setRouterCacheName(DocumentVite, routeName('document_vite'));
 | 
			
		||||
setRouterCacheName(DocumentNaive, routeName('document_naive'));
 | 
			
		||||
 | 
			
		||||
const DOCUMENT: CustomRoute = {
 | 
			
		||||
  name: ROUTE_NAME_MAP.get('document'),
 | 
			
		||||
  path: EnumRoutePath.document,
 | 
			
		||||
  name: routeName('document'),
 | 
			
		||||
  path: routePath('document'),
 | 
			
		||||
  component: BasicLayout,
 | 
			
		||||
  redirect: { name: ROUTE_NAME_MAP.get('document_vue') },
 | 
			
		||||
  redirect: { name: routeName('document_vue') },
 | 
			
		||||
  meta: {
 | 
			
		||||
    requiresAuth: true,
 | 
			
		||||
    title: EnumRouteTitle.document,
 | 
			
		||||
    title: routeTitle('document'),
 | 
			
		||||
    icon: 'carbon:document'
 | 
			
		||||
  },
 | 
			
		||||
  children: [
 | 
			
		||||
    {
 | 
			
		||||
      name: ROUTE_NAME_MAP.get('document_vue'),
 | 
			
		||||
      path: EnumRoutePath.document_vue,
 | 
			
		||||
      name: routeName('document_vue'),
 | 
			
		||||
      path: routePath('document_vue'),
 | 
			
		||||
      component: DocumentVue,
 | 
			
		||||
      meta: {
 | 
			
		||||
        requiresAuth: true,
 | 
			
		||||
        title: EnumRouteTitle.document_vue,
 | 
			
		||||
        title: routeTitle('document_vue'),
 | 
			
		||||
        fullPage: true,
 | 
			
		||||
        keepAlive: true
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: ROUTE_NAME_MAP.get('document_vite'),
 | 
			
		||||
      path: EnumRoutePath.document_vite,
 | 
			
		||||
      name: routeName('document_vite'),
 | 
			
		||||
      path: routePath('document_vite'),
 | 
			
		||||
      component: DocumentVite,
 | 
			
		||||
      meta: {
 | 
			
		||||
        requiresAuth: true,
 | 
			
		||||
        title: EnumRouteTitle.document_vite,
 | 
			
		||||
        title: routeTitle('document_vite'),
 | 
			
		||||
        fullPage: true
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: ROUTE_NAME_MAP.get('document_naive'),
 | 
			
		||||
      path: EnumRoutePath.document_naive,
 | 
			
		||||
      name: routeName('document_naive'),
 | 
			
		||||
      path: routePath('document_naive'),
 | 
			
		||||
      component: DocumentNaive,
 | 
			
		||||
      meta: {
 | 
			
		||||
        requiresAuth: true,
 | 
			
		||||
        title: EnumRouteTitle.document_naive,
 | 
			
		||||
        title: routeTitle('document_naive'),
 | 
			
		||||
        fullPage: true
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,53 +1,53 @@
 | 
			
		||||
import type { CustomRoute } from '@/interface';
 | 
			
		||||
import { EnumRoutePath, EnumRouteTitle } from '@/enum';
 | 
			
		||||
import { BasicLayout } from '@/layouts';
 | 
			
		||||
import { ROUTE_NAME_MAP, setRouterCacheName } from '@/utils';
 | 
			
		||||
import { setRouterCacheName } from '@/utils';
 | 
			
		||||
import Exception403 from '@/views/system/exception/403.vue';
 | 
			
		||||
import Exception404 from '@/views/system/exception/404.vue';
 | 
			
		||||
import Exception500 from '@/views/system/exception/500.vue';
 | 
			
		||||
import { routeName, routePath, routeTitle } from '../const';
 | 
			
		||||
 | 
			
		||||
setRouterCacheName(Exception404, ROUTE_NAME_MAP.get('exception_404'));
 | 
			
		||||
setRouterCacheName(Exception403, ROUTE_NAME_MAP.get('exception_403'));
 | 
			
		||||
setRouterCacheName(Exception500, ROUTE_NAME_MAP.get('exception_500'));
 | 
			
		||||
setRouterCacheName(Exception404, routeName('exception_404'));
 | 
			
		||||
setRouterCacheName(Exception403, routeName('exception_403'));
 | 
			
		||||
setRouterCacheName(Exception500, routeName('exception_500'));
 | 
			
		||||
 | 
			
		||||
const EXCEPTION: CustomRoute = {
 | 
			
		||||
  name: ROUTE_NAME_MAP.get('exception'),
 | 
			
		||||
  path: EnumRoutePath.exception,
 | 
			
		||||
  name: routeName('exception'),
 | 
			
		||||
  path: routePath('exception'),
 | 
			
		||||
  component: BasicLayout,
 | 
			
		||||
  redirect: { name: ROUTE_NAME_MAP.get('exception_403') },
 | 
			
		||||
  redirect: { name: routeName('exception_403') },
 | 
			
		||||
  meta: {
 | 
			
		||||
    requiresAuth: true,
 | 
			
		||||
    title: EnumRouteTitle.exception,
 | 
			
		||||
    title: routeTitle('exception'),
 | 
			
		||||
    icon: 'ant-design:exception-outlined'
 | 
			
		||||
  },
 | 
			
		||||
  children: [
 | 
			
		||||
    {
 | 
			
		||||
      name: ROUTE_NAME_MAP.get('exception_403'),
 | 
			
		||||
      path: EnumRoutePath.exception_403,
 | 
			
		||||
      name: routeName('exception_403'),
 | 
			
		||||
      path: routePath('exception_403'),
 | 
			
		||||
      component: Exception403,
 | 
			
		||||
      meta: {
 | 
			
		||||
        requiresAuth: true,
 | 
			
		||||
        title: EnumRouteTitle.exception_403,
 | 
			
		||||
        title: routeTitle('exception_403'),
 | 
			
		||||
        fullPage: true
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: ROUTE_NAME_MAP.get('exception_404'),
 | 
			
		||||
      path: EnumRoutePath.exception_404,
 | 
			
		||||
      name: routeName('exception_404'),
 | 
			
		||||
      path: routePath('exception_404'),
 | 
			
		||||
      component: Exception404,
 | 
			
		||||
      meta: {
 | 
			
		||||
        requiresAuth: true,
 | 
			
		||||
        title: EnumRouteTitle.exception_404,
 | 
			
		||||
        title: routeTitle('exception_404'),
 | 
			
		||||
        fullPage: true
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: ROUTE_NAME_MAP.get('exception_500'),
 | 
			
		||||
      path: EnumRoutePath.exception_500,
 | 
			
		||||
      name: routeName('exception_500'),
 | 
			
		||||
      path: routePath('exception_500'),
 | 
			
		||||
      component: Exception500,
 | 
			
		||||
      meta: {
 | 
			
		||||
        requiresAuth: true,
 | 
			
		||||
        title: EnumRouteTitle.exception_500,
 | 
			
		||||
        title: routeTitle('exception_500'),
 | 
			
		||||
        fullPage: true
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,52 +1,52 @@
 | 
			
		||||
import type { CustomRoute } from '@/interface';
 | 
			
		||||
import { EnumRoutePath, EnumRouteTitle } from '@/enum';
 | 
			
		||||
import { BasicLayout } from '@/layouts';
 | 
			
		||||
import { ROUTE_NAME_MAP, setRouterCacheName } from '@/utils';
 | 
			
		||||
import { setRouterCacheName } from '@/utils';
 | 
			
		||||
import FeatCopy from '@/views/feat/copy/index.vue';
 | 
			
		||||
import FeatIcon from '@/views/feat/icon/index.vue';
 | 
			
		||||
import FeatPrint from '@/views/feat/print/index.vue';
 | 
			
		||||
import { routeName, routePath, routeTitle } from '../const';
 | 
			
		||||
 | 
			
		||||
setRouterCacheName(FeatCopy, ROUTE_NAME_MAP.get('feat_copy'));
 | 
			
		||||
setRouterCacheName(FeatIcon, ROUTE_NAME_MAP.get('feat_icon'));
 | 
			
		||||
setRouterCacheName(FeatPrint, ROUTE_NAME_MAP.get('feat_print'));
 | 
			
		||||
setRouterCacheName(FeatCopy, routeName('feat_copy'));
 | 
			
		||||
setRouterCacheName(FeatIcon, routeName('feat_icon'));
 | 
			
		||||
setRouterCacheName(FeatPrint, routeName('feat_print'));
 | 
			
		||||
 | 
			
		||||
const FEAT: CustomRoute = {
 | 
			
		||||
  name: ROUTE_NAME_MAP.get('feat'),
 | 
			
		||||
  path: EnumRoutePath.feat,
 | 
			
		||||
  name: routeName('feat'),
 | 
			
		||||
  path: routePath('feat'),
 | 
			
		||||
  component: BasicLayout,
 | 
			
		||||
  redirect: { name: ROUTE_NAME_MAP.get('feat_copy') },
 | 
			
		||||
  redirect: { name: routeName('feat_copy') },
 | 
			
		||||
  meta: {
 | 
			
		||||
    requiresAuth: true,
 | 
			
		||||
    title: EnumRouteTitle.feat,
 | 
			
		||||
    title: routeTitle('feat'),
 | 
			
		||||
    icon: 'ic:round-repeat'
 | 
			
		||||
  },
 | 
			
		||||
  children: [
 | 
			
		||||
    {
 | 
			
		||||
      name: ROUTE_NAME_MAP.get('feat_copy'),
 | 
			
		||||
      path: EnumRoutePath.feat_copy,
 | 
			
		||||
      name: routeName('feat_copy'),
 | 
			
		||||
      path: routePath('feat_copy'),
 | 
			
		||||
      component: FeatCopy,
 | 
			
		||||
      meta: {
 | 
			
		||||
        requiresAuth: true,
 | 
			
		||||
        title: EnumRouteTitle.feat_copy,
 | 
			
		||||
        title: routeTitle('feat_copy'),
 | 
			
		||||
        fullPage: true
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: ROUTE_NAME_MAP.get('feat_icon'),
 | 
			
		||||
      path: EnumRoutePath.feat_icon,
 | 
			
		||||
      name: routeName('feat_icon'),
 | 
			
		||||
      path: routePath('feat_icon'),
 | 
			
		||||
      component: FeatIcon,
 | 
			
		||||
      meta: {
 | 
			
		||||
        requiresAuth: true,
 | 
			
		||||
        title: EnumRouteTitle.feat_icon
 | 
			
		||||
        title: routeTitle('feat_icon')
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: ROUTE_NAME_MAP.get('feat_print'),
 | 
			
		||||
      path: EnumRoutePath.feat_print,
 | 
			
		||||
      name: routeName('feat_print'),
 | 
			
		||||
      path: routePath('feat_print'),
 | 
			
		||||
      component: FeatPrint,
 | 
			
		||||
      meta: {
 | 
			
		||||
        requiresAuth: true,
 | 
			
		||||
        title: EnumRouteTitle.feat_print
 | 
			
		||||
        title: routeTitle('feat_print')
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
 
 | 
			
		||||
@@ -1,40 +1,41 @@
 | 
			
		||||
import type { CustomRoute } from '@/interface';
 | 
			
		||||
import { EnumRoutePath, EnumRouteTitle } from '@/enum';
 | 
			
		||||
import { BasicLayout, RouterViewLayout } from '@/layouts';
 | 
			
		||||
import { ROUTE_NAME_MAP, setRouterCacheName } from '@/utils';
 | 
			
		||||
import { setRouterCacheName } from '@/utils';
 | 
			
		||||
import MultiMenuFirstSecond from '@/views/multi-menu/first/second/index.vue';
 | 
			
		||||
import { routeName, routePath, routeTitle } from '../const';
 | 
			
		||||
 | 
			
		||||
setRouterCacheName(MultiMenuFirstSecond, ROUTE_NAME_MAP.get('multi-menu_first_second'));
 | 
			
		||||
setRouterCacheName(MultiMenuFirstSecond, routeName('multi-menu_first_second'));
 | 
			
		||||
 | 
			
		||||
const MULTI_MENU: CustomRoute = {
 | 
			
		||||
  name: ROUTE_NAME_MAP.get('multi-menu'),
 | 
			
		||||
  path: EnumRoutePath['multi-menu'],
 | 
			
		||||
  name: routeName('multi-menu'),
 | 
			
		||||
  path: routePath('multi-menu'),
 | 
			
		||||
  component: BasicLayout,
 | 
			
		||||
  redirect: { name: ROUTE_NAME_MAP.get('multi-menu_first') },
 | 
			
		||||
  redirect: { name: routeName('multi-menu_first') },
 | 
			
		||||
  meta: {
 | 
			
		||||
    title: EnumRouteTitle['multi-menu'],
 | 
			
		||||
    title: routeTitle('multi-menu'),
 | 
			
		||||
    icon: 'carbon:menu'
 | 
			
		||||
  },
 | 
			
		||||
  children: [
 | 
			
		||||
    {
 | 
			
		||||
      name: ROUTE_NAME_MAP.get('multi-menu_first'),
 | 
			
		||||
      path: EnumRoutePath['multi-menu_first'],
 | 
			
		||||
      name: routeName('multi-menu_first'),
 | 
			
		||||
      path: routePath('multi-menu_first'),
 | 
			
		||||
      component: RouterViewLayout,
 | 
			
		||||
      redirect: { name: ROUTE_NAME_MAP.get('multi-menu_first_second') },
 | 
			
		||||
      redirect: { name: routeName('multi-menu_first_second') },
 | 
			
		||||
      meta: {
 | 
			
		||||
        keepAlive: true,
 | 
			
		||||
        requiresAuth: true,
 | 
			
		||||
        title: EnumRouteTitle['multi-menu_first']
 | 
			
		||||
        title: routeTitle('multi-menu_first_second')
 | 
			
		||||
      },
 | 
			
		||||
      children: [
 | 
			
		||||
        {
 | 
			
		||||
          name: ROUTE_NAME_MAP.get('multi-menu_first_second'),
 | 
			
		||||
          path: EnumRoutePath['multi-menu_first_second'],
 | 
			
		||||
          name: routeName('multi-menu_first_second'),
 | 
			
		||||
          path: routePath('multi-menu_first_second'),
 | 
			
		||||
          component: MultiMenuFirstSecond,
 | 
			
		||||
          meta: {
 | 
			
		||||
            keepAlive: true,
 | 
			
		||||
            requiresAuth: true,
 | 
			
		||||
            title: EnumRouteTitle['multi-menu_first_second']
 | 
			
		||||
            title: routeTitle('multi-menu_first_second'),
 | 
			
		||||
            fullPage: true
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      ]
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,10 @@
 | 
			
		||||
import type { CustomRoute } from '@/interface';
 | 
			
		||||
import { EnumRoutePath } from '@/enum';
 | 
			
		||||
import { ROUTE_NAME_MAP } from '@/utils';
 | 
			
		||||
import { routeName, routePath } from '../const';
 | 
			
		||||
import { ROUTE_HOME } from '../routes';
 | 
			
		||||
 | 
			
		||||
const ROOT: CustomRoute = {
 | 
			
		||||
  name: ROUTE_NAME_MAP.get('root'),
 | 
			
		||||
  path: EnumRoutePath.root,
 | 
			
		||||
  name: routeName('root'),
 | 
			
		||||
  path: routePath('root'),
 | 
			
		||||
  redirect: { name: ROUTE_HOME.name },
 | 
			
		||||
  meta: {
 | 
			
		||||
    isNotMenu: true
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
import type { Router, RouteLocationNormalized, NavigationGuardNext } from 'vue-router';
 | 
			
		||||
import { useTitle } from '@vueuse/core';
 | 
			
		||||
import { getToken, getLoginRedirectUrl, ROUTE_NAME_MAP } from '@/utils';
 | 
			
		||||
import { routeName } from '@/router';
 | 
			
		||||
import { getToken, getLoginRedirectUrl } from '@/utils';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 路由守卫函数
 | 
			
		||||
@@ -29,9 +30,9 @@ function handleRouterAction(to: RouteLocationNormalized, from: RouteLocationNorm
 | 
			
		||||
  const routerAction: [boolean, () => void][] = [
 | 
			
		||||
    // 已登录状态跳转登录页,跳转至首页
 | 
			
		||||
    [
 | 
			
		||||
      isLogin && to.name === ROUTE_NAME_MAP.get('login'),
 | 
			
		||||
      isLogin && to.name === routeName('login'),
 | 
			
		||||
      () => {
 | 
			
		||||
        next({ name: ROUTE_NAME_MAP.get('root') });
 | 
			
		||||
        next({ name: routeName('root') });
 | 
			
		||||
      }
 | 
			
		||||
    ],
 | 
			
		||||
    // 不需要登录权限的页面直接通行
 | 
			
		||||
@@ -46,7 +47,7 @@ function handleRouterAction(to: RouteLocationNormalized, from: RouteLocationNorm
 | 
			
		||||
      !isLogin && needLogin,
 | 
			
		||||
      () => {
 | 
			
		||||
        const redirectUrl = getLoginRedirectUrl();
 | 
			
		||||
        next({ name: ROUTE_NAME_MAP.get('login'), query: { redirectUrl } });
 | 
			
		||||
        next({ name: routeName('login'), query: { redirectUrl } });
 | 
			
		||||
      }
 | 
			
		||||
    ],
 | 
			
		||||
    // 登录状态进入需要登录权限的页面,直接通行
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,11 @@
 | 
			
		||||
import type { RouteRecordRaw } from 'vue-router';
 | 
			
		||||
import { EnumRoutePath, EnumRouteTitle } from '@/enum';
 | 
			
		||||
import { BlankLayout } from '@/layouts';
 | 
			
		||||
import type { LoginModuleType } from '@/interface';
 | 
			
		||||
import { ROUTE_NAME_MAP } from '@/utils';
 | 
			
		||||
import Login from '@/views/system/login/index.vue';
 | 
			
		||||
import NoPermission from '@/views/system/exception/403.vue';
 | 
			
		||||
import NotFound from '@/views/system/exception/404.vue';
 | 
			
		||||
import ServiceError from '@/views/system/exception/500.vue';
 | 
			
		||||
import { routeName, routePath, routeTitle } from '../const';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 固定不变的路由
 | 
			
		||||
@@ -17,15 +16,15 @@ const constantRoutes: RouteRecordRaw[] = [
 | 
			
		||||
    name: 'single_',
 | 
			
		||||
    path: '/single_',
 | 
			
		||||
    component: BlankLayout,
 | 
			
		||||
    redirect: { name: ROUTE_NAME_MAP.get('not-found') },
 | 
			
		||||
    redirect: { name: routeName('not-found') },
 | 
			
		||||
    meta: {
 | 
			
		||||
      keepAlive: true
 | 
			
		||||
    },
 | 
			
		||||
    children: [
 | 
			
		||||
      // 登录
 | 
			
		||||
      {
 | 
			
		||||
        name: ROUTE_NAME_MAP.get('login'),
 | 
			
		||||
        path: EnumRoutePath.login,
 | 
			
		||||
        name: routeName('login'),
 | 
			
		||||
        path: routePath('login'),
 | 
			
		||||
        component: Login,
 | 
			
		||||
        props: route => {
 | 
			
		||||
          const moduleType: LoginModuleType = (route.query?.module as LoginModuleType) || 'pwd-login';
 | 
			
		||||
@@ -34,37 +33,37 @@ const constantRoutes: RouteRecordRaw[] = [
 | 
			
		||||
          };
 | 
			
		||||
        },
 | 
			
		||||
        meta: {
 | 
			
		||||
          title: EnumRouteTitle.login,
 | 
			
		||||
          title: routeTitle('login'),
 | 
			
		||||
          fullPage: true
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      // 403
 | 
			
		||||
      {
 | 
			
		||||
        name: ROUTE_NAME_MAP.get('no-permission'),
 | 
			
		||||
        path: EnumRoutePath['no-permission'],
 | 
			
		||||
        name: routeName('no-permission'),
 | 
			
		||||
        path: routePath('no-permission'),
 | 
			
		||||
        component: NoPermission,
 | 
			
		||||
        meta: {
 | 
			
		||||
          title: EnumRouteTitle['no-permission'],
 | 
			
		||||
          title: routeTitle('no-permission'),
 | 
			
		||||
          fullPage: true
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      // 404
 | 
			
		||||
      {
 | 
			
		||||
        name: ROUTE_NAME_MAP.get('not-found'),
 | 
			
		||||
        path: EnumRoutePath['not-found'],
 | 
			
		||||
        name: routeName('not-found'),
 | 
			
		||||
        path: routePath('not-found'),
 | 
			
		||||
        component: NotFound,
 | 
			
		||||
        meta: {
 | 
			
		||||
          title: EnumRouteTitle['not-found'],
 | 
			
		||||
          title: routeTitle('not-found'),
 | 
			
		||||
          fullPage: true
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      // 500
 | 
			
		||||
      {
 | 
			
		||||
        name: ROUTE_NAME_MAP.get('service-error'),
 | 
			
		||||
        path: EnumRoutePath['service-error'],
 | 
			
		||||
        name: routeName('service-error'),
 | 
			
		||||
        path: routePath('service-error'),
 | 
			
		||||
        component: ServiceError,
 | 
			
		||||
        meta: {
 | 
			
		||||
          title: EnumRouteTitle['service-error'],
 | 
			
		||||
          title: routeTitle('service-error'),
 | 
			
		||||
          fullPage: true
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
@@ -73,7 +72,7 @@ const constantRoutes: RouteRecordRaw[] = [
 | 
			
		||||
  // 匹配无效的路径重定向404
 | 
			
		||||
  {
 | 
			
		||||
    path: '/:pathMatch(.*)*',
 | 
			
		||||
    redirect: { name: 'not-found' }
 | 
			
		||||
    redirect: { name: routeName('not-found') }
 | 
			
		||||
  }
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,18 +1,20 @@
 | 
			
		||||
import type { CustomRoute } from '@/interface';
 | 
			
		||||
import { EnumRoutePath, EnumRouteTitle } from '@/enum';
 | 
			
		||||
import { ROUTE_NAME_MAP, setRouterCacheName } from '@/utils';
 | 
			
		||||
import { setRouterCacheName } from '@/utils';
 | 
			
		||||
import DashboardAnalysis from '@/views/dashboard/analysis/index.vue';
 | 
			
		||||
import { getRouteConst } from '../const';
 | 
			
		||||
 | 
			
		||||
setRouterCacheName(DashboardAnalysis, ROUTE_NAME_MAP.get('dashboard_analysis'));
 | 
			
		||||
const { name, path, title } = getRouteConst('dashboard_analysis');
 | 
			
		||||
 | 
			
		||||
setRouterCacheName(DashboardAnalysis, name);
 | 
			
		||||
 | 
			
		||||
/** 路由首页 */
 | 
			
		||||
const ROUTE_HOME: CustomRoute = {
 | 
			
		||||
  name: ROUTE_NAME_MAP.get('dashboard_analysis'),
 | 
			
		||||
  path: EnumRoutePath.dashboard_analysis,
 | 
			
		||||
  name,
 | 
			
		||||
  path,
 | 
			
		||||
  component: DashboardAnalysis,
 | 
			
		||||
  meta: {
 | 
			
		||||
    requiresAuth: true,
 | 
			
		||||
    title: EnumRouteTitle.dashboard_analysis
 | 
			
		||||
    title
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ type ResponseFail = [any, null];
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 封装各个请求方法及结果处理的类
 | 
			
		||||
 * @author Soybean(曹理斌) 2021-03-15
 | 
			
		||||
 * @author Soybean<honghuangdc@gmail.com> 2021-03-15
 | 
			
		||||
 * @class Request
 | 
			
		||||
 */
 | 
			
		||||
class Request {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,2 +1,2 @@
 | 
			
		||||
export * from './theme';
 | 
			
		||||
export * from './constant';
 | 
			
		||||
export * from './sdk';
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,7 @@
 | 
			
		||||
import type { Component } from 'vue';
 | 
			
		||||
import { EnumRoutePath } from '@/enum';
 | 
			
		||||
import type { RoutePathKey, CustomRoute } from '@/interface';
 | 
			
		||||
import type { CustomRoute } from '@/interface';
 | 
			
		||||
import { router } from '@/router';
 | 
			
		||||
 | 
			
		||||
/** 获取路由name map */
 | 
			
		||||
function getRouteNameMap() {
 | 
			
		||||
  return new Map<RoutePathKey, RoutePathKey>((Object.keys(EnumRoutePath) as RoutePathKey[]).map(v => [v, v]));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 路由名称 */
 | 
			
		||||
export const ROUTE_NAME_MAP = getRouteNameMap();
 | 
			
		||||
 | 
			
		||||
/** 给需要缓存的页面组件设置名称 */
 | 
			
		||||
export function setRouterCacheName(component: Component, name?: string) {
 | 
			
		||||
  if (name) {
 | 
			
		||||
@@ -20,8 +11,8 @@ export function setRouterCacheName(component: Component, name?: string) {
 | 
			
		||||
 | 
			
		||||
/** 获取登录后的重定向地址 */
 | 
			
		||||
export function getLoginRedirectUrl() {
 | 
			
		||||
  const path = router.currentRoute.value.fullPath as EnumRoutePath;
 | 
			
		||||
  const redirectUrl = path === EnumRoutePath.root ? undefined : path;
 | 
			
		||||
  const path = router.currentRoute.value.fullPath as string;
 | 
			
		||||
  const redirectUrl = path === '/' ? undefined : path;
 | 
			
		||||
  return redirectUrl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -31,12 +22,12 @@ export function getLoginRedirectUrl() {
 | 
			
		||||
 * @param notFoundName - 404未找到的路由名称
 | 
			
		||||
 * @param container - 路由容器
 | 
			
		||||
 */
 | 
			
		||||
export function setSingleRoute(container: Component, route: CustomRoute) {
 | 
			
		||||
export function setSingleRoute(container: Component, route: CustomRoute, notFoundName = 'not-found') {
 | 
			
		||||
  const routeItem: CustomRoute = {
 | 
			
		||||
    name: `${route.name as string}_`,
 | 
			
		||||
    path: `${route.path}_`,
 | 
			
		||||
    component: container,
 | 
			
		||||
    redirect: { name: ROUTE_NAME_MAP.get('not-found') },
 | 
			
		||||
    redirect: { name: notFoundName },
 | 
			
		||||
    meta: {
 | 
			
		||||
      isNotMenu: true
 | 
			
		||||
    },
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,10 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div>多级菜单-二级菜单</div>
 | 
			
		||||
  <div>
 | 
			
		||||
    <n-card title="多级菜单-二级菜单" class="h-full shadow-sm rounded-16px"></n-card>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts"></script>
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { NCard } from 'naive-ui';
 | 
			
		||||
</script>
 | 
			
		||||
<style scoped></style>
 | 
			
		||||
 
 | 
			
		||||
@@ -23,10 +23,11 @@
 | 
			
		||||
import { reactive, ref } from 'vue';
 | 
			
		||||
import { NForm, NFormItem, NInput, NSpace, NButton, useMessage } from 'naive-ui';
 | 
			
		||||
import type { FormInst } from 'naive-ui';
 | 
			
		||||
import { useRouterChange, useSmsCode } from '@/hooks';
 | 
			
		||||
import { useRouterPush } from '@/composables';
 | 
			
		||||
import { useSmsCode } from '@/hooks';
 | 
			
		||||
 | 
			
		||||
const message = useMessage();
 | 
			
		||||
const { toCurrentLogin } = useRouterChange();
 | 
			
		||||
const { toCurrentLogin } = useRouterPush();
 | 
			
		||||
const { label, isCounting, start } = useSmsCode();
 | 
			
		||||
 | 
			
		||||
const formRef = ref<(HTMLElement & FormInst) | null>(null);
 | 
			
		||||
 
 | 
			
		||||
@@ -36,13 +36,14 @@ import { NForm, NFormItem, NInput, NSpace, NCheckbox, NButton, useNotification }
 | 
			
		||||
import type { FormInst, FormRules } from 'naive-ui';
 | 
			
		||||
import { EnumLoginModule } from '@/enum';
 | 
			
		||||
import { useAuthStore } from '@/store';
 | 
			
		||||
import { useRouterChange, useRouteQuery, useLoading } from '@/hooks';
 | 
			
		||||
import { useRouterPush, useRouteQuery } from '@/composables';
 | 
			
		||||
import { useLoading } from '@/hooks';
 | 
			
		||||
import { setToken } from '@/utils';
 | 
			
		||||
import { OtherLogin } from './components';
 | 
			
		||||
 | 
			
		||||
const notification = useNotification();
 | 
			
		||||
const auth = useAuthStore();
 | 
			
		||||
const { toHome, toCurrentLogin, toLoginRedirectUrl } = useRouterChange();
 | 
			
		||||
const { toHome, toCurrentLogin, toLoginRedirectUrl } = useRouterPush();
 | 
			
		||||
const { loginRedirectUrl } = useRouteQuery();
 | 
			
		||||
const { loading, startLoading, endLoading } = useLoading();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -30,10 +30,11 @@
 | 
			
		||||
import { reactive, ref } from 'vue';
 | 
			
		||||
import { NForm, NFormItem, NInput, NSpace, NCheckbox, NButton, useMessage } from 'naive-ui';
 | 
			
		||||
import type { FormInst } from 'naive-ui';
 | 
			
		||||
import { useRouterChange, useSmsCode } from '@/hooks';
 | 
			
		||||
import { useRouterPush } from '@/composables';
 | 
			
		||||
import { useSmsCode } from '@/hooks';
 | 
			
		||||
 | 
			
		||||
const message = useMessage();
 | 
			
		||||
const { toCurrentLogin } = useRouterChange();
 | 
			
		||||
const { toCurrentLogin } = useRouterPush();
 | 
			
		||||
const { label, isCounting, start } = useSmsCode();
 | 
			
		||||
 | 
			
		||||
const formRef = ref<(HTMLElement & FormInst) | null>(null);
 | 
			
		||||
 
 | 
			
		||||
@@ -29,10 +29,11 @@
 | 
			
		||||
import { reactive, ref } from 'vue';
 | 
			
		||||
import { NForm, NFormItem, NInput, NSpace, NButton, useMessage } from 'naive-ui';
 | 
			
		||||
import type { FormInst } from 'naive-ui';
 | 
			
		||||
import { useRouterChange, useSmsCode } from '@/hooks';
 | 
			
		||||
import { useRouterPush } from '@/composables';
 | 
			
		||||
import { useSmsCode } from '@/hooks';
 | 
			
		||||
 | 
			
		||||
const message = useMessage();
 | 
			
		||||
const { toCurrentLogin } = useRouterChange();
 | 
			
		||||
const { toCurrentLogin } = useRouterPush();
 | 
			
		||||
const { label, isCounting, start } = useSmsCode();
 | 
			
		||||
 | 
			
		||||
const formRef = ref<(HTMLElement & FormInst) | null>(null);
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@ import { computed } from 'vue';
 | 
			
		||||
import type { Component } from 'vue';
 | 
			
		||||
import { NCard, NGradientText } from 'naive-ui';
 | 
			
		||||
import { SystemLogo, LoginBg } from '@/components';
 | 
			
		||||
import { useAppTitle } from '@/hooks';
 | 
			
		||||
import { useAppTitle } from '@/composables';
 | 
			
		||||
import { EnumLoginModule } from '@/enum';
 | 
			
		||||
import { mixColor } from '@/utils';
 | 
			
		||||
import type { LoginModuleType } from '@/interface';
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user