import request from './request' import type { ApiResponse } from '@/types/api' import { getToken } from '@/utils/token' /** Token 相关辅助 —— 旧版 api.js 中 handleUnauthorized 行为已由 request.ts 拦截器接管 */ function authHeaders(): Record { const token = getToken() return token ? { Authorization: `Bearer ${token}` } : {} } // ==================== 文档 CRUD ==================== /** 文档列表(分页 + 过滤 + 搜索) */ export function listDocuments(page = 1, size = 10, categoryId?: string, status?: string, keyword?: string, tag?: string, folderId?: string, sortField?: string, sortOrder?: string): Promise { let path = `/document/list?page=${page}&size=${size}` if (categoryId) path += `&categoryId=${categoryId}` if (folderId != null) path += `&folderId=${folderId}` if (status) path += `&status=${status}` if (keyword) path += `&keyword=${encodeURIComponent(keyword)}` if (tag) path += `&tag=${encodeURIComponent(tag)}` if (sortField) path += `&sortField=${sortField}` if (sortOrder) path += `&sortOrder=${sortOrder}` return request.get(path).then(r => r.data) } /** 文档详情 */ export function getDocumentDetail(id: string): Promise { return request.get(`/document/${id}`).then(r => r.data) } /** 文档分块列表 */ export function getDocumentChunks(id: string): Promise { return request.get(`/document/${id}/chunks`).then(r => r.data) } /** 下载文档原始文件 */ export async function downloadDocument(id: string): Promise { const response = await fetch(`/document/download/${id}`, { headers: authHeaders() }) if (!response.ok) { const error = await response.json().catch(() => ({ message: '下载失败' })) throw new Error(error.message || `HTTP ${response.status}`) } const disposition = response.headers.get('Content-Disposition') let filename = 'download' if (disposition) { const utf8Match = disposition.match(/filename\*=UTF-8''(.+?)(?:;|$)/i) if (utf8Match) { filename = decodeURIComponent(utf8Match[1]) } else { const quotedMatch = disposition.match(/filename="(.+?)"/i) if (quotedMatch) filename = decodeURIComponent(quotedMatch[1]) } } const blob = await response.blob() const url = window.URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = filename document.body.appendChild(a) a.click() document.body.removeChild(a) window.URL.revokeObjectURL(url) } /** 删除文档 */ export function deleteDocument(id: string): Promise { return request.delete(`/document/${id}`).then(r => r.data) } /** 更新文档元信息 */ export function updateDocument(id: string, title: string, categoryId: string, tags?: string[]): Promise { return request.put(`/document/${id}`, { title, categoryId, tags }).then(r => r.data) } /** 重新处理文档 */ export function reprocessDocument(id: string): Promise { return request.put(`/document/${id}/reprocess`).then(r => r.data) } /** 批量删除文档 */ export function batchDeleteDocuments(ids: string[]): Promise { return request.post('/document/batch/delete', { ids }).then(r => r.data) } /** 批量重新处理文档 */ export function batchReprocessDocuments(ids: string[]): Promise { return request.post('/document/batch/reprocess', { ids }).then(r => r.data) } /** 切换文档启用/禁用 */ export function toggleDocument(id: string): Promise { return request.put(`/document/${id}/toggle`).then(r => r.data) } /** 批量启用/禁用 */ export function batchToggleDocuments(ids: string[], enabled: boolean): Promise { return request.post('/document/batch/toggle', { ids, enabled }).then(r => r.data) } /** 批量移动(分类根或目录,folderId 为空/0 表示移动到分类根) */ export function batchMoveDocuments(ids: string[], categoryId: string, folderId?: string): Promise { return request.post('/document/batch/move', { ids, categoryId, folderId }).then(r => r.data) } /** 更新单个分块内容 */ export function updateChunk(docId: string, chunkIndex: number, content: string): Promise { return request.put(`/document/${docId}/chunk/${chunkIndex}`, { content }).then(r => r.data) } /** 删除单个分块 */ export function deleteChunk(docId: string, chunkIndex: number): Promise { return request.delete(`/document/${docId}/chunk/${chunkIndex}`).then(r => r.data) } /** 语义搜索 */ export function searchDocuments(query: string, topK?: number, similarityThreshold?: number, categoryId?: string, categoryIds?: string[], searchMode?: string): Promise { const body: any = { query, topK, similarityThreshold } if (categoryIds && categoryIds.length) body.categoryIds = categoryIds if (categoryId) body.categoryId = categoryId if (searchMode) body.searchMode = searchMode return request.post('/document/search', body).then(r => r.data) } // ==================== 统计 ==================== /** 知识库统计 */ export function getStats(): Promise { return request.get('/document/stats').then(r => r.data) } // ==================== 标签 ==================== /** 获取标签列表 */ export function getTagList(): Promise { return request.get('/tag/list').then(r => r.data) }