- Add VisionMenu component with Camera (QRCode) and Barcode (Keyence) submenus - Remove old CameraPanel component and replace with dropdown menu structure - Add ProcessedDataPanel to display processed data in bottom dock (5 rows visible) - Create SystemStatusPanel component with horizontal button layout (START/STOP/RESET) - Create EventLogPanel component for better code organization - Add device initialization feature with 7-axis progress tracking - Add GetProcessedData and GetInitializeStatus backend methods - Update Header menu layout to vertical (icon on top, text below) for more space - Update HomePage layout with bottom-docked ProcessedDataPanel - Refactor HomePage to use new modular components 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
134 lines
7.0 KiB
TypeScript
134 lines
7.0 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
|
import { Database, RefreshCw } from 'lucide-react';
|
|
import { comms } from '../communication';
|
|
import { ProcessedDataRow } from '../types';
|
|
import { PanelHeader } from './common/PanelHeader';
|
|
import { CyberPanel } from './common/CyberPanel';
|
|
|
|
export const ProcessedDataPanel: React.FC = () => {
|
|
const [data, setData] = useState<ProcessedDataRow[]>([]);
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
const loadData = async () => {
|
|
setLoading(true);
|
|
try {
|
|
const dataJson = await comms.getProcessedData();
|
|
const parsedData = JSON.parse(dataJson) as ProcessedDataRow[];
|
|
// Display only the first 5 rows
|
|
setData(parsedData.slice(0, 5));
|
|
} catch (error) {
|
|
console.error('[ProcessedDataPanel] Failed to load data:', error);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
loadData();
|
|
// Refresh every 5 seconds
|
|
const interval = setInterval(loadData, 5000);
|
|
return () => clearInterval(interval);
|
|
}, []);
|
|
|
|
const getRowBackgroundColor = (row: ProcessedDataRow) => {
|
|
if (row.REMARK.startsWith('(BYPASS')) {
|
|
return 'bg-sky-300/20';
|
|
}
|
|
return row.LOC === 'L' ? 'bg-slate-700/20' : 'bg-slate-800/10';
|
|
};
|
|
|
|
const getRowTextColor = (row: ProcessedDataRow) => {
|
|
if (row.REMARK.startsWith('(BYPASS')) {
|
|
return 'text-white';
|
|
}
|
|
if (!row.PRNATTACH) {
|
|
return 'text-red-500';
|
|
}
|
|
if (!row.PRNVALID) {
|
|
return 'text-emerald-900';
|
|
}
|
|
return 'text-slate-200';
|
|
};
|
|
|
|
return (
|
|
<CyberPanel className="flex flex-col h-full">
|
|
<PanelHeader
|
|
icon={Database}
|
|
title="PROCESSED DATA"
|
|
className="mb-3"
|
|
>
|
|
<button
|
|
onClick={loadData}
|
|
disabled={loading}
|
|
className="p-1.5 hover:bg-white/10 rounded transition-colors disabled:opacity-50"
|
|
title="Refresh"
|
|
>
|
|
<RefreshCw className={`w-4 h-4 ${loading ? 'animate-spin' : ''}`} />
|
|
</button>
|
|
</PanelHeader>
|
|
|
|
<div className="flex-1 overflow-auto">
|
|
<table className="w-full text-xs border-collapse">
|
|
<thead className="sticky top-0 bg-slate-900/90 backdrop-blur-sm z-10">
|
|
<tr className="border-b border-neon-blue/30">
|
|
<th className="px-2 py-1.5 text-left font-tech text-neon-blue">R</th>
|
|
<th className="px-2 py-1.5 text-left font-tech text-neon-blue">MODEL</th>
|
|
<th className="px-2 py-1.5 text-left font-tech text-neon-blue">START</th>
|
|
<th className="px-2 py-1.5 text-left font-tech text-neon-blue">BATCH</th>
|
|
<th className="px-2 py-1.5 text-left font-tech text-neon-blue">SID</th>
|
|
<th className="px-2 py-1.5 text-left font-tech text-neon-blue">RID</th>
|
|
<th className="px-2 py-1.5 text-left font-tech text-neon-blue">VENDER</th>
|
|
<th className="px-2 py-1.5 text-right font-tech text-neon-blue">QTY</th>
|
|
<th className="px-2 py-1.5 text-right font-tech text-neon-blue">(MAX)</th>
|
|
<th className="px-2 py-1.5 text-left font-tech text-neon-blue">MFG</th>
|
|
<th className="px-2 py-1.5 text-left font-tech text-neon-blue">V.LOT</th>
|
|
<th className="px-2 py-1.5 text-left font-tech text-neon-blue">PARTNO</th>
|
|
<th className="px-2 py-1.5 text-left font-tech text-neon-blue">CPN</th>
|
|
<th className="px-2 py-1.5 text-left font-tech text-neon-blue">Remark</th>
|
|
<th className="px-2 py-1.5 text-center font-tech text-neon-blue">Attach</th>
|
|
<th className="px-2 py-1.5 text-center font-tech text-neon-blue">Valid</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{data.length === 0 ? (
|
|
<tr>
|
|
<td colSpan={16} className="px-2 py-8 text-center text-slate-500 font-mono text-xs">
|
|
{loading ? 'Loading...' : 'No data available'}
|
|
</td>
|
|
</tr>
|
|
) : (
|
|
data.map((row, index) => (
|
|
<tr
|
|
key={index}
|
|
className={`border-b border-white/5 ${getRowBackgroundColor(row)} ${getRowTextColor(row)} hover:bg-white/5 transition-colors`}
|
|
>
|
|
<td className="px-2 py-1.5 font-mono text-center">{row.target}</td>
|
|
<td className="px-2 py-1.5 font-mono">{row.JTYPE}</td>
|
|
<td className="px-2 py-1.5 font-mono">{row.STIME}</td>
|
|
<td className="px-2 py-1.5 font-mono">{row.BATCH}</td>
|
|
<td className="px-2 py-1.5 font-mono font-bold">{row.SID}</td>
|
|
<td className="px-2 py-1.5 font-mono font-bold">{row.RID}</td>
|
|
<td className="px-2 py-1.5 font-mono text-center">{row.VNAME}</td>
|
|
<td className="px-2 py-1.5 font-mono text-right">{row.QTY.toLocaleString()}</td>
|
|
<td className="px-2 py-1.5 font-mono text-right">{row.qtymax.toLocaleString()}</td>
|
|
<td className="px-2 py-1.5 font-mono text-center">{row.MFGDATE}</td>
|
|
<td className="px-2 py-1.5 font-mono">{row.VLOT}</td>
|
|
<td className="px-2 py-1.5 font-mono">{row.PARTNO}</td>
|
|
<td className="px-2 py-1.5 font-mono">{row.MCN}</td>
|
|
<td className="px-2 py-1.5 font-mono">{row.REMARK}</td>
|
|
<td className="px-2 py-1.5 text-center">
|
|
<span className={`inline-block w-3 h-3 rounded-full ${row.PRNATTACH ? 'bg-neon-green' : 'bg-red-500'}`} />
|
|
</td>
|
|
<td className="px-2 py-1.5 text-center">
|
|
<span className={`inline-block w-3 h-3 rounded-full ${row.PRNVALID ? 'bg-neon-green' : 'bg-red-500'}`} />
|
|
</td>
|
|
</tr>
|
|
))
|
|
)}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</CyberPanel>
|
|
);
|
|
};
|