// 位置追踪服务 - 处理用户签到后的位置追踪和状态管理 import { UserInfo, LocationData } from '../types'; import apiService from './apiService'; import { isMockMode } from './apiService'; import userService from './userService'; /** * 在线用户信息接口 */ export interface OnlineUserInfo { userId: number; name: string; avatarUrl: string; lastLocation: LocationData; lastUpdateTime: number; status: 'online' | 'offline' | 'timeout'; } /** * 位置追踪服务类 * 提供用户签到后的位置追踪、状态管理和位置分发功能 */ class LocationTrackingService { // 在线用户列表 private onlineUsers: Map; // 位置更新定时器 private locationUpdateTimer: number | null; // 状态检查定时器 private statusCheckTimer: number | null; // 位置更新回调集合 private locationUpdateCallbacks: Set<(locations: OnlineUserInfo[]) => void>; // 用户状态变化回调集合 private userStatusCallbacks: Set<(userId: number, status: 'online' | 'offline' | 'timeout') => void>; // 当前用户是否已签到 private isSignedIn: boolean; // 用户信息缓存 private userInfo: UserInfo | null; // 取消订阅回调函数 private unsubscribeCallback: (() => void) | null; /** * 构造函数 */ constructor() { this.onlineUsers = new Map(); this.locationUpdateTimer = null; this.statusCheckTimer = null; this.locationUpdateCallbacks = new Set(); this.userStatusCallbacks = new Set(); this.isSignedIn = false; this.userInfo = null; this.unsubscribeCallback = null; } /** * 用户签到后启动位置追踪 */ public async startTrackingAfterSignIn(): Promise { const userInfo = userService.getGlobalUserInfo(); if (!userInfo || !userInfo.id) { throw new Error('用户未登录,无法启动位置追踪'); } this.isSignedIn = true; // 将当前用户添加到在线列表 await this.addUserToOnlineList(userInfo); // 启动位置更新定时器(每30秒更新一次) this.startLocationUpdateTimer(); // 启动状态检查定时器(每60秒检查一次) this.startStatusCheckTimer(); // 订阅其他用户的位置更新 await this.subscribeToOtherUsersLocations(); console.log('位置追踪服务已启动'); } /** * 用户签退后停止位置追踪 */ public async stopTracking(): Promise { const userInfo = userService.getGlobalUserInfo(); if (!userInfo || !userInfo.id) { return; } this.isSignedIn = false; // 从在线列表中移除用户 this.removeUserFromOnlineList(userInfo.id); // 停止定时器 this.stopTimers(); // 取消订阅 await this.unsubscribeFromLocations(); console.log('位置追踪服务已停止'); } /** * 手动更新用户位置 */ public async updateUserLocation(location: { longitude: number; latitude: number }): Promise { const userInfo = userService.getGlobalUserInfo(); if (!userInfo || !userInfo.id || !this.isSignedIn) { console.warn('[位置追踪服务] 用户未登录或未签到,无法更新位置'); return; } console.log('[位置追踪服务] 前端发送给服务器的位置信息:'); console.log(`- 用户ID: ${userInfo.id}`); console.log(`- 经度: ${location.longitude}`); console.log(`- 纬度: ${location.latitude}`); console.log(`- 时间戳: ${Date.now()}`); const locationData: LocationData = { userId: userInfo.id, longitude: location.longitude, latitude: location.latitude, timestamp: Date.now() }; if (isMockMode) { // 模拟模式:更新本地在线用户列表 console.log('[位置追踪服务] 模拟模式:更新本地位置'); this.updateLocalUserLocation(userInfo.id, locationData); } else { // 真实模式:调用API更新位置 console.log('[位置追踪服务] 真实模式:调用API更新位置'); await apiService.updateDeliveryPersonLocation(userInfo.id, location); // 同时更新本地缓存 this.updateLocalUserLocation(userInfo.id, locationData); } // 通知所有回调 this.notifyLocationUpdateCallbacks(); console.log('[位置追踪服务] 位置更新完成,已通知回调'); } /** * 获取所有在线用户信息 */ public getOnlineUsers(): OnlineUserInfo[] { return Array.from(this.onlineUsers.values()).filter(user => user.status === 'online' ); } /** * 订阅位置更新 */ public subscribeToLocationUpdates(callback: (locations: OnlineUserInfo[]) => void): void { this.locationUpdateCallbacks.add(callback); } /** * 取消订阅位置更新 */ public unsubscribeFromLocationUpdates(callback: (locations: OnlineUserInfo[]) => void): void { this.locationUpdateCallbacks.delete(callback); } /** * 订阅用户状态变化 */ public subscribeToUserStatusChanges(callback: (userId: number, status: 'online' | 'offline' | 'timeout') => void): void { this.userStatusCallbacks.add(callback); } /** * 取消订阅用户状态变化 */ public unsubscribeFromUserStatusChanges(callback: (userId: number, status: 'online' | 'offline' | 'timeout') => void): void { this.userStatusCallbacks.delete(callback); } /** * 检查用户是否在线 */ public isUserOnline(userId: number): boolean { const userInfo = this.onlineUsers.get(userId); return userInfo ? userInfo.status === 'online' : false; } // ===== 私有方法 ===== /** * 添加用户到在线列表 */ private async addUserToOnlineList(userInfo: UserInfo): Promise { const currentLocation = await this.getCurrentLocation(); const onlineUser: OnlineUserInfo = { userId: userInfo.id, name: userInfo.name || '未知用户', avatarUrl: '/images/user-avatar.png', lastLocation: currentLocation, lastUpdateTime: Date.now(), status: 'online' }; this.onlineUsers.set(userInfo.id, onlineUser); console.log(`用户 ${userInfo.id} 已添加到在线列表`); } /** * 从在线列表中移除用户 */ private removeUserFromOnlineList(userId: number): void { if (this.onlineUsers.has(userId)) { this.onlineUsers.delete(userId); // 通知状态变化回调 this.notifyUserStatusChange(userId, 'offline'); console.log(`用户 ${userId} 已从在线列表移除`); } } /** * 更新本地用户位置 */ private updateLocalUserLocation(userId: number, location: LocationData): void { const userInfo = this.onlineUsers.get(userId); if (userInfo) { userInfo.lastLocation = location; userInfo.lastUpdateTime = Date.now(); userInfo.status = 'online'; this.onlineUsers.set(userId, userInfo); } } /** * 启动位置更新定时器 */ private startLocationUpdateTimer(): void { this.stopLocationUpdateTimer(); this.locationUpdateTimer = setInterval(async () => { if (this.isSignedIn) { try { const location = await this.getCurrentLocation(); await this.updateUserLocation(location); } catch (error) { console.error('自动位置更新失败:', error); } } }, 30000); // 每30秒更新一次 } /** * 启动状态检查定时器 */ private startStatusCheckTimer(): void { this.stopStatusCheckTimer(); this.statusCheckTimer = setInterval(() => { this.checkUserStatuses(); }, 60000); // 每60秒检查一次 } /** * 检查用户状态 */ private checkUserStatuses(): void { const now = Date.now(); const timeoutThreshold = 120000; // 2分钟无更新视为超时 this.onlineUsers.forEach((userInfo, userId) => { if (now - userInfo.lastUpdateTime > timeoutThreshold) { // 用户超时 userInfo.status = 'timeout'; this.onlineUsers.set(userId, userInfo); this.notifyUserStatusChange(userId, 'timeout'); console.log(`用户 ${userId} 因超时被标记为离线`); } }); } /** * 获取当前位置 */ private async getCurrentLocation(): Promise { const userInfo = userService.getGlobalUserInfo(); if (!userInfo || !userInfo.id) { throw new Error('用户未登录'); } // 这里应该调用地图服务获取当前位置 // 暂时返回一个默认位置 return { userId: userInfo.id, longitude: 102.833722, latitude: 24.880095, timestamp: Date.now() }; } /** * 订阅其他用户的位置更新 */ private async subscribeToOtherUsersLocations(): Promise { if (isMockMode) { // 模拟模式:定时生成其他用户的位置更新 this.startMockOtherUsersUpdates(); } else { // 真实模式:通过WebSocket订阅 await this.setupRealTimeSubscription(); } } /** * 取消订阅位置更新 */ private async unsubscribeFromLocations(): Promise { if (!isMockMode) { // 真实模式:取消WebSocket订阅 await this.teardownRealTimeSubscription(); } } /** * 启动模拟的其他用户位置更新 */ private startMockOtherUsersUpdates(): void { // 模拟其他用户的位置更新(每45秒一次) setInterval(() => { if (this.isSignedIn) { this.generateMockOtherUsersLocations(); this.notifyLocationUpdateCallbacks(); } }, 45000); } /** * 生成模拟的其他用户位置 */ private generateMockOtherUsersLocations(): void { const currentUserInfo = userService.getGlobalUserInfo(); if (!currentUserInfo) return; // 模拟2个其他在线用户 const mockUserIds = [101, 102]; // 模拟用户ID mockUserIds.forEach(userId => { if (userId !== currentUserInfo.id) { const existingUser = this.onlineUsers.get(userId); if (existingUser) { // 更新现有用户位置 existingUser.lastLocation.longitude += (Math.random() - 0.5) * 0.001; existingUser.lastLocation.latitude += (Math.random() - 0.5) * 0.001; existingUser.lastUpdateTime = Date.now(); existingUser.status = 'online'; this.onlineUsers.set(userId, existingUser); } else { // 添加新用户 const newUser: OnlineUserInfo = { userId, name: `用户${userId}`, avatarUrl: '/images/user-avatar.png', lastLocation: { userId, longitude: 102.833722 + (Math.random() - 0.5) * 0.01, latitude: 24.880095 + (Math.random() - 0.5) * 0.01, timestamp: Date.now() }, lastUpdateTime: Date.now(), status: 'online' }; this.onlineUsers.set(userId, newUser); this.notifyUserStatusChange(userId, 'online'); } } }); } /** * 设置实时位置订阅 */ private setupRealTimeSubscription(): void { // 获取用户信息 const userInfo = userService.getGlobalUserInfo(); if (!userInfo || !userInfo.id) { console.warn('用户未登录,无法设置实时位置订阅'); return; } // 缓存用户信息 this.userInfo = userInfo; if (isMockMode) { console.log('[MOCK] 设置实时位置订阅'); this.startMockLocationGeneration(); return; } // 真实环境:初始化WebSocket连接并订阅位置更新 try { // 使用新的API接口 apiService.initLocationWebSocket(); // 订阅当前用户的位置更新 apiService.subscribeToLocationUpdates(this.userInfo.id) .then(() => { console.log('成功订阅位置更新'); }) .catch((error) => { console.error('订阅位置更新失败:', error); }); // 设置位置更新回调 this.unsubscribeCallback = apiService.onLocationUpdate((locationUpdate) => { this.handleLocationUpdate(locationUpdate); }); } catch (error) { console.error('设置实时位置订阅失败:', error); } } /** * 关闭实时位置订阅 */ private teardownRealTimeSubscription(): void { if (isMockMode) { console.log('[MOCK] 关闭实时位置订阅'); this.stopMockLocationGeneration(); return; } // 真实环境:取消订阅并关闭WebSocket连接 try { if (this.userInfo) { // 使用新的API接口取消订阅 apiService.unsubscribeFromLocationUpdates(this.userInfo.id) .then(() => { console.log('成功取消订阅位置更新'); }) .catch((error) => { console.error('取消订阅位置更新失败:', error); }); } // 移除位置更新回调 if (this.unsubscribeCallback) { this.unsubscribeCallback(); this.unsubscribeCallback = null; } // 关闭WebSocket连接 apiService.closeLocationWebSocket(); } catch (error) { console.error('关闭实时位置订阅失败:', error); } } /** * 停止所有定时器 */ private stopTimers(): void { this.stopLocationUpdateTimer(); this.stopStatusCheckTimer(); } /** * 停止位置更新定时器 */ private stopLocationUpdateTimer(): void { if (this.locationUpdateTimer) { clearInterval(this.locationUpdateTimer); this.locationUpdateTimer = null; } } /** * 停止状态检查定时器 */ private stopStatusCheckTimer(): void { if (this.statusCheckTimer) { clearInterval(this.statusCheckTimer); this.statusCheckTimer = null; } } /** * 通知位置更新回调 */ private notifyLocationUpdateCallbacks(): void { const onlineUsers = this.getOnlineUsers(); this.locationUpdateCallbacks.forEach(callback => { try { callback(onlineUsers); } catch (error) { console.error('位置更新回调执行失败:', error); } }); } /** * 通知用户状态变化回调 */ private notifyUserStatusChange(userId: number, status: 'online' | 'offline' | 'timeout'): void { this.userStatusCallbacks.forEach(callback => { try { callback(userId, status); } catch (error) { console.error('用户状态变化回调执行失败:', error); } }); } /** * 启动模拟位置生成 */ private startMockLocationGeneration(): void { console.log('[MOCK] 启动模拟位置生成'); // 这里可以添加模拟位置生成的逻辑 } /** * 停止模拟位置生成 */ private stopMockLocationGeneration(): void { console.log('[MOCK] 停止模拟位置生成'); // 这里可以添加停止模拟位置生成的逻辑 } /** * 处理位置更新 */ private handleLocationUpdate(locationUpdate: any): void { console.log('收到位置更新:', locationUpdate); // 这里可以添加处理位置更新的逻辑 } } /** * 位置追踪服务单例实例 * 导出供应用程序全局使用 */ export default new LocationTrackingService();