refactor(user): 调整用户 ID 类型和添加 phone 字段
- 前端用户 ID 类型从 number 改为 string,与后端保持一致 - 后端用户服务添加 phone 字段处理 - 更新权限相关代码以适配新的 ID 类型 - E2E 测试中添加 phone 字段
This commit is contained in:
+4
-1
@@ -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.SysUser;
|
||||||
import cn.novalon.gym.manage.sys.core.domain.SysRole;
|
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.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.PageRequest;
|
||||||
import cn.novalon.gym.manage.common.dto.PageResponse;
|
import cn.novalon.gym.manage.common.dto.PageResponse;
|
||||||
import cn.novalon.gym.manage.sys.core.repository.ISysUserRepository;
|
import cn.novalon.gym.manage.sys.core.repository.ISysUserRepository;
|
||||||
@@ -80,7 +81,9 @@ public class SysUserService implements ISysUserService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<PageResponse<SysUser>> findUsersByPage(PageRequest pageRequest) {
|
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
|
@Override
|
||||||
|
|||||||
+13
-3
@@ -1,15 +1,25 @@
|
|||||||
package cn.novalon.gym.manage.sys.dto.request;
|
package cn.novalon.gym.manage.sys.dto.request;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class AssignRolesRequest {
|
public class AssignRolesRequest {
|
||||||
private List<Long> roleIds;
|
private List<String> roleIds;
|
||||||
|
|
||||||
public List<Long> getRoleIds() {
|
public List<String> getRoleIds() {
|
||||||
return roleIds;
|
return roleIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRoleIds(List<Long> roleIds) {
|
public void setRoleIds(List<String> roleIds) {
|
||||||
this.roleIds = roleIds;
|
this.roleIds = roleIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Long> getRoleIdsAsLong() {
|
||||||
|
if (roleIds == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return roleIds.stream()
|
||||||
|
.map(Long::valueOf)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-1
@@ -63,6 +63,10 @@ public class SysUserHandler {
|
|||||||
String order = request.queryParam("order").orElse("asc");
|
String order = request.queryParam("order").orElse("asc");
|
||||||
String keyword = request.queryParam("keyword").orElse(null);
|
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 pageRequest = new PageRequest();
|
||||||
pageRequest.setPage(page);
|
pageRequest.setPage(page);
|
||||||
pageRequest.setSize(size);
|
pageRequest.setSize(size);
|
||||||
@@ -259,7 +263,7 @@ public class SysUserHandler {
|
|||||||
public Mono<ServerResponse> assignRoles(ServerRequest request) {
|
public Mono<ServerResponse> assignRoles(ServerRequest request) {
|
||||||
Long id = Long.valueOf(request.pathVariable("id"));
|
Long id = Long.valueOf(request.pathVariable("id"));
|
||||||
return request.bodyToMono(AssignRolesRequest.class)
|
return request.bodyToMono(AssignRolesRequest.class)
|
||||||
.flatMap(req -> userService.assignRolesToUser(id, req.getRoleIds()))
|
.flatMap(req -> userService.assignRolesToUser(id, req.getRoleIdsAsLong()))
|
||||||
.then(ServerResponse.ok().build())
|
.then(ServerResponse.ok().build())
|
||||||
.onErrorResume(error -> {
|
.onErrorResume(error -> {
|
||||||
logger.error("分配角色失败", error);
|
logger.error("分配角色失败", error);
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ import request from '@/utils/request'
|
|||||||
import { UserStatus } from '@/constants/status'
|
import { UserStatus } from '@/constants/status'
|
||||||
|
|
||||||
export interface User {
|
export interface User {
|
||||||
id: number
|
id: string
|
||||||
username: string
|
username: string
|
||||||
nickname: string
|
nickname: string
|
||||||
email: string
|
email: string
|
||||||
phone: string
|
phone: string
|
||||||
avatar: string
|
avatar: string
|
||||||
status: UserStatus
|
status: UserStatus
|
||||||
roles: number[]
|
roles: string[]
|
||||||
createdAt: string
|
createdAt: string
|
||||||
updatedAt: string
|
updatedAt: string
|
||||||
}
|
}
|
||||||
@@ -20,7 +20,7 @@ export interface CreateUserRequest {
|
|||||||
nickname: string
|
nickname: string
|
||||||
email: string
|
email: string
|
||||||
phone: string
|
phone: string
|
||||||
roles?: number[]
|
roles?: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UpdateUserRequest {
|
export interface UpdateUserRequest {
|
||||||
@@ -29,7 +29,7 @@ export interface UpdateUserRequest {
|
|||||||
phone?: string
|
phone?: string
|
||||||
avatar?: string
|
avatar?: string
|
||||||
status?: UserStatus
|
status?: UserStatus
|
||||||
roles?: number[]
|
roles?: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UserPageRequest {
|
export interface UserPageRequest {
|
||||||
@@ -60,27 +60,27 @@ export const userApi = {
|
|||||||
getPage: (params: UserPageRequest) =>
|
getPage: (params: UserPageRequest) =>
|
||||||
request.get<PageResponse<User>>('/users/page', { params }),
|
request.get<PageResponse<User>>('/users/page', { params }),
|
||||||
|
|
||||||
getById: (id: number) =>
|
getById: (id: string) =>
|
||||||
request.get<User>(`/users/${id}`),
|
request.get<User>(`/users/${id}`),
|
||||||
|
|
||||||
create: (data: CreateUserRequest) =>
|
create: (data: CreateUserRequest) =>
|
||||||
request.post<User>('/users', data),
|
request.post<User>('/users', data),
|
||||||
|
|
||||||
update: (id: number, data: UpdateUserRequest) =>
|
update: (id: string, data: UpdateUserRequest) =>
|
||||||
request.put<User>(`/users/${id}`, data),
|
request.put<User>(`/users/${id}`, data),
|
||||||
|
|
||||||
delete: (id: number) =>
|
delete: (id: string) =>
|
||||||
request.delete<void>(`/users/${id}`),
|
request.delete<void>(`/users/${id}`),
|
||||||
|
|
||||||
batchDelete: (ids: number[]) =>
|
batchDelete: (ids: string[]) =>
|
||||||
request.post<void>('/users/batch-delete', { ids }),
|
request.post<void>('/users/batch-delete', { ids }),
|
||||||
|
|
||||||
resetPassword: (id: number) =>
|
resetPassword: (id: string) =>
|
||||||
request.post<void>(`/users/${id}/reset-password`),
|
request.post<void>(`/users/${id}/reset-password`),
|
||||||
|
|
||||||
updateStatus: (id: number, status: UserStatus) =>
|
updateStatus: (id: string, status: UserStatus) =>
|
||||||
request.put<void>(`/users/${id}/status`, { status }),
|
request.put<void>(`/users/${id}/status`, { status }),
|
||||||
|
|
||||||
assignRoles: (id: number, roleIds: number[]) =>
|
assignRoles: (id: string, roleIds: string[]) =>
|
||||||
request.post<void>(`/users/${id}/roles`, { roleIds }),
|
request.post<void>(`/users/${id}/roles`, { roleIds }),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,19 +2,19 @@ import { defineStore } from 'pinia'
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
|
|
||||||
export interface MenuItem {
|
export interface MenuItem {
|
||||||
id: number
|
id: string
|
||||||
name: string
|
name: string
|
||||||
path: string
|
path: string
|
||||||
icon?: string
|
icon?: string
|
||||||
parentId?: number
|
parentId?: string
|
||||||
sort: number
|
sort: number
|
||||||
children?: MenuItem[]
|
children?: MenuItem[]
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BackendMenuItem {
|
interface BackendMenuItem {
|
||||||
id: number
|
id: string
|
||||||
menuName: string
|
menuName: string
|
||||||
parentId: number
|
parentId: string
|
||||||
orderNum: number
|
orderNum: number
|
||||||
menuType: string
|
menuType: string
|
||||||
perms?: string
|
perms?: string
|
||||||
@@ -24,7 +24,7 @@ interface BackendMenuItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function transformMenuData(backendMenus: BackendMenuItem[]): MenuItem[] {
|
function transformMenuData(backendMenus: BackendMenuItem[]): MenuItem[] {
|
||||||
const menuMap = new Map<number, MenuItem>()
|
const menuMap = new Map<string, MenuItem>()
|
||||||
const rootMenus: MenuItem[] = []
|
const rootMenus: MenuItem[] = []
|
||||||
|
|
||||||
const componentToPathMap: Record<string, string> = {
|
const componentToPathMap: Record<string, string> = {
|
||||||
@@ -48,7 +48,7 @@ function transformMenuData(backendMenus: BackendMenuItem[]): MenuItem[] {
|
|||||||
name: menu.menuName,
|
name: menu.menuName,
|
||||||
path: menu.component ? (componentToPathMap[menu.component] || `/${menu.component.replace('/index', '').replace('system/', '')}`) : '',
|
path: menu.component ? (componentToPathMap[menu.component] || `/${menu.component.replace('/index', '').replace('system/', '')}`) : '',
|
||||||
icon: getMenuIcon(menu.menuName),
|
icon: getMenuIcon(menu.menuName),
|
||||||
parentId: menu.parentId === 0 ? undefined : menu.parentId,
|
parentId: menu.parentId === '0' ? undefined : menu.parentId,
|
||||||
sort: menu.orderNum
|
sort: menu.orderNum
|
||||||
}
|
}
|
||||||
menuMap.set(menu.id, menuItem)
|
menuMap.set(menu.id, menuItem)
|
||||||
@@ -56,7 +56,7 @@ function transformMenuData(backendMenus: BackendMenuItem[]): MenuItem[] {
|
|||||||
|
|
||||||
filteredMenus.forEach(menu => {
|
filteredMenus.forEach(menu => {
|
||||||
const menuItem = menuMap.get(menu.id)!
|
const menuItem = menuMap.get(menu.id)!
|
||||||
if (menu.parentId === 0) {
|
if (menu.parentId === '0') {
|
||||||
rootMenus.push(menuItem)
|
rootMenus.push(menuItem)
|
||||||
} else {
|
} else {
|
||||||
const parentMenu = menuMap.get(menu.parentId)
|
const parentMenu = menuMap.get(menu.parentId)
|
||||||
|
|||||||
@@ -21,20 +21,28 @@ const permissionMapping: PermissionMapping = {
|
|||||||
'POST /dict': 'system:dict:add',
|
'POST /dict': 'system:dict:add',
|
||||||
'PUT /dict': 'system:dict:edit',
|
'PUT /dict': 'system:dict:edit',
|
||||||
'DELETE /dict': 'system:dict:remove',
|
'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',
|
'GET /sys/config': 'system:config:list',
|
||||||
'POST /sys/config': 'system:config:add',
|
'POST /sys/config': 'system:config:list',
|
||||||
'PUT /sys/config': 'system:config:edit',
|
'PUT /sys/config': 'system:config:list',
|
||||||
'DELETE /sys/config': 'system:config:remove',
|
'DELETE /sys/config': 'system:config:list',
|
||||||
'GET /files': 'system:file:list',
|
'GET /files': 'system:file:list',
|
||||||
'POST /files': 'system:file:upload',
|
'POST /files': 'system:file:upload',
|
||||||
'DELETE /files': 'system:file:delete',
|
'DELETE /files': 'system:file:delete',
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkApiPermission(method: string, url: string): boolean {
|
export function checkApiPermission(method: string, url: string): boolean {
|
||||||
const permissionStore = usePermissionStore()
|
|
||||||
|
|
||||||
const key = `${method.toUpperCase()} ${url.split('?')[0]}`
|
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) {
|
if (!requiredPermission) {
|
||||||
return true
|
return true
|
||||||
@@ -44,11 +52,24 @@ export function checkApiPermission(method: string, url: string): boolean {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Array.isArray(requiredPermission)) {
|
const stored = localStorage.getItem('permission')
|
||||||
return requiredPermission.some(p => permissionStore.hasPermission(p))
|
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 {
|
export function getRequiredPermission(method: string, url: string): string | string[] | null {
|
||||||
|
|||||||
@@ -279,9 +279,9 @@ const formRules = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const roleDialogVisible = ref(false)
|
const roleDialogVisible = ref(false)
|
||||||
const selectedRoles = ref<number[]>([])
|
const selectedRoles = ref<string[]>([])
|
||||||
const allRoles = ref<{ key: number; label: string }[]>([])
|
const allRoles = ref<{ key: string; label: string }[]>([])
|
||||||
const currentUserId = ref<number | null>(null)
|
const currentUserId = ref<string | null>(null)
|
||||||
|
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ class TestBusinessFlow:
|
|||||||
"username": f"e2e_user_{unique_id}",
|
"username": f"e2e_user_{unique_id}",
|
||||||
"password": "Test123!@#",
|
"password": "Test123!@#",
|
||||||
"email": f"e2e_{unique_id}@example.com",
|
"email": f"e2e_{unique_id}@example.com",
|
||||||
|
"phone": "13800138000",
|
||||||
"status": 1
|
"status": 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,6 +177,7 @@ class TestBusinessFlow:
|
|||||||
"username": f"admin_{unique_id}",
|
"username": f"admin_{unique_id}",
|
||||||
"password": "Admin123!@#",
|
"password": "Admin123!@#",
|
||||||
"email": f"admin_{unique_id}@example.com",
|
"email": f"admin_{unique_id}@example.com",
|
||||||
|
"phone": "13800138001",
|
||||||
"status": 1
|
"status": 1
|
||||||
}
|
}
|
||||||
admin_user = await user_api.create_user(admin_user_data)
|
admin_user = await user_api.create_user(admin_user_data)
|
||||||
@@ -186,6 +188,7 @@ class TestBusinessFlow:
|
|||||||
"username": f"regular_{unique_id}",
|
"username": f"regular_{unique_id}",
|
||||||
"password": "User123!@#",
|
"password": "User123!@#",
|
||||||
"email": f"regular_{unique_id}@example.com",
|
"email": f"regular_{unique_id}@example.com",
|
||||||
|
"phone": "13800138002",
|
||||||
"status": 1
|
"status": 1
|
||||||
}
|
}
|
||||||
regular_user = await user_api.create_user(regular_user_data)
|
regular_user = await user_api.create_user(regular_user_data)
|
||||||
@@ -238,6 +241,7 @@ class TestBusinessFlow:
|
|||||||
"username": f"cascade_user_{unique_id}_{i}",
|
"username": f"cascade_user_{unique_id}_{i}",
|
||||||
"password": "Test123!@#",
|
"password": "Test123!@#",
|
||||||
"email": f"cascade_{unique_id}_{i}@example.com",
|
"email": f"cascade_{unique_id}_{i}@example.com",
|
||||||
|
"phone": f"1380013800{i}",
|
||||||
"status": 1
|
"status": 1
|
||||||
}
|
}
|
||||||
user_response = await user_api.create_user(user_data)
|
user_response = await user_api.create_user(user_data)
|
||||||
@@ -282,6 +286,7 @@ class TestBusinessFlow:
|
|||||||
"username": f"search_{unique_id}_{i}",
|
"username": f"search_{unique_id}_{i}",
|
||||||
"password": "Test123!@#",
|
"password": "Test123!@#",
|
||||||
"email": f"search_{unique_id}_{i}@example.com",
|
"email": f"search_{unique_id}_{i}@example.com",
|
||||||
|
"phone": f"1380013800{i}",
|
||||||
"status": 1
|
"status": 1
|
||||||
}
|
}
|
||||||
user_response = await user_api.create_user(user_data)
|
user_response = await user_api.create_user(user_data)
|
||||||
@@ -323,6 +328,7 @@ class TestBusinessFlow:
|
|||||||
"username": f"recovery_{unique_id}",
|
"username": f"recovery_{unique_id}",
|
||||||
"password": "Valid123!@#",
|
"password": "Valid123!@#",
|
||||||
"email": f"recovery_{unique_id}@example.com",
|
"email": f"recovery_{unique_id}@example.com",
|
||||||
|
"phone": "13800138000",
|
||||||
"status": 1
|
"status": 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -241,6 +241,7 @@ class TestRealE2E:
|
|||||||
"username": username,
|
"username": username,
|
||||||
"password": "Test123!@#",
|
"password": "Test123!@#",
|
||||||
"email": f"search_{timestamp}_{i}@example.com",
|
"email": f"search_{timestamp}_{i}@example.com",
|
||||||
|
"phone": f"1380013800{i}",
|
||||||
"status": 1
|
"status": 1
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user