diff --git a/bx-mobile/src/router/index.ts b/bx-mobile/src/router/index.ts index de6b15050..a7138ab0b 100644 --- a/bx-mobile/src/router/index.ts +++ b/bx-mobile/src/router/index.ts @@ -1,4 +1,5 @@ import { createRouter, createWebHistory } from 'vue-router' +import { showToast } from 'vant' import { useAuthStore } from '@/stores/auth' const routes = [ @@ -13,29 +14,110 @@ const routes = [ component: () => import('@/views/home/HomeLayout.vue'), children: [ { path: '', name: 'Home', component: () => import('@/views/home/HomePage.vue') }, - { path: 'mine', name: 'Mine', component: () => import('@/views/mine/MinePage.vue') }, - { path: 'approval', name: 'Approval', component: () => import('@/views/approval/ApprovalPage.vue') }, - { path: 'approval/:bizType/:id', name: 'ApprovalDetail', component: () => import('@/views/approval/ApprovalDetailPage.vue') }, - { path: 'advance/list', name: 'AdvanceList', component: () => import('@/views/advance/AdvanceListPage.vue') }, - { path: 'advance/apply', name: 'AdvanceApply', component: () => import('@/views/advance/AdvanceApplyPage.vue') }, + { + path: 'mine', + name: 'Mine', + component: () => import('@/views/mine/MinePage.vue'), + meta: { menuCodes: ['bx:viewMine:list'] }, + }, + { + path: 'approval', + name: 'Approval', + component: () => import('@/views/approval/ApprovalPage.vue'), + meta: { menuCodes: ['bx:viewTodo:list'] }, + }, + { + path: 'approval/:bizType/:id', + name: 'ApprovalDetail', + component: () => import('@/views/approval/ApprovalDetailPage.vue'), + meta: { menuCodes: ['bx:viewTodo:list', 'bx:advanceApprove:list', 'bx:reimburseApprove:list'] }, + }, + { + path: 'advance/list', + name: 'AdvanceList', + component: () => import('@/views/advance/AdvanceListPage.vue'), + meta: { menuCodes: ['bx:advanceApply:list'] }, + }, + { + path: 'advance/apply', + name: 'AdvanceApply', + component: () => import('@/views/advance/AdvanceApplyPage.vue'), + meta: { menuCodes: ['bx:advanceApply:list'] }, + }, /* 须放在 advance/:id 之前,否则 approve/issue 会被当成动态 id */ - { path: 'advance/approve', name: 'AdvanceApprove', component: () => import('@/views/advance/AdvanceApprovePage.vue'), meta: { roles: ['ADMIN', 'FINANCE', 'GENERAL_MANAGER'] } }, - /* 与 bx_menu_role 一致:ADMIN、FINANCE 均分配「备用金发放管理」 */ - { path: 'advance/issue', name: 'AdvanceIssue', component: () => import('@/views/advance/AdvanceIssuePage.vue'), meta: { roles: ['ADMIN', 'FINANCE'] } }, - { path: 'advance/:id', name: 'AdvanceDetail', component: () => import('@/views/advance/AdvanceDetailPage.vue') }, - { path: 'reimburse/list', name: 'ReimburseList', component: () => import('@/views/reimburse/ReimburseListPage.vue') }, - { path: 'reimburse/apply', name: 'ReimburseApply', component: () => import('@/views/reimburse/ReimburseApplyPage.vue') }, - { path: 'reimburse/approve', name: 'ReimburseApprove', component: () => import('@/views/reimburse/ReimburseApprovePage.vue'), meta: { roles: ['ADMIN', 'FINANCE', 'GENERAL_MANAGER'] } }, - { path: 'reimburse/:id', name: 'ReimburseDetail', component: () => import('@/views/reimburse/ReimburseDetailPage.vue') }, - { path: 'payment', name: 'Payment', component: () => import('@/views/payment/PaymentPage.vue'), meta: { roles: ['ADMIN', 'FINANCE'] } }, - { path: 'all', name: 'All', component: () => import('@/views/all/AllPage.vue'), meta: { roles: ['ADMIN', 'GENERAL_MANAGER'] } }, - { path: 'admin', name: 'AdminIndex', component: () => import('@/views/admin/AdminIndexPage.vue'), meta: { roles: ['ADMIN'] } }, - { path: 'admin/users', name: 'UserManage', component: () => import('@/views/admin/UserManagePage.vue'), meta: { roles: ['ADMIN'] } }, - { path: 'admin/roles', name: 'RoleManage', component: () => import('@/views/admin/RoleManagePage.vue'), meta: { roles: ['ADMIN'] } }, - { path: 'admin/menus', name: 'MenuManage', component: () => import('@/views/admin/MenuManagePage.vue'), meta: { roles: ['ADMIN'] } }, - { path: 'admin/expenses', name: 'ExpenseProject', component: () => import('@/views/admin/ExpenseProjectPage.vue'), meta: { roles: ['ADMIN'] } }, - { path: 'admin/wf-advance', name: 'WfAdvance', component: () => import('@/views/admin/WfAdvancePage.vue'), meta: { roles: ['ADMIN'] } }, - { path: 'admin/wf-reimburse', name: 'WfReimburse', component: () => import('@/views/admin/WfReimbursePage.vue'), meta: { roles: ['ADMIN'] } }, + { + path: 'advance/approve', + name: 'AdvanceApprove', + component: () => import('@/views/advance/AdvanceApprovePage.vue'), + meta: { menuCodes: ['bx:advanceApprove:list'] }, + }, + { + path: 'advance/issue', + name: 'AdvanceIssue', + component: () => import('@/views/advance/AdvanceIssuePage.vue'), + meta: { menuCodes: ['bx:advanceIssue:list'] }, + }, + { + path: 'advance/:id', + name: 'AdvanceDetail', + component: () => import('@/views/advance/AdvanceDetailPage.vue'), + meta: { + menuCodes: [ + 'bx:advanceApply:list', + 'bx:advanceApprove:list', + 'bx:advanceIssue:list', + 'bx:viewMine:list', + 'bx:viewTodo:list', + 'bx:viewAll:list', + ], + }, + }, + { + path: 'reimburse/list', + name: 'ReimburseList', + component: () => import('@/views/reimburse/ReimburseListPage.vue'), + meta: { menuCodes: ['bx:reimburseApply:list'] }, + }, + { + path: 'reimburse/apply', + name: 'ReimburseApply', + component: () => import('@/views/reimburse/ReimburseApplyPage.vue'), + meta: { menuCodes: ['bx:reimburseApply:list'] }, + }, + { + path: 'reimburse/approve', + name: 'ReimburseApprove', + component: () => import('@/views/reimburse/ReimburseApprovePage.vue'), + meta: { menuCodes: ['bx:reimburseApprove:list'] }, + }, + { + path: 'reimburse/:id', + name: 'ReimburseDetail', + component: () => import('@/views/reimburse/ReimburseDetailPage.vue'), + meta: { + menuCodes: [ + 'bx:reimburseApply:list', + 'bx:reimburseApprove:list', + 'bx:payment:list', + 'bx:viewMine:list', + 'bx:viewTodo:list', + 'bx:viewAll:list', + ], + }, + }, + { + path: 'payment', + name: 'Payment', + component: () => import('@/views/payment/PaymentPage.vue'), + meta: { menuCodes: ['bx:payment:list'] }, + }, + { + path: 'all', + name: 'All', + component: () => import('@/views/all/AllPage.vue'), + meta: { menuCodes: ['bx:viewAll:list'] }, + }, + /* P1:不注册 invoice/*、admin 配置与 IAM(users/roles/menus) */ { path: 'profile', name: 'Profile', component: () => import('@/views/profile/ProfilePage.vue') }, ], }, @@ -50,9 +132,18 @@ router.beforeEach(async (to, _from, next) => { const auth = useAuthStore() if (to.meta?.public) return next() if (!auth.isLoggedIn) return next('/login') - if (!auth.user) await auth.fetchUser() - const roles = to.meta?.roles as string[] | undefined - if (roles?.length && !roles.some((r: string) => auth.roleCodes.includes(r))) { + if (!auth.user) { + try { + await auth.fetchUser() + } catch { + return next('/login') + } + } + if (!auth.isLoggedIn) return next('/login') + + const codes = to.meta?.menuCodes as string[] | undefined + if (codes?.length && !codes.some((c) => auth.can(c))) { + showToast('无权限') return next('/') } next() diff --git a/bx-mobile/src/views/profile/ProfilePage.vue b/bx-mobile/src/views/profile/ProfilePage.vue index d785ee3b6..40ac147ee 100644 --- a/bx-mobile/src/views/profile/ProfilePage.vue +++ b/bx-mobile/src/views/profile/ProfilePage.vue @@ -28,20 +28,37 @@ - - - - -