From 4edb7619bcb47505f5ff2ecfacc26de1d0116524 Mon Sep 17 00:00:00 2001 From: WorkBuddy Date: Fri, 9 Oct 2026 19:33:40 +0800 Subject: [PATCH] =?UTF-8?q?fix(admin-web,db):=20=E7=BA=A2=E5=A8=98?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E6=9D=83=E9=99=90=E7=A0=81=E5=AF=B9=E9=BD=90?= =?UTF-8?q?=E5=90=8E=E7=AB=AF=E7=9C=9F=E5=AE=9E=E7=A0=81=20+=20=E7=BA=A2?= =?UTF-8?q?=E5=A8=98=E8=A7=92=E8=89=B2=E6=8E=88=E6=9D=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 前端菜单/路由守卫用 referral.manage、matchmaker.service.view,但后端 permissions 表不存在这两个码(referral 控制器要 matchmaker.service、红娘控制器要 matchmaker.view/service/assign)。visibleNavigation 据此把「公益红娘」「红娘服务」 两个菜单对**所有角色(含 super_admin)隐藏**。 - admin-web: MainLayout.vue(菜单 + 角色名判定)、router/index.ts(路由 meta)、 stores/auth.ts(DEV 预览角色)三处对齐为后端真实 authority 码。 - db: 新增 V052 迁移,将 matchmaker.view/service/assign 授予 matchmaker 角色 (005),修复「角色定义!=可用」同族缺陷;幂等 ON CONFLICT DO NOTHING。 - 重建 danyang-admin-web 镜像并重新部署;运行时验证 wanghongniang 登录返回 [matchmaker.assign, matchmaker.service, matchmaker.view],两菜单可见。 --- admin-web/src/layouts/MainLayout.vue | 6 ++-- admin-web/src/router/index.ts | 4 +-- admin-web/src/stores/auth.ts | 4 +-- .../V052__grant_matchmaker_permissions.sql | 28 +++++++++++++++++++ 4 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 backend/src/main/resources/db/migration/V052__grant_matchmaker_permissions.sql diff --git a/admin-web/src/layouts/MainLayout.vue b/admin-web/src/layouts/MainLayout.vue index ff99013..5276e3c 100644 --- a/admin-web/src/layouts/MainLayout.vue +++ b/admin-web/src/layouts/MainLayout.vue @@ -174,8 +174,8 @@ const navigation: NavigationItem[] = [ { label: '用户管理', path: '/users', permissions: ['user.view'], icon: User }, { label: '资料审核', path: '/review', permissions: ['review.view'], icon: DocumentChecked }, { label: '匹配管理', path: '/activities/interests', permissions: ['activity.review_registration'], icon: StarFilled }, - { label: '公益红娘', path: '/referral', permissions: ['referral.manage'], icon: Connection }, - { label: '红娘服务', path: '/matchmaker', permissions: ['matchmaker.service.view'], icon: Connection }, + { label: '公益红娘', path: '/referral', permissions: ['matchmaker.service'], icon: Connection }, + { label: '红娘服务', path: '/matchmaker', permissions: ['matchmaker.view'], icon: Connection }, { label: '公益咨询', path: '/counseling', permissions: ['counseling.service.view'], icon: ChatDotRound }, { label: '活动管理', path: '/activities', permissions: ['activity.view'], icon: Calendar }, { label: '活动签到', path: '/activities/checkin', permissions: ['activity.checkin'], icon: Calendar }, @@ -217,7 +217,7 @@ const currentRoleName = computed(() => { if (perms.includes('counseling.service.view')) return '公益咨询人员' if (perms.includes('service_appointment.view')) return '服务站运营人员' if (perms.includes('review.view')) return '资料审核人员' - if (perms.includes('matchmaker.service.view')) return '公益红娘' + if (perms.includes('matchmaker.view')) return '公益红娘' return '运营人员' }) const visibleNavigation = computed(() => navigation.filter((item) => item.permissions.every(hasPerm))) diff --git a/admin-web/src/router/index.ts b/admin-web/src/router/index.ts index a86c3eb..de5ecb1 100644 --- a/admin-web/src/router/index.ts +++ b/admin-web/src/router/index.ts @@ -37,8 +37,8 @@ const routes: RouteRecordRaw[] = [ { path: 'service-appointment', name: 'ServiceAppointment', component: () => import('@/modules/service-appointment/ServiceAppointmentView.vue'), meta: { title: '服务预约', permissions: ['service_appointment.view'] } }, { path: 'service-program', name: 'ServiceProgram', component: () => import('@/modules/service-program/ServiceProgramView.vue'), meta: { title: '专项服务项目', permissions: ['service_program.manage'] } }, { path: 'counseling', name: 'Counseling', component: () => import('@/modules/counseling/CounselingView.vue'), meta: { title: '婚恋咨询', permissions: ['counseling.service.view'] } }, - { path: 'referral', name: 'ReferralManagement', component: () => import('@/modules/referral/ReferralManagementView.vue'), meta: { title: '转介管理', permissions: ['referral.manage'] } }, - { path: 'matchmaker', name: 'MatchmakerManagement', component: () => import('@/modules/matchmaker/MatchmakerManagementView.vue'), meta: { title: '红娘管理', permissions: ['matchmaker.service.view'] } }, + { path: 'referral', name: 'ReferralManagement', component: () => import('@/modules/referral/ReferralManagementView.vue'), meta: { title: '转介管理', permissions: ['matchmaker.service'] } }, + { path: 'matchmaker', name: 'MatchmakerManagement', component: () => import('@/modules/matchmaker/MatchmakerManagementView.vue'), meta: { title: '红娘管理', permissions: ['matchmaker.view'] } }, ], }, diff --git a/admin-web/src/stores/auth.ts b/admin-web/src/stores/auth.ts index e90f414..f97964a 100644 --- a/admin-web/src/stores/auth.ts +++ b/admin-web/src/stores/auth.ts @@ -13,9 +13,9 @@ interface OperatorInfo { const previewRolePermissions: Record = { reviewer: ['review.view', 'user.view'], - counselor: ['counseling.service.view', 'referral.manage'], + counselor: ['counseling.service.view', 'matchmaker.service'], station: ['service_location.view', 'service_appointment.view'], - operator: ['review.view', 'user.view', 'organization.manage', 'permission.manage', 'activity.review_registration', 'risk.report.view', 'risk.report.process', 'analytics.view', 'banner.view', 'content.view', 'service_location.view', 'service_appointment.view', 'service_program.manage', 'counseling.service.view', 'referral.manage'], + operator: ['review.view', 'user.view', 'organization.manage', 'permission.manage', 'activity.review_registration', 'risk.report.view', 'risk.report.process', 'analytics.view', 'banner.view', 'content.view', 'service_location.view', 'service_appointment.view', 'service_program.manage', 'counseling.service.view', 'matchmaker.view', 'matchmaker.service'], } export const useAuthStore = defineStore('auth', () => { diff --git a/backend/src/main/resources/db/migration/V052__grant_matchmaker_permissions.sql b/backend/src/main/resources/db/migration/V052__grant_matchmaker_permissions.sql new file mode 100644 index 0000000..7316e4d --- /dev/null +++ b/backend/src/main/resources/db/migration/V052__grant_matchmaker_permissions.sql @@ -0,0 +1,28 @@ +-- ============================================================ +-- V052: 补齐 matchmaker(公益红娘)角色权限 +-- +-- 发现方式:2026-10-09 搭建本地演示栈、创建红娘运营账号 wanghongniang 并授予 +-- matchmaker 角色后发现,该角色在 role_permissions 中零条授权。 +-- 用该账号登录后台,点「红娘服务」菜单加载 GET /operator/matchmaker/dashboard +-- 直接 403;同时前端菜单权限码(referral.manage / matchmaker.service.view)与后端 +-- 真实 authority 码(matchmaker.service / matchmaker.view)不匹配,导致这两个菜单 +-- 对所有角色(含 super_admin)被 visibleNavigation 过滤隐藏。 +-- +-- 根因:与 V043/V044 同族 —— 角色定义了、权限定义了,两者之间从未连上。 +-- V015 只把全部权限授予 super_admin;matchmaker 等运营角色从未被授予任何权限。 +-- +-- 授权范围(最小权限原则,与后端 @PreAuthorize 严格对应): +-- * matchmaker.view —— 查看红娘服务(GET /operator/matchmaker/*) +-- * matchmaker.service —— 认领/推荐/跟进/完成红娘服务 + 转介管理(referral 控制器) +-- * matchmaker.assign —— 分配红娘服务 +-- 后端 MatchmakerOperatorController / ReferralController 的 @PreAuthorize 仅要求这三条, +-- 故仅授予这三条,不扩权。 +-- +-- 幂等:ON CONFLICT (role_id, permission_id) DO NOTHING。 +-- ============================================================ + +INSERT INTO role_permissions (role_id, permission_id) +SELECT '00000000-0000-0000-0000-000000000005', id +FROM permissions +WHERE code IN ('matchmaker.view', 'matchmaker.service', 'matchmaker.assign') +ON CONFLICT (role_id, permission_id) DO NOTHING;