# 前端对接指南 - KMZ文件生成系统 ## 📋 概述 本指南详细说明如何在前端应用中对接KMZ文件生成系统,包括WebSocket消息监听、API接口调用、文件下载等功能。 ## 🔗 系统架构 ``` 前端应用 ←→ WebSocket ←→ 后端服务 ←→ MQTT ←→ GH/YGWRXT主题 ↓ KMZ文件下载/显示 ``` ## 🚀 快速开始 ### 1. 环境要求 - 支持WebSocket的现代浏览器 - JavaScript ES6+ 支持 - 网络连接到后端服务 ### 2. 基础配置 ```javascript // 配置信息 const CONFIG = { // WebSocket连接地址 websocketUrl: 'ws://localhost:8080/ws', // API基础地址 apiBaseUrl: 'http://localhost:8080/api/v1', // 工作空间ID workspaceId: 'e3dea0f5-37f2-4d79-ae58-490af3228069', // 用户类型 userType: 1 }; ``` ## 📡 WebSocket连接 ### 1. 建立连接 ```javascript class WebSocketManager { constructor(config) { this.config = config; this.websocket = null; this.reconnectAttempts = 0; this.maxReconnectAttempts = 5; this.reconnectInterval = 3000; } connect() { try { this.websocket = new WebSocket(this.config.websocketUrl); this.setupEventListeners(); } catch (error) { console.error('WebSocket连接失败:', error); this.handleReconnect(); } } setupEventListeners() { this.websocket.onopen = () => { console.log('WebSocket连接已建立'); this.reconnectAttempts = 0; }; this.websocket.onmessage = (event) => { this.handleMessage(event); }; this.websocket.onclose = () => { console.log('WebSocket连接已关闭'); this.handleReconnect(); }; this.websocket.onerror = (error) => { console.error('WebSocket错误:', error); }; } handleReconnect() { if (this.reconnectAttempts < this.maxReconnectAttempts) { this.reconnectAttempts++; console.log(`尝试重连 (${this.reconnectAttempts}/${this.maxReconnectAttempts})`); setTimeout(() => this.connect(), this.reconnectInterval); } else { console.error('WebSocket重连失败,已达到最大重试次数'); } } } ``` ### 2. 消息处理 ```javascript class MessageHandler { constructor() { this.handlers = new Map(); this.setupDefaultHandlers(); } setupDefaultHandlers() { // GK数据消息 this.handlers.set('gk_data', (data) => { console.log('收到GK数据:', data); this.displayGkData(data); }); // KMZ数据消息 this.handlers.set('kmz_data', (data) => { console.log('收到KMZ数据:', data); this.handleKmzData(data); }); // KMZ文件数据消息 this.handlers.set('kmz_file_data', (data) => { console.log('收到KMZ文件数据:', data); this.handleKmzFileData(data); }); // KMZ生成通知 this.handlers.set('kmz_notification', (data) => { console.log('KMZ文件生成通知:', data); this.showNotification('success', data.message); }); // KMZ生成错误 this.handlers.set('kmz_error', (data) => { console.error('KMZ文件生成错误:', data); this.showNotification('error', data.message); }); } handleMessage(event) { try { const message = JSON.parse(event.data); const { bizCode, host } = message; if (this.handlers.has(bizCode)) { this.handlers.get(bizCode)(host); } else { console.log('未处理的消息类型:', bizCode, host); } } catch (error) { console.error('消息解析失败:', error); } } } ``` ## 🗂️ KMZ文件处理 ### 1. KMZ数据处理器 ```javascript class KmzFileHandler { constructor() { this.downloadedFiles = new Map(); } // 处理KMZ数据(不包含文件内容) handleKmzData(kmzData) { console.log('KMZ文件信息:', kmzData.kmzFile); // 显示文件信息 this.displayKmzInfo(kmzData); // 提供下载按钮 this.createDownloadButton(kmzData); } // 处理KMZ文件数据(包含文件内容) handleKmzFileData(kmzData) { console.log('KMZ文件数据:', kmzData); // 自动下载文件 this.autoDownloadKmzFile(kmzData); // 显示文件信息 this.displayKmzInfo(kmzData); // 解析并显示航点信息 if (kmzData.waypoints) { this.displayWaypoints(kmzData.waypoints); } } // 自动下载KMZ文件 autoDownloadKmzFile(kmzData) { if (!kmzData.fileData) { console.warn('KMZ数据中不包含文件内容'); return; } try { // 解码Base64数据 const byteCharacters = atob(kmzData.fileData); const byteNumbers = new Array(byteCharacters.length); for (let i = 0; i < byteCharacters.length; i++) { byteNumbers[i] = byteCharacters.charCodeAt(i); } const byteArray = new Uint8Array(byteNumbers); const blob = new Blob([byteArray], { type: 'application/zip' }); // 创建下载链接 const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = kmzData.kmzFile.fileName; a.style.display = 'none'; document.body.appendChild(a); a.click(); document.body.removeChild(a); window.URL.revokeObjectURL(url); console.log('KMZ文件下载完成:', kmzData.kmzFile.fileName); } catch (error) { console.error('KMZ文件下载失败:', error); } } // 显示KMZ文件信息 displayKmzInfo(kmzData) { const infoContainer = document.getElementById('kmz-info'); if (!infoContainer) return; const fileInfo = kmzData.kmzFile; infoContainer.innerHTML = `

