// 大神接单心跳:工作台/接单大厅/雷达页在前台时每 60 秒上报一次 // 服务端以 last_active_at 判断是否真实在线(10 分钟无心跳自动移出匹配池) import { getUserLocation } from './location.js'; import { sendCompanionHeartbeat, normalizeUserId } from './api.js'; let timer = null; let inFlight = false; let lastSentAt = 0; let coords = null; let coordsAt = 0; const COORD_TTL_MS = 5 * 60 * 1000; async function resolveCoords() { if (coords && Date.now() - coordsAt < COORD_TTL_MS) return coords; try { const pos = await getUserLocation(); coords = { lat: pos.latitude, lng: pos.longitude }; coordsAt = Date.now(); return coords; } catch (_) { // 用户拒绝定位时仍上报活跃时间,只是没有距离信息 return coords; } } export async function sendHeartbeat(force = false) { if (inFlight) return; if (!force && Date.now() - lastSentAt < 45 * 1000) return; if (!normalizeUserId()) return; inFlight = true; try { const pos = await resolveCoords(); await sendCompanionHeartbeat(pos || {}); lastSentAt = Date.now(); } catch (_) { } finally { inFlight = false; } } export function startHeartbeat(intervalMs = 60 * 1000) { if (timer) return; void sendHeartbeat(true); timer = setInterval(() => { void sendHeartbeat(); }, Math.max(30 * 1000, Number(intervalMs) || 60 * 1000)); if (timer && typeof timer.unref === 'function') timer.unref(); } export function stopHeartbeat() { if (timer) { clearInterval(timer); timer = null; } } export function resetHeartbeatLocation() { coords = null; coordsAt = 0; }