feat(auth): implement login and user management features
- Added server-side login action with form handling and cookie storage - Implemented user authentication service with token management - Created user list page with data fetching from userService - Developed reusable DataTable component with selection and pagination - Enhanced AppSidebar with nested navigation and active state tracking - Updated icon definitions and sprite symbols for UI consistency - Improved HTTP client to properly handle request bodies for different methods - Refactored auth store to manage authentication state and cookies - Added strict typing for navigation items and table columns - Removed obsolete code and simplified authentication flow
This commit is contained in:
@@ -61,66 +61,68 @@ export class HttpError extends Error {
|
||||
}
|
||||
|
||||
|
||||
const httpRequest= async <T>(
|
||||
url:string,
|
||||
const httpRequest = async <T>(
|
||||
url: string,
|
||||
method: HttpMethod,
|
||||
options: RequestOptions = {}
|
||||
):Promise<ApiResult<T>> =>{
|
||||
): Promise<ApiResult<T>> => {
|
||||
const fullUrl = `${API_BASE_URL}${url}`;
|
||||
const { body, headers, ...rest} = options;
|
||||
const { body, headers, ...rest } = options;
|
||||
|
||||
const requestHeaders: Record<string, string> = normalizeHeaders(headers);
|
||||
let requestBody:BodyInit | undefined;
|
||||
const requestHeaders: Record<string, string> = normalizeHeaders(headers);
|
||||
let requestBody: BodyInit | undefined;
|
||||
|
||||
if (body instanceof FormData){
|
||||
requestBody = body;
|
||||
}else if (body){
|
||||
requestHeaders['content-type'] = 'application/json';
|
||||
requestBody = JSON.stringify(body);
|
||||
const canHaveBody = method !== 'GET' ;
|
||||
|
||||
// 【修改点 2】:只有在允许携带 Body 时才处理
|
||||
if (canHaveBody) {
|
||||
if (body instanceof FormData) {
|
||||
requestBody = body;
|
||||
} else if (body) {
|
||||
requestHeaders['content-type'] = 'application/json';
|
||||
requestBody = JSON.stringify(body);
|
||||
}
|
||||
}
|
||||
|
||||
// ... Token 处理逻辑保持不变 ...
|
||||
if (currentToken && currentTokenHead) {
|
||||
requestHeaders['authorization'] = `${currentTokenHead} ${currentToken}`;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(fullUrl,{
|
||||
const response = await fetch(fullUrl, {
|
||||
method,
|
||||
headers: requestHeaders,
|
||||
body: requestBody,
|
||||
// 【修改点 3】:确保 GET 请求的 body 显式为 undefined
|
||||
// 虽然通常 undefined 是被允许的,但加上 canHaveBody 判断更加严谨
|
||||
body: canHaveBody ? requestBody : undefined,
|
||||
...rest
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
|
||||
let errorDetail;
|
||||
|
||||
try {
|
||||
|
||||
errorDetail = await response.json()
|
||||
|
||||
}catch (e){
|
||||
errorDetail = await response.json();
|
||||
} catch (e) {
|
||||
console.error('Error parsing JSON:', e);
|
||||
errorDetail = await response.text()
|
||||
errorDetail = await response.text();
|
||||
}
|
||||
|
||||
const message = `HTTP Error ${response.status} (${response.statusText})`;
|
||||
throw new HttpError(message, response.status, errorDetail);
|
||||
}
|
||||
|
||||
const contentType = response.headers.get('Content-Type');
|
||||
if (contentType && contentType.includes('application/json')){
|
||||
return (await response.json() ) as ApiResult<T>;
|
||||
if (contentType && contentType.includes('application/json')) {
|
||||
return (await response.json()) as ApiResult<T>;
|
||||
}
|
||||
|
||||
return {code:200, msg:'OK', data:null} ;
|
||||
return { code: 200, msg: 'OK', data: null } ; // 这里的 as any 是为了兼容 T 可能是 null 的情况
|
||||
|
||||
}catch (error){
|
||||
} catch (error) {
|
||||
console.error(`API Request Failed to ${fullUrl}:`, error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
export const api = {
|
||||
|
||||
Reference in New Issue
Block a user