diff --git a/src/app/api/do/actions.tsx b/src/app/api/do/actions.tsx index a94c79b..a385dcc 100644 --- a/src/app/api/do/actions.tsx +++ b/src/app/api/do/actions.tsx @@ -107,6 +107,39 @@ export interface BatchReleaseResponse { success: boolean; message?: string } + +export interface getTicketReleaseTable { + id: number; + storeId: string | null; + ticketNo: string | null; + pickOrderId: number | null; + doOrderId: number | null; + pickOrderCode: string | null; + deliveryOrderCode: string | null; + loadingSequence: number | null; + ticketStatus: string | null; + truckId: number | null; + truckDepartureTime: string | null; + shopId: number | null; + handledBy: number | null; + ticketReleaseTime: string | null; + ticketCompleteDateTime: string | null; + truckLanceCode: string | null; + shopCode: string | null; + shopName: string | null; + requiredDeliveryDate: string | null; + handlerName: string | null; +} + +export const fetchTicketReleaseTable = cache(async ()=> { + return await serverFetchJson( + `${BASE_API_URL}/doPickOrder/ticket-release-table`, + { + method: "GET", + } + ); +}); + export const startBatchReleaseAsync = cache(async (data: { ids: number[]; userId: number }) => { const { ids, userId } = data; return await serverFetchJson<{ id: number|null; code: string; entity?: any }>( @@ -217,3 +250,4 @@ export async function printDNLabels(request: PrintDNLabelsRequest){ } + diff --git a/src/components/FinishedGoodSearch/FGPickOrderTicketReleaseTable.tsx b/src/components/FinishedGoodSearch/FGPickOrderTicketReleaseTable.tsx index b63c939..ee04688 100644 --- a/src/components/FinishedGoodSearch/FGPickOrderTicketReleaseTable.tsx +++ b/src/components/FinishedGoodSearch/FGPickOrderTicketReleaseTable.tsx @@ -1,6 +1,6 @@ "use client"; -import React, { useState } from 'react'; +import React, { useState, useEffect, useCallback, useMemo } from 'react'; import { Box, Typography, @@ -11,19 +11,95 @@ import { Card, CardContent, Stack, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + Paper, + CircularProgress, + TablePagination } from '@mui/material'; import { useTranslation } from 'react-i18next'; import dayjs from 'dayjs'; +import { fetchTicketReleaseTable, getTicketReleaseTable } from '@/app/api/do/actions'; const FGPickOrderTicketReleaseTable: React.FC = () => { const { t } = useTranslation("pickOrder"); const [selectedDate, setSelectedDate] = useState("today"); const [selectedFloor, setSelectedFloor] = useState(""); + const [data, setData] = useState([]); + const [loading, setLoading] = useState(true); + const [paginationController, setPaginationController] = useState({ + pageNum: 0, + pageSize: 10, + }); const getDateLabel = (offset: number) => { return dayjs().add(offset, 'day').format('YYYY-MM-DD'); }; + useEffect(() => { + const loadData = async () => { + setLoading(true); + try { + const result = await fetchTicketReleaseTable(); + setData(result); + } catch (error) { + console.error('Error fetching ticket release table:', error); + } finally { + setLoading(false); + } + }; + loadData(); + }, []); + + const filteredData = data.filter((item) => { + // Filter by floor if selected + if (selectedFloor && item.storeId !== selectedFloor) { + return false; + } + + // Filter by date if selected + if (selectedDate && item.requiredDeliveryDate) { + const itemDate = dayjs(item.requiredDeliveryDate).format('YYYY-MM-DD'); + const targetDate = getDateLabel( + selectedDate === "today" ? 0 : selectedDate === "tomorrow" ? 1 : 2 + ); + if (itemDate !== targetDate) { + return false; + } + } + + return true; + },[data, selectedDate, selectedFloor]); + + const handlePageChange = useCallback((event: unknown, newPage: number) => { + setPaginationController(prev => ({ + ...prev, + pageNum: newPage, + })); + }, []); + + const handlePageSizeChange = useCallback((event: React.ChangeEvent) => { + const newPageSize = parseInt(event.target.value, 10); + setPaginationController({ + pageNum: 0, + pageSize: newPageSize, + }); + }, []); + + const paginatedData = useMemo(() => { + const startIndex = paginationController.pageNum * paginationController.pageSize; + const endIndex = startIndex + paginationController.pageSize; + return filteredData.slice(startIndex, endIndex); + }, [filteredData, paginationController]); + + useEffect(() => { + setPaginationController(prev => ({ ...prev, pageNum: 0 })); + }, [selectedDate, selectedFloor]); + return ( @@ -56,9 +132,13 @@ const FGPickOrderTicketReleaseTable: React.FC = () => { - {/* Floor Selection Dropdown */} - - {t("Floor")} + + + {t("Floor")} + - {/* Table content will go here */} - - - {/* Add your table component here */} - Table content goes here... - + + {loading ? ( + + + + ) : ( + <> + + + + + {t("Store ID")} + {t("Required Delivery Date")} + + + + {t("Truck Information")} + + + {t("Departure Time")} / {t("Truck Lane Code")} + + + + {/*{t("Truck Departure Time")} + {t("Truck Lane Code")}*/} + {t("Shop Name")} + {t("Loading Sequence")} + {/*{t("Delivery Order Code(s)")} + {t("Pick Order Code(s)")} + {t("Ticket Number")} + {t("Ticket Release Time")} + {t("Ticket Complete Date Time")} + {t("Ticket Status")}*/} + + + + {t("Ticket Information")} + + + {t("Ticket No.")} ({t("Status")}) / {t("Release Time")} / {t("Complete Time")} + + + + {t("Handler Name")} + {t("Number of FG Items")} + + + + {paginatedData.length === 0 ? ( + + + {t("No data available")} + + + ) : ( + paginatedData.map((row) => { + const isPending = row.ticketStatus?.toLowerCase() === 'pending'; + const showTimes = !isPending && (row.ticketStatus?.toLowerCase() === 'released' || row.ticketStatus?.toLowerCase() === 'completed'); + + return ( + + {row.storeId || '-'} + + {row.requiredDeliveryDate + ? dayjs(row.requiredDeliveryDate).format('YYYY-MM-DD') + : '-'} + + + + + {row.truckDepartureTime && row.truckLanceCode + ? (() => { + let timeStr = row.truckDepartureTime.toString().trim(); + timeStr = timeStr.replace(',', ':'); + const timeMatch = timeStr.match(/^(\d{1,2})[:](\d{2})/); + if (timeMatch) { + const hours = timeMatch[1].padStart(2, '0'); + const minutes = timeMatch[2]; + return `${hours}:${minutes} | ${row.truckLanceCode}`; + } + return `${timeStr} | ${row.truckLanceCode}`; + })() + : row.truckDepartureTime + ? (() => { + let timeStr = row.truckDepartureTime.toString().trim(); + timeStr = timeStr.replace(',', ':'); + const timeMatch = timeStr.match(/^(\d{1,2})[:](\d{2})/); + if (timeMatch) { + const hours = timeMatch[1].padStart(2, '0'); + const minutes = timeMatch[2]; + return `${hours}:${minutes}`; + } + return timeStr; + })() + : row.truckLanceCode || '-'} + + + + {row.shopName || '-'} + {row.loadingSequence || '-'} + {/*{row.deliveryOrderCode || '-'} + {row.pickOrderCode || '-'} + {row.ticketNo || '-'} + + {row.ticketReleaseTime + ? dayjs(row.ticketReleaseTime).format('YYYY-MM-DD HH:mm:ss') + : '-'} + + + {row.ticketCompleteDateTime + ? dayjs(row.ticketCompleteDateTime).format('YYYY-MM-DD HH:mm:ss') + : '-'} + + {row.ticketStatus || '-'}*/} + + + + + {row.ticketNo || '-'} ({row.ticketStatus || '-'}) + + {showTimes && ( + <> + + {row.ticketReleaseTime + ? dayjs(row.ticketReleaseTime, 'YYYYMMDDHHmmss').format('YYYY-MM-DD HH:mm') + : '-'} + + + {row.ticketCompleteDateTime + ? dayjs(row.ticketCompleteDateTime, 'YYYYMMDDHHmmss').format('YYYY-MM-DD HH:mm') + : '-'} + + + )} + + + {row.handlerName || '-'} + - + + ); + }) + )} + +
+
+ {filteredData.length > 0 && ( + + )} + + )}
diff --git a/src/components/FinishedGoodSearch/GoodPickExecutionRecord.tsx b/src/components/FinishedGoodSearch/GoodPickExecutionRecord.tsx index f0e4918..3bd7052 100644 --- a/src/components/FinishedGoodSearch/GoodPickExecutionRecord.tsx +++ b/src/components/FinishedGoodSearch/GoodPickExecutionRecord.tsx @@ -113,7 +113,7 @@ const GoodPickExecutionRecord: React.FC = ({ filterArgs }) => { const handleDN = useCallback(async (doPickOrderId: number) => { const askNumofCarton = await Swal.fire({ - title: t("Enter the number of cartons: "), + title: t("Enter the number of cartons: "), icon: "info", input: "number", inputPlaceholder: t("Number of cartons"),