2025-04-02 16:14:30 +08:00
|
|
|
|
import { useTusUpload } from "@web/src/hooks/useTusUpload";
|
|
|
|
|
|
import { ShareCodeGenerator } from "../sharecode/sharecodegenerator";
|
|
|
|
|
|
import { ShareCodeValidator } from "../sharecode/sharecodevalidator";
|
2025-04-02 21:59:19 +08:00
|
|
|
|
import { useState, useRef, useCallback, useEffect } from "react";
|
|
|
|
|
|
import { message, Progress, Button, Tabs, DatePicker, Form } from "antd";
|
2025-04-02 16:14:30 +08:00
|
|
|
|
import { UploadOutlined, DeleteOutlined, InboxOutlined } from "@ant-design/icons";
|
|
|
|
|
|
import { env } from '../../../env'
|
2025-04-02 21:59:19 +08:00
|
|
|
|
import { TusUploader } from "@web/src/components/common/uploader/TusUploader";
|
2025-04-02 16:14:30 +08:00
|
|
|
|
const { TabPane } = Tabs;
|
|
|
|
|
|
|
|
|
|
|
|
export default function DeptSettingPage() {
|
|
|
|
|
|
const [uploadedFileId, setUploadedFileId] = useState<string>('');
|
|
|
|
|
|
const [uploadedFileName, setUploadedFileName] = useState<string>('');
|
|
|
|
|
|
const [fileNameMap, setFileNameMap] = useState<Record<string, string>>({});
|
|
|
|
|
|
const [uploadedFiles, setUploadedFiles] = useState<{ id: string, name: string }[]>([]);
|
|
|
|
|
|
const [isDragging, setIsDragging] = useState(false);
|
|
|
|
|
|
const [expireTime, setExpireTime] = useState<Date | null>(null);
|
|
|
|
|
|
const dropRef = useRef<HTMLDivElement>(null);
|
2025-04-02 21:59:19 +08:00
|
|
|
|
const [form] = Form.useForm();
|
|
|
|
|
|
const [currentFile, setCurrentFile] = useState<string[]>([])
|
|
|
|
|
|
const uploadFileId = Form.useWatch(["file"], form)?.[0]
|
2025-04-02 16:14:30 +08:00
|
|
|
|
// 使用您的 useTusUpload hook
|
2025-04-02 21:59:19 +08:00
|
|
|
|
const { uploadProgress, isUploading, uploadError, handleFileUpload } = useTusUpload();
|
2025-04-02 16:14:30 +08:00
|
|
|
|
|
|
|
|
|
|
// 清除已上传文件
|
|
|
|
|
|
const handleClearFile = () => {
|
|
|
|
|
|
setUploadedFileId('');
|
|
|
|
|
|
setUploadedFileName('');
|
|
|
|
|
|
setUploadedFiles([]);
|
|
|
|
|
|
setFileNameMap({});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 处理文件上传
|
|
|
|
|
|
const handleFileSelect = async (file: File) => {
|
|
|
|
|
|
// 限制:如果已有上传文件,则提示用户
|
|
|
|
|
|
if (uploadedFiles.length > 0) {
|
|
|
|
|
|
message.warning('只能上传一个文件,请先删除已上传的文件');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-04-02 21:59:19 +08:00
|
|
|
|
|
2025-04-02 16:14:30 +08:00
|
|
|
|
const fileKey = `file-${Date.now()}`; // 生成唯一的文件标识
|
|
|
|
|
|
|
|
|
|
|
|
handleFileUpload(
|
|
|
|
|
|
file,
|
|
|
|
|
|
async (result) => {
|
|
|
|
|
|
setUploadedFileId(result.fileId);
|
|
|
|
|
|
setUploadedFileName(result.fileName);
|
|
|
|
|
|
|
|
|
|
|
|
// 添加到已上传文件列表
|
|
|
|
|
|
setUploadedFiles([{ id: result.fileId, name: file.name }]);
|
|
|
|
|
|
|
|
|
|
|
|
// 在前端保存文件名映射(用于当前会话)
|
|
|
|
|
|
setFileNameMap({
|
|
|
|
|
|
[result.fileId]: file.name
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 上传成功后保存原始文件名到数据库
|
|
|
|
|
|
try {
|
|
|
|
|
|
console.log('正在保存文件名到数据库:', result.fileName, '对应文件ID:', result.fileId);
|
|
|
|
|
|
|
|
|
|
|
|
const response = await fetch(`http://${env.SERVER_IP}:${env.SERVER_PORT}/upload/filename`, {
|
|
|
|
|
|
method: 'POST',
|
|
|
|
|
|
headers: {
|
|
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
|
|
},
|
|
|
|
|
|
body: JSON.stringify({
|
|
|
|
|
|
fileId: result.fileId,
|
|
|
|
|
|
fileName: file.name
|
|
|
|
|
|
}),
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const responseText = await response.text();
|
|
|
|
|
|
console.log('保存文件名响应:', response.status, responseText);
|
|
|
|
|
|
|
|
|
|
|
|
if (!response.ok) {
|
|
|
|
|
|
console.error('保存文件名失败:', responseText);
|
|
|
|
|
|
message.warning('文件名保存失败,下载时可能无法显示原始文件名');
|
|
|
|
|
|
} else {
|
|
|
|
|
|
console.log('文件名保存成功:', file.name);
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('保存文件名请求失败:', error);
|
|
|
|
|
|
message.warning('文件名保存失败,下载时可能无法显示原始文件名');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
message.success('文件上传成功');
|
|
|
|
|
|
},
|
|
|
|
|
|
(error) => {
|
|
|
|
|
|
message.error('上传失败:' + error.message);
|
|
|
|
|
|
},
|
|
|
|
|
|
fileKey
|
|
|
|
|
|
);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 处理多个文件上传 - 已移除
|
|
|
|
|
|
// const handleFilesUpload = (file: File) => {
|
|
|
|
|
|
// handleFileSelect(file);
|
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
|
|
// 处理文件删除
|
|
|
|
|
|
const handleDeleteFile = async (fileId: string) => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 可以添加删除文件的API调用
|
|
|
|
|
|
// const response = await fetch(`http://${env.SERVER_IP}:${env.SERVER_PORT}/upload/delete/${fileId}`, {
|
|
|
|
|
|
// method: 'DELETE'
|
|
|
|
|
|
// });
|
2025-04-02 21:59:19 +08:00
|
|
|
|
|
2025-04-02 16:14:30 +08:00
|
|
|
|
// if (!response.ok) {
|
|
|
|
|
|
// throw new Error('删除文件失败');
|
|
|
|
|
|
// }
|
2025-04-02 21:59:19 +08:00
|
|
|
|
|
2025-04-02 16:14:30 +08:00
|
|
|
|
// 无论服务器删除是否成功,前端都需要更新状态
|
|
|
|
|
|
setUploadedFiles([]);
|
|
|
|
|
|
setUploadedFileId('');
|
|
|
|
|
|
setUploadedFileName('');
|
|
|
|
|
|
setFileNameMap({});
|
2025-04-02 21:59:19 +08:00
|
|
|
|
|
2025-04-02 16:14:30 +08:00
|
|
|
|
message.success('文件已删除');
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('删除文件错误:', error);
|
|
|
|
|
|
message.error('删除文件失败');
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 拖拽相关处理函数
|
|
|
|
|
|
const handleDragEnter = useCallback((e: React.DragEvent<HTMLDivElement>) => {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
|
setIsDragging(true);
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
const handleDragLeave = useCallback((e: React.DragEvent<HTMLDivElement>) => {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
|
setIsDragging(false);
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
const handleDragOver = useCallback((e: React.DragEvent<HTMLDivElement>) => {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
|
setIsDragging(true);
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
const handleDrop = useCallback((e: React.DragEvent<HTMLDivElement>) => {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
|
setIsDragging(false);
|
|
|
|
|
|
|
|
|
|
|
|
handleFileSelect(e.dataTransfer.files[0]);
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 处理分享码生成成功
|
|
|
|
|
|
const handleShareSuccess = (code: string) => {
|
|
|
|
|
|
message.success('分享码生成成功:' + code);
|
|
|
|
|
|
// 可以在这里添加其他逻辑,比如保存到历史记录
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 处理分享码验证成功
|
|
|
|
|
|
const handleValidSuccess = async (fileId: string, fileName: string) => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 构建下载URL(包含文件名参数)
|
|
|
|
|
|
const downloadUrl = `/upload/download/${fileId}?fileName=${encodeURIComponent(fileName)}`;
|
|
|
|
|
|
const response = await fetch(downloadUrl);
|
|
|
|
|
|
if (!response.ok) {
|
|
|
|
|
|
throw new Error('文件下载失败');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建下载链接
|
|
|
|
|
|
const blob = await response.blob();
|
|
|
|
|
|
const url = window.URL.createObjectURL(blob);
|
|
|
|
|
|
const link = document.createElement('a');
|
|
|
|
|
|
link.href = url;
|
|
|
|
|
|
|
|
|
|
|
|
// 直接使用传入的 fileName
|
|
|
|
|
|
link.download = fileName;
|
|
|
|
|
|
|
|
|
|
|
|
// 触发下载
|
|
|
|
|
|
document.body.appendChild(link);
|
|
|
|
|
|
link.click();
|
|
|
|
|
|
document.body.removeChild(link);
|
|
|
|
|
|
window.URL.revokeObjectURL(url);
|
|
|
|
|
|
|
|
|
|
|
|
message.success('文件下载开始');
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('下载失败:', error);
|
|
|
|
|
|
message.error('文件下载失败');
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div style={{ maxWidth: '800px', margin: '0 auto', padding: '20px' }}>
|
|
|
|
|
|
<span className="text-2xl py-4">文件分享中心</span>
|
|
|
|
|
|
<Tabs defaultActiveKey="upload">
|
|
|
|
|
|
<TabPane tab="上传分享" key="upload">
|
|
|
|
|
|
{/* 文件上传区域 */}
|
|
|
|
|
|
<div style={{ marginBottom: '40px' }}>
|
2025-04-02 21:59:19 +08:00
|
|
|
|
<span className="text-lg block text-zinc-700 py-2">第一步:上传文件</span>
|
2025-04-02 16:14:30 +08:00
|
|
|
|
{/* 如果没有已上传文件,显示上传区域 */}
|
2025-04-02 21:59:19 +08:00
|
|
|
|
<Form form={form}>
|
|
|
|
|
|
<Form.Item name="file">
|
|
|
|
|
|
<TusUploader
|
|
|
|
|
|
multiple={false}
|
|
|
|
|
|
style={"w-full py-4"}
|
|
|
|
|
|
></TusUploader>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
</Form>
|
2025-04-02 16:14:30 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* 生成分享码区域 */}
|
2025-04-02 21:59:19 +08:00
|
|
|
|
<div style={{ marginBottom: '40px' }}>
|
|
|
|
|
|
<span className="text-lg block text-zinc-700 py-4">第二步:生成分享码</span>
|
|
|
|
|
|
<ShareCodeGenerator
|
|
|
|
|
|
fileId={uploadFileId}
|
|
|
|
|
|
onSuccess={handleShareSuccess}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
2025-04-02 16:14:30 +08:00
|
|
|
|
</TabPane>
|
|
|
|
|
|
|
|
|
|
|
|
{/* 使用分享码区域 */}
|
|
|
|
|
|
<TabPane tab="下载文件" key="download">
|
|
|
|
|
|
<div>
|
2025-04-02 21:59:19 +08:00
|
|
|
|
<span className="text-lg block text-zinc-700 py-4">使用分享码下载文件</span>
|
2025-04-02 16:14:30 +08:00
|
|
|
|
<ShareCodeValidator
|
|
|
|
|
|
onValidSuccess={handleValidSuccess}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</TabPane>
|
|
|
|
|
|
</Tabs>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|