FPSMS-frontend
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

ProductionProcessStepExecution.tsx 25 KiB

1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
4週間前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
4週間前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
3週間前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
3週間前
1ヶ月前
4週間前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
4週間前
1ヶ月前
4週間前
1ヶ月前
4週間前
1ヶ月前
3週間前
1ヶ月前
3週間前
4週間前
1ヶ月前
4週間前
1ヶ月前
4週間前
1ヶ月前
4週間前
1ヶ月前
3週間前
1ヶ月前
3週間前
1ヶ月前
3週間前
1ヶ月前
3週間前
1ヶ月前
3週間前
1ヶ月前
3週間前
1ヶ月前
3週間前
1ヶ月前
4週間前
1ヶ月前
1ヶ月前
1ヶ月前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. "use client";
  2. import {
  3. Box,
  4. Button,
  5. Paper,
  6. Stack,
  7. Typography,
  8. TextField,
  9. Table,
  10. TableBody,
  11. TableCell,
  12. TableHead,
  13. TableRow,
  14. Card,
  15. CardContent,
  16. Grid,
  17. } from "@mui/material";
  18. import QrCodeIcon from '@mui/icons-material/QrCode';
  19. import CheckCircleIcon from "@mui/icons-material/CheckCircle";
  20. import StopIcon from "@mui/icons-material/Stop";
  21. import PauseIcon from "@mui/icons-material/Pause";
  22. import PlayArrowIcon from "@mui/icons-material/PlayArrow";
  23. import { useTranslation } from "react-i18next";
  24. import { JobOrderProcessLineDetailResponse, updateProductProcessLineQty,updateProductProcessLineQrscan,fetchProductProcessLineDetail ,UpdateProductProcessLineQtyRequest} from "@/app/api/jo/actions";
  25. import { Operator, Machine } from "@/app/api/jo";
  26. import React, { useCallback, useEffect, useState } from "react";
  27. import { useQrCodeScannerContext } from "../QrCodeScannerProvider/QrCodeScannerProvider";
  28. import { fetchNameList, NameList } from "@/app/api/user/actions";
  29. interface ProductionProcessStepExecutionProps {
  30. lineId: number | null
  31. onBack: () => void
  32. //onClose: () => void
  33. // onOutputSubmitted: () => Promise<void>
  34. }
  35. const ProductionProcessStepExecution: React.FC<ProductionProcessStepExecutionProps> = ({
  36. lineId,
  37. onBack,
  38. }) => {
  39. const { t } = useTranslation();
  40. const [lineDetail, setLineDetail] = useState<JobOrderProcessLineDetailResponse | null>(null);
  41. const isCompleted = lineDetail?.status === "Completed";
  42. const [outputData, setOutputData] = useState<UpdateProductProcessLineQtyRequest & {
  43. byproductName: string;
  44. byproductQty: number;
  45. byproductUom: string;
  46. }>({
  47. productProcessLineId: lineId ?? 0,
  48. outputFromProcessQty: 0,
  49. outputFromProcessUom: "",
  50. defectQty: 0,
  51. defectUom: "",
  52. scrapQty: 0,
  53. scrapUom: "",
  54. byproductName: "",
  55. byproductQty: 0,
  56. byproductUom: ""
  57. });
  58. const [isManualScanning, setIsManualScanning] = useState(false);
  59. const [processedQrCodes, setProcessedQrCodes] = useState<Set<string>>(new Set());
  60. const [scannedOperators, setScannedOperators] = useState<Operator[]>([]);
  61. const [scannedMachines, setScannedMachines] = useState<Machine[]>([]);
  62. const [isPaused, setIsPaused] = useState(false);
  63. const [showOutputTable, setShowOutputTable] = useState(false);
  64. const { values: qrValues, startScan, stopScan, resetScan } = useQrCodeScannerContext();
  65. const equipmentName = (lineDetail as any)?.equipment || lineDetail?.equipmentType || "-";
  66. const [remainingTime, setRemainingTime] = useState<string | null>(null);
  67. // 检查是否两个都已扫描
  68. //const bothScanned = lineDetail?.operatorId && lineDetail?.equipmentId;
  69. useEffect(() => {
  70. if (!lineId) {
  71. setLineDetail(null);
  72. return;
  73. }
  74. fetchProductProcessLineDetail(lineId)
  75. .then((detail) => {
  76. setLineDetail(detail as any);
  77. // 初始化 outputData 从 lineDetail
  78. setOutputData(prev => ({
  79. ...prev,
  80. productProcessLineId: detail.id,
  81. outputFromProcessQty: (detail as any).outputFromProcessQty || 0, // 取消注释,使用类型断言
  82. outputFromProcessUom: (detail as any).outputFromProcessUom || "", // 取消注释,使用类型断言
  83. defectQty: detail.defectQty || 0,
  84. defectUom: detail.defectUom || "",
  85. scrapQty: detail.scrapQty || 0,
  86. scrapUom: detail.scrapUom || "",
  87. byproductName: detail.byproductName || "",
  88. byproductQty: detail.byproductQty || 0,
  89. byproductUom: detail.byproductUom || ""
  90. }));
  91. })
  92. .catch(err => {
  93. console.error("Failed to load line detail", err);
  94. setLineDetail(null);
  95. });
  96. }, [lineId]);
  97. useEffect(() => {
  98. if (!lineDetail?.durationInMinutes || !lineDetail?.startTime) {
  99. setRemainingTime(null);
  100. return;
  101. }
  102. const start = new Date(lineDetail.startTime as any);
  103. const end = new Date(start.getTime() + lineDetail.durationInMinutes * 60_000);
  104. const update = () => {
  105. const diff = end.getTime() - Date.now();
  106. if (diff <= 0) {
  107. setRemainingTime("00:00");
  108. return;
  109. }
  110. const minutes = Math.floor(diff / 60000).toString().padStart(2, "0");
  111. const seconds = Math.floor((diff % 60000) / 1000).toString().padStart(2, "0");
  112. setRemainingTime(`${minutes}:${seconds}`);
  113. };
  114. update();
  115. const timer = setInterval(update, 1000);
  116. return () => clearInterval(timer);
  117. }, [lineDetail?.durationInMinutes, lineDetail?.startTime]);
  118. const handleSubmitOutput = async () => {
  119. if (!lineDetail?.id) return;
  120. try {
  121. // 直接使用 actions.ts 中定义的函数
  122. await updateProductProcessLineQty({
  123. productProcessLineId: lineDetail?.id || 0 as number,
  124. byproductName: outputData.byproductName,
  125. byproductQty: outputData.byproductQty,
  126. byproductUom: outputData.byproductUom,
  127. outputFromProcessQty: outputData.outputFromProcessQty,
  128. outputFromProcessUom: outputData.outputFromProcessUom,
  129. // outputFromProcessUom: outputData.outputFromProcessUom,
  130. defectQty: outputData.defectQty,
  131. defectUom: outputData.defectUom,
  132. scrapQty: outputData.scrapQty,
  133. scrapUom: outputData.scrapUom,
  134. });
  135. console.log(" Output data submitted successfully");
  136. fetchProductProcessLineDetail(lineDetail.id)
  137. .then((detail) => {
  138. setLineDetail(detail as any);
  139. // 初始化 outputData 从 lineDetail
  140. setOutputData(prev => ({
  141. ...prev,
  142. productProcessLineId: detail.id,
  143. outputFromProcessQty: (detail as any).outputFromProcessQty || 0, // 取消注释,使用类型断言
  144. outputFromProcessUom: (detail as any).outputFromProcessUom || "", // 取消注释,使用类型断言
  145. defectQty: detail.defectQty || 0,
  146. defectUom: detail.defectUom || "",
  147. scrapQty: detail.scrapQty || 0,
  148. scrapUom: detail.scrapUom || "",
  149. byproductName: detail.byproductName || "",
  150. byproductQty: detail.byproductQty || 0,
  151. byproductUom: detail.byproductUom || ""
  152. }));
  153. })
  154. .catch(err => {
  155. console.error("Failed to load line detail", err);
  156. setLineDetail(null);
  157. });
  158. } catch (error) {
  159. console.error("Error submitting output:", error);
  160. alert("Failed to submit output data. Please try again.");
  161. }
  162. };
  163. // 处理 QR 码扫描效果
  164. useEffect(() => {
  165. if (isManualScanning && qrValues.length > 0 && lineDetail?.id) {
  166. const latestQr = qrValues[qrValues.length - 1];
  167. if (processedQrCodes.has(latestQr)) {
  168. return;
  169. }
  170. setProcessedQrCodes(prev => new Set(prev).add(latestQr));
  171. //processQrCode(latestQr);
  172. }
  173. }, [qrValues, isManualScanning, lineDetail?.id, processedQrCodes]);
  174. // 开始扫描
  175. const handlePause = () => {
  176. setIsPaused(true);
  177. };
  178. const handleContinue = () => {
  179. setIsPaused(false);
  180. };
  181. const handleStop = () => {
  182. setIsPaused(false);
  183. // TODO: 调用停止流程的 API
  184. };
  185. return (
  186. <Box>
  187. <Box sx={{ mb: 2 }}>
  188. <Button variant="outlined" onClick={onBack}>
  189. {t("Back to List")}
  190. </Button>
  191. </Box>
  192. {/* 如果已完成,显示合并的视图 */}
  193. {isCompleted ? (
  194. <Card sx={{ bgcolor: 'success.50', border: '2px solid', borderColor: 'success.main', mb: 3 }}>
  195. <CardContent>
  196. <Typography variant="h5" color="success.main" gutterBottom fontWeight="bold">
  197. {t("Completed Step")}: {lineDetail?.name} (Seq: {lineDetail?.seqNo})
  198. </Typography>
  199. {/*<Divider sx={{ my: 2 }} />*/}
  200. {/* 步骤信息部分 */}
  201. <Typography variant="h6" gutterBottom sx={{ mt: 2 }}>
  202. {t("Step Information")}
  203. </Typography>
  204. <Grid container spacing={2} sx={{ mb: 3 }}>
  205. <Grid item xs={12} md={6}>
  206. <Typography variant="body2" color="text.secondary">
  207. <strong>{t("Description")}:</strong> {lineDetail?.description || "-"}
  208. </Typography>
  209. </Grid>
  210. <Grid item xs={12} md={6}>
  211. <Typography variant="body2" color="text.secondary">
  212. <strong>{t("Operator")}:</strong> {lineDetail?.operatorName || "-"}
  213. </Typography>
  214. </Grid>
  215. <Grid item xs={12} md={6}>
  216. <Typography variant="body2" color="text.secondary">
  217. <strong>{t("Equipment")}:</strong> {equipmentName}
  218. </Typography>
  219. </Grid>
  220. <Grid item xs={12} md={6}>
  221. <Typography variant="body2" color="text.secondary">
  222. <strong>{t("Status")}:</strong> {lineDetail?.status || "-"}
  223. </Typography>
  224. </Grid>
  225. </Grid>
  226. {/*<Divider sx={{ my: 2 }} />*/}
  227. {/* 产出数据部分 */}
  228. <Typography variant="h6" gutterBottom sx={{ mt: 2 }}>
  229. {t("Production Output Data")}
  230. </Typography>
  231. <Table size="small" sx={{ mt: 2 }}>
  232. <TableHead>
  233. <TableRow>
  234. <TableCell width="30%"><strong>{t("Type")}</strong></TableCell>
  235. <TableCell width="35%"><strong>{t("Quantity")}</strong></TableCell>
  236. <TableCell width="35%"><strong>{t("Unit")}</strong></TableCell>
  237. </TableRow>
  238. </TableHead>
  239. <TableBody>
  240. {/* Output from Process */}
  241. <TableRow>
  242. <TableCell>
  243. <Typography fontWeight={500}>{t("Output from Process")}</Typography>
  244. </TableCell>
  245. <TableCell>
  246. <Typography>{lineDetail?.outputFromProcessQty || 0}</Typography>
  247. </TableCell>
  248. <TableCell>
  249. <Typography>{lineDetail?.outputFromProcessUom || "-"}</Typography>
  250. </TableCell>
  251. </TableRow>
  252. {/* By-product */}
  253. {/*
  254. <TableRow>
  255. <TableCell>
  256. <Typography fontWeight={500}>{t("By-product")}</Typography>
  257. {lineDetail.byproductName && (
  258. <Typography variant="caption" color="text.secondary">
  259. ({lineDetail.byproductName})
  260. </Typography>
  261. )}
  262. </TableCell>
  263. <TableCell>
  264. <Typography>{lineDetail.byproductQty}</Typography>
  265. </TableCell>
  266. <TableCell>
  267. <Typography>{lineDetail.byproductUom || "-"}</Typography>
  268. </TableCell>
  269. </TableRow>
  270. */}
  271. {/* Defect */}
  272. <TableRow sx={{ bgcolor: 'warning.50' }}>
  273. <TableCell>
  274. <Typography fontWeight={500} color="warning.dark">{t("Defect")}</Typography>
  275. </TableCell>
  276. <TableCell>
  277. <Typography>{lineDetail.defectQty}</Typography>
  278. </TableCell>
  279. <TableCell>
  280. <Typography>{lineDetail.defectUom || "-"}</Typography>
  281. </TableCell>
  282. </TableRow>
  283. {/* Scrap */}
  284. <TableRow sx={{ bgcolor: 'error.50' }}>
  285. <TableCell>
  286. <Typography fontWeight={500} color="error.dark">{t("Scrap")}</Typography>
  287. </TableCell>
  288. <TableCell>
  289. <Typography>{lineDetail.scrapQty}</Typography>
  290. </TableCell>
  291. <TableCell>
  292. <Typography>{lineDetail.scrapUom || "-"}</Typography>
  293. </TableCell>
  294. </TableRow>
  295. </TableBody>
  296. </Table>
  297. </CardContent>
  298. </Card>
  299. ) : (
  300. <>
  301. {/* 如果未完成,显示原来的两个部分 */}
  302. {/* 当前步骤信息 */}
  303. {!showOutputTable && (
  304. <Grid container spacing={2} sx={{ mb: 3 }}>
  305. <Grid item xs={12} >
  306. <Card sx={{ bgcolor: 'primary.50', border: '2px solid', borderColor: 'primary.main', height: '100%' }}>
  307. <CardContent>
  308. <Typography variant="h6" color="primary.main" gutterBottom>
  309. {t("Executing")}: {lineDetail?.name} (Seq: {lineDetail?.seqNo})
  310. </Typography>
  311. <Typography variant="body2" color="text.secondary">
  312. {lineDetail?.description}
  313. </Typography>
  314. <Typography variant="body2" color="text.secondary">
  315. {t("Operator")}: {lineDetail?.operatorName || "-"}
  316. </Typography>
  317. <Typography variant="body2" color="text.secondary">
  318. {t("Equipment")}: {equipmentName}
  319. </Typography>
  320. <Stack direction="row" spacing={2} justifyContent="center" sx={{ mt: 2 }}>
  321. {/*
  322. <Button
  323. variant="contained"
  324. color="error"
  325. startIcon={<StopIcon />}
  326. onClick={handleStop}
  327. >
  328. {t("Stop")}
  329. </Button>
  330. {!isPaused ? (
  331. <Button
  332. variant="contained"
  333. color="warning"
  334. startIcon={<PauseIcon />}
  335. onClick={handlePause}
  336. >
  337. {t("Pause")}
  338. </Button>
  339. ) : (
  340. <Button
  341. variant="contained"
  342. color="success"
  343. startIcon={<PlayArrowIcon />}
  344. onClick={handleContinue}
  345. >
  346. {t("Continue")}
  347. </Button>
  348. )}
  349. */}
  350. <Button
  351. sx={{ mt: 2, alignSelf: "flex-end" }}
  352. variant="outlined"
  353. onClick={() => setShowOutputTable(true)}
  354. >
  355. {t("Order Complete")}
  356. </Button>
  357. </Stack>
  358. </CardContent>
  359. </Card>
  360. </Grid>
  361. </Grid>
  362. )}
  363. {/* ========== 产出输入表单 ========== */}
  364. {showOutputTable && (
  365. <Box>
  366. <Paper sx={{ p: 3, bgcolor: 'grey.50' }}>
  367. <Table size="small">
  368. <TableHead>
  369. <TableRow>
  370. <TableCell width="25%" align="center">{t("Type")}</TableCell>
  371. <TableCell width="25%" align="center">{t("Quantity")}</TableCell>
  372. <TableCell width="25%" align="center">{t("Unit")}</TableCell>
  373. <TableCell width="25%" align="center">{t(" ")}</TableCell>
  374. </TableRow>
  375. </TableHead>
  376. <TableBody>
  377. {/* start line output */}
  378. <TableRow>
  379. <TableCell>
  380. <Typography fontWeight={500}>{t("Output from Process")}</Typography>
  381. </TableCell>
  382. <TableCell>
  383. <TextField
  384. type="number"
  385. fullWidth
  386. size="small"
  387. value={outputData.outputFromProcessQty}
  388. onChange={(e) => setOutputData({
  389. ...outputData,
  390. outputFromProcessQty: parseInt(e.target.value) || 0
  391. })}
  392. />
  393. </TableCell>
  394. <TableCell>
  395. <TextField
  396. fullWidth
  397. size="small"
  398. value={outputData.outputFromProcessUom}
  399. onChange={(e) => setOutputData({
  400. ...outputData,
  401. outputFromProcessUom: e.target.value
  402. })}
  403. />
  404. </TableCell>
  405. <TableCell>
  406. <Typography fontSize={15} align="center"> <strong>{t("Description")}</strong></Typography>
  407. </TableCell>
  408. </TableRow>
  409. {/* byproduct */}
  410. {/*
  411. <TableRow>
  412. <TableCell>
  413. <Stack>
  414. <Typography fontWeight={500}>{t("By-product")}</Typography>
  415. </Stack>
  416. </TableCell>
  417. <TableCell>
  418. <TextField
  419. type="number"
  420. fullWidth
  421. size="small"
  422. value={outputData.byproductQty}
  423. onChange={(e) => setOutputData({
  424. ...outputData,
  425. byproductQty: parseInt(e.target.value) || 0
  426. })}
  427. />
  428. </TableCell>
  429. <TableCell>
  430. <TextField
  431. fullWidth
  432. size="small"
  433. value={outputData.byproductUom}
  434. onChange={(e) => setOutputData({
  435. ...outputData,
  436. byproductUom: e.target.value
  437. })}
  438. />
  439. </TableCell>
  440. </TableRow>
  441. */}
  442. {/* defect 1 */}
  443. <TableRow sx={{ bgcolor: 'warning.50' }}>
  444. <TableCell>
  445. <Typography fontWeight={500} color="warning.dark">{t("Defect")}{t("(1)")}</Typography>
  446. </TableCell>
  447. <TableCell>
  448. <TextField
  449. type="number"
  450. fullWidth
  451. size="small"
  452. value={outputData.defectQty}
  453. onChange={(e) => setOutputData({
  454. ...outputData,
  455. defectQty: parseInt(e.target.value) || 0
  456. })}
  457. />
  458. </TableCell>
  459. <TableCell>
  460. <TextField
  461. fullWidth
  462. size="small"
  463. value={outputData.defectUom}
  464. onChange={(e) => setOutputData({
  465. ...outputData,
  466. defectUom: e.target.value
  467. })}
  468. />
  469. </TableCell>
  470. <TableCell>
  471. <TextField
  472. fullWidth
  473. size="small"
  474. //value={outputData.defectUom}
  475. onChange={(e) => setOutputData({
  476. ...outputData,
  477. defectUom: e.target.value
  478. })}
  479. />
  480. </TableCell>
  481. </TableRow>
  482. {/* defect 2 */}
  483. <TableRow sx={{ bgcolor: 'warning.50' }}>
  484. <TableCell>
  485. <Typography fontWeight={500} color="warning.dark">{t("Defect")}{t("(2)")}</Typography>
  486. </TableCell>
  487. <TableCell>
  488. <TextField
  489. type="number"
  490. fullWidth
  491. size="small"
  492. value={outputData.defectQty}
  493. onChange={(e) => setOutputData({
  494. ...outputData,
  495. defectQty: parseInt(e.target.value) || 0
  496. })}
  497. />
  498. </TableCell>
  499. <TableCell>
  500. <TextField
  501. fullWidth
  502. size="small"
  503. value={outputData.defectUom}
  504. onChange={(e) => setOutputData({
  505. ...outputData,
  506. defectUom: e.target.value
  507. })}
  508. />
  509. </TableCell>
  510. <TableCell>
  511. <TextField
  512. fullWidth
  513. size="small"
  514. //value={outputData.defectUom}
  515. onChange={(e) => setOutputData({
  516. ...outputData,
  517. defectUom: e.target.value
  518. })}
  519. />
  520. </TableCell>
  521. </TableRow>
  522. {/* defect 3 */}
  523. <TableRow sx={{ bgcolor: 'warning.50' }}>
  524. <TableCell>
  525. <Typography fontWeight={500} color="warning.dark">{t("Defect")}{t("(3)")}</Typography>
  526. </TableCell>
  527. <TableCell>
  528. <TextField
  529. type="number"
  530. fullWidth
  531. size="small"
  532. value={outputData.defectQty}
  533. onChange={(e) => setOutputData({
  534. ...outputData,
  535. defectQty: parseInt(e.target.value) || 0
  536. })}
  537. />
  538. </TableCell>
  539. <TableCell>
  540. <TextField
  541. fullWidth
  542. size="small"
  543. value={outputData.defectUom}
  544. onChange={(e) => setOutputData({
  545. ...outputData,
  546. defectUom: e.target.value
  547. })}
  548. />
  549. </TableCell>
  550. <TableCell>
  551. <TextField
  552. fullWidth
  553. size="small"
  554. //value={outputData.defectUom}
  555. onChange={(e) => setOutputData({
  556. ...outputData,
  557. defectUom: e.target.value
  558. })}
  559. />
  560. </TableCell>
  561. </TableRow>
  562. {/* scrap */}
  563. <TableRow sx={{ bgcolor: 'error.50' }}>
  564. <TableCell>
  565. <Typography fontWeight={500} color="error.dark">{t("Scrap")}</Typography>
  566. </TableCell>
  567. <TableCell>
  568. <TextField
  569. type="number"
  570. fullWidth
  571. size="small"
  572. value={outputData.scrapQty}
  573. onChange={(e) => setOutputData({
  574. ...outputData,
  575. scrapQty: parseInt(e.target.value) || 0
  576. })}
  577. />
  578. </TableCell>
  579. <TableCell>
  580. <TextField
  581. fullWidth
  582. size="small"
  583. value={outputData.scrapUom}
  584. onChange={(e) => setOutputData({
  585. ...outputData,
  586. scrapUom: e.target.value
  587. })}
  588. />
  589. </TableCell>
  590. </TableRow>
  591. </TableBody>
  592. </Table>
  593. {/* submit button */}
  594. <Box sx={{ mt: 3, display: 'flex', gap: 2 }}>
  595. <Button
  596. variant="outlined"
  597. onClick={() => setShowOutputTable(false)}
  598. >
  599. {t("Cancel")}
  600. </Button>
  601. <Button
  602. variant="contained"
  603. startIcon={<CheckCircleIcon />}
  604. onClick={handleSubmitOutput}
  605. >
  606. {t("Complete Step")}
  607. </Button>
  608. </Box>
  609. </Paper>
  610. </Box>
  611. )}
  612. </>
  613. )}
  614. </Box>
  615. );
  616. };
  617. export default ProductionProcessStepExecution;