import { useEventSource } from '@vueuse/core' import { usePage } from '@inertiajs/vue3' import { computed, ref, watch } from 'vue' export function useServerTime() { const page = usePage() const url = page.props.config?.timeEventSourceUrl // Реактивные состояния const serverTime = ref(null) const lastRawData = ref(null) const error = ref(null) const isConnected = ref(false) if (!url) { console.warn('[useServerTime] TIME_EVENT_SOURCE_URL not configured') return { serverTime, lastRawData, error, isConnected, status: 'CONFIG_ERROR' } } // Подключаемся к EventSource, слушаем кастомное событие "ServerTimeEvent" const { status, data, eventSource } = useEventSource(url, 'ServerTimeEvent', { immediate: true, onError: (e) => { error.value = e isConnected.value = false console.error('[useServerTime] Connection error:', e) }, onOpen: () => { isConnected.value = true error.value = null console.log('[useServerTime] Connected') }, onClose: () => { isConnected.value = false console.log('[useServerTime] Disconnected') } }) // Парсим данные при получении if (data) { watch(() => data.value, (newData) => { if (!newData) return lastRawData.value = newData try { const parsed = JSON.parse(newData) if (parsed.time) { // Создаём дату из ISO-строки serverTime.value = new Date(parsed.time) } } catch (e) { console.error('[useServerTime] Failed to parse event:', newData, e) } }) } // Удобные вычисляемые свойства const formattedTime = computed(() => { if (!serverTime.value) return null return serverTime.value.toLocaleString('ru-RU', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', timeZoneName: 'short' }) }) const timeDiff = computed(() => { if (!serverTime.value) return null return Date.now() - serverTime.value.getTime() // задержка в мс }) // Функция для принудительного переподключения const reconnect = () => { if (eventSource.value?.readyState === EventSource.OPEN) { eventSource.value.close() } // useEventSource автоматически переподключится при изменении URL или через retry-логику } return { serverTime, // Date | null formattedTime, // отформатированная строка "01.04.2026, 16:59:49" lastRawData, // сырые данные для отладки error, // ошибка подключения isConnected, // статус соединения status, // 'CONNECTING' | 'OPEN' | 'CLOSED' timeDiff, // задержка в мс (для мониторинга) reconnect // метод переподключения } }