"use client"; import { Box, Button, Card, CardContent, CardActions, Stack, Typography, Chip, CircularProgress, TablePagination, Grid, LinearProgress, } from "@mui/material"; import { useState, useCallback, useEffect } from "react"; import { useTranslation } from "react-i18next"; import duration from "dayjs/plugin/duration"; import { getStockTakeRecords, AllPickedStockTakeListReponse, createStockTakeForSections, } from "@/app/api/stockTake/actions"; import dayjs from "dayjs"; import { OUTPUT_DATE_FORMAT } from "@/app/utils/formatUtil"; const PER_PAGE = 6; interface PickerCardListProps { onCardClick: (session: AllPickedStockTakeListReponse) => void; onReStockTakeClick: (session: AllPickedStockTakeListReponse) => void; } const PickerCardList: React.FC = ({ onCardClick, onReStockTakeClick }) => { const { t } = useTranslation(["inventory", "common"]); dayjs.extend(duration); const PER_PAGE = 6; const [loading, setLoading] = useState(false); const [stockTakeSessions, setStockTakeSessions] = useState([]); const [page, setPage] = useState(0); const [creating, setCreating] = useState(false); const fetchStockTakeSessions = useCallback(async () => { setLoading(true); try { const data = await getStockTakeRecords(); setStockTakeSessions(Array.isArray(data) ? data : []); setPage(0); } catch (e) { console.error(e); setStockTakeSessions([]); } finally { setLoading(false); } }, []); useEffect(() => { fetchStockTakeSessions(); }, [fetchStockTakeSessions]); const startIdx = page * PER_PAGE; const paged = stockTakeSessions.slice(startIdx, startIdx + PER_PAGE); const handleCreateStockTake = useCallback(async () => { setCreating(true); try { const result = await createStockTakeForSections(); const createdCount = Object.values(result).filter(msg => msg.startsWith("Created:")).length; const skippedCount = Object.values(result).filter(msg => msg.startsWith("Skipped:")).length; const errorCount = Object.values(result).filter(msg => msg.startsWith("Error:")).length; let message = `${t("Created")}: ${createdCount}, ${t("Skipped")}: ${skippedCount}`; if (errorCount > 0) { message += `, ${t("Errors")}: ${errorCount}`; } console.log(message); await fetchStockTakeSessions(); } catch (e) { console.error(e); } finally { setCreating(false); } }, [fetchStockTakeSessions, t]); const getStatusColor = (status: string) => { const statusLower = status.toLowerCase(); if (statusLower === "completed") return "success"; if (statusLower === "in_progress" || statusLower === "processing") return "primary"; if (statusLower === "approving") return "info"; if (statusLower === "stockTaking") return "primary"; if (statusLower === "no_cycle") return "default"; return "warning"; }; const TimeDisplay: React.FC<{ startTime: string | null; endTime: string | null }> = ({ startTime, endTime }) => { const [currentTime, setCurrentTime] = useState(dayjs()); useEffect(() => { if (!endTime && startTime) { const interval = setInterval(() => { setCurrentTime(dayjs()); }, 1000); // 每秒更新一次 return () => clearInterval(interval); } }, [startTime, endTime]); if (endTime && startTime) { // 当有结束时间时,计算从开始到结束的持续时间 const start = dayjs(startTime); const end = dayjs(endTime); const duration = dayjs.duration(end.diff(start)); const hours = Math.floor(duration.asHours()); const minutes = duration.minutes(); const seconds = duration.seconds(); return ( <> {hours.toString().padStart(2, '0')}:{minutes.toString().padStart(2, '0')}:{seconds.toString().padStart(2, '0')} ); } else if (startTime) { // 当没有结束时间时,显示实时计时器 const start = dayjs(startTime); const duration = dayjs.duration(currentTime.diff(start)); const hours = Math.floor(duration.asHours()); const minutes = duration.minutes(); const seconds = duration.seconds(); return ( <> {hours.toString().padStart(2, '0')}:{minutes.toString().padStart(2, '0')}:{seconds.toString().padStart(2, '0')} ); } else { return <>-; } }; const startTimeDisplay = (startTime: string | null) => { if (startTime) { const start = dayjs(startTime); return start.format("HH:mm"); } else { return "-"; } }; const endTimeDisplay = (endTime: string | null) => { if (endTime) { const end = dayjs(endTime); return end.format("HH:mm"); } else { return "-"; } }; const getCompletionRate = (session: AllPickedStockTakeListReponse): number => { if (session.totalInventoryLotNumber === 0) return 0; return Math.round((session.currentStockTakeItemNumber / session.totalInventoryLotNumber) * 100); }; if (loading) { return ( ); } return ( {t("Total Sections")}: {stockTakeSessions.length} {paged.map((session) => { const statusColor = getStatusColor(session.status || ""); const lastStockTakeDate = session.lastStockTakeDate ? dayjs(session.lastStockTakeDate).format(OUTPUT_DATE_FORMAT) : "-"; const completionRate = getCompletionRate(session); return ( {t("Section")}: {session.stockTakeSession} {t("Last Stock Take Date")}: {lastStockTakeDate || "-"} {t("Stock Taker")}: {session.stockTakerName} {t("start time")}: {startTimeDisplay(session.startTime) || "-"} {t("end time")}: {endTimeDisplay(session.endTime) || "-"} {t("Control Time")}: {t("Total Item Number")}: {session.totalItemNumber} {session.totalInventoryLotNumber > 0 && ( {t("Progress")} {completionRate}% )} ); })} {stockTakeSessions.length > 0 && ( setPage(p)} rowsPerPageOptions={[PER_PAGE]} /> )} ); }; export default PickerCardList;