Sync frontend project from dev-yjp branch
- Updated web folder with latest frontend code - Added new components: CreateContentModal, CreateContentModalExample - Added new hook: useBreadcrumbManager - Updated knowledge base components and views - Updated i18n translations - Various bug fixes and improvements
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import { useEffect, useState, useRef, useMemo, type FC } from 'react';
|
||||
import { useEffect, useState, useRef, useMemo, useCallback, type FC } from 'react';
|
||||
import { Row, Col, Button, Dropdown, Modal, message, Tooltip } from 'antd'
|
||||
import type { MenuProps } from 'antd';
|
||||
import { EllipsisOutlined } from '@ant-design/icons';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useNavigate, useLocation } from 'react-router-dom';
|
||||
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import clsx from 'clsx';
|
||||
@@ -18,7 +18,8 @@ import Empty from '@/components/Empty'
|
||||
import { getKnowledgeBaseList, getModelList, getModelTypeList, deleteKnowledgeBase, getKnowledgeBaseTypeList } from '@/api/knowledgeBase'
|
||||
const { confirm } = Modal;
|
||||
import InfiniteScroll from 'react-infinite-scroll-component';
|
||||
import { useMenu } from '@/store/menu';
|
||||
|
||||
import { useBreadcrumbManager, type BreadcrumbItem } from '@/hooks/useBreadcrumbManager';
|
||||
|
||||
type ModelMenuInfo = {
|
||||
menu: NonNullable<MenuProps['items']>;
|
||||
@@ -28,6 +29,7 @@ type ModelMenuInfo = {
|
||||
const KnowledgeBaseManagement: FC = () => {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [data, setData] = useState<KnowledgeBaseListItem[]>([])
|
||||
const [page, setPage] = useState(1)
|
||||
@@ -42,10 +44,29 @@ const KnowledgeBaseManagement: FC = () => {
|
||||
const modelListCache = useRef<Record<string, string>>({});
|
||||
const modalRef = useRef<CreateModalRef>(null)
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
const processedStateRef = useRef<any>(null);
|
||||
|
||||
// 使用 menu store 管理面包屑
|
||||
const { allBreadcrumbs, setCustomBreadcrumbs } = useMenu();
|
||||
const [folderPath, setFolderPath] = useState<Array<{ id: string; name: string }>>([]);
|
||||
// 使用面包屑管理 Hook
|
||||
const { updateBreadcrumbs } = useBreadcrumbManager({
|
||||
breadcrumbType: 'list',
|
||||
onKnowledgeBaseMenuClick: useCallback(() => {
|
||||
// 返回根目录
|
||||
setFolderPath([]);
|
||||
setQuery((prev) => ({
|
||||
...prev,
|
||||
parent_id: undefined,
|
||||
}));
|
||||
}, []),
|
||||
onKnowledgeBaseFolderClick: useCallback((folderId: string, folderPath: Array<{ id: string; name: string }>) => {
|
||||
// 直接更新文件夹路径和查询状态
|
||||
setFolderPath(folderPath);
|
||||
setQuery((prev) => ({
|
||||
...prev,
|
||||
parent_id: folderId,
|
||||
}));
|
||||
}, [])
|
||||
});
|
||||
const [folderPath, setFolderPath] = useState<BreadcrumbItem[]>([]);
|
||||
|
||||
|
||||
// 生成下拉菜单项(根据当前 item)
|
||||
@@ -134,7 +155,7 @@ const KnowledgeBaseManagement: FC = () => {
|
||||
handleCreate(type);
|
||||
},
|
||||
}));
|
||||
}, [knowledgeBaseTypes, t, folderPath, query]);
|
||||
}, [knowledgeBaseTypes, t]);
|
||||
const typeToFieldKey = (type: string) => {
|
||||
const normalized = (type || '').toLowerCase();
|
||||
switch (normalized) {
|
||||
@@ -371,90 +392,72 @@ const KnowledgeBaseManagement: FC = () => {
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
// 根据权限类型跳转到不同的详情页
|
||||
if (knowledgeBase.permission_id === 'Private' || knowledgeBase.permission_id === 'private') {
|
||||
navigate(`/knowledge-base/${knowledgeBase.id}/private`)
|
||||
// 跳转时传递当前的文件夹路径信息
|
||||
const navigationState = {
|
||||
fromKnowledgeBaseList: true,
|
||||
knowledgeBaseFolderPath: folderPath,
|
||||
parentId: query.parent_id,
|
||||
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;
|
||||
|
||||
if (currentPath === targetPath) {
|
||||
// 如果是相同路径,使用replace并强制刷新状态
|
||||
navigate(targetPath, {
|
||||
state: navigationState,
|
||||
replace: true
|
||||
});
|
||||
} else {
|
||||
navigate(`/knowledge-base/${knowledgeBase.id}/share`)
|
||||
// 不同路径,正常跳转
|
||||
navigate(targetPath, { state: navigationState });
|
||||
}
|
||||
}
|
||||
// 更新面包屑的函数
|
||||
const updateBreadcrumbs = () => {
|
||||
const baseBreadcrumbs = allBreadcrumbs['space'] || [];
|
||||
// 只保留知识库菜单项之前的面包屑
|
||||
const knowledgeBaseMenuIndex = baseBreadcrumbs.findIndex(item => item.path === '/knowledge-base');
|
||||
const filteredBaseBreadcrumbs = knowledgeBaseMenuIndex >= 0
|
||||
? baseBreadcrumbs.slice(0, knowledgeBaseMenuIndex + 1)
|
||||
: baseBreadcrumbs;
|
||||
|
||||
// 给"知识库管理"添加点击事件,返回根目录
|
||||
const breadcrumbsWithClick = filteredBaseBreadcrumbs.map((item) => {
|
||||
if (item.path === '/knowledge-base') {
|
||||
return {
|
||||
...item,
|
||||
onClick: (e?: React.MouseEvent) => {
|
||||
e?.preventDefault();
|
||||
e?.stopPropagation();
|
||||
// 返回根目录
|
||||
setFolderPath([]);
|
||||
setQuery((prev) => ({
|
||||
...prev,
|
||||
parent_id: undefined,
|
||||
}));
|
||||
return false;
|
||||
},
|
||||
};
|
||||
}
|
||||
return item;
|
||||
});
|
||||
|
||||
const customBreadcrumbs = [
|
||||
...breadcrumbsWithClick,
|
||||
...folderPath.map((folder, index) => ({
|
||||
id: 0,
|
||||
parent: 0,
|
||||
code: null,
|
||||
label: folder.name,
|
||||
i18nKey: null,
|
||||
path: null,
|
||||
enable: true,
|
||||
display: true,
|
||||
level: 0,
|
||||
sort: 0,
|
||||
icon: null,
|
||||
iconActive: null,
|
||||
menuDesc: null,
|
||||
deleted: null,
|
||||
updateTime: 0,
|
||||
new_: null,
|
||||
keepAlive: false,
|
||||
master: null,
|
||||
disposable: false,
|
||||
appSystem: null,
|
||||
subs: [],
|
||||
onClick: (e?: React.MouseEvent) => {
|
||||
e?.preventDefault();
|
||||
e?.stopPropagation();
|
||||
// 点击文件夹,回到该文件夹层级
|
||||
const newFolderPath = folderPath.slice(0, index + 1);
|
||||
setFolderPath(newFolderPath);
|
||||
setQuery((prev) => ({
|
||||
...prev,
|
||||
parent_id: folder.id,
|
||||
}));
|
||||
return false;
|
||||
},
|
||||
})),
|
||||
];
|
||||
|
||||
setCustomBreadcrumbs(customBreadcrumbs, 'space');
|
||||
};
|
||||
|
||||
// 更新面包屑
|
||||
useEffect(() => {
|
||||
updateBreadcrumbs();
|
||||
}, [folderPath]);
|
||||
updateBreadcrumbs({
|
||||
knowledgeBaseFolderPath: folderPath,
|
||||
documentFolderPath: [],
|
||||
});
|
||||
}, [folderPath, updateBreadcrumbs]);
|
||||
|
||||
// 处理从详情页返回的导航
|
||||
useEffect(() => {
|
||||
const state = location.state as {
|
||||
navigateToFolder?: string;
|
||||
folderPath?: Array<{ id: string; name: string }>;
|
||||
resetToRoot?: boolean;
|
||||
} | null;
|
||||
|
||||
// 避免重复处理相同的状态
|
||||
if (state && state !== processedStateRef.current) {
|
||||
processedStateRef.current = state;
|
||||
|
||||
if (state.resetToRoot) {
|
||||
// 重置到根目录
|
||||
setFolderPath([]);
|
||||
setQuery((prev) => ({
|
||||
...prev,
|
||||
parent_id: undefined,
|
||||
}));
|
||||
} else if (state?.navigateToFolder && state?.folderPath) {
|
||||
// 恢复文件夹路径和查询状态
|
||||
setFolderPath(state.folderPath);
|
||||
setQuery((prev) => ({
|
||||
...prev,
|
||||
parent_id: state.navigateToFolder,
|
||||
}));
|
||||
}
|
||||
|
||||
// 不清除 state,避免干扰后续导航
|
||||
// 使用 processedStateRef 来避免重复处理相同的 state
|
||||
}
|
||||
}, [location.state, navigate]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchModelTypes();
|
||||
@@ -465,7 +468,7 @@ const KnowledgeBaseManagement: FC = () => {
|
||||
if (modelTypes.length) {
|
||||
fetchData(1, false);
|
||||
}
|
||||
}, [modelTypes, query])
|
||||
}, [modelTypes, query.parent_id, query.keywords, query.orderby, query.desc])
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
Reference in New Issue
Block a user