fix(P0): 画中画片段类型显示 + OSS上传错误诊断增强
CI/CD Pipeline / Frontend Lint (push) Failing after 23h46m31s
CI/CD Pipeline / Validate Code Quality And Tests (push) Failing after 23h46m31s
CI/CD Pipeline / Production Browser E2E (push) Failing after 1682h20m14s
CI/CD Pipeline / Deploy Production (push) Failing after 1682h20m15s
CI/CD Pipeline / Build Production Runtime Images (push) Failing after 1682h20m17s
CI/CD Pipeline / Build & Push Staging (Watchtower auto-deploy) (push) Failing after 1682h20m17s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 1682h51m43s

P0-2: TimelinePanel 添加 getSegmentTypeLabel,画中画模式显示'画中画1、画中画2'
P0-4: uploadAssetDirect 增加 AbortController 10分钟超时、OSS XML 错误解析、CORS 检测
P0-4: AssetLibrary 上传错误提示改为显示详细信息(err.message)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
xiaoxia
2026-07-08 13:01:58 +08:00
parent efd7bfb6f9
commit ea99fc6e25
2 changed files with 62 additions and 3 deletions
+38 -3
View File
@@ -263,10 +263,14 @@ export const uploadAssetDirect = async (data: {
);
directForm.append("file", data.file);
// 使用 XMLHttpRequest 以获取上传进度(fetch 不支持)
// 使用 XMLHttpRequest 以获取上传进度 + 超时控制 + 详细错误诊断
await new Promise<void>((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open(prepared.method, prepared.upload_url);
// 超时 10 分钟
xhr.timeout = 10 * 60 * 1000;
xhr.upload.onprogress = (e) => {
if (e.lengthComputable && data.onProgress) {
data.onProgress(Math.round((e.loaded / e.total) * 100));
@@ -276,10 +280,41 @@ export const uploadAssetDirect = async (data: {
if (xhr.status >= 200 && xhr.status < 300) {
resolve();
} else {
reject(new Error(`OSS direct upload failed: ${xhr.status}`));
// 解析 OSS 返回的 XML 错误信息
let ossError = "";
try {
const codeMatch = xhr.responseText.match(/<Code>([^<]+)<\/Code>/);
const msgMatch = xhr.responseText.match(/<Message>([^<]+)<\/Message>/);
if (codeMatch || msgMatch) {
ossError = ` [OSS: ${codeMatch?.[1] || "unknown"} - ${msgMatch?.[1] || "unknown"}]`;
}
} catch {
// 无法解析响应体
}
const detail = `OSS 直传失败: HTTP ${xhr.status} ${xhr.statusText}${ossError}`;
console.error("[OSS Upload] 直传失败:", {
url: prepared.upload_url,
storage_key: prepared.storage_key,
status: xhr.status,
statusText: xhr.statusText,
});
reject(new Error(detail));
}
};
xhr.onerror = () => reject(new Error("OSS direct upload failed"));
xhr.onerror = () => {
console.error("[OSS Upload] 网络错误:", {
url: prepared.upload_url,
storage_key: prepared.storage_key,
});
reject(new Error("OSS 上传网络错误,请检查网络连接"));
};
xhr.ontimeout = () => {
console.error("[OSS Upload] 上传超时:", {
url: prepared.upload_url,
storage_key: prepared.storage_key,
});
reject(new Error("OSS 上传超时(10分钟),请检查网络或尝试更小的文件"));
};
xhr.send(directForm);
});
@@ -375,6 +375,30 @@ const AssetLibrary: React.FC = () => {
/* 状态 */
const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());
// 大文件直传(OSS 预签名)
const directUploadMutation = useMutation({
mutationFn: uploadAssetDirect,
onSuccess: () => {
message.success("上传成功");
queryClient.invalidateQueries({ queryKey: ["assets", activeLibrary] });
queryClient.invalidateQueries({ queryKey: ["asset-libraries"] });
},
onError: (err: unknown) => {
if (!(err as { __msgShown?: boolean })?.__msgShown) {
const errMsg = err instanceof Error ? err.message : "上传失败";
// 显示详细错误信息,方便排查 OSS 问题
message.error({
content: errMsg,
duration: 8, // 8秒,让用户能看清错误详情
});
console.error("[AssetLibrary] 大文件上传失败:", {
error: errMsg,
fullError: err,
});
}
},
});
/* 筛选 */
const [searchText, setSearchText] = useState("");
const [filterType, setFilterType] = useState<string>("all");