fix(upload): 修复服务器环境下图片读取NotReadableError,改由后端接收文件流

This commit is contained in:
hangyu.tao 2026-02-02 10:56:33 +08:00
parent 66e5532139
commit 1134943bb2
2 changed files with 46 additions and 66 deletions

View File

@ -1174,7 +1174,7 @@
</div> </div>
<!-- Scripts --> <!-- Scripts -->
<script src="/static/js/main.js?v=20260130-2222"></script> <script src="/static/js/main.js?v=4.0"></script>
<script src="/static/js/trial-periods.js?v=1.3"></script> <script src="/static/js/trial-periods.js?v=1.3"></script>
<script src="/static/js/trial-periods-page.js?v=1.6"></script> <script src="/static/js/trial-periods-page.js?v=1.6"></script>
</body> </body>

View File

@ -61,7 +61,7 @@ function canDelete() {
} }
document.addEventListener("DOMContentLoaded", function () { document.addEventListener("DOMContentLoaded", function () {
console.log("CRM System Main JS v3.5 Loaded - " + new Date().toLocaleString()); console.log("CRM System Main JS v4.0 Loaded - " + new Date().toLocaleString());
// 登录守卫 // 登录守卫
const token = localStorage.getItem("crmToken"); const token = localStorage.getItem("crmToken");
if (!token && !window.location.pathname.endsWith("login.html")) { if (!token && !window.location.pathname.endsWith("login.html")) {
@ -3240,76 +3240,56 @@ document.addEventListener("DOMContentLoaded", function () {
if (!this.files.length) return; if (!this.files.length) return;
const files = Array.from(this.files); const files = Array.from(this.files);
const newBase64Images = []; if (files.length === 0) return;
for (const file of files) { const formData = new FormData();
// 验证是否为图片 files.forEach(file => {
if (!file.type.startsWith("image/")) { if (file.type.startsWith("image/")) {
formData.append("screenshots", file);
} else {
console.warn(`File is not an image: ${file.name}`); console.warn(`File is not an image: ${file.name}`);
continue;
} }
});
// Helper to convert file to base64 with retry if (formData.getAll("screenshots").length === 0) {
const fileToBase64 = async (f, attempt = 1) => { alert("请选择有效的图片文件");
try { return;
return await new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = () => reject(reader.error || new Error("FileReader error"));
reader.onabort = () => reject(new Error("File read aborted"));
reader.readAsDataURL(f);
});
} catch (err) {
if (attempt < 3 && err.name === "NotReadableError") {
console.warn(`Retrying ${f.name} read due to NotReadableError (attempt ${attempt})...`);
await new Promise(r => setTimeout(r, 200 * attempt));
return fileToBase64(f, attempt + 1);
}
throw err;
}
};
try {
console.log(`[v3.5] Processing ${file.name} (${file.size} bytes)...`);
const base64 = await fileToBase64(file);
newBase64Images.push(base64);
console.log(`Successfully converted ${file.name}`);
} catch (error) {
console.error(`Primary method failed for ${file.name}:`, error);
// Fallback: arrayBuffer
try {
console.log(`Trying arrayBuffer fallback for ${file.name}...`);
const buffer = await file.arrayBuffer();
const bytes = new Uint8Array(buffer);
let binary = "";
const chunkSize = 8192;
for (let i = 0; i < bytes.length; i += chunkSize) {
const chunk = bytes.slice(i, i + chunkSize);
binary += String.fromCharCode.apply(null, chunk);
}
const b64 = `data:${file.type};base64,${btoa(binary)}`;
newBase64Images.push(b64);
console.log(`Fallback successful for ${file.name}`);
} catch (fallbackError) {
console.error(`Both methods failed for ${file.name}:`, fallbackError);
alert(`无法读取文件 "${file.name}"。\n这种情况通常是浏览器或系统文件锁定导致的。\n\n建议尝试:\n1. 刷新页面后再试\n2. 使用浏览器的“无痕模式”\n3. 确认文件没有被其他软件打开`);
}
}
} }
if (type === "create") { try {
createUploadedScreenshots = [ console.log(`[v4.0] Uploading ${files.length} files to server...`);
...createUploadedScreenshots, const response = await authenticatedFetch("/api/upload", {
...newBase64Images, method: "POST",
]; body: formData,
renderScreenshotPreviews("create", createUploadedScreenshots); // Note: When sending FormData, the browser automatically sets the correct Content-Type with boundary
} else { });
editUploadedScreenshots = [
...editUploadedScreenshots, if (response.ok) {
...newBase64Images, const result = await response.json();
]; const newBase64Images = result.filePaths || [];
renderScreenshotPreviews("edit", editUploadedScreenshots); console.log(`Successfully uploaded ${newBase64Images.length} images`);
if (type === "create") {
createUploadedScreenshots = [
...createUploadedScreenshots,
...newBase64Images,
];
renderScreenshotPreviews("create", createUploadedScreenshots);
} else {
editUploadedScreenshots = [
...editUploadedScreenshots,
...newBase64Images,
];
renderScreenshotPreviews("edit", editUploadedScreenshots);
}
} else {
const errorText = await response.text();
console.error("Upload failed:", errorText);
alert("图片上传失败,请稍后重试。");
}
} catch (error) {
console.error("Error during upload:", error);
alert("上传过程出错,可能是浏览器权限问题或网络连接中断。");
} }
// 清除 input以便再次选择同一张图片 // 清除 input以便再次选择同一张图片