diff --git a/src/app/(main)/testing/page.tsx b/src/app/(main)/testing/page.tsx index 4c64f92..3efaf70 100644 --- a/src/app/(main)/testing/page.tsx +++ b/src/app/(main)/testing/page.tsx @@ -4,13 +4,47 @@ import React, { useState } from "react"; import { Box, Grid, Paper, Typography, Button, Dialog, DialogTitle, DialogContent, DialogActions, TextField, Stack, Table, - TableBody, TableCell, TableContainer, TableHead, TableRow + TableBody, TableCell, TableContainer, TableHead, TableRow, + Tabs, Tab // ← Added for tabs } from "@mui/material"; import { FileDownload, Print, SettingsEthernet, Lan, Router } from "@mui/icons-material"; import dayjs from "dayjs"; import { NEXT_PUBLIC_API_URL } from "@/config/api"; +// Simple TabPanel component for conditional rendering +interface TabPanelProps { + children?: React.ReactNode; + index: number; + value: number; +} + +function TabPanel(props: TabPanelProps) { + const { children, value, index, ...other } = props; + return ( + + ); +} + export default function TestingPage() { + // Tab state + const [tabValue, setTabValue] = useState(0); + + const handleTabChange = (event: React.SyntheticEvent, newValue: number) => { + setTabValue(newValue); + }; + // --- 1. TSC Section States --- const [tscConfig, setTscConfig] = useState({ ip: '192.168.1.100', port: '9100' }); const [tscItems, setTscItems] = useState([ @@ -35,10 +69,22 @@ export default function TestingPage() { }); // --- 4. Laser Section States --- -const [laserConfig, setLaserConfig] = useState({ ip: '192.168.1.102', port: '8080' }); -const [laserItems, setLaserItems] = useState([ - { id: 1, templateId: 'JOB_001', lotNo: 'L-LASER-01', expiryDate: '2025-12-31', power: '50' }, -]); + const [laserConfig, setLaserConfig] = useState({ ip: '192.168.1.102', port: '8080' }); + const [laserItems, setLaserItems] = useState([ + { id: 1, templateId: 'JOB_001', lotNo: 'L-LASER-01', expiryDate: '2025-12-31', power: '50' }, + ]); + + // --- 5. HANS600S-M Section States --- + const [hansConfig, setHansConfig] = useState({ ip: '192.168.76.10', port: '45678' }); + const [hansItems, setHansItems] = useState([ + { + id: 1, + textChannel3: 'SN-HANS-001-20260117', // channel 3 (e.g. serial / text1) + textChannel4: 'BATCH-HK-TEST-OK', // channel 4 (e.g. batch / text2) + text3ObjectName: 'Text3', // EZCAD object name for channel 3 + text4ObjectName: 'Text4' // EZCAD object name for channel 4 + }, + ]); // Generic handler for inline table edits const handleItemChange = (setter: any, id: number, field: string, value: string) => { @@ -105,6 +151,7 @@ const [laserItems, setLaserItems] = useState([ } catch (e) { console.error("OnPack Error:", e); } }; + // Laser Print (Section 4 - original) const handleLaserPrint = async (row: any) => { const token = localStorage.getItem("accessToken"); const payload = { ...row, printerIp: laserConfig.ip, printerPort: laserConfig.port }; @@ -122,7 +169,6 @@ const [laserItems, setLaserItems] = useState([ const token = localStorage.getItem("accessToken"); const payload = { ...row, printerIp: laserConfig.ip, printerPort: parseInt(laserConfig.port) }; try { - // We'll create this endpoint in the backend next const response = await fetch(`${NEXT_PUBLIC_API_URL}/plastic/preview-laser`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, @@ -132,24 +178,58 @@ const [laserItems, setLaserItems] = useState([ } catch (e) { console.error("Preview Error:", e); } }; + // HANS600S-M TCP Print (Section 5) + const handleHansPrint = async (row: any) => { + const token = localStorage.getItem("accessToken"); + const payload = { + printerIp: hansConfig.ip, + printerPort: hansConfig.port, + textChannel3: row.textChannel3, + textChannel4: row.textChannel4, + text3ObjectName: row.text3ObjectName, + text4ObjectName: row.text4ObjectName + }; + try { + const response = await fetch(`${NEXT_PUBLIC_API_URL}/plastic/print-laser-tcp`, { + method: 'POST', + headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, + body: JSON.stringify(payload) + }); + const result = await response.text(); + if (response.ok) { + alert(`HANS600S-M Mark Success: ${result}`); + } else { + alert(`HANS600S-M Failed: ${result}`); + } + } catch (e) { + console.error("HANS600S-M Error:", e); + alert("HANS600S-M Connection Error"); + } + }; + // Layout Helper const Section = ({ title, children }: { title: string, children?: React.ReactNode }) => ( - - - - {title} - - {children || Waiting for implementation...} - - + + + {title} + + {children || Waiting for implementation...} + ); return ( - Printer Testing Dashboard + Printer Testing - - {/* 1. TSC Section */} + + + + + + + + +
setTscConfig({...tscConfig, ip: e.target.value})} /> @@ -181,8 +261,9 @@ const [laserItems, setLaserItems] = useState([
+
- {/* 2. DataFlex Section */} +
setDfConfig({...dfConfig, ip: e.target.value})} /> @@ -214,8 +295,9 @@ const [laserItems, setLaserItems] = useState([
+
- {/* 3. OnPack Section */} +
@@ -226,8 +308,9 @@ const [laserItems, setLaserItems] = useState([
+
- {/* 4. Laser Section (HANS600S-M) */} +
setLaserConfig({...laserConfig, ip: e.target.value})} /> @@ -283,7 +366,94 @@ const [laserItems, setLaserItems] = useState([ Note: HANS Laser requires pre-saved templates on the controller.
-
+ + + +
+ + setHansConfig({...hansConfig, ip: e.target.value})} + /> + setHansConfig({...hansConfig, port: e.target.value})} + /> + + + + + + + + Ch3 Text (SN) + Ch4 Text (Batch) + Obj3 Name + Obj4 Name + Action + + + + {hansItems.map(row => ( + + + handleItemChange(setHansItems, row.id, 'textChannel3', e.target.value)} + sx={{ minWidth: 180 }} + /> + + + handleItemChange(setHansItems, row.id, 'textChannel4', e.target.value)} + sx={{ minWidth: 140 }} + /> + + + handleItemChange(setHansItems, row.id, 'text3ObjectName', e.target.value)} + size="small" + /> + + + handleItemChange(setHansItems, row.id, 'text4ObjectName', e.target.value)} + size="small" + /> + + + + + + ))} + +
+
+ + TCP Push to EZCAD3 (Ch3/Ch4 via E3_SetTextObject) | IP:192.168.76.10:45678 | Backend: /print-laser-tcp + +
+
{/* Dialog for OnPack */} setIsPrinterModalOpen(false)} fullWidth maxWidth="sm"> diff --git a/src/components/NavigationContent/NavigationContent.tsx b/src/components/NavigationContent/NavigationContent.tsx index 6161151..d2de191 100644 --- a/src/components/NavigationContent/NavigationContent.tsx +++ b/src/components/NavigationContent/NavigationContent.tsx @@ -247,7 +247,7 @@ const NavigationContent: React.FC = () => { icon: , label: "PS", path: "/ps", - requiredAbility: AUTH.TESTING, + requiredAbility: [AUTH.TESTING, AUTH.ADMIN], isHidden: false, }, {