feat: 重构用户端手机号验证码登录页
This commit is contained in:
@@ -2,6 +2,18 @@ import type { ApiResponse, CaptchaResult, ChatMessage, ChatSession, LoginResult,
|
||||
|
||||
const API_BASE = import.meta.env.VITE_API_BASE_URL ?? "/api";
|
||||
const TOKEN_KEY = "ai-kb-user-token";
|
||||
const REQUEST_TIMEOUT_MS = 15_000;
|
||||
|
||||
export class ApiError extends Error {
|
||||
constructor(
|
||||
message: string,
|
||||
readonly status: number,
|
||||
readonly requestId = "",
|
||||
) {
|
||||
super(message);
|
||||
this.name = "ApiError";
|
||||
}
|
||||
}
|
||||
|
||||
export function getToken() {
|
||||
return window.localStorage.getItem(TOKEN_KEY);
|
||||
@@ -22,18 +34,38 @@ async function request<T>(path: string, init: RequestInit = {}): Promise<T> {
|
||||
if (token) {
|
||||
headers.set("Authorization", `Bearer ${token}`);
|
||||
}
|
||||
const response = await fetch(`${API_BASE}${path}`, { ...init, headers });
|
||||
const body = (await response.json()) as ApiResponse<T>;
|
||||
const controller = new AbortController();
|
||||
const timeout = window.setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
||||
let response: Response;
|
||||
try {
|
||||
response = await fetch(`${API_BASE}${path}`, { ...init, headers, signal: controller.signal });
|
||||
} catch (error) {
|
||||
if (error instanceof DOMException && error.name === "AbortError") {
|
||||
throw new ApiError("请求超时,请检查网络后重试", 408);
|
||||
}
|
||||
throw new ApiError("网络连接失败,请稍后重试", 0);
|
||||
} finally {
|
||||
window.clearTimeout(timeout);
|
||||
}
|
||||
|
||||
const body = (await response.json().catch(() => ({ code: response.status, message: "服务响应异常", data: null }))) as ApiResponse<T>;
|
||||
if (!response.ok || body.code !== 0) {
|
||||
throw new Error(body.message || `${response.status} ${response.statusText}`);
|
||||
throw new ApiError(
|
||||
body.message || `${response.status} ${response.statusText}`,
|
||||
response.status,
|
||||
response.headers.get("X-Request-ID") ?? "",
|
||||
);
|
||||
}
|
||||
return body.data;
|
||||
}
|
||||
|
||||
export const api = {
|
||||
captcha: () => request<CaptchaResult>("/auth/captcha"),
|
||||
sendSms: (phone: string, captchaId: string, captchaCode: string) =>
|
||||
request<null>("/auth/sms/send", { method: "POST", body: JSON.stringify({ phone, captchaId, captchaCode }) }),
|
||||
sendSms: (phone: string, captchaId?: string, captchaCode?: string) =>
|
||||
request<null>("/auth/sms/send", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ phone, ...(captchaId && captchaCode ? { captchaId, captchaCode } : {}) }),
|
||||
}),
|
||||
login: (phone: string, code: string) =>
|
||||
request<LoginResult>("/auth/login", { method: "POST", body: JSON.stringify({ phone, code }) }),
|
||||
logout: () => request<null>("/auth/logout", { method: "POST", body: JSON.stringify({}) }),
|
||||
|
||||
Reference in New Issue
Block a user