From 93ed3343decceb44b8a5fd1e3c16bb85ffa31e8d Mon Sep 17 00:00:00 2001 From: hailin Date: Fri, 6 Feb 2026 23:29:37 -0800 Subject: [PATCH] refactor(knowledge): separate file upload into independent entry point MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将知识库的"新建文章"和"上传文件"拆分为两个独立入口: UI 改动: - 移除 Segmented 切换器,"新建文章"弹窗恢复为纯手动输入 - 新增独立的"上传文件"按钮 + 上传弹窗(Upload.Dragger) - 上传提取完成后自动打开"确认提取内容"弹窗,预填标题+内容 - 管理员编辑确认后保存,文章来源标记为 EXTRACT 后端改动: - CreateArticleDto 新增可选 source 字段 - Controller 使用 dto.source || MANUAL(不再硬编码 MANUAL) 流程: - 新建文章 → 手动输入 → source = MANUAL - 上传文件 → 提取文本 → 编辑确认 → source = EXTRACT Co-Authored-By: Claude Opus 4.6 --- .../knowledge/infrastructure/knowledge.api.ts | 1 + .../presentation/pages/KnowledgePage.tsx | 137 ++++++++++-------- .../adapters/inbound/knowledge.controller.ts | 2 +- .../src/application/dtos/knowledge.dto.ts | 1 + 4 files changed, 79 insertions(+), 62 deletions(-) diff --git a/packages/admin-client/src/features/knowledge/infrastructure/knowledge.api.ts b/packages/admin-client/src/features/knowledge/infrastructure/knowledge.api.ts index 23c85a8..61ebde9 100644 --- a/packages/admin-client/src/features/knowledge/infrastructure/knowledge.api.ts +++ b/packages/admin-client/src/features/knowledge/infrastructure/knowledge.api.ts @@ -24,6 +24,7 @@ export interface CreateArticleParams { content: string; category: string; tags?: string[]; + source?: string; } export interface ExtractedTextResponse { diff --git a/packages/admin-client/src/features/knowledge/presentation/pages/KnowledgePage.tsx b/packages/admin-client/src/features/knowledge/presentation/pages/KnowledgePage.tsx index 1706bfe..95163cb 100644 --- a/packages/admin-client/src/features/knowledge/presentation/pages/KnowledgePage.tsx +++ b/packages/admin-client/src/features/knowledge/presentation/pages/KnowledgePage.tsx @@ -13,7 +13,6 @@ import { Typography, Drawer, Upload, - Segmented, message, } from 'antd'; import { @@ -55,10 +54,11 @@ export function KnowledgePage() { const [searchText, setSearchText] = useState(''); const [categoryFilter, setCategoryFilter] = useState(); const [isModalOpen, setIsModalOpen] = useState(false); + const [isUploadModalOpen, setIsUploadModalOpen] = useState(false); const [isDrawerOpen, setIsDrawerOpen] = useState(false); const [selectedArticle, setSelectedArticle] = useState
(null); - const [inputMode, setInputMode] = useState<'manual' | 'upload'>('manual'); const [isExtracting, setIsExtracting] = useState(false); + const [articleSource, setArticleSource] = useState<'MANUAL' | 'EXTRACT'>('MANUAL'); const [form] = Form.useForm(); const { data, isLoading } = useKnowledgeArticles(categoryFilter); @@ -98,10 +98,11 @@ export function KnowledgePage() { } ); } else { - createMutation.mutate(values, { + createMutation.mutate({ ...values, source: articleSource }, { onSuccess: () => { setIsModalOpen(false); form.resetFields(); + setArticleSource('MANUAL'); }, }); } @@ -111,19 +112,24 @@ export function KnowledgePage() { setIsExtracting(true); uploadMutation.mutate(file, { onSuccess: (result) => { + // 关闭上传弹窗,打开文章编辑弹窗(预填提取内容) + setIsUploadModalOpen(false); + setSelectedArticle(null); + setArticleSource('EXTRACT'); + form.resetFields(); form.setFieldsValue({ title: result.suggestedTitle, content: result.extractedText, }); + setIsModalOpen(true); const info = result.pageCount - ? `已提取 ${result.wordCount} 字(${result.pageCount} 页)` - : `已提取 ${result.wordCount} 字`; + ? `已提取 ${result.wordCount} 字(${result.pageCount} 页),请编辑后保存` + : `已提取 ${result.wordCount} 字,请编辑后保存`; message.success(info); - setInputMode('manual'); }, onSettled: () => setIsExtracting(false), }); - return false; // prevent default upload + return false; }; const columns = [ @@ -256,18 +262,26 @@ export function KnowledgePage() { options={CATEGORIES} /> - + + + + + {/* 上传文件弹窗 */} + { + if (!isExtracting) setIsUploadModalOpen(false); + }} + footer={null} + width={520} + > + +

+ +

+

+ {isExtracting ? '正在提取文本...' : '点击或拖拽文件到此区域'} +

+

+ 支持 PDF、Word(.docx)、TXT、Markdown 格式,最大 200MB +

+
+
+ {/* 编辑/新建弹窗 */} { setIsModalOpen(false); setSelectedArticle(null); + setArticleSource('MANUAL'); form.resetFields(); }} footer={null} @@ -316,47 +365,13 @@ export function KnowledgePage() {