|
- "use client";
- import React, { useState, useEffect, useCallback } from "react";
- import { useSession } from "next-auth/react";
- import { SessionWithTokens } from "@/config/authConfig";
- import { Box, Tabs, Tab, Stack, Typography, Autocomplete, TextField } from "@mui/material";
- import { usePathname, useRouter, useSearchParams } from "next/navigation";
- import QcStockInModal from "@/components/Qc/QcStockInModal";
- import ProductionProcessList, {
- createDefaultProductionProcessListPersistedState,
- } from "@/components/ProductionProcess/ProductionProcessList";
- import ProductionProcessDetail from "@/components/ProductionProcess/ProductionProcessDetail";
- import ProductionProcessJobOrderDetail from "@/components/ProductionProcess/ProductionProcessJobOrderDetail";
- import JobPickExecutionsecondscan from "@/components/Jodetail/JobPickExecutionsecondscan";
- import JobProcessStatus from "@/components/ProductionProcess/JobProcessStatus";
- import OperatorKpiDashboard from "@/components/ProductionProcess/OperatorKpiDashboard";
- import EquipmentStatusDashboard from "@/components/ProductionProcess/EquipmentStatusDashboard";
- import type { PrinterCombo } from "@/app/api/settings/printer";
- import { useTranslation } from "react-i18next";
-
- interface ProductionProcessPageProps {
- printerCombo: PrinterCombo[];
- }
-
- const STORAGE_KEY = 'productionProcess_selectedMatchingStock';
-
- const ProductionProcessPage: React.FC<ProductionProcessPageProps> = ({ printerCombo }) => {
- const { t } = useTranslation(["common"]);
- const [selectedProcessId, setSelectedProcessId] = useState<number | null>(null);
- const [selectedMatchingStock, setSelectedMatchingStock] = useState<{
- jobOrderId: number;
- productProcessId: number;
- pickOrderId: number;
- } | null>(null);
- const [tabIndex, setTabIndex] = useState(0);
- /** 列表搜尋/分頁:保留在切換工單詳情時,返回後仍為同一條件 */
- const [productionListState, setProductionListState] = useState(
- createDefaultProductionProcessListPersistedState,
- );
- const [waitingPutawayListState, setWaitingPutawayListState] = useState(
- createDefaultProductionProcessListPersistedState,
- );
- const [putawayedListState, setPutawayedListState] = useState(
- createDefaultProductionProcessListPersistedState,
- );
- const { data: session } = useSession() as { data: SessionWithTokens | null };
- const sessionToken = session as SessionWithTokens | null;
- const searchParams = useSearchParams();
- const pathname = usePathname();
- const router = useRouter();
- const [linkQcOpen, setLinkQcOpen] = useState(false);
- const [linkQcSilId, setLinkQcSilId] = useState<number | null>(null);
-
- // Add printer selection state
- const [selectedPrinter, setSelectedPrinter] = useState<PrinterCombo | null>(
- printerCombo && printerCombo.length > 0 ? printerCombo[0] : null
- );
-
- // 从 sessionStorage 恢复状态(仅在客户端)
- useEffect(() => {
- if (typeof window !== 'undefined') {
- try {
- const saved = sessionStorage.getItem(STORAGE_KEY);
- if (saved) {
- const parsed = JSON.parse(saved);
- // 验证数据有效性
- if (parsed && typeof parsed.jobOrderId === 'number' && typeof parsed.productProcessId === 'number') {
- setSelectedMatchingStock(parsed);
- console.log(" Restored selectedMatchingStock from sessionStorage:", parsed);
- }
- }
- } catch (error) {
- console.error("Error restoring selectedMatchingStock:", error);
- sessionStorage.removeItem(STORAGE_KEY);
- }
- }
- }, []);
-
- // 保存状态到 sessionStorage
- useEffect(() => {
- if (typeof window !== 'undefined') {
- if (selectedMatchingStock) {
- sessionStorage.setItem(STORAGE_KEY, JSON.stringify(selectedMatchingStock));
- console.log(" Saved selectedMatchingStock to sessionStorage:", selectedMatchingStock);
- } else {
- sessionStorage.removeItem(STORAGE_KEY);
- }
- }
- }, [selectedMatchingStock]);
-
- // 处理返回列表时清除存储
- const handleBackFromSecondScan = useCallback(() => {
- setSelectedMatchingStock(null);
- if (typeof window !== 'undefined') {
- sessionStorage.removeItem(STORAGE_KEY);
- }
- }, []);
-
- const handleTabChange = useCallback((event: React.SyntheticEvent, newValue: number) => {
- setTabIndex(newValue);
- }, []);
-
- const openStockInLineIdQ = searchParams.get("openStockInLineId");
-
- /** Deep link from nav alert: /productionProcess?openStockInLineId=… → 「完成QC工單」tab + FG QC modal */
- useEffect(() => {
- if (!openStockInLineIdQ) {
- setLinkQcOpen(false);
- setLinkQcSilId(null);
- return;
- }
- const id = parseInt(openStockInLineIdQ, 10);
- if (!Number.isFinite(id) || id <= 0) return;
- setSelectedProcessId(null);
- setSelectedMatchingStock(null);
- setTabIndex(1);
- setLinkQcSilId(id);
- setLinkQcOpen(true);
- }, [openStockInLineIdQ]);
-
- const closeLinkQc = useCallback(() => {
- setLinkQcOpen(false);
- setLinkQcSilId(null);
- const p = new URLSearchParams(searchParams.toString());
- p.delete("openStockInLineId");
- const q = p.toString();
- router.replace(q ? `${pathname}?${q}` : pathname, { scroll: false });
- }, [pathname, router, searchParams]);
-
- if (selectedMatchingStock) {
- return (
- <JobPickExecutionsecondscan
- filterArgs={{
- jobOrderId: selectedMatchingStock.jobOrderId,
- pickOrderId: selectedMatchingStock.pickOrderId,
- }}
- onBack={handleBackFromSecondScan}
- />
- );
- }
-
- if (selectedProcessId !== null) {
- return (
- <ProductionProcessJobOrderDetail
- jobOrderId={selectedProcessId}
- initialTabIndex={2}
- onBack={() => setSelectedProcessId(null)}
- />
- );
- }
-
- return (
- <>
- <Box>
- {/* Header section with printer selection */}
- {tabIndex === 1 && (
- <Box sx={{
- p: 1,
- borderBottom: '1px solid #e0e0e0',
- minHeight: 'auto',
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'flex-end',
- gap: 2,
- flexWrap: 'wrap',
- }}>
- <Stack
- direction="row"
- spacing={2}
- sx={{
- alignItems: 'center',
- flexWrap: 'wrap',
- rowGap: 1,
- }}
- >
- <Typography variant="body2" sx={{ minWidth: 'fit-content', mr: 1.5 }}>
- {t("Select Printer")}:
- </Typography>
- <Autocomplete
- disableClearable
- options={printerCombo || []}
- getOptionLabel={(option) =>
- option.name || option.label || option.code || `Printer ${option.id}`
- }
- value={selectedPrinter || undefined}
- onChange={(_, newValue) => setSelectedPrinter(newValue)}
- sx={{ minWidth: 200 }}
- size="small"
- renderInput={(params) => (
- <TextField
- {...params}
- placeholder={t("Printer")}
- inputProps={{
- ...params.inputProps,
- readOnly: true,
- }}
- />
- )}
- />
- </Stack>
- </Box>
- )}
-
- <Tabs value={tabIndex} onChange={handleTabChange} sx={{ mb: 2 }}>
- <Tab label={t("Production Process")} />
- <Tab label={t("Waiting QC Put Away Job Orders")} />
- <Tab label={t("Put Awayed Job Orders")} />
- <Tab label={t("Job Process Status Dashboard")} />
- <Tab label={t("Operator KPI Dashboard")} />
- <Tab label={t("Production Equipment Status Dashboard")} />
- </Tabs>
-
- {tabIndex === 0 && (
- <ProductionProcessList
- printerCombo={printerCombo}
- qcReady={false}
- disableDateFilter={true}
- listPersistedState={productionListState}
- onListPersistedStateChange={setProductionListState}
- onSelectProcess={(jobOrderId) => {
- const id = jobOrderId ?? null;
- if (id !== null) {
- setSelectedProcessId(id);
- }
- }}
- onSelectMatchingStock={(jobOrderId, productProcessId,pickOrderId) => {
- setSelectedMatchingStock({
- jobOrderId: jobOrderId || 0,
- productProcessId: productProcessId || 0 ,
- pickOrderId: pickOrderId || 0
- });
- }}
- />
- )}
-
- {tabIndex === 1 && (
- <ProductionProcessList
- printerCombo={printerCombo}
- qcReady={true}
- includePutaway={true}
- putawayStatus="notCompleted"
- listPersistedState={waitingPutawayListState}
- onListPersistedStateChange={setWaitingPutawayListState}
- onSelectProcess={(jobOrderId) => {
- const id = jobOrderId ?? null;
- if (id !== null) {
- setSelectedProcessId(id);
- }
- }}
- onSelectMatchingStock={(jobOrderId, productProcessId, pickOrderId) => {
- setSelectedMatchingStock({
- jobOrderId: jobOrderId || 0,
- productProcessId: productProcessId || 0,
- pickOrderId: pickOrderId || 0,
- });
- }}
- />
- )}
- {tabIndex === 2 && (
- <ProductionProcessList
- printerCombo={printerCombo}
- qcReady={true}
- includePutaway={true}
- putawayStatus="completed"
- listPersistedState={putawayedListState}
- onListPersistedStateChange={setPutawayedListState}
- onSelectProcess={(jobOrderId) => {
- const id = jobOrderId ?? null;
- if (id !== null) {
- setSelectedProcessId(id);
- }
- }}
- onSelectMatchingStock={(jobOrderId, productProcessId, pickOrderId) => {
- setSelectedMatchingStock({
- jobOrderId: jobOrderId || 0,
- productProcessId: productProcessId || 0,
- pickOrderId: pickOrderId || 0,
- });
- }}
- />
- )}
- {tabIndex === 3 && (
- <JobProcessStatus />
- )}
- {tabIndex === 4 && (
- <OperatorKpiDashboard />
- )}
- {tabIndex === 5 && (
- <EquipmentStatusDashboard />
- )}
- </Box>
- <QcStockInModal
- session={sessionToken}
- open={Boolean(linkQcOpen && linkQcSilId != null && linkQcSilId > 0)}
- onClose={closeLinkQc}
- inputDetail={linkQcSilId != null && linkQcSilId > 0 ? { id: linkQcSilId } : undefined}
- printerCombo={printerCombo}
- warehouse={[]}
- printSource="productionProcess"
- uiMode="default"
- />
- </>
- );
- };
-
- export default ProductionProcessPage;
|