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:
yujiangping
2025-12-16 11:58:37 +08:00
parent 9b8db9a001
commit 1bc06e8204
33 changed files with 996 additions and 370 deletions

View File

@@ -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 (
<>