Add user management page and technician picker for reassign
- New /admin/users page (admin only) for creating technicians, editing role/email, resetting passwords, deleting users - AftersalesDetail reassign modal now uses a searchable Select populated from /api/users/assignable instead of raw user ID input - Menu entry only shown to admins Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,10 @@ import type {
|
||||
CreateAftersalesRequest,
|
||||
UpdateAftersalesRequest,
|
||||
CustomerConfirmRequest,
|
||||
CreateUserRequest,
|
||||
UpdateUserRequest,
|
||||
UserListFilter,
|
||||
UserListResponse,
|
||||
} from '@/types';
|
||||
|
||||
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || '/api';
|
||||
@@ -433,4 +437,55 @@ export const aftersalesApi = {
|
||||
}
|
||||
throw new Error(response.data.error || '提交确认失败');
|
||||
},
|
||||
};
|
||||
|
||||
export const usersApi = {
|
||||
list: async (filter?: UserListFilter) => {
|
||||
const params = new URLSearchParams();
|
||||
if (filter?.page && filter.page > 1) params.append('page', String(filter.page));
|
||||
if (filter?.limit && filter.limit !== 20) params.append('limit', String(filter.limit));
|
||||
if (filter?.role) params.append('role', filter.role);
|
||||
if (filter?.search) params.append('search', filter.search);
|
||||
|
||||
const url = params.toString() ? `/users?${params.toString()}` : '/users';
|
||||
const response = await apiClient.get(url);
|
||||
return response.data as UserListResponse;
|
||||
},
|
||||
|
||||
create: async (data: CreateUserRequest) => {
|
||||
const response = await apiClient.post('/users', data);
|
||||
if (response.data.user) {
|
||||
return response.data.user as User;
|
||||
}
|
||||
throw new Error(response.data.error || '创建用户失败');
|
||||
},
|
||||
|
||||
update: async (id: number, data: UpdateUserRequest) => {
|
||||
const response = await apiClient.patch(`/users/${id}`, data);
|
||||
if (response.data.user) {
|
||||
return response.data.user as User;
|
||||
}
|
||||
throw new Error(response.data.error || '更新用户失败');
|
||||
},
|
||||
|
||||
resetPassword: async (id: number, newPassword: string) => {
|
||||
const response = await apiClient.post(`/users/${id}/reset-password`, { newPassword });
|
||||
if (response.data.message) {
|
||||
return true;
|
||||
}
|
||||
throw new Error(response.data.error || '重置密码失败');
|
||||
},
|
||||
|
||||
delete: async (id: number) => {
|
||||
const response = await apiClient.delete(`/users/${id}`);
|
||||
if (response.data.message) {
|
||||
return true;
|
||||
}
|
||||
throw new Error(response.data.error || '删除用户失败');
|
||||
},
|
||||
|
||||
assignable: async () => {
|
||||
const response = await apiClient.get('/users/assignable');
|
||||
return (response.data?.data || []) as User[];
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user