feat(knowledge): add knowledge base detail page components and hooks

refactor(knowledge): restructure knowledge detail page with new components
feat(components): add FileUploadDialog for file upload functionality
feat(hooks): implement document management hooks for CRUD operations
This commit is contained in:
2025-10-14 15:42:40 +08:00
parent 34181cf025
commit 7384ae36d0
12 changed files with 1456 additions and 356 deletions

472
src/hooks/document-hooks.ts Normal file
View File

@@ -0,0 +1,472 @@
import { useState, useEffect, useCallback } from 'react';
import knowledgeService from '@/services/knowledge_service';
import type { IKnowledgeFile } from '@/interfaces/database/knowledge';
import type { IFetchKnowledgeListRequestParams, IFetchDocumentListRequestBody } from '@/interfaces/request/knowledge';
// 文档列表Hook状态接口
export interface UseDocumentListState {
documents: IKnowledgeFile[];
total: number;
loading: boolean;
error: string | null;
currentPage: number;
pageSize: number;
keywords: string;
}
// 文档列表Hook返回值接口
export interface UseDocumentListReturn extends UseDocumentListState {
fetchDocuments: (params?: IFetchKnowledgeListRequestParams) => Promise<void>;
setKeywords: (keywords: string) => void;
setCurrentPage: (page: number) => void;
setPageSize: (size: number) => void;
refresh: () => Promise<void>;
}
/**
* 文档列表数据管理Hook
* 支持关键词搜索、分页等功能
*/
export const useDocumentList = (
kbId: string,
initialParams?: IFetchKnowledgeListRequestParams
): UseDocumentListReturn => {
const [documents, setDocuments] = useState<IKnowledgeFile[]>([]);
const [total, setTotal] = useState(0);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [currentPage, setCurrentPage] = useState(initialParams?.page || 1);
const [pageSize, setPageSize] = useState(initialParams?.page_size || 10);
const [keywords, setKeywords] = useState(initialParams?.keywords || '');
/**
* 获取文档列表
*/
const fetchDocuments = useCallback(async (params?: IFetchKnowledgeListRequestParams) => {
if (!kbId) return;
try {
setLoading(true);
setError(null);
// 合并参数
const queryParams = {
keywords: params?.keywords ?? keywords,
page: params?.page ?? currentPage,
page_size: params?.page_size ?? pageSize,
};
// 构建请求体
const requestBody: IFetchDocumentListRequestBody = {};
// 构建查询参数
const requestParams: IFetchKnowledgeListRequestParams = {
kb_id: kbId,
};
if (queryParams.page) {
requestParams.page = queryParams.page;
}
if (queryParams.page_size) {
requestParams.page_size = queryParams.page_size;
}
if (queryParams.keywords && queryParams.keywords.trim()) {
requestParams.keywords = queryParams.keywords.trim();
}
const response = await knowledgeService.getDocumentList(
Object.keys(requestParams).length > 0 ? requestParams : undefined,
requestBody
);
// 检查响应状态
if (response.data.code === 0) {
const data = response.data.data;
setDocuments(data.docs || []);
setTotal(data.total || 0);
} else {
throw new Error(response.data.message || '获取文档列表失败');
}
} catch (err: any) {
const errorMessage = err.response?.data?.message || err.message || '获取文档列表失败';
setError(errorMessage);
console.error('Failed to fetch documents:', err);
} finally {
setLoading(false);
}
}, [kbId, keywords, currentPage, pageSize]);
/**
* 刷新当前页面数据
*/
const refresh = useCallback(() => {
return fetchDocuments();
}, [fetchDocuments]);
/**
* 设置关键词并重置到第一页
*/
const handleSetKeywords = useCallback((newKeywords: string) => {
setKeywords(newKeywords);
setCurrentPage(1);
}, []);
/**
* 设置当前页
*/
const handleSetCurrentPage = useCallback((page: number) => {
setCurrentPage(page);
}, []);
/**
* 设置页面大小并重置到第一页
*/
const handleSetPageSize = useCallback((size: number) => {
setPageSize(size);
setCurrentPage(1);
}, []);
// 当关键词、页码或页面大小变化时重新获取数据
useEffect(() => {
fetchDocuments();
}, [keywords, currentPage, pageSize]);
return {
documents,
total,
loading,
error,
currentPage,
pageSize,
keywords,
fetchDocuments,
setKeywords: handleSetKeywords,
setCurrentPage: handleSetCurrentPage,
setPageSize: handleSetPageSize,
refresh,
};
};
/**
* 文档操作Hook
* 提供上传、删除、重命名等功能
*/
export const useDocumentOperations = () => {
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
/**
* 上传文档
*/
const uploadDocuments = useCallback(async (kbId: string, files: File[]) => {
try {
setLoading(true);
setError(null);
const formData = new FormData();
formData.append('kb_id', kbId);
files.forEach((file) => {
formData.append('file', file);
});
const response = await knowledgeService.uploadDocument(formData);
if (response.data.code === 0) {
return response.data.data;
} else {
throw new Error(response.data.message || '上传文档失败');
}
} catch (err: any) {
const errorMessage = err.response?.data?.message || err.message || '上传文档失败';
setError(errorMessage);
console.error('Failed to upload documents:', err);
throw err;
} finally {
setLoading(false);
}
}, []);
/**
* 上传并解析文档
*/
const uploadAndParseDocuments = useCallback(async (kbId: string, files: File[]) => {
try {
setLoading(true);
setError(null);
const formData = new FormData();
formData.append('kb_id', kbId);
files.forEach((file) => {
formData.append('file', file);
});
const response = await knowledgeService.uploadAndParseDocument(formData);
if (response.data.code === 0) {
return response.data.data;
} else {
throw new Error(response.data.message || '上传并解析文档失败');
}
} catch (err: any) {
const errorMessage = err.response?.data?.message || err.message || '上传并解析文档失败';
setError(errorMessage);
console.error('Failed to upload and parse documents:', err);
throw err;
} finally {
setLoading(false);
}
}, []);
/**
* 删除文档
*/
const deleteDocuments = useCallback(async (docIds: string | string[]) => {
try {
setLoading(true);
setError(null);
const response = await knowledgeService.removeDocument({ doc_id: docIds });
if (response.data.code === 0) {
return response.data.data;
} else {
throw new Error(response.data.message || '删除文档失败');
}
} catch (err: any) {
const errorMessage = err.response?.data?.message || err.message || '删除文档失败';
setError(errorMessage);
console.error('Failed to delete documents:', err);
throw err;
} finally {
setLoading(false);
}
}, []);
/**
* 重命名文档
*/
const renameDocument = useCallback(async (docId: string, name: string) => {
try {
setLoading(true);
setError(null);
const response = await knowledgeService.renameDocument({ doc_id: docId, name });
if (response.data.code === 0) {
return response.data.data;
} else {
throw new Error(response.data.message || '重命名文档失败');
}
} catch (err: any) {
const errorMessage = err.response?.data?.message || err.message || '重命名文档失败';
setError(errorMessage);
console.error('Failed to rename document:', err);
throw err;
} finally {
setLoading(false);
}
}, []);
/**
* 创建文档
*/
const createDocument = useCallback(async (data: any) => {
try {
setLoading(true);
setError(null);
const response = await knowledgeService.createDocument(data);
if (response.data.code === 0) {
return response.data.data;
} else {
throw new Error(response.data.message || '创建文档失败');
}
} catch (err: any) {
const errorMessage = err.response?.data?.message || err.message || '创建文档失败';
setError(errorMessage);
console.error('Failed to create document:', err);
throw err;
} finally {
setLoading(false);
}
}, []);
/**
* 更改文档状态
*/
const changeDocumentStatus = useCallback(async (docIds: string[], status: string) => {
try {
setLoading(true);
setError(null);
const response = await knowledgeService.changeDocumentStatus({ doc_id: docIds, status });
if (response.data.code === 0) {
return response.data.data;
} else {
throw new Error(response.data.message || '更改文档状态失败');
}
} catch (err: any) {
const errorMessage = err.response?.data?.message || err.message || '更改文档状态失败';
setError(errorMessage);
console.error('Failed to change document status:', err);
throw err;
} finally {
setLoading(false);
}
}, []);
/**
* 运行文档处理
*/
const runDocuments = useCallback(async (docIds: string[]) => {
try {
setLoading(true);
setError(null);
const response = await knowledgeService.runDocument({ doc_id: docIds });
if (response.data.code === 0) {
return response.data.data;
} else {
throw new Error(response.data.message || '运行文档处理失败');
}
} catch (err: any) {
const errorMessage = err.response?.data?.message || err.message || '运行文档处理失败';
setError(errorMessage);
console.error('Failed to run documents:', err);
throw err;
} finally {
setLoading(false);
}
}, []);
/**
* 清除错误状态
*/
const clearError = useCallback(() => {
setError(null);
}, []);
return {
loading,
error,
uploadDocuments,
uploadAndParseDocuments,
deleteDocuments,
renameDocument,
createDocument,
changeDocumentStatus,
runDocuments,
clearError,
};
};
/**
* 文档批量操作Hook
* 提供批量删除等功能
*/
export const useDocumentBatchOperations = () => {
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
/**
* 批量删除文档
*/
const batchDeleteDocuments = useCallback(async (docIds: string[]) => {
try {
setLoading(true);
setError(null);
const results = await Promise.allSettled(
docIds.map(docId => knowledgeService.removeDocument({ doc_id: docId }))
);
const failures = results
.map((result, index) => ({ result, index }))
.filter(({ result }) => result.status === 'rejected')
.map(({ index }) => docIds[index]);
if (failures.length > 0) {
throw new Error(`删除失败的文档: ${failures.join(', ')}`);
}
return results;
} catch (err: any) {
const errorMessage = err.response?.data?.message || err.message || '批量删除文档失败';
setError(errorMessage);
console.error('Failed to batch delete documents:', err);
throw err;
} finally {
setLoading(false);
}
}, []);
/**
* 批量更改文档状态
*/
const batchChangeDocumentStatus = useCallback(async (docIds: string[], status: string) => {
try {
setLoading(true);
setError(null);
const response = await knowledgeService.changeDocumentStatus({ doc_id: docIds, status });
if (response.data.code === 0) {
return response.data.data;
} else {
throw new Error(response.data.message || '批量更改文档状态失败');
}
} catch (err: any) {
const errorMessage = err.response?.data?.message || err.message || '批量更改文档状态失败';
setError(errorMessage);
console.error('Failed to batch change document status:', err);
throw err;
} finally {
setLoading(false);
}
}, []);
/**
* 批量运行文档处理
*/
const batchRunDocuments = useCallback(async (docIds: string[]) => {
try {
setLoading(true);
setError(null);
const response = await knowledgeService.runDocument({ doc_id: docIds });
if (response.data.code === 0) {
return response.data.data;
} else {
throw new Error(response.data.message || '批量运行文档处理失败');
}
} catch (err: any) {
const errorMessage = err.response?.data?.message || err.message || '批量运行文档处理失败';
setError(errorMessage);
console.error('Failed to batch run documents:', err);
throw err;
} finally {
setLoading(false);
}
}, []);
/**
* 清除错误状态
*/
const clearError = useCallback(() => {
setError(null);
}, []);
return {
loading,
error,
batchDeleteDocuments,
batchChangeDocumentStatus,
batchRunDocuments,
clearError,
};
};