102 lines
3.1 KiB
JavaScript
102 lines
3.1 KiB
JavaScript
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 // метод переподключения
|
|
}
|
|
} |