Files
AIclinicalresearch/docs/05-每日进度/Day21-知识库管理前端完成.md
AI Clinical Dev Team 239c7ea85e feat: Day 21-22 - knowledge base frontend completed, fix CORS and file upload issues
- Complete knowledge base list and detail pages
- Complete document upload component
- Fix CORS config (add PUT/DELETE method support)
- Fix file upload issues (disabled state and beforeUpload return value)
- Add detailed debug logs (cleaned up)
- Create Day 21-22 completion summary document
2025-10-11 15:40:12 +08:00

16 KiB
Raw Blame History

Day 21 - 知识库管理前端开发完成

完成时间: 2025年10月11日
提交记录: feat(frontend): Day 21 knowledge base management frontend completed


📋 任务概览

完成知识库管理的前端开发,包括:

  1. 前端API服务封装
  2. Zustand状态管理
  3. 知识库列表组件
  4. 创建/编辑知识库对话框
  5. 文档上传组件
  6. 文档列表组件
  7. 主页面集成
  8. 前端编译测试通过

🎨 前端架构

1. API服务层 (knowledgeBaseApi.ts)

类型定义

export interface KnowledgeBase {
  id: string;
  userId: string;
  name: string;
  description?: string;
  difyDatasetId: string;
  fileCount: number;
  totalSizeBytes: number;
  createdAt: string;
  updatedAt: string;
  _count?: { documents: number };
}

export interface Document {
  id: string;
  kbId: string;
  filename: string;
  fileType: string;
  fileSizeBytes: number;
  status: 'uploading' | 'parsing' | 'indexing' | 'completed' | 'error';
  progress: number;
  errorMessage?: string;
  segmentsCount?: number;
  tokensCount?: number;
  uploadedAt: string;
  processedAt?: string;
}

API方法

// 知识库管理
knowledgeBaseApi.getList()          // 获取列表
knowledgeBaseApi.getById(id)        // 获取详情
knowledgeBaseApi.create(data)       // 创建
knowledgeBaseApi.update(id, data)   // 更新
knowledgeBaseApi.delete(id)         // 删除
knowledgeBaseApi.getStats(id)       // 统计信息
knowledgeBaseApi.search(id, query)  // 检索RAG

// 文档管理
documentApi.getList(kbId)           // 获取列表
documentApi.upload(kbId, file)      // 上传
documentApi.delete(id)              // 删除
documentApi.reprocess(id)           // 重新处理

2. 状态管理 (useKnowledgeBaseStore.ts)

Zustand Store

interface KnowledgeBaseState {
  // 数据状态
  knowledgeBases: KnowledgeBase[];
  currentKb: KnowledgeBase | null;
  documents: Document[];
  loading: boolean;
  error: string | null;
  
  // 知识库操作
  fetchKnowledgeBases: () => Promise<void>;
  fetchKnowledgeBaseById: (id: string) => Promise<void>;
  createKnowledgeBase: (name, description?) => Promise<KnowledgeBase>;
  updateKnowledgeBase: (id, name?, description?) => Promise<void>;
  deleteKnowledgeBase: (id: string) => Promise<void>;
  
  // 文档操作
  fetchDocuments: (kbId: string) => Promise<void>;
  uploadDocument: (kbId, file, onProgress?) => Promise<Document>;
  deleteDocument: (id: string) => Promise<void>;
  reprocessDocument: (id: string) => Promise<void>;
}

特点

  • 集中式状态管理
  • 自动错误处理
  • Loading状态管理
  • 操作后自动刷新

🧩 核心组件

1. KnowledgeBaseList知识库列表

功能

  • 卡片式展示3列网格布局
  • 配额显示(已使用 X/3 个)
  • 文档数量、总大小、创建时间
  • 编辑/删除操作
  • 空状态提示
  • 配额上限禁用创建按钮

UI特点

// 卡片式布局
<Card hoverable onClick={onSelectClick}>
  <Card.Meta
    avatar={<FolderIcon />}
    title={kb.name}
    description={
      - 描述(省略显示)
      - 文档数量
      - 总大小
      - 创建时间
    }
  />
  <Actions>
    - 编辑按钮
    - 删除按钮(带确认)
  </Actions>
</Card>

2. CreateKBDialog创建对话框

功能

  • 表单验证(名称必填、长度限制)
  • 描述字段(可选、字数统计)
  • 配额提示信息
  • Loading状态
  • 错误提示

