FPSMS-frontend
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 

324 рядки
13 KiB

  1. "use client";
  2. import React, { useState, useEffect, useCallback, useMemo } from 'react';
  3. import {
  4. Box,
  5. Typography,
  6. FormControl,
  7. InputLabel,
  8. Select,
  9. MenuItem,
  10. Card,
  11. CardContent,
  12. Stack,
  13. Table,
  14. TableBody,
  15. TableCell,
  16. TableContainer,
  17. TableHead,
  18. TableRow,
  19. Paper,
  20. CircularProgress,
  21. TablePagination
  22. } from '@mui/material';
  23. import { useTranslation } from 'react-i18next';
  24. import dayjs from 'dayjs';
  25. import { fetchTicketReleaseTable, getTicketReleaseTable } from '@/app/api/do/actions';
  26. const FGPickOrderTicketReleaseTable: React.FC = () => {
  27. const { t } = useTranslation("pickOrder");
  28. const [selectedDate, setSelectedDate] = useState<string>("today");
  29. const [selectedFloor, setSelectedFloor] = useState<string>("");
  30. const [data, setData] = useState<getTicketReleaseTable[]>([]);
  31. const [loading, setLoading] = useState<boolean>(true);
  32. const [paginationController, setPaginationController] = useState({
  33. pageNum: 0,
  34. pageSize: 10,
  35. });
  36. const getDateLabel = (offset: number) => {
  37. return dayjs().add(offset, 'day').format('YYYY-MM-DD');
  38. };
  39. useEffect(() => {
  40. const loadData = async () => {
  41. setLoading(true);
  42. try {
  43. const result = await fetchTicketReleaseTable();
  44. setData(result);
  45. } catch (error) {
  46. console.error('Error fetching ticket release table:', error);
  47. } finally {
  48. setLoading(false);
  49. }
  50. };
  51. loadData();
  52. }, []);
  53. const filteredData = data.filter((item) => {
  54. // Filter by floor if selected
  55. if (selectedFloor && item.storeId !== selectedFloor) {
  56. return false;
  57. }
  58. // Filter by date if selected
  59. if (selectedDate && item.requiredDeliveryDate) {
  60. const itemDate = dayjs(item.requiredDeliveryDate).format('YYYY-MM-DD');
  61. const targetDate = getDateLabel(
  62. selectedDate === "today" ? 0 : selectedDate === "tomorrow" ? 1 : 2
  63. );
  64. if (itemDate !== targetDate) {
  65. return false;
  66. }
  67. }
  68. return true;
  69. },[data, selectedDate, selectedFloor]);
  70. const handlePageChange = useCallback((event: unknown, newPage: number) => {
  71. setPaginationController(prev => ({
  72. ...prev,
  73. pageNum: newPage,
  74. }));
  75. }, []);
  76. const handlePageSizeChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
  77. const newPageSize = parseInt(event.target.value, 10);
  78. setPaginationController({
  79. pageNum: 0,
  80. pageSize: newPageSize,
  81. });
  82. }, []);
  83. const paginatedData = useMemo(() => {
  84. const startIndex = paginationController.pageNum * paginationController.pageSize;
  85. const endIndex = startIndex + paginationController.pageSize;
  86. return filteredData.slice(startIndex, endIndex);
  87. }, [filteredData, paginationController]);
  88. useEffect(() => {
  89. setPaginationController(prev => ({ ...prev, pageNum: 0 }));
  90. }, [selectedDate, selectedFloor]);
  91. return (
  92. <Card sx={{ mb: 2 }}>
  93. <CardContent>
  94. {/* Title */}
  95. <Typography variant="h5" sx={{ mb: 3, fontWeight: 600 }}>
  96. Ticket Release Table
  97. </Typography>
  98. {/* Dropdown Menus */}
  99. <Stack direction="row" spacing={2} sx={{ mb: 3 }}>
  100. {/* Date Selection Dropdown */}
  101. <FormControl sx={{ minWidth: 250 }} size="small">
  102. <InputLabel id="date-select-label">{t("Select Date")}</InputLabel>
  103. <Select
  104. labelId="date-select-label"
  105. id="date-select"
  106. value={selectedDate}
  107. label={t("Select Date")}
  108. onChange={(e) => setSelectedDate(e.target.value)}
  109. >
  110. <MenuItem value="today">
  111. {t("Today")} ({getDateLabel(0)})
  112. </MenuItem>
  113. <MenuItem value="tomorrow">
  114. {t("Tomorrow")} ({getDateLabel(1)})
  115. </MenuItem>
  116. <MenuItem value="dayAfterTomorrow">
  117. {t("Day After Tomorrow")} ({getDateLabel(2)})
  118. </MenuItem>
  119. </Select>
  120. </FormControl>
  121. <FormControl sx={{ minWidth: 150 }} size="small">
  122. <InputLabel
  123. id="floor-select-label"
  124. shrink={true}
  125. >
  126. {t("Floor")}
  127. </InputLabel>
  128. <Select
  129. labelId="floor-select-label"
  130. id="floor-select"
  131. value={selectedFloor}
  132. label={t("Floor")}
  133. onChange={(e) => setSelectedFloor(e.target.value)}
  134. displayEmpty
  135. >
  136. <MenuItem value="">
  137. <em>{t("All Floors")}</em>
  138. </MenuItem>
  139. <MenuItem value="2/F">2/F</MenuItem>
  140. <MenuItem value="4/F">4/F</MenuItem>
  141. </Select>
  142. </FormControl>
  143. </Stack>
  144. <Box sx={{ mt: 2 }}>
  145. {loading ? (
  146. <Box sx={{ display: 'flex', justifyContent: 'center', p: 3 }}>
  147. <CircularProgress />
  148. </Box>
  149. ) : (
  150. <>
  151. <TableContainer component={Paper}>
  152. <Table size="small" sx={{ minWidth: 650 }}>
  153. <TableHead>
  154. <TableRow>
  155. <TableCell>{t("Store ID")}</TableCell>
  156. <TableCell>{t("Required Delivery Date")}</TableCell>
  157. <TableCell>
  158. <Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.5 }}>
  159. <Typography variant="subtitle2" sx={{ fontWeight: 600 }}>
  160. {t("Truck Information")}
  161. </Typography>
  162. <Typography variant="caption" sx={{ color: 'text.secondary' }}>
  163. {t("Departure Time")} / {t("Truck Lane Code")}
  164. </Typography>
  165. </Box>
  166. </TableCell>
  167. {/*<TableCell>{t("Truck Departure Time")}</TableCell>
  168. <TableCell>{t("Truck Lane Code")}</TableCell>*/}
  169. <TableCell>{t("Shop Name")}</TableCell>
  170. <TableCell>{t("Loading Sequence")}</TableCell>
  171. {/*<TableCell>{t("Delivery Order Code(s)")}</TableCell>
  172. <TableCell>{t("Pick Order Code(s)")}</TableCell>
  173. <TableCell>{t("Ticket Number")}</TableCell>
  174. <TableCell>{t("Ticket Release Time")}</TableCell>
  175. <TableCell>{t("Ticket Complete Date Time")}</TableCell>
  176. <TableCell>{t("Ticket Status")}</TableCell>*/}
  177. <TableCell>
  178. <Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.5 }}>
  179. <Typography variant="subtitle2" sx={{ fontWeight: 600 }}>
  180. {t("Ticket Information")}
  181. </Typography>
  182. <Typography variant="caption" sx={{ color: 'text.secondary' }}>
  183. {t("Ticket No.")} ({t("Status")}) / {t("Release Time")} / {t("Complete Time")}
  184. </Typography>
  185. </Box>
  186. </TableCell>
  187. <TableCell>{t("Handler Name")}</TableCell>
  188. <TableCell>{t("Number of FG Items")}</TableCell>
  189. </TableRow>
  190. </TableHead>
  191. <TableBody>
  192. {paginatedData.length === 0 ? (
  193. <TableRow>
  194. <TableCell colSpan={12} align="center">
  195. {t("No data available")}
  196. </TableCell>
  197. </TableRow>
  198. ) : (
  199. paginatedData.map((row) => {
  200. const isPending = row.ticketStatus?.toLowerCase() === 'pending';
  201. const showTimes = !isPending && (row.ticketStatus?.toLowerCase() === 'released' || row.ticketStatus?.toLowerCase() === 'completed');
  202. return (
  203. <TableRow key={row.id}>
  204. <TableCell>{row.storeId || '-'}</TableCell>
  205. <TableCell>
  206. {row.requiredDeliveryDate
  207. ? dayjs(row.requiredDeliveryDate).format('YYYY-MM-DD')
  208. : '-'}
  209. </TableCell>
  210. <TableCell>
  211. <Typography variant="body2">
  212. {row.truckDepartureTime && row.truckLanceCode
  213. ? (() => {
  214. let timeStr = row.truckDepartureTime.toString().trim();
  215. timeStr = timeStr.replace(',', ':');
  216. const timeMatch = timeStr.match(/^(\d{1,2})[:](\d{2})/);
  217. if (timeMatch) {
  218. const hours = timeMatch[1].padStart(2, '0');
  219. const minutes = timeMatch[2];
  220. return `${hours}:${minutes} | ${row.truckLanceCode}`;
  221. }
  222. return `${timeStr} | ${row.truckLanceCode}`;
  223. })()
  224. : row.truckDepartureTime
  225. ? (() => {
  226. let timeStr = row.truckDepartureTime.toString().trim();
  227. timeStr = timeStr.replace(',', ':');
  228. const timeMatch = timeStr.match(/^(\d{1,2})[:](\d{2})/);
  229. if (timeMatch) {
  230. const hours = timeMatch[1].padStart(2, '0');
  231. const minutes = timeMatch[2];
  232. return `${hours}:${minutes}`;
  233. }
  234. return timeStr;
  235. })()
  236. : row.truckLanceCode || '-'}
  237. </Typography>
  238. </TableCell>
  239. <TableCell>{row.shopName || '-'}</TableCell>
  240. <TableCell>{row.loadingSequence || '-'}</TableCell>
  241. {/*<TableCell>{row.deliveryOrderCode || '-'}</TableCell>
  242. <TableCell>{row.pickOrderCode || '-'}</TableCell>
  243. <TableCell>{row.ticketNo || '-'}</TableCell>
  244. <TableCell>
  245. {row.ticketReleaseTime
  246. ? dayjs(row.ticketReleaseTime).format('YYYY-MM-DD HH:mm:ss')
  247. : '-'}
  248. </TableCell>
  249. <TableCell>
  250. {row.ticketCompleteDateTime
  251. ? dayjs(row.ticketCompleteDateTime).format('YYYY-MM-DD HH:mm:ss')
  252. : '-'}
  253. </TableCell>
  254. <TableCell>{row.ticketStatus || '-'}</TableCell>*/}
  255. <TableCell>
  256. <Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.5 }}>
  257. <Typography variant="body2">
  258. {row.ticketNo || '-'} ({row.ticketStatus || '-'})
  259. </Typography>
  260. {showTimes && (
  261. <>
  262. <Typography variant="body2">
  263. {row.ticketReleaseTime
  264. ? dayjs(row.ticketReleaseTime, 'YYYYMMDDHHmmss').format('YYYY-MM-DD HH:mm')
  265. : '-'}
  266. </Typography>
  267. <Typography variant="body2">
  268. {row.ticketCompleteDateTime
  269. ? dayjs(row.ticketCompleteDateTime, 'YYYYMMDDHHmmss').format('YYYY-MM-DD HH:mm')
  270. : '-'}
  271. </Typography>
  272. </>
  273. )}
  274. </Box>
  275. </TableCell>
  276. <TableCell>{row.handlerName || '-'}</TableCell>
  277. <TableCell>-</TableCell>
  278. </TableRow>
  279. );
  280. })
  281. )}
  282. </TableBody>
  283. </Table>
  284. </TableContainer>
  285. {filteredData.length > 0 && (
  286. <TablePagination
  287. component="div"
  288. count={filteredData.length}
  289. page={paginationController.pageNum}
  290. rowsPerPage={paginationController.pageSize}
  291. onPageChange={handlePageChange}
  292. onRowsPerPageChange={handlePageSizeChange}
  293. rowsPerPageOptions={[5, 10, 15]}
  294. labelRowsPerPage={t("Rows per page")}
  295. />
  296. )}
  297. </>
  298. )}
  299. </Box>
  300. </CardContent>
  301. </Card>
  302. );
  303. };
  304. export default FGPickOrderTicketReleaseTable;