feat: Add core queue management system with Pinia store, WebSocket integration, and dedicated pages for patient check-in and kiosk display.

This commit is contained in:
Fanrouver
2026-02-12 10:06:57 +07:00
parent c08941aed3
commit 0e3ee37fd8
4 changed files with 223 additions and 126 deletions

No files matched your search

+46 -16
View File
@@ -1,9 +1,9 @@
// composables/useWebSocket.ts
import { ref, computed, onUnmounted, getCurrentInstance } from 'vue'
import { ref, computed, onUnmounted, getCurrentInstance, toValue } from 'vue'
export interface WebSocketConfig {
url: string
clientId: string
url: string | any
clientId: string | any
onMessage?: (data: any) => void
onOpen?: () => void
onClose?: () => void
@@ -24,8 +24,11 @@ export const useWebSocket = (config: WebSocketConfig) => {
const reconnectAttempts = ref(0)
const reconnectTimer = ref<NodeJS.Timeout | null>(null)
const currentUrl = computed(() => toValue(config.url))
const currentClientId = computed(() => toValue(config.clientId))
const wsUrl = computed(() => {
let baseUrl = config.url
let baseUrl = currentUrl.value
// Automatically upgrade to secure protocols if caller uses HTTPS
if (typeof window !== 'undefined' && window.location.protocol === 'https:') {
@@ -37,21 +40,44 @@ export const useWebSocket = (config: WebSocketConfig) => {
}
const url = new URL(baseUrl)
url.searchParams.set('client_id', config.clientId)
url.searchParams.set('client_id', currentClientId.value)
return url.toString()
})
const clearHandlers = (wsInstance: WebSocket | null) => {
if (wsInstance) {
wsInstance.onopen = null
wsInstance.onmessage = null
wsInstance.onclose = null
wsInstance.onerror = null
}
}
const connect = () => {
try {
// Close existing connection if any
if (ws.value && ws.value.readyState !== WebSocket.CLOSED) {
ws.value.close()
// Clear any pending reconnect timer first
if (reconnectTimer.value) {
clearTimeout(reconnectTimer.value)
reconnectTimer.value = null
}
ws.value = new WebSocket(wsUrl.value)
// Close existing connection if any, and CLEAN HANDLERS to prevent recursion
if (ws.value) {
if (ws.value.readyState !== WebSocket.CLOSED) {
console.log('🔌 Closing existing WebSocket before new connection...')
clearHandlers(ws.value)
ws.value.close()
}
ws.value = null
}
const connectionUrl = wsUrl.value
console.log('🔌 Connecting to WebSocket:', connectionUrl)
ws.value = new WebSocket(connectionUrl)
ws.value.onopen = () => {
console.log('WebSocket connected:', config.clientId)
console.log('WebSocket connected:', currentClientId.value)
isConnected.value = true
reconnectAttempts.value = 0
config.onOpen?.()
@@ -67,16 +93,17 @@ export const useWebSocket = (config: WebSocketConfig) => {
}
ws.value.onclose = () => {
console.log('WebSocket closed:', config.clientId)
console.log('WebSocket closed:', currentClientId.value)
isConnected.value = false
config.onClose?.()
// Attempt to reconnect
// Attempt to reconnect only if we didn't just reach max attempts
// The reconnectTimer is cleared in disconnect() and at start of connect()
if (reconnectAttempts.value < (config.maxReconnectAttempts || 5)) {
reconnectAttempts.value++
const interval = config.reconnectInterval || 3000
console.log(`⏳ Reconnecting in ${interval}ms... Attempt ${reconnectAttempts.value}`)
reconnectTimer.value = setTimeout(() => {
console.log(`Reconnecting... Attempt ${reconnectAttempts.value}`)
connect()
}, interval)
} else {
@@ -85,11 +112,11 @@ export const useWebSocket = (config: WebSocketConfig) => {
}
ws.value.onerror = (error) => {
console.error('WebSocket error:', error)
console.error('⚠️ WebSocket error:', error)
config.onError?.(error)
}
} catch (error) {
console.error('Error creating WebSocket:', error)
console.error('Error creating WebSocket:', error)
config.onError?.(error as Event)
}
}
@@ -100,10 +127,13 @@ export const useWebSocket = (config: WebSocketConfig) => {
reconnectTimer.value = null
}
if (ws.value) {
console.log('🔌 Manual disconnect: Cleaning handlers and closing...')
clearHandlers(ws.value)
ws.value.close()
ws.value = null
}
isConnected.value = false
reconnectAttempts.value = 0
}
const sendMessage = (message: any) => {
@@ -125,7 +155,7 @@ export const useWebSocket = (config: WebSocketConfig) => {
postUrl = config.fallbackPostUrl
} else {
// Derive post URL from WebSocket URL (legacy behavior)
let baseUrl = config.url
let baseUrl = currentUrl.value
if (baseUrl.startsWith('ws://')) {
baseUrl = baseUrl.replace('ws://', 'http://')
} else if (baseUrl.startsWith('wss://')) {