From b2b2034f4ca6d9782db302344f96432a12edf8f2 Mon Sep 17 00:00:00 2001 From: HotelSync Date: Fri, 27 Mar 2026 12:41:31 +0300 Subject: [PATCH] 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 --- .../042_workstation_devices_com.sql | 13 ++++++ backend/src/routes/workstations.ts | 12 +++--- src/lib/api.ts | 3 +- src/pages/EquipmentPage.tsx | 42 +++++++++++++------ 4 files changed, 51 insertions(+), 19 deletions(-) create mode 100644 backend/migrations/042_workstation_devices_com.sql diff --git a/backend/migrations/042_workstation_devices_com.sql b/backend/migrations/042_workstation_devices_com.sql new file mode 100644 index 0000000..c6e4827 --- /dev/null +++ b/backend/migrations/042_workstation_devices_com.sql @@ -0,0 +1,13 @@ +-- Добавляем поддержку COM-порта для устройств рабочего места + +-- Расширяем CHECK constraint для connection (добавляем 'com') +ALTER TABLE workstation_devices + DROP CONSTRAINT IF EXISTS workstation_devices_connection_check; + +ALTER TABLE workstation_devices + ADD CONSTRAINT workstation_devices_connection_check + CHECK (connection IN ('usb', 'network', 'com')); + +-- Добавляем поле com_port (например: COM1, COM3, /dev/ttyUSB0) +ALTER TABLE workstation_devices + ADD COLUMN IF NOT EXISTS com_port VARCHAR(50); diff --git a/backend/src/routes/workstations.ts b/backend/src/routes/workstations.ts index 78fbeec..d4b8ca8 100644 --- a/backend/src/routes/workstations.ts +++ b/backend/src/routes/workstations.ts @@ -209,17 +209,17 @@ const workstationRoutes: FastifyPluginAsync = async (fastify) => { // ── POST /api/hotels/:slug/workstations/:id/devices ───────────────────────── fastify.post( '/api/hotels/:slug/workstations/:id/devices', { onRequest: [fastify.authenticate] }, async (req, reply) => { const { id } = req.params - const { type, name, connection, network_host, network_port, purpose, config } = req.body + const { type, name, connection, network_host, network_port, com_port, purpose, config } = req.body const { rows } = await db.query( - `INSERT INTO workstation_devices (workstation_id, type, name, connection, network_host, network_port, purpose, config) - VALUES ($1,$2,$3,$4,$5,$6,$7,$8) RETURNING *`, - [id, type, name, connection, network_host ?? null, network_port ?? null, purpose ?? 'other', config ?? {}], + `INSERT INTO workstation_devices (workstation_id, type, name, connection, network_host, network_port, com_port, purpose, config) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9) RETURNING *`, + [id, type, name, connection, network_host ?? null, network_port ?? null, com_port ?? null, purpose ?? 'other', config ?? {}], ) return reply.code(201).send(rows[0]) }, @@ -232,7 +232,7 @@ const workstationRoutes: FastifyPluginAsync = async (fastify) => { async (req, reply) => { const { deviceId } = req.params const body = req.body as Record - const fields = ['name', 'connection', 'network_host', 'network_port', 'purpose', 'config'] + const fields = ['name', 'connection', 'network_host', 'network_port', 'com_port', 'purpose', 'config'] const sets: string[] = [] const vals: unknown[] = [] fields.forEach(f => { diff --git a/src/lib/api.ts b/src/lib/api.ts index afda219..9781b2a 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -972,9 +972,10 @@ export interface WorkstationDevice { workstationId: string type: 'kkt' | 'printer' name: string - connection: 'usb' | 'network' + connection: 'usb' | 'network' | 'com' networkHost?: string networkPort?: number + comPort?: string purpose: 'fiscal' | 'kitchen' | 'bar' | 'receipt' | 'other' config: Record } diff --git a/src/pages/EquipmentPage.tsx b/src/pages/EquipmentPage.tsx index 57b882d..faf43f9 100644 --- a/src/pages/EquipmentPage.tsx +++ b/src/pages/EquipmentPage.tsx @@ -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({
- {(['usb', 'network'] as const).map(c => ( + {([ + { id: 'usb', icon: , label: 'USB' }, + { id: 'network', icon: , label: 'Сеть (TCP)' }, + { id: 'com', icon: , label: 'COM-порт' }, + ] as const).map(c => ( ))}
@@ -273,6 +278,19 @@ function DeviceForm({
)} + {connection === 'com' && ( +
+ + setComPort(e.target.value)} + className="w-full input text-sm font-mono" + placeholder="COM1" + /> +

Windows: COM1, COM3 и т.д. Linux: /dev/ttyUSB0

+
+ )} +