Initial commit

This commit is contained in:
shanshuilala
2026-07-13 16:21:02 +08:00
commit da16d2ae6e
183 changed files with 87241 additions and 0 deletions
+139
View File
@@ -0,0 +1,139 @@
import axios from "axios";
import type { ApiResponse, Scale, ScaleSummary, SubmitResult, ValidationResult } from "../types";
const api = axios.create({ baseURL: "/api", timeout: 30000 });
api.interceptors.request.use((config) => {
const token = localStorage.getItem("token");
if (token) config.headers.Authorization = `Bearer ${token}`;
return config;
});
api.interceptors.response.use(
(res) => res,
(err) => {
if (err.response?.status === 401 && !window.location.pathname.includes("/login")) {
localStorage.removeItem("token");
window.location.href = "/login";
}
return Promise.reject(err);
}
);
// Auth
export const authApi = {
login: (username: string, password: string, turnstileToken?: string) => api.post("/auth/login", { username, password, turnstileToken }).then((r) => r.data),
sendCode: (email: string) => api.post("/auth/send-code", { email }).then((r) => r.data),
register: (name: string, email: string, code: string, password: string, turnstileToken?: string) => api.post("/auth/register", { name, email, code, password, turnstileToken }).then((r) => r.data),
me: () => api.get("/auth/me").then((r) => r.data),
};
// Captcha
export const captchaApi = {
status: () => api.get("/captcha/status").then((r) => r.data.data),
verify: (token: string) => api.post("/captcha/verify", { token }).then((r) => r.data),
};
// Scales
export const scaleApi = {
getAll: () => api.get<ApiResponse<ScaleSummary[]>>("/scales").then((r) => r.data.data),
getOne: (id: string) => api.get<ApiResponse<Scale>>(`/scales/${id}`).then((r) => r.data.data),
preview: (content: Scale, answers: Record<number, number>, demographics?: any) =>
api.post("/scales/preview", { content, answers, demographics }).then((r) => r.data.data),
};
// Test
export const testApi = {
submit: (scaleId: string, answers: Record<number, number>, demographics?: { gender?: string; age?: string }) =>
api.post<ApiResponse<SubmitResult>>("/test/submit", { scaleId, answers, demographics }).then((r) => r.data.data),
};
// AI
export const aiApi = {
interpret: (recordId: string) => api.post("/ai/interpret", { recordId }).then((r) => r.data),
reInterpret: (recordId: string) => api.post("/ai/re-interpret", { recordId }).then((r) => r.data),
status: () => api.get("/ai/status").then((r) => r.data.data),
};
// Records
// User Scales
export const userScaleApi = {
list: (status?: string) => api.get("/user-scales", { params: status ? { status } : {} }).then((r) => r.data.data),
get: (id: string) => api.get(`/user-scales/${id}`).then((r) => r.data.data),
create: (id: string, content: any, turnstileToken?: string) => api.post("/user-scales", { id, content, turnstileToken }).then((r) => r.data.data),
update: (id: string, content: any) => api.put(`/user-scales/${id}`, { content }),
delete: (id: string) => api.delete(`/user-scales/${id}`),
share: (id: string, turnstileToken?: string) => api.post(`/user-scales/${id}/share`, { turnstileToken }).then((r) => r.data.data),
unshare: (id: string) => api.post(`/user-scales/${id}/unshare`).then((r) => r.data),
submitReview: (id: string, turnstileToken?: string) => api.post(`/user-scales/${id}/submit-review`, { turnstileToken }).then((r) => r.data),
getByShareCode: (code: string) => api.get(`/s/${code}`).then((r) => r.data.data),
};
// Samples
export const samplesApi = {
submit: (data: { scaleId: string; userId?: string; gender?: string; age?: string; consented?: boolean; rawData?: any }) =>
api.post("/samples/submit", data).then((r) => r.data),
list: (scaleId?: string) =>
api.get("/samples/list", { params: scaleId ? { scaleId } : {} }).then((r) => r.data.data),
getDetail: (id: string) => api.get("/samples/detail/" + id).then((r) => r.data.data),
delete: (id: string) => api.delete("/samples/" + id),
stats: () => api.get("/samples/stats").then((r) => r.data.data),
exportCsv: (scaleId: string) => api.get("/samples/export/" + scaleId, { responseType: "blob" }).then((r) => r.data),
};
export const recordApi = {
getAll: (scaleId?: string, page?: number, size?: number, dateFrom?: string, dateTo?: string) =>
api.get("/records", { params: { scaleId, page, size, dateFrom, dateTo } }).then((r) => r.data.data),
getOne: (id: string) => api.get(`/records/${id}`).then((r) => r.data.data),
recalc: (id: string) => api.post(`/records/${id}/recalc`).then((r) => r.data.data),
delete: (id: string) => api.delete(`/records/${id}`),
verify: (id: string) => api.get(`/records/${id}/verify`).then((r) => r.data.data),
};
// Admin
export const adminApi = {
getUsers: (params?: { page?: number; size?: number; search?: string; role?: string; status?: string }) =>
api.get("/admin/users", { params }).then((r) => r.data.data),
createUser: (data: { name: string; email?: string; password: string; role?: string }) =>
api.post("/admin/users", data).then((r) => r.data.data),
updateUser: (id: string, data: { name?: string; email?: string; role?: string; status?: string }) =>
api.put(`/admin/users/${id}`, data).then((r) => r.data),
resetPassword: (id: string, newPassword: string) =>
api.put(`/admin/users/${id}/password`, { newPassword }).then((r) => r.data),
toggleBan: (id: string) => api.put(`/admin/users/${id}/ban`).then((r) => r.data),
deleteUser: (id: string) => api.delete(`/admin/users/${id}`),
updateUserPermissions: (id: string, permissions: string[]) =>
api.put(`/admin/users/${id}/permissions`, { permissions }).then((r) => r.data),
getPermissions: () => api.get("/admin/permissions").then((r) => r.data.data),
getUserRecords: (id: string, params?: { page?: number; size?: number }) =>
api.get(`/admin/users/${id}/records`, { params }).then((r) => r.data.data),
getUserStats: (id: string) => api.get(`/admin/users/${id}/stats`).then((r) => r.data.data),
getRecords: (params?: { page?: number; size?: number; userId?: string; scaleId?: string; dateFrom?: string; dateTo?: string }) =>
api.get("/admin/records", { params }).then((r) => r.data.data),
deleteRecord: (id: string) => api.delete(`/admin/records/${id}`),
getSettings: () => api.get("/admin/settings").then((r) => r.data.data),
saveSettings: (settings: Record<string, string>) => api.post("/admin/settings", settings),
getStats: () => api.get("/admin/stats").then((r) => r.data.data),
reloadScales: () => api.post("/scales/reload"),
getPendingReviews: () => api.get("/admin/reviews").then((r) => r.data.data),
approveReview: (id: string, notes?: string) => api.post(`/admin/reviews/${id}/approve`, { notes }),
rejectReview: (id: string, notes?: string) => api.post(`/admin/reviews/${id}/reject`, { notes }),
getAllUserScales: (params?: { status?: string; owner?: string }) =>
api.get("/admin/user-scales", { params }).then((r) => r.data.data),
getUserScaleById: (id: string) => api.get(`/admin/user-scales/${id}`).then((r) => r.data.data),
deleteUserScale: (id: string) => api.delete(`/admin/user-scales/${id}`).then((r) => r.data),
changePassword: (oldPassword: string, newPassword: string) =>
api.post("/admin/change-password", { oldPassword, newPassword }),
getRawScale: (id: string) => api.get(`/scales/${id}/raw`).then((r) => r.data.data),
saveScale: (id: string, content: any) => api.post("/scales/save", { id, content }),
deleteScale: (id: string) => api.delete(`/scales/${id}`),
validateScale: (content: any) =>
api.post<ApiResponse<ValidationResult>>("/scales/validate", { content }).then((r) => r.data.data),
cloneScale: (sourceId: string, newId: string) =>
api.post("/scales/clone", { sourceId, newId }).then((r) => r.data.data),
previewScale: (content: any, answers: Record<number, number>, demographics?: any) =>
api.post("/scales/preview", { content, answers, demographics }).then((r) => r.data.data),
};
export default api;