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

211 lines
7.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useRef, useState, useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { uploadDocument, getKnowledgeBaseDocuments } from '../../../../store/knowledgeBase/knowledgeBase.thunks';
/**
* 文件上传模态框组件
*/
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 = () => {
fileInputRef.current?.click();
};
// 处理拖拽事件
const handleDragOver = (e) => {
e.preventDefault();
e.stopPropagation();
};
const handleDrop = (e) => {
e.preventDefault();
e.stopPropagation();
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(getKnowledgeBaseDocuments({ knowledge_base_id: 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;
}
};
}, []);
if (!show) return null;
return (
<div
ref={modalRef}
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'>
<h5 className='modal-title m-0'>上传文档</h5>
<button
type='button'
className='btn-close'
onClick={handleClose}
disabled={isUploading}
aria-label='Close'
></button>
</div>
<div className='modal-body'>
<div
className={`mb-3 p-4 border rounded text-center ${
fileError ? 'border-danger' : 'border-dashed'
}`}
style={{ cursor: isUploading ? 'not-allowed' : 'pointer' }}
onClick={!isUploading ? handleUploadAreaClick : undefined}
onDrop={!isUploading ? handleDrop : undefined}
onDragOver={handleDragOver}
>
<input
type='file'
ref={fileInputRef}
className='d-none'
onChange={handleFileChange}
accept='.pdf,.doc,.docx,.txt,.md,.csv,.xlsx,.xls'
disabled={isUploading}
/>
{selectedFile ? (
<div>
<p className='mb-1'>已选择文件</p>
<p className='fw-bold mb-0'>{selectedFile.name}</p>
</div>
) : (
<div>
<p className='mb-1'>点击或拖拽文件到此处上传</p>
<p className='text-muted small mb-0'>
支持 PDF, Word, Excel, TXT, Markdown, CSV 等格式
</p>
</div>
)}
{fileError && <div className='text-danger mt-2'>{fileError}</div>}
</div>
</div>
<div className='modal-footer gap-2'>
<button type='button' className='btn btn-secondary' onClick={handleClose} disabled={isUploading}>
关闭
</button>
<button
type='button'
className='btn btn-primary'
onClick={handleUpload}
disabled={!selectedFile || isUploading}
>
{isUploading ? (
<>
<span
className='spinner-border spinner-border-sm me-2'
role='status'
aria-hidden='true'
></span>
上传中...
</>
) : (
'上传文档'
)}
</button>
</div>
</div>
</div>
);
};
export default FileUploadModal;