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:
248
web/src/hooks/useBreadcrumbManager.ts
Normal file
248
web/src/hooks/useBreadcrumbManager.ts
Normal file
@@ -0,0 +1,248 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useMenu } from '@/store/menu';
|
||||
import type { MenuItem } from '@/store/menu';
|
||||
|
||||
export interface BreadcrumbItem {
|
||||
id: string;
|
||||
name: string;
|
||||
type?: 'knowledgeBase' | 'folder' | 'document';
|
||||
}
|
||||
|
||||
export interface BreadcrumbPath {
|
||||
knowledgeBaseFolderPath: BreadcrumbItem[]; // 知识库文件夹路径
|
||||
knowledgeBase?: BreadcrumbItem; // 知识库信息
|
||||
documentFolderPath: BreadcrumbItem[]; // 文档文件夹路径
|
||||
document?: BreadcrumbItem; // 文档信息
|
||||
}
|
||||
|
||||
export interface BreadcrumbOptions {
|
||||
onKnowledgeBaseMenuClick?: () => void;
|
||||
onKnowledgeBaseFolderClick?: (folderId: string, folderPath: BreadcrumbItem[]) => void;
|
||||
// 新增:区分面包屑类型
|
||||
breadcrumbType?: 'list' | 'detail';
|
||||
}
|
||||
|
||||
export const useBreadcrumbManager = (options?: BreadcrumbOptions) => {
|
||||
const { allBreadcrumbs, setCustomBreadcrumbs } = useMenu();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const updateBreadcrumbs = useCallback((breadcrumbPath: BreadcrumbPath) => {
|
||||
const breadcrumbType = options?.breadcrumbType || 'list';
|
||||
|
||||
// 获取基础面包屑,对于详情页面,使用列表页面的基础面包屑作为起点
|
||||
const baseBreadcrumbs = breadcrumbType === 'list'
|
||||
? (allBreadcrumbs['space'] || [])
|
||||
: (allBreadcrumbs['space'] || []); // 详情页面也从 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();
|
||||
|
||||
if (options?.onKnowledgeBaseMenuClick) {
|
||||
// 如果提供了回调函数,执行回调
|
||||
options.onKnowledgeBaseMenuClick();
|
||||
} else if (breadcrumbType === 'detail') {
|
||||
// 知识库详情页面:没有回调函数时,返回到知识库列表页面
|
||||
navigate('/knowledge-base', {
|
||||
state: {
|
||||
resetToRoot: true,
|
||||
}
|
||||
});
|
||||
}
|
||||
return false;
|
||||
},
|
||||
};
|
||||
}
|
||||
return item;
|
||||
});
|
||||
|
||||
let customBreadcrumbs: MenuItem[] = [...breadcrumbsWithClick];
|
||||
|
||||
if (breadcrumbType === 'list') {
|
||||
// 知识库列表页面:只显示知识库文件夹路径
|
||||
customBreadcrumbs = [
|
||||
...breadcrumbsWithClick,
|
||||
...breadcrumbPath.knowledgeBaseFolderPath.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();
|
||||
|
||||
// 如果有回调函数,直接调用回调函数来更新状态
|
||||
if (options?.onKnowledgeBaseFolderClick) {
|
||||
options.onKnowledgeBaseFolderClick(folder.id, breadcrumbPath.knowledgeBaseFolderPath.slice(0, index + 1));
|
||||
} else {
|
||||
// 否则使用导航(兜底逻辑)
|
||||
navigate('/knowledge-base', {
|
||||
state: {
|
||||
navigateToFolder: folder.id,
|
||||
folderPath: breadcrumbPath.knowledgeBaseFolderPath.slice(0, index + 1)
|
||||
}
|
||||
});
|
||||
}
|
||||
return false;
|
||||
},
|
||||
})),
|
||||
];
|
||||
} else {
|
||||
// 知识库详情页面:显示知识库名称 + 文档文件夹路径 + 文档名称
|
||||
customBreadcrumbs = [
|
||||
...breadcrumbsWithClick,
|
||||
|
||||
// 添加知识库名称
|
||||
...(breadcrumbPath.knowledgeBase ? [{
|
||||
id: 0,
|
||||
parent: 0,
|
||||
code: null,
|
||||
label: breadcrumbPath.knowledgeBase.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 navigationState = {
|
||||
fromKnowledgeBaseList: true,
|
||||
knowledgeBaseFolderPath: breadcrumbPath.knowledgeBaseFolderPath,
|
||||
resetToRoot: true, // 添加重置到根目录的标志
|
||||
refresh: true, // 添加刷新标志
|
||||
timestamp: Date.now(), // 添加时间戳确保状态变化
|
||||
};
|
||||
navigate(`/knowledge-base/${breadcrumbPath.knowledgeBase!.id}/private`, {
|
||||
state: navigationState,
|
||||
replace: true // 使用 replace 避免历史记录堆积
|
||||
});
|
||||
return false;
|
||||
},
|
||||
}] : []),
|
||||
|
||||
// 添加文档文件夹路径
|
||||
...breadcrumbPath.documentFolderPath.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 navigationState = {
|
||||
fromKnowledgeBaseList: true,
|
||||
knowledgeBaseFolderPath: breadcrumbPath.knowledgeBaseFolderPath,
|
||||
navigateToDocumentFolder: folder.id,
|
||||
documentFolderPath: breadcrumbPath.documentFolderPath.slice(0, index + 1),
|
||||
refresh: true, // 添加刷新标志
|
||||
timestamp: Date.now(), // 添加时间戳确保状态变化
|
||||
};
|
||||
navigate(`/knowledge-base/${breadcrumbPath.knowledgeBase!.id}/private`, {
|
||||
state: navigationState,
|
||||
replace: true // 使用 replace 避免历史记录堆积
|
||||
});
|
||||
return false;
|
||||
},
|
||||
})),
|
||||
|
||||
// 添加文档名称(如果存在)
|
||||
...(breadcrumbPath.document ? [{
|
||||
id: 0,
|
||||
parent: 0,
|
||||
code: null,
|
||||
label: breadcrumbPath.document.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: [],
|
||||
// 文档名称不可点击
|
||||
}] : []),
|
||||
];
|
||||
}
|
||||
|
||||
// 根据面包屑类型使用不同的键,实现独立的面包屑路径
|
||||
const breadcrumbKey = breadcrumbType === 'list' ? 'space' : 'space-detail';
|
||||
|
||||
|
||||
|
||||
setCustomBreadcrumbs(customBreadcrumbs, breadcrumbKey);
|
||||
}, [setCustomBreadcrumbs, navigate, options?.breadcrumbType, options?.onKnowledgeBaseMenuClick, options?.onKnowledgeBaseFolderClick]);
|
||||
|
||||
return {
|
||||
updateBreadcrumbs,
|
||||
};
|
||||
};
|
||||
@@ -11,8 +11,10 @@ export const checkAuthStatus = (): boolean => {
|
||||
|
||||
// 递归检查路由是否存在于菜单数据中
|
||||
export const checkRoutePermission = (menus: MenuItem[], currentPath: string): boolean => {
|
||||
// 首页默认有权限
|
||||
if (currentPath === '/' || currentPath.includes('knowledge-detail')) return true;
|
||||
// 首页和知识库相关页面默认有权限
|
||||
if (currentPath === '/' || currentPath.includes('knowledge-detail') || currentPath.includes('knowledge-base')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const menu of menus) {
|
||||
// 检查当前菜单的path是否匹配
|
||||
@@ -26,6 +28,7 @@ export const checkRoutePermission = (menus: MenuItem[], currentPath: string): bo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
@@ -52,7 +55,7 @@ export const useRouteGuard = (source: 'space' | 'manage') => {
|
||||
const hasPermission = checkRoutePermission(menus, location.pathname);
|
||||
if (!hasPermission) {
|
||||
// 无权限访问该路由,重定向到无权限页面
|
||||
// navigate('/not-found', { replace: true });
|
||||
// navigate('/no-permission', { replace: true });
|
||||
}
|
||||
}
|
||||
}, [navigate, location.pathname, location.search, location.hash, menus]);
|
||||
|
||||
Reference in New Issue
Block a user