KMZ文件信息

文件名: ${fileInfo.fileName}

文件大小: ${this.formatFileSize(fileInfo.fileSize)}

文件类型: ${fileInfo.fileType}

任务ID: ${kmzData.taskId}

设备SN: ${kmzData.deviceSn}

生成时间: ${new Date(kmzData.timestamp).toLocaleString()}

`; } // 显示航点信息 displayWaypoints(waypoints) { const waypointsContainer = document.getElementById('waypoints-info'); if (!waypointsContainer) return; let waypointsHtml = '

航点信息

'; waypointsContainer.innerHTML = waypointsHtml; } // 格式化文件大小 formatFileSize(bytes) { if (bytes === 0) return '0 Bytes'; const k = 1024; const sizes = ['Bytes', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; } // 创建下载按钮 createDownloadButton(kmzData) { const downloadBtn = document.createElement('button'); downloadBtn.textContent = '下载KMZ文件'; downloadBtn.className = 'download-btn'; downloadBtn.onclick = () => this.downloadKmzFile(kmzData); const container = document.getElementById('kmz-actions'); if (container) { container.appendChild(downloadBtn); } } // 下载KMZ文件 async downloadKmzFile(kmzData) { try { const response = await fetch(`${CONFIG.apiBaseUrl}/kmz/download/${kmzData.taskId}?fileType=${kmzData.fileType || 'dji'}`); if (response.ok) { const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = kmzData.kmzFile.fileName; document.body.appendChild(a); a.click(); document.body.removeChild(a); window.URL.revokeObjectURL(url); } else { throw new Error(`下载失败: ${response.statusText}`); } } catch (error) { console.error('下载KMZ文件失败:', error); this.showNotification('error', '下载失败: ' + error.message); } } } ``` ## 🔌 API接口调用 ### 1. API客户端 ```javascript class ApiClient { constructor(baseUrl) { this.baseUrl = baseUrl; } async request(endpoint, options = {}) { const url = `${this.baseUrl}${endpoint}`; const defaultOptions = { headers: { 'Content-Type': 'application/json', }, }; const config = { ...defaultOptions, ...options }; try { const response = await fetch(url, config); const data = await response.json(); if (!response.ok) { throw new Error(data.message || `HTTP ${response.status}`); } return data; } catch (error) { console.error('API请求失败:', error); throw error; } } // 获取KMZ文件信息 async getKmzFileInfo(taskId, fileType = 'dji') { return this.request(`/kmz/info/${taskId}?fileType=${fileType}`); } // 获取任务KMZ文件列表 async getKmzFileList(taskId) { return this.request(`/kmz/list/${taskId}`); } // 获取设备KMZ文件列表 async getDeviceKmzFileList(deviceId) { return this.request(`/kmz/list/device/${deviceId}`); } // 删除KMZ文件 async deleteKmzFile(taskId, fileType = 'dji') { return this.request(`/kmz/delete/${taskId}?fileType=${fileType}`, { method: 'DELETE' }); } // 重新发送KMZ数据 async resendKmzData(taskId, fileType = 'dji') { return this.request(`/kmz/resend/${taskId}?fileType=${fileType}`, { method: 'POST' }); } // 获取统计信息 async getKmzStatistics() { return this.request('/kmz/statistics'); } } ``` ### 2. 使用示例 ```javascript // 初始化API客户端 const apiClient = new ApiClient(CONFIG.apiBaseUrl); // 获取KMZ文件信息 async function loadKmzFileInfo(taskId) { try { const result = await apiClient.getKmzFileInfo(taskId); if (result.success) { console.log('KMZ文件信息:', result.data); return result.data; } } catch (error) { console.error('获取KMZ文件信息失败:', error); } } // 获取任务的所有KMZ文件 async function loadTaskKmzFiles(taskId) { try { const result = await apiClient.getKmzFileList(taskId); if (result.success) { console.log('任务KMZ文件列表:', result.data); return result.data; } } catch (error) { console.error('获取任务KMZ文件列表失败:', error); } } ``` ## 🎨 用户界面组件 ### 1. HTML结构 ```html KMZ文件管理系统

