# 前端对接指南 - 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 = '航点信息
';
waypoints.forEach((waypoint, index) => {
waypointsHtml += `
-
航点 ${index + 1}:
经度 ${waypoint.longitude},
纬度 ${waypoint.latitude},
高度 ${waypoint.altitude}m
`;
});
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文件管理系统
```
### 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到项目仓库
---
**注意**: 本指南基于当前系统实现,如有更新请及时同步文档。