/** * PKB工作台页面 * 设计要点: * 1. 单层Header - 包含返回、知识库名、Tab切换、设置 * 2. 工作模式紧凑上移 * 3. 对话框最大化空间 */ import React, { useState, useEffect } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import { Table, Button, message, Progress, Dropdown } from 'antd'; import type { MenuProps } from 'antd'; import { MessageSquare, FileText, Database, Settings, ChevronLeft, Trash2, CheckCircle2, Loader2, X, PanelRightOpen, Filter, Plus, BookOpen, FileSearch, Zap, ChevronDown } from 'lucide-react'; import { useKnowledgeBaseStore } from '../stores/useKnowledgeBaseStore'; import { useWorkMode } from '../hooks/useWorkMode'; import { FullTextMode } from '../components/Workspace/FullTextMode'; import { DeepReadMode } from '../components/Workspace/DeepReadMode'; import { BatchModeComplete } from '../components/Workspace/BatchModeComplete'; import '../styles/workspace.css'; interface WorkspacePageProps { standalone?: boolean; } const WorkspacePage: React.FC = ({ standalone = false }) => { const { kbId } = useParams<{ kbId: string }>(); const navigate = useNavigate(); const { currentKb, documents, loading, fetchKnowledgeBaseById, fetchDocuments, deleteDocument, } = useKnowledgeBaseStore(); const { workMode, selectedDocuments, setWorkMode, setSelectedDocuments, } = useWorkMode('full_text'); const [activeTab, setActiveTab] = useState('chat'); const [isPdfOpen, setIsPdfOpen] = useState(false); useEffect(() => { if (kbId) { fetchKnowledgeBaseById(kbId); fetchDocuments(kbId); } }, [kbId]); // 轮询文档处理状态 useEffect(() => { if (!kbId) return; const hasProcessing = documents.some(doc => ['uploading', 'parsing', 'indexing'].includes(doc.status) ); if (!hasProcessing) return; const interval = setInterval(() => { fetchDocuments(kbId); }, 5000); return () => clearInterval(interval); }, [kbId, documents]); // 工作模式配置 const workModeConfig = { full_text: { label: '全文阅读', icon: , color: 'text-blue-600' }, deep_read: { label: '逐篇精读', icon: , color: 'text-purple-600' }, batch: { label: '批处理', icon: , color: 'text-orange-600' }, }; const workModeMenuItems: MenuProps['items'] = [ { key: 'full_text', label: (
全文阅读
加载全部文档,综合问答
), }, { key: 'deep_read', label: (
逐篇精读
选择单篇文档,深度分析
), }, { key: 'batch', label: (
批处理
批量提取,结构化输出
), }, ]; const handleWorkModeChange: MenuProps['onClick'] = ({ key }) => { setWorkMode(key as 'full_text' | 'deep_read' | 'batch'); }; // 逐篇精读的文档选择器 const completedDocs = documents.filter(d => d.status === 'completed'); const docMenuItems: MenuProps['items'] = completedDocs.map(doc => ({ key: doc.id, label: (
{doc.filename}
), })); const handleDocSelect: MenuProps['onClick'] = ({ key }) => { const doc = documents.find(d => d.id === key); if (doc) { setSelectedDocuments([doc]); } }; const getStatusBadge = (status: string) => { const statusMap: Record = { completed: { text: '解析完成', className: 'bg-green-50 text-green-700 border-green-200', icon: }, uploading: { text: 'MinerU 版面分析', className: 'bg-blue-50 text-blue-700 border-blue-200', icon: }, parsing: { text: '结构化提取', className: 'bg-purple-50 text-purple-700 border-purple-200', icon: }, indexing: { text: '向量索引', className: 'bg-orange-50 text-orange-700 border-orange-200', icon: }, error: { text: '解析失败', className: 'bg-red-50 text-red-700 border-red-200' }, }; const config = statusMap[status] || statusMap.completed; return ( {config.icon} {config.text} ); }; const handleDeleteDocument = async (docId: string) => { try { await deleteDocument(docId); message.success('文档删除成功'); } catch (error: any) { message.error(error.message || '删除失败'); } }; if (!currentKb) { return (
); } const containerClass = standalone ? "fixed inset-0 z-50 flex flex-col bg-gray-50" : "flex flex-col h-screen bg-gray-50"; const currentModeConfig = workModeConfig[workMode]; return (
{/* 单层Header - 包含所有导航元素 */}
{/* 左侧:返回 + 知识库名称 */}

{currentKb.name}

{/* 中间:Tab切换(精致胶囊按钮) */}
{/* 右侧:标签 + 设置 + 头像 */}
{currentKb.fileCount || documents.length} 篇文档
DL
{/* 主内容区 */}
{/* 智能问答Tab */} {activeTab === 'chat' && (
{/* 工作模式选择器 - 紧凑设计,只占一行 */}
{/* 逐篇精读时显示文档选择器 */} {workMode === 'deep_read' && ( )}
已加载 {completedDocs.length} / {documents.length} 篇
{/* 聊天区域 - 全屏展开,白色背景 */}
{workMode === 'full_text' && ( )} {workMode === 'deep_read' && ( )} {workMode === 'batch' && ( )}
{/* PDF侧边栏 */} {isPdfOpen && (
PDF预览
)} {/* Toggle按钮 */} {!isPdfOpen && ( )}
)} {/* 知识资产Tab */} {activeTab === 'assets' && (

文档资产管理

管理该知识库下的所有文件,查看 MinerU 解析状态。

{/* 文档表格 */}
(
{text}
), }, { title: '解析状态 (MinerU Pipeline)', dataIndex: 'status', key: 'status', render: (status, record) => (
{getStatusBadge(status)} {status !== 'completed' && status !== 'error' && ( )}
), }, { title: '文件大小', dataIndex: 'fileSizeBytes', key: 'fileSizeBytes', render: (size) => ( {(size / 1024 / 1024).toFixed(1)} MB ), }, { title: 'Tokens', dataIndex: 'tokensCount', key: 'tokensCount', render: (tokens) => ( {tokens ? `${(tokens / 1000).toFixed(0)}k` : '-'} ), }, { title: '上传时间', dataIndex: 'uploadedAt', key: 'uploadedAt', render: (date) => ( {new Date(date).toLocaleString('zh-CN')} ), }, { title: '操作', key: 'action', align: 'right', render: (_, record) => ( ), }, ]} /> )} ); }; export default WorkspacePage;