| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- import { createRouter, createWebHistory } from 'vue-router'
- import { useUserStore } from '@/stores/user-store'
- import { getToken } from '@/utils/auth'
- const router = createRouter({
- history: createWebHistory(),
- routes: [
- {
- path: '/login',
- name: 'Login',
- component: () => import('@/views/login/index.vue'),
- meta: { hidden: true }
- },
- {
- path: '/profile',
- component: () => import('@/components/Layout/index.vue'),
- meta: { hidden: true },
- children: [
- {
- path: '',
- name: 'Profile',
- component: () => import('@/views/profile/index.vue'),
- meta: { title: '个人中心' }
- }
- ]
- },
- {
- path: '/:pathMatch(.*)*',
- name: 'NotFound',
- component: () => import('@/views/error/404.vue'),
- meta: { hidden: true }
- },
- {
- path: '/',
- component: () => import('@/components/Layout/index.vue'),
- redirect: '/dashboard',
- children: [
- {
- path: 'dashboard',
- name: 'Dashboard',
- component: () => import('@/views/dashboard/index.vue'),
- meta: { title: '首页', icon: 'HomeFilled' }
- }
- ]
- },
- {
- path: '/workbench',
- component: () => import('@/components/Layout/index.vue'),
- meta: { title: '工作台', icon: 'Monitor' },
- children: [
- {
- path: '',
- name: 'Workbench',
- component: () => import('@/views/workbench/index.vue'),
- meta: { title: '智能工作台', icon: 'Monitor' }
- }
- ]
- },
- {
- path: '/analysis',
- component: () => import('@/components/Layout/index.vue'),
- redirect: '/analysis/flow',
- meta: { title: '数据看板', icon: 'TrendCharts' },
- children: [
- {
- path: 'flow',
- name: 'FlowAnalysis',
- component: () => import('@/views/analysis/index.vue'),
- meta: { title: '流程分析看板', icon: 'TrendCharts' }
- }
- ]
- },
- {
- path: '/system',
- component: () => import('@/components/Layout/index.vue'),
- redirect: '/system/user',
- meta: { title: '系统管理', icon: 'Setting' },
- children: [
- {
- path: 'user',
- name: 'User',
- component: () => import('@/views/system/user/index.vue'),
- meta: { title: '用户管理', icon: 'UserFilled' }
- },
- {
- path: 'role',
- name: 'Role',
- component: () => import('@/views/system/role/index.vue'),
- meta: { title: '审批角色', icon: 'User' }
- },
- ]
- },
- {
- path: '/flow',
- component: () => import('@/components/Layout/index.vue'),
- redirect: '/flow/definition',
- meta: { title: '流程管理', icon: 'Connection' },
- children: [
- {
- path: 'designer',
- name: 'FlowDesigner',
- component: () => import('@/views/flow/designer/index.vue'),
- meta: { title: '流程设计器', icon: 'EditPen' }
- },
- {
- path: 'definition',
- name: 'FlowDefinition',
- component: () => import('@/views/flow/definition/index.vue'),
- meta: { title: '流程管理', icon: 'Document' }
- }
- ]
- },
- {
- path: '/approval',
- component: () => import('@/components/Layout/index.vue'),
- redirect: '/approval/todo',
- meta: { title: '审批中心', icon: 'Stamp' },
- children: [
- {
- path: 'todo',
- name: 'Todo',
- component: () => import('@/views/flow/task/todo.vue'),
- meta: { title: '我的待办', icon: 'Bell' }
- },
- {
- path: 'handled',
- name: 'Handled',
- component: () => import('@/views/flow/task/handled.vue'),
- meta: { title: '我的已办', icon: 'CircleCheck' }
- },
- {
- path: 'cc',
- name: 'Cc',
- component: () => import('@/views/flow/task/cc.vue'),
- meta: { title: '我的抄送', icon: 'Message' }
- },
- {
- path: 'mine',
- name: 'MyInstance',
- component: () => import('@/views/flow/instance/mine.vue'),
- meta: { title: '我的流程', icon: 'List' }
- },
- {
- path: 'execute',
- name: 'FlowExecute',
- component: () => import('@/views/flow/execute/index.vue'),
- meta: { title: '流程执行', icon: 'Pointer' }
- },
- {
- path: 'all',
- name: 'AllInstance',
- component: () => import('@/views/flow/instance/all.vue'),
- meta: { title: '流程明细', icon: 'Document' }
- }
- ]
- }
- ]
- })
- const publicPaths = new Set(['/login'])
- // 按员工类型限制的路径
- const permissionPaths: Record<string, Set<string>> = {
- common_user: new Set(['/', '/dashboard', '/login', '/profile', '/approval/todo', '/approval/handled', '/approval/mine', '/approval/execute', '/approval/cc']),
- dept_manager: new Set(['/', '/dashboard', '/login', '/profile', '/system/user', '/system/role', '/approval/todo', '/approval/handled', '/approval/mine', '/approval/execute', '/approval/cc']),
- flow_manager: new Set(['/', '/dashboard', '/login', '/profile', '/flow/designer', '/flow/definition', '/flow/instance/all', '/approval/todo', '/approval/handled', '/approval/mine', '/approval/execute', '/approval/cc', '/analysis']),
- super_admin: new Set(['/', '/dashboard', '/login', '/profile', '/system/user', '/system/role', '/flow/designer', '/flow/definition', '/flow/instance/all', '/approval/todo', '/approval/handled', '/approval/mine', '/approval/execute', '/approval/cc', '/analysis'])
- }
- function isPathAllowed(allowedSet: Set<string>, path: string): boolean {
- if (allowedSet.has(path)) return true
- // 允许子路径,但父路径必须以 / 结尾或精确匹配
- for (const allowed of allowedSet) {
- if (allowed !== '/' && path.startsWith(allowed + '/')) {
- return true
- }
- }
- return false
- }
- // 防止快速切换 tab 时并发多次拉取用户信息
- let fetchingUserInfo: Promise<unknown> | null = null
- router.beforeEach(async (to, from, next) => {
- const token = getToken()
- // 404、登录页等公开页面直接放行
- if (publicPaths.has(to.path) || to.name === 'NotFound') {
- next()
- return
- }
- if (token) {
- const userStore = useUserStore()
- if (!userStore.userInfo) {
- try {
- if (!fetchingUserInfo) {
- fetchingUserInfo = userStore.fetchUserInfo().catch(async (err) => {
- await userStore.logoutAction()
- throw err
- })
- }
- await fetchingUserInfo
- } catch {
- next(`/login?redirect=${to.path}`)
- return
- } finally {
- fetchingUserInfo = null
- }
- }
- // 按 employeeType 限制
- const employeeType = userStore.userInfo?.employeeType || 'common_user'
- const allowedPaths = permissionPaths[employeeType] || permissionPaths['common_user']
- if (!isPathAllowed(allowedPaths, to.path)) {
- next('/dashboard')
- return
- }
- next()
- } else {
- next(`/login?redirect=${to.path}`)
- }
- })
- export default router
|