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:
472
src/hooks/document-hooks.ts
Normal file
472
src/hooks/document-hooks.ts
Normal 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,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user