feat: TTLock integration + fix agent offline status
- Add TTLock electronic lock module: settings page, room-lock mapping, card issuance via agent command (ttlock:write_card) - Fix agent offline: EquipmentPage now polls every 30s + reacts to workstation:online/offline WebSocket events instantly - Backend broadcasts workstation online/offline events to hotel clients via existing WebSocket (agent-ws.ts) - New DB migration 048_ttlock.sql: hotel_ttlock_config, room_lock_mappings, card_issuances tables - New backend routes: GET/PATCH ttlock/config, POST ttlock/token, GET ttlock/locks, POST/DELETE ttlock/room-locks, POST issue-card - "Выдать ключ (TTLock)" button in BookingDetailPanel for confirmed/checked_in - TTLock page added to sidebar under Настройки Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
52
backend/migrations/048_ttlock.sql
Normal file
52
backend/migrations/048_ttlock.sql
Normal file
@@ -0,0 +1,52 @@
|
||||
-- TTLock integration: credentials, room-to-lock mapping, card issuance log
|
||||
|
||||
-- TTLock API credentials per hotel (Open Platform)
|
||||
CREATE TABLE IF NOT EXISTS hotel_ttlock_config (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
hotel_id UUID NOT NULL REFERENCES hotels(id) ON DELETE CASCADE,
|
||||
is_enabled BOOLEAN NOT NULL DEFAULT false,
|
||||
client_id TEXT NOT NULL DEFAULT '',
|
||||
client_secret TEXT NOT NULL DEFAULT '',
|
||||
ttlock_username TEXT NOT NULL DEFAULT '',
|
||||
ttlock_password TEXT NOT NULL DEFAULT '',
|
||||
access_token TEXT,
|
||||
refresh_token TEXT,
|
||||
token_expires_at TIMESTAMPTZ,
|
||||
-- Which workstation has the card encoder attached
|
||||
workstation_id UUID REFERENCES workstations(id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
UNIQUE(hotel_id)
|
||||
);
|
||||
|
||||
-- Mapping: room → TTLock lock_id
|
||||
CREATE TABLE IF NOT EXISTS room_lock_mappings (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
hotel_id UUID NOT NULL REFERENCES hotels(id) ON DELETE CASCADE,
|
||||
room_id UUID NOT NULL REFERENCES rooms(id) ON DELETE CASCADE,
|
||||
lock_id BIGINT NOT NULL,
|
||||
lock_name TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
UNIQUE(hotel_id, room_id)
|
||||
);
|
||||
|
||||
-- Log of every card issuance
|
||||
CREATE TABLE IF NOT EXISTS card_issuances (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
hotel_id UUID NOT NULL REFERENCES hotels(id) ON DELETE CASCADE,
|
||||
booking_id UUID NOT NULL REFERENCES bookings(id) ON DELETE CASCADE,
|
||||
room_id UUID NOT NULL REFERENCES rooms(id),
|
||||
lock_id BIGINT NOT NULL,
|
||||
ttlock_card_id BIGINT,
|
||||
issued_by UUID REFERENCES users(id),
|
||||
issued_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
check_in TIMESTAMPTZ NOT NULL,
|
||||
check_out TIMESTAMPTZ NOT NULL,
|
||||
is_revoked BOOLEAN NOT NULL DEFAULT false,
|
||||
revoked_at TIMESTAMPTZ,
|
||||
revoked_by UUID REFERENCES users(id),
|
||||
notes TEXT
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_card_issuances_booking ON card_issuances(booking_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_card_issuances_hotel ON card_issuances(hotel_id);
|
||||
Reference in New Issue
Block a user