fix(upload): 恢复并增强Base64前端逻辑,绕过服务器网络访问限制
This commit is contained in:
parent
a2ad9cafde
commit
7964ccd062
@ -1180,7 +1180,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Scripts -->
|
<!-- Scripts -->
|
||||||
<script src="/static/js/main.js?v=4.0"></script>
|
<script src="/static/js/main.js?v=5.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>
|
||||||
|
|||||||
@ -61,7 +61,7 @@ function canDelete() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
console.log("CRM System Main JS v4.5 Loaded - " + new Date().toLocaleString());
|
console.log("CRM System Main JS v5.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")) {
|
||||||
@ -3233,33 +3233,65 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
const files = Array.from(this.files);
|
const files = Array.from(this.files);
|
||||||
if (files.length === 0) return;
|
if (files.length === 0) return;
|
||||||
|
|
||||||
const formData = new FormData();
|
const newBase64Images = [];
|
||||||
files.forEach(file => {
|
|
||||||
if (file.type.startsWith("image/")) {
|
|
||||||
formData.append("screenshots", file);
|
|
||||||
} else {
|
|
||||||
console.warn(`File is not an image: ${file.name}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (formData.getAll("screenshots").length === 0) {
|
// Helper to convert file to base64 with retry
|
||||||
alert("请选择有效的图片文件");
|
const fileToBase64 = async (f, attempt = 1) => {
|
||||||
return;
|
try {
|
||||||
|
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 NotReadableError, retry up to 3 times
|
||||||
|
if (attempt < 3 && (err.name === "NotReadableError" || err.code === 1)) {
|
||||||
|
console.warn(`Retrying ${f.name} read due to error (attempt ${attempt})...`);
|
||||||
|
await new Promise(r => setTimeout(r, 200 * attempt));
|
||||||
|
return fileToBase64(f, attempt + 1);
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
if (!file.type.startsWith("image/")) {
|
||||||
|
console.warn(`File is not an image: ${file.name}`);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log(`[v4.0] Uploading ${files.length} files to server...`);
|
console.log(`[v5.0] Converting ${file.name} (${file.size} bytes)...`);
|
||||||
const response = await authenticatedFetch("/api/upload", {
|
const base64 = await fileToBase64(file);
|
||||||
method: "POST",
|
newBase64Images.push(base64);
|
||||||
body: formData,
|
console.log(`Successfully converted ${file.name}`);
|
||||||
// Note: When sending FormData, the browser automatically sets the correct Content-Type with boundary
|
} catch (error) {
|
||||||
});
|
console.error(`Primary method failed for ${file.name}:`, error);
|
||||||
|
|
||||||
if (response.ok) {
|
// Fallback: arrayBuffer (usually works when FileReader fails)
|
||||||
const result = await response.json();
|
try {
|
||||||
const newBase64Images = result.filePaths || [];
|
console.log(`Trying arrayBuffer fallback for ${file.name}...`);
|
||||||
console.log(`Successfully uploaded ${newBase64Images.length} images`);
|
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 (newBase64Images.length > 0) {
|
||||||
if (type === "create") {
|
if (type === "create") {
|
||||||
createUploadedScreenshots = [
|
createUploadedScreenshots = [
|
||||||
...createUploadedScreenshots,
|
...createUploadedScreenshots,
|
||||||
@ -3273,14 +3305,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
];
|
];
|
||||||
renderScreenshotPreviews("edit", editUploadedScreenshots);
|
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,以便再次选择同一张图片
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user