Files
course-agent-od/web/src/lib/api.ts
T
pengxiao abcced35b8 feat: RAG inline citations, source highlighting, and admin panel
- Increase RAG retrieval from 5 to 50 docs with relevance threshold (0.15)
- LLM inline citations with [来源N] format and reference list
- Clickable citation links scroll to source cards with highlight animation
- Source previews with full chunk text and answer-matched highlighting
- Message-scoped source IDs to fix cross-round citation targeting
- Admin panel pages (knowledge, users, forum, course, settings)
- Add rehype-raw dependency for HTML-in-markdown rendering

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 20:51:28 +08:00

1199 lines
32 KiB
TypeScript

import { z } from "zod";
import type {
CourseModule,
Book,
Chapter,
BookStructure,
User,
ForumCategory,
ForumPostSummary,
ForumPostDetail,
ForumReply,
} from "@/types";
// API基础配置
const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || (typeof window !== 'undefined' ? `${window.location.protocol}//${window.location.host}/api` : "http://127.0.0.1:8000");
// 请求拦截器
async function apiRequest<T>(
endpoint: string,
options: RequestInit = {}
): Promise<T> {
const url = `${API_BASE_URL}${endpoint}`;
const defaultHeaders: Record<string, string> = {
"Content-Type": "application/json",
};
// 添加认证头
const token = localStorage.getItem("auth_token");
if (token) {
defaultHeaders.Authorization = `Bearer ${token}`;
}
const config: RequestInit = {
...options,
headers: {
...defaultHeaders,
...options.headers,
},
};
try {
const response = await fetch(url, config);
if (!response.ok) {
if (response.status === 401) {
localStorage.removeItem("auth_token");
if (typeof window !== 'undefined' &&
!window.location.pathname.includes('/login') &&
!window.location.pathname.includes('/register')) {
window.location.replace("/login");
}
throw new Error("认证已过期,请重新登录");
}
const errorData = await response.json().catch(() => ({}));
throw new Error(errorData.detail || `HTTP ${response.status}`);
}
return await response.json();
} catch (error) {
throw error;
}
}
// 认证相关API
export const authAPI = {
async login(username: string, password: string) {
return apiRequest<{
access_token: string;
token_type: string;
}>("/auth/login", {
method: "POST",
body: JSON.stringify({ username, password }),
});
},
async register(userData: {
username: string;
email: string;
password: string;
full_name?: string;
}) {
return apiRequest<User>("/auth/register", {
method: "POST",
body: JSON.stringify(userData),
});
},
async getCurrentUser() {
return apiRequest<User>("/auth/me");
},
async updateUserInfo(data: { email?: string; full_name?: string }) {
return apiRequest<User>("/auth/me", {
method: "PUT",
body: JSON.stringify(data),
});
},
async changePassword(data: { old_password: string; new_password: string }) {
return apiRequest<{ message: string }>("/auth/change-password", {
method: "POST",
body: JSON.stringify(data),
});
},
async verifyEmail(token: string) {
return apiRequest<{
success: boolean;
message: string;
user?: User;
}>("/auth/verify-email", {
method: "POST",
body: JSON.stringify({ token }),
});
},
};
// 图像生成相关API
export const imageAPI = {
// 文生图 API
async textToImage(request: {
prompt: string;
model?: string;
template?: string;
style?: string;
size?: string;
num_images?: number;
}) {
return apiRequest<{
images: Array<{
id: string;
url: string;
prompt: string;
model: string;
metadata: any;
}>;
total: number;
}>("/image/text-to-image", {
method: "POST",
body: JSON.stringify(request),
});
},
// 图生图 - 图像编辑
async imageEdit(
image: File,
prompt: string,
mode: string = "optimize",
mask?: File,
strength: number = 0.8
) {
const formData = new FormData();
formData.append("image", image);
formData.append("prompt", prompt);
formData.append("mode", mode);
formData.append("strength", strength.toString());
if (mask) {
formData.append("mask", mask);
}
const token = localStorage.getItem("auth_token");
const response = await fetch(`${API_BASE_URL}/image/image-to-image/edit`, {
method: "POST",
headers: {
...(token && { Authorization: `Bearer ${token}` }),
},
body: formData,
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(errorData.detail || `HTTP ${response.status}`);
}
return await response.json();
},
// 图生图 - 生成变体
async imageVariations(image: File, num_variations: number = 3) {
const formData = new FormData();
formData.append("image", image);
formData.append("num_variations", num_variations.toString());
const token = localStorage.getItem("auth_token");
const response = await fetch(`${API_BASE_URL}/image/image-to-image/variations`, {
method: "POST",
headers: {
...(token && { Authorization: `Bearer ${token}` }),
},
body: formData,
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(errorData.detail || `HTTP ${response.status}`);
}
return await response.json();
},
// 图生图 - 风格转换
async styleTransfer(image: File, style_prompt: string, strength: number = 0.8) {
const formData = new FormData();
formData.append("image", image);
formData.append("style_prompt", style_prompt);
formData.append("strength", strength.toString());
const token = localStorage.getItem("auth_token");
const response = await fetch(`${API_BASE_URL}/image/image-to-image/style-transfer`, {
method: "POST",
headers: {
...(token && { Authorization: `Bearer ${token}` }),
},
body: formData,
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(errorData.detail || `HTTP ${response.status}`);
}
return await response.json();
},
// 图生图 - 图像优化
async optimizeImage(
image: File,
optimization_prompt: string = "优化图像质量,增强细节,提高清晰度",
strength: number = 0.6
) {
const formData = new FormData();
formData.append("image", image);
formData.append("optimization_prompt", optimization_prompt);
formData.append("strength", strength.toString());
const token = localStorage.getItem("auth_token");
const response = await fetch(`${API_BASE_URL}/image/image-to-image/optimize`, {
method: "POST",
headers: {
...(token && { Authorization: `Bearer ${token}` }),
},
body: formData,
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(errorData.detail || `HTTP ${response.status}`);
}
return await response.json();
},
// 图生图 - 图像扩展
async outpaintImage(image: File, expansion_prompt: string, strength: number = 0.7) {
const formData = new FormData();
formData.append("image", image);
formData.append("expansion_prompt", expansion_prompt);
formData.append("strength", strength.toString());
const token = localStorage.getItem("auth_token");
const response = await fetch(`${API_BASE_URL}/image/image-to-image/outpaint`, {
method: "POST",
headers: {
...(token && { Authorization: `Bearer ${token}` }),
},
body: formData,
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(errorData.detail || `HTTP ${response.status}`);
}
return await response.json();
},
// 配置信息 API
async getModels() {
const response = await apiRequest<{
models: Array<{
id: string;
name: string;
description: string;
}>;
}>("/image/models", {
method: "GET",
});
return response.models;
},
async getTemplates() {
const response = await apiRequest<{
templates: Array<{
id: string;
name: string;
description: string;
}>;
}>("/image/templates", {
method: "GET",
});
return response.templates;
},
async getStyles() {
const response = await apiRequest<{
styles: Array<{
id: string;
name: string;
description: string;
}>;
}>("/image/styles", {
method: "GET",
});
return response.styles;
},
async getSizes() {
const response = await apiRequest<{
sizes: Array<{
id: string;
name: string;
description: string;
}>;
}>("/image/sizes", {
method: "GET",
});
return response.sizes;
},
async getEditModes() {
const response = await apiRequest<{
modes: Array<{
id: string;
name: string;
description: string;
}>;
}>("/image/edit-modes", {
method: "GET",
});
return response.modes;
},
async getStylePresets() {
const response = await apiRequest<{
presets: Array<{
id: string;
name: string;
description: string;
}>;
}>("/image/style-presets", {
method: "GET",
});
return response.presets;
},
// 历史记录 API
async getImageHistory(page: number = 1, page_size: number = 20) {
return apiRequest<{
images: Array<{
id: string;
url: string;
prompt: string;
style: string;
size: string;
created_at: string;
metadata: any;
}>;
total: number;
page: number;
page_size: number;
has_next: boolean;
has_prev: boolean;
}>(`/image/history?page=${page}&page_size=${page_size}`, {
method: "GET",
});
},
async deleteImage(imageId: string) {
return apiRequest<{ message: string }>(`/image/${imageId}`, {
method: "DELETE",
});
},
};
// 聊天相关API
export const chatAPI = {
async createSession(title: string = "新对话") {
return apiRequest<{
id: number;
title: string;
created_at: string;
updated_at: string;
message_count: number;
}>("/chat/sessions", {
method: "POST",
body: JSON.stringify({ title }),
});
},
async sendMessage(message: string, sessionId?: number) {
return apiRequest<{
answer: string;
sources: Array<{
title: string;
filename: string;
page: number;
score: number;
preview: string;
}>;
session_id: number;
message_id: number;
}>("/chat/send", {
method: "POST",
body: JSON.stringify({ message, session_id: sessionId }),
});
},
async streamMessage(
message: string,
sessionId: number | undefined,
mode: string,
knowledgeBaseIds?: string[],
signal?: AbortSignal,
onChunk?: (chunk: string) => void,
onComplete?: (sessionId: number, messageId?: number, userMessageId?: number) => void,
onError?: (error: string) => void,
onStatus?: (status: string) => void,
onThinking?: (step: { step: string; message: string; details?: Record<string, any>; timestamp?: string }) => void,
onThinkingContent?: (content: string) => void,
model?: string
) {
const url = `${API_BASE_URL}/chat/stream`;
const token = localStorage.getItem("auth_token");
const requestBody: any = {
message,
mode: mode,
};
// 添加模型ID
if (model) {
requestBody.model = model;
}
// 只在有值时添加 session_id
if (sessionId !== undefined && sessionId !== null) {
requestBody.session_id = sessionId;
}
// 只在有值且非空数组时添加 knowledge_base_ids
if (knowledgeBaseIds && knowledgeBaseIds.length > 0) {
// 智能提取数字ID
const numericIds = knowledgeBaseIds
.map(id => {
// 如果已经是数字字符串,直接转换
if (/^\d+$/.test(id)) {
return parseInt(id);
}
// 如果是 "kb-system-1" 格式,提取末尾数字
const match = id.match(/\d+$/);
return match ? parseInt(match[0]) : null;
})
.filter(id => id !== null && !isNaN(id));
// 只有在有有效ID时才添加
if (numericIds.length > 0) {
requestBody.knowledge_base_ids = numericIds;
}
}
console.log("[DEBUG-CHAT] 发送流式请求:", {
url,
body: requestBody,
bodyJSON: JSON.stringify(requestBody),
headers: {
"Content-Type": "application/json",
...(token && { Authorization: `Bearer ${token}` }),
}
});
console.log("[DEBUG-CHAT] 请求详情:", {
message: message,
sessionId: sessionId,
mode: mode,
knowledgeBaseIds: knowledgeBaseIds,
model: model,
hasToken: !!token
});
let response;
try {
response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
...(token && { Authorization: `Bearer ${token}` }),
},
body: JSON.stringify(requestBody),
signal, // 新增:传递 signal
});
} catch (fetchError) {
// 检查是否是用户中止
if (fetchError instanceof Error && fetchError.name === 'AbortError') {
console.log("[DEBUG-STOP] 用户中止了请求");
onError?.("已停止生成");
return;
}
console.error("❌ Fetch failed:", fetchError);
onError?.(`Network error: ${fetchError}`);
return;
}
console.log("[DEBUG-STREAM] 流式响应:", {
status: response.status,
statusText: response.statusText,
ok: response.ok,
headers: Object.fromEntries(response.headers.entries())
});
if (!response.ok) {
console.error("❌ Chat stream failed:", {
status: response.status,
statusText: response.statusText,
url: response.url,
ok: response.ok
});
try {
const errorData = await response.json();
console.error("❌ Error response body:", errorData);
onError?.(`HTTP ${response.status}: ${errorData.detail || errorData.message || response.statusText}`);
} catch (e) {
console.error("❌ Could not parse error response:", e);
onError?.(`HTTP ${response.status}: ${response.statusText}`);
}
return;
}
const reader = response.body?.getReader();
if (!reader) {
onError?.("无法读取响应流");
return;
}
const decoder = new TextDecoder();
let buffer = ""; // Buffer for incomplete lines
try {
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value, { stream: true });
buffer += chunk; // Accumulate data
const lines = buffer.split("\n");
// Keep the last incomplete line in buffer
buffer = lines.pop() || "";
for (const line of lines) {
if (line.startsWith("data: ")) {
try {
const data = JSON.parse(line.slice(6));
if (data.type === "status") {
console.log("[DEBUG-STREAM] 状态更新:", data.message);
onStatus?.(data.message);
} else if (data.type === "thinking") {
console.log("[DEBUG-STREAM] 思考中:", data.message);
// 将thinking数据作为JSON字符串传递给onChunk,让Zustand store处理
onChunk?.(JSON.stringify(data));
} else if (data.type === "thinking_content") {
console.log("[DEBUG-STREAM] 思考内容:", data.content);
onThinkingContent?.(data.content);
} else if (data.type === "chunk") {
console.log("[DEBUG-STREAM] 接收chunk:", data.content);
onChunk?.(data.content);
} else if (data.type === "sources") {
console.log("[DEBUG-STREAM] 收到sources:", data.sources?.length, "个来源");
onChunk?.(JSON.stringify(data));
} else if (data.type === "done") {
console.log("[DEBUG-STREAM] 流式完成, session_id:", data.session_id, "message_id:", data.message_id, "user_message_id:", data.user_message_id);
onComplete?.(data.session_id, data.message_id, data.user_message_id);
} else if (data.error) {
console.log("[DEBUG-STREAM] 流式错误:", data.error);
onError?.(data.error);
}
} catch (e) {
// 忽略解析错误
console.warn("[DEBUG-STREAM] 解析SSE数据失败:", line, e);
}
}
}
}
} catch (error) {
// 检查是否是用户中止
if (error instanceof Error && error.name === 'AbortError') {
console.log("[DEBUG-STOP] 读取流时被中止");
onError?.("已停止生成");
} else {
onError?.(`流式请求失败: ${error}`);
}
} finally {
reader.releaseLock();
}
},
async getSessions() {
return apiRequest<Array<{
id: number;
title: string;
created_at: string;
updated_at: string;
message_count: number;
}>>("/chat/sessions");
},
async getSessionMessages(sessionId: number) {
return apiRequest<Array<{
id: number;
role: "user" | "assistant" | "system";
content: string;
created_at: string;
metadata?: any;
}>>(`/chat/sessions/${sessionId}/messages`);
},
// 会话管理 API
async renameSession(sessionId: number, title: string) {
return apiRequest<{ message: string; title: string }>(`/chat/sessions/${sessionId}`, {
method: "PUT",
body: JSON.stringify({ title }),
});
},
async deleteSession(sessionId: number) {
return apiRequest<{ message: string }>(`/chat/sessions/${sessionId}`, {
method: "DELETE",
});
},
async exportSession(sessionId: number, format: string = "json") {
return apiRequest<{
session_id: number;
title: string;
messages: Array<{
id: number;
role: string;
content: string;
created_at: string;
feedback?: string;
edited: boolean;
}>;
export_format: string;
created_at: string;
}>(`/chat/sessions/${sessionId}/export?format=${format}`, {
method: "POST",
});
},
// 消息操作 API
async editMessage(messageId: number, content: string) {
return apiRequest<{ message: string }>(`/chat/messages/${messageId}`, {
method: "PUT",
body: JSON.stringify({ content }),
});
},
async regenerateMessage(messageId: number, model?: string) {
return apiRequest<{
message: string;
new_message_id: number;
content: string;
}>(`/chat/messages/${messageId}/regenerate`, {
method: "POST",
body: JSON.stringify({ model: model || null }),
});
},
async feedbackMessage(messageId: number, feedback: "like" | "dislike") {
return apiRequest<{ message: string; feedback: string }>(`/chat/messages/${messageId}/feedback`, {
method: "POST",
body: JSON.stringify({ feedback }),
});
},
};
// 文档相关API
export const documentAPI = {
/**
* @deprecated 此方法已废弃,请使用 knowledgeBaseAPI.uploadDocument()
*/
async uploadDocument(file: File) {
throw new Error("此方法已废弃,请使用知识库上传接口:knowledgeBaseAPI.uploadDocument()");
},
async getDocuments() {
return apiRequest<Array<{
id: number;
filename: string;
title: string;
file_size: number;
file_type: string;
is_processed: boolean;
is_public: boolean;
created_at: string;
updated_at: string;
}>>("/documents");
},
};
// 知识库相关API
export const knowledgeBaseAPI = {
// 获取用户的所有知识库
async getKnowledgeBases() {
return apiRequest<Array<{
id: number;
name: string;
description?: string;
user_id: number;
document_count: number;
created_at: string;
updated_at: string;
is_system?: boolean;
}>>("/knowledge-bases");
},
// 创建新知识库
async createKnowledgeBase(data: {
name: string;
description?: string;
}) {
return apiRequest<{
id: number;
name: string;
description?: string;
user_id: number;
document_count: number;
created_at: string;
updated_at: string;
}>("/knowledge-bases", {
method: "POST",
body: JSON.stringify(data),
});
},
// 获取知识库详情(包括文档列表)
async getKnowledgeBase(id: string) {
return apiRequest<{
id: number;
name: string;
description?: string;
user_id: number;
document_count: number;
created_at: string;
updated_at: string;
documents: Array<{
id: number;
filename: string;
title: string;
file_size: number;
file_type: string;
is_processed: boolean;
is_public: boolean;
knowledge_base_id: number;
created_at: string;
updated_at: string;
}>;
}>(`/knowledge-bases/${id}`);
},
// 更新知识库信息
async updateKnowledgeBase(id: string, data: {
name?: string;
description?: string;
}) {
return apiRequest<{
id: number;
name: string;
description?: string;
user_id: number;
document_count: number;
created_at: string;
updated_at: string;
}>(`/knowledge-bases/${id}`, {
method: "PUT",
body: JSON.stringify(data),
});
},
// 删除知识库
async deleteKnowledgeBase(id: string) {
return apiRequest<void>(`/knowledge-bases/${id}`, {
method: "DELETE",
});
},
// 上传文档到指定知识库
async uploadDocument(
knowledgeBaseId: string,
file: File,
title: string,
description?: string
) {
const formData = new FormData();
formData.append("file", file);
formData.append("title", title);
if (description) {
formData.append("description", description);
}
const token = localStorage.getItem("auth_token");
const response = await fetch(`${API_BASE_URL}/knowledge-bases/${knowledgeBaseId}/documents`, {
method: "POST",
headers: {
...(token && { Authorization: `Bearer ${token}` }),
},
body: formData,
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(errorData.detail || `HTTP ${response.status}`);
}
return await response.json();
},
// 获取知识库的文档列表
async getKnowledgeBaseDocuments(knowledgeBaseId: string) {
return apiRequest<Array<{
id: number;
filename: string;
title: string;
file_size: number;
file_type: string;
is_processed: boolean;
is_public: boolean;
knowledge_base_id: number;
created_at: string;
updated_at: string;
}>>(`/knowledge-bases/${knowledgeBaseId}/documents`);
},
// 删除文档
async deleteDocument(documentId: string) {
return apiRequest<void>(`/documents/${documentId}`, {
method: "DELETE",
});
},
};
// 论坛 API
export const forumAPI = {
async getCategories() {
return apiRequest<ForumCategory[]>("/forum/categories");
},
async getPosts(categoryId: number, limit: number = 20) {
const params = new URLSearchParams({ limit: String(limit) });
return apiRequest<ForumPostSummary[]>(
`/forum/categories/${categoryId}/posts?${params.toString()}`
);
},
async createPost(categoryId: number, data: { title: string; content: string }) {
return apiRequest<ForumPostDetail>(`/forum/categories/${categoryId}/posts`, {
method: "POST",
body: JSON.stringify(data),
});
},
async getPost(postId: number) {
return apiRequest<ForumPostDetail>(`/forum/posts/${postId}`);
},
async createReply(postId: number, content: string) {
return apiRequest<ForumReply>(`/forum/posts/${postId}/replies`, {
method: "POST",
body: JSON.stringify({ content }),
});
},
};
// 学习分析 API
export const analyticsAPI = {
async getPlatformStats() {
return apiRequest<{
active_users: number;
knowledge_documents: number;
qa_dialogues: number;
generated_images: number;
}>("/analytics/platform-stats", {
method: "GET",
});
},
// 获取用户统计数据
async getStatistics() {
return apiRequest<{
total_sessions: number;
total_messages: number;
total_documents: number;
active_days: number;
user_since: string;
last_login: string;
}>("/analytics/statistics", {
method: "GET",
});
},
// 获取学习报告
async getLearningReport() {
return apiRequest<{
user_id: number;
total_questions: number;
topics_covered: string[];
learning_progress: number;
recommendations: string[];
study_time: number;
knowledge_gaps: string[];
}>("/analytics/learning-report", {
method: "GET",
});
},
// 获取学习趋势
async getLearningTrends(days: number = 30) {
return apiRequest<{
success: boolean;
data: Array<{
date: string;
sessions: number;
messages: number;
}>;
}>(`/analytics/trends?days=${days}`, {
method: "GET",
});
},
// 获取热门问题
async getPopularQuestions(limit: number = 10) {
return apiRequest<{
success: boolean;
data: Array<{
question: string;
count: number;
category: string;
}>;
}>(`/analytics/popular-questions?limit=${limit}`, {
method: "GET",
});
},
// 获取知识覆盖度
async getKnowledgeCoverage() {
return apiRequest<{
success: boolean;
data: Array<{
topic: string;
coverage: number;
questions: number;
}>;
}>("/analytics/knowledge-coverage", {
method: "GET",
});
},
// 获取完整分析数据
async getFullAnalytics() {
return apiRequest<{
success: boolean;
data: {
statistics: {
total_sessions: number;
total_messages: number;
total_documents: number;
active_days: number;
user_since: string;
last_login: string;
};
learning_trends: Array<{
date: string;
sessions: number;
messages: number;
}>;
popular_questions: Array<{
question: string;
count: number;
category: string;
}>;
knowledge_coverage: Array<{
topic: string;
coverage: number;
questions: number;
}>;
learning_report: {
user_id: number;
total_questions: number;
topics_covered: string[];
learning_progress: number;
recommendations: string[];
study_time: number;
knowledge_gaps: string[];
};
};
}>("/analytics/full-analytics", {
method: "GET",
});
},
};
// 课程内容API
export const courseContentAPI = {
// 获取书籍层级结构(新版本)
async getCourseContent(): Promise<BookStructure> {
return apiRequest<BookStructure>("/course-content", {
method: "GET",
});
},
// 获取章节完整内容
async getChapterContent(chapterId: number): Promise<{ content: string }> {
return apiRequest<{ content: string }>(`/course-content/chapters/${chapterId}/content`, {
method: "GET",
});
},
// 获取节完整内容
async getSectionContent(sectionId: number): Promise<{ content: string }> {
return apiRequest<{ content: string }>(`/course-content/sections/${sectionId}/content`, {
method: "GET",
});
},
// 获取小节完整内容(知识点)
async getSubsectionContent(subsectionId: number): Promise<{ content: string }> {
return apiRequest<{ content: string }>(`/course-content/subsections/${subsectionId}/content`, {
method: "GET",
});
},
};
// 书籍相关API
export const bookAPI = {
// 获取所有书籍列表
async getBooks(): Promise<Book[]> {
return apiRequest<Book[]>("/books", {
method: "GET",
});
},
// 获取书籍章节列表
async getBookChapters(bookId: number): Promise<Chapter[]> {
return apiRequest<Chapter[]>(`/books/${bookId}/chapters`, {
method: "GET",
});
},
// 获取PDF文件URL
getBookFileUrl(bookId: number): string {
return `${API_BASE_URL}/books/${bookId}/file`;
},
};
// ===== 后台管理 API =====
export const adminAPI = {
// 仪表盘
async getDashboard() {
return apiRequest<{
total_users: number;
active_users_7d: number;
total_sessions: number;
total_messages: number;
total_documents: number;
total_knowledge_bases: number;
total_forum_posts: number;
total_forum_replies: number;
total_generated_images: number;
}>("/admin/dashboard");
},
async getUserTrends(days = 30) {
return apiRequest<{ date: string; count: number }[]>(`/admin/trends/users?days=${days}`);
},
async getMessageTrends(days = 30) {
return apiRequest<{ date: string; count: number }[]>(`/admin/trends/messages?days=${days}`);
},
// 用户管理
async listUsers(skip = 0, limit = 50) {
return apiRequest<{
id: number;
username: string;
email: string;
full_name: string | null;
is_active: boolean;
is_superuser: boolean;
created_at: string | null;
last_login: string | null;
session_count: number;
message_count: number;
}[]>(`/admin/users?skip=${skip}&limit=${limit}`);
},
async toggleUserActive(userId: number) {
return apiRequest<{ success: boolean; is_active: boolean }>(`/admin/users/${userId}/toggle-active`, { method: "PUT" });
},
async toggleUserAdmin(userId: number) {
return apiRequest<{ success: boolean; is_superuser: boolean }>(`/admin/users/${userId}/toggle-admin`, { method: "PUT" });
},
async deleteUser(userId: number) {
return apiRequest<{ success: boolean }>(`/admin/users/${userId}`, { method: "DELETE" });
},
// 论坛管理
async listForumCategories() {
return apiRequest<{
id: number;
slug: string;
name: string;
description: string | null;
post_count: number;
}[]>("/admin/forum/categories");
},
async createForumCategory(data: { name: string; slug: string; description?: string }) {
return apiRequest("/admin/forum/categories", {
method: "POST",
body: JSON.stringify(data),
});
},
async updateForumCategory(categoryId: number, data: { name: string; slug: string; description?: string }) {
return apiRequest(`/admin/forum/categories/${categoryId}`, {
method: "PUT",
body: JSON.stringify(data),
});
},
async deleteForumCategory(categoryId: number) {
return apiRequest<{ success: boolean }>(`/admin/forum/categories/${categoryId}`, { method: "DELETE" });
},
async listForumPosts(skip = 0, limit = 50) {
return apiRequest<{
id: number;
title: string;
author_name: string;
category_name: string;
reply_count: number;
created_at: string;
}[]>(`/admin/forum/posts?skip=${skip}&limit=${limit}`);
},
async deleteForumPost(postId: number) {
return apiRequest<{ success: boolean }>(`/admin/forum/posts/${postId}`, { method: "DELETE" });
},
// 知识库管理
async listKnowledgeBases() {
return apiRequest<{
id: number;
name: string;
description: string | null;
owner_name: string;
is_system: boolean;
document_count: number;
chunk_count: number;
created_at: string;
}[]>("/admin/knowledge-bases");
},
async deleteKnowledgeBase(kbId: number) {
return apiRequest<{ success: boolean }>(`/admin/knowledge-bases/${kbId}`, { method: "DELETE" });
},
// 系统状态
async getSystemStatus() {
return apiRequest<{
database: { status: string };
vector_store: { status: string; vector_count: number };
llm_model: string;
embedding_model: string;
}>("/admin/system/status");
},
};