diff --git a/src/main/java/com/mini/capi/biz/workController.java b/src/main/java/com/mini/capi/biz/workController.java index aa2f230..34d695a 100644 --- a/src/main/java/com/mini/capi/biz/workController.java +++ b/src/main/java/com/mini/capi/biz/workController.java @@ -12,6 +12,7 @@ import com.mini.capi.model.info.TodoHandleDTO; import com.mini.capi.utils.FileUtils; import com.mini.capi.utils.vId; import jakarta.annotation.Resource; +import org.apache.commons.io.FilenameUtils; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -37,7 +38,7 @@ public class workController { @Resource private BizFilesService bizFilesService; - private static String UPLOAD_PATH = "/ogsapp/files/"; + private static final String UPLOAD_PATH = "/ogsapp/files/"; /** @@ -69,7 +70,7 @@ public class workController { /** * 创建文件夹 */ - @PostMapping("/CreateFolder") + @PostMapping("/createFolder") public ApiResult CreateFolder(@Validated @RequestBody CreateFolder request) { try { String dirId = vId.getCid(); @@ -104,6 +105,7 @@ public class workController { try { // 1. 获取原始文件名和后缀 String originalFilename = file.getOriginalFilename(); + String fileType = FilenameUtils.getExtension(originalFilename); String fileSuffix = originalFilename.substring(originalFilename.lastIndexOf(".")); // 2. 生成唯一文件名(避免文件名冲突) String uniqueFileName = vId.getCid() + fileSuffix; @@ -114,7 +116,7 @@ public class workController { bizFiles.setFileName(originalFilename); bizFiles.setFolderId(folderId); bizFiles.setFileSize(file.getSize()); - bizFiles.setFileType(fileSuffix); + bizFiles.setFileType(fileType); bizFiles.setFilePath(filePath.toString()); bizFiles.setCreatorId(0); bizFiles.setIsDeleted(0); diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 05f2bd7..affaa2a 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -6,6 +6,10 @@ server.compression.mime-types=text/html,text/xml,text/plain,text/css,text/javasc server.tomcat.max-connections=200 server.tomcat.threads.max=100 server.tomcat.threads.min-spare=10 +spring.servlet.multipart.enabled=true +spring.servlet.multipart.max-file-size=200MB +spring.servlet.multipart.max-request-size=1000MB +spring.servlet.multipart.file-size-threshold=10MB ## Token security.default-token=3774e79ac55aff6d1afc0f94bfaf131d ## MySQL diff --git a/src/main/resources/templates/file.html b/src/main/resources/templates/file.html index 87cfef5..0bee091 100644 --- a/src/main/resources/templates/file.html +++ b/src/main/resources/templates/file.html @@ -468,7 +468,7 @@ setTimeout(() => { // 实际项目中,这里应该调用后端API创建文件夹 // 例如: - fetch('CreateFolder', { + fetch('createFolder', { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -582,74 +582,118 @@ showMessage('请先选择要上传的文件', 'error'); return; } + + // 前端文件大小校验(和后端max-file-size一致,可选) + const MAX_FILE_SIZE = 200 * 1024 * 1024; // 200MB(字节) + const overSizeFile = uploadFiles.find(file => file.size > MAX_FILE_SIZE); + if (overSizeFile) { + showMessage(`文件 ${overSizeFile.name} 超过 200MB 限制,请压缩后上传`, 'error'); + return; + } + const uploadFolder = document.getElementById('uploadFolder').value; showMessage(`正在上传 ${uploadFiles.length} 个文件...`); - // 禁用上传按钮 const uploadBtn = document.getElementById('startUploadBtn'); uploadBtn.disabled = true; uploadBtn.innerHTML = ' 上传中...'; - // 显示进度条 const progressBars = document.querySelectorAll('.upload-progress'); progressBars.forEach(bar => { bar.classList.remove('hidden'); }); - // 模拟上传进度 - let completedFiles = 0; + let processedFiles = 0; // 统计「已处理完成」的文件数(成功+失败) + let successCount = 0; // 统计成功数 + const failedFiles = []; // 记录失败文件名 + uploadFiles.forEach((file, index) => { - simulateUploadProgress(index, file, () => { - completedFiles++; - // 检查是否所有文件都上传完成 - if (completedFiles === uploadFiles.length) { - setTimeout(() => { - // 启用上传按钮 + uploadSingleFile(file, index, uploadFolder, + // 单个文件处理完成后的回调(无论成功/失败) + (isSuccess) => { + processedFiles++; + if (isSuccess) successCount++; + else failedFiles.push(file.name); + + // 关键:所有文件都处理完成后,再关闭模态框 + if (processedFiles === uploadFiles.length) { uploadBtn.disabled = false; uploadBtn.innerHTML = '开始上传'; - // 实际项目中,这里应该调用后端API上传文件 - // 例如: - const formData = new FormData(); - uploadFiles.forEach(file => { - formData.append('files', file); - }); - formData.append('folderId', uploadFolder); - fetch('uploadFiles', { - method: 'POST', - body: formData, - }) - .then(response => response.json()) - .then(data => { - // 处理上传成功 - closeUploadFileModal(); - // 显示成功消息 - showMessage(`${completedFiles} 个文件上传成功`); - window.location.href = 'dataDoc' - }) - .catch(error => { - // 处理上传失败 - showMessage('上传文件失败', 'error'); - }); - }, 500); + + // 关闭模态框(核心位置:所有文件处理完后) + closeUploadFileModal(); + + // 显示最终结果 + let message = ''; + if (successCount === uploadFiles.length) { + message = `全部 ${successCount} 个文件上传成功`; + window.location.href = 'dataDoc'; // 全部成功才跳转 + } else if (successCount > 0) { + message = `上传完成:成功 ${successCount} 个,失败 ${failedFiles.length} 个(失败:${failedFiles.join('、')})`; + } else { + message = `全部 ${failedFiles.length} 个文件上传失败(${failedFiles.join('、')})`; + } + showMessage(message, failedFiles.length > 0 ? 'error' : 'success'); + } } - }); + ); }); } - // 模拟上传进度 - function simulateUploadProgress(index, file, callback) { + // 单个文件上传(补充回调参数isSuccess,标记是否成功) + function uploadSingleFile(file, index, folderId, callback) { const progressBar = document.querySelectorAll('.upload-progress-bar')[index]; - let progress = 0; + const formData = new FormData(); + formData.append('files', file); + formData.append('folderId', folderId); - const interval = setInterval(() => { - progress += Math.random() * 20; - if (progress >= 100) { - progress = 100; - clearInterval(interval); - setTimeout(callback, 500); + const xhr = new XMLHttpRequest(); + xhr.open('POST', 'uploadFiles', true); + xhr.withCredentials = true; + xhr.timeout = 300000; // 5分钟超时 + + xhr.upload.onprogress = (e) => { + if (e.lengthComputable) { + const progress = (e.loaded / e.total) * 100; + progressBar.style.width = `${progress.toFixed(2)}%`; } - progressBar.style.width = `${progress}%`; - }, 200); + }; + + xhr.onload = () => { + if (xhr.status >= 200 && xhr.status < 300) { + let data; + try { + data = JSON.parse(xhr.responseText); + } catch (err) { + showMessage(`文件 ${file.name} 上传成功,但后端返回格式错误`, 'warning'); + progressBar.style.width = '100%'; + callback(true); // 格式错误仍算上传成功(可根据需求调整) + return; + } + if (data.success) { + progressBar.style.width = '100%'; + callback(true); // 成功:回调传true + } else { + showMessage(`文件 ${file.name} 上传失败:${data.message}`, 'error'); + callback(false); // 失败:回调传false + } + } else { + showMessage(`文件 ${file.name} 上传失败:状态码 ${xhr.status}`, 'error'); + callback(false); + } + }; + + xhr.onerror = () => { + showMessage(`文件 ${file.name} 网络错误`, 'error'); + callback(false); + }; + + xhr.ontimeout = () => { + showMessage(`文件 ${file.name} 上传超时`, 'error'); + callback(false); + }; + + xhr.send(formData); } // 格式化文件大小