feat: build account dashboard and settings workspace

This commit is contained in:
2026-03-26 23:03:45 +08:00
parent be4bc8a3af
commit 8ee9a696b4
18 changed files with 2468 additions and 54 deletions

67
src/service/http.ts Normal file
View File

@@ -0,0 +1,67 @@
import axios from "axios";
import type { AxiosRequestConfig, InternalAxiosRequestConfig } from "axios";
type UnauthorizedHandler = () => Promise<boolean>;
let unauthorizedHandler: UnauthorizedHandler | null = null;
export const setUnauthorizedHandler = (handler: UnauthorizedHandler | null) => {
unauthorizedHandler = handler;
};
const instance = axios.create({
baseURL: "http://127.0.0.1:8080",
});
instance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
const sessionID = sessionStorage.getItem("session_id");
if (sessionID) {
config.headers["X-Session-Id"] = sessionID;
}
return config;
});
instance.interceptors.response.use(
(response) => response.data,
async (error) => {
const config = error.config as
| (AxiosRequestConfig & { _retry?: boolean })
| undefined;
const status = error.response?.status;
const url = config?.url ?? "";
if (
status === 401 &&
config &&
!config._retry &&
unauthorizedHandler &&
!url.includes("/api/login")
) {
config._retry = true;
const ok = await unauthorizedHandler();
if (ok) {
return instance.request(config);
}
}
return Promise.reject(error);
},
);
const http = {
get<T>(url: string, config?: AxiosRequestConfig) {
return instance.get<unknown, T>(url, config);
},
post<T>(url: string, data?: unknown, config?: AxiosRequestConfig) {
return instance.post<unknown, T>(url, data, config);
},
put<T>(url: string, data?: unknown, config?: AxiosRequestConfig) {
return instance.put<unknown, T>(url, data, config);
},
delete<T>(url: string, config?: AxiosRequestConfig) {
return instance.delete<unknown, T>(url, config);
},
};
export default http;