|
|
|
|
@ -2,186 +2,58 @@ import { createRouter, createWebHashHistory } from 'vue-router'
|
|
|
|
|
import { getToken, setToken } from '@/utils/auth'
|
|
|
|
|
import Login from '@/views/Login.vue'
|
|
|
|
|
import MainLayout from '@/layout/MainLayout.vue'
|
|
|
|
|
import Dashboard from '@/views/Dashboard.vue'
|
|
|
|
|
import BudgetList from '@/views/BudgetList.vue'
|
|
|
|
|
import ExecutionList from '@/views/ExecutionList.vue'
|
|
|
|
|
import Report from '@/views/Report.vue'
|
|
|
|
|
|
|
|
|
|
// 事前流程
|
|
|
|
|
import StartProcess from '@/views/pre-approval/StartProcess.vue'
|
|
|
|
|
import ProcessQuery from '@/views/pre-approval/ProcessQuery.vue'
|
|
|
|
|
|
|
|
|
|
// 支付流程
|
|
|
|
|
import DirectPayment from '@/views/payment/DirectPayment.vue'
|
|
|
|
|
import IndirectPayment from '@/views/payment/IndirectPayment.vue'
|
|
|
|
|
import PaymentProcessQuery from '@/views/payment/ProcessQuery.vue'
|
|
|
|
|
import PaymentQuery from '@/views/payment/PaymentQuery.vue'
|
|
|
|
|
import PaymentDetailPrint from '@/views/payment/PaymentDetailPrint.vue'
|
|
|
|
|
import DraftQuery from '@/views/payment/DraftQuery.vue'
|
|
|
|
|
import CreatePayment from '@/views/payment/CreatePayment.vue'
|
|
|
|
|
import ContractManagement from '@/views/payment/ContractManagement.vue'
|
|
|
|
|
import ContractSettings from '@/views/payment/ContractSettings.vue'
|
|
|
|
|
|
|
|
|
|
// 资金管理
|
|
|
|
|
import Budget from '@/views/funds/Budget.vue'
|
|
|
|
|
import BudgetManagement from '@/views/funds/BudgetManagement.vue'
|
|
|
|
|
|
|
|
|
|
// 系统设置
|
|
|
|
|
import CanvasSettings from '@/views/settings/CanvasSettings.vue'
|
|
|
|
|
import PlannedExpenditureCategory from '@/views/settings/PlannedExpenditureCategory.vue'
|
|
|
|
|
import PaymentCategory from '@/views/settings/PaymentCategory.vue'
|
|
|
|
|
import TemplateElementSettings from '@/views/settings/TemplateElementSettings.vue'
|
|
|
|
|
import PaymentTemplateElementSettings from '@/views/settings/PaymentTemplateElementSettings.vue'
|
|
|
|
|
import PreApprovalTemplateSettings from '@/views/settings/PreApprovalTemplateSettings.vue'
|
|
|
|
|
import PreApprovalProcessConfig from '@/views/settings/PreApprovalProcessConfig.vue'
|
|
|
|
|
|
|
|
|
|
const routes = [
|
|
|
|
|
/**
|
|
|
|
|
* 常量路由(无需权限,所有角色可访问)
|
|
|
|
|
*/
|
|
|
|
|
export const constantRoutes = [
|
|
|
|
|
{
|
|
|
|
|
path: '/login',
|
|
|
|
|
name: 'Login',
|
|
|
|
|
component: Login
|
|
|
|
|
component: Login,
|
|
|
|
|
hidden: true
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: '/404',
|
|
|
|
|
name: '404',
|
|
|
|
|
component: () => import('@/views/404.vue'),
|
|
|
|
|
hidden: true
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: '/',
|
|
|
|
|
name: 'Layout',
|
|
|
|
|
component: MainLayout,
|
|
|
|
|
redirect: '/dashboard',
|
|
|
|
|
children: [
|
|
|
|
|
{
|
|
|
|
|
path: 'dashboard',
|
|
|
|
|
name: 'Dashboard',
|
|
|
|
|
component: Dashboard
|
|
|
|
|
},
|
|
|
|
|
// 事前流程
|
|
|
|
|
{
|
|
|
|
|
path: 'pre-approval/start-process',
|
|
|
|
|
name: 'StartProcess',
|
|
|
|
|
component: StartProcess
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: 'pre-approval/process-query',
|
|
|
|
|
name: 'ProcessQuery',
|
|
|
|
|
component: ProcessQuery
|
|
|
|
|
},
|
|
|
|
|
// 支付流程
|
|
|
|
|
{
|
|
|
|
|
path: 'payment/direct-payment',
|
|
|
|
|
name: 'DirectPayment',
|
|
|
|
|
component: DirectPayment
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: 'payment/indirect-payment',
|
|
|
|
|
name: 'IndirectPayment',
|
|
|
|
|
component: IndirectPayment
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: 'payment/process-query',
|
|
|
|
|
name: 'PaymentProcessQuery',
|
|
|
|
|
component: PaymentProcessQuery
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: 'payment/payment-query',
|
|
|
|
|
name: 'PaymentQuery',
|
|
|
|
|
component: PaymentQuery
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: 'payment/payment-detail-print/:id',
|
|
|
|
|
name: 'PaymentDetailPrint',
|
|
|
|
|
component: PaymentDetailPrint
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: 'payment/draft-query',
|
|
|
|
|
name: 'DraftQuery',
|
|
|
|
|
component: DraftQuery
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: 'payment/create-payment',
|
|
|
|
|
name: 'CreatePayment',
|
|
|
|
|
component: CreatePayment
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: 'payment/contract-management',
|
|
|
|
|
name: 'ContractManagement',
|
|
|
|
|
component: ContractManagement
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: 'settings/contract-settings',
|
|
|
|
|
name: 'ContractSettings',
|
|
|
|
|
component: ContractSettings
|
|
|
|
|
},
|
|
|
|
|
// 资金管理
|
|
|
|
|
{
|
|
|
|
|
path: 'funds/budget',
|
|
|
|
|
name: 'Budget',
|
|
|
|
|
component: Budget
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: 'funds/budget-management',
|
|
|
|
|
name: 'BudgetManagement',
|
|
|
|
|
component: BudgetManagement
|
|
|
|
|
},
|
|
|
|
|
// 系统设置
|
|
|
|
|
{
|
|
|
|
|
path: 'settings/planned-expenditure-template-settings',
|
|
|
|
|
name: 'CanvasSettings',
|
|
|
|
|
component: CanvasSettings
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: 'settings/planned-expenditure-category',
|
|
|
|
|
name: 'PlannedExpenditureCategory',
|
|
|
|
|
component: PlannedExpenditureCategory
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: 'settings/payment-category',
|
|
|
|
|
name: 'PaymentCategory',
|
|
|
|
|
component: PaymentCategory
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: 'settings/template-element-settings',
|
|
|
|
|
name: 'TemplateElementSettings',
|
|
|
|
|
component: TemplateElementSettings
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: 'settings/payment-template-element-settings',
|
|
|
|
|
name: 'PaymentTemplateElementSettings',
|
|
|
|
|
component: PaymentTemplateElementSettings
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: 'settings/pre-approval-template-settings',
|
|
|
|
|
name: 'PreApprovalTemplateSettings',
|
|
|
|
|
component: PreApprovalTemplateSettings
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: 'settings/pre-approval-process-config',
|
|
|
|
|
name: 'PreApprovalProcessConfig',
|
|
|
|
|
component: PreApprovalProcessConfig
|
|
|
|
|
},
|
|
|
|
|
// 保留原有路由
|
|
|
|
|
{
|
|
|
|
|
path: 'budget-list',
|
|
|
|
|
name: 'BudgetList',
|
|
|
|
|
component: BudgetList
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: 'execution-list',
|
|
|
|
|
name: 'ExecutionList',
|
|
|
|
|
component: ExecutionList
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
path: 'report',
|
|
|
|
|
name: 'Report',
|
|
|
|
|
component: Report
|
|
|
|
|
component: () => import('@/views/Dashboard.vue'),
|
|
|
|
|
meta: {
|
|
|
|
|
title: '首页',
|
|
|
|
|
icon: 'el-icon-odometer'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
const router = createRouter({
|
|
|
|
|
history: createWebHashHistory(),
|
|
|
|
|
routes
|
|
|
|
|
})
|
|
|
|
|
/**
|
|
|
|
|
* 异步路由(需权限,动态加载)
|
|
|
|
|
*/
|
|
|
|
|
export const asyncRoutes = []
|
|
|
|
|
|
|
|
|
|
const createRouterInstance = () => {
|
|
|
|
|
return createRouter({
|
|
|
|
|
history: createWebHashHistory(),
|
|
|
|
|
routes: constantRoutes
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const router = createRouterInstance()
|
|
|
|
|
|
|
|
|
|
// 路由守卫 - 处理跨模块认证和登录状态检查
|
|
|
|
|
router.beforeEach((to, from, next) => {
|
|
|
|
|
router.beforeEach(async (to, from, next) => {
|
|
|
|
|
try {
|
|
|
|
|
// 1. 处理URL参数中的auth_token(跨模块跳转时携带)
|
|
|
|
|
if (to.query.auth_token) {
|
|
|
|
|
@ -202,11 +74,86 @@ router.beforeEach((to, from, next) => {
|
|
|
|
|
: '/'
|
|
|
|
|
next({ path: redirectPath, replace: true })
|
|
|
|
|
} else {
|
|
|
|
|
// 支持to参数进行路由跳转(跨模块跳转时使用)
|
|
|
|
|
if (to.query.to && /^\/.*/.test(to.query.to)) {
|
|
|
|
|
next({ path: to.query.to, replace: true })
|
|
|
|
|
// 动态加载路由
|
|
|
|
|
const { usePermissionStore } = await import('@/store/permission')
|
|
|
|
|
const permissionStore = usePermissionStore()
|
|
|
|
|
|
|
|
|
|
// 如果还没有生成路由,则生成
|
|
|
|
|
if (permissionStore.addRoutes.length === 0) {
|
|
|
|
|
try {
|
|
|
|
|
const accessedRoutes = await permissionStore.generateRoutes()
|
|
|
|
|
console.log('[Router] 获取到的路由:', accessedRoutes)
|
|
|
|
|
|
|
|
|
|
// 过滤出 404 路由和其他路由
|
|
|
|
|
const notFoundRoute = accessedRoutes.find(route => route.path === '/:pathMatch(.*)*')
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 扁平化路由树,将一级菜单的 children 提取出来作为独立路由
|
|
|
|
|
* 因为 Vue Router 4 不能注册 path 为空的路由,但我们需要保留一级菜单结构用于菜单显示
|
|
|
|
|
*/
|
|
|
|
|
const flattenRoutes = (routes) => {
|
|
|
|
|
const flattened = []
|
|
|
|
|
routes.forEach(route => {
|
|
|
|
|
// 跳过 404 路由
|
|
|
|
|
if (route.path === '/:pathMatch(.*)*') {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果路由有 children 且 path 为空(文件夹路由),提取其 children
|
|
|
|
|
if (route.children && route.children.length > 0 && (!route.path || route.path === '')) {
|
|
|
|
|
// 递归处理 children,将它们扁平化
|
|
|
|
|
const childRoutes = flattenRoutes(route.children)
|
|
|
|
|
flattened.push(...childRoutes)
|
|
|
|
|
} else if (route.path && route.path !== '') {
|
|
|
|
|
// 如果路由有实际的 path,直接添加(但需要移除 children,因为已经扁平化了)
|
|
|
|
|
const { children, ...routeWithoutChildren } = route
|
|
|
|
|
flattened.push(routeWithoutChildren)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
return flattened
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const dynamicRoutes = flattenRoutes(accessedRoutes)
|
|
|
|
|
|
|
|
|
|
console.log('[Router] 动态路由数量:', dynamicRoutes.length)
|
|
|
|
|
console.log('[Router] 动态路由详情:', dynamicRoutes)
|
|
|
|
|
|
|
|
|
|
// 将动态路由作为主布局(name: 'Layout')的子路由添加
|
|
|
|
|
dynamicRoutes.forEach((route, index) => {
|
|
|
|
|
console.log(`[Router] 添加路由 ${index + 1}:`, route.path, route.name)
|
|
|
|
|
router.addRoute('Layout', route)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 最后添加 404 路由(放在最后匹配)
|
|
|
|
|
if (notFoundRoute) {
|
|
|
|
|
router.addRoute(notFoundRoute)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 打印所有路由用于调试
|
|
|
|
|
console.log('[Router] 当前所有路由:', router.getRoutes())
|
|
|
|
|
|
|
|
|
|
// 重新导航到目标路由,确保路由已添加
|
|
|
|
|
// 如果访问的是根路径,重定向到 dashboard
|
|
|
|
|
if (to.path === '/' || to.path === '') {
|
|
|
|
|
console.log('[Router] 重定向到 /dashboard')
|
|
|
|
|
next({ path: '/dashboard', replace: true })
|
|
|
|
|
} else {
|
|
|
|
|
console.log('[Router] 导航到:', to.path)
|
|
|
|
|
next({ ...to, replace: true })
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('[Router] 生成动态路由失败:', error)
|
|
|
|
|
console.error('[Router] 错误详情:', error)
|
|
|
|
|
// 如果生成路由失败,仍然允许访问
|
|
|
|
|
next()
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
next()
|
|
|
|
|
// 支持to参数进行路由跳转(跨模块跳转时使用)
|
|
|
|
|
if (to.query.to && /^\/.*/.test(to.query.to)) {
|
|
|
|
|
next({ path: to.query.to, replace: true })
|
|
|
|
|
} else {
|
|
|
|
|
next()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
@ -234,5 +181,13 @@ router.beforeEach((to, from, next) => {
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 重置路由
|
|
|
|
|
*/
|
|
|
|
|
export function resetRouter() {
|
|
|
|
|
const newRouter = createRouterInstance()
|
|
|
|
|
router.matcher = newRouter.matcher
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default router
|
|
|
|
|
|
|
|
|
|
|