diff --git a/src/pages/KnowledgeBase/Detail/SettingsTab.jsx b/src/pages/KnowledgeBase/Detail/SettingsTab.jsx
index 98454f6..8dba641 100644
--- a/src/pages/KnowledgeBase/Detail/SettingsTab.jsx
+++ b/src/pages/KnowledgeBase/Detail/SettingsTab.jsx
@@ -13,6 +13,7 @@ import Breadcrumb from './components/Breadcrumb';
import KnowledgeBaseForm from './components/KnowledgeBaseForm';
import DeleteConfirmModal from './components/DeleteConfirmModal';
import UserPermissionsManager from './components/UserPermissionsManager';
+import FileUploadModal from './components/FileUploadModal';
// 部门和组别的映射关系
const departmentGroups = {
@@ -47,6 +48,7 @@ export default function SettingsTab({ knowledgeBase }) {
const [isSubmitting, setIsSubmitting] = useState(false);
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
const [availableGroups, setAvailableGroups] = useState([]);
+ const [showUploadModal, setShowUploadModal] = useState(false);
// 当部门变化时,更新可选的组别
useEffect(() => {
@@ -93,7 +95,7 @@ export default function SettingsTab({ knowledgeBase }) {
allowed = ['admin', 'member', 'private'].includes(value);
} else {
// 普通成员只能选择公共和private
- allowed = ['admin', 'private'].includes(value);
+ allowed = ['admin', 'private'].includes(value);
}
if (!allowed) {
@@ -334,6 +336,26 @@ export default function SettingsTab({ knowledgeBase }) {
availableGroups={availableGroups}
/>
+ {/* Document Upload Section */}
+
+
+
文档管理
+
+ 上传文档到知识库,支持PDF、Word、Excel、TXT、Markdown和CSV等格式。
+
+
+
+
+
+ {/* File Upload Modal */}
+ setShowUploadModal(false)}
+ knowledgeBaseId={knowledgeBase.id}
+ />
+
{/* User Permissions Manager */}
{/* */}
diff --git a/src/pages/KnowledgeBase/Detail/components/FileUploadModal.jsx b/src/pages/KnowledgeBase/Detail/components/FileUploadModal.jsx
index 915f85e..0839ceb 100644
--- a/src/pages/KnowledgeBase/Detail/components/FileUploadModal.jsx
+++ b/src/pages/KnowledgeBase/Detail/components/FileUploadModal.jsx
@@ -1,23 +1,17 @@
-import React, { useRef, useEffect } from 'react';
+import React, { useRef, useState, useEffect } from 'react';
+import { useDispatch } from 'react-redux';
+import { uploadDocument, getKnowledgeBaseById } from '../../../../store/knowledgeBase/knowledgeBase.thunks';
/**
* 文件上传模态框组件
*/
-const FileUploadModal = ({
- show,
- newFile,
- fileErrors,
- isSubmitting,
- onClose,
- onDescriptionChange,
- onFileChange,
- onFileDrop,
- onDragOver,
- onUploadAreaClick,
- onUpload,
-}) => {
+const FileUploadModal = ({ show, knowledgeBaseId, onClose }) => {
+ const dispatch = useDispatch();
const fileInputRef = useRef(null);
const modalRef = useRef(null);
+ const [selectedFile, setSelectedFile] = useState(null);
+ const [isUploading, setIsUploading] = useState(false);
+ const [fileError, setFileError] = useState('');
// 处理上传区域点击事件
const handleUploadAreaClick = () => {
@@ -28,13 +22,76 @@ const FileUploadModal = ({
const handleDragOver = (e) => {
e.preventDefault();
e.stopPropagation();
- onDragOver?.(e);
};
const handleDrop = (e) => {
e.preventDefault();
e.stopPropagation();
- onFileDrop?.(e);
+
+ if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
+ handleFileSelected(e.dataTransfer.files[0]);
+ }
+ };
+
+ const handleFileChange = (e) => {
+ if (e.target.files && e.target.files.length > 0) {
+ handleFileSelected(e.target.files[0]);
+ }
+ };
+
+ const handleFileSelected = (file) => {
+ setFileError('');
+ setSelectedFile(file);
+ };
+
+ const resetFileInput = () => {
+ setSelectedFile(null);
+ setFileError('');
+ if (fileInputRef.current) {
+ fileInputRef.current.value = '';
+ }
+ };
+
+ const handleUpload = async () => {
+ if (!selectedFile) {
+ setFileError('请选择要上传的文件');
+ return;
+ }
+
+ setIsUploading(true);
+
+ try {
+ await dispatch(
+ uploadDocument({
+ knowledge_base_id: knowledgeBaseId,
+ file: selectedFile,
+ })
+ ).unwrap();
+
+ // 成功上传后刷新知识库信息以更新文件列表
+ dispatch(getKnowledgeBaseById(knowledgeBaseId));
+
+ // Reset the file input
+ resetFileInput();
+
+ // 不要在上传成功后关闭模态框,允许用户继续上传或手动关闭
+ } catch (error) {
+ console.error('Upload failed:', error);
+ setFileError('文件上传失败: ' + (error?.message || '未知错误'));
+
+ // 清空选中的文件
+ resetFileInput();
+ } finally {
+ setIsUploading(false);
+ }
+ };
+
+ const handleClose = () => {
+ // 只有在非上传状态才允许关闭
+ if (!isUploading) {
+ resetFileInput();
+ onClose();
+ }
};
// 清理函数
@@ -78,64 +135,60 @@ const FileUploadModal = ({
}}
>
-
上传文件
-
+ 上传文档
+
- {newFile.file ? (
+ {selectedFile ? (
已选择文件:
-
{newFile.file.name}
+
{selectedFile.name}
) : (
点击或拖拽文件到此处上传
-
支持 PDF, DOCX, TXT, CSV 等格式
+
+ 支持 PDF, Word, Excel, TXT, Markdown, CSV 等格式
+
)}
- {fileErrors.file &&
{fileErrors.file}
}
-
-
-
-
+ {fileError &&
{fileError}
}
-
diff --git a/src/services/mockApi.js b/src/services/mockApi.js
index 46c9355..5c758da 100644
--- a/src/services/mockApi.js
+++ b/src/services/mockApi.js
@@ -674,7 +674,7 @@ export const mockGet = async (url, config = {}) => {
throw { response: { status: 404, data: { message: 'Not found' } } };
};
-export const mockPost = async (url, data) => {
+export const mockPost = async (url, data, isMultipart = false) => {
console.log(`[MOCK API] POST ${url}`, data);
// Simulate network delay
@@ -857,6 +857,26 @@ export const mockPost = async (url, data) => {
};
}
+ // 上传知识库文档
+ if (url.match(/\/knowledge-bases\/([^/]+)\/upload_document\//)) {
+ const knowledge_base_id = url.match(/\/knowledge-bases\/([^/]+)\/upload_document\//)[1];
+ const file = isMultipart ? data.get('file') : null;
+
+ return {
+ data: {
+ code: 200,
+ message: 'Document uploaded successfully',
+ data: {
+ id: `doc-${Date.now()}`,
+ knowledge_base_id: knowledge_base_id,
+ filename: file ? file.name : 'mock-document.pdf',
+ status: 'processing',
+ created_at: new Date().toISOString(),
+ },
+ },
+ };
+ }
+
throw { response: { status: 404, data: { message: 'Not found' } } };
};
diff --git a/src/store/knowledgeBase/knowledgeBase.slice.js b/src/store/knowledgeBase/knowledgeBase.slice.js
index c95515c..65defd3 100644
--- a/src/store/knowledgeBase/knowledgeBase.slice.js
+++ b/src/store/knowledgeBase/knowledgeBase.slice.js
@@ -8,6 +8,7 @@ import {
searchKnowledgeBases,
requestKnowledgeBaseAccess,
getKnowledgeBaseById,
+ uploadDocument,
} from './knowledgeBase.thunks';
const initialState = {
@@ -27,6 +28,7 @@ const initialState = {
batchLoading: false,
editStatus: 'idle',
requestAccessStatus: 'idle',
+ uploadStatus: 'idle',
};
const knowledgeBaseSlice = createSlice({
@@ -180,6 +182,18 @@ const knowledgeBaseSlice = createSlice({
.addCase(getKnowledgeBaseById.rejected, (state, action) => {
state.loading = false;
state.error = action.payload || 'Failed to get knowledge base details';
+ })
+
+ // 上传文档
+ .addCase(uploadDocument.pending, (state) => {
+ state.uploadStatus = 'loading';
+ })
+ .addCase(uploadDocument.fulfilled, (state) => {
+ state.uploadStatus = 'successful';
+ })
+ .addCase(uploadDocument.rejected, (state, action) => {
+ state.uploadStatus = 'failed';
+ state.error = action.payload || 'Failed to upload document';
});
},
});
diff --git a/src/store/knowledgeBase/knowledgeBase.thunks.js b/src/store/knowledgeBase/knowledgeBase.thunks.js
index 187af7f..663f68c 100644
--- a/src/store/knowledgeBase/knowledgeBase.thunks.js
+++ b/src/store/knowledgeBase/knowledgeBase.thunks.js
@@ -1,5 +1,5 @@
import { createAsyncThunk } from '@reduxjs/toolkit';
-import { get, post, put, del } from '../../services/api';
+import { get, post, put, del, upload } from '../../services/api';
import { showNotification } from '../notification.slice';
/**
@@ -20,7 +20,7 @@ export const fetchKnowledgeBases = createAsyncThunk(
return response.data;
} catch (error) {
console.log(error);
-
+
return rejectWithValue(error.response?.data.error.message || 'Failed to fetch knowledge bases');
}
}
@@ -196,3 +196,44 @@ export const requestKnowledgeBaseAccess = createAsyncThunk(
}
}
);
+
+/**
+ * Upload a document to a knowledge base
+ * @param {Object} params - Upload parameters
+ * @param {string} params.knowledge_base_id - Knowledge base ID
+ * @param {File} params.file - File to upload
+ */
+export const uploadDocument = createAsyncThunk(
+ 'knowledgeBase/uploadDocument',
+ async ({ knowledge_base_id, file }, { rejectWithValue, dispatch }) => {
+ try {
+ const formData = new FormData();
+ formData.append('file', file);
+
+ const response = await post(`/knowledge-bases/${knowledge_base_id}/upload_document/`, formData, true);
+
+ dispatch(
+ showNotification({
+ type: 'success',
+ message: `文档 ${file.name} 上传成功`,
+ })
+ );
+
+ // 处理新的返回格式
+ if (response.data && response.data.code === 200) {
+ return response.data.data;
+ }
+
+ return response.data;
+ } catch (error) {
+ const errorMessage = error.response?.data?.message || error.message || '文档上传失败';
+ dispatch(
+ showNotification({
+ type: 'danger',
+ message: errorMessage,
+ })
+ );
+ return rejectWithValue(errorMessage);
+ }
+ }
+);