KnowledgeBase_frontend/src/pages/KnowledgeBase/Detail/components/FileUploadModal.jsx

211 lines
7.0 KiB
React
Raw Normal View History

2025-04-02 10:05:43 +08:00
import React, { useRef, useState, useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { uploadDocument, getKnowledgeBaseById } from '../../../../store/knowledgeBase/knowledgeBase.thunks';
2025-03-07 23:59:53 +08:00
/**
* 文件上传模态框组件
*/
2025-04-02 10:05:43 +08:00
const FileUploadModal = ({ show, knowledgeBaseId, onClose }) => {
const dispatch = useDispatch();
2025-03-07 23:59:53 +08:00
const fileInputRef = useRef(null);
const modalRef = useRef(null);
2025-04-02 10:05:43 +08:00
const [selectedFile, setSelectedFile] = useState(null);
const [isUploading, setIsUploading] = useState(false);
const [fileError, setFileError] = useState('');
// 处理上传区域点击事件
const handleUploadAreaClick = () => {
fileInputRef.current?.click();
};
// 处理拖拽事件
const handleDragOver = (e) => {
e.preventDefault();
e.stopPropagation();
};
const handleDrop = (e) => {
e.preventDefault();
e.stopPropagation();
2025-04-02 10:05:43 +08:00
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();
}
};
// 清理函数
useEffect(() => {
return () => {
// 确保在组件卸载时清理所有引用
if (fileInputRef.current) {
fileInputRef.current.value = '';
}
if (modalRef.current) {
modalRef.current = null;
}
};
}, []);
2025-03-07 23:59:53 +08:00
if (!show) return null;
return (
<div
ref={modalRef}
2025-03-07 23:59:53 +08:00
className='modal-backdrop'
style={{
position: 'fixed',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
zIndex: 1050,
}}
>
<div
className='modal-content bg-white rounded shadow'
style={{
width: '500px',
maxWidth: '90%',
padding: '20px',
}}
>
<div className='modal-header d-flex justify-content-between align-items-center mb-3'>
2025-04-02 10:05:43 +08:00
<h5 className='modal-title m-0'>上传文档</h5>
<button
type='button'
className='btn-close'
onClick={handleClose}
disabled={isUploading}
aria-label='Close'
></button>
2025-03-07 23:59:53 +08:00
</div>
<div className='modal-body'>
<div
className={`mb-3 p-4 border rounded text-center ${
2025-04-02 10:05:43 +08:00
fileError ? 'border-danger' : 'border-dashed'
2025-03-07 23:59:53 +08:00
}`}
2025-04-02 10:05:43 +08:00
style={{ cursor: isUploading ? 'not-allowed' : 'pointer' }}
onClick={!isUploading ? handleUploadAreaClick : undefined}
onDrop={!isUploading ? handleDrop : undefined}
onDragOver={handleDragOver}
2025-03-07 23:59:53 +08:00
>
<input
type='file'
ref={fileInputRef}
className='d-none'
2025-04-02 10:05:43 +08:00
onChange={handleFileChange}
accept='.pdf,.doc,.docx,.txt,.md,.csv,.xlsx,.xls'
disabled={isUploading}
/>
2025-04-02 10:05:43 +08:00
{selectedFile ? (
2025-03-07 23:59:53 +08:00
<div>
<p className='mb-1'>已选择文件</p>
2025-04-02 10:05:43 +08:00
<p className='fw-bold mb-0'>{selectedFile.name}</p>
2025-03-07 23:59:53 +08:00
</div>
) : (
<div>
<p className='mb-1'>点击或拖拽文件到此处上传</p>
2025-04-02 10:05:43 +08:00
<p className='text-muted small mb-0'>
支持 PDF, Word, Excel, TXT, Markdown, CSV 等格式
</p>
2025-03-07 23:59:53 +08:00
</div>
)}
2025-04-02 10:05:43 +08:00
{fileError && <div className='text-danger mt-2'>{fileError}</div>}
2025-03-07 23:59:53 +08:00
</div>
</div>
2025-03-13 09:14:25 +08:00
<div className='modal-footer gap-2'>
2025-04-02 10:05:43 +08:00
<button type='button' className='btn btn-secondary' onClick={handleClose} disabled={isUploading}>
关闭
2025-03-07 23:59:53 +08:00
</button>
<button
type='button'
2025-04-02 10:05:43 +08:00
className='btn btn-primary'
onClick={handleUpload}
disabled={!selectedFile || isUploading}
2025-03-07 23:59:53 +08:00
>
2025-04-02 10:05:43 +08:00
{isUploading ? (
2025-03-07 23:59:53 +08:00
<>
<span
className='spinner-border spinner-border-sm me-2'
role='status'
aria-hidden='true'
></span>
上传中...
</>
) : (
2025-04-02 10:05:43 +08:00
'上传文档'
2025-03-07 23:59:53 +08:00
)}
</button>
</div>
</div>
</div>
);
};
export default FileUploadModal;