자잘한 통신 오류 수정 및 모바일용 디자인 변경, connect 메뉴 별도 추가

This commit is contained in:
backuppc
2026-01-23 13:23:11 +09:00
parent 3396104011
commit abb32575f4
3 changed files with 408 additions and 359 deletions

63
App.tsx
View File

@@ -18,7 +18,7 @@ const App: React.FC = () => {
const [address, setAddress] = useState(0xFF); // Broadcast address default
// App State - Set Quick Test as Default
const [activeTab, setActiveTab] = useState<'inventory' | 'settings' | 'memory' | 'quicktest'>('quicktest');
const [activeTab, setActiveTab] = useState<'connect' | 'inventory' | 'settings' | 'memory' | 'quicktest'>('quicktest');
const [logs, setLogs] = useState<LogEntry[]>([]);
const [tags, setTags] = useState<TagData[]>([]);
const [isScanning, setIsScanning] = useState(false);
@@ -146,6 +146,7 @@ const App: React.FC = () => {
setStatus(ConnectionStatus.CONNECTED);
addLog('INFO', `Connected to serial port at ${baudRate}`);
setActiveTab('quicktest');
startReading(p);
} catch (err: any) {
console.error(err);
@@ -318,7 +319,7 @@ const App: React.FC = () => {
addLog('INFO', 'VERIFICATION SUCCESS: Data matches written value.');
performingQuickWriteRef.current = false;
verificationRetriesRef.current = 0;
alert("Quick Test Successful: Write verified.");
//alert("Quick Test Successful: Write verified.");
} else {
if (verificationRetriesRef.current < 5) {
verificationRetriesRef.current += 1;
@@ -614,9 +615,8 @@ const App: React.FC = () => {
};
const getLogHeightClass = () => {
if (isLogExpanded) return 'h-96';
if (activeTab === 'quicktest' || activeTab === 'settings') return 'h-12';
return 'h-48';
if (isLogExpanded) return 'h-[30vh]';
return 'h-12';
};
return (
@@ -632,6 +632,13 @@ const App: React.FC = () => {
</div>
<div className="p-4 space-y-2 flex-1">
<button
onClick={() => setActiveTab('connect')}
className={`w-full flex items-center gap-3 px-4 py-3 rounded-lg text-sm font-medium transition-colors ${activeTab === 'connect' ? 'bg-emerald-50 text-emerald-700' : 'text-slate-600 hover:bg-slate-50'
}`}
>
<Wifi className="w-5 h-5" /> Connection
</button>
<button
onClick={() => setActiveTab('quicktest')}
className={`w-full flex items-center gap-3 px-4 py-3 rounded-lg text-sm font-medium transition-colors ${activeTab === 'quicktest' ? 'bg-indigo-50 text-indigo-700' : 'text-slate-600 hover:bg-slate-50'
@@ -662,42 +669,26 @@ const App: React.FC = () => {
</button>
</div>
<div className="p-4 border-t border-slate-100">
<ConnectionPanel
status={status}
onConnect={connectSerial}
onDisconnect={disconnectSerial}
baudRate={baudRate}
setBaudRate={setBaudRate}
address={address}
setAddress={setAddress}
/>
</div>
{/* Connection Panel removed from here and moved to main content */}
</div>
{/* Main Content */}
<div className="flex-1 flex flex-col overflow-hidden relative">
{/* Mobile Top Navigation Bar */}
<div className="md:hidden bg-white border-b border-slate-200 p-2 flex items-center justify-between shrink-0 overflow-x-auto">
<div className="flex items-center gap-3 pr-4 border-r border-slate-100 mr-2 shrink-0">
<div className="flex items-center gap-1">
<div className="flex items-center gap-1 pr-4 border-r border-slate-100 mr-2 shrink-0">
<Database className="text-blue-600 w-5 h-5" />
<span className="font-bold text-slate-800 text-sm">UHF</span>
</div>
{/* Connection Status Indicator */}
<div className="flex items-center gap-1 flex-1 justify-around">
<button
onClick={() => setActiveTab('settings')}
className={`flex items-center gap-1 px-2 py-1 rounded-full text-xs font-medium transition-colors ${status === ConnectionStatus.CONNECTED
? 'bg-emerald-50 text-emerald-600 border border-emerald-100'
: 'bg-red-50 text-red-600 border border-red-100 animate-pulse'
onClick={() => setActiveTab('connect')}
className={`p-2 rounded-lg transition-colors flex flex-col items-center justify-center gap-1 ${activeTab === 'connect' ? 'bg-emerald-50 text-emerald-700' : 'text-slate-600 hover:bg-slate-50'
}`}
>
{status === ConnectionStatus.CONNECTED ? <Wifi className="w-3 h-3" /> : <WifiOff className="w-3 h-3" />}
<span>{status === ConnectionStatus.CONNECTED ? 'On' : 'Connect'}</span>
<Wifi className="w-5 h-5" />
<span className="text-[10px] font-medium leading-none">Connect</span>
</button>
</div>
<div className="flex items-center gap-1 flex-1 justify-around">
<button
onClick={() => setActiveTab('quicktest')}
className={`p-2 rounded-lg transition-colors flex flex-col items-center justify-center gap-1 ${activeTab === 'quicktest' ? 'bg-indigo-50 text-indigo-700' : 'text-slate-600 hover:bg-slate-50'
@@ -733,6 +724,22 @@ const App: React.FC = () => {
</div>
</div>
<main className="flex-1 p-6 overflow-auto">
{activeTab === 'connect' && (
<div className="space-y-4 max-w-2xl mx-auto">
<h2 className="text-lg font-bold text-slate-800">Connection Manager</h2>
<div className="bg-white rounded-xl border border-slate-200 shadow-sm p-6">
<ConnectionPanel
status={status}
onConnect={connectSerial}
onDisconnect={disconnectSerial}
baudRate={baudRate}
setBaudRate={setBaudRate}
address={address}
setAddress={setAddress}
/>
</div>
</div>
)}
{activeTab === 'inventory' && (
<InventoryPanel
tags={tags}

View File

@@ -35,35 +35,20 @@ export const QuickTestPanel: React.FC<Props> = ({
</div>
<h1 className="text-3xl font-bold text-slate-800 mb-2">Quick Test Mode</h1>
<p className="text-slate-500">
Automatically detects the first tag in the field and performs a Read or Write operation.<br/>
Target: <strong>EPC Bank</strong>, Start Address: <strong>2</strong><br/>
Length: <strong>{config.length} Words</strong>, Format: <strong>{config.format.toUpperCase()}</strong>
.
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 w-full">
{/* Read Card */}
{/* Read/Write Card */}
<div className="bg-white p-8 rounded-2xl shadow-sm border border-slate-200 hover:shadow-md transition-shadow flex flex-col items-center text-center">
<div className="mb-6 p-4 bg-blue-50 text-blue-600 rounded-full">
<HardDriveDownload className="w-8 h-8" />
</div>
<h2 className="text-xl font-bold text-slate-800 mb-2">Auto Read</h2>
<div className="w-full bg-slate-50 border border-slate-200 rounded-xl p-4 mb-6 min-h-[80px] flex items-center justify-center font-mono text-lg text-slate-700 break-all">
{isPending ? (
<div className="flex items-center gap-2 text-amber-500 animate-pulse">
<Activity className="w-5 h-5" /> Scanning & Reading...
</div>
) : (
result ? (
<span className="text-emerald-600 font-bold">{result}</span>
) : (
<span className="text-slate-300">No Data Read</span>
)
)}
</div>
{/* 1. Read Button */}
<div className="w-full mb-6">
{isPending ? (
<button
onClick={onCancel}
@@ -82,13 +67,22 @@ export const QuickTestPanel: React.FC<Props> = ({
)}
</div>
{/* Write Card */}
<div className="bg-white p-8 rounded-2xl shadow-sm border border-slate-200 hover:shadow-md transition-shadow flex flex-col items-center text-center">
<div className="mb-6 p-4 bg-purple-50 text-purple-600 rounded-full">
<HardDriveUpload className="w-8 h-8" />
{/* 2. Read Result Display */}
<div className="w-full bg-slate-50 border border-slate-200 rounded-xl p-4 mb-6 min-h-[80px] flex items-center justify-center font-mono text-lg text-slate-700 break-all">
{isPending ? (
<div className="flex items-center gap-2 text-amber-500 animate-pulse">
<Activity className="w-5 h-5" /> Scanning & Reading...
</div>
) : (
result ? (
<span className="text-emerald-600 font-bold">{result}</span>
) : (
<span className="text-slate-300">No Data Read</span>
)
)}
</div>
<h2 className="text-xl font-bold text-slate-800 mb-2">Auto Write</h2>
{/* 3. Write Input */}
<input
type="text"
value={writeInput}
@@ -97,6 +91,8 @@ export const QuickTestPanel: React.FC<Props> = ({
className="w-full bg-slate-50 border border-slate-300 text-center text-lg rounded-xl p-4 mb-6 font-mono focus:ring-2 focus:ring-purple-500 outline-none"
/>
{/* 4. Write Button */}
<div className="w-full">
{isPending ? (
<button
onClick={onCancel}
@@ -117,6 +113,46 @@ export const QuickTestPanel: React.FC<Props> = ({
</div>
{/* Info / Config Card */}
<div className="flex flex-col justify-center space-y-6">
<div className="bg-white p-6 rounded-2xl shadow-sm border border-slate-200 hover:shadow-md transition-shadow">
<h3 className="text-lg font-bold text-slate-800 mb-4 flex items-center gap-2">
<Zap className="w-5 h-5 text-indigo-500" />
Test Configuration
</h3>
<div className="space-y-4">
<div className="flex justify-between items-center p-3 bg-slate-50 rounded-lg">
<span className="text-slate-500 text-sm">Target Bank</span>
<span className="font-bold text-slate-700">EPC (01)</span>
</div>
<div className="flex justify-between items-center p-3 bg-slate-50 rounded-lg">
<span className="text-slate-500 text-sm">Start Address</span>
<span className="font-bold text-slate-700">2 (User Data)</span>
</div>
<div className="flex justify-between items-center p-3 bg-slate-50 rounded-lg">
<span className="text-slate-500 text-sm">Data Length</span>
<span className="font-bold text-slate-700">{config.length} Words</span>
</div>
<div className="flex justify-between items-center p-3 bg-slate-50 rounded-lg">
<span className="text-slate-500 text-sm">Format</span>
<span className="font-bold text-slate-700">{config.format.toUpperCase()}</span>
</div>
</div>
</div>
<div className="bg-indigo-50 p-6 rounded-2xl border border-indigo-100 text-sm text-indigo-800">
<h4 className="font-bold mb-2 flex items-center gap-2">
<AlertCircle className="w-4 h-4" />
Note
</h4>
<p>
(, ) <strong>Settings</strong> .
</p>
</div>
</div>
</div>
{isScanning && !isPending && (
<div className="mt-8 flex items-center gap-2 px-4 py-2 bg-amber-50 text-amber-700 border border-amber-200 rounded-full text-sm animate-pulse">
<Activity className="w-4 h-4" /> Background scanning is active in Inventory...

View File

@@ -90,83 +90,10 @@ export const SettingsPanel: React.FC<Props> = ({
<div className="mb-8 pb-6 border-b border-slate-100">
<h2 className="text-2xl font-bold text-slate-800">System Configuration</h2>
<p className="text-slate-500 mt-1">
Manage device parameters and local browser settings.
.
</p>
</div>
{/* 1. Quick Test Settings Card */}
<div className="mb-10">
<div className="flex items-center gap-2 mb-4">
<Settings2 className="w-5 h-5 text-indigo-600" />
<h3 className="text-lg font-bold text-slate-800">Quick Test Settings (Local)</h3>
</div>
<div className="bg-indigo-50/50 p-6 rounded-xl border border-indigo-100">
<p className="text-sm text-indigo-900 mb-6 border-l-4 border-indigo-400 pl-3">
These settings are stored in your browser's local storage and control the behavior of the "Quick Test" tab.
</p>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 mb-6">
<div className="space-y-3">
<label className="text-sm font-medium text-slate-600">Read/Write Length (Words)</label>
<div className="flex items-center gap-4">
<label className="flex items-center gap-2 cursor-pointer bg-white px-4 py-2 rounded-lg border border-indigo-100 shadow-sm">
<input
type="radio"
checked={qtLength === 3}
onChange={() => setQtLength(3)}
className="w-4 h-4 text-indigo-600 focus:ring-indigo-500 border-gray-300"
/>
<span className="text-sm text-slate-700">3 Words (6 Bytes)</span>
</label>
<label className="flex items-center gap-2 cursor-pointer bg-white px-4 py-2 rounded-lg border border-indigo-100 shadow-sm">
<input
type="radio"
checked={qtLength === 4}
onChange={() => setQtLength(4)}
className="w-4 h-4 text-indigo-600 focus:ring-indigo-500 border-gray-300"
/>
<span className="text-sm text-slate-700">4 Words (8 Bytes)</span>
</label>
</div>
</div>
<div className="space-y-3">
<label className="text-sm font-medium text-slate-600">Data Display Format</label>
<div className="flex items-center gap-4">
<label className="flex items-center gap-2 cursor-pointer bg-white px-4 py-2 rounded-lg border border-indigo-100 shadow-sm">
<input
type="radio"
checked={qtFormat === 'hex'}
onChange={() => setQtFormat('hex')}
className="w-4 h-4 text-indigo-600 focus:ring-indigo-500 border-gray-300"
/>
<span className="text-sm text-slate-700">HEX</span>
</label>
<label className="flex items-center gap-2 cursor-pointer bg-white px-4 py-2 rounded-lg border border-indigo-100 shadow-sm">
<input
type="radio"
checked={qtFormat === 'ascii'}
onChange={() => setQtFormat('ascii')}
className="w-4 h-4 text-indigo-600 focus:ring-indigo-500 border-gray-300"
/>
<span className="text-sm text-slate-700">ASCII</span>
</label>
</div>
</div>
</div>
<button
onClick={handleSaveLocalSettings}
className="flex items-center justify-center gap-2 px-5 py-2.5 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 shadow-sm hover:shadow transition-colors font-medium"
title="Save these settings to browser"
>
<Save className="w-4 h-4" />
Save Local Settings
</button>
</div>
</div>
<hr className="border-slate-100 mb-10" />
{/* 2. Reader Configuration */}
<div className="flex-1">
@@ -183,7 +110,7 @@ export const SettingsPanel: React.FC<Props> = ({
className="flex items-center justify-center gap-2 px-4 py-2 bg-slate-100 text-slate-700 border border-slate-200 rounded-lg hover:bg-slate-200 hover:text-slate-900 transition-all font-medium"
>
<RefreshCw className={`w-4 h-4 ${!isLoaded ? 'animate-pulse' : ''}`} />
Read Config
Read
</button>
<button
@@ -191,7 +118,7 @@ export const SettingsPanel: React.FC<Props> = ({
className="flex items-center justify-center gap-2 px-5 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 shadow-sm hover:shadow transition-colors font-medium"
>
<Save className="w-4 h-4" />
Apply Config
Write
</button>
<button
@@ -366,6 +293,85 @@ export const SettingsPanel: React.FC<Props> = ({
</div>
</div>
</div>
<hr className="border-slate-100 mb-10" />
{/* 1. Quick Test Settings Card */}
<div className="mb-10">
<div className="flex items-center gap-2 mb-4">
<Settings2 className="w-5 h-5 text-indigo-600" />
<h3 className="text-lg font-bold text-slate-800">Quick Test Settings (Local)</h3>
</div>
<div className="bg-indigo-50/50 p-6 rounded-xl border border-indigo-100">
<p className="text-sm text-indigo-900 mb-6 border-l-4 border-indigo-400 pl-3">
&quot;Quick Test&quot; .
</p>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 mb-6">
<div className="space-y-3">
<label className="text-sm font-medium text-slate-600">Read/Write Length (Words)</label>
<div className="flex items-center gap-4">
<label className="flex items-center gap-2 cursor-pointer bg-white px-4 py-2 rounded-lg border border-indigo-100 shadow-sm">
<input
type="radio"
checked={qtLength === 3}
onChange={() => setQtLength(3)}
className="w-4 h-4 text-indigo-600 focus:ring-indigo-500 border-gray-300"
/>
<span className="text-sm text-slate-700">3 Words</span>
</label>
<label className="flex items-center gap-2 cursor-pointer bg-white px-4 py-2 rounded-lg border border-indigo-100 shadow-sm">
<input
type="radio"
checked={qtLength === 4}
onChange={() => setQtLength(4)}
className="w-4 h-4 text-indigo-600 focus:ring-indigo-500 border-gray-300"
/>
<span className="text-sm text-slate-700">4 Words</span>
</label>
</div>
</div>
<div className="space-y-3">
<label className="text-sm font-medium text-slate-600">Data Display Format</label>
<div className="flex items-center gap-4">
<label className="flex items-center gap-2 cursor-pointer bg-white px-4 py-2 rounded-lg border border-indigo-100 shadow-sm">
<input
type="radio"
checked={qtFormat === 'hex'}
onChange={() => setQtFormat('hex')}
className="w-4 h-4 text-indigo-600 focus:ring-indigo-500 border-gray-300"
/>
<span className="text-sm text-slate-700">HEX</span>
</label>
<label className="flex items-center gap-2 cursor-pointer bg-white px-4 py-2 rounded-lg border border-indigo-100 shadow-sm">
<input
type="radio"
checked={qtFormat === 'ascii'}
onChange={() => setQtFormat('ascii')}
className="w-4 h-4 text-indigo-600 focus:ring-indigo-500 border-gray-300"
/>
<span className="text-sm text-slate-700">ASCII</span>
</label>
</div>
</div>
</div>
<button
onClick={handleSaveLocalSettings}
className="flex items-center justify-center gap-2 px-5 py-2.5 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 shadow-sm hover:shadow transition-colors font-medium"
title="Save these settings to browser"
>
<Save className="w-4 h-4" />
Save Local Settings
</button>
</div>
</div>
</div>
);
};