66 lines
1.8 KiB
TypeScript
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
|
|
}
|
|
}
|