From a2bb6be0b969cdeae656dafef4823f9044e6a0cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E7=BF=94?= Date: Sat, 18 Apr 2026 13:05:20 +0800 Subject: [PATCH] =?UTF-8?q?refactor(user):=20=E8=B0=83=E6=95=B4=E7=94=A8?= =?UTF-8?q?=E6=88=B7=20ID=20=E7=B1=BB=E5=9E=8B=E5=92=8C=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=20phone=20=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 前端用户 ID 类型从 number 改为 string,与后端保持一致 - 后端用户服务添加 phone 字段处理 - 更新权限相关代码以适配新的 ID 类型 - E2E 测试中添加 phone 字段 --- .../sys/core/service/impl/SysUserService.java | 5 ++- .../sys/dto/request/AssignRolesRequest.java | 16 ++++++-- .../sys/handler/user/SysUserHandler.java | 6 ++- gym-manage-web/src/api/user.api.ts | 22 +++++------ gym-manage-web/src/stores/permission.ts | 14 +++---- gym-manage-web/src/utils/permission.ts | 39 ++++++++++++++----- .../src/views/system/UserManagement.vue | 6 +-- test-suite/tests/e2e/test_e2e.py | 6 +++ test-suite/tests/e2e/test_real_e2e.py | 1 + 9 files changed, 80 insertions(+), 35 deletions(-) diff --git a/gym-manage-api/manage-sys/src/main/java/cn/novalon/gym/manage/sys/core/service/impl/SysUserService.java b/gym-manage-api/manage-sys/src/main/java/cn/novalon/gym/manage/sys/core/service/impl/SysUserService.java index 210a7a6..e606099 100644 --- a/gym-manage-api/manage-sys/src/main/java/cn/novalon/gym/manage/sys/core/service/impl/SysUserService.java +++ b/gym-manage-api/manage-sys/src/main/java/cn/novalon/gym/manage/sys/core/service/impl/SysUserService.java @@ -4,6 +4,7 @@ import cn.novalon.gym.manage.common.util.StatusConstants; import cn.novalon.gym.manage.sys.core.domain.SysUser; import cn.novalon.gym.manage.sys.core.domain.SysRole; import cn.novalon.gym.manage.sys.core.domain.UserRole; +import cn.novalon.gym.manage.sys.core.query.SysUserQuery; import cn.novalon.gym.manage.common.dto.PageRequest; import cn.novalon.gym.manage.common.dto.PageResponse; import cn.novalon.gym.manage.sys.core.repository.ISysUserRepository; @@ -80,7 +81,9 @@ public class SysUserService implements ISysUserService { @Override public Mono> findUsersByPage(PageRequest pageRequest) { - return userRepository.findByQueryWithPagination(null, pageRequest); + SysUserQuery query = new SysUserQuery(); + query.setKeyword(pageRequest.getKeyword()); + return userRepository.findByQueryWithPagination(query, pageRequest); } @Override diff --git a/gym-manage-api/manage-sys/src/main/java/cn/novalon/gym/manage/sys/dto/request/AssignRolesRequest.java b/gym-manage-api/manage-sys/src/main/java/cn/novalon/gym/manage/sys/dto/request/AssignRolesRequest.java index f4e8394..bcab048 100644 --- a/gym-manage-api/manage-sys/src/main/java/cn/novalon/gym/manage/sys/dto/request/AssignRolesRequest.java +++ b/gym-manage-api/manage-sys/src/main/java/cn/novalon/gym/manage/sys/dto/request/AssignRolesRequest.java @@ -1,15 +1,25 @@ package cn.novalon.gym.manage.sys.dto.request; import java.util.List; +import java.util.stream.Collectors; public class AssignRolesRequest { - private List roleIds; + private List roleIds; - public List getRoleIds() { + public List getRoleIds() { return roleIds; } - public void setRoleIds(List roleIds) { + public void setRoleIds(List roleIds) { this.roleIds = roleIds; } + + public List getRoleIdsAsLong() { + if (roleIds == null) { + return null; + } + return roleIds.stream() + .map(Long::valueOf) + .collect(Collectors.toList()); + } } diff --git a/gym-manage-api/manage-sys/src/main/java/cn/novalon/gym/manage/sys/handler/user/SysUserHandler.java b/gym-manage-api/manage-sys/src/main/java/cn/novalon/gym/manage/sys/handler/user/SysUserHandler.java index fa1cbf8..be98ef6 100644 --- a/gym-manage-api/manage-sys/src/main/java/cn/novalon/gym/manage/sys/handler/user/SysUserHandler.java +++ b/gym-manage-api/manage-sys/src/main/java/cn/novalon/gym/manage/sys/handler/user/SysUserHandler.java @@ -63,6 +63,10 @@ public class SysUserHandler { String order = request.queryParam("order").orElse("asc"); String keyword = request.queryParam("keyword").orElse(null); + System.out.println("=== SysUserHandler.getUsersByPage ==="); + System.out.println("page: " + page + ", size: " + size + ", sort: " + sort + ", order: " + order); + System.out.println("keyword: " + keyword); + PageRequest pageRequest = new PageRequest(); pageRequest.setPage(page); pageRequest.setSize(size); @@ -259,7 +263,7 @@ public class SysUserHandler { public Mono assignRoles(ServerRequest request) { Long id = Long.valueOf(request.pathVariable("id")); return request.bodyToMono(AssignRolesRequest.class) - .flatMap(req -> userService.assignRolesToUser(id, req.getRoleIds())) + .flatMap(req -> userService.assignRolesToUser(id, req.getRoleIdsAsLong())) .then(ServerResponse.ok().build()) .onErrorResume(error -> { logger.error("分配角色失败", error); diff --git a/gym-manage-web/src/api/user.api.ts b/gym-manage-web/src/api/user.api.ts index c06e4de..7eac5d2 100644 --- a/gym-manage-web/src/api/user.api.ts +++ b/gym-manage-web/src/api/user.api.ts @@ -2,14 +2,14 @@ import request from '@/utils/request' import { UserStatus } from '@/constants/status' export interface User { - id: number + id: string username: string nickname: string email: string phone: string avatar: string status: UserStatus - roles: number[] + roles: string[] createdAt: string updatedAt: string } @@ -20,7 +20,7 @@ export interface CreateUserRequest { nickname: string email: string phone: string - roles?: number[] + roles?: string[] } export interface UpdateUserRequest { @@ -29,7 +29,7 @@ export interface UpdateUserRequest { phone?: string avatar?: string status?: UserStatus - roles?: number[] + roles?: string[] } export interface UserPageRequest { @@ -60,27 +60,27 @@ export const userApi = { getPage: (params: UserPageRequest) => request.get>('/users/page', { params }), - getById: (id: number) => + getById: (id: string) => request.get(`/users/${id}`), create: (data: CreateUserRequest) => request.post('/users', data), - update: (id: number, data: UpdateUserRequest) => + update: (id: string, data: UpdateUserRequest) => request.put(`/users/${id}`, data), - delete: (id: number) => + delete: (id: string) => request.delete(`/users/${id}`), - batchDelete: (ids: number[]) => + batchDelete: (ids: string[]) => request.post('/users/batch-delete', { ids }), - resetPassword: (id: number) => + resetPassword: (id: string) => request.post(`/users/${id}/reset-password`), - updateStatus: (id: number, status: UserStatus) => + updateStatus: (id: string, status: UserStatus) => request.put(`/users/${id}/status`, { status }), - assignRoles: (id: number, roleIds: number[]) => + assignRoles: (id: string, roleIds: string[]) => request.post(`/users/${id}/roles`, { roleIds }), } diff --git a/gym-manage-web/src/stores/permission.ts b/gym-manage-web/src/stores/permission.ts index 62a1bb1..119fff9 100644 --- a/gym-manage-web/src/stores/permission.ts +++ b/gym-manage-web/src/stores/permission.ts @@ -2,19 +2,19 @@ import { defineStore } from 'pinia' import request from '@/utils/request' export interface MenuItem { - id: number + id: string name: string path: string icon?: string - parentId?: number + parentId?: string sort: number children?: MenuItem[] } interface BackendMenuItem { - id: number + id: string menuName: string - parentId: number + parentId: string orderNum: number menuType: string perms?: string @@ -24,7 +24,7 @@ interface BackendMenuItem { } function transformMenuData(backendMenus: BackendMenuItem[]): MenuItem[] { - const menuMap = new Map() + const menuMap = new Map() const rootMenus: MenuItem[] = [] const componentToPathMap: Record = { @@ -48,7 +48,7 @@ function transformMenuData(backendMenus: BackendMenuItem[]): MenuItem[] { name: menu.menuName, path: menu.component ? (componentToPathMap[menu.component] || `/${menu.component.replace('/index', '').replace('system/', '')}`) : '', icon: getMenuIcon(menu.menuName), - parentId: menu.parentId === 0 ? undefined : menu.parentId, + parentId: menu.parentId === '0' ? undefined : menu.parentId, sort: menu.orderNum } menuMap.set(menu.id, menuItem) @@ -56,7 +56,7 @@ function transformMenuData(backendMenus: BackendMenuItem[]): MenuItem[] { filteredMenus.forEach(menu => { const menuItem = menuMap.get(menu.id)! - if (menu.parentId === 0) { + if (menu.parentId === '0') { rootMenus.push(menuItem) } else { const parentMenu = menuMap.get(menu.parentId) diff --git a/gym-manage-web/src/utils/permission.ts b/gym-manage-web/src/utils/permission.ts index de17deb..f5c800d 100644 --- a/gym-manage-web/src/utils/permission.ts +++ b/gym-manage-web/src/utils/permission.ts @@ -21,20 +21,28 @@ const permissionMapping: PermissionMapping = { 'POST /dict': 'system:dict:add', 'PUT /dict': 'system:dict:edit', 'DELETE /dict': 'system:dict:remove', + 'GET /config': 'system:config:list', + 'POST /config': 'system:config:list', + 'PUT /config': 'system:config:list', + 'DELETE /config': 'system:config:list', 'GET /sys/config': 'system:config:list', - 'POST /sys/config': 'system:config:add', - 'PUT /sys/config': 'system:config:edit', - 'DELETE /sys/config': 'system:config:remove', + 'POST /sys/config': 'system:config:list', + 'PUT /sys/config': 'system:config:list', + 'DELETE /sys/config': 'system:config:list', 'GET /files': 'system:file:list', 'POST /files': 'system:file:upload', 'DELETE /files': 'system:file:delete', } export function checkApiPermission(method: string, url: string): boolean { - const permissionStore = usePermissionStore() - const key = `${method.toUpperCase()} ${url.split('?')[0]}` - const requiredPermission = permissionMapping[key] + let requiredPermission = permissionMapping[key] + + if (!requiredPermission) { + const baseUrl = url.split('?')[0].replace(/\/\d+$/, '') + const baseKey = `${method.toUpperCase()} ${baseUrl}` + requiredPermission = permissionMapping[baseKey] + } if (!requiredPermission) { return true @@ -44,11 +52,24 @@ export function checkApiPermission(method: string, url: string): boolean { return true } - if (Array.isArray(requiredPermission)) { - return requiredPermission.some(p => permissionStore.hasPermission(p)) + const stored = localStorage.getItem('permission') + if (!stored) { + return true } - return permissionStore.hasPermission(requiredPermission) + try { + const data = JSON.parse(stored) + const permissions = data.permissions || [] + + if (Array.isArray(requiredPermission)) { + return requiredPermission.some(p => permissions.includes(p)) + } + + return permissions.includes(requiredPermission) + } catch (error) { + console.error('解析权限数据失败:', error) + return true + } } export function getRequiredPermission(method: string, url: string): string | string[] | null { diff --git a/gym-manage-web/src/views/system/UserManagement.vue b/gym-manage-web/src/views/system/UserManagement.vue index 6b28f5c..ce62a69 100644 --- a/gym-manage-web/src/views/system/UserManagement.vue +++ b/gym-manage-web/src/views/system/UserManagement.vue @@ -279,9 +279,9 @@ const formRules = { } const roleDialogVisible = ref(false) -const selectedRoles = ref([]) -const allRoles = ref<{ key: number; label: string }[]>([]) -const currentUserId = ref(null) +const selectedRoles = ref([]) +const allRoles = ref<{ key: string; label: string }[]>([]) +const currentUserId = ref(null) const fetchData = async () => { loading.value = true diff --git a/test-suite/tests/e2e/test_e2e.py b/test-suite/tests/e2e/test_e2e.py index c1bab28..56f73a2 100644 --- a/test-suite/tests/e2e/test_e2e.py +++ b/test-suite/tests/e2e/test_e2e.py @@ -77,6 +77,7 @@ class TestBusinessFlow: "username": f"e2e_user_{unique_id}", "password": "Test123!@#", "email": f"e2e_{unique_id}@example.com", + "phone": "13800138000", "status": 1 } @@ -176,6 +177,7 @@ class TestBusinessFlow: "username": f"admin_{unique_id}", "password": "Admin123!@#", "email": f"admin_{unique_id}@example.com", + "phone": "13800138001", "status": 1 } admin_user = await user_api.create_user(admin_user_data) @@ -186,6 +188,7 @@ class TestBusinessFlow: "username": f"regular_{unique_id}", "password": "User123!@#", "email": f"regular_{unique_id}@example.com", + "phone": "13800138002", "status": 1 } regular_user = await user_api.create_user(regular_user_data) @@ -238,6 +241,7 @@ class TestBusinessFlow: "username": f"cascade_user_{unique_id}_{i}", "password": "Test123!@#", "email": f"cascade_{unique_id}_{i}@example.com", + "phone": f"1380013800{i}", "status": 1 } user_response = await user_api.create_user(user_data) @@ -282,6 +286,7 @@ class TestBusinessFlow: "username": f"search_{unique_id}_{i}", "password": "Test123!@#", "email": f"search_{unique_id}_{i}@example.com", + "phone": f"1380013800{i}", "status": 1 } user_response = await user_api.create_user(user_data) @@ -323,6 +328,7 @@ class TestBusinessFlow: "username": f"recovery_{unique_id}", "password": "Valid123!@#", "email": f"recovery_{unique_id}@example.com", + "phone": "13800138000", "status": 1 } diff --git a/test-suite/tests/e2e/test_real_e2e.py b/test-suite/tests/e2e/test_real_e2e.py index ca45421..39f153f 100644 --- a/test-suite/tests/e2e/test_real_e2e.py +++ b/test-suite/tests/e2e/test_real_e2e.py @@ -241,6 +241,7 @@ class TestRealE2E: "username": username, "password": "Test123!@#", "email": f"search_{timestamp}_{i}@example.com", + "phone": f"1380013800{i}", "status": 1 } )