物业代码生成
This commit is contained in:
266
apps/web-antd/src/router/access.ts
Normal file
266
apps/web-antd/src/router/access.ts
Normal file
@@ -0,0 +1,266 @@
|
||||
import type {
|
||||
ComponentRecordType,
|
||||
GenerateMenuAndRoutesOptions,
|
||||
RouteMeta,
|
||||
RouteRecordStringComponent,
|
||||
} from '@vben/types';
|
||||
|
||||
import type { Menu } from '#/api';
|
||||
|
||||
import { generateAccessible } from '@vben/access';
|
||||
import { preferences } from '@vben/preferences';
|
||||
|
||||
import { message } from 'ant-design-vue';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
||||
import { getAllMenusApi } from '#/api';
|
||||
import { BasicLayout, IFrameView } from '#/layouts';
|
||||
import { $t } from '#/locales';
|
||||
|
||||
import { localMenuList } from './routes/local';
|
||||
|
||||
const forbiddenComponent = () => import('#/views/_core/fallback/forbidden.vue');
|
||||
const NotFoundComponent = () => import('#/views/_core/fallback/not-found.vue');
|
||||
|
||||
/**
|
||||
* 后端返回的meta有时候不包括需要的信息 比如activePath等
|
||||
* 在这里定义映射
|
||||
*/
|
||||
const routeMetaMapping: Record<string, Omit<RouteMeta, 'title'>> = {
|
||||
'/system/role-auth/user/:roleId(\\d+)': {
|
||||
activePath: '/system/role',
|
||||
requireHomeRedirect: true,
|
||||
},
|
||||
|
||||
'/system/oss-config/index': {
|
||||
activePath: '/system/oss',
|
||||
requireHomeRedirect: true,
|
||||
},
|
||||
|
||||
'/tool/gen-edit/index/:tableId(\\d+)': {
|
||||
activePath: '/tool/gen',
|
||||
requireHomeRedirect: true,
|
||||
},
|
||||
|
||||
'/workflow/design/index': {
|
||||
activePath: '/workflow/processDefinition',
|
||||
requireHomeRedirect: true,
|
||||
},
|
||||
|
||||
'/workflow/leaveEdit/index': {
|
||||
activePath: '/demo/leave',
|
||||
requireHomeRedirect: true,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 后台路由转vben路由
|
||||
* @param menuList 后台菜单
|
||||
* @param parentPath 上级目录
|
||||
* @returns vben路由
|
||||
*/
|
||||
function backMenuToVbenMenu(
|
||||
menuList: Menu[],
|
||||
parentPath = '',
|
||||
): RouteRecordStringComponent[] {
|
||||
const resultList: RouteRecordStringComponent[] = [];
|
||||
menuList.forEach((menu) => {
|
||||
// 根目录为菜单形式
|
||||
// 固定有一个children children为当前菜单
|
||||
if (menu.path === '/' && menu.children && menu.children.length === 1) {
|
||||
if (!menu.children || !menu.children[0]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 需要处理根目录为内嵌的情况 不会带InnerLink
|
||||
if (/^https?:\/\//.test(menu.children[0].path)) {
|
||||
menu.children[0].component = 'InnerLink';
|
||||
menu.children[0].path = menu.children[0].path
|
||||
.replaceAll(/^https?:\/\//g, '')
|
||||
.replaceAll('/#/', '')
|
||||
.replaceAll('#', '')
|
||||
.replaceAll(/[?&]/g, '');
|
||||
}
|
||||
|
||||
// 取子路径作为父级路径
|
||||
const path = menu.children[0].path;
|
||||
// 取子菜单的meta作为当前菜单的meta
|
||||
menu.meta = menu.children[0].meta;
|
||||
// 由于在一级路由 父级路径需要加上/
|
||||
menu.path = `/${path}`;
|
||||
menu.component = 'RootMenu';
|
||||
// 将子路径设置为''
|
||||
menu.children[0].path = '';
|
||||
}
|
||||
|
||||
// 外链: http开头 & 组件为Layout || ParentView
|
||||
// 正则判断是否为http://或者https://开头
|
||||
if (
|
||||
/^https?:\/\//.test(menu.path) &&
|
||||
(menu.component === 'Layout' || menu.component === 'ParentView')
|
||||
) {
|
||||
menu.component = 'Link';
|
||||
}
|
||||
|
||||
// 内嵌iframe 组件为InnerLink
|
||||
if (menu.meta?.link && menu.component === 'InnerLink') {
|
||||
menu.component = 'IFrameView';
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼接path
|
||||
* menu.path为''(根目录路由) 则不拼接
|
||||
*/
|
||||
if (parentPath && menu.path) {
|
||||
menu.path = `${parentPath}/${menu.path}`;
|
||||
}
|
||||
|
||||
// 创建vben路由对象
|
||||
const vbenRoute: RouteRecordStringComponent = {
|
||||
component: menu.component,
|
||||
meta: {
|
||||
// 当前路由不在菜单显示 但是可以通过链接访问
|
||||
// 不可访问的路由由后端控制隐藏(不返回对应路由)
|
||||
hideInMenu: menu.hidden,
|
||||
icon: menu.meta?.icon,
|
||||
keepAlive: !menu.meta?.noCache,
|
||||
title: menu.meta?.title,
|
||||
},
|
||||
name: menu.name,
|
||||
path: menu.path,
|
||||
};
|
||||
|
||||
// 处理meta映射
|
||||
if (Object.keys(routeMetaMapping).includes(vbenRoute.path)) {
|
||||
const routeMeta = routeMetaMapping[vbenRoute.path];
|
||||
if (routeMeta) {
|
||||
vbenRoute.meta = {
|
||||
...vbenRoute.meta,
|
||||
...(routeMeta as RouteMeta),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 添加路由参数信息
|
||||
if (menu.query) {
|
||||
try {
|
||||
const query = JSON.parse(menu.query);
|
||||
vbenRoute.meta && (vbenRoute.meta.query = query);
|
||||
} catch {
|
||||
console.error('错误的路由参数类型, 必须为[json]格式');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理不同组件
|
||||
*/
|
||||
switch (menu.component) {
|
||||
/**
|
||||
* iframe内嵌
|
||||
*/
|
||||
case 'IFrameView': {
|
||||
vbenRoute.component = 'IFrameView';
|
||||
if (vbenRoute.meta) {
|
||||
vbenRoute.meta.iframeSrc = menu.meta.link;
|
||||
}
|
||||
/**
|
||||
* 需要判断特殊情况 比如vue的hash是带#的
|
||||
* 比如链接 aaa.com/#/bbb path会转换为 aaa/com/#/bbb
|
||||
* 比如链接 aaa.com/?bbb=xxx
|
||||
* 需要去除# 否则无法被添加到路由
|
||||
*/
|
||||
vbenRoute.path = vbenRoute.path
|
||||
// 替换https:// 或者 http://
|
||||
.replaceAll(/^https?:\/\//g, '')
|
||||
.replaceAll('/#/', '')
|
||||
.replaceAll('#', '')
|
||||
.replaceAll(/[?&]/g, '');
|
||||
break;
|
||||
}
|
||||
case 'Layout': {
|
||||
vbenRoute.component = 'BasicLayout';
|
||||
break;
|
||||
}
|
||||
/**
|
||||
* 外链 新窗口打开
|
||||
*/
|
||||
case 'Link': {
|
||||
if (vbenRoute.meta) {
|
||||
vbenRoute.meta.link = menu.meta.link;
|
||||
}
|
||||
vbenRoute.component = 'BasicLayout';
|
||||
break;
|
||||
}
|
||||
/**
|
||||
* 三级以上菜单 父级component为ParentView
|
||||
* 不能为layout 会套两层BasicLayout
|
||||
*/
|
||||
case 'ParentView': {
|
||||
vbenRoute.component = '';
|
||||
break;
|
||||
}
|
||||
/**
|
||||
* 根目录菜单
|
||||
*/
|
||||
case 'RootMenu': {
|
||||
if (vbenRoute.meta) {
|
||||
vbenRoute.meta.hideChildrenInMenu = true;
|
||||
}
|
||||
vbenRoute.component = 'BasicLayout';
|
||||
break;
|
||||
}
|
||||
/**
|
||||
* 其他自定义组件 如system/user/index 拼接/
|
||||
*/
|
||||
default: {
|
||||
vbenRoute.component = `/${menu.component}`;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// children处理
|
||||
if (menu.children && menu.children.length > 0) {
|
||||
vbenRoute.children = backMenuToVbenMenu(menu.children, menu.path);
|
||||
}
|
||||
// 添加
|
||||
resultList.push(vbenRoute);
|
||||
});
|
||||
return resultList;
|
||||
}
|
||||
|
||||
async function generateAccess(options: GenerateMenuAndRoutesOptions) {
|
||||
const pageMap: ComponentRecordType = import.meta.glob('../views/**/*.vue');
|
||||
|
||||
const layoutMap: ComponentRecordType = {
|
||||
BasicLayout,
|
||||
IFrameView,
|
||||
NotFoundComponent,
|
||||
};
|
||||
|
||||
return await generateAccessible(preferences.app.accessMode, {
|
||||
...options,
|
||||
fetchMenuListAsync: async () => {
|
||||
// 清除以前的message
|
||||
message.destroy();
|
||||
message.loading({
|
||||
content: `${$t('common.loadingMenu')}...`,
|
||||
duration: 1,
|
||||
});
|
||||
// 后台返回路由/菜单
|
||||
const backMenuList = await getAllMenusApi();
|
||||
// 转换为vben能用的路由
|
||||
const vbenMenuList = backMenuToVbenMenu(backMenuList);
|
||||
// 特别注意 这里要深拷贝
|
||||
const menuList = [...cloneDeep(localMenuList), ...vbenMenuList];
|
||||
// console.log('menuList', menuList);
|
||||
return menuList;
|
||||
},
|
||||
// 可以指定没有权限跳转403页面
|
||||
forbiddenComponent,
|
||||
// 如果 route.meta.menuVisibleWithForbidden = true
|
||||
layoutMap,
|
||||
pageMap,
|
||||
});
|
||||
}
|
||||
|
||||
export { generateAccess };
|
133
apps/web-antd/src/router/guard.ts
Normal file
133
apps/web-antd/src/router/guard.ts
Normal file
@@ -0,0 +1,133 @@
|
||||
import type { Router } from 'vue-router';
|
||||
|
||||
import { LOGIN_PATH } from '@vben/constants';
|
||||
import { preferences } from '@vben/preferences';
|
||||
import { useAccessStore, useUserStore } from '@vben/stores';
|
||||
import { startProgress, stopProgress } from '@vben/utils';
|
||||
|
||||
import { accessRoutes, coreRouteNames } from '#/router/routes';
|
||||
import { useAuthStore } from '#/store';
|
||||
|
||||
import { generateAccess } from './access';
|
||||
|
||||
/**
|
||||
* 通用守卫配置
|
||||
* @param router
|
||||
*/
|
||||
function setupCommonGuard(router: Router) {
|
||||
// 记录已经加载的页面
|
||||
const loadedPaths = new Set<string>();
|
||||
|
||||
router.beforeEach((to) => {
|
||||
to.meta.loaded = loadedPaths.has(to.path);
|
||||
|
||||
// 页面加载进度条
|
||||
if (!to.meta.loaded && preferences.transition.progress) {
|
||||
startProgress();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
router.afterEach((to) => {
|
||||
// 记录页面是否加载,如果已经加载,后续的页面切换动画等效果不在重复执行
|
||||
|
||||
loadedPaths.add(to.path);
|
||||
|
||||
// 关闭页面加载进度条
|
||||
if (preferences.transition.progress) {
|
||||
stopProgress();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 权限访问守卫配置
|
||||
* @param router
|
||||
*/
|
||||
function setupAccessGuard(router: Router) {
|
||||
router.beforeEach(async (to, from) => {
|
||||
const accessStore = useAccessStore();
|
||||
const userStore = useUserStore();
|
||||
const authStore = useAuthStore();
|
||||
|
||||
// 基本路由,这些路由不需要进入权限拦截
|
||||
if (coreRouteNames.includes(to.name as string)) {
|
||||
if (to.path === LOGIN_PATH && accessStore.accessToken) {
|
||||
return decodeURIComponent(
|
||||
(to.query?.redirect as string) ||
|
||||
userStore.userInfo?.homePath ||
|
||||
preferences.app.defaultHomePath,
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// accessToken 检查
|
||||
if (!accessStore.accessToken) {
|
||||
// 明确声明忽略权限访问权限,则可以访问
|
||||
if (to.meta.ignoreAccess) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 没有访问权限,跳转登录页面
|
||||
if (to.fullPath !== LOGIN_PATH) {
|
||||
return {
|
||||
path: LOGIN_PATH,
|
||||
// 如不需要,直接删除 query
|
||||
query:
|
||||
to.fullPath === preferences.app.defaultHomePath
|
||||
? {}
|
||||
: { redirect: encodeURIComponent(to.fullPath) },
|
||||
// 携带当前跳转的页面,登录后重新跳转该页面
|
||||
replace: true,
|
||||
};
|
||||
}
|
||||
return to;
|
||||
}
|
||||
|
||||
// 是否已经生成过动态路由
|
||||
if (accessStore.isAccessChecked) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 生成路由表
|
||||
// 当前登录用户拥有的角色标识列表
|
||||
const userInfo = userStore.userInfo || (await authStore.fetchUserInfo());
|
||||
const userRoles = userInfo.roles ?? [];
|
||||
|
||||
// 生成菜单和路由
|
||||
const { accessibleMenus, accessibleRoutes } = await generateAccess({
|
||||
roles: userRoles,
|
||||
router,
|
||||
// 则会在菜单中显示,但是访问会被重定向到403
|
||||
routes: accessRoutes,
|
||||
});
|
||||
|
||||
// 保存菜单信息和路由信息
|
||||
accessStore.setAccessMenus(accessibleMenus);
|
||||
accessStore.setAccessRoutes(accessibleRoutes);
|
||||
accessStore.setIsAccessChecked(true);
|
||||
const redirectPath = (from.query.redirect ??
|
||||
(to.path === preferences.app.defaultHomePath
|
||||
? userInfo.homePath || preferences.app.defaultHomePath
|
||||
: to.fullPath)) as string;
|
||||
|
||||
return {
|
||||
...router.resolve(decodeURIComponent(redirectPath)),
|
||||
replace: true,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 项目守卫配置
|
||||
* @param router
|
||||
*/
|
||||
function createRouterGuard(router: Router) {
|
||||
/** 通用 */
|
||||
setupCommonGuard(router);
|
||||
/** 权限访问 */
|
||||
setupAccessGuard(router);
|
||||
}
|
||||
|
||||
export { createRouterGuard };
|
37
apps/web-antd/src/router/index.ts
Normal file
37
apps/web-antd/src/router/index.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import {
|
||||
createRouter,
|
||||
createWebHashHistory,
|
||||
createWebHistory,
|
||||
} from 'vue-router';
|
||||
|
||||
import { resetStaticRoutes } from '@vben/utils';
|
||||
|
||||
import { createRouterGuard } from './guard';
|
||||
import { routes } from './routes';
|
||||
|
||||
/**
|
||||
* @zh_CN 创建vue-router实例
|
||||
*/
|
||||
const router = createRouter({
|
||||
history:
|
||||
import.meta.env.VITE_ROUTER_HISTORY === 'hash'
|
||||
? createWebHashHistory(import.meta.env.VITE_BASE)
|
||||
: createWebHistory(import.meta.env.VITE_BASE),
|
||||
// 应该添加到路由的初始路由列表。
|
||||
routes,
|
||||
scrollBehavior: (to, _from, savedPosition) => {
|
||||
if (savedPosition) {
|
||||
return savedPosition;
|
||||
}
|
||||
return to.hash ? { behavior: 'smooth', el: to.hash } : { left: 0, top: 0 };
|
||||
},
|
||||
// 是否应该禁止尾部斜杠。
|
||||
// strict: true,
|
||||
});
|
||||
|
||||
const resetRoutes = () => resetStaticRoutes(router, routes);
|
||||
|
||||
// 创建路由守卫
|
||||
createRouterGuard(router);
|
||||
|
||||
export { resetRoutes, router };
|
105
apps/web-antd/src/router/routes/core.ts
Normal file
105
apps/web-antd/src/router/routes/core.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
|
||||
import { LOGIN_PATH } from '@vben/constants';
|
||||
import { preferences } from '@vben/preferences';
|
||||
|
||||
import { $t } from '#/locales';
|
||||
|
||||
const BasicLayout = () => import('#/layouts/basic.vue');
|
||||
const AuthPageLayout = () => import('#/layouts/auth.vue');
|
||||
/** 全局404页面 */
|
||||
const fallbackNotFoundRoute: RouteRecordRaw = {
|
||||
component: () => import('#/views/_core/fallback/not-found.vue'),
|
||||
meta: {
|
||||
hideInBreadcrumb: true,
|
||||
hideInMenu: true,
|
||||
hideInTab: true,
|
||||
title: '404',
|
||||
},
|
||||
name: 'FallbackNotFound',
|
||||
path: '/:path(.*)*',
|
||||
};
|
||||
|
||||
/** 基本路由,这些路由是必须存在的 */
|
||||
const coreRoutes: RouteRecordRaw[] = [
|
||||
/**
|
||||
* 根路由
|
||||
* 使用基础布局,作为所有页面的父级容器,子级就不必配置BasicLayout。
|
||||
* 此路由必须存在,且不应修改
|
||||
*/
|
||||
{
|
||||
component: BasicLayout,
|
||||
meta: {
|
||||
hideInBreadcrumb: true,
|
||||
title: 'Root',
|
||||
},
|
||||
name: 'Root',
|
||||
path: '/',
|
||||
redirect: preferences.app.defaultHomePath,
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
component: () => import('#/views/_core/social-callback/index.vue'),
|
||||
meta: {
|
||||
title: $t('page.auth.oauthLogin'),
|
||||
},
|
||||
name: 'OAuthRedirect',
|
||||
path: '/social-callback',
|
||||
},
|
||||
{
|
||||
component: AuthPageLayout,
|
||||
meta: {
|
||||
hideInTab: true,
|
||||
title: 'Authentication',
|
||||
},
|
||||
name: 'Authentication',
|
||||
path: '/auth',
|
||||
redirect: LOGIN_PATH,
|
||||
children: [
|
||||
{
|
||||
name: 'Login',
|
||||
path: 'login',
|
||||
component: () => import('#/views/_core/authentication/login.vue'),
|
||||
meta: {
|
||||
title: $t('page.auth.login'),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'CodeLogin',
|
||||
path: 'code-login',
|
||||
component: () => import('#/views/_core/authentication/code-login.vue'),
|
||||
meta: {
|
||||
title: $t('page.auth.codeLogin'),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'QrCodeLogin',
|
||||
path: 'qrcode-login',
|
||||
component: () =>
|
||||
import('#/views/_core/authentication/qrcode-login.vue'),
|
||||
meta: {
|
||||
title: $t('page.auth.qrcodeLogin'),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'ForgetPassword',
|
||||
path: 'forget-password',
|
||||
component: () =>
|
||||
import('#/views/_core/authentication/forget-password.vue'),
|
||||
meta: {
|
||||
title: $t('page.auth.forgetPassword'),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Register',
|
||||
path: 'register',
|
||||
component: () => import('#/views/_core/authentication/register.vue'),
|
||||
meta: {
|
||||
title: $t('page.auth.register'),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export { coreRoutes, fallbackNotFoundRoute };
|
41
apps/web-antd/src/router/routes/index.ts
Normal file
41
apps/web-antd/src/router/routes/index.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
|
||||
import { mergeRouteModules, traverseTreeValues } from '@vben/utils';
|
||||
|
||||
import { coreRoutes, fallbackNotFoundRoute } from './core';
|
||||
import { workflowIframeRoutes } from './workflow-iframe';
|
||||
|
||||
const dynamicRouteFiles = import.meta.glob('./modules/**/*.ts', {
|
||||
eager: true,
|
||||
});
|
||||
|
||||
// 有需要可以自行打开注释,并创建文件夹
|
||||
// const externalRouteFiles = import.meta.glob('./external/**/*.ts', { eager: true });
|
||||
// const staticRouteFiles = import.meta.glob('./static/**/*.ts', { eager: true });
|
||||
|
||||
/** 动态路由 */
|
||||
const dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles);
|
||||
|
||||
/** 外部路由列表,访问这些页面可以不需要Layout,可能用于内嵌在别的系统(不会显示在菜单中) */
|
||||
// const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles);
|
||||
// const staticRoutes: RouteRecordRaw[] = mergeRouteModules(staticRouteFiles);
|
||||
const staticRoutes: RouteRecordRaw[] = [];
|
||||
const externalRoutes: RouteRecordRaw[] = [];
|
||||
|
||||
/** 路由列表,由基本路由、外部路由和404兜底路由组成
|
||||
* 无需走权限验证(会一直显示在菜单中) */
|
||||
const routes: RouteRecordRaw[] = [
|
||||
...coreRoutes,
|
||||
...externalRoutes,
|
||||
...workflowIframeRoutes,
|
||||
fallbackNotFoundRoute,
|
||||
];
|
||||
|
||||
/** 基本路由(登录, 第三方登录, 注册等) + workflowIframe路由不需要拦截 */
|
||||
const basicRoutes = [...coreRoutes, ...workflowIframeRoutes];
|
||||
/** 基本路由列表,这些路由不需要进入权限拦截 */
|
||||
const coreRouteNames = traverseTreeValues(basicRoutes, (route) => route.name);
|
||||
|
||||
/** 有权限校验的路由列表,包含动态路由和静态路由 */
|
||||
const accessRoutes = [...dynamicRoutes, ...staticRoutes];
|
||||
export { accessRoutes, coreRouteNames, routes };
|
97
apps/web-antd/src/router/routes/local.ts
Normal file
97
apps/web-antd/src/router/routes/local.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import type { RouteRecordStringComponent } from '@vben/types';
|
||||
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
const {
|
||||
version,
|
||||
// vite inject-metadata 插件注入的全局变量
|
||||
} = __VBEN_ADMIN_METADATA__ || {};
|
||||
|
||||
/**
|
||||
* 该文件放非后台返回的路由 比如个人中心 等需要跳转显示的页面
|
||||
* 也可以直接在菜单管理配置
|
||||
*/
|
||||
const localRoutes: RouteRecordStringComponent[] = [
|
||||
{
|
||||
component: '/_core/profile/index',
|
||||
meta: {
|
||||
icon: 'mingcute:profile-line',
|
||||
title: $t('ui.widgets.profile'),
|
||||
hideInMenu: true,
|
||||
requireHomeRedirect: true,
|
||||
},
|
||||
name: 'Profile',
|
||||
path: '/profile',
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* 这里放本地路由
|
||||
*/
|
||||
export const localMenuList: RouteRecordStringComponent[] = [
|
||||
{
|
||||
component: 'BasicLayout',
|
||||
meta: {
|
||||
order: -1,
|
||||
title: 'page.dashboard.title',
|
||||
// 不使用基础布局(仅在顶级生效)
|
||||
noBasicLayout: true,
|
||||
},
|
||||
name: 'Dashboard',
|
||||
path: '/',
|
||||
redirect: '/analytics',
|
||||
children: [
|
||||
{
|
||||
name: 'Analytics',
|
||||
path: '/analytics',
|
||||
component: '/dashboard/analytics/index',
|
||||
meta: {
|
||||
affixTab: true,
|
||||
title: 'page.dashboard.analytics',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Workspace',
|
||||
path: '/workspace',
|
||||
component: '/dashboard/workspace/index',
|
||||
meta: {
|
||||
title: 'page.dashboard.workspace',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'VbenDocument',
|
||||
path: '/vben-admin/document',
|
||||
component: 'IFrameView',
|
||||
meta: {
|
||||
icon: 'lucide:book-open-text',
|
||||
iframeSrc: 'https://dapdap.top',
|
||||
keepAlive: true,
|
||||
title: $t('demos.vben.document'),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'V5UpdateLog',
|
||||
path: '/changelog',
|
||||
component: '/演示使用自行删除/changelog/index',
|
||||
meta: {
|
||||
icon: 'lucide:book-open-text',
|
||||
keepAlive: true,
|
||||
title: '更新记录',
|
||||
badge: `当前: ${version}`,
|
||||
badgeVariants: 'bg-primary',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
component: '/_core/about/index',
|
||||
meta: {
|
||||
icon: 'lucide:copyright',
|
||||
order: 9999,
|
||||
title: $t('demos.vben.about'),
|
||||
},
|
||||
name: 'About',
|
||||
path: '/vben-admin/about',
|
||||
},
|
||||
...localRoutes,
|
||||
];
|
38
apps/web-antd/src/router/routes/modules/dashboard.ts
Normal file
38
apps/web-antd/src/router/routes/modules/dashboard.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
|
||||
import { $t } from '#/locales';
|
||||
|
||||
const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
meta: {
|
||||
icon: 'lucide:layout-dashboard',
|
||||
order: -1,
|
||||
title: $t('page.dashboard.title'),
|
||||
},
|
||||
name: 'Dashboard',
|
||||
path: '/dashboard',
|
||||
children: [
|
||||
{
|
||||
name: 'Analytics',
|
||||
path: '/analytics',
|
||||
component: () => import('#/views/dashboard/analytics/index.vue'),
|
||||
meta: {
|
||||
affixTab: true,
|
||||
icon: 'lucide:area-chart',
|
||||
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'),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default routes;
|
90
apps/web-antd/src/router/routes/modules/vben.ts
Normal file
90
apps/web-antd/src/router/routes/modules/vben.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
|
||||
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: 'VbenAbout',
|
||||
path: '/vben-admin/about',
|
||||
component: () => import('#/views/_core/about/index.vue'),
|
||||
meta: {
|
||||
icon: 'lucide:copyright|offline',
|
||||
title: $t('demos.vben.about'),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'VbenDocument',
|
||||
path: '/vben-admin/document',
|
||||
component: IFrameView,
|
||||
meta: {
|
||||
icon: 'lucide:book-open-text|offline',
|
||||
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;
|
18
apps/web-antd/src/router/routes/workflow-iframe.ts
Normal file
18
apps/web-antd/src/router/routes/workflow-iframe.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import type { RouteRecordRaw } from '@vben/types';
|
||||
|
||||
/**
|
||||
* 该文件存放workflow表单的iframe内嵌路由
|
||||
* 不需要权限认证 少走两个接口😅
|
||||
*/
|
||||
export const workflowIframeRoutes: RouteRecordRaw[] = [
|
||||
// 这里是iframe使用的 去掉外层的BasicLayout
|
||||
{
|
||||
name: 'WorkflowLeaveInner',
|
||||
path: '/workflow/leaveEdit/index/iframe',
|
||||
component: () => import('#/views/workflow/leave/leave-form.vue'),
|
||||
meta: {
|
||||
hideInTab: true,
|
||||
title: '请假申请',
|
||||
},
|
||||
},
|
||||
];
|
Reference in New Issue
Block a user