From 7079e2f9d0e43f85b853f2c1ddb2994b5c0b1e15 Mon Sep 17 00:00:00 2001 From: "CANCERYS\\kw093" Date: Mon, 27 Apr 2026 17:27:26 +0800 Subject: [PATCH] fix stock take efficient --- src/app/api/stockTake/actions.ts | 17 ++++ .../GoodPickExecutionWorkbenchRecord.tsx | 2 +- .../WorkbenchPickExecution.tsx | 35 ++++---- .../ApproverStockTakeAll.tsx | 82 ++++--------------- 4 files changed, 53 insertions(+), 83 deletions(-) diff --git a/src/app/api/stockTake/actions.ts b/src/app/api/stockTake/actions.ts index d655829..22399d7 100644 --- a/src/app/api/stockTake/actions.ts +++ b/src/app/api/stockTake/actions.ts @@ -394,6 +394,11 @@ export interface BatchSaveApproverStockTakeAllRequest { sectionDescription?: string | null; stockTakeSections?: string | null; // 逗號字串 } +export interface BatchSaveApproverStockTakeByIdsRequest { + stockTakeId: number; + approverId: number; + recordIds: number[]; +} export const saveApproverStockTakeRecord = async ( request: SaveApproverStockTakeRecordRequest, stockTakeId: number @@ -451,6 +456,18 @@ export const batchSaveApproverStockTakeRecordsAll = cache(async (data: BatchSave return r }) +export const batchSaveApproverStockTakeRecordsByIds = cache(async (data: BatchSaveApproverStockTakeByIdsRequest) => { + const r = await serverFetchJson( + `${BASE_API_URL}/stockTakeRecord/batchSaveApproverStockTakeRecordsByIds`, + { + method: "POST", + body: JSON.stringify(data), + headers: { "Content-Type": "application/json" }, + } + ) + return r +}) + export const updateStockTakeRecordStatusToNotMatch = async ( stockTakeRecordId: number ) => { diff --git a/src/components/DoWorkbench/GoodPickExecutionWorkbenchRecord.tsx b/src/components/DoWorkbench/GoodPickExecutionWorkbenchRecord.tsx index 2a8e4b1..d032e16 100644 --- a/src/components/DoWorkbench/GoodPickExecutionWorkbenchRecord.tsx +++ b/src/components/DoWorkbench/GoodPickExecutionWorkbenchRecord.tsx @@ -488,7 +488,7 @@ const GoodPickExecutionWorkbenchRecord: React.FC = ({ criteria={searchCriteria} onSearch={handleSearch} onReset={handleSearchReset} - searchQuery={searchQuery} + // searchQuery={searchQuery} /> = ({ filterArgs }) => { ...(typeof qtyValue === "number" && Number.isFinite(qtyValue) ? { qty: qtyValue } : {}), userId, }); - const errMsg = localizeBackendMessage(res.message, "Scan pick failed"); - setError(errMsg); - setQrScanErrorMsg(errMsg); - + const ok = String(res.code || "").toUpperCase() === "SUCCESS"; + if (!ok) { + const errMsg = localizeBackendMessage(res.message, "Scan pick failed"); + setError(errMsg); + setQrScanErrorMsg(errMsg); + startTransition(() => { + setQrScanError(true); + setQrScanSuccess(false); + }); + return; + } const okMsg = localizeBackendMessage(res.message, "Scan pick success"); setMessage(okMsg); setQrScanSuccessMsg(okMsg); - if (workbenchScanPickResponseNeedsFullRefresh(res)) { - if (selectedPickOrderId != null && selectedPickOrderLineId != null && selectedTopMeta) { - await loadLineDetailV2(selectedPickOrderId, selectedPickOrderLineId, selectedTopMeta); - } - } else { - const entity = res.entity as any; - setLotRows((prev) => - prev.map((r) => - r.stockOutLineId === row.stockOutLineId - ? { ...r, status: toStr(entity?.status || r.status), pickedQty: toNum(entity?.qty, r.pickedQty) } - : r, - ), - ); + startTransition(() => { + setQrScanError(false); + setQrScanSuccess(true); + }); + if (selectedPickOrderId != null && selectedPickOrderLineId != null && selectedTopMeta) { + await loadLineDetailV2(selectedPickOrderId, selectedPickOrderLineId, selectedTopMeta); } setWorkbenchLotLabelModalOpen(false); setWorkbenchLotLabelContextLot(null); diff --git a/src/components/StockTakeManagement/ApproverStockTakeAll.tsx b/src/components/StockTakeManagement/ApproverStockTakeAll.tsx index f34d270..d10f1c4 100644 --- a/src/components/StockTakeManagement/ApproverStockTakeAll.tsx +++ b/src/components/StockTakeManagement/ApproverStockTakeAll.tsx @@ -31,6 +31,7 @@ import { InventoryLotDetailResponse, SaveApproverStockTakeRecordRequest, saveApproverStockTakeRecord, + batchSaveApproverStockTakeRecordsByIds, getApproverInventoryLotDetailsAllPending, getApproverInventoryLotDetailsAllApproved, updateStockTakeRecordStatusToNotMatch, @@ -745,75 +746,32 @@ const ApproverStockTakeAll: React.FC = ({ } setBatchSaving(true); - let successCount = 0; - let skippedApproverEmpty = 0; - let errorCount = 0; try { - for (const detail of sortedDetails) { - if (detail.stockTakeRecordStatus === "completed") { - continue; - } + const recordIds = sortedDetails + .map((d) => d.stockTakeRecordId) + .filter((id): id is number => typeof id === "number" && id > 0); - const built = buildApproverSaveRequest( - detail, - qtySelection, - approverQty, - approverBadQty, - currentUserId, - t - ); - if (!built.ok) { - if (built.reason === "skip_approver_empty") { - skippedApproverEmpty += 1; - continue; - } - errorCount += 1; - continue; - } - - try { - await saveApproverStockTakeRecord(built.request, selectedSession.stockTakeId); - successCount += 1; - const { goodQty, finalQty, finalBadQty, selection } = built; - setInventoryLotDetails((prev) => - prev.map((d) => - d.id === detail.id - ? { - ...d, - finalQty: goodQty, - approverQty: selection === "approver" ? finalQty : d.approverQty, - approverBadQty: selection === "approver" ? finalBadQty : d.approverBadQty, - stockTakeRecordStatus: "completed", - } - : d - ) - ); - } catch (e: any) { - errorCount += 1; - let msg = e?.message || t("Failed to save approver stock take record"); - if (e?.response) { - try { - const errorData = await e.response.json(); - msg = errorData.message || errorData.error || msg; - } catch { - /* ignore */ - } - } - console.error("Batch save row failed", detail.id, msg); - } + if (recordIds.length === 0) { + onSnackbar(t("No valid records to batch save"), "warning"); + return; } + const result = await batchSaveApproverStockTakeRecordsByIds({ + stockTakeId: selectedSession.stockTakeId, + approverId: currentUserId, + recordIds, + }); + onSnackbar( - t("Batch approver save completed: {{success}} success, {{skipped}} skipped, {{errors}} errors", { - success: successCount, - skipped: skippedApproverEmpty, - errors: errorCount, + t("Batch approver save completed: {{success}} success, {{errors}} errors", { + success: result.successCount, + errors: result.errorCount, }), - errorCount > 0 ? "warning" : "success" + result.errorCount > 0 ? "warning" : "success" ); - if (appliedFilters && successCount > 0) { + if (appliedFilters && result.successCount > 0) { await loadDetails(appliedFilters); } } catch (e: any) { @@ -835,10 +793,6 @@ const ApproverStockTakeAll: React.FC = ({ mode, appliedFilters, inventoryLotDetails.length, - sortedDetails, - qtySelection, - approverQty, - approverBadQty, ]); const formatNumber = (num: number | null | undefined): string => {