feat: COM-port support for workstation devices + agent UI fixes
- EquipmentPage: add COM-port connection type with port field (COM1, /dev/ttyUSB0) - api.ts: add comPort field to WorkstationDevice type - workstations route: pass com_port to INSERT/PATCH - migration 042: extend connection check constraint to include 'com', add com_port column - agent index.html: highlight first cell on load, reset input on unpair Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { useState, useEffect, useCallback } from 'react'
|
||||
import {
|
||||
Monitor, Plus, Trash2, Pencil, Check, X, RefreshCw,
|
||||
Wifi, WifiOff, Printer, CreditCard, Usb, Network,
|
||||
Wifi, WifiOff, Printer, CreditCard, Usb, Network, Cable,
|
||||
ChevronDown, ChevronRight, Copy, Clock, AlertCircle,
|
||||
} from 'lucide-react'
|
||||
import { cn } from '../lib/utils'
|
||||
@@ -171,9 +171,10 @@ function DeviceForm({
|
||||
}) {
|
||||
const [type, setType] = useState<'kkt' | 'printer'>(initial?.type ?? 'printer')
|
||||
const [name, setName] = useState(initial?.name ?? '')
|
||||
const [connection, setConnection] = useState<'usb' | 'network'>(initial?.connection ?? 'network')
|
||||
const [connection, setConnection] = useState<'usb' | 'network' | 'com'>(initial?.connection ?? 'network')
|
||||
const [networkHost, setNetworkHost] = useState(initial?.networkHost ?? '')
|
||||
const [networkPort, setNetworkPort] = useState(String(initial?.networkPort ?? 9100))
|
||||
const [comPort, setComPort] = useState(initial?.comPort ?? 'COM1')
|
||||
const [purpose, setPurpose] = useState(initial?.purpose ?? 'receipt')
|
||||
const [saving, setSaving] = useState(false)
|
||||
|
||||
@@ -184,8 +185,9 @@ function DeviceForm({
|
||||
type,
|
||||
name: name.trim(),
|
||||
connection,
|
||||
networkHost: connection === 'network' ? networkHost.trim() : undefined,
|
||||
networkPort: connection === 'network' ? Number(networkPort) : undefined,
|
||||
networkHost: connection === 'network' ? networkHost.trim() : undefined,
|
||||
networkPort: connection === 'network' ? Number(networkPort) : undefined,
|
||||
comPort: connection === 'com' ? comPort.trim() : undefined,
|
||||
purpose: purpose as WorkstationDevice['purpose'],
|
||||
})
|
||||
setSaving(false)
|
||||
@@ -232,19 +234,22 @@ function DeviceForm({
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-slate-500 mb-1">Подключение</label>
|
||||
<div className="flex gap-2">
|
||||
{(['usb', 'network'] as const).map(c => (
|
||||
{([
|
||||
{ id: 'usb', icon: <Usb size={14} />, label: 'USB' },
|
||||
{ id: 'network', icon: <Network size={14} />, label: 'Сеть (TCP)' },
|
||||
{ id: 'com', icon: <Cable size={14} />, label: 'COM-порт' },
|
||||
] as const).map(c => (
|
||||
<button
|
||||
key={c}
|
||||
onClick={() => setConnection(c)}
|
||||
key={c.id}
|
||||
onClick={() => setConnection(c.id)}
|
||||
className={cn(
|
||||
'flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-sm font-medium border transition-colors',
|
||||
connection === c
|
||||
connection === c.id
|
||||
? 'bg-brand-600 border-brand-600 text-white'
|
||||
: 'border-slate-300 dark:border-slate-600 text-slate-600 dark:text-slate-300 hover:border-brand-400',
|
||||
)}
|
||||
>
|
||||
{c === 'usb' ? <Usb size={14} /> : <Network size={14} />}
|
||||
{c === 'usb' ? 'USB' : 'Сеть (TCP)'}
|
||||
{c.icon}{c.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
@@ -273,6 +278,19 @@ function DeviceForm({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{connection === 'com' && (
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-slate-500 mb-1">COM-порт</label>
|
||||
<input
|
||||
value={comPort}
|
||||
onChange={e => setComPort(e.target.value)}
|
||||
className="w-full input text-sm font-mono"
|
||||
placeholder="COM1"
|
||||
/>
|
||||
<p className="text-xs text-slate-400 mt-1">Windows: COM1, COM3 и т.д. Linux: /dev/ttyUSB0</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex gap-2 pt-1">
|
||||
<button
|
||||
onClick={handleSave}
|
||||
@@ -441,8 +459,8 @@ function WorkstationCard({
|
||||
<span className="text-xs text-slate-500">{PURPOSE_LABELS[device.purpose]}</span>
|
||||
<span className="text-slate-300 dark:text-slate-600">·</span>
|
||||
<span className="inline-flex items-center gap-1 text-xs text-slate-500">
|
||||
{device.connection === 'usb' ? <Usb size={10} /> : <Network size={10} />}
|
||||
{device.connection === 'usb' ? 'USB' : `${device.networkHost}:${device.networkPort}`}
|
||||
{device.connection === 'usb' ? <Usb size={10} /> : device.connection === 'com' ? <Cable size={10} /> : <Network size={10} />}
|
||||
{device.connection === 'usb' ? 'USB' : device.connection === 'com' ? device.comPort : `${device.networkHost}:${device.networkPort}`}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user