modified: .gitignore

This commit is contained in:
brusnitsyn
2026-04-21 10:08:14 +09:00
parent 0e8b6f61b4
commit 2041ab54ea
74 changed files with 7533 additions and 1544 deletions

View File

@@ -0,0 +1,45 @@
import {computed, ref} from "vue";
const pending = ref(0)
const visible = ref(false)
let showTimer = null
const SHOW_DELAY_MS = 3000
const scheduleShow = () => {
if (visible.value || showTimer) return
showTimer = setTimeout(() => {
showTimer = null
if (pending.value > 0) {
visible.value = true
}
}, SHOW_DELAY_MS)
}
const cancelScheduledShow = () => {
if (!showTimer) return
clearTimeout(showTimer)
showTimer = null
}
export const startGlobalLoading = () => {
pending.value += 1
scheduleShow()
}
export const stopGlobalLoading = () => {
pending.value = Math.max(0, pending.value - 1)
if (pending.value === 0) {
cancelScheduledShow()
visible.value = false
}
}
export const useGlobalLoading = () => {
return {
isGlobalLoading: computed(() => visible.value),
pendingCount: computed(() => pending.value),
}
}

View File

@@ -0,0 +1,102 @@
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 // метод переподключения
}
}