shinnosuke
2026-08-06 32a8a52d251106f486bd7576cb662df1264da09a
fix(admin): 按角色权限展示后台菜单 (bug #24030)
5个文件已修改
46 ■■■■■ 已修改文件
talent-card-admin/src/api/auth.ts 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
talent-card-admin/src/layouts/AdminLayout.vue 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
talent-card-admin/src/stores/app.ts 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
talent-card-admin/src/views/LoginView.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
talent-card-server/src/main/java/com/talentcard/server/business/admin/auth/AdminAuthService.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
talent-card-admin/src/api/auth.ts
@@ -4,6 +4,7 @@
  id: number
  name: string
  roleCode: string
  permissionCodes?: string[]
}
export interface AdminLoginResult {
talent-card-admin/src/layouts/AdminLayout.vue
@@ -126,6 +126,20 @@
  { index: 'system-management', label: '系统管理', icon: Setting, items: systemMenus },
]
const routePermissions: Record<string, string> = {
  '/talents': 'admin.talents.view', '/family-card-applications': 'admin.family-cards.view', '/upgrade-applications': 'admin.talents.view', '/family-cards': 'admin.family-cards.view', '/child-cards': 'admin.family-cards.view',
  '/merchants': 'admin.merchants.view', '/products': 'admin.products.view', '/orders': 'admin.orders.view', '/refund-records': 'admin.refunds.view', '/hotel-free-verifications': 'admin.orders.view',
  '/medical-reservations': 'admin.medical-reservations.view', '/medical-applications': 'admin.medical-reservations.view', '/parking-plates': 'admin.parking-plates.view', '/fuel-services': 'admin.parking-plates.view', '/spouse-employment': 'admin.parking-plates.view', '/hotel-reservations': 'admin.medical-reservations.view',
  '/merchant-settlement': 'admin.merchants.view', '/equity-images': 'admin.equity-images.view', '/talent-news-management': 'admin.news.view', '/talent-policy-management': 'admin.news.view', '/movie-tickets': 'admin.news.view',
  '/system-settings': 'admin.settings.view', '/protocol-settings': 'admin.settings.view', '/roles': 'admin.roles.view', '/staff': 'admin.staff.view',
}
const canAccess = (path?: string) => {
  if (!path || appStore.user.role === '平台管理') return true
  const required = routePermissions[path]
  return !required || Boolean(appStore.user.permissionCodes?.includes('*') || appStore.user.permissionCodes?.includes(required))
}
const visibleMenuGroups = computed(() => menuGroups.map((group) => ({ ...group, items: group.items.filter((item) => canAccess(item.path)) })).filter((group) => group.items.length > 0))
const defaultOpeneds = computed(() => {
  const currentGroup = menuGroups.find((item) => findMenuLabel(item.items, activeMenu.value))
  return currentGroup ? [currentGroup.index] : []
@@ -313,7 +327,7 @@
          <span>首页</span>
        </el-menu-item>
        <el-sub-menu v-for="group in menuGroups" :key="group.index" :index="group.index">
        <el-sub-menu v-for="group in visibleMenuGroups" :key="group.index" :index="group.index">
          <template #title>
            <el-icon>
              <component :is="group.icon" />
talent-card-admin/src/stores/app.ts
@@ -3,6 +3,7 @@
interface UserProfile {
  name: string
  role: string
  permissionCodes?: string[]
}
const tokenKey = 'talent-card-admin-token'
talent-card-admin/src/views/LoginView.vue
@@ -46,7 +46,7 @@
    }
    appStore.login(
      result.accessToken,
      { name: result.operator.name, role: result.operator.roleCode === 'platform_admin' ? '平台管理' : result.operator.roleCode },
      { name: result.operator.name, role: result.operator.roleCode === 'platform_admin' ? '平台管理' : result.operator.roleCode, permissionCodes: result.operator.permissionCodes || [] },
      form.remember,
    )
    await router.replace(String(route.query.redirect || '/dashboard'))
talent-card-server/src/main/java/com/talentcard/server/business/admin/auth/AdminAuthService.java
@@ -10,6 +10,8 @@
import java.util.List;
import java.util.Map;
import com.alibaba.fastjson.JSON;
import com.talentcard.server.business.DatabaseRows;
import com.talentcard.server.business.merchant.auth.MerchantPasswordHasher;
import com.talentcard.server.common.BusinessException;
@@ -34,10 +36,11 @@
    public Map<String, Object> login(AdminLoginRequest request, String requestId) {
        String account = request.account().trim();
        List<Map<String, Object>> rows = rows("""
                select id operator_id, password_hash, display_name, role_code, status,
                select o.id operator_id, o.password_hash, o.display_name, o.role_code, o.status,
                       r.permission_codes,
                       login_failed_count, locked_until
                from admin_operator
                where account = ? and deleted = 0
                from admin_operator o left join admin_role r on r.role_code = o.role_code
                where o.account = ? and o.deleted = 0
                limit 1
                """, account);
        if (rows.isEmpty()) {
@@ -114,13 +117,22 @@
        Map<String, Object> result = new LinkedHashMap<>();
        result.put("accessToken", accessToken);
        result.put("expiresIn", ACCESS_TOKEN_SECONDS);
        result.put("operator", Map.of(
                "id", number(operator.get("operatorId")),
                "name", String.valueOf(operator.get("displayName")),
                "roleCode", String.valueOf(operator.get("roleCode"))));
        Map<String, Object> principal = new LinkedHashMap<>();
        principal.put("id", number(operator.get("operatorId")));
        principal.put("name", String.valueOf(operator.get("displayName")));
        principal.put("roleCode", String.valueOf(operator.get("roleCode")));
        principal.put("permissionCodes", permissions(operator));
        result.put("operator", principal);
        return result;
    }
    private List<String> permissions(Map<String, Object> operator) {
        if ("platform_admin".equals(String.valueOf(operator.get("roleCode")))) return List.of("*");
        String raw = String.valueOf(operator.getOrDefault("permissionCodes", ""));
        try { return JSON.parseArray(raw, String.class); }
        catch (Exception ignored) { return List.of(); }
    }
    private void audit(Long operatorId, String account, boolean success, String reason, String requestId) {
        jdbc.update("insert into admin_login_audit(operator_id, account, success, failure_reason, request_id) values (?, ?, ?, ?, ?)",
                operatorId, account, success ? 1 : 0, reason, requestId);