837 lines
22 KiB
Markdown
837 lines
22 KiB
Markdown
# 前端对接指南 - 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 = `
|
||
<div class="kmz-file-info">
|
||
<h3>KMZ文件信息</h3>
|
||
<p><strong>文件名:</strong> ${fileInfo.fileName}</p>
|
||
<p><strong>文件大小:</strong> ${this.formatFileSize(fileInfo.fileSize)}</p>
|
||
<p><strong>文件类型:</strong> ${fileInfo.fileType}</p>
|
||
<p><strong>任务ID:</strong> ${kmzData.taskId}</p>
|
||
<p><strong>设备SN:</strong> ${kmzData.deviceSn}</p>
|
||
<p><strong>生成时间:</strong> ${new Date(kmzData.timestamp).toLocaleString()}</p>
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
// 显示航点信息
|
||
displayWaypoints(waypoints) {
|
||
const waypointsContainer = document.getElementById('waypoints-info');
|
||
if (!waypointsContainer) return;
|
||
|
||
let waypointsHtml = '<h3>航点信息</h3><ul>';
|
||
waypoints.forEach((waypoint, index) => {
|
||
waypointsHtml += `
|
||
<li>
|
||
航点 ${index + 1}:
|
||
经度 ${waypoint.longitude},
|
||
纬度 ${waypoint.latitude},
|
||
高度 ${waypoint.altitude}m
|
||
</li>
|
||
`;
|
||
});
|
||
waypointsHtml += '</ul>';
|
||
|
||
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
|
||
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>KMZ文件管理系统</title>
|
||
<style>
|
||
.container {
|
||
max-width: 1200px;
|
||
margin: 0 auto;
|
||
padding: 20px;
|
||
}
|
||
|
||
.status-indicator {
|
||
padding: 10px;
|
||
margin: 10px 0;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.status-connected {
|
||
background-color: #d4edda;
|
||
color: #155724;
|
||
border: 1px solid #c3e6cb;
|
||
}
|
||
|
||
.status-disconnected {
|
||
background-color: #f8d7da;
|
||
color: #721c24;
|
||
border: 1px solid #f5c6cb;
|
||
}
|
||
|
||
.kmz-file-info {
|
||
background-color: #f8f9fa;
|
||
padding: 15px;
|
||
border-radius: 4px;
|
||
margin: 10px 0;
|
||
}
|
||
|
||
.waypoints-info {
|
||
background-color: #e9ecef;
|
||
padding: 15px;
|
||
border-radius: 4px;
|
||
margin: 10px 0;
|
||
}
|
||
|
||
.download-btn {
|
||
background-color: #007bff;
|
||
color: white;
|
||
border: none;
|
||
padding: 10px 20px;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.download-btn:hover {
|
||
background-color: #0056b3;
|
||
}
|
||
|
||
.notification {
|
||
position: fixed;
|
||
top: 20px;
|
||
right: 20px;
|
||
padding: 15px;
|
||
border-radius: 4px;
|
||
color: white;
|
||
z-index: 1000;
|
||
}
|
||
|
||
.notification.success {
|
||
background-color: #28a745;
|
||
}
|
||
|
||
.notification.error {
|
||
background-color: #dc3545;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<h1>KMZ文件管理系统</h1>
|
||
|
||
<!-- 连接状态 -->
|
||
<div id="connection-status" class="status-indicator status-disconnected">
|
||
WebSocket未连接
|
||
</div>
|
||
|
||
<!-- KMZ文件信息 -->
|
||
<div id="kmz-info"></div>
|
||
|
||
<!-- 航点信息 -->
|
||
<div id="waypoints-info"></div>
|
||
|
||
<!-- 操作按钮 -->
|
||
<div id="kmz-actions"></div>
|
||
|
||
<!-- 日志区域 -->
|
||
<div id="log-area">
|
||
<h3>系统日志</h3>
|
||
<div id="log-content" style="height: 300px; overflow-y: auto; border: 1px solid #ccc; padding: 10px;"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<script src="websocket-manager.js"></script>
|
||
<script src="message-handler.js"></script>
|
||
<script src="kmz-file-handler.js"></script>
|
||
<script src="api-client.js"></script>
|
||
<script src="app.js"></script>
|
||
</body>
|
||
</html>
|
||
```
|
||
|
||
### 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到项目仓库
|
||
|
||
---
|
||
|
||
**注意**: 本指南基于当前系统实现,如有更新请及时同步文档。
|