|
- "use client";
-
- import React, { useState } from "react";
- import {
- Box, Grid, Paper, Typography, Button, Dialog, DialogTitle,
- DialogContent, DialogActions, TextField, Stack, Table,
- 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 (
- <div
- role="tabpanel"
- hidden={value !== index}
- id={`simple-tabpanel-${index}`}
- aria-labelledby={`simple-tab-${index}`}
- {...other}
- >
- {value === index && (
- <Box sx={{ p: 3 }}>
- {children}
- </Box>
- )}
- </div>
- );
- }
-
- 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([
- { id: 1, itemCode: 'FG-001', itemName: 'Yellow Curry Sauce', lotNo: 'LOT-TSC-01', expiryDate: '2025-12-01' },
- { id: 2, itemCode: 'FG-002', itemName: 'Red Curry Paste', lotNo: 'LOT-TSC-02', expiryDate: '2025-12-05' },
- ]);
-
- // --- 2. DataFlex Section States ---
- const [dfConfig, setDfConfig] = useState({ ip: '192.168.1.101', port: '9100' });
- const [dfItems, setDfItems] = useState([
- { id: 1, itemCode: 'DF-101', itemName: 'Instant Noodle A', lotNo: 'LOT-DF-01', expiryDate: '2026-01-10' },
- { id: 2, itemCode: 'DF-102', itemName: 'Instant Noodle B', lotNo: 'LOT-DF-02', expiryDate: '2026-01-15' },
- ]);
-
- // --- 3. OnPack Section States ---
- const [isPrinterModalOpen, setIsPrinterModalOpen] = useState(false);
- const [printerFormData, setPrinterFormData] = useState({
- itemCode: '',
- lotNo: '',
- expiryDate: dayjs().format('YYYY-MM-DD'),
- productName: ''
- });
-
- // --- 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' },
- ]);
-
- // --- 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) => {
- setter((prev: any[]) => prev.map(item =>
- item.id === id ? { ...item, [field]: value } : item
- ));
- };
-
- // --- API CALLS ---
-
- // TSC Print (Section 1)
- const handleTscPrint = async (row: any) => {
- const token = localStorage.getItem("accessToken");
- const payload = { ...row, printerIp: tscConfig.ip, printerPort: tscConfig.port };
- try {
- const response = await fetch(`${NEXT_PUBLIC_API_URL}/plastic/print-tsc`, {
- method: 'POST',
- headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
- body: JSON.stringify(payload)
- });
- if (response.ok) alert(`TSC Print Command Sent for ${row.itemCode}!`);
- else alert("TSC Print Failed");
- } catch (e) { console.error("TSC Error:", e); }
- };
-
- // DataFlex Print (Section 2)
- const handleDfPrint = async (row: any) => {
- const token = localStorage.getItem("accessToken");
- const payload = { ...row, printerIp: dfConfig.ip, printerPort: dfConfig.port };
- try {
- const response = await fetch(`${NEXT_PUBLIC_API_URL}/plastic/print-dataflex`, {
- method: 'POST',
- headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
- body: JSON.stringify(payload)
- });
- if (response.ok) alert(`DataFlex Print Command Sent for ${row.itemCode}!`);
- else alert("DataFlex Print Failed");
- } catch (e) { console.error("DataFlex Error:", e); }
- };
-
- // OnPack Zip Download (Section 3)
- const handleDownloadPrintJob = async () => {
- const token = localStorage.getItem("accessToken");
- const params = new URLSearchParams(printerFormData);
- try {
- const response = await fetch(`${NEXT_PUBLIC_API_URL}/plastic/get-printer6?${params.toString()}`, {
- method: 'GET',
- headers: { 'Authorization': `Bearer ${token}` }
- });
-
- if (!response.ok) throw new Error('Download failed');
-
- const blob = await response.blob();
- const url = window.URL.createObjectURL(blob);
- const link = document.createElement('a');
- link.href = url;
- link.setAttribute('download', `${printerFormData.lotNo || 'OnPack'}.zip`);
- document.body.appendChild(link);
- link.click();
- link.remove();
- window.URL.revokeObjectURL(url);
-
- setIsPrinterModalOpen(false);
- } 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 };
- try {
- const response = await fetch(`${NEXT_PUBLIC_API_URL}/plastic/print-laser`, {
- method: 'POST',
- headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
- body: JSON.stringify(payload)
- });
- if (response.ok) alert(`Laser Command Sent: ${row.templateId}`);
- } catch (e) { console.error(e); }
- };
-
- const handleLaserPreview = async (row: any) => {
- const token = localStorage.getItem("accessToken");
- const payload = { ...row, printerIp: laserConfig.ip, printerPort: parseInt(laserConfig.port) };
- try {
- const response = await fetch(`${NEXT_PUBLIC_API_URL}/plastic/preview-laser`, {
- method: 'POST',
- headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
- body: JSON.stringify(payload)
- });
- if (response.ok) alert("Red light preview active!");
- } 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 }) => (
- <Paper sx={{ p: 3, minHeight: '450px', display: 'flex', flexDirection: 'column' }}>
- <Typography variant="h5" gutterBottom color="primary" sx={{ borderBottom: '2px solid #f0f0f0', pb: 1, mb: 2 }}>
- {title}
- </Typography>
- {children || <Typography color="textSecondary" sx={{ m: 'auto' }}>Waiting for implementation...</Typography>}
- </Paper>
- );
-
- return (
- <Box sx={{ p: 4 }}>
- <Typography variant="h4" sx={{ mb: 4, fontWeight: 'bold' }}>Printer Testing</Typography>
-
- <Tabs value={tabValue} onChange={handleTabChange} aria-label="printer sections tabs" centered variant="fullWidth">
- <Tab label="1. TSC" />
- <Tab label="2. DataFlex" />
- <Tab label="3. OnPack" />
- <Tab label="4. Laser" />
- <Tab label="5. HANS600S-M" />
- </Tabs>
-
- <TabPanel value={tabValue} index={0}>
- <Section title="1. TSC">
- <Stack direction="row" spacing={2} sx={{ mb: 2 }}>
- <TextField size="small" label="Printer IP" value={tscConfig.ip} onChange={e => setTscConfig({...tscConfig, ip: e.target.value})} />
- <TextField size="small" label="Port" value={tscConfig.port} onChange={e => setTscConfig({...tscConfig, port: e.target.value})} />
- <SettingsEthernet color="action" />
- </Stack>
- <TableContainer component={Paper} variant="outlined" sx={{ maxHeight: 300 }}>
- <Table size="small" stickyHeader>
- <TableHead>
- <TableRow>
- <TableCell>Code</TableCell>
- <TableCell>Name</TableCell>
- <TableCell>Lot</TableCell>
- <TableCell>Expiry</TableCell>
- <TableCell align="center">Action</TableCell>
- </TableRow>
- </TableHead>
- <TableBody>
- {tscItems.map(row => (
- <TableRow key={row.id}>
- <TableCell><TextField variant="standard" value={row.itemCode} onChange={e => handleItemChange(setTscItems, row.id, 'itemCode', e.target.value)} /></TableCell>
- <TableCell><TextField variant="standard" value={row.itemName} onChange={e => handleItemChange(setTscItems, row.id, 'itemName', e.target.value)} /></TableCell>
- <TableCell><TextField variant="standard" value={row.lotNo} onChange={e => handleItemChange(setTscItems, row.id, 'lotNo', e.target.value)} /></TableCell>
- <TableCell><TextField variant="standard" type="date" value={row.expiryDate} onChange={e => handleItemChange(setTscItems, row.id, 'expiryDate', e.target.value)} /></TableCell>
- <TableCell align="center"><Button variant="contained" size="small" startIcon={<Print />} onClick={() => handleTscPrint(row)}>Print</Button></TableCell>
- </TableRow>
- ))}
- </TableBody>
- </Table>
- </TableContainer>
- </Section>
- </TabPanel>
-
- <TabPanel value={tabValue} index={1}>
- <Section title="2. DataFlex">
- <Stack direction="row" spacing={2} sx={{ mb: 2 }}>
- <TextField size="small" label="Printer IP" value={dfConfig.ip} onChange={e => setDfConfig({...dfConfig, ip: e.target.value})} />
- <TextField size="small" label="Port" value={dfConfig.port} onChange={e => setDfConfig({...dfConfig, port: e.target.value})} />
- <Lan color="action" />
- </Stack>
- <TableContainer component={Paper} variant="outlined" sx={{ maxHeight: 300 }}>
- <Table size="small" stickyHeader>
- <TableHead>
- <TableRow>
- <TableCell>Code</TableCell>
- <TableCell>Name</TableCell>
- <TableCell>Lot</TableCell>
- <TableCell>Expiry</TableCell>
- <TableCell align="center">Action</TableCell>
- </TableRow>
- </TableHead>
- <TableBody>
- {dfItems.map(row => (
- <TableRow key={row.id}>
- <TableCell><TextField variant="standard" value={row.itemCode} onChange={e => handleItemChange(setDfItems, row.id, 'itemCode', e.target.value)} /></TableCell>
- <TableCell><TextField variant="standard" value={row.itemName} onChange={e => handleItemChange(setDfItems, row.id, 'itemName', e.target.value)} /></TableCell>
- <TableCell><TextField variant="standard" value={row.lotNo} onChange={e => handleItemChange(setDfItems, row.id, 'lotNo', e.target.value)} /></TableCell>
- <TableCell><TextField variant="standard" type="date" value={row.expiryDate} onChange={e => handleItemChange(setDfItems, row.id, 'expiryDate', e.target.value)} /></TableCell>
- <TableCell align="center"><Button variant="contained" color="secondary" size="small" startIcon={<Print />} onClick={() => handleDfPrint(row)}>Print</Button></TableCell>
- </TableRow>
- ))}
- </TableBody>
- </Table>
- </TableContainer>
- </Section>
- </TabPanel>
-
- <TabPanel value={tabValue} index={2}>
- <Section title="3. OnPack">
- <Box sx={{ m: 'auto', textAlign: 'center' }}>
- <Typography variant="body2" color="textSecondary" sx={{ mb: 2 }}>
- Calls /plastic/get-printer6 to generate CoLOS .job bundle.
- </Typography>
- <Button variant="contained" color="success" size="large" startIcon={<FileDownload />} onClick={() => setIsPrinterModalOpen(true)}>
- Generate CoLOS Files
- </Button>
- </Box>
- </Section>
- </TabPanel>
-
- <TabPanel value={tabValue} index={3}>
- <Section title="4. Laser">
- <Stack direction="row" spacing={2} sx={{ mb: 2 }}>
- <TextField size="small" label="Laser IP" value={laserConfig.ip} onChange={e => setLaserConfig({...laserConfig, ip: e.target.value})} />
- <TextField size="small" label="Port" value={laserConfig.port} onChange={e => setLaserConfig({...laserConfig, port: e.target.value})} />
- <Router color="action" />
- </Stack>
-
- <TableContainer component={Paper} variant="outlined" sx={{ maxHeight: 300 }}>
- <Table size="small" stickyHeader>
- <TableHead>
- <TableRow>
- <TableCell>Template</TableCell>
- <TableCell>Lot</TableCell>
- <TableCell>Exp</TableCell>
- <TableCell>Pwr%</TableCell>
- <TableCell align="center">Action</TableCell>
- </TableRow>
- </TableHead>
- <TableBody>
- {laserItems.map(row => (
- <TableRow key={row.id}>
- <TableCell><TextField variant="standard" value={row.templateId} onChange={e => handleItemChange(setLaserItems, row.id, 'templateId', e.target.value)} /></TableCell>
- <TableCell><TextField variant="standard" value={row.lotNo} onChange={e => handleItemChange(setLaserItems, row.id, 'lotNo', e.target.value)} /></TableCell>
- <TableCell><TextField variant="standard" type="date" value={row.expiryDate} onChange={e => handleItemChange(setLaserItems, row.id, 'expiryDate', e.target.value)} /></TableCell>
- <TableCell><TextField variant="standard" value={row.power} sx={{ width: 40 }} onChange={e => handleItemChange(setLaserItems, row.id, 'power', e.target.value)} /></TableCell>
- <TableCell align="center">
- <Stack direction="row" spacing={1} justifyContent="center">
- <Button
- variant="outlined"
- color="info"
- size="small"
- onClick={() => handleLaserPreview(row)}
- >
- Preview
- </Button>
- <Button
- variant="contained"
- color="warning"
- size="small"
- startIcon={<Print />}
- onClick={() => handleLaserPrint(row)}
- >
- Mark
- </Button>
- </Stack>
- </TableCell>
- </TableRow>
- ))}
- </TableBody>
- </Table>
- </TableContainer>
- <Typography variant="caption" sx={{ mt: 2, display: 'block', color: 'text.secondary' }}>
- Note: HANS Laser requires pre-saved templates on the controller.
- </Typography>
- </Section>
- </TabPanel>
-
- <TabPanel value={tabValue} index={4}>
- <Section title="5. HANS600S-M">
- <Stack direction="row" spacing={2} sx={{ mb: 2 }}>
- <TextField
- size="small"
- label="Laser IP"
- value={hansConfig.ip}
- onChange={e => setHansConfig({...hansConfig, ip: e.target.value})}
- />
- <TextField
- size="small"
- label="Port"
- value={hansConfig.port}
- onChange={e => setHansConfig({...hansConfig, port: e.target.value})}
- />
- <Router color="action" sx={{ ml: 'auto' }} />
- </Stack>
-
- <TableContainer component={Paper} variant="outlined" sx={{ maxHeight: 300 }}>
- <Table size="small" stickyHeader>
- <TableHead>
- <TableRow>
- <TableCell>Ch3 Text (SN)</TableCell>
- <TableCell>Ch4 Text (Batch)</TableCell>
- <TableCell>Obj3 Name</TableCell>
- <TableCell>Obj4 Name</TableCell>
- <TableCell align="center">Action</TableCell>
- </TableRow>
- </TableHead>
- <TableBody>
- {hansItems.map(row => (
- <TableRow key={row.id}>
- <TableCell>
- <TextField
- variant="standard"
- value={row.textChannel3}
- onChange={e => handleItemChange(setHansItems, row.id, 'textChannel3', e.target.value)}
- sx={{ minWidth: 180 }}
- />
- </TableCell>
- <TableCell>
- <TextField
- variant="standard"
- value={row.textChannel4}
- onChange={e => handleItemChange(setHansItems, row.id, 'textChannel4', e.target.value)}
- sx={{ minWidth: 140 }}
- />
- </TableCell>
- <TableCell>
- <TextField
- variant="standard"
- value={row.text3ObjectName}
- onChange={e => handleItemChange(setHansItems, row.id, 'text3ObjectName', e.target.value)}
- size="small"
- />
- </TableCell>
- <TableCell>
- <TextField
- variant="standard"
- value={row.text4ObjectName}
- onChange={e => handleItemChange(setHansItems, row.id, 'text4ObjectName', e.target.value)}
- size="small"
- />
- </TableCell>
- <TableCell align="center">
- <Button
- variant="contained"
- color="error"
- size="small"
- startIcon={<Print />}
- onClick={() => handleHansPrint(row)}
- sx={{ minWidth: 80 }}
- >
- TCP Mark
- </Button>
- </TableCell>
- </TableRow>
- ))}
- </TableBody>
- </Table>
- </TableContainer>
- <Typography variant="caption" sx={{ mt: 2, display: 'block', color: 'text.secondary', fontSize: '0.75rem' }}>
- TCP Push to EZCAD3 (Ch3/Ch4 via E3_SetTextObject) | IP:192.168.76.10:45678 | Backend: /print-laser-tcp
- </Typography>
- </Section>
- </TabPanel>
-
- {/* Dialog for OnPack */}
- <Dialog open={isPrinterModalOpen} onClose={() => setIsPrinterModalOpen(false)} fullWidth maxWidth="sm">
- <DialogTitle sx={{ bgcolor: 'success.main', color: 'white' }}>OnPack Printer Job Details</DialogTitle>
- <DialogContent sx={{ mt: 2 }}>
- <Stack spacing={3}>
- <TextField label="Item Code" fullWidth value={printerFormData.itemCode} onChange={(e) => setPrinterFormData({ ...printerFormData, itemCode: e.target.value })} />
- <TextField label="Lot Number" fullWidth value={printerFormData.lotNo} onChange={(e) => setPrinterFormData({ ...printerFormData, lotNo: e.target.value })} />
- <TextField label="Product Name" fullWidth value={printerFormData.productName} onChange={(e) => setPrinterFormData({ ...printerFormData, productName: e.target.value })} />
- <TextField label="Expiry Date" type="date" fullWidth InputLabelProps={{ shrink: true }} value={printerFormData.expiryDate} onChange={(e) => setPrinterFormData({ ...printerFormData, expiryDate: e.target.value })} />
- </Stack>
- </DialogContent>
- <DialogActions sx={{ p: 3 }}>
- <Button onClick={() => setIsPrinterModalOpen(false)} variant="outlined" color="inherit">Cancel</Button>
- <Button variant="contained" color="success" onClick={handleDownloadPrintJob}>Generate & Download</Button>
- </DialogActions>
- </Dialog>
- </Box>
- );
- }
|