first commit

This commit is contained in:
muzi
2025-06-16 14:42:26 +08:00
commit 6f06721506
149 changed files with 56883 additions and 0 deletions

View File

@ -0,0 +1,16 @@
import { appRoutes, appExternalRoutes } from '../routes';
const mixinRoutes = [...appRoutes, ...appExternalRoutes];
const appClientMenus = mixinRoutes.map((el) => {
const { name, path, meta, redirect, children } = el;
return {
name,
path,
meta,
redirect,
children,
};
});
export default mixinRoutes;

25
src/router/constants.ts Normal file
View File

@ -0,0 +1,25 @@
/*
* @Author: 田鑫
* @Date: 2023-03-05 18:14:17
* @LastEditors: 田鑫
* @LastEditTime: 2023-03-05 18:24:40
* @Description:
*/
export const WHITE_LIST = [
{ name: 'notFound', children: [] },
{ name: 'login', children: [] },
];
export const NOT_FOUND = {
name: 'notFound',
};
export const REDIRECT_ROUTE_NAME = 'Redirect';
export const DEFAULT_ROUTE_NAME = 'main';
export const DEFAULT_ROUTE = {
title: '首页',
name: DEFAULT_ROUTE_NAME,
fullPath: '/',
};

24
src/router/guard/index.ts Normal file
View File

@ -0,0 +1,24 @@
/*
* @Author: 田鑫
* @Date: 2023-03-05 18:14:17
* @LastEditors: 田鑫
* @LastEditTime: 2023-03-05 19:21:15
* @Description:
*/
import type { Router } from 'vue-router';
import { setRouteEmitter } from '@/utils/route-listener';
import setupUserLoginInfoGuard from './userLoginInfo';
import setupPermissionGuard from './permission';
function setupPageGuard(router: Router) {
router.beforeEach(async (to) => {
// emit route change
setRouteEmitter(to);
});
}
export default function createRouteGuard(router: Router) {
setupPageGuard(router);
setupUserLoginInfoGuard(router);
setupPermissionGuard(router);
}

View File

@ -0,0 +1,29 @@
/*
* @Author: 田鑫
* @Date: 2023-03-05 14:46:43
* @LastEditors: 田鑫
* @LastEditTime: 2023-03-05 15:55:36
* @Description: 路由权限守卫
*/
import type { Router, RouteRecordNormalized } from 'vue-router';
import NProgress from 'nprogress'; // progress bar
import { useAppStore } from '@/stores';
export default function setupPermissionGuard(router: Router) {
router.beforeEach(async (to, from, next) => {
console.log('access permission router guard');
const appStore = useAppStore();
//* 菜单是否为服务端渲染
if (appStore.menuFromServer) {
//* 没有服务端渲染的菜单
if(!appStore.appAsyncMenus) {
// todo 请求服务端渲染菜单的接口当前为mock数据
await appStore.fetchServerMenuConfig();
}
next();
} else {
next();
}
NProgress.done();
});
}

View File

@ -0,0 +1,43 @@
/*
* @Author: 田鑫
* @Date: 2023-03-05 14:46:43
* @LastEditors: 田鑫
* @LastEditTime: 2023-03-05 15:59:25
* @Description: 路由登录状态守卫
*/
import type { Router, LocationQueryRaw } from 'vue-router';
import NProgress from 'nprogress'; // progress bar
import { isLogin, clearAllLocalStorage } from '@/utils/auth';
import { useUserStore } from '@/stores/modules/user';
export default function setupUserLoginInfoGuard(router: Router) {
router.beforeEach(async (to, from, next) => {
console.log('access login info router guard');
NProgress.start();
if (to.name === 'auth') {
next();
}
const userStore = useUserStore();
//* 判断用户是否登录,若登录则放过,进入下一步
//* 若无,则清空所有缓存并弹回登录鉴权页
if (isLogin()) {
if (userStore.role) {
next();
} else {
userStore.getUserInfo();
next();
}
} else {
clearAllLocalStorage();
// todo 跳转回登录鉴权页当前为mock路由地址
next({
name: 'auth',
query: {
redirect: to.name,
...to.query,
} as LocationQueryRaw,
});
}
});
}

50
src/router/index.ts Normal file
View File

@ -0,0 +1,50 @@
/*
* @Author: 田鑫
* @Date: 2023-03-05 18:14:17
* @LastEditors: 田鑫
* @LastEditTime: 2023-03-05 19:20:40
* @Description:
*/
import { createRouter, createWebHistory } from 'vue-router';
import { appRoutes } from './routes';
import { REDIRECT_MAIN, NOT_FOUND_ROUTE } from './routes/base';
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
import createRouteGuard from './guard';
NProgress.configure({ showSpinner: false }); // NProgress Configuration
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'workplace',
component: () => import('@/views/components/workplace'),
},
{
path: '/dataEngine',
name: 'dataEngine',
redirect: '@/views/components/dataEngine',
children: [...appRoutes, REDIRECT_MAIN, NOT_FOUND_ROUTE],
},
{
path: '/permission',
name: 'permission',
component: () => import('@/views/components/permission/choose-enterprise.vue'),
},
{
path: '/auth',
name: 'auth',
component: () => import('@/views/components/permission/auth.vue'),
},
],
scrollBehavior() {
return { top: 0 };
},
});
createRouteGuard(router);
export default router;

