feat: 完善 ele 的请求、路由、百度统计、概览、登录
This commit is contained in:
@@ -1,21 +1,21 @@
|
||||
import type {
|
||||
AppRouteRecordRaw,
|
||||
ComponentRecordType,
|
||||
GenerateMenuAndRoutesOptions,
|
||||
} from '@vben/types';
|
||||
|
||||
import { generateAccessible } from '@vben/access';
|
||||
import { preferences } from '@vben/preferences';
|
||||
import { useAccessStore } from '@vben/stores';
|
||||
import { convertServerMenuToRouteRecordStringComponent } from '@vben/utils';
|
||||
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
import { getAllMenusApi } from '#/api';
|
||||
import { BasicLayout, IFrameView } from '#/layouts';
|
||||
import { $t } from '#/locales';
|
||||
|
||||
const forbiddenComponent = () => import('#/views/_core/fallback/forbidden.vue');
|
||||
|
||||
async function generateAccess(options: GenerateMenuAndRoutesOptions) {
|
||||
const pageMap: ComponentRecordType = import.meta.glob('../views/**/*.vue');
|
||||
const accessStore = useAccessStore();
|
||||
|
||||
const layoutMap: ComponentRecordType = {
|
||||
BasicLayout,
|
||||
@@ -25,11 +25,10 @@ async function generateAccess(options: GenerateMenuAndRoutesOptions) {
|
||||
return await generateAccessible(preferences.app.accessMode, {
|
||||
...options,
|
||||
fetchMenuListAsync: async () => {
|
||||
ElMessage({
|
||||
duration: 1500,
|
||||
message: `${$t('common.loadingMenu')}...`,
|
||||
});
|
||||
return await getAllMenusApi();
|
||||
// 由于 yudao 通过 accessStore 读取,所以不在进行 message.loading 提示
|
||||
// 补充说明:accessStore.accessMenus 一开始是 AppRouteRecordRaw 类型(后端加载),后面被赋值成 MenuRecordRaw 类型(前端转换)
|
||||
const accessMenus = accessStore.accessMenus as AppRouteRecordRaw[];
|
||||
return convertServerMenuToRouteRecordStringComponent(accessMenus);
|
||||
},
|
||||
// 可以指定没有权限跳转403页面
|
||||
forbiddenComponent,
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import type { Router } from 'vue-router';
|
||||
|
||||
import { LOGIN_PATH } from '@vben/constants';
|
||||
import { $t } from '@vben/locales';
|
||||
import { preferences } from '@vben/preferences';
|
||||
import { useAccessStore, useUserStore } from '@vben/stores';
|
||||
import { startProgress, stopProgress } from '@vben/utils';
|
||||
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
import { getSimpleDictDataList } from '#/api/system/dict/data';
|
||||
import { accessRoutes, coreRouteNames } from '#/router/routes';
|
||||
import { useAuthStore } from '#/store';
|
||||
import { useAuthStore, useDictStore } from '#/store';
|
||||
|
||||
import { generateAccess } from './access';
|
||||
|
||||
@@ -49,6 +53,7 @@ function setupAccessGuard(router: Router) {
|
||||
const accessStore = useAccessStore();
|
||||
const userStore = useUserStore();
|
||||
const authStore = useAuthStore();
|
||||
const dictStore = useDictStore();
|
||||
|
||||
// 基本路由,这些路由不需要进入权限拦截
|
||||
if (coreRouteNames.includes(to.name as string)) {
|
||||
@@ -90,10 +95,29 @@ function setupAccessGuard(router: Router) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 加载字典数据(不阻塞加载)
|
||||
dictStore.setDictCacheByApi(getSimpleDictDataList);
|
||||
|
||||
// 生成路由表
|
||||
// 当前登录用户拥有的角色标识列表
|
||||
const userInfo = userStore.userInfo || (await authStore.fetchUserInfo());
|
||||
const userRoles = userInfo.roles ?? [];
|
||||
let userInfo = userStore.userInfo;
|
||||
if (!userInfo) {
|
||||
// add by 芋艿:由于 yudao 是 fetchUserInfo 统一加载用户 + 权限信息,所以将 fetchMenuListAsync
|
||||
const message = ElMessage({
|
||||
message: `${$t('common.loadingMenu')}...`,
|
||||
type: 'success',
|
||||
plain: true,
|
||||
});
|
||||
try {
|
||||
const authPermissionInfo = await authStore.fetchUserInfo();
|
||||
if (authPermissionInfo) {
|
||||
userInfo = authPermissionInfo.user;
|
||||
}
|
||||
} finally {
|
||||
message.close();
|
||||
}
|
||||
}
|
||||
const userRoles = userStore.userRoles ?? [];
|
||||
|
||||
// 生成菜单和路由
|
||||
const { accessibleMenus, accessibleRoutes } = await generateAccess({
|
||||
@@ -107,9 +131,10 @@ function setupAccessGuard(router: Router) {
|
||||
accessStore.setAccessMenus(accessibleMenus);
|
||||
accessStore.setAccessRoutes(accessibleRoutes);
|
||||
accessStore.setIsAccessChecked(true);
|
||||
userStore.setUserRoles(userRoles);
|
||||
const redirectPath = (from.query.redirect ??
|
||||
(to.path === preferences.app.defaultHomePath
|
||||
? userInfo.homePath || preferences.app.defaultHomePath
|
||||
? userInfo?.homePath || preferences.app.defaultHomePath
|
||||
: to.fullPath)) as string;
|
||||
|
||||
return {
|
||||
|
||||
@@ -8,6 +8,7 @@ import { resetStaticRoutes } from '@vben/utils';
|
||||
|
||||
import { createRouterGuard } from './guard';
|
||||
import { routes } from './routes';
|
||||
import { setupBaiduTongJi } from './tongji';
|
||||
|
||||
/**
|
||||
* @zh_CN 创建vue-router实例
|
||||
@@ -33,5 +34,7 @@ const resetRoutes = () => resetStaticRoutes(router, routes);
|
||||
|
||||
// 创建路由守卫
|
||||
createRouterGuard(router);
|
||||
// 设置百度统计
|
||||
setupBaiduTongJi(router);
|
||||
|
||||
export { resetRoutes, router };
|
||||
|
||||
@@ -90,6 +90,23 @@ const coreRoutes: RouteRecordRaw[] = [
|
||||
title: $t('page.auth.register'),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'SocialLogin',
|
||||
path: 'social-login',
|
||||
component: () =>
|
||||
import('#/views/_core/authentication/social-login.vue'),
|
||||
meta: {
|
||||
title: $t('page.auth.login'),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'SSOLogin',
|
||||
path: 'sso-login',
|
||||
component: () => import('#/views/_core/authentication/sso-login.vue'),
|
||||
meta: {
|
||||
title: $t('page.auth.login'),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -34,4 +34,14 @@ const coreRouteNames = traverseTreeValues(coreRoutes, (route) => route.name);
|
||||
|
||||
/** 有权限校验的路由列表,包含动态路由和静态路由 */
|
||||
const accessRoutes = [...dynamicRoutes, ...staticRoutes];
|
||||
export { accessRoutes, coreRouteNames, routes };
|
||||
|
||||
// add by 芋艿:from https://github.com/vbenjs/vue-vben-admin/blob/main/playground/src/router/routes/index.ts#L38-L45
|
||||
const componentKeys: string[] = Object.keys(
|
||||
import.meta.glob('../../views/**/*.vue'),
|
||||
)
|
||||
.filter((item) => !item.includes('/modules/'))
|
||||
.map((v) => {
|
||||
const path = v.replace('../../views/', '/');
|
||||
return path.endsWith('.vue') ? path.slice(0, -4) : path;
|
||||
});
|
||||
export { accessRoutes, componentKeys, coreRouteNames, routes };
|
||||
|
||||
@@ -12,6 +12,15 @@ const routes: RouteRecordRaw[] = [
|
||||
name: 'Dashboard',
|
||||
path: '/dashboard',
|
||||
children: [
|
||||
{
|
||||
name: 'Workspace',
|
||||
path: '/workspace',
|
||||
component: () => import('#/views/dashboard/workspace/index.vue'),
|
||||
meta: {
|
||||
icon: 'carbon:workspace',
|
||||
title: $t('page.dashboard.workspace'),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Analytics',
|
||||
path: '/analytics',
|
||||
@@ -22,17 +31,18 @@ const routes: RouteRecordRaw[] = [
|
||||
title: $t('page.dashboard.analytics'),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Workspace',
|
||||
path: '/workspace',
|
||||
component: () => import('#/views/dashboard/workspace/index.vue'),
|
||||
meta: {
|
||||
icon: 'carbon:workspace',
|
||||
title: $t('page.dashboard.workspace'),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Profile',
|
||||
path: '/profile',
|
||||
component: () => import('#/views/_core/profile/index.vue'),
|
||||
meta: {
|
||||
icon: 'ant-design:profile-outlined',
|
||||
title: $t('ui.widgets.profile'),
|
||||
hideInMenu: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default routes;
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
|
||||
import { $t } from '#/locales';
|
||||
|
||||
const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
meta: {
|
||||
icon: 'ic:baseline-view-in-ar',
|
||||
keepAlive: true,
|
||||
order: 1000,
|
||||
title: $t('demos.title'),
|
||||
},
|
||||
name: 'Demos',
|
||||
path: '/demos',
|
||||
children: [
|
||||
{
|
||||
meta: {
|
||||
title: $t('demos.elementPlus'),
|
||||
},
|
||||
name: 'NaiveDemos',
|
||||
path: '/demos/element',
|
||||
component: () => import('#/views/demos/element/index.vue'),
|
||||
},
|
||||
{
|
||||
meta: {
|
||||
title: $t('demos.form'),
|
||||
},
|
||||
name: 'BasicForm',
|
||||
path: '/demos/form',
|
||||
component: () => import('#/views/demos/form/basic.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default routes;
|
||||
@@ -1,82 +1,81 @@
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
|
||||
import {
|
||||
VBEN_ANT_PREVIEW_URL,
|
||||
VBEN_DOC_URL,
|
||||
VBEN_GITHUB_URL,
|
||||
VBEN_LOGO_URL,
|
||||
VBEN_NAIVE_PREVIEW_URL,
|
||||
} from '@vben/constants';
|
||||
import { SvgAntdvLogoIcon } from '@vben/icons';
|
||||
|
||||
import { IFrameView } from '#/layouts';
|
||||
import { $t } from '#/locales';
|
||||
// import {
|
||||
// VBEN_DOC_URL,
|
||||
// VBEN_ELE_PREVIEW_URL,
|
||||
// VBEN_GITHUB_URL,
|
||||
// VBEN_LOGO_URL,
|
||||
// VBEN_NAIVE_PREVIEW_URL,
|
||||
// } from '@vben/constants';
|
||||
//
|
||||
// import { IFrameView } from '#/layouts';
|
||||
// import { $t } from '#/locales';
|
||||
|
||||
const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
meta: {
|
||||
badgeType: 'dot',
|
||||
icon: VBEN_LOGO_URL,
|
||||
order: 9998,
|
||||
title: $t('demos.vben.title'),
|
||||
},
|
||||
name: 'VbenProject',
|
||||
path: '/vben-admin',
|
||||
children: [
|
||||
{
|
||||
name: 'VbenDocument',
|
||||
path: '/vben-admin/document',
|
||||
component: IFrameView,
|
||||
meta: {
|
||||
icon: 'lucide:book-open-text',
|
||||
link: VBEN_DOC_URL,
|
||||
title: $t('demos.vben.document'),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'VbenGithub',
|
||||
path: '/vben-admin/github',
|
||||
component: IFrameView,
|
||||
meta: {
|
||||
icon: 'mdi:github',
|
||||
link: VBEN_GITHUB_URL,
|
||||
title: 'Github',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'VbenNaive',
|
||||
path: '/vben-admin/naive',
|
||||
component: IFrameView,
|
||||
meta: {
|
||||
badgeType: 'dot',
|
||||
icon: 'logos:naiveui',
|
||||
link: VBEN_NAIVE_PREVIEW_URL,
|
||||
title: $t('demos.vben.naive-ui'),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'VbenAntd',
|
||||
path: '/vben-admin/antd',
|
||||
component: IFrameView,
|
||||
meta: {
|
||||
badgeType: 'dot',
|
||||
icon: SvgAntdvLogoIcon,
|
||||
link: VBEN_ANT_PREVIEW_URL,
|
||||
title: $t('demos.vben.antdv'),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'VbenAbout',
|
||||
path: '/vben-admin/about',
|
||||
component: () => import('#/views/_core/about/index.vue'),
|
||||
meta: {
|
||||
icon: 'lucide:copyright',
|
||||
title: $t('demos.vben.about'),
|
||||
order: 9999,
|
||||
},
|
||||
},
|
||||
// {
|
||||
// meta: {
|
||||
// badgeType: 'dot',
|
||||
// icon: VBEN_LOGO_URL,
|
||||
// order: 9998,
|
||||
// title: $t('demos.vben.title'),
|
||||
// },
|
||||
// name: 'VbenProject',
|
||||
// path: '/vben-admin',
|
||||
// children: [
|
||||
// {
|
||||
// name: 'VbenDocument',
|
||||
// path: '/vben-admin/document',
|
||||
// component: IFrameView,
|
||||
// meta: {
|
||||
// icon: 'lucide:book-open-text',
|
||||
// link: VBEN_DOC_URL,
|
||||
// title: $t('demos.vben.document'),
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// name: 'VbenGithub',
|
||||
// path: '/vben-admin/github',
|
||||
// component: IFrameView,
|
||||
// meta: {
|
||||
// icon: 'mdi:github',
|
||||
// link: VBEN_GITHUB_URL,
|
||||
// title: 'Github',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// name: 'VbenNaive',
|
||||
// path: '/vben-admin/naive',
|
||||
// component: IFrameView,
|
||||
// meta: {
|
||||
// badgeType: 'dot',
|
||||
// icon: 'logos:naiveui',
|
||||
// link: VBEN_NAIVE_PREVIEW_URL,
|
||||
// title: $t('demos.vben.naive-ui'),
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// name: 'VbenElementPlus',
|
||||
// path: '/vben-admin/ele',
|
||||
// component: IFrameView,
|
||||
// meta: {
|
||||
// badgeType: 'dot',
|
||||
// icon: 'logos:element',
|
||||
// link: VBEN_ELE_PREVIEW_URL,
|
||||
// title: $t('demos.vben.element-plus'),
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// name: 'VbenAbout',
|
||||
// path: '/vben-admin/about',
|
||||
// component: () => import('#/views/_core/about/index.vue'),
|
||||
// meta: {
|
||||
// icon: 'lucide:copyright',
|
||||
// title: $t('demos.vben.about'),
|
||||
// order: 9999,
|
||||
// },
|
||||
// },
|
||||
];
|
||||
|
||||
export default routes;
|
||||
export default routes; // update by 芋艿:不展示
|
||||
|
||||
30
apps/web-ele/src/router/tongji.ts
Normal file
30
apps/web-ele/src/router/tongji.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import type { Router } from 'vue-router';
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
_hmt: any[];
|
||||
}
|
||||
}
|
||||
|
||||
const HM_ID = import.meta.env.VITE_APP_BAIDU_CODE;
|
||||
|
||||
/**
|
||||
* 设置百度统计
|
||||
* @param router
|
||||
*/
|
||||
function setupBaiduTongJi(router: Router) {
|
||||
// 如果没有配置百度统计的 ID,则不进行设置
|
||||
if (!HM_ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
// _hmt:用于 router push
|
||||
window._hmt = window._hmt || [];
|
||||
|
||||
router.afterEach((to) => {
|
||||
// 添加到 _hmt 中
|
||||
window._hmt.push(['_trackPageview', to.fullPath]);
|
||||
});
|
||||
}
|
||||
|
||||
export { setupBaiduTongJi };
|
||||
Reference in New Issue
Block a user