179 lines
4.5 KiB
JavaScript
179 lines
4.5 KiB
JavaScript
|
|
/**
|
|||
|
|
* 高德地图 API 客户端
|
|||
|
|
* 封装路径规划 API 调用
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
import axios from 'axios'
|
|||
|
|
import { AMAP_CONFIG, AMAP_ENDPOINTS } from '../config/amap'
|
|||
|
|
import { generateCacheKey } from './geoUtils'
|
|||
|
|
|
|||
|
|
// 路由缓存
|
|||
|
|
const routeCache = new Map()
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 清理过期缓存
|
|||
|
|
*/
|
|||
|
|
function cleanExpiredCache() {
|
|||
|
|
const now = Date.now()
|
|||
|
|
for (const [key, value] of routeCache.entries()) {
|
|||
|
|
if (now - value.timestamp > AMAP_CONFIG.cacheExpiry) {
|
|||
|
|
routeCache.delete(key)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 定期清理缓存(每小时)
|
|||
|
|
setInterval(cleanExpiredCache, 60 * 60 * 1000)
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 调用高德地图驾车路径规划 API
|
|||
|
|
* @param {Object} origin - 起点 { lon, lat }
|
|||
|
|
* @param {Object} destination - 终点 { lon, lat }
|
|||
|
|
* @param {Object} options - 可选参数
|
|||
|
|
* @returns {Promise<Object>} 路径规划结果
|
|||
|
|
*/
|
|||
|
|
export async function calculateDrivingRoute(origin, destination, options = {}) {
|
|||
|
|
const cacheKey = generateCacheKey(origin, destination)
|
|||
|
|
|
|||
|
|
// 检查缓存
|
|||
|
|
if (routeCache.has(cacheKey)) {
|
|||
|
|
const cached = routeCache.get(cacheKey)
|
|||
|
|
console.log('[AmapAPI] 使用缓存路线:', cacheKey)
|
|||
|
|
return cached.data
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const url = `${AMAP_CONFIG.baseUrl}${AMAP_ENDPOINTS.driving}`
|
|||
|
|
|
|||
|
|
const params = {
|
|||
|
|
key: AMAP_CONFIG.webServiceKey,
|
|||
|
|
origin: `${origin.lon},${origin.lat}`,
|
|||
|
|
destination: `${destination.lon},${destination.lat}`,
|
|||
|
|
extensions: 'all', // 返回详细路径
|
|||
|
|
output: 'json',
|
|||
|
|
strategy: options.strategy ?? AMAP_CONFIG.strategy
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
console.log('[AmapAPI] 请求路径规划:', params)
|
|||
|
|
|
|||
|
|
const response = await axios.get(url, {
|
|||
|
|
params,
|
|||
|
|
timeout: AMAP_CONFIG.timeout
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
if (response.data.status !== '1') {
|
|||
|
|
throw new Error(`高德API错误: ${response.data.info}`)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!response.data.route || !response.data.route.paths || response.data.route.paths.length === 0) {
|
|||
|
|
throw new Error('未找到可用路线')
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const path = response.data.route.paths[0]
|
|||
|
|
|
|||
|
|
// 提取路径数据
|
|||
|
|
const routeData = {
|
|||
|
|
distance: parseInt(path.distance), // 米
|
|||
|
|
duration: parseInt(path.duration), // 秒
|
|||
|
|
polyline: extractPolyline(path.steps),
|
|||
|
|
steps: path.steps.map(step => ({
|
|||
|
|
instruction: step.instruction,
|
|||
|
|
distance: parseInt(step.distance),
|
|||
|
|
duration: parseInt(step.duration)
|
|||
|
|
}))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 缓存结果
|
|||
|
|
routeCache.set(cacheKey, {
|
|||
|
|
data: routeData,
|
|||
|
|
timestamp: Date.now()
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
console.log('[AmapAPI] 路径规划成功:', {
|
|||
|
|
distance: routeData.distance,
|
|||
|
|
duration: routeData.duration,
|
|||
|
|
points: routeData.polyline.split(';').length
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
return routeData
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('[AmapAPI] 路径规划失败:', error.message)
|
|||
|
|
throw error
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 从步骤中提取完整的 polyline
|
|||
|
|
* @param {Array} steps - 路径步骤数组
|
|||
|
|
* @returns {string} 完整的 polyline 字符串
|
|||
|
|
*/
|
|||
|
|
function extractPolyline(steps) {
|
|||
|
|
const allPolylines = steps
|
|||
|
|
.map(step => step.polyline)
|
|||
|
|
.filter(Boolean)
|
|||
|
|
|
|||
|
|
return allPolylines.join(';')
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 批量计算路线(并行请求)
|
|||
|
|
* @param {Array} routePairs - 路线对数组 [{ origin, destination, type, name, id }]
|
|||
|
|
* @returns {Promise<Array>} 路线结果数组
|
|||
|
|
*/
|
|||
|
|
export async function calculateMultipleRoutes(routePairs) {
|
|||
|
|
console.log(`[AmapAPI] 批量计算 ${routePairs.length} 条路线`)
|
|||
|
|
|
|||
|
|
const promises = routePairs.map(async (pair) => {
|
|||
|
|
try {
|
|||
|
|
const routeData = await calculateDrivingRoute(pair.origin, pair.destination)
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
id: pair.id,
|
|||
|
|
name: pair.name,
|
|||
|
|
type: pair.type,
|
|||
|
|
origin: pair.origin,
|
|||
|
|
destination: pair.destination,
|
|||
|
|
...routeData,
|
|||
|
|
success: true
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
console.warn(`[AmapAPI] 路线计算失败 (${pair.name}):`, error.message)
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
id: pair.id,
|
|||
|
|
name: pair.name,
|
|||
|
|
type: pair.type,
|
|||
|
|
origin: pair.origin,
|
|||
|
|
destination: pair.destination,
|
|||
|
|
error: error.message,
|
|||
|
|
success: false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
const results = await Promise.all(promises)
|
|||
|
|
|
|||
|
|
const successCount = results.filter(r => r.success).length
|
|||
|
|
console.log(`[AmapAPI] 批量计算完成: ${successCount}/${routePairs.length} 成功`)
|
|||
|
|
|
|||
|
|
return results
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 清除所有缓存
|
|||
|
|
*/
|
|||
|
|
export function clearRouteCache() {
|
|||
|
|
routeCache.clear()
|
|||
|
|
console.log('[AmapAPI] 缓存已清空')
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取缓存统计信息
|
|||
|
|
*/
|
|||
|
|
export function getCacheStats() {
|
|||
|
|
return {
|
|||
|
|
size: routeCache.size,
|
|||
|
|
keys: Array.from(routeCache.keys())
|
|||
|
|
}
|
|||
|
|
}
|