Files
BYW-VoiceHub/app/composables/useSyncedTime.ts
T

66 lines
1.8 KiB
TypeScript

// 全局状态,保存本地时间与服务器时间的差值
// offset = serverTime - localTime
// 仅在客户端有效,服务端默认为0且不进行同步
let timeOffset = 0
let hasSynced = false
/**
* 获取当前修正后的时间戳 (毫秒)
* 可以在任何地方(包括非 Vue 组件环境)安全调用
*/
export const getSyncedTimestamp = (): number => {
return Date.now() + timeOffset
}
/**
* 获取当前修正后的 Date 对象
*/
export const getSyncedDate = (): Date => {
return new Date(getSyncedTimestamp())
}
export function useSyncedTime() {
/**
* 同步服务器时间
* 直接调用本站后端提供的 API(/api/sys/time),返回服务器本机时间。
*/
const syncTime = async () => {
// 服务端本身的时间就是服务器时间,不需要同步
if (import.meta.server) {
hasSynced = true
return
}
if (hasSynced) return
try {
const startTime = Date.now()
// 请求我们自己的后端以获取标准时间戳,避免 CORS
const data = await $fetch<{ timestamp: number }>('/api/sys/time')
if (data?.timestamp) {
const endTime = Date.now()
// 估算单向传输延迟
const latency = (endTime - startTime) / 2
const serverTime = data.timestamp + latency
timeOffset = serverTime - endTime
hasSynced = true
console.log(`[TimeSync] 时间同步完成,与服务器时间相差 ${timeOffset}ms`)
}
} catch (error) {
console.error('[TimeSync] 时间同步失败,将使用本地时间:', error)
hasSynced = true // 避免反复重试
}
}
return {
get offset() { return timeOffset },
get hasSynced() { return hasSynced },
syncTime,
now: getSyncedTimestamp,
nowDate: getSyncedDate
}
}