| @@ -294,117 +294,47 @@ const PoSearch: React.FC<Props> = ({ | |||||
| if (typeof v === "string" && (v as string).trim() === "") return; | if (typeof v === "string" && (v as string).trim() === "") return; | ||||
| cleanedQuery[k] = String(v); | cleanedQuery[k] = String(v); | ||||
| }); | }); | ||||
| try { | |||||
| const baseListResp = await clientAuthFetch( | |||||
| `${NEXT_PUBLIC_API_URL}/po/list?${new URLSearchParams(cleanedQuery).toString()}`, | |||||
| { method: "GET" }, | |||||
| ); | |||||
| if (!baseListResp.ok) { | |||||
| throw new Error(`PO list fetch failed: ${baseListResp.status}`); | |||||
| } | |||||
| const res = await baseListResp.json(); | |||||
| if (!res) return; | |||||
| const records: PoResult[] = res.records ?? []; | |||||
| const searchedCodeRaw = (filterArgs as any)?.code; | const searchedCodeRaw = (filterArgs as any)?.code; | ||||
| const searchedCode = | const searchedCode = | ||||
| typeof searchedCodeRaw === "string" ? searchedCodeRaw.trim() : ""; | typeof searchedCodeRaw === "string" ? searchedCodeRaw.trim() : ""; | ||||
| const isM18PoCode = | const isM18PoCode = | ||||
| searchedCode.length > 14 && | searchedCode.length > 14 && | ||||
| (searchedCode.startsWith("PP") || searchedCode.startsWith("PF")); | (searchedCode.startsWith("PP") || searchedCode.startsWith("PF")); | ||||
| const hasLocalPending = records.some( | |||||
| (row) => String(row.status ?? "").toLowerCase() === "pending", | |||||
| ); | |||||
| const shouldLookupMissing = records.length === 0 && isM18PoCode; | |||||
| const shouldRefreshPending = hasLocalPending && isM18PoCode; | |||||
| if ( | |||||
| (!shouldLookupMissing && !shouldRefreshPending) || | |||||
| autoSyncInProgressRef.current | |||||
| ) { | |||||
| setFilteredPo(records); | |||||
| setTotalCount(res.total); | |||||
| return; | |||||
| } | |||||
| if (shouldRefreshPending) { | |||||
| setFilteredPo(records); | |||||
| setTotalCount(res.total); | |||||
| if (isM18PoCode) { | |||||
| cleanedQuery.refreshFromM18 = "true"; | |||||
| setIsM18LookupLoading(true); | |||||
| setAutoSyncStatus("載入中..."); | |||||
| } | } | ||||
| try { | try { | ||||
| autoSyncInProgressRef.current = true; | |||||
| setIsM18LookupLoading(shouldLookupMissing); | |||||
| setAutoSyncStatus( | |||||
| shouldLookupMissing | |||||
| ? "正在從M18找尋PO..." | |||||
| : "正在檢查M18是否有更新...", | |||||
| ); | |||||
| const syncResp = await clientAuthFetch( | |||||
| `${NEXT_PUBLIC_API_URL}/m18/test/po-by-code?code=${encodeURIComponent( | |||||
| searchedCode, | |||||
| )}&ifNewer=true`, | |||||
| const baseListResp = await clientAuthFetch( | |||||
| `${NEXT_PUBLIC_API_URL}/po/list?${new URLSearchParams(cleanedQuery).toString()}`, | |||||
| { method: "GET" }, | { method: "GET" }, | ||||
| ); | ); | ||||
| if (!syncResp.ok) { | |||||
| throw new Error(`M18 sync failed: ${syncResp.status}`); | |||||
| } | |||||
| let syncJson: any = null; | |||||
| try { | |||||
| syncJson = await syncResp.json(); | |||||
| } catch { | |||||
| // Some endpoints may respond with plain text | |||||
| const txt = await syncResp.text(); | |||||
| syncJson = { raw: txt }; | |||||
| } | |||||
| const syncOk = Boolean(syncJson?.totalSuccess && syncJson.totalSuccess > 0); | |||||
| const skippedIfNewer = String(syncJson?.query ?? "").includes( | |||||
| "skipped (ifNewer)", | |||||
| ); | |||||
| if (syncOk) { | |||||
| setAutoSyncStatus( | |||||
| shouldLookupMissing ? "成功找到PO" : "已從M18更新PO", | |||||
| ); | |||||
| const listResp = await clientAuthFetch( | |||||
| `${NEXT_PUBLIC_API_URL}/po/list?${new URLSearchParams( | |||||
| cleanedQuery, | |||||
| ).toString()}`, | |||||
| { method: "GET" }, | |||||
| ); | |||||
| if (listResp.ok) { | |||||
| const listJson = await listResp.json(); | |||||
| setFilteredPo(listJson.records ?? []); | |||||
| setTotalCount(listJson.total ?? 0); | |||||
| setAutoSyncStatus( | |||||
| shouldLookupMissing ? "成功找到PO" : "已從M18更新PO", | |||||
| ); | |||||
| return; | |||||
| } | |||||
| setAutoSyncStatus(shouldLookupMissing ? "找不到PO" : null); | |||||
| } else if (skippedIfNewer || shouldRefreshPending) { | |||||
| setAutoSyncStatus(null); | |||||
| } else { | |||||
| setAutoSyncStatus("找不到PO"); | |||||
| if (!baseListResp.ok) { | |||||
| throw new Error(`PO list fetch failed: ${baseListResp.status}`); | |||||
| } | } | ||||
| const res = await baseListResp.json(); | |||||
| if (!res) return; | |||||
| const records: PoResult[] = res.records ?? []; | |||||
| setFilteredPo(records); | setFilteredPo(records); | ||||
| setTotalCount(res.total ?? 0); | setTotalCount(res.total ?? 0); | ||||
| if (isM18PoCode) { | |||||
| const refreshAction = baseListResp.headers.get("X-M18-Po-Refresh"); | |||||
| if (refreshAction === "synced") { | |||||
| setAutoSyncStatus(records.length > 0 ? "已從M18同步PO" : "找不到PO"); | |||||
| } else { | |||||
| setAutoSyncStatus(null); | |||||
| } | |||||
| } | |||||
| } catch (e) { | } catch (e) { | ||||
| console.error("Auto sync error:", e); | |||||
| setAutoSyncStatus(shouldLookupMissing ? "找不到PO" : null); | |||||
| setFilteredPo(records); | |||||
| setTotalCount(res.total ?? 0); | |||||
| console.error("PO list fetch error:", e); | |||||
| if (isM18PoCode) setAutoSyncStatus("找不到PO"); | |||||
| } finally { | } finally { | ||||
| setIsM18LookupLoading(false); | setIsM18LookupLoading(false); | ||||
| autoSyncInProgressRef.current = false; | autoSyncInProgressRef.current = false; | ||||
| } | } | ||||
| } catch (e) { | |||||
| console.error("PO list fetch error:", e); | |||||
| } | |||||
| }, | }, | ||||
| [], | [], | ||||
| ); | ); | ||||
| @@ -501,7 +431,7 @@ const PoSearch: React.FC<Props> = ({ | |||||
| > | > | ||||
| <CircularProgress color="inherit" /> | <CircularProgress color="inherit" /> | ||||
| <Typography variant="body1"> | <Typography variant="body1"> | ||||
| {autoSyncStatus || "正在從M18找尋PO..."} | |||||
| {autoSyncStatus || "載入中..."} | |||||
| </Typography> | </Typography> | ||||
| </Backdrop> | </Backdrop> | ||||
| </> | </> | ||||