|
|
|
@@ -33,6 +33,29 @@ export interface OnPackQrDownloadRequest { |
|
|
|
}[]; |
|
|
|
} |
|
|
|
|
|
|
|
/** Readable message when ZIP download returns non-OK (plain text, JSON error body, or generic). */ |
|
|
|
async function zipDownloadError(res: Response): Promise<Error> { |
|
|
|
const text = await res.text(); |
|
|
|
const ct = res.headers.get("content-type") ?? ""; |
|
|
|
if (ct.includes("application/json")) { |
|
|
|
try { |
|
|
|
const j = JSON.parse(text) as { message?: string; error?: string }; |
|
|
|
if (typeof j.message === "string" && j.message.length > 0) { |
|
|
|
return new Error(j.message); |
|
|
|
} |
|
|
|
if (typeof j.error === "string" && j.error.length > 0) { |
|
|
|
return new Error(j.error); |
|
|
|
} |
|
|
|
} catch { |
|
|
|
/* ignore parse */ |
|
|
|
} |
|
|
|
} |
|
|
|
if (text && text.length > 0 && text.length < 800 && !text.trim().startsWith("{")) { |
|
|
|
return new Error(text); |
|
|
|
} |
|
|
|
return new Error(`下載失敗(HTTP ${res.status})。請查看後端日誌或確認資料庫已執行 Liquibase 更新。`); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Fetch job orders by plan date from GET /py/job-orders. |
|
|
|
* Client-side only; uses auth token from localStorage. |
|
|
|
@@ -75,7 +98,7 @@ export async function downloadOnPackQrZip( |
|
|
|
}); |
|
|
|
|
|
|
|
if (!res.ok) { |
|
|
|
throw new Error((await res.text()) || "Download failed"); |
|
|
|
throw await zipDownloadError(res); |
|
|
|
} |
|
|
|
|
|
|
|
return res.blob(); |
|
|
|
@@ -93,7 +116,7 @@ export async function downloadOnPackTextQrZip( |
|
|
|
}); |
|
|
|
|
|
|
|
if (!res.ok) { |
|
|
|
throw new Error((await res.text()) || "Download failed"); |
|
|
|
throw await zipDownloadError(res); |
|
|
|
} |
|
|
|
|
|
|
|
return res.blob(); |
|
|
|
|