You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
137 lines
5.3 KiB
137 lines
5.3 KiB
import request from './request'
|
|
import type { ApiResponse } from '@/types/api'
|
|
import { getToken } from '@/utils/token'
|
|
|
|
/** Token 相关辅助 —— 旧版 api.js 中 handleUnauthorized 行为已由 request.ts 拦截器接管 */
|
|
|
|
function authHeaders(): Record<string, string> {
|
|
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<ApiResponse> {
|
|
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<ApiResponse> {
|
|
return request.get(`/document/${id}`).then(r => r.data)
|
|
}
|
|
|
|
/** 文档分块列表 */
|
|
export function getDocumentChunks(id: string): Promise<ApiResponse> {
|
|
return request.get(`/document/${id}/chunks`).then(r => r.data)
|
|
}
|
|
|
|
/** 下载文档原始文件 */
|
|
export async function downloadDocument(id: string): Promise<void> {
|
|
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<ApiResponse> {
|
|
return request.delete(`/document/${id}`).then(r => r.data)
|
|
}
|
|
|
|
/** 更新文档元信息 */
|
|
export function updateDocument(id: string, title: string, categoryId: string, tags?: string[]): Promise<ApiResponse> {
|
|
return request.put(`/document/${id}`, { title, categoryId, tags }).then(r => r.data)
|
|
}
|
|
|
|
/** 重新处理文档 */
|
|
export function reprocessDocument(id: string): Promise<ApiResponse> {
|
|
return request.put(`/document/${id}/reprocess`).then(r => r.data)
|
|
}
|
|
|
|
/** 批量删除文档 */
|
|
export function batchDeleteDocuments(ids: string[]): Promise<ApiResponse> {
|
|
return request.post('/document/batch/delete', { ids }).then(r => r.data)
|
|
}
|
|
|
|
/** 批量重新处理文档 */
|
|
export function batchReprocessDocuments(ids: string[]): Promise<ApiResponse> {
|
|
return request.post('/document/batch/reprocess', { ids }).then(r => r.data)
|
|
}
|
|
|
|
/** 切换文档启用/禁用 */
|
|
export function toggleDocument(id: string): Promise<ApiResponse> {
|
|
return request.put(`/document/${id}/toggle`).then(r => r.data)
|
|
}
|
|
|
|
/** 批量启用/禁用 */
|
|
export function batchToggleDocuments(ids: string[], enabled: boolean): Promise<ApiResponse> {
|
|
return request.post('/document/batch/toggle', { ids, enabled }).then(r => r.data)
|
|
}
|
|
|
|
/** 批量移动(分类根或目录,folderId 为空/0 表示移动到分类根) */
|
|
export function batchMoveDocuments(ids: string[], categoryId: string, folderId?: string): Promise<ApiResponse> {
|
|
return request.post('/document/batch/move', { ids, categoryId, folderId }).then(r => r.data)
|
|
}
|
|
|
|
/** 更新单个分块内容 */
|
|
export function updateChunk(docId: string, chunkIndex: number, content: string): Promise<ApiResponse> {
|
|
return request.put(`/document/${docId}/chunk/${chunkIndex}`, { content }).then(r => r.data)
|
|
}
|
|
|
|
/** 删除单个分块 */
|
|
export function deleteChunk(docId: string, chunkIndex: number): Promise<ApiResponse> {
|
|
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<ApiResponse> {
|
|
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<ApiResponse> {
|
|
return request.get('/document/stats').then(r => r.data)
|
|
}
|
|
|
|
// ==================== 标签 ====================
|
|
|
|
/** 获取标签列表 */
|
|
export function getTagList(): Promise<ApiResponse> {
|
|
return request.get('/tag/list').then(r => r.data)
|
|
}
|