验证规则

- 名称:必填、最多50
- 描述:选填、最多200

提示信息

📌 提示
• 每个用户最多创建 3 个知识库
• 每个知识库最多上传 50 个文档
• 支持的文件格式PDF、DOC、DOCX、TXT、MD
• 单个文件最大10MB

3. EditKBDialog编辑对话框

功能

  • 自动填充现有数据
  • 表单验证
  • 更新成功提示
  • 错误处理

4. DocumentUpload文档上传

功能

  • 拖拽上传
  • 点击上传
  • 文件类型验证(前端)
  • 文件大小验证10MB
  • 上传进度显示
  • 配额检查50个/知识库)
  • 实时进度条

验证逻辑

const beforeUpload = (file: File) => {
  // 检查数量限制
  if (currentDocumentCount >= 50) {
    message.error('已达到文档数量上限50个');
    return Upload.LIST_IGNORE;
  }
  
  // 检查文件类型
  const allowedTypes = ['application/pdf', 'application/msword', ...];
  if (!allowedTypes.includes(file.type)) {
    message.error('不支持的文件类型');
    return Upload.LIST_IGNORE;
  }
  
  // 检查文件大小10MB
  if (file.size > 10 * 1024 * 1024) {
    message.error('文件大小不能超过 10MB');
    return Upload.LIST_IGNORE;
  }
  
  return false; // 手动上传
};

上传流程

customRequest = async (options) => {
  1. 调用 useKnowledgeBaseStore.uploadDocument()
  2. 显示上传进度(0-100%
  3. 上传完成后通知父组件刷新
  4. 显示成功/失败消息
}

5. DocumentList文档列表

功能

  • 表格展示
  • 状态图标(上传中、解析中、索引中、已就绪、失败)
  • 进度显示
  • 文件大小格式化
  • Token数、段落数显示
  • 删除操作(带确认)
  • 重试按钮(失败状态)
  • 分页
  • 空状态

状态图标

const statusConfig = {
  uploading:  { color: 'blue',       icon: <LoadingOutlined />, text: '上传中' },
  parsing:    { color: 'processing', icon: <ClockCircleOutlined />, text: '解析中' },
  indexing:   { color: 'processing', icon: <ClockCircleOutlined />, text: '索引中' },
  completed:  { color: 'success',    icon: <CheckCircleOutlined />, text: '已就绪' },
  error:      { color: 'error',      icon: <CloseCircleOutlined />, text: '失败' },
};

进度显示

  • 处理中进度条0-100%
  • 已完成显示段落数和Token数
  • 失败显示错误提示Tooltip

6. KnowledgePage主页面

双视图架构

视图1知识库列表

<KnowledgeBaseList
  knowledgeBases={knowledgeBases}
  onCreateClick={() => setCreateDialogOpen(true)}
  onEditClick={handleEdit}
  onDeleteClick={handleDelete}
  onSelectClick={handleSelectKb}  // 切换到详情视图
/>

<CreateKBDialog />
<EditKBDialog />

视图2知识库详情

<返回按钮 onClick={handleBackToList} />

<Card>
  <知识库名称和描述>
  <编辑按钮>
</Card>

<Tabs>
  <TabPane key="documents">
    <DocumentUpload />
    <DocumentList />
  </TabPane>
  
  <TabPane key="stats">
    <统计卡片网格>
      - 总文档数
      - 已就绪数
      - 处理中数
      - 失败数
      - Token数
      - 总段落数
    </统计卡片网格>
  </TabPane>
</Tabs>

实时状态轮询

useEffect(() => {
  if (!currentKb) return;
  
  // 检查是否有处理中的文档
  const hasProcessing = documents.some(doc => 
    ['uploading', 'parsing', 'indexing'].includes(doc.status)
  );
  
  if (!hasProcessing) return;
  
  // 每5秒轮询一次
  const interval = setInterval(() => {
    fetchDocuments(currentKb.id);
  }, 5000);
  
  return () => clearInterval(interval);
}, [currentKb, documents]);

🎯 核心功能实现

1. 配额管理

知识库配额3个/用户)

// 前端检查
const canCreateMore = knowledgeBases.length < 3;

<Button
  disabled={!canCreateMore}
  onClick={onCreateClick}
>
  创建知识库
</Button>