28
src/router/routes/base.ts Normal file
View File

@ -0,0 +1,28 @@
import type { RouteRecordRaw } from 'vue-router';
import { REDIRECT_ROUTE_NAME } from '@/router/constants';
export const REDIRECT_MAIN: RouteRecordRaw = {
path: '/redirect',
name: 'redirect',
meta: {
requiresAuth: true,
hideInMenu: true,
},
children: [
{
path: '/redirect/:path',
name: REDIRECT_ROUTE_NAME,
component: () => import('@/layouts/Basic.vue'),
meta: {
requiresAuth: true,
hideInMenu: true,
},
},
],
};
export const NOT_FOUND_ROUTE: RouteRecordRaw = {
path: '/:pathMatch(.*)*',
name: 'notFound',
component: () => import('@/layouts/NotFound.vue'),
};

View File

@ -0,0 +1,20 @@
import type { RouteRecordNormalized } from 'vue-router';
const modules = import.meta.glob('./modules/*.ts', { eager: true });
const externalModules = import.meta.glob('./externalModules/*.ts', {
eager: true,
});
function formatModules(_modules: any, result: RouteRecordNormalized[]) {
Object.keys(_modules).forEach((key) => {
const defaultModule = _modules[key].default;
if (!defaultModule) return;
const moduleList = Array.isArray(defaultModule) ? [...defaultModule] : [defaultModule];
result.push(...moduleList);
});
return result;
}
export const appRoutes: RouteRecordNormalized[] = formatModules(modules, []);
export const appExternalRoutes: RouteRecordNormalized[] = formatModules(externalModules, []);

View File

@ -0,0 +1,77 @@
import { IconBookmark } from '@arco-design/web-vue/es/icon';
import type { AppRouteRecordRaw } from '../types';
const COMPONENTS: AppRouteRecordRaw = {
path: 'dataEngine',
name: 'dataEngine',
meta: {
locale: '全域数据引擎',
icon: IconBookmark,
requiresAuth: true,
roles: ['*'],
},
children: [
{
path: 'hotTranslation',
name: '行业热门话题洞察',
meta: {
locale: '行业热门话题洞察',
requiresAuth: true,
roles: ['*'],
},
component: () => import('@/views/components/dataEngine/hotTranslation.vue'),
},
{
path: 'hotCloud',
name: '行业词云',
meta: {
locale: '行业词云',
requiresAuth: true,
roles: ['*'],
},
component: () => import('@/views/components/dataEngine/hotCloud.vue'),
},
{
path: 'keyWord',
name: '行业关键词动向',
meta: {
locale: '行业关键词动向',
requiresAuth: true,
roles: ['*'],
},
component: () => import('@/views/components/dataEngine/keyWord.vue'),
},
{
path: 'userPainPoints',
name: '用户痛点观察',
meta: {
locale: '用户痛点观察',
requiresAuth: true,
roles: ['*'],
},
component: () => import('@/views/components/dataEngine/userPainPoints.vue'),
},
{
path: 'keyBrandMovement',
name: '重点品牌动向',
meta: {
locale: '重点品牌动向',
requiresAuth: true,
roles: ['*'],
},
component: () => import('@/views/components/dataEngine/keyBrandMovement.vue'),
},
{
path: 'userPersona',
name: '用户画像',
meta: {
locale: '用户画像',
requiresAuth: true,
roles: ['*'],
},
component: () => import('@/views/components/dataEngine/userPersona.vue'),
},
],
};
export default COMPONENTS;

View File

@ -0,0 +1,14 @@
import type { RouteMeta, NavigationGuard, RouteComponent } from 'vue-router';
export interface AppRouteRecordRaw {
path: string;
name?: string | symbol;
meta?: RouteMeta;
redirect?: string;
component?: RouteComponent;
children?: AppRouteRecordRaw[];
alias?: string | string[];
props?: Record<string, any>;
beforeEnter?: NavigationGuard | NavigationGuard[];
fullPath?: string;
}

17
src/router/typeings.d.ts vendored Normal file
View File

@ -0,0 +1,17 @@
import { RouteComponent } from 'vue-router';
declare module 'vue-router' {
interface RouteMeta {
roles?: string[]; // Controls roles that have access to the page
requiresAuth: boolean; // Whether login is required to access the current page (every route must declare)
icon?: RouteComponent; // The icon show in the side menu
locale?: string; // The locale name show in side menu and breadcrumb
needNavigate?: boolean; // if set true, the breadcrumb will support navigate
hideInMenu?: boolean; // If true, it is not displayed in the side menu
hideChildrenInMenu?: boolean; // if set true, the children are not displayed in the side menu
activeMenu?: string; // if set name, the menu will be highlighted according to the name you set
order?: number; // Sort routing menu items. If set key, the higher the value, the more forward it is
noAffix?: boolean; // if set true, the tag will not affix in the tab-bar
ignoreCache?: boolean; // if set true, the page will not be cached
}
}