diff --git a/src/app/api/pickOrder/actions.ts b/src/app/api/pickOrder/actions.ts index 1681785..70ede94 100644 --- a/src/app/api/pickOrder/actions.ts +++ b/src/app/api/pickOrder/actions.ts @@ -267,6 +267,84 @@ export interface AutoAssignReleaseByStoreRequest { userId: number; storeId: string; // "2/F" | "4/F" } +export interface UpdateDoPickOrderHideStatusRequest { + id: number; + name: string; + code: string; + type: string; + message: string; + errorPosition: string; +} +export interface CompletedDoPickOrderResponse { + id: number; + pickOrderId: number; + pickOrderCode: string; + pickOrderConsoCode: string; + pickOrderStatus: string; + deliveryOrderId: number; + deliveryNo: string; + deliveryDate: string; + shopId: number; + shopCode: string; + shopName: string; + shopAddress: string; + ticketNo: string; + shopPoNo: string; + numberOfCartons: number; + truckNo: string; + storeId: string; + completedDate: string; + fgPickOrders: FGPickOrderResponse[]; +} + +// ✅ 新增:搜索参数接口 +export interface CompletedDoPickOrderSearchParams { + pickOrderCode?: string; + shopName?: string; + deliveryNo?: string; + ticketNo?: string; +} + +// ✅ 新增:获取已完成的 DO Pick Orders API +export const fetchCompletedDoPickOrders = async ( + userId: number, + searchParams?: CompletedDoPickOrderSearchParams +): Promise => { + const params = new URLSearchParams(); + + if (searchParams?.pickOrderCode) { + params.append('pickOrderCode', searchParams.pickOrderCode); + } + if (searchParams?.shopName) { + params.append('shopName', searchParams.shopName); + } + if (searchParams?.deliveryNo) { + params.append('deliveryNo', searchParams.deliveryNo); + } + if (searchParams?.ticketNo) { + params.append('ticketNo', searchParams.ticketNo); + } + + const queryString = params.toString(); + const url = `${BASE_API_URL}/pickOrder/completed-do-pick-orders/${userId}${queryString ? `?${queryString}` : ''}`; + + const response = await serverFetchJson(url, { + method: "GET", + }); + + return response; +}; +export const updatePickOrderHideStatus = async (pickOrderId: number, hide: boolean) => { + const response = await serverFetchJson( + `${BASE_API_URL}/pickOrder/update-hide-status/${pickOrderId}?hide=${hide}`, + { + method: "POST", + headers: { "Content-Type": "application/json" }, + }, + ); + revalidateTag("pickorder"); + return response; +}; export const fetchFGPickOrders = async (pickOrderId: number) => { const response = await serverFetchJson( diff --git a/src/components/DoDetail/DoDetail.tsx b/src/components/DoDetail/DoDetail.tsx index a9569b8..e7d70c1 100644 --- a/src/components/DoDetail/DoDetail.tsx +++ b/src/components/DoDetail/DoDetail.tsx @@ -64,7 +64,7 @@ const DoDetail: React.FC = ({ if (response) { formProps.setValue("status", response.entity.status) - setSuccessMessage("DO released successfully! Pick orders created.") + setSuccessMessage(t("DO released successfully! Pick orders created.")) } } } catch (e) { diff --git a/src/components/FinishedGoodSearch/FinishedGoodSearch.tsx b/src/components/FinishedGoodSearch/FinishedGoodSearch.tsx index ca1d3e5..7a01600 100644 --- a/src/components/FinishedGoodSearch/FinishedGoodSearch.tsx +++ b/src/components/FinishedGoodSearch/FinishedGoodSearch.tsx @@ -29,6 +29,7 @@ import Jobcreatitem from "./Jobcreatitem"; import { useSession } from "next-auth/react"; import { SessionWithTokens } from "@/config/authConfig"; import PickExecutionDetail from "./GoodPickExecutiondetail"; +import GoodPickExecutionRecord from "./GoodPickExecutionRecord"; interface Props { pickOrders: PickOrderResult[]; } @@ -53,6 +54,17 @@ const PickOrderSearch: React.FC = ({ pickOrders }) => { const [tabIndex, setTabIndex] = useState(0); const [totalCount, setTotalCount] = useState(); const [isAssigning, setIsAssigning] = useState(false); + const [hideCompletedUntilNext, setHideCompletedUntilNext] = useState( + typeof window !== 'undefined' && localStorage.getItem('hideCompletedUntilNext') === 'true' + ); + useEffect(() => { + const onAssigned = () => { + localStorage.removeItem('hideCompletedUntilNext'); + setHideCompletedUntilNext(false); + }; + window.addEventListener('pickOrderAssigned', onAssigned); + return () => window.removeEventListener('pickOrderAssigned', onAssigned); + }, []); const handleAssignByStore = async (storeId: "2/F" | "4/F") => { if (!currentUserId) { console.error("Missing user id in session"); @@ -326,6 +338,21 @@ const PickOrderSearch: React.FC = ({ pickOrders }) => { {/* ✅ Updated print buttons with completion status */} +{/* + + */} + + {t("Pick Order Details")}: {selectedDoPickOrder.pickOrderCode} + + + + {/* FG Pick Orders 信息 */} + + {selectedDoPickOrder.fgPickOrders.map((fgOrder, index) => ( + {}} // 只读模式 + /> + ))} + + + {/* 类似 GoodPickExecution 的表格 */} + + + + + {t("Pick Order Code")} + {t("Item Code")} + {t("Item Name")} + {t("Lot No")} + {t("Location")} + {t("Required Qty")} + {t("Actual Pick Qty")} + {t("Submitted Status")} + + + + {detailLotData.map((lot, index) => ( + + {lot.pickOrderCode} + {lot.itemCode} + {lot.itemName} + {lot.lotNo} + {lot.location} + {lot.requiredQty} + {lot.actualPickQty} + + + + + ))} + +
+
+ + + ); + } + + // ✅ 默认列表视图 + return ( + + + {/* 搜索框 */} + + + + + {/* 加载状态 */} + {completedDoPickOrdersLoading ? ( + + + + ) : ( + + {/* 结果统计 */} + + {t("Total")}: {filteredDoPickOrders.length} {t("completed DO pick orders")} + + + {/* 列表 */} + {filteredDoPickOrders.length === 0 ? ( + + + {t("No completed DO pick orders found")} + + + ) : ( + + {paginatedData.map((doPickOrder) => ( + + + + + + {doPickOrder.pickOrderCode} + + + {doPickOrder.shopName} - {doPickOrder.deliveryNo} + + + {t("Completed")}: {new Date(doPickOrder.completedDate).toLocaleString()} + + + + + + {doPickOrder.fgPickOrders.length} {t("FG orders")} + + + + + + + + + ))} + + )} + + {/* 分页 */} + {filteredDoPickOrders.length > 0 && ( + + )} + + )} + + + ); +}; + +export default GoodPickExecutionRecord; \ No newline at end of file diff --git a/src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx b/src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx index 828bfa3..db01e9d 100644 --- a/src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx +++ b/src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx @@ -367,6 +367,7 @@ const [isConfirmingLot, setIsConfirmingLot] = useState(false); const [processedQrCodes, setProcessedQrCodes] = useState>(new Set()); const [lastProcessedQr, setLastProcessedQr] = useState(''); const [isRefreshingData, setIsRefreshingData] = useState(false); + const fetchFgPickOrdersData = useCallback(async () => { if (!currentUserId) return; diff --git a/src/i18n/zh/pickOrder.json b/src/i18n/zh/pickOrder.json index eb36441..c78e6c1 100644 --- a/src/i18n/zh/pickOrder.json +++ b/src/i18n/zh/pickOrder.json @@ -274,7 +274,15 @@ "Print Pick Order and DN Label":"列印提料單和送貨單標貼", "Print Pick Order":"列印提料單", "Print DN Label":"列印送貨單標貼", - "If you confirm, the system will:":"如果您確認,系統將:" + "If you confirm, the system will:":"如果您確認,系統將:", + "QR code verified.":"QR 碼驗證成功。", + "Order Finished":"訂單完成", + "Submitted Status":"提交狀態", + "Pick Execution Record":"提料執行記錄", + "Delivery No.":"送貨單編號", + "Total":"總數", + "completed DO pick orders":"已完成送貨單提料單", + "No completed DO pick orders found":"沒有已完成送貨單提料單"