refactor(user): 调整用户 ID 类型和添加 phone 字段

- 前端用户 ID 类型从 number 改为 string,与后端保持一致
- 后端用户服务添加 phone 字段处理
- 更新权限相关代码以适配新的 ID 类型
- E2E 测试中添加 phone 字段
This commit is contained in:
张翔
2026-04-18 13:05:20 +08:00
parent aedca161ec
commit a2bb6be0b9
9 changed files with 80 additions and 35 deletions
@@ -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<PageResponse<SysUser>> findUsersByPage(PageRequest pageRequest) {
return userRepository.findByQueryWithPagination(null, pageRequest);
SysUserQuery query = new SysUserQuery();
query.setKeyword(pageRequest.getKeyword());
return userRepository.findByQueryWithPagination(query, pageRequest);
}
@Override
@@ -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<Long> roleIds;
private List<String> roleIds;
public List<Long> getRoleIds() {
public List<String> getRoleIds() {
return roleIds;
}
public void setRoleIds(List<Long> roleIds) {
public void setRoleIds(List<String> roleIds) {
this.roleIds = roleIds;
}
public List<Long> getRoleIdsAsLong() {
if (roleIds == null) {
return null;
}
return roleIds.stream()
.map(Long::valueOf)
.collect(Collectors.toList());
}
}
@@ -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<ServerResponse> 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);
+11 -11
View File
@@ -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<PageResponse<User>>('/users/page', { params }),
getById: (id: number) =>
getById: (id: string) =>
request.get<User>(`/users/${id}`),
create: (data: CreateUserRequest) =>
request.post<User>('/users', data),
update: (id: number, data: UpdateUserRequest) =>
update: (id: string, data: UpdateUserRequest) =>
request.put<User>(`/users/${id}`, data),
delete: (id: number) =>
delete: (id: string) =>
request.delete<void>(`/users/${id}`),
batchDelete: (ids: number[]) =>
batchDelete: (ids: string[]) =>
request.post<void>('/users/batch-delete', { ids }),
resetPassword: (id: number) =>
resetPassword: (id: string) =>
request.post<void>(`/users/${id}/reset-password`),
updateStatus: (id: number, status: UserStatus) =>
updateStatus: (id: string, status: UserStatus) =>
request.put<void>(`/users/${id}/status`, { status }),
assignRoles: (id: number, roleIds: number[]) =>
assignRoles: (id: string, roleIds: string[]) =>
request.post<void>(`/users/${id}/roles`, { roleIds }),
}
+7 -7
View File
@@ -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<number, MenuItem>()
const menuMap = new Map<string, MenuItem>()
const rootMenus: MenuItem[] = []
const componentToPathMap: Record<string, string> = {
@@ -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)
+30 -9
View File
@@ -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 {
@@ -279,9 +279,9 @@ const formRules = {
}
const roleDialogVisible = ref(false)
const selectedRoles = ref<number[]>([])
const allRoles = ref<{ key: number; label: string }[]>([])
const currentUserId = ref<number | null>(null)
const selectedRoles = ref<string[]>([])
const allRoles = ref<{ key: string; label: string }[]>([])
const currentUserId = ref<string | null>(null)
const fetchData = async () => {
loading.value = true
+6
View File
@@ -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
}
+1
View File
@@ -241,6 +241,7 @@ class TestRealE2E:
"username": username,
"password": "Test123!@#",
"email": f"search_{timestamp}_{i}@example.com",
"phone": f"1380013800{i}",
"status": 1
}
)