KMZ文件管理系统

WebSocket未连接

系统日志

``` ### 2. 主应用逻辑 ```javascript // app.js class KmzApp { constructor() { this.websocketManager = new WebSocketManager(CONFIG); this.messageHandler = new MessageHandler(); this.kmzFileHandler = new KmzFileHandler(); this.apiClient = new ApiClient(CONFIG.apiBaseUrl); this.init(); } init() { // 设置消息处理器 this.websocketManager.onMessage = (data) => { this.messageHandler.handleMessage(data); }; // 连接WebSocket this.websocketManager.connect(); // 更新连接状态 this.updateConnectionStatus(); // 设置定时器更新状态 setInterval(() => { this.updateConnectionStatus(); }, 1000); } updateConnectionStatus() { const statusElement = document.getElementById('connection-status'); if (this.websocketManager.websocket && this.websocketManager.websocket.readyState === WebSocket.OPEN) { statusElement.textContent = 'WebSocket已连接'; statusElement.className = 'status-indicator status-connected'; } else { statusElement.textContent = 'WebSocket未连接'; statusElement.className = 'status-indicator status-disconnected'; } } // 显示通知 showNotification(type, message) { const notification = document.createElement('div'); notification.className = `notification ${type}`; notification.textContent = message; document.body.appendChild(notification); setTimeout(() => { document.body.removeChild(notification); }, 3000); } // 添加日志 addLog(message) { const logContent = document.getElementById('log-content'); const timestamp = new Date().toLocaleTimeString(); const logEntry = document.createElement('div'); logEntry.textContent = `[${timestamp}] ${message}`; logContent.appendChild(logEntry); logContent.scrollTop = logContent.scrollHeight; } } // 启动应用 const app = new KmzApp(); ``` ## 📊 数据格式说明 ### 1. WebSocket消息格式 ```javascript // GK数据消息 { "bizCode": "gk_data", "host": { "sid": "1581F6GKB244J00402NM", "tm": 1706342400000, "task_id": "TASK_001", "task_name": "巡检任务", "task_type": 1, "route": [ { "longitude": 112.894686, "latitude": 28.207833, "altitude": 50.0 } ] } } // KMZ文件数据消息 { "bizCode": "kmz_file_data", "host": { "messageType": "kmz_file_data", "taskId": "TASK_001", "taskName": "巡检任务", "deviceSn": "1581F6GKB244J00402NM", "dataType": "route", "timestamp": 1706342400000, "kmzFile": { "fileName": "巡检任务_1581F6GKB244J00402NM_dji_20250127_143022.kmz", "fileSize": 3891, "filePath": "/opt/dji/routes/巡检任务_1581F6GKB244J00402NM_dji_20250127_143022.kmz", "downloadUrl": "/api/v1/kmz/download/TASK_001", "fileType": "kmz" }, "fileData": "UEsDBBQAAAAIAA...", // Base64编码的文件内容 "waypoints": [ { "longitude": 112.894686, "latitude": 28.207833, "altitude": 50.0 } ] } } ``` ### 2. API响应格式 ```javascript // 成功响应 { "success": true, "data": { // 具体数据 }, "message": "操作成功" } // 错误响应 { "success": false, "message": "错误信息", "code": "ERROR_CODE" } ``` ## 🔧 配置选项 ### 1. 环境配置 ```javascript const ENV_CONFIG = { development: { websocketUrl: 'ws://localhost:8080/ws', apiBaseUrl: 'http://localhost:8080/api/v1', workspaceId: 'e3dea0f5-37f2-4d79-ae58-490af3228069' }, production: { websocketUrl: 'wss://your-domain.com/ws', apiBaseUrl: 'https://your-domain.com/api/v1', workspaceId: 'your-workspace-id' } }; ``` ### 2. 功能配置 ```javascript const FEATURE_CONFIG = { // 是否自动下载KMZ文件 autoDownload: true, // 是否显示详细日志 verboseLogging: true, // 重连配置 reconnect: { maxAttempts: 5, interval: 3000 }, // 文件大小限制(字节) maxFileSize: 10 * 1024 * 1024 // 10MB }; ``` ## 🚨 错误处理 ### 1. 常见错误类型 ```javascript class ErrorHandler { static handleWebSocketError(error) { console.error('WebSocket错误:', error); // 处理WebSocket连接错误 } static handleApiError(error) { console.error('API错误:', error); // 处理API调用错误 } static handleFileError(error) { console.error('文件处理错误:', error); // 处理文件下载/解析错误 } } ``` ### 2. 错误恢复策略 ```javascript class ErrorRecovery { static retryOperation(operation, maxRetries = 3) { return new Promise((resolve, reject) => { let attempts = 0; const tryOperation = () => { attempts++; operation() .then(resolve) .catch(error => { if (attempts < maxRetries) { console.log(`操作失败,重试中 (${attempts}/${maxRetries})`); setTimeout(tryOperation, 1000 * attempts); } else { reject(error); } }); }; tryOperation(); }); } } ``` ## 📝 最佳实践 ### 1. 性能优化 - 使用防抖和节流处理频繁的消息 - 合理使用缓存避免重复请求 - 及时清理不需要的资源 ### 2. 用户体验 - 提供清晰的状态指示 - 显示操作进度 - 提供错误提示和恢复建议 ### 3. 安全性 - 验证所有输入数据 - 使用HTTPS/WSS连接 - 避免在客户端存储敏感信息 ## 🔍 调试指南 ### 1. 开启调试模式 ```javascript const DEBUG = true; if (DEBUG) { // 开启详细日志 console.log('调试模式已开启'); // 监听所有WebSocket消息 const originalOnMessage = WebSocket.prototype.onmessage; WebSocket.prototype.onmessage = function(event) { console.log('WebSocket消息:', event.data); originalOnMessage.call(this, event); }; } ``` ### 2. 常见问题排查 1. **WebSocket连接失败** - 检查URL是否正确 - 确认服务器是否运行 - 检查网络连接 2. **KMZ文件下载失败** - 检查文件是否存在 - 验证API接口是否正常 - 确认文件权限 3. **消息处理异常** - 检查消息格式是否正确 - 验证消息处理器是否注册 - 查看控制台错误信息 ## 📞 技术支持 如有问题,请联系开发团队或查看相关文档: - API文档:`/api/v1/kmz/docs` - 系统日志:检查浏览器控制台和后端日志 - 问题反馈:提交Issue到项目仓库 --- **注意**: 本指南基于当前系统实现,如有更新请及时同步文档。