import type { AdminProfile, AdminUser, AgentDebugResult, AgentGenerationConfig, AgentRuntimeConfig, AiLogRecord, ApiResponse, ChatDetail, ChatRecord, ChatRecordQuery, DashboardStats, KnowledgeItem, KnowledgeDetail, KnowledgeSyncJob, KnowledgeVersion, KnowledgeVersionContent, MigrationSummary, KnowledgeBatchUpdateResult, RetrievalLogItem, AttentionItem, ModelItem, SystemConfigItem, UserImportResult, PageResult, PromptDetail, PromptHistoryItem, } from "../types/api"; const API_BASE = import.meta.env.VITE_API_BASE_URL ?? "/api"; const TOKEN_KEY = "ai-kb-admin-token"; export function getToken() { return window.localStorage.getItem(TOKEN_KEY); } export function saveToken(token: string) { window.localStorage.setItem(TOKEN_KEY, token); } export function clearToken() { window.localStorage.removeItem(TOKEN_KEY); } async function request(path: string, init: RequestInit = {}): Promise { const headers = new Headers(init.headers); headers.set("Content-Type", "application/json"); const token = getToken(); if (token) headers.set("Authorization", `Bearer ${token}`); const response = await fetch(`${API_BASE}${path}`, { ...init, headers }); const body = await readApiResponse(response); if (!response.ok || body.code !== 0) { throw new Error(body.detail || body.message || `${response.status} ${response.statusText}`); } return body.data; } async function readApiResponse(response: Response): Promise & { detail?: string }> { const text = await response.text(); if (!text.trim()) { throw new Error(response.ok ? "接口返回为空" : `服务暂时不可用(${response.status})`); } try { return JSON.parse(text) as ApiResponse & { detail?: string }; } catch { throw new Error(response.ok ? "接口返回格式不正确" : `服务暂时不可用(${response.status})`); } } async function download(path: string, filename: string) { const headers = new Headers(); const token = getToken(); if (token) headers.set("Authorization", `Bearer ${token}`); const response = await fetch(`${API_BASE}${path}`, { headers }); if (!response.ok) throw new Error("导出失败"); const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const anchor = document.createElement("a"); anchor.href = url; anchor.download = filename; anchor.click(); window.URL.revokeObjectURL(url); } async function upload(path: string, formData: FormData): Promise { const headers = new Headers(); const token = getToken(); if (token) headers.set("Authorization", `Bearer ${token}`); const response = await fetch(`${API_BASE}${path}`, { method: "POST", body: formData, headers }); const body = await readApiResponse(response); if (!response.ok || body.code !== 0) { throw new Error(body.message || body.detail || `${response.status} ${response.statusText}`); } return body.data; } function queryString(query: object) { const params = new URLSearchParams(); Object.entries(query).forEach(([key, value]) => { if (value !== undefined && value !== null && value !== "") params.set(key, String(value)); }); const text = params.toString(); return text ? `?${text}` : ""; } export const api = { login: (username: string, password: string) => request<{ token: string; admin: AdminProfile }>("/admin/login", { method: "POST", body: JSON.stringify({ username, password }), }), logout: () => request("/admin/logout", { method: "POST", body: "{}" }), profile: () => request("/admin/profile"), dashboard: (start?: string, end?: string) => { const params = new URLSearchParams(); if (start) params.set("start", start); if (end) params.set("end", end); const qs = params.toString(); return request(`/admin/dashboard${qs ? "?" + qs : ""}`); }, users: (query: { keyword?: string; page?: number; pageSize?: number } = {}) => request>(`/admin/user/list${queryString(query)}`), createUser: (payload: Record) => request("/admin/user", { method: "POST", body: JSON.stringify(payload) }), importUsers: (students: Record[]) => request("/admin/user/import", { method: "POST", body: JSON.stringify({ students }) }), downloadStudentTemplate: () => download("/admin/user/import/template", "学员导入模板.xlsx"), importUsersExcel: (file: File) => { const formData = new FormData(); formData.append("file", file); return upload("/admin/user/import/excel", formData); }, updateUser: (id: number, payload: Record) => request(`/admin/user/${id}`, { method: "PUT", body: JSON.stringify(payload) }), deleteUser: (id: number) => request(`/admin/user/${id}`, { method: "DELETE" }), knowledge: (query: Record = {}) => request>(`/admin/knowledge/list${queryString(query)}`), knowledgeOptions: () => request("/admin/knowledge/options"), resolveKnowledgeNode: (nodeId: string) => request<{ nodeId: string; spaceId: string; sourceTitle: string; name: string; remark: string }>("/admin/knowledge/resolve-node", { method: "POST", body: JSON.stringify({ nodeId }) }), createKnowledge: (payload: Record) => request("/admin/knowledge", { method: "POST", body: JSON.stringify(payload) }), updateKnowledge: (id: number, payload: Record) => request(`/admin/knowledge/${id}`, { method: "PUT", body: JSON.stringify(payload) }), updateKnowledgeMetadata: (id: number, payload: { name: string; knowledgeType: string }) => request(`/admin/knowledge/${id}/metadata`, { method: "PATCH", body: JSON.stringify(payload) }), batchUpdateKnowledgeMetadata: (payload: { knowledgeIds: number[]; knowledgeType?: string }) => request("/admin/knowledge/batch/metadata", { method: "PATCH", body: JSON.stringify(payload) }), deleteKnowledge: (id: number) => request(`/admin/knowledge/${id}`, { method: "DELETE" }), importKnowledgeFromSpace: (body: { node_token: string }) => request<{ imported: number; skipped: number; id: number; name: string }>( "/admin/knowledge/import", { method: "POST", body: JSON.stringify(body) }, ), knowledgeDetail: (id: number) => request(`/admin/knowledge/${id}/detail`), knowledgeVersions: (id: number) => request(`/admin/knowledge/${id}/versions`), knowledgeVersionContent: (versionId: number) => request(`/admin/knowledge/version/${versionId}/content`), knowledgeSyncJobs: (id: number) => request(`/admin/knowledge/${id}/sync-jobs`), syncKnowledge: (id: number) => request(`/admin/knowledge/${id}/sync`, { method: "POST" }), rollbackKnowledgeVersion: (id: number, versionId: number, keepOpen: boolean) => request(`/admin/knowledge/${id}/version/${versionId}/rollback`, { method: "POST", body: JSON.stringify({ keepOpen }) }), setKnowledgeOpen: (id: number, open: boolean) => request(`/admin/knowledge/${id}/open-status`, { method: "PUT", body: JSON.stringify({ open }) }), setKnowledgeLifecycle: (id: number, status: "active" | "archived") => request(`/admin/knowledge/${id}/lifecycle`, { method: "PUT", body: JSON.stringify({ status }) }), migrationSummary: () => request("/admin/knowledge-migration/summary"), runKnowledgeMigration: (knowledgeId?: number) => request<{ total: number; success: number; results: Record[] }>(`/admin/knowledge-migration/run${knowledgeId ? `?knowledgeId=${knowledgeId}` : ""}`, { method: "POST", body: "{}" }), prompt: () => request("/admin/prompt"), savePrompt: (promptContent: string) => request("/admin/prompt", { method: "PUT", body: JSON.stringify({ promptContent }) }), resetPrompt: () => request("/admin/prompt/reset", { method: "POST", body: "{}" }), promptHistory: (query: { page?: number; pageSize?: number } = {}) => request>(`/admin/prompt/history${queryString(query)}`), promptHistoryDetail: (id: number) => request(`/admin/prompt/history/${id}`), restorePrompt: (id: number) => request(`/admin/prompt/history/${id}/restore`, { method: "POST", body: "{}" }), debugAgent: (payload: Record) => request("/admin/agent/debug", { method: "POST", body: JSON.stringify(payload) }), agentRuntimeConfig: () => request("/admin/agent/runtime-config"), saveAgentRuntimeConfig: (payload: AgentGenerationConfig) => request("/admin/agent/runtime-config", { method: "PUT", body: JSON.stringify(payload) }), models: () => request("/admin/model/list"), createModel: (payload: Record) => request("/admin/model", { method: "POST", body: JSON.stringify(payload) }), updateModel: (id: number, payload: Record) => request(`/admin/model/${id}`, { method: "PUT", body: JSON.stringify(payload) }), enableModel: (modelId: number) => request("/admin/model/enable", { method: "POST", body: JSON.stringify({ modelId }) }), deleteModel: (modelId: number) => request(`/admin/model/${modelId}`, { method: "DELETE" }), testModel: (modelId: number) => request<{ ok: boolean; message: string; answer: string }>(`/admin/model/${modelId}/test`, { method: "POST", body: "{}", }), configs: () => request("/admin/config"), saveConfig: (payload: Record) => request("/admin/config", { method: "PUT", body: JSON.stringify(payload) }), chats: (query: ChatRecordQuery = {}) => request>(`/admin/chat/list${queryString(query)}`), chatDetail: (sessionId: number) => request(`/admin/chat/${sessionId}`), exportChats: (query: ChatRecordQuery = {}) => download(`/admin/chat/export${queryString(query)}`, "chat_records.csv"), aiLogs: (query: { sessionId?: number; userId?: number; status?: string; page?: number; pageSize?: number } = {}) => request>(`/admin/ai-log/list${queryString(query)}`), aiLogDetail: (id: number) => request(`/admin/ai-log/${id}`), operationLogs: (query: { module?: string; page?: number; pageSize?: number } = {}) => request>>(`/admin/log/list${queryString(query)}`), retrievalLogs: (query: { page?: number; pageSize?: number } = {}) => request>(`/admin/retrieval-log/list${queryString(query)}`), estimateRetrievalCleanup: (before: string) => request<{ before: string; estimatedCount: number }>("/admin/retrieval-log/cleanup/estimate", { method: "POST", body: JSON.stringify({ before }) }), cleanupRetrievalLogs: (before: string) => request<{ before: string; deleted: number }>("/admin/retrieval-log/cleanup", { method: "POST", body: JSON.stringify({ before }) }), retrievalRetention: () => request<{ enabled: boolean; retentionDays: number | null; lastRunAt: string | null; lastResult: string | null }>("/admin/retrieval-log/retention"), saveRetrievalRetention: (retentionDays: number | null) => request<{ enabled: boolean; retentionDays: number | null }>("/admin/retrieval-log/retention", { method: "PUT", body: JSON.stringify({ retentionDays }) }), storageStats: (refresh = false) => request>(`/admin/dashboard/storage${refresh ? "?refresh=true" : ""}`), retrievalLogDetail: (id: number) => request>(`/admin/retrieval-log/${id}`), attentionList: (query: { page?: number; pageSize?: number } = {}) => request>(`/admin/attention/list${queryString(query)}`), updateAttention: (id: number, status: string, note?: string) => request(`/admin/attention/${id}`, { method: "PUT", body: JSON.stringify({ status, note }) }), deleteAttention: (id: number) => request(`/admin/attention/${id}`, { method: "DELETE" }), clearFeishuCache: () => request<{ cleared: number; message: string }>("/admin/feishu/cache/clear", { method: "POST", body: "{}" }), };