// 后端验证
if (user.kbUsed >= user.kbQuota) {
  throw new Error('Knowledge base quota exceeded');
}

文档配额50个/知识库)

// 前端检查
const isAtLimit = currentDocumentCount >= 50;

<Upload
  disabled={isAtLimit}
  beforeUpload={(file) => {
    if (isAtLimit) {
      message.error('已达到文档数量上限50个');
      return Upload.LIST_IGNORE;
    }
  }}
/>

// 后端验证
const documentCount = await prisma.document.count({ where: { kbId } });
if (documentCount >= 50) {
  throw new Error('Document limit exceeded');
}

2. 文件验证

前端验证

const allowedTypes = [
  'application/pdf',
  'application/msword',
  'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  'text/plain',
  'text/markdown',
];

const allowedExtensions = ['.pdf', '.doc', '.docx', '.txt', '.md'];

// 类型检查
if (!allowedTypes.includes(file.type) && 
    !allowedExtensions.some(ext => file.name.endsWith(ext))) {
  message.error('不支持的文件类型');
  return Upload.LIST_IGNORE;
}

// 大小检查
if (file.size > 10 * 1024 * 1024) {
  message.error('文件大小不能超过 10MB');
  return Upload.LIST_IGNORE;
}

后端验证

// Controller层
const allowedTypes = [
  'application/pdf',
  'application/msword',
  'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  'text/plain',
  'text/markdown',
];

if (!allowedTypes.includes(fileType)) {
  return reply.status(400).send({
    success: false,
    message: 'File type not supported',
  });
}

if (fileSizeBytes > 10 * 1024 * 1024) {
  return reply.status(400).send({
    success: false,
    message: 'File size exceeds 10MB limit',
  });
}

3. 状态追踪

文档处理状态流

uploading → parsing → indexing → completed
                              ↘ error

前端轮询

// 每5秒检查一次处理中的文档
const interval = setInterval(() => {
  if (hasProcessingDocs) {
    fetchDocuments(currentKb.id);
  }
}, 5000);

后端轮询

// Service层上传后自动轮询Dify状态
async function pollDocumentStatus(userId, kbId, documentId, difyDocumentId) {
  for (let i = 0; i < 30; i++) {
    await new Promise(resolve => setTimeout(resolve, 2000));
    
    const difyDocument = await difyClient.getDocument(
      knowledgeBase.difyDatasetId,
      difyDocumentId
    );
    
    await prisma.document.update({
      where: { id: documentId },
      data: {
        status: difyDocument.indexing_status,
        progress: calculateProgress(difyDocument),
        segmentsCount: difyDocument.word_count,
        tokensCount: difyDocument.tokens,
      },
    });
    
    if (difyDocument.indexing_status === 'completed') break;
    if (difyDocument.indexing_status === 'error') break;
  }
}

4. 错误处理

统一错误处理

// Store层
try {
  await operation();
} catch (error: any) {
  const errorMsg = error.response?.data?.message || '操作失败';
  set({ error: errorMsg, loading: false });
  throw new Error(errorMsg);
}

// 组件层
useEffect(() => {
  if (error) {
    message.error(error);
    clearError();
  }
}, [error]);

// 操作层
const handleDelete = async (kb: KnowledgeBase) => {
  try {
    await deleteKnowledgeBase(kb.id);
    message.success('知识库删除成功');
  } catch (error: any) {
    message.error(error.message || '删除失败');
  }
};

📊 UI/UX设计

1. 响应式布局

知识库列表

display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: 16px;

统计信息

display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 16px;

2. 交互反馈

Loading状态

  • 按钮 loading 属性
  • 列表 loading 属性
  • 上传进度条
  • Spin加载指示器

成功/失败提示

message.success('操作成功');
message.error('操作失败');
message.warning('已达到上限');

确认对话框

<Popconfirm
  title="确认删除?"
  description="删除知识库将同时删除其中的所有文档,此操作不可恢复。"
  onConfirm={onDelete}
  okText="确认"
  cancelText="取消"
  okButtonProps={{ danger: true }}
>
  <Button danger>删除</Button>
</Popconfirm>

3. 状态可视化

状态图标

  • 🔵 上传中Loading图标 + 蓝色)
  • 🟡 解析中/索引中Clock图标 + 黄色)
  • 🟢 已就绪CheckCircle图标 + 绿色)
  • 🔴 失败CloseCircle图标 + 红色)

