// 地图服务 - 处理地图相关的功能,包括定位、路线规划、地理编码等 import { AMapRegeoResponse, RoutePlanResult, SearchResult, LocationData } from '../types'; /** * 地图服务类 * 提供地图相关功能,包括定位、路线规划、地理编码等 */ class MapService { // 引入高德地图小程序SDK private amapFile: any; // 高德地图API密钥 private readonly MAP_KEY: string; // 昆明中心点坐标 private readonly KUNMING_CENTER: { longitude: number; latitude: number }; // 高德地图实例 private amapInstance: any; /** * 构造函数,初始化地图实例 */ constructor() { this.amapFile = require('../libs/amap-wx.js'); this.MAP_KEY = '1fc5cafd570d9fbfd14c39359d41823d'; this.KUNMING_CENTER = { longitude: 102.833722, latitude: 24.880095 }; this.amapInstance = new this.amapFile.AMapWX({ key: this.MAP_KEY }); } /** * 获取用户位置信息 * @returns 用户位置坐标 */ async getLocation(): Promise<{ longitude: number; latitude: number }> { return new Promise((resolve, reject) => { console.log('开始调用高德地图SDK获取位置...'); // 添加超时机制 const timeout = setTimeout(() => { console.error('高德地图SDK调用超时,使用模拟位置'); resolve({ longitude: 102.7123, latitude: 25.0409 }); }, 10000); // 10秒超时 try { // 高德地图SDK的getWxLocation方法需要两个参数:配置对象和回调函数 this.amapInstance.getWxLocation({ type: 'gcj02', // 使用国测局坐标系 success: (res: { longitude: number; latitude: number }) => { clearTimeout(timeout); console.log('高德地图SDK定位成功:', res); resolve(res); }, fail: (err: any) => { clearTimeout(timeout); console.error('高德地图SDK定位失败:', err); // 如果高德SDK失败,尝试使用微信原生API console.log('尝试使用微信原生getLocation API...'); wx.getLocation({ type: 'gcj02', success: (wxRes) => { console.log('微信原生API定位成功:', wxRes); resolve({ longitude: wxRes.longitude, latitude: wxRes.latitude }); }, fail: (wxErr) => { console.error('微信原生API定位失败:', wxErr); // 所有方法都失败,使用模拟位置 console.log('所有定位方法失败,使用模拟位置'); resolve({ longitude: 102.7123, latitude: 25.0409 }); } }); } }, (locationString: string) => { // 这是高德地图SDK的回调函数,参数是格式化的位置字符串 console.log('高德地图SDK格式化位置:', locationString); // 如果格式化位置回调被调用,说明SDK已经获取到位置 // 尝试从格式化字符串中解析经纬度 if (locationString) { const coords = locationString.split(','); if (coords.length === 2) { const longitude = parseFloat(coords[0]); const latitude = parseFloat(coords[1]); if (!isNaN(longitude) && !isNaN(latitude)) { clearTimeout(timeout); console.log('从格式化位置解析成功,使用解析的位置:', { longitude, latitude }); resolve({ longitude, latitude }); return; } } } // 如果无法解析,继续等待success回调 console.log('格式化位置回调被调用,但无法解析位置,继续等待success回调...'); }); } catch (error) { clearTimeout(timeout); console.error('高德地图SDK调用异常:', error); reject(error); } }); } /** * 获取当前位置信息(兼容格式) * @returns 当前位置的详细信息 */ async getCurrentLocation(): Promise<{ latitude: number; longitude: number; accuracy?: number; speed?: number; altitude?: number; }> { const location = await this.getLocation(); return { latitude: location.latitude, longitude: location.longitude, accuracy: 50, speed: 0, altitude: 1891 }; } /** * 获取位置详细信息(逆地理编码) * @param longitude 经度 * @param latitude 纬度 * @returns 逆地理编码结果 */ async getLocationInfo(longitude: number, latitude: number): Promise { return new Promise((resolve, reject) => { this.amapInstance.getRegeo({ location: `${longitude.toFixed(6)},${latitude.toFixed(6)}`, success: (res: AMapRegeoResponse) => { console.log('逆地理编码成功:', res); resolve(res); }, fail: (err: any) => { console.log('逆地理编码失败:', err); reject(err); } }); }); } /** * 获取昆明中心点坐标 * @returns 昆明中心点坐标 */ getKunmingCenter(): { longitude: number; latitude: number } { return this.KUNMING_CENTER; } /** * 搜索地点 * @param keyword 搜索关键词 * @param city 城市名称 * @returns 搜索结果列表 */ async searchPoi(keyword: string, city: string): Promise { return new Promise((resolve, reject) => { this.amapInstance.getPoiAround({ querykeywords: keyword, city: city, radius: 50000, // 搜索半径50公里 offset: 20, // 返回20条结果 success: (res: any) => { console.log('搜索POI成功:', res); if (res.pois && res.pois.length > 0) { const results: SearchResult[] = res.pois.map((poi: any) => ({ id: poi.id, name: poi.name, address: poi.address, longitude: parseFloat(poi.location.split(',')[0]), latitude: parseFloat(poi.location.split(',')[1]), phone: poi.tel || '' })); resolve(results); } else { resolve([]); } }, fail: (err: any) => { console.error('搜索POI失败:', err); reject(err); } }); }); } /** * 规划驾车路线 * @param origin 起点坐标字符串 (经度,纬度) * @param destination 终点坐标字符串 (经度,纬度) * @returns 路线规划结果 */ async getDrivingRoute(origin: string, destination: string): Promise { return new Promise((resolve, reject) => { this.amapInstance.getDrivingRoute({ origin, destination, strategy: '0', // 推荐路线策略 showtraffic: false, // 不显示交通状况 success: (res: any) => { console.log('高德地图路线规划API调用成功'); if (res.paths && res.paths.length > 0) { const path = res.paths[0]; const result: RoutePlanResult = { polyline: path.polyline || '', distance: path.distance || 0, duration: path.duration || 0 }; console.log(`路线规划完成: 距离${result.distance}米, 预计${result.duration}秒`); resolve(result); } else { resolve({ polyline: '', distance: 0, duration: 0 }); } }, fail: (err: any) => { console.error('高德地图路线规划API调用失败:', err); reject(err); } }); }); } /** * 计算两点之间的距离(米) * @param lat1 第一个点的纬度 * @param lng1 第一个点的经度 * @param lat2 第二个点的纬度 * @param lng2 第二个点的经度 * @returns 两点之间的距离(米) */ calculateDistance( lat1: number, lng1: number, lat2: number, lng2: number ): number { const R = 6371000; // 地球半径(米) const dLat = (lat2 - lat1) * Math.PI / 180; const dLng = (lng2 - lng1) * Math.PI / 180; const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * Math.sin(dLng / 2) * Math.sin(dLng / 2); const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); return R * c; } /** * 获取路线规划(通用版本) * @param origin 起点坐标 * @param destination 终点坐标 * @returns 路线规划结果 */ async getRoute( origin: { latitude: number; longitude: number }, destination: { latitude: number; longitude: number } ): Promise<{ distance: number; // 距离(米) duration: number; // 时间(秒) polyline: { latitude: number; longitude: number }[]; }> { // 对于真实模式,目前只支持驾车路线 const originStr = `${origin.longitude},${origin.latitude}`; const destStr = `${destination.longitude},${destination.latitude}`; const result = await this.getDrivingRoute(originStr, destStr); // 转换polyline格式 const polylinePoints: { latitude: number; longitude: number }[] = []; if (result.polyline) { const points = result.polyline.split(';'); for (const point of points) { const [lng, lat] = point.split(','); if (lng && lat) { polylinePoints.push({ latitude: parseFloat(lat), longitude: parseFloat(lng) }); } } } return { distance: result.distance, duration: result.duration, polyline: polylinePoints }; } /** * 地理编码 - 地址转坐标 * @param address 地址字符串 * @returns 坐标信息 */ async geocode(address: string): Promise<{ latitude: number; longitude: number; formattedAddress: string; }> { // 对于真实模式,使用搜索API来模拟地理编码 const results = await this.searchPoi(address, '昆明'); if (results.length > 0) { return { latitude: results[0].latitude, longitude: results[0].longitude, formattedAddress: results[0].address }; } // 如果没有找到结果,返回默认位置 return { latitude: 25.0409, longitude: 102.7123, formattedAddress: '云南省昆明市' }; } /** * 逆地理编码 - 坐标转地址 * @param latitude 纬度 * @param longitude 经度 * @returns 地址信息 */ async reverseGeocode(latitude: number, longitude: number): Promise<{ formattedAddress: string; country: string; province: string; city: string; district: string; street: string; }> { const result = await this.getLocationInfo(longitude, latitude); return { // 修复:不再使用不存在的formatted_address字段,而是根据已有的addressComponent字段构建格式化地址 formattedAddress: `${(result.regeocode && result.regeocode.addressComponent && result.regeocode.addressComponent.province) || '云南省'}${(result.regeocode && result.regeocode.addressComponent && result.regeocode.addressComponent.city) || '昆明市'}${(result.regeocode && result.regeocode.addressComponent && result.regeocode.addressComponent.district) || '五华区'}` || '未知地址', country: '中国', province: (result.regeocode && result.regeocode.addressComponent && result.regeocode.addressComponent.province) || '云南省', city: (result.regeocode && result.regeocode.addressComponent && result.regeocode.addressComponent.city) || '昆明市', district: (result.regeocode && result.regeocode.addressComponent && result.regeocode.addressComponent.district) || '五华区', street: (result.regeocode && result.regeocode.addressComponent && result.regeocode.addressComponent.township) || '' }; } /** * 获取附近的地点 * @param latitude 纬度 * @param longitude 经度 * @param radius 搜索半径 * @param type 地点类型 * @returns 附近地点列表 */ async getNearbyPlaces( latitude: number, longitude: number, radius: number, type?: string ): Promise> { // 对于真实模式,使用搜索API const keyword = type ? type : ''; const results = await this.searchPoi(keyword, '昆明'); return results.map(place => ({ id: place.id, name: place.name, latitude: place.latitude, longitude: place.longitude, address: place.address, distance: this.calculateDistance(latitude, longitude, place.latitude, place.longitude) })).filter(place => place.distance <= radius); } /** * 格式化路线距离 * @param distance 距离(米) * @returns 格式化后的距离字符串 */ formatRouteDistance(distance: number): string { if (distance < 1000) { return `${distance}米`; } else { return `${(distance / 1000).toFixed(1)}公里`; } } /** * 格式化路线时间 * @param duration 时间(秒) * @returns 格式化后的时间字符串 */ formatRouteDuration(duration: number): string { if (duration < 60) { return `${Math.round(duration)} 秒`; } else if (duration < 3600) { return `${Math.round(duration / 60)} 分钟`; } else { const hours = Math.floor(duration / 3600); const minutes = Math.round((duration % 3600) / 60); return `${hours}小时${minutes}分钟`; } } } /** * 地图服务单例实例 * 导出供应用程序全局使用 */ export default new MapService();