|
|
|
@@ -33,12 +33,16 @@ import { |
|
|
|
fetchProductProcessLines, |
|
|
|
updateProductProcessLineQrscan, |
|
|
|
fetchProductProcessLineDetail, |
|
|
|
ProductProcessLineDetailResponse, |
|
|
|
updateLineOutput, |
|
|
|
ProductProcessResponse, |
|
|
|
ProductProcessLineResponse, |
|
|
|
startProductProcessLine |
|
|
|
completeProductProcessLine, |
|
|
|
startProductProcessLine, |
|
|
|
fetchProductProcessesByJobOrderId |
|
|
|
} from "@/app/api/jo/actions"; |
|
|
|
import { fetchNameList, NameList } from "@/app/api/user/actions"; |
|
|
|
|
|
|
|
import ProductionProcessStepExecution from "./ProductionProcessStepExecution"; |
|
|
|
// 添加设备数据库(从 MachineScanner.tsx) |
|
|
|
const machineDatabase: Machine[] = [ |
|
|
|
{ id: 1, name: "CNC Mill #1", code: "CNC001", qrCode: "QR-CNC001" }, |
|
|
|
@@ -48,30 +52,14 @@ const machineDatabase: Machine[] = [ |
|
|
|
{ id: 5, name: "Drill Press #5", code: "DRL005", qrCode: "QR-DRL005" }, |
|
|
|
]; |
|
|
|
|
|
|
|
interface ProcessLine { |
|
|
|
id: number; |
|
|
|
seqNo: number; |
|
|
|
name: string; |
|
|
|
description?: string; |
|
|
|
equipmentType?: string; |
|
|
|
startTime?: string; |
|
|
|
endTime?: string; |
|
|
|
outputFromProcessQty?: number; |
|
|
|
outputFromProcessUom?: string; |
|
|
|
defectQty?: number; |
|
|
|
scrapQty?: number; |
|
|
|
byproductName?: string; |
|
|
|
byproductQty?: number; |
|
|
|
handlerId?: number; // 添加 handlerId |
|
|
|
} |
|
|
|
|
|
|
|
interface ProductProcessDetailProps { |
|
|
|
processId: number; |
|
|
|
jobOrderId: number; |
|
|
|
onBack: () => void; |
|
|
|
} |
|
|
|
|
|
|
|
const ProductionProcessDetail: React.FC<ProductProcessDetailProps> = ({ |
|
|
|
processId, |
|
|
|
jobOrderId, |
|
|
|
onBack, |
|
|
|
}) => { |
|
|
|
const { t } = useTranslation(); |
|
|
|
@@ -81,7 +69,7 @@ const ProductionProcessDetail: React.FC<ProductProcessDetailProps> = ({ |
|
|
|
|
|
|
|
// 基本信息 |
|
|
|
const [processData, setProcessData] = useState<any>(null); |
|
|
|
const [lines, setLines] = useState<ProcessLine[]>([]); |
|
|
|
const [lines, setLines] = useState<ProductProcessLineDetailResponse[]>([]); |
|
|
|
const [loading, setLoading] = useState(false); |
|
|
|
|
|
|
|
// 选中的 line 和执行状态 |
|
|
|
@@ -241,24 +229,34 @@ const ProductionProcessDetail: React.FC<ProductProcessDetailProps> = ({ |
|
|
|
const fetchProcessDetail = useCallback(async () => { |
|
|
|
setLoading(true); |
|
|
|
try { |
|
|
|
console.log(`🔍 Loading process detail for ID: ${processId}`); |
|
|
|
console.log(`🔍 Loading process detail for JobOrderId: ${jobOrderId}`); |
|
|
|
|
|
|
|
// 使用 fetchProductProcessesByJobOrderId 获取基础数据 |
|
|
|
const processesWithLines = await fetchProductProcessesByJobOrderId(jobOrderId); |
|
|
|
|
|
|
|
if (!processesWithLines || processesWithLines.length === 0) { |
|
|
|
throw new Error("No processes found for this job order"); |
|
|
|
} |
|
|
|
|
|
|
|
// 如果有多个 process,取第一个(或者可以根据需要选择) |
|
|
|
const currentProcess = processesWithLines[0]; |
|
|
|
|
|
|
|
const data = await fetchProductProcessLineDetail(processId); |
|
|
|
setProcessData(data); |
|
|
|
setProcessData(currentProcess); |
|
|
|
|
|
|
|
const linesData = await fetchProductProcessLineDetail(processId); |
|
|
|
setLines([linesData]); |
|
|
|
// 使用 productProcessLines 字段(API 返回的字段名) |
|
|
|
const lines = (currentProcess as any).productProcessLines || []; |
|
|
|
setLines(lines); |
|
|
|
|
|
|
|
console.log(" Process data loaded:", data); |
|
|
|
console.log(" Lines loaded:", linesData); |
|
|
|
console.log(" Process data loaded:", currentProcess); |
|
|
|
console.log(" Lines loaded:", lines); |
|
|
|
} catch (error) { |
|
|
|
console.error("❌ Error loading process detail:", error); |
|
|
|
alert(`无法加载生产流程 ID ${processId}。该记录可能不存在。`); |
|
|
|
//alert(`无法加载 Job Order ID ${jobOrderId} 的生产流程。该记录可能不存在。`); |
|
|
|
onBack(); |
|
|
|
} finally { |
|
|
|
setLoading(false); |
|
|
|
} |
|
|
|
}, [processId, onBack]); |
|
|
|
}, [jobOrderId, onBack]); |
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
fetchProcessDetail(); |
|
|
|
@@ -266,34 +264,13 @@ const ProductionProcessDetail: React.FC<ProductProcessDetailProps> = ({ |
|
|
|
|
|
|
|
// 开始执行某个 line |
|
|
|
const handleStartLine = async (lineId: number) => { |
|
|
|
if (!currentUserId) { |
|
|
|
alert("Please login first!"); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
// 使用 Server Action 而不是直接 fetch |
|
|
|
await startProductProcessLine(lineId, currentUserId); |
|
|
|
|
|
|
|
console.log(` Starting line ${lineId} with handlerId: ${currentUserId}`); |
|
|
|
setSelectedLineId(lineId); |
|
|
|
setIsExecutingLine(true); |
|
|
|
setScannedOperators([]); |
|
|
|
setScannedMachines([]); |
|
|
|
setOutputData({ |
|
|
|
byproductName: "", |
|
|
|
byproductQty: "", |
|
|
|
byproductUom: "", |
|
|
|
scrapQty: "", |
|
|
|
scrapUom: "", |
|
|
|
defectQty: "", |
|
|
|
defectUom: "", |
|
|
|
outputFromProcessQty: "", |
|
|
|
outputFromProcessUom: "", |
|
|
|
}); |
|
|
|
await startProductProcessLine(lineId); |
|
|
|
|
|
|
|
// 刷新数据 |
|
|
|
await fetchProcessDetail(); |
|
|
|
//await fetchProcessDetail(); |
|
|
|
} catch (error) { |
|
|
|
console.error("Error starting line:", error); |
|
|
|
alert("Failed to start line. Please try again."); |
|
|
|
@@ -310,31 +287,27 @@ const ProductionProcessDetail: React.FC<ProductProcessDetailProps> = ({ |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8090'}/product-process/lines/${selectedLineId}/output`, { |
|
|
|
method: 'PUT', |
|
|
|
headers: { 'Content-Type': 'application/json' }, |
|
|
|
body: JSON.stringify({ |
|
|
|
outputQty: parseFloat(outputData.outputFromProcessQty) || 0, |
|
|
|
outputUom: outputData.outputFromProcessUom, |
|
|
|
defectQty: parseFloat(outputData.defectQty) || 0, |
|
|
|
defectUom: outputData.defectUom, |
|
|
|
scrapQty: parseFloat(outputData.scrapQty) || 0, |
|
|
|
scrapUom: outputData.scrapUom, |
|
|
|
byproductName: outputData.byproductName, |
|
|
|
byproductQty: parseFloat(outputData.byproductQty) || 0, |
|
|
|
byproductUom: outputData.byproductUom, |
|
|
|
}), |
|
|
|
// 直接使用 actions.ts 中定义的函数 |
|
|
|
await updateLineOutput(selectedLineId, { |
|
|
|
outputQty: parseFloat(outputData.outputFromProcessQty) || 0, |
|
|
|
outputUom: outputData.outputFromProcessUom, |
|
|
|
defectQty: parseFloat(outputData.defectQty) || 0, |
|
|
|
defectUom: outputData.defectUom, |
|
|
|
scrapQty: parseFloat(outputData.scrapQty) || 0, |
|
|
|
scrapUom: outputData.scrapUom, |
|
|
|
byproductName: outputData.byproductName, |
|
|
|
byproductQty: parseFloat(outputData.byproductQty) || 0, |
|
|
|
byproductUom: outputData.byproductUom, |
|
|
|
}); |
|
|
|
|
|
|
|
if (response.ok) { |
|
|
|
console.log(" Output data submitted successfully"); |
|
|
|
setIsExecutingLine(false); |
|
|
|
setSelectedLineId(null); |
|
|
|
handleStopScan(); // 停止扫描 |
|
|
|
fetchProcessDetail(); // 刷新数据 |
|
|
|
} |
|
|
|
console.log(" Output data submitted successfully"); |
|
|
|
setIsExecutingLine(false); |
|
|
|
setSelectedLineId(null); |
|
|
|
handleStopScan(); |
|
|
|
await fetchProcessDetail(); |
|
|
|
} catch (error) { |
|
|
|
console.error("Error submitting output:", error); |
|
|
|
alert("Failed to submit output data. Please try again."); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
@@ -403,250 +376,101 @@ const ProductionProcessDetail: React.FC<ProductProcessDetailProps> = ({ |
|
|
|
<TableCell align="center">{t("Action")}</TableCell> |
|
|
|
</TableRow> |
|
|
|
</TableHead> |
|
|
|
<TableBody> |
|
|
|
{lines.map((line) => ( |
|
|
|
<TableRow key={line.id}> |
|
|
|
<TableCell>{line.seqNo}</TableCell> |
|
|
|
<TableCell> |
|
|
|
<Typography fontWeight={500}>{line.name}</Typography> |
|
|
|
</TableCell> |
|
|
|
<TableCell>{line.description}</TableCell> |
|
|
|
<TableCell>{line.equipmentType}</TableCell> |
|
|
|
<TableCell align="center"> |
|
|
|
{line.endTime ? ( |
|
|
|
<Chip label={t("Completed")} color="success" size="small" /> |
|
|
|
) : line.startTime ? ( |
|
|
|
<Chip label={t("In Progress")} color="primary" size="small" /> |
|
|
|
) : ( |
|
|
|
<Chip label={t("Pending")} color="default" size="small" /> |
|
|
|
)} |
|
|
|
</TableCell> |
|
|
|
<TableCell align="center"> |
|
|
|
<Button |
|
|
|
variant="contained" |
|
|
|
size="small" |
|
|
|
startIcon={<PlayArrowIcon />} |
|
|
|
onClick={() => handleStartLine(line.id)} |
|
|
|
disabled={!!line.endTime} |
|
|
|
> |
|
|
|
{line.endTime ? t("Completed") : t("Start")} |
|
|
|
</Button> |
|
|
|
</TableCell> |
|
|
|
</TableRow> |
|
|
|
))} |
|
|
|
</TableBody> |
|
|
|
</Table> |
|
|
|
</TableContainer> |
|
|
|
) : ( |
|
|
|
/* ========== 步骤执行视图 ========== */ |
|
|
|
<Box> |
|
|
|
{/* 当前步骤信息 */} |
|
|
|
<Card sx={{ mb: 3, bgcolor: 'primary.50', border: '2px solid', borderColor: 'primary.main' }}> |
|
|
|
<CardContent> |
|
|
|
<Typography variant="h6" color="primary.main" gutterBottom> |
|
|
|
{t("Executing")}: {selectedLine?.name} (Seq: {selectedLine?.seqNo}) |
|
|
|
</Typography> |
|
|
|
<Typography variant="body2" color="text.secondary"> |
|
|
|
{selectedLine?.description} |
|
|
|
</Typography> |
|
|
|
<Typography variant="body2" color="text.secondary"> |
|
|
|
{t("Equipment")}: {selectedLine?.equipmentType} |
|
|
|
</Typography> |
|
|
|
</CardContent> |
|
|
|
</Card> |
|
|
|
|
|
|
|
<Stack spacing={3}> |
|
|
|
{/* 合并的扫描器 */} |
|
|
|
<Paper sx={{ p: 3, mb: 3 }}> |
|
|
|
<Typography variant="h6" gutterBottom> |
|
|
|
{t("Scan Operator & Equipment")} |
|
|
|
</Typography> |
|
|
|
|
|
|
|
<Stack spacing={2}> |
|
|
|
{/* 操作员扫描 */} |
|
|
|
<Box> |
|
|
|
<Typography variant="body2" color="text.secondary"> |
|
|
|
{scannedOperators.length > 0 |
|
|
|
? `${t("Operator")}: ${scannedOperators[0].name || scannedOperators[0].username}` |
|
|
|
: t("Please scan operator code") |
|
|
|
} |
|
|
|
</Typography> |
|
|
|
</Box> |
|
|
|
|
|
|
|
{/* 设备扫描 */} |
|
|
|
<Box> |
|
|
|
<Typography variant="body2" color="text.secondary"> |
|
|
|
{scannedMachines.length > 0 |
|
|
|
? `${t("Equipment")}: ${scannedMachines[0].name || scannedMachines[0].code}` |
|
|
|
: t("Please scan equipment code") |
|
|
|
} |
|
|
|
</Typography> |
|
|
|
</Box> |
|
|
|
|
|
|
|
{/* 单个扫描按钮 */} |
|
|
|
<TableBody> |
|
|
|
{lines.map((line) => { |
|
|
|
const status = (line as any).status || ''; |
|
|
|
const statusLower = status.toLowerCase(); |
|
|
|
const equipmentName = (line as any).equipment_name || line.equipmentType || "-"; |
|
|
|
|
|
|
|
// 使用 status 字段判断状态 |
|
|
|
const isCompleted = statusLower === 'completed'; |
|
|
|
const isInProgress = statusLower === 'in_progress' || statusLower === 'in progress'; |
|
|
|
const isPending = statusLower === 'pending' || status === ''; |
|
|
|
|
|
|
|
return ( |
|
|
|
<TableRow key={line.id}> |
|
|
|
<TableCell>{line.seqNo}</TableCell> |
|
|
|
<TableCell> |
|
|
|
<Typography fontWeight={500}>{line.name}</Typography> |
|
|
|
</TableCell> |
|
|
|
<TableCell>{line.description || "-"}</TableCell> |
|
|
|
<TableCell>{equipmentName}</TableCell> |
|
|
|
<TableCell align="center"> |
|
|
|
{isCompleted ? ( |
|
|
|
<Chip label={t("Completed")} color="success" size="small" /> |
|
|
|
) : isInProgress ? ( |
|
|
|
<Chip label={t("In Progress")} color="primary" size="small" /> |
|
|
|
) : ( |
|
|
|
<Chip label={t("Pending")} color="default" size="small" /> |
|
|
|
)} |
|
|
|
</TableCell> |
|
|
|
<TableCell align="center"> |
|
|
|
{statusLower === 'pending' ? ( |
|
|
|
<Button |
|
|
|
variant={isManualScanning ? "outlined" : "contained"} |
|
|
|
startIcon={<QrCodeIcon />} |
|
|
|
onClick={isManualScanning ? handleStopScan : handleStartScan} |
|
|
|
color={isManualScanning ? "secondary" : "primary"} |
|
|
|
variant="contained" |
|
|
|
size="small" |
|
|
|
startIcon={<PlayArrowIcon />} |
|
|
|
onClick={async () => { |
|
|
|
await handleStartLine(line.id); |
|
|
|
setSelectedLineId(line.id); |
|
|
|
setIsExecutingLine(true); |
|
|
|
await fetchProcessDetail(); |
|
|
|
}} |
|
|
|
> |
|
|
|
{isManualScanning ? t("Stop QR Scan") : t("Start QR Scan")} |
|
|
|
{t("Start")} |
|
|
|
</Button> |
|
|
|
</Stack> |
|
|
|
</Paper> |
|
|
|
|
|
|
|
{/* ========== 产出输入表单 ========== */} |
|
|
|
{scannedOperators.length > 0 && scannedMachines.length > 0 && ( |
|
|
|
<Paper sx={{ p: 3, bgcolor: 'grey.50' }}> |
|
|
|
<Typography variant="h6" gutterBottom fontWeight={600}> |
|
|
|
{t("Production Output Data Entry")} |
|
|
|
</Typography> |
|
|
|
|
|
|
|
<Table size="small"> |
|
|
|
<TableHead> |
|
|
|
<TableRow> |
|
|
|
<TableCell width="30%">{t("Type")}</TableCell> |
|
|
|
<TableCell width="35%">{t("Quantity")}</TableCell> |
|
|
|
<TableCell width="35%">{t("Unit of Measure")}</TableCell> |
|
|
|
</TableRow> |
|
|
|
</TableHead> |
|
|
|
<TableBody> |
|
|
|
{/* 步骤收成 */} |
|
|
|
<TableRow> |
|
|
|
<TableCell> |
|
|
|
<Typography fontWeight={500}>{t("Output from Process")}</Typography> |
|
|
|
</TableCell> |
|
|
|
<TableCell> |
|
|
|
<TextField |
|
|
|
type="number" |
|
|
|
fullWidth |
|
|
|
size="small" |
|
|
|
value={outputData.outputFromProcessQty} |
|
|
|
onChange={(e) => setOutputData(prev => ({ ...prev, outputFromProcessQty: e.target.value }))} |
|
|
|
/> |
|
|
|
</TableCell> |
|
|
|
<TableCell> |
|
|
|
<TextField |
|
|
|
fullWidth |
|
|
|
size="small" |
|
|
|
value={outputData.outputFromProcessUom} |
|
|
|
onChange={(e) => setOutputData(prev => ({ ...prev, outputFromProcessUom: e.target.value }))} |
|
|
|
placeholder="KG, L, PCS..." |
|
|
|
/> |
|
|
|
</TableCell> |
|
|
|
</TableRow> |
|
|
|
|
|
|
|
{/* 副产品 */} |
|
|
|
<TableRow> |
|
|
|
<TableCell> |
|
|
|
<Stack> |
|
|
|
<Typography fontWeight={500}>{t("By-product")}</Typography> |
|
|
|
<TextField |
|
|
|
fullWidth |
|
|
|
size="small" |
|
|
|
value={outputData.byproductName} |
|
|
|
onChange={(e) => setOutputData(prev => ({ ...prev, byproductName: e.target.value }))} |
|
|
|
placeholder={t("By-product name")} |
|
|
|
sx={{ mt: 1 }} |
|
|
|
/> |
|
|
|
</Stack> |
|
|
|
</TableCell> |
|
|
|
<TableCell> |
|
|
|
<TextField |
|
|
|
type="number" |
|
|
|
fullWidth |
|
|
|
size="small" |
|
|
|
value={outputData.byproductQty} |
|
|
|
onChange={(e) => setOutputData(prev => ({ ...prev, byproductQty: e.target.value }))} |
|
|
|
/> |
|
|
|
</TableCell> |
|
|
|
<TableCell> |
|
|
|
<TextField |
|
|
|
fullWidth |
|
|
|
size="small" |
|
|
|
value={outputData.byproductUom} |
|
|
|
onChange={(e) => setOutputData(prev => ({ ...prev, byproductUom: e.target.value }))} |
|
|
|
placeholder="KG, L, PCS..." |
|
|
|
/> |
|
|
|
</TableCell> |
|
|
|
</TableRow> |
|
|
|
|
|
|
|
{/* 次品 */} |
|
|
|
<TableRow sx={{ bgcolor: 'warning.50' }}> |
|
|
|
<TableCell> |
|
|
|
<Typography fontWeight={500} color="warning.dark">{t("Defect")}</Typography> |
|
|
|
</TableCell> |
|
|
|
<TableCell> |
|
|
|
<TextField |
|
|
|
type="number" |
|
|
|
fullWidth |
|
|
|
size="small" |
|
|
|
value={outputData.defectQty} |
|
|
|
onChange={(e) => setOutputData(prev => ({ ...prev, defectQty: e.target.value }))} |
|
|
|
/> |
|
|
|
</TableCell> |
|
|
|
<TableCell> |
|
|
|
<TextField |
|
|
|
fullWidth |
|
|
|
size="small" |
|
|
|
value={outputData.defectUom} |
|
|
|
onChange={(e) => setOutputData(prev => ({ ...prev, defectUom: e.target.value }))} |
|
|
|
placeholder="KG, L, PCS..." |
|
|
|
/> |
|
|
|
</TableCell> |
|
|
|
</TableRow> |
|
|
|
|
|
|
|
{/* 废品 */} |
|
|
|
<TableRow sx={{ bgcolor: 'error.50' }}> |
|
|
|
<TableCell> |
|
|
|
<Typography fontWeight={500} color="error.dark">{t("Scrap")}</Typography> |
|
|
|
</TableCell> |
|
|
|
<TableCell> |
|
|
|
<TextField |
|
|
|
type="number" |
|
|
|
fullWidth |
|
|
|
size="small" |
|
|
|
value={outputData.scrapQty} |
|
|
|
onChange={(e) => setOutputData(prev => ({ ...prev, scrapQty: e.target.value }))} |
|
|
|
/> |
|
|
|
</TableCell> |
|
|
|
<TableCell> |
|
|
|
<TextField |
|
|
|
fullWidth |
|
|
|
size="small" |
|
|
|
value={outputData.scrapUom} |
|
|
|
onChange={(e) => setOutputData(prev => ({ ...prev, scrapUom: e.target.value }))} |
|
|
|
placeholder="KG, L, PCS..." |
|
|
|
/> |
|
|
|
</TableCell> |
|
|
|
</TableRow> |
|
|
|
</TableBody> |
|
|
|
</Table> |
|
|
|
|
|
|
|
{/* 提交按钮 */} |
|
|
|
<Box sx={{ mt: 3, display: 'flex', gap: 2 }}> |
|
|
|
): |
|
|
|
statusLower === 'in_progress' || statusLower === 'in progress' ? ( |
|
|
|
<Button |
|
|
|
variant="contained" |
|
|
|
size="small" |
|
|
|
startIcon={<CheckCircleIcon />} |
|
|
|
onClick={async () => { |
|
|
|
setSelectedLineId(line.id); |
|
|
|
setIsExecutingLine(true); |
|
|
|
await fetchProcessDetail(); |
|
|
|
}} |
|
|
|
> |
|
|
|
{t("View")} |
|
|
|
</Button> |
|
|
|
):( |
|
|
|
<Button |
|
|
|
variant="outlined" |
|
|
|
onClick={() => { |
|
|
|
setIsExecutingLine(false); |
|
|
|
setSelectedLineId(null); |
|
|
|
handleStopScan(); |
|
|
|
size="small" |
|
|
|
onClick={async() => { |
|
|
|
setSelectedLineId(line.id); |
|
|
|
setIsExecutingLine(true); |
|
|
|
await fetchProcessDetail(); |
|
|
|
}} |
|
|
|
> |
|
|
|
{t("Cancel")} |
|
|
|
</Button> |
|
|
|
<Button |
|
|
|
variant="contained" |
|
|
|
startIcon={<CheckCircleIcon />} |
|
|
|
onClick={handleSubmitOutput} |
|
|
|
> |
|
|
|
{t("Complete Step")} |
|
|
|
{t("View")} |
|
|
|
</Button> |
|
|
|
</Box> |
|
|
|
</Paper> |
|
|
|
)} |
|
|
|
</Stack> |
|
|
|
</Box> |
|
|
|
)} |
|
|
|
</TableCell> |
|
|
|
</TableRow> |
|
|
|
);})} |
|
|
|
</TableBody> |
|
|
|
</Table> |
|
|
|
</TableContainer> |
|
|
|
) : ( |
|
|
|
/* ========== 步骤执行视图 ========== */ |
|
|
|
<ProductionProcessStepExecution |
|
|
|
selectedLine={selectedLine} |
|
|
|
scannedOperators={scannedOperators} |
|
|
|
scannedMachines={scannedMachines} |
|
|
|
isManualScanning={isManualScanning} |
|
|
|
outputData={outputData} |
|
|
|
onStartScan={handleStartScan} |
|
|
|
onStopScan={handleStopScan} |
|
|
|
onCancel={() => { |
|
|
|
setIsExecutingLine(false); |
|
|
|
setSelectedLineId(null); |
|
|
|
handleStopScan(); |
|
|
|
fetchProcessDetail(); |
|
|
|
}} |
|
|
|
onSubmitOutput={handleSubmitOutput} |
|
|
|
onOutputDataChange={(data) => setOutputData({...outputData, ...data})} |
|
|
|
/> |
|
|
|
)} |
|
|
|
</Paper> |
|
|
|
</Box> |
|
|
|
|