CANCERYS\kw093 1 month ago
parent
commit
e83a2e7cc2
3 changed files with 280 additions and 13 deletions
  1. +34
    -0
      src/app/api/do/actions.tsx
  2. +245
    -12
      src/components/FinishedGoodSearch/FGPickOrderTicketReleaseTable.tsx
  3. +1
    -1
      src/components/FinishedGoodSearch/GoodPickExecutionRecord.tsx

+ 34
- 0
src/app/api/do/actions.tsx View File

@@ -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<getTicketReleaseTable[]>(
`${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){
}




+ 245
- 12
src/components/FinishedGoodSearch/FGPickOrderTicketReleaseTable.tsx View File

@@ -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<string>("today");
const [selectedFloor, setSelectedFloor] = useState<string>("");
const [data, setData] = useState<getTicketReleaseTable[]>([]);
const [loading, setLoading] = useState<boolean>(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<HTMLInputElement>) => {
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 (
<Card sx={{ mb: 2 }}>
<CardContent>
@@ -56,9 +132,13 @@ const FGPickOrderTicketReleaseTable: React.FC = () => {
</Select>
</FormControl>

{/* Floor Selection Dropdown */}
<FormControl sx={{ minWidth: 150 }} size="small">
<InputLabel id="floor-select-label">{t("Floor")}</InputLabel>
<FormControl sx={{ minWidth: 150 }} size="small">
<InputLabel
id="floor-select-label"
shrink={true}
>
{t("Floor")}
</InputLabel>
<Select
labelId="floor-select-label"
id="floor-select"
@@ -70,18 +150,171 @@ const FGPickOrderTicketReleaseTable: React.FC = () => {
<MenuItem value="">
<em>{t("All Floors")}</em>
</MenuItem>
<MenuItem value="2F">2/F</MenuItem>
<MenuItem value="4F">4/F</MenuItem>
<MenuItem value="2/F">2/F</MenuItem>
<MenuItem value="4/F">4/F</MenuItem>
</Select>
</FormControl>
</Stack>

{/* Table content will go here */}
<Box sx={{ mt: 2 }}>
<Typography variant="body2" color="text.secondary">
{/* Add your table component here */}
Table content goes here...
</Typography>
<Box sx={{ mt: 2 }}>
{loading ? (
<Box sx={{ display: 'flex', justifyContent: 'center', p: 3 }}>
<CircularProgress />
</Box>
) : (
<>
<TableContainer component={Paper}>
<Table size="small" sx={{ minWidth: 650 }}>
<TableHead>
<TableRow>
<TableCell>{t("Store ID")}</TableCell>
<TableCell>{t("Required Delivery Date")}</TableCell>
<TableCell>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.5 }}>
<Typography variant="subtitle2" sx={{ fontWeight: 600 }}>
{t("Truck Information")}
</Typography>
<Typography variant="caption" sx={{ color: 'text.secondary' }}>
{t("Departure Time")} / {t("Truck Lane Code")}
</Typography>
</Box>
</TableCell>
{/*<TableCell>{t("Truck Departure Time")}</TableCell>
<TableCell>{t("Truck Lane Code")}</TableCell>*/}
<TableCell>{t("Shop Name")}</TableCell>
<TableCell>{t("Loading Sequence")}</TableCell>
{/*<TableCell>{t("Delivery Order Code(s)")}</TableCell>
<TableCell>{t("Pick Order Code(s)")}</TableCell>
<TableCell>{t("Ticket Number")}</TableCell>
<TableCell>{t("Ticket Release Time")}</TableCell>
<TableCell>{t("Ticket Complete Date Time")}</TableCell>
<TableCell>{t("Ticket Status")}</TableCell>*/}
<TableCell>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.5 }}>
<Typography variant="subtitle2" sx={{ fontWeight: 600 }}>
{t("Ticket Information")}
</Typography>
<Typography variant="caption" sx={{ color: 'text.secondary' }}>
{t("Ticket No.")} ({t("Status")}) / {t("Release Time")} / {t("Complete Time")}
</Typography>
</Box>
</TableCell>
<TableCell>{t("Handler Name")}</TableCell>
<TableCell>{t("Number of FG Items")}</TableCell>
</TableRow>
</TableHead>
<TableBody>
{paginatedData.length === 0 ? (
<TableRow>
<TableCell colSpan={12} align="center">
{t("No data available")}
</TableCell>
</TableRow>
) : (
paginatedData.map((row) => {
const isPending = row.ticketStatus?.toLowerCase() === 'pending';
const showTimes = !isPending && (row.ticketStatus?.toLowerCase() === 'released' || row.ticketStatus?.toLowerCase() === 'completed');
return (
<TableRow key={row.id}>
<TableCell>{row.storeId || '-'}</TableCell>
<TableCell>
{row.requiredDeliveryDate
? dayjs(row.requiredDeliveryDate).format('YYYY-MM-DD')
: '-'}
</TableCell>

<TableCell>
<Typography variant="body2">
{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 || '-'}
</Typography>
</TableCell>

<TableCell>{row.shopName || '-'}</TableCell>
<TableCell>{row.loadingSequence || '-'}</TableCell>
{/*<TableCell>{row.deliveryOrderCode || '-'}</TableCell>
<TableCell>{row.pickOrderCode || '-'}</TableCell>
<TableCell>{row.ticketNo || '-'}</TableCell>
<TableCell>
{row.ticketReleaseTime
? dayjs(row.ticketReleaseTime).format('YYYY-MM-DD HH:mm:ss')
: '-'}
</TableCell>
<TableCell>
{row.ticketCompleteDateTime
? dayjs(row.ticketCompleteDateTime).format('YYYY-MM-DD HH:mm:ss')
: '-'}
</TableCell>
<TableCell>{row.ticketStatus || '-'}</TableCell>*/}

<TableCell>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.5 }}>
<Typography variant="body2">
{row.ticketNo || '-'} ({row.ticketStatus || '-'})
</Typography>
{showTimes && (
<>
<Typography variant="body2">
{row.ticketReleaseTime
? dayjs(row.ticketReleaseTime, 'YYYYMMDDHHmmss').format('YYYY-MM-DD HH:mm')
: '-'}
</Typography>
<Typography variant="body2">
{row.ticketCompleteDateTime
? dayjs(row.ticketCompleteDateTime, 'YYYYMMDDHHmmss').format('YYYY-MM-DD HH:mm')
: '-'}
</Typography>
</>
)}
</Box>
</TableCell>
<TableCell>{row.handlerName || '-'}</TableCell>
<TableCell>-</TableCell>
</TableRow>
);
})
)}
</TableBody>
</Table>
</TableContainer>
{filteredData.length > 0 && (
<TablePagination
component="div"
count={filteredData.length}
page={paginationController.pageNum}
rowsPerPage={paginationController.pageSize}
onPageChange={handlePageChange}
onRowsPerPageChange={handlePageSizeChange}
rowsPerPageOptions={[5, 10, 15]}
labelRowsPerPage={t("Rows per page")}
/>
)}
</>
)}
</Box>
</CardContent>
</Card>


+ 1
- 1
src/components/FinishedGoodSearch/GoodPickExecutionRecord.tsx View File

@@ -113,7 +113,7 @@ const GoodPickExecutionRecord: React.FC<Props> = ({ 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"),


Loading…
Cancel
Save