PayrollManagementSystem/frontend/src/router/index.ts
liuwenxin 06cdf4141f feat(business): 前端业务/发货/回款管理三页
- 业务页:明细行编辑器、详情抽屉五分区(含状态时间线与毛利润卡片)
- 回款页:业务→发货批次级联指定(可清空)、已核算行禁改禁删
- 金额/比率字符串直出;毛利润卡片注明不含运费口径

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-13 12:50:10 +08:00

175 lines
6.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router'
import { ElMessage } from 'element-plus'
import { useUserStore } from '@/store/user'
import { ROLE_ADMIN } from '@/utils/constants'
declare module 'vue-router' {
interface RouteMeta {
/** 免登录页面(登录页) */
public?: boolean
/** 页面标题:浏览器标题 / 面包屑 / 菜单共用,新页面必须写 */
title?: string
/** 仅管理员可访问 —— 菜单隐藏 + 守卫兜底(直接输 URL 会被弹回首页) */
requiresAdmin?: boolean
/** 是否出现在侧边菜单(默认 true);false 用于排除登录页等 */
menu?: boolean
/** 菜单分组名(同名聚合为一个子菜单);不设则为顶层菜单项 */
group?: string
/** 菜单排序,越小越靠前 */
order?: number
}
}
const routes: RouteRecordRaw[] = [
{
path: '/login',
name: 'login',
component: () => import('@/views/login/index.vue'),
meta: { public: true, title: '登录', menu: false },
},
{
// 应用主框架:菜单、顶栏、面包屑由布局提供,业务页面作为子路由渲染
path: '/',
component: () => import('@/components/layout/BasicLayout.vue'),
redirect: '/dashboard',
children: [
{
path: '/dashboard',
name: 'dashboard',
component: () => import('@/views/dashboard/index.vue'),
meta: { title: '首页', order: 1 },
},
{
path: '/system/users',
name: 'system-users',
component: () => import('@/views/system/users/index.vue'),
meta: { title: '用户管理', group: '系统管理', requiresAdmin: true, order: 2 },
},
{
path: '/system/roles',
name: 'system-roles',
component: () => import('@/views/system/roles/index.vue'),
meta: { title: '角色管理', group: '系统管理', requiresAdmin: true, order: 3 },
},
{
path: '/system/business-roles',
name: 'system-business-roles',
component: () => import('@/views/system/business-roles/index.vue'),
meta: { title: '岗位角色', group: '系统管理', requiresAdmin: true, order: 5 },
},
{
path: '/system/params',
name: 'system-params',
component: () => import('@/views/system/params/index.vue'),
meta: { title: '计提参数', group: '系统管理', requiresAdmin: true, order: 6 },
},
{
path: '/system/logs',
name: 'system-logs',
component: () => import('@/views/system/logs/index.vue'),
meta: { title: '日志查询', group: '系统管理', requiresAdmin: true, order: 7 },
},
{
// 基础数据属业务操作:登录即可访问,不设 requiresAdmin(对照后端 api/v1/base)
path: '/base/personnel',
name: 'base-personnel',
component: () => import('@/views/base/personnel/index.vue'),
meta: { title: '人员管理', group: '基础数据', order: 8 },
},
{
path: '/base/products',
name: 'base-products',
component: () => import('@/views/base/products/index.vue'),
meta: { title: '产品管理', group: '基础数据', order: 9 },
},
{
path: '/base/customers',
name: 'base-customers',
component: () => import('@/views/base/customers/index.vue'),
meta: { title: '客户管理', group: '基础数据', order: 10 },
},
{
// 业务数据组一律为业务操作:登录即可访问,不设 requiresAdmin
path: '/business/businesses',
name: 'business-businesses',
component: () => import('@/views/business/businesses/index.vue'),
meta: { title: '业务管理', group: '业务数据', order: 11 },
},
{
path: '/business/shipments',
name: 'business-shipments',
component: () => import('@/views/business/shipments/index.vue'),
meta: { title: '发货管理', group: '业务数据', order: 12 },
},
{
path: '/business/receipts',
name: 'business-receipts',
component: () => import('@/views/business/receipts/index.vue'),
meta: { title: '回款管理', group: '业务数据', order: 13 },
},
{
// 业务数据组首个页面:评级计算器是打分工具,不影响绩效金额,
// 登录用户即可用,不设 requiresAdmin(区别于系统管理组)
path: '/business/rating',
name: 'business-rating',
component: () => import('@/views/business/rating/index.vue'),
meta: { title: '客户评级计算器', group: '业务数据', order: 14 },
},
],
},
// 未匹配路由回首页;若未登录会被守卫拦到登录页
{ path: '/:pathMatch(.*)*', redirect: '/dashboard' },
]
const router = createRouter({
history: createWebHistory(),
routes,
})
/**
* 全局前置守卫。
*
* 四层判断:
* 1. `meta.public` 标记的页面(登录页)直接放行
* 2. 无令牌 → 跳登录页,并把原目标记在 query 里供登录后回跳
* 3. 有令牌但内存中无用户信息(说明是刷新页面)→ 调 /me 恢复会话;
* 失败则视为令牌已失效,清状态并跳登录页
* 4. `meta.requiresAdmin` 的页面要求管理员角色 —— 此时用户信息已就绪,
* 这是"隐藏菜单"之外的第二道防线(防手输 URL)
*/
router.beforeEach(async (to) => {
const userStore = useUserStore()
if (to.meta.public) {
return true
}
if (!userStore.token) {
return { path: '/login', query: { redirect: to.fullPath } }
}
if (!userStore.userInfo) {
try {
await userStore.fetchUserInfo()
} catch {
userStore.resetAuth()
return { path: '/login', query: { redirect: to.fullPath } }
}
}
if (to.meta.requiresAdmin && !userStore.roles.includes(ROLE_ADMIN)) {
ElMessage.error('需要管理员权限')
return { path: '/dashboard' }
}
return true
})
router.afterEach((to) => {
const title = to.meta.title as string | undefined
document.title = title ? `${title} - ${import.meta.env.VITE_APP_TITLE}` : import.meta.env.VITE_APP_TITLE
})
export default router