Merge #27 into develop_web from feature/20251219_yjp
feat(knowledgeBase): Refactor document list API and improve polling logic * feature/20251219_yjp: (1 commits) feat(knowledgeBase): Refactor document list API and improve polling logic Signed-off-by: vrhs@163.com <accounts_660b6454a0eb398d3f8d2c76@mail.teambition.com> Merged-by: vrhs@163.com <accounts_660b6454a0eb398d3f8d2c76@mail.teambition.com> CR-link: https://codeup.aliyun.com/redbearai/python/redbear-mem-open/change/27
This commit is contained in:
@@ -199,8 +199,8 @@ export const deleteFile = async (id: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 获取文档列表
|
// 获取文档列表
|
||||||
export const getDocumentList = async (query: PathQuery) => {
|
export const getDocumentList = async (kb_id:string, query: PathQuery) => {
|
||||||
const response = await request.get(`${apiPrefix}/documents/${query.kb_id}/documents`, query);
|
const response = await request.get(`${apiPrefix}/documents/${kb_id}/documents`, query);
|
||||||
return response as KnowledgeBaseDocumentData[];
|
return response as KnowledgeBaseDocumentData[];
|
||||||
};
|
};
|
||||||
// 文档详情
|
// 文档详情
|
||||||
|
|||||||
@@ -111,15 +111,17 @@ const CreateDataset = () => {
|
|||||||
|
|
||||||
// 从参数设置进入确认上传时的处理
|
// 从参数设置进入确认上传时的处理
|
||||||
if(current === 1 && nextStep === 2) {
|
if(current === 1 && nextStep === 2) {
|
||||||
|
// debugger
|
||||||
// handlePreview(data[0],0)
|
// handlePreview(data[0],0)
|
||||||
if(parameterSettings === 'customSettings'){
|
if(parameterSettings === 'customSettings' || processingMethod === 'qaExtract'){
|
||||||
rechunkFileIds.map((id) => {
|
rechunkFileIds.map((id) => {
|
||||||
const params = {
|
const params = {
|
||||||
|
progress: 0,
|
||||||
parser_config: {
|
parser_config: {
|
||||||
layout_recognize:'DeepDOC',
|
layout_recognize:'DeepDOC',
|
||||||
delimiter: delimiter,
|
delimiter: delimiter,
|
||||||
chunk_token_num: blockSize,
|
chunk_token_num: blockSize,
|
||||||
auto_question: processingMethod === 'directBlock' ? 0 : 1,
|
auto_questions: processingMethod === 'directBlock' ? 0 : 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateDocument(id, params)
|
updateDocument(id, params)
|
||||||
@@ -145,7 +147,6 @@ const CreateDataset = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 显示确认弹框
|
// 显示确认弹框
|
||||||
confirm({
|
confirm({
|
||||||
title: t('knowledgeBase.startUploadConfirmTitle') || '开始处理文档',
|
title: t('knowledgeBase.startUploadConfirmTitle') || '开始处理文档',
|
||||||
@@ -153,12 +154,18 @@ const CreateDataset = () => {
|
|||||||
okText: t('knowledgeBase.returnToList') || '返回列表页',
|
okText: t('knowledgeBase.returnToList') || '返回列表页',
|
||||||
cancelText: t('knowledgeBase.stayOnPage') || '停留在此页',
|
cancelText: t('knowledgeBase.stayOnPage') || '停留在此页',
|
||||||
onOk: () => {
|
onOk: () => {
|
||||||
// 用户选择返回列表页
|
// 用户选择返回列表页 - 不显示 loading,直接跳转
|
||||||
startProcessing(true);
|
startProcessing(true);
|
||||||
},
|
},
|
||||||
onCancel: () => {
|
onCancel: () => {
|
||||||
// 用户选择停留在当前页
|
// 用户选择停留在当前页 - 显示 loading 并开始轮询
|
||||||
startProcessing(false);
|
console.log('用户选择停留,开始显示 loading');
|
||||||
|
setPollingLoading(true);
|
||||||
|
|
||||||
|
// 延迟一点时间让用户看到 loading 效果,然后开始处理
|
||||||
|
setTimeout(() => {
|
||||||
|
startProcessing(false);
|
||||||
|
}, 100);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -170,15 +177,12 @@ const CreateDataset = () => {
|
|||||||
parseDocument(id, {});
|
parseDocument(id, {});
|
||||||
});
|
});
|
||||||
|
|
||||||
// 开启 loading
|
|
||||||
setPollingLoading(true);
|
|
||||||
|
|
||||||
if (autoReturnToList) {
|
if (autoReturnToList) {
|
||||||
// 用户选择立即返回,直接跳转
|
// 用户选择立即返回,直接跳转(不显示 loading)
|
||||||
console.log('用户选择立即返回列表页');
|
console.log('用户选择立即返回列表页');
|
||||||
handleBack();
|
handleBack();
|
||||||
} else {
|
} else {
|
||||||
// 用户选择停留,启动轮询查看进度
|
// 用户选择停留,启动轮询查看进度(loading 已在 onCancel 中设置)
|
||||||
console.log('用户选择停留查看进度');
|
console.log('用户选择停留查看进度');
|
||||||
|
|
||||||
// 立即执行一次轮询(启用自动返回)
|
// 立即执行一次轮询(启用自动返回)
|
||||||
@@ -187,7 +191,7 @@ const CreateDataset = () => {
|
|||||||
// 然后每3秒执行一次(启用自动返回)
|
// 然后每3秒执行一次(启用自动返回)
|
||||||
pollingTimerRef.current = setInterval(() => {
|
pollingTimerRef.current = setInterval(() => {
|
||||||
pollDocumentStatus(true);
|
pollDocumentStatus(true);
|
||||||
}, 5000);
|
}, 3000);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleDelete = (record: AnyObject) => {
|
const handleDelete = (record: AnyObject) => {
|
||||||
@@ -222,7 +226,7 @@ const CreateDataset = () => {
|
|||||||
title: t('knowledgeBase.status'),
|
title: t('knowledgeBase.status'),
|
||||||
dataIndex: 'progress',
|
dataIndex: 'progress',
|
||||||
key: 'progress',
|
key: 'progress',
|
||||||
render: (value: number) => {
|
render: (value: number, record: any) => {
|
||||||
return (
|
return (
|
||||||
<span className="rb:text-xs rb:border rb:border-[#DFE4ED] rb:bg-[#FBFDFF] rb:rounded rb:items-center rb:text-[#212332] rb:py-1 rb:px-2">
|
<span className="rb:text-xs rb:border rb:border-[#DFE4ED] rb:bg-[#FBFDFF] rb:rounded rb:items-center rb:text-[#212332] rb:py-1 rb:px-2">
|
||||||
<span className="rb:inline-block rb:w-[5px] rb:h-[5px] rb:mr-2 rb:rounded-full" style={{ backgroundColor: value === 1 ? '#369F21' : '#FF8A4C' }}></span>
|
<span className="rb:inline-block rb:w-[5px] rb:h-[5px] rb:mr-2 rb:rounded-full" style={{ backgroundColor: value === 1 ? '#369F21' : '#FF8A4C' }}></span>
|
||||||
@@ -280,44 +284,59 @@ const CreateDataset = () => {
|
|||||||
// 轮询检查文档处理状态
|
// 轮询检查文档处理状态
|
||||||
// autoReturn: 是否在所有文档完成时自动返回列表页
|
// autoReturn: 是否在所有文档完成时自动返回列表页
|
||||||
const pollDocumentStatus = (autoReturn: boolean = false) => {
|
const pollDocumentStatus = (autoReturn: boolean = false) => {
|
||||||
|
console.log('开始轮询文档状态,当前 pollingLoading:', pollingLoading);
|
||||||
|
|
||||||
if (!knowledgeBaseId || !parentId || rechunkFileIds.length === 0) {
|
if (!knowledgeBaseId || !parentId || rechunkFileIds.length === 0) {
|
||||||
|
console.log('轮询条件不满足,退出');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 刷新 Table 组件的数据(仅在 confirmUpload 步骤)
|
// 获取文档列表检查是否全部完成,并刷新表格数据
|
||||||
if (current === 2) {
|
getDocumentList(knowledgeBaseId, {
|
||||||
tableRef.current?.loadData();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 同时获取文档列表检查是否全部完成
|
|
||||||
getDocumentList({
|
|
||||||
kb_id: knowledgeBaseId,
|
|
||||||
parent_id: parentId,
|
|
||||||
document_ids: rechunkFileIds.join(','),
|
document_ids: rechunkFileIds.join(','),
|
||||||
})
|
})
|
||||||
.then((res: any) => {
|
.then((res: any) => {
|
||||||
const documents = res.items || [];
|
const documents = res.items || [];
|
||||||
setData(documents);
|
setData(documents);
|
||||||
|
|
||||||
|
// 只在 confirmUpload 步骤刷新表格数据
|
||||||
|
if (current === 2) {
|
||||||
|
tableRef.current?.loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('documents', documents);
|
||||||
// 检查是否所有文档的 progress 都为 1
|
// 检查是否所有文档的 progress 都为 1
|
||||||
const allCompleted = documents.every((doc: KnowledgeBaseDocumentData) => doc.progress === 1);
|
const allCompleted = documents.every((doc: KnowledgeBaseDocumentData) => doc.progress === 1);
|
||||||
|
|
||||||
console.log('轮询状态:', documents.map((d: KnowledgeBaseDocumentData) => ({ name: d.file_name, progress: d.progress })));
|
console.log('轮询状态:', allCompleted);
|
||||||
|
|
||||||
// 只有在 autoReturn 为 true 且所有文档完成时才自动返回
|
// 检查是否所有文档都完成了
|
||||||
if (allCompleted && autoReturn) {
|
// debugger
|
||||||
// 所有文档处理完成,清除定时器和 loading
|
if (allCompleted) {
|
||||||
|
// 清除定时器和 loading 状态
|
||||||
if (pollingTimerRef.current) {
|
if (pollingTimerRef.current) {
|
||||||
clearInterval(pollingTimerRef.current);
|
clearInterval(pollingTimerRef.current);
|
||||||
pollingTimerRef.current = null;
|
pollingTimerRef.current = null;
|
||||||
}
|
}
|
||||||
setPollingLoading(false);
|
|
||||||
|
|
||||||
// 延迟 2 秒后跳转,让用户看到完成状态
|
// 延迟清除 loading,让用户看到完成状态
|
||||||
console.log('所有文档处理完成,2秒后返回列表页');
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
handleBack();
|
setPollingLoading(false);
|
||||||
}, 2000);
|
}, 1000);
|
||||||
|
|
||||||
|
// 只有在 autoReturn 为 true 时才自动返回
|
||||||
|
if (autoReturn) {
|
||||||
|
// 延迟 2 秒后跳转,让用户看到完成状态
|
||||||
|
console.log('所有文档处理完成,2秒后返回列表页');
|
||||||
|
setTimeout(() => {
|
||||||
|
handleBack();
|
||||||
|
}, 2000);
|
||||||
|
} else {
|
||||||
|
console.log('所有文档处理完成,用户可手动操作');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果还有文档在处理中,确保 loading 状态保持
|
||||||
|
console.log('还有文档在处理中,保持 loading 状态');
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@@ -349,9 +368,7 @@ const CreateDataset = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (initialFileIds.length > 0 && initialStepKey !== 'selectFile' && knowledgeBaseId && parentId) {
|
if (initialFileIds.length > 0 && initialStepKey !== 'selectFile' && knowledgeBaseId && parentId) {
|
||||||
// 加载文档列表数据
|
// 加载文档列表数据
|
||||||
getDocumentList({
|
getDocumentList(knowledgeBaseId,{
|
||||||
kb_id: knowledgeBaseId,
|
|
||||||
parent_id: parentId,
|
|
||||||
document_ids: initialFileIds.join(','),
|
document_ids: initialFileIds.join(','),
|
||||||
})
|
})
|
||||||
.then((res: any) => {
|
.then((res: any) => {
|
||||||
@@ -364,7 +381,7 @@ const CreateDataset = () => {
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// 清理函数:组件卸载时清除定时器
|
// 清理函数:组件卸载时清除定时器和 loading 状态
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
if (pollingTimerRef.current) {
|
if (pollingTimerRef.current) {
|
||||||
@@ -375,6 +392,18 @@ const CreateDataset = () => {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// 监听路由变化,确保在页面切换时清理状态
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
// 页面卸载时清理状态
|
||||||
|
if (pollingTimerRef.current) {
|
||||||
|
clearInterval(pollingTimerRef.current);
|
||||||
|
pollingTimerRef.current = null;
|
||||||
|
}
|
||||||
|
setPollingLoading(false);
|
||||||
|
};
|
||||||
|
}, [location.pathname]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{contextHolder}
|
{contextHolder}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
* @Author: yujiangping
|
* @Author: yujiangping
|
||||||
* @Date: 2025-11-15 16:13:47
|
* @Date: 2025-11-15 16:13:47
|
||||||
* @LastEditors: yujiangping
|
* @LastEditors: yujiangping
|
||||||
* @LastEditTime: 2025-12-12 20:02:05
|
* @LastEditTime: 2025-12-19 20:19:59
|
||||||
*/
|
*/
|
||||||
import { useEffect, useState, useRef, type FC } from 'react';
|
import { useEffect, useState, useRef, type FC } from 'react';
|
||||||
import { useNavigate, useParams, useLocation } from 'react-router-dom';
|
import { useNavigate, useParams, useLocation } from 'react-router-dom';
|
||||||
@@ -47,6 +47,7 @@ const DocumentDetails: FC = () => {
|
|||||||
const [chunkLoading, setChunkLoading] = useState(false);
|
const [chunkLoading, setChunkLoading] = useState(false);
|
||||||
const [keywords, setKeywords] = useState('');
|
const [keywords, setKeywords] = useState('');
|
||||||
const [fileUrl, setFileUrl] = useState('');
|
const [fileUrl, setFileUrl] = useState('');
|
||||||
|
const [parserMode, setParserMode] = useState(0);
|
||||||
const insertModalRef = useRef<InsertModalRef>(null);
|
const insertModalRef = useRef<InsertModalRef>(null);
|
||||||
const isManualRefreshRef = useRef(false);
|
const isManualRefreshRef = useRef(false);
|
||||||
|
|
||||||
@@ -127,6 +128,7 @@ const DocumentDetails: FC = () => {
|
|||||||
setInfoItems(formatDocumentInfo(response));
|
setInfoItems(formatDocumentInfo(response));
|
||||||
const url = `${imagePath}/api/files/${response.file_id}`
|
const url = `${imagePath}/api/files/${response.file_id}`
|
||||||
setFileUrl(url);
|
setFileUrl(url);
|
||||||
|
setParserMode(response?.parser_config?.auto_questions || 0)
|
||||||
// ChunkList 会在 useEffect 中根据 document.progress 自动调用
|
// ChunkList 会在 useEffect 中根据 document.progress 自动调用
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取文档详情失败:', error);
|
console.error('获取文档详情失败:', error);
|
||||||
@@ -388,6 +390,7 @@ const DocumentDetails: FC = () => {
|
|||||||
{t('knowledgeBase.chunkList') || '分块列表'}
|
{t('knowledgeBase.chunkList') || '分块列表'}
|
||||||
</h2>
|
</h2>
|
||||||
<RecallTestResult
|
<RecallTestResult
|
||||||
|
|
||||||
data={chunkList}
|
data={chunkList}
|
||||||
showEmpty={false}
|
showEmpty={false}
|
||||||
hasMore={hasMore}
|
hasMore={hasMore}
|
||||||
@@ -396,6 +399,7 @@ const DocumentDetails: FC = () => {
|
|||||||
scrollableTarget="chunkScrollableDiv"
|
scrollableTarget="chunkScrollableDiv"
|
||||||
editable={true}
|
editable={true}
|
||||||
onItemClick={handleChunkClick}
|
onItemClick={handleChunkClick}
|
||||||
|
parserMode={parserMode}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ const CreateFolderModal = forwardRef<CreateFolderModalRef,CreateFolderModalRefPr
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleOpen = (folder?: FolderFormData | null) => {
|
const handleOpen = (folder?: FolderFormData | null) => {
|
||||||
|
debugger
|
||||||
if (folder) {
|
if (folder) {
|
||||||
setFolder(folder);
|
setFolder(folder);
|
||||||
// 设置表单值
|
// 设置表单值
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ interface RecallTestResultProps {
|
|||||||
scrollableTarget?: string;
|
scrollableTarget?: string;
|
||||||
editable?: boolean; // 是否可编辑
|
editable?: boolean; // 是否可编辑
|
||||||
onItemClick?: (item: RecallTestData, index: number) => void; // 点击项的回调
|
onItemClick?: (item: RecallTestData, index: number) => void; // 点击项的回调
|
||||||
|
parserMode?: number; // 解析模式,1 表示 QA 格式
|
||||||
}
|
}
|
||||||
|
|
||||||
const RecallTestResult = ({
|
const RecallTestResult = ({
|
||||||
@@ -35,9 +36,31 @@ const RecallTestResult = ({
|
|||||||
scrollableTarget,
|
scrollableTarget,
|
||||||
editable = false,
|
editable = false,
|
||||||
onItemClick,
|
onItemClick,
|
||||||
|
parserMode = 0,
|
||||||
}: RecallTestResultProps) => {
|
}: RecallTestResultProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
// 解析 QA 格式内容
|
||||||
|
const parseQAContent = (content: string) => {
|
||||||
|
if (!content || parserMode !== 1) return null;
|
||||||
|
|
||||||
|
const qaRegex = /question:\s*(.*?)\s*answer:\s*(.*?)$/s;
|
||||||
|
const match = content.match(qaRegex);
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
const question = match[1]?.trim() || '';
|
||||||
|
const answer = match[2]?.trim() || '';
|
||||||
|
return { question, answer };
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 格式化 QA 内容为显示格式
|
||||||
|
const formatQAContent = (question: string, answer: string) => {
|
||||||
|
return `**问题:** ${question}\n\n**答案:** ${answer}`;
|
||||||
|
};
|
||||||
|
|
||||||
const handleItemClick = (e: React.MouseEvent, item: RecallTestData, index: number) => {
|
const handleItemClick = (e: React.MouseEvent, item: RecallTestData, index: number) => {
|
||||||
// 检查点击的是否是图片或图片相关元素
|
// 检查点击的是否是图片或图片相关元素
|
||||||
const target = e.target as HTMLElement;
|
const target = e.target as HTMLElement;
|
||||||
@@ -126,7 +149,14 @@ const RecallTestResult = ({
|
|||||||
</div>
|
</div>
|
||||||
<div className='rb:flex rb:text-left rb:px-4 rb:py-3 rb:bg-[#F0F3F8] rb:rounded-lg rb:mt-2'>
|
<div className='rb:flex rb:text-left rb:px-4 rb:py-3 rb:bg-[#F0F3F8] rb:rounded-lg rb:mt-2'>
|
||||||
<div className='rb:text-gray-800 rb:text-sm rb:whitespace-pre-wrap rb:break-words rb:w-full'>
|
<div className='rb:text-gray-800 rb:text-sm rb:whitespace-pre-wrap rb:break-words rb:w-full'>
|
||||||
<RbMarkdown content={item.page_content} showHtmlComments={true} />
|
{(() => {
|
||||||
|
const qaContent = parseQAContent(item.page_content);
|
||||||
|
if (qaContent) {
|
||||||
|
const formattedContent = formatQAContent(qaContent.question, qaContent.answer);
|
||||||
|
return <RbMarkdown content={formattedContent} showHtmlComments={true} />;
|
||||||
|
}
|
||||||
|
return <RbMarkdown content={item.page_content} showHtmlComments={true} />;
|
||||||
|
})()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{item.metadata?.file_created_at && (
|
{item.metadata?.file_created_at && (
|
||||||
|
|||||||
@@ -74,7 +74,8 @@ const KnowledgeBaseManagement: FC = () => {
|
|||||||
const items: NonNullable<MenuProps['items']> = [];
|
const items: NonNullable<MenuProps['items']> = [];
|
||||||
|
|
||||||
// 当权限为 share 时,不显示编辑按钮
|
// 当权限为 share 时,不显示编辑按钮
|
||||||
if (item.permission_id !== 'share') {
|
const permissionId = (item.permission_id || '').toLowerCase();
|
||||||
|
if (permissionId !== 'share') {
|
||||||
items.push({
|
items.push({
|
||||||
key: '1',
|
key: '1',
|
||||||
label: t('knowledgeBase.edit'),
|
label: t('knowledgeBase.edit'),
|
||||||
@@ -131,7 +132,7 @@ const KnowledgeBaseManagement: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 处理创建
|
// 处理创建
|
||||||
const handleCreate = (type?: string) => {
|
const handleCreate = useCallback((type?: string) => {
|
||||||
// 如果在文件夹内,使用 folderPath 的最后一项作为 parent_id
|
// 如果在文件夹内,使用 folderPath 的最后一项作为 parent_id
|
||||||
// 这样更可靠,因为 folderPath 是直接管理的状态
|
// 这样更可靠,因为 folderPath 是直接管理的状态
|
||||||
const currentParentId = folderPath.length > 0
|
const currentParentId = folderPath.length > 0
|
||||||
@@ -142,8 +143,17 @@ const KnowledgeBaseManagement: FC = () => {
|
|||||||
parent_id: currentParentId as string,
|
parent_id: currentParentId as string,
|
||||||
} as KnowledgeBaseListItem : null;
|
} as KnowledgeBaseListItem : null;
|
||||||
|
|
||||||
|
console.log('handleCreate called:', {
|
||||||
|
type,
|
||||||
|
folderPath,
|
||||||
|
folderPathLength: folderPath.length,
|
||||||
|
queryParentId: query.parent_id,
|
||||||
|
currentParentId,
|
||||||
|
record
|
||||||
|
});
|
||||||
|
|
||||||
modalRef?.current?.handleOpen(record, type)
|
modalRef?.current?.handleOpen(record, type)
|
||||||
}
|
}, [folderPath, query.parent_id])
|
||||||
|
|
||||||
// 动态生成 createItems
|
// 动态生成 createItems
|
||||||
const createItems: MenuProps['items'] = useMemo(() => {
|
const createItems: MenuProps['items'] = useMemo(() => {
|
||||||
@@ -155,7 +165,7 @@ const KnowledgeBaseManagement: FC = () => {
|
|||||||
handleCreate(type);
|
handleCreate(type);
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
}, [knowledgeBaseTypes, t]);
|
}, [knowledgeBaseTypes, t, handleCreate]);
|
||||||
const typeToFieldKey = (type: string) => {
|
const typeToFieldKey = (type: string) => {
|
||||||
const normalized = (type || '').toLowerCase();
|
const normalized = (type || '').toLowerCase();
|
||||||
switch (normalized) {
|
switch (normalized) {
|
||||||
@@ -180,7 +190,7 @@ const KnowledgeBaseManagement: FC = () => {
|
|||||||
key,
|
key,
|
||||||
label: t(`knowledgeBase.${key}`),
|
label: t(`knowledgeBase.${key}`),
|
||||||
children: key === 'permission_id'
|
children: key === 'permission_id'
|
||||||
? (data[key] === 'Private' || data[key] === 'private' ? t('knowledgeBase.private') : t('knowledgeBase.share'))
|
? ((data[key] || '').toLowerCase() === 'private' ? t('knowledgeBase.private') : t('knowledgeBase.share'))
|
||||||
: String(data[key] || '-'),
|
: String(data[key] || '-'),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@@ -283,7 +293,15 @@ const KnowledgeBaseManagement: FC = () => {
|
|||||||
const fetchData = async (pageNum: number = 1, isLoadMore: boolean = false) => {
|
const fetchData = async (pageNum: number = 1, isLoadMore: boolean = false) => {
|
||||||
if (!modelTypes.length) return;
|
if (!modelTypes.length) return;
|
||||||
if (loading) return;
|
if (loading) return;
|
||||||
console.log('fetchData called, pageNum:', pageNum, 'isLoadMore:', isLoadMore);
|
|
||||||
|
console.log('fetchData called:', {
|
||||||
|
pageNum,
|
||||||
|
isLoadMore,
|
||||||
|
currentQuery: query,
|
||||||
|
currentFolderPath: folderPath,
|
||||||
|
folderPathLastId: folderPath.length > 0 ? folderPath[folderPath.length - 1].id : 'none'
|
||||||
|
});
|
||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const params = {
|
const params = {
|
||||||
@@ -293,6 +311,8 @@ const KnowledgeBaseManagement: FC = () => {
|
|||||||
orderby:'created_at',
|
orderby:'created_at',
|
||||||
desc:true,
|
desc:true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('API params:', params);
|
||||||
const res = await getKnowledgeBaseList(undefined, params);
|
const res = await getKnowledgeBaseList(undefined, params);
|
||||||
const response = res as KnowledgeBaseListResponse & { items?: KnowledgeBaseListItem[] };
|
const response = res as KnowledgeBaseListResponse & { items?: KnowledgeBaseListItem[] };
|
||||||
console.log('API response:', response);
|
console.log('API response:', response);
|
||||||
@@ -373,10 +393,21 @@ const KnowledgeBaseManagement: FC = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
// 处理跳转详情
|
// 处理跳转详情
|
||||||
const handleToDetail = (knowledgeBase: KnowledgeBaseListItem) => {
|
const handleToDetail = useCallback((knowledgeBase: KnowledgeBaseListItem) => {
|
||||||
|
// 统一处理类型判断,忽略大小写
|
||||||
|
const itemType = (knowledgeBase.type || '').toLowerCase();
|
||||||
|
|
||||||
|
console.log('handleToDetail called with:', {
|
||||||
|
id: knowledgeBase.id,
|
||||||
|
name: knowledgeBase.name,
|
||||||
|
type: itemType,
|
||||||
|
currentFolderPath: folderPath,
|
||||||
|
currentQuery: query
|
||||||
|
});
|
||||||
|
|
||||||
// 如果是 Folder 类型,刷新当前页面,显示该文件夹下的知识库列表
|
// 如果是 Folder 类型,刷新当前页面,显示该文件夹下的知识库列表
|
||||||
if (knowledgeBase.type === 'Folder' || knowledgeBase.type === 'folder') {
|
if (itemType === 'folder') {
|
||||||
// 添加到文件夹路径
|
// 计算新的文件夹路径
|
||||||
const newFolderPath = [
|
const newFolderPath = [
|
||||||
...folderPath,
|
...folderPath,
|
||||||
{
|
{
|
||||||
@@ -384,15 +415,33 @@ const KnowledgeBaseManagement: FC = () => {
|
|||||||
name: knowledgeBase.name,
|
name: knowledgeBase.name,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
setFolderPath(newFolderPath);
|
|
||||||
|
|
||||||
|
console.log('Folder clicked:', {
|
||||||
|
folderId: knowledgeBase.id,
|
||||||
|
folderName: knowledgeBase.name,
|
||||||
|
currentFolderPath: folderPath,
|
||||||
|
newFolderPath: newFolderPath
|
||||||
|
});
|
||||||
|
|
||||||
|
// 同步更新状态,保持与面包屑逻辑一致
|
||||||
|
setFolderPath(newFolderPath);
|
||||||
setQuery((prev) => ({
|
setQuery((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
parent_id: knowledgeBase.id,
|
parent_id: knowledgeBase.id,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 统一处理权限判断,忽略大小写
|
||||||
|
const permissionId = (knowledgeBase.permission_id || '').toLowerCase();
|
||||||
|
const isPrivate = permissionId === 'private';
|
||||||
|
|
||||||
// 根据权限类型跳转到不同的详情页
|
// 根据权限类型跳转到不同的详情页
|
||||||
|
const targetPath = isPrivate
|
||||||
|
? `/knowledge-base/${knowledgeBase.id}/private`
|
||||||
|
: `/knowledge-base/${knowledgeBase.id}/share`;
|
||||||
|
|
||||||
// 跳转时传递当前的文件夹路径信息
|
// 跳转时传递当前的文件夹路径信息
|
||||||
const navigationState = {
|
const navigationState = {
|
||||||
fromKnowledgeBaseList: true,
|
fromKnowledgeBaseList: true,
|
||||||
@@ -400,9 +449,6 @@ const KnowledgeBaseManagement: FC = () => {
|
|||||||
parentId: query.parent_id,
|
parentId: query.parent_id,
|
||||||
timestamp: Date.now(), // 添加时间戳确保每次跳转状态都不同
|
timestamp: Date.now(), // 添加时间戳确保每次跳转状态都不同
|
||||||
};
|
};
|
||||||
const targetPath = knowledgeBase.permission_id === 'Private' || knowledgeBase.permission_id === 'private'
|
|
||||||
? `/knowledge-base/${knowledgeBase.id}/private`
|
|
||||||
: `/knowledge-base/${knowledgeBase.id}/share`;
|
|
||||||
|
|
||||||
// 检查是否是相同路径跳转
|
// 检查是否是相同路径跳转
|
||||||
const currentPath = location.pathname;
|
const currentPath = location.pathname;
|
||||||
@@ -417,7 +463,7 @@ const KnowledgeBaseManagement: FC = () => {
|
|||||||
// 不同路径,正常跳转
|
// 不同路径,正常跳转
|
||||||
navigate(targetPath, { state: navigationState });
|
navigate(targetPath, { state: navigationState });
|
||||||
}
|
}
|
||||||
}
|
}, [folderPath, query, location.pathname, navigate])
|
||||||
// 更新面包屑
|
// 更新面包屑
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
updateBreadcrumbs({
|
updateBreadcrumbs({
|
||||||
|
|||||||
Reference in New Issue
Block a user