Przeglądaj źródła

Show the step byproduct only when the BOM has one, and block a second complete-step submit.

debrand
Harry Groves 2 dni temu
rodzic
commit
dc7e9448fc
3 zmienionych plików z 62 dodań i 14 usunięć
  1. +12
    -12
      src/components/ProductionProcess/ProductionOutputForm.tsx
  2. +11
    -1
      src/components/ProductionProcess/ProductionOutputFormPage.tsx
  3. +39
    -1
      src/components/ProductionProcess/ProductionProcessStepExecution.tsx

+ 12
- 12
src/components/ProductionProcess/ProductionOutputForm.tsx Wyświetl plik

@@ -18,6 +18,7 @@ import { useTranslation } from "react-i18next";
import { UpdateProductProcessLineQtyRequest } from "@/app/api/jo/actions"; import { UpdateProductProcessLineQtyRequest } from "@/app/api/jo/actions";


interface ProductionOutputFormProps { interface ProductionOutputFormProps {
showByproduct?: boolean;
outputData: (UpdateProductProcessLineQtyRequest & { outputData: (UpdateProductProcessLineQtyRequest & {
byproductName: string; byproductName: string;
byproductQty: number; byproductQty: number;
@@ -34,13 +35,16 @@ interface ProductionOutputFormProps {
>; >;
onSubmit: () => Promise<void> | void; onSubmit: () => Promise<void> | void;
onCancel: () => void; onCancel: () => void;
submitting?: boolean;
} }


const ProductionOutputForm: React.FC<ProductionOutputFormProps> = ({ const ProductionOutputForm: React.FC<ProductionOutputFormProps> = ({
showByproduct = false,
outputData, outputData,
setOutputData, setOutputData,
onSubmit, onSubmit,
onCancel, onCancel,
submitting = false,
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();


@@ -88,10 +92,14 @@ const ProductionOutputForm: React.FC<ProductionOutputFormProps> = ({
</TableCell> </TableCell>
</TableRow> </TableRow>


{showByproduct && (
<TableRow> <TableRow>
<TableCell> <TableCell>
<Stack> <Stack>
<Typography fontWeight={500}>{t("By-product")}</Typography> <Typography fontWeight={500}>{t("By-product")}</Typography>
<Typography variant="body2" color="text.secondary">
{outputData.byproductName}
</Typography>
</Stack> </Stack>
</TableCell> </TableCell>
<TableCell> <TableCell>
@@ -106,22 +114,14 @@ const ProductionOutputForm: React.FC<ProductionOutputFormProps> = ({
byproductQty: parseInt(e.target.value) || 0, byproductQty: parseInt(e.target.value) || 0,
}) })
} }
inputProps={{ min: 0 }}
/> />
</TableCell> </TableCell>
<TableCell> <TableCell>
<TextField
fullWidth
size="small"
value={outputData.byproductUom}
onChange={(e) =>
setOutputData({
...outputData,
byproductUom: e.target.value,
})
}
/>
<Typography>{outputData.byproductUom || "-"}</Typography>
</TableCell> </TableCell>
</TableRow> </TableRow>
)}


<TableRow sx={{ bgcolor: "warning.50" }}> <TableRow sx={{ bgcolor: "warning.50" }}>
<TableCell> <TableCell>
@@ -199,7 +199,7 @@ const ProductionOutputForm: React.FC<ProductionOutputFormProps> = ({
<Button variant="outlined" onClick={onCancel}> <Button variant="outlined" onClick={onCancel}>
{t("Cancel")} {t("Cancel")}
</Button> </Button>
<Button variant="contained" startIcon={<CheckCircleIcon />} onClick={onSubmit}>
<Button variant="contained" startIcon={<CheckCircleIcon />} onClick={onSubmit} disabled={submitting}>
{t("Complete Step")} {t("Complete Step")}
</Button> </Button>
</Box> </Box>


+ 11
- 1
src/components/ProductionProcess/ProductionOutputFormPage.tsx Wyświetl plik

@@ -1,5 +1,5 @@
"use client"; "use client";
import React, { useEffect, useState } from "react";
import React, { useEffect, useRef, useState } from "react";
import { import {
Box, Box,
Button, Button,
@@ -25,6 +25,8 @@ const ProductionOutputFormPage: React.FC<ProductionOutputFormPageProps> = ({
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const [lineDetail, setLineDetail] = useState<JobOrderProcessLineDetailResponse | null>(null); const [lineDetail, setLineDetail] = useState<JobOrderProcessLineDetailResponse | null>(null);
const outputInFlightRef = useRef(false);
const [isSubmitting, setIsSubmitting] = useState(false);
const [outputData, setOutputData] = useState<UpdateProductProcessLineQtyRequest & { const [outputData, setOutputData] = useState<UpdateProductProcessLineQtyRequest & {
byproductName: string; byproductName: string;
byproductQty: number; byproductQty: number;
@@ -79,6 +81,9 @@ const ProductionOutputFormPage: React.FC<ProductionOutputFormPageProps> = ({


const handleSubmitOutput = async () => { const handleSubmitOutput = async () => {
if (!lineDetail?.id) return; if (!lineDetail?.id) return;
if (outputInFlightRef.current) return;
outputInFlightRef.current = true;
setIsSubmitting(true);


try { try {
await updateProductProcessLineQty({ await updateProductProcessLineQty({
@@ -110,6 +115,9 @@ const ProductionOutputFormPage: React.FC<ProductionOutputFormPageProps> = ({
} catch (error) { } catch (error) {
console.error("Error submitting output:", error); console.error("Error submitting output:", error);
alert("Failed to submit output data. Please try again."); alert("Failed to submit output data. Please try again.");
} finally {
outputInFlightRef.current = false;
setIsSubmitting(false);
} }
}; };


@@ -133,10 +141,12 @@ const ProductionOutputFormPage: React.FC<ProductionOutputFormPageProps> = ({
</Box> </Box>


<ProductionOutputForm <ProductionOutputForm
showByproduct={(lineDetail?.byproductId ?? 0) > 0}
outputData={outputData} outputData={outputData}
setOutputData={setOutputData} setOutputData={setOutputData}
onSubmit={handleSubmitOutput} onSubmit={handleSubmitOutput}
onCancel={onBack} onCancel={onBack}
submitting={isSubmitting}
/> />
</Box> </Box>
); );


+ 39
- 1
src/components/ProductionProcess/ProductionProcessStepExecution.tsx Wyświetl plik

@@ -42,7 +42,7 @@ import {
ProductProcessLineResponse, // ✅ 添加 ProductProcessLineResponse, // ✅ 添加
} from "@/app/api/jo/actions"; } from "@/app/api/jo/actions";
import { Operator, Machine } from "@/app/api/jo"; import { Operator, Machine } from "@/app/api/jo";
import React, { useCallback, useEffect, useState, useMemo } from "react"; // ✅ 添加 useMemo
import React, { useCallback, useEffect, useState, useMemo, useRef } from "react";
import { useQrCodeScannerContext } from "../QrCodeScannerProvider/QrCodeScannerProvider"; import { useQrCodeScannerContext } from "../QrCodeScannerProvider/QrCodeScannerProvider";
import { fetchNameList, NameList } from "@/app/api/user/actions"; import { fetchNameList, NameList } from "@/app/api/user/actions";
import BagConsumptionForm from "./BagConsumptionForm"; // ✅ 添加导入 import BagConsumptionForm from "./BagConsumptionForm"; // ✅ 添加导入
@@ -114,6 +114,9 @@ const ProductionProcessStepExecution: React.FC<ProductionProcessStepExecutionPro
const [lastPauseTime, setLastPauseTime] = useState<Date | null>(null); const [lastPauseTime, setLastPauseTime] = useState<Date | null>(null);
const[isOpenReasonModel, setIsOpenReasonModel] = useState(false); const[isOpenReasonModel, setIsOpenReasonModel] = useState(false);
const [pauseReason, setPauseReason] = useState(""); const [pauseReason, setPauseReason] = useState("");
const outputInFlightRef = useRef(false);
const [isSubmittingOutput, setIsSubmittingOutput] = useState(false);
const hasByproduct = (lineDetail?.byproductId ?? 0) > 0;


// ✅ 添加:判断是否显示 Bag 表单的条件 // ✅ 添加:判断是否显示 Bag 表单的条件
const isPackagingProcess = useMemo(() => { const isPackagingProcess = useMemo(() => {
@@ -360,6 +363,9 @@ const ProductionProcessStepExecution: React.FC<ProductionProcessStepExecutionPro


const handleSubmitOutput = async () => { const handleSubmitOutput = async () => {
if (!lineDetail?.id) return; if (!lineDetail?.id) return;
if (outputInFlightRef.current) return;
outputInFlightRef.current = true;
setIsSubmittingOutput(true);


try { try {
await updateProductProcessLineQty({ await updateProductProcessLineQty({
@@ -422,6 +428,9 @@ const ProductionProcessStepExecution: React.FC<ProductionProcessStepExecutionPro
} catch (error) { } catch (error) {
console.error("Error submitting output:", error); console.error("Error submitting output:", error);
alert("Failed to submit output data. Please try again."); alert("Failed to submit output data. Please try again.");
} finally {
outputInFlightRef.current = false;
setIsSubmittingOutput(false);
} }
}; };
@@ -856,6 +865,34 @@ const ProductionProcessStepExecution: React.FC<ProductionProcessStepExecutionPro
</TableCell> </TableCell>
</TableRow> </TableRow>


{hasByproduct && (
<TableRow>
<TableCell>
<Typography fontWeight={500}>{t("By-product")}</Typography>
<Typography variant="body2" color="text.secondary">
{outputData.byproductName}
</Typography>
</TableCell>
<TableCell>
<TextField
type="number"
fullWidth
size="small"
value={outputData.byproductQty}
onChange={(e) => setOutputData({
...outputData,
byproductQty: parseInt(e.target.value) || 0
})}
inputProps={{ min: 0 }}
/>
</TableCell>
<TableCell>
<Typography>{outputData.byproductUom || "-"}</Typography>
</TableCell>
<TableCell />
</TableRow>
)}

<TableRow sx={{ bgcolor: 'warning.50' }}> <TableRow sx={{ bgcolor: 'warning.50' }}>
<TableCell> <TableCell>
<Typography fontWeight={500} color="warning.dark">{t("Defect")}{t("(1)")}</Typography> <Typography fontWeight={500} color="warning.dark">{t("Defect")}{t("(1)")}</Typography>
@@ -1052,6 +1089,7 @@ const ProductionProcessStepExecution: React.FC<ProductionProcessStepExecutionPro
variant="contained" variant="contained"
startIcon={<CheckCircleIcon />} startIcon={<CheckCircleIcon />}
onClick={handleSubmitOutput} onClick={handleSubmitOutput}
disabled={isSubmittingOutput}
> >
{t("Complete Step")} {t("Complete Step")}
</Button> </Button>


Ładowanie…
Anuluj
Zapisz