进度显示

  • 处理中:<Progress percent={progress} status="active" />
  • 已完成:段落数 | Token数
  • 失败:处理失败带错误详情Tooltip

测试验证

编译测试

cd D:\MyCursor\AIclinicalresearch\frontend
npm run build

✅ TypeScript编译通过0错误
✅ Vite构建成功
✅ 产物大小1.98MBgzip: 656.82KB

代码质量

  • TypeScript类型安全
  • ESLint检查通过
  • 组件化设计
  • 状态管理规范
  • 错误处理完善

📦 新增文件

frontend/src/
├── api/
│   └── knowledgeBaseApi.ts          # API服务270行
├── stores/
│   └── useKnowledgeBaseStore.ts     # 状态管理180行
├── components/knowledge/
│   ├── KnowledgeBaseList.tsx        # 知识库列表205行
│   ├── CreateKBDialog.tsx           # 创建对话框95行
│   ├── EditKBDialog.tsx             # 编辑对话框85行
│   ├── DocumentUpload.tsx           # 文档上传145行
│   └── DocumentList.tsx             # 文档列表220行
└── pages/
    └── KnowledgePage.tsx             # 主页面281行

总计8个文件约1481行代码


🎯 功能清单

知识库管理

  • 创建知识库(带表单验证)
  • 编辑知识库(名称、描述)
  • 删除知识库(带确认、级联删除)
  • 查看知识库列表(卡片式)
  • 查看知识库详情(文档列表、统计)
  • 配额管理3个/用户)

文档管理

  • 上传文档(拖拽/点击)
  • 删除文档(带确认)
  • 重新处理文档(失败时)
  • 查看文档列表(表格式)
  • 状态追踪5种状态
  • 进度显示(实时更新)
  • 配额管理50个/知识库)

文件验证

  • 类型验证PDF、DOC、DOCX、TXT、MD
  • 大小验证10MB上限
  • 数量验证50个上限
  • 前端预检查
  • 后端二次验证

实时更新

  • 状态轮询每5秒
  • 上传进度0-100%
  • 自动刷新(操作后)
  • 错误提示(实时)

UI/UX

  • 响应式布局
  • Loading状态
  • 成功/失败提示
  • 确认对话框
  • 空状态提示
  • 状态图标
  • 进度条
  • Tooltip提示

🚀 后续优化建议

1. 性能优化

  • 虚拟滚动(大量文档时)
  • 懒加载图片/文件预览
  • 分页加载优化
  • 代码分割(动态导入)

2. 功能增强

  • 文件预览功能
  • 批量上传
  • 批量删除
  • 导入/导出知识库
  • 知识库搜索
  • 文档内容搜索
  • 标签管理
  • 文档分类

3. 用户体验

  • 上传队列管理
  • 断点续传
  • 拖拽排序
  • 键盘快捷键
  • 暗黑模式
  • 移动端适配

💡 技术亮点

  1. 组件化设计8个独立组件职责清晰易于维护
  2. 状态管理Zustand集中管理操作简洁
  3. 类型安全完整的TypeScript类型定义
  4. 错误处理三层错误处理API → Store → Component
  5. 实时更新:智能轮询,只在需要时启动
  6. 用户体验:丰富的交互反馈,操作流畅
  7. 配额管理:前后端双重验证,防止滥用
  8. 文件验证:多重验证机制,保证数据质量

📝 提交信息

git commit -m "feat(frontend): Day 21 knowledge base management frontend completed"

9 files changed, 1466 insertions(+)
 create mode 100644 frontend/src/api/knowledgeBaseApi.ts
 create mode 100644 frontend/src/components/knowledge/CreateKBDialog.tsx
 create mode 100644 frontend/src/components/knowledge/DocumentList.tsx
 create mode 100644 frontend/src/components/knowledge/DocumentUpload.tsx
 create mode 100644 frontend/src/components/knowledge/EditKBDialog.tsx
 create mode 100644 frontend/src/components/knowledge/KnowledgeBaseList.tsx
 create mode 100644 frontend/src/stores/useKnowledgeBaseStore.ts
 rewrite frontend/src/pages/AgentChatPage.tsx
 rewrite frontend/src/pages/KnowledgePage.tsx

总结Day 21成功完成知识库管理的前端开发所有组件功能完整编译测试通过为用户提供了流畅的知识库管理体验🎉