Initial commit

This commit is contained in:
zyp
2026-05-22 16:13:20 +08:00
commit b3089a254e
1444 changed files with 372077 additions and 0 deletions

648
前端集成文档.md Normal file
View File

@@ -0,0 +1,648 @@
# 区域侦查任务前端集成文档
## 📋 概述
本文档详细说明前端如何集成区域侦查任务API包括接口调用、数据格式、错误处理等完整的前端集成方案。
## 🚀 快速开始
### 基础配置
```javascript
// API基础配置
const API_BASE_URL = 'http://localhost:8080/api/v1/region-reconnaissance';
// 动态获取鉴权头(如有需要)
function getAuthHeaders() {
const token = window.localStorage.getItem('token');
return token ? { Authorization: `Bearer ${token}` } : {};
}
// 统一请求方法(基于 fetch
async function request(path, options = {}) {
const url = path.startsWith('http') ? path : `${API_BASE_URL}${path}`;
const headers = {
'Content-Type': 'application/json',
...getAuthHeaders(),
...(options.headers || {})
};
const response = await fetch(url, { ...options, headers });
// 尝试解析响应体(可能为 204 无内容)
let payload = null;
if (response.status !== 204) {
try {
payload = await response.json();
} catch {
// 非 JSON 响应体容忍
}
}
if (!response.ok) {
const message = payload?.message || `HTTP ${response.status}`;
throw new Error(message);
}
// 兼容 204 的删除等请求
return payload ?? { code: 200, message: 'OK', data: null };
}
```
## 📡 API接口集成
### 1. 创建区域侦查任务
#### 接口信息
- **URL**: `POST /api/v1/region-reconnaissance/tasks`
- **功能**: 创建新的区域侦查任务
- **返回**: 任务ID和创建结果
#### 前端实现
```javascript
/**
* 创建区域侦查任务
* @param {Object} taskData - 任务数据
* @returns {Promise<Object>} 创建结果
*/
async function createRegionReconnaissanceTask(taskData) {
try {
const result = await request('/tasks', {
method: 'POST',
body: JSON.stringify(taskData)
});
console.log('任务创建成功:', result);
return result;
} catch (error) {
console.error('创建任务失败:', error);
throw error;
}
}
```
#### 请求数据格式
```javascript
// 完整的任务创建数据示例(区域闭合由后端自动处理,前端无需首尾重复)
const taskData = {
taskName: "测试区域侦查任务",
taskType: 1, // 1-区域侦查, 2-航线侦查
regionZone: {
pointList: [
{ latitude: 39.9042, longitude: 116.4074, altitude: 100.0 },
{ latitude: 39.9142, longitude: 116.4174, altitude: 100.0 },
{ latitude: 39.9242, longitude: 116.4274, altitude: 100.0 }
]
},
description: "这是一个测试任务",
executeTime: "2025-01-27T10:00:00Z" // 使用 ISO 8601UTC
};
```
> 说明
> - 区域闭合规则:后端会基于点列表自动闭合多边形,前端不需要重复首尾点。
> - 时间与时区:所有时间字段使用 ISO 8601 UTC例如 `2025-01-27T10:00:00Z`)。服务端按 UTC 存储与计算,前端展示时可按本地时区格式化。
### 2. 获取任务列表
#### 接口信息
- **URL**: `GET /api/v1/region-reconnaissance/tasks`
- **功能**: 获取区域侦查任务列表
- **支持分页**: 是
#### 前端实现
```javascript
/**
* 获取任务列表
* @param {Object} params - 查询参数
* @returns {Promise<Object>} 任务列表
*/
async function getRegionReconnaissanceTasks(params = {}) {
try {
const qp = Object.fromEntries(
Object.entries({ page: params.page ?? 1, size: params.size ?? 10, ...params })
.filter(([, v]) => v !== undefined && v !== null && v !== '')
);
const queryParams = new URLSearchParams(qp).toString();
const result = await request(`/tasks?${queryParams}`, { method: 'GET' });
return result;
} catch (error) {
console.error('获取任务列表失败:', error);
throw error;
}
}
```
### 3. 获取任务详情
#### 接口信息
- **URL**: `GET /api/v1/region-reconnaissance/tasks/{taskId}`
- **功能**: 获取指定任务的详细信息
#### 前端实现
```javascript
/**
* 获取任务详情
* @param {string} taskId - 任务ID
* @returns {Promise<Object>} 任务详情
*/
async function getRegionReconnaissanceTaskDetail(taskId) {
try {
const result = await request(`/tasks/${taskId}`, { method: 'GET' });
return result;
} catch (error) {
console.error('获取任务详情失败:', error);
throw error;
}
}
```
### 4. 更新任务状态
#### 接口信息
- **URL**: `PUT /api/v1/region-reconnaissance/tasks/{taskId}/status`
- **功能**: 更新任务状态
#### 前端实现
```javascript
/**
* 更新任务状态
* @param {string} taskId - 任务ID
* @param {number} status - 新状态
* @returns {Promise<Object>} 更新结果
*/
async function updateTaskStatus(taskId, status) {
try {
const result = await request(`/tasks/${taskId}/status`, {
method: 'PUT',
body: JSON.stringify({ status })
});
return result;
} catch (error) {
console.error('更新任务状态失败:', error);
throw error;
}
}
```
### 5. 删除任务
#### 接口信息
- **URL**: `DELETE /api/v1/region-reconnaissance/tasks/{taskId}`
- **功能**: 删除指定任务
#### 前端实现
```javascript
/**
* 删除任务
* @param {string} taskId - 任务ID
* @returns {Promise<Object>} 删除结果
*/
async function deleteRegionReconnaissanceTask(taskId) {
try {
const result = await request(`/tasks/${taskId}`, { method: 'DELETE' });
return result; // 兼容 204无内容时返回 { code: 200, message: 'OK', data: null }
} catch (error) {
console.error('删除任务失败:', error);
throw error;
}
}
```
## 🎨 前端组件示例
### React组件示例
```jsx
import React, { useState, useEffect } from 'react';
const RegionReconnaissanceTaskManager = () => {
const [tasks, setTasks] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
// 获取任务列表
const fetchTasks = async () => {
setLoading(true);
try {
const result = await getRegionReconnaissanceTasks();
setTasks(result.data?.records ?? []);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
// 创建任务
const handleCreateTask = async (taskData) => {
try {
await createRegionReconnaissanceTask(taskData);
await fetchTasks(); // 刷新列表
alert('任务创建成功!');
} catch (err) {
alert(`创建失败: ${err.message}`);
}
};
// 删除任务
const handleDeleteTask = async (taskId) => {
if (window.confirm('确定要删除这个任务吗?')) {
try {
await deleteRegionReconnaissanceTask(taskId);
await fetchTasks(); // 刷新列表
alert('任务删除成功!');
} catch (err) {
alert(`删除失败: ${err.message}`);
}
}
};
useEffect(() => {
fetchTasks();
}, []);
return (
<div className="task-manager">
<h2>区域侦查任务管理</h2>
{loading && <div>加载中...</div>}
{error && <div className="error">错误: {error}</div>}
<div className="task-list">
{tasks.map(task => (
<div key={task.taskId} className="task-item">
<h3>{task.taskName}</h3>
<p>类型: {task.taskType === 1 ? '区域侦查' : '航线侦查'}</p>
<p>状态: {getStatusText(task.status)}</p>
<p>创建时间: {new Date(task.createTime).toLocaleString()}</p>
<button onClick={() => handleDeleteTask(task.taskId)}>
删除
</button>
</div>
))}
</div>
</div>
);
};
// 状态文本转换
const getStatusText = (status) => {
const statusMap = {
0: '待执行',
1: '执行中',
2: '已完成',
3: '已取消',
4: '执行失败'
};
return statusMap[status] || '未知状态';
};
export default RegionReconnaissanceTaskManager;
```
### Vue组件示例
```vue
<template>
<div class="task-manager">
<h2>区域侦查任务管理</h2>
<div v-if="loading" class="loading">加载中...</div>
<div v-if="error" class="error">错误: {{ error }}</div>
<div class="task-list">
<div
v-for="task in tasks"
:key="task.taskId"
class="task-item"
>
<h3>{{ task.taskName }}</h3>
<p>类型: {{ task.taskType === 1 ? '区域侦查' : '航线侦查' }}</p>
<p>状态: {{ getStatusText(task.status) }}</p>
<p>创建时间: {{ formatDate(task.createTime) }}</p>
<button @click="handleDeleteTask(task.taskId)">
删除
</button>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'RegionReconnaissanceTaskManager',
data() {
return {
tasks: [],
loading: false,
error: null
};
},
async mounted() {
await this.fetchTasks();
},
methods: {
async fetchTasks() {
this.loading = true;
try {
const result = await getRegionReconnaissanceTasks();
this.tasks = result.data?.records ?? [];
} catch (err) {
this.error = err.message;
} finally {
this.loading = false;
}
},
async handleCreateTask(taskData) {
try {
await createRegionReconnaissanceTask(taskData);
await this.fetchTasks();
alert('任务创建成功!');
} catch (err) {
alert(`创建失败: ${err.message}`);
}
},
async handleDeleteTask(taskId) {
if (confirm('确定要删除这个任务吗?')) {
try {
await deleteRegionReconnaissanceTask(taskId);
await this.fetchTasks();
alert('任务删除成功!');
} catch (err) {
alert(`删除失败: ${err.message}`);
}
}
},
getStatusText(status) {
const statusMap = {
0: '待执行',
1: '执行中',
2: '已完成',
3: '已取消',
4: '执行失败'
};
return statusMap[status] || '未知状态';
},
formatDate(dateString) {
return new Date(dateString).toLocaleString();
}
}
};
</script>
```
## 📊 数据格式说明
### 任务对象结构
```typescript
interface RegionReconnaissanceTask {
taskId: string; // 任务ID
taskName: string; // 任务名称
taskType: number; // 任务类型 (1-区域侦查, 2-航线侦查)
status: number; // 任务状态 (0-待执行, 1-执行中, 2-已完成, 3-已取消, 4-执行失败)
regionZone: RegionZone; // 区域信息
description?: string; // 任务描述
executeTime?: string; // 执行时间
createTime: string; // 创建时间
updateTime: string; // 更新时间
createUserId: string; // 创建用户ID
mqttSendStatus: number; // MQTT发送状态
}
interface RegionZone {
pointList: Point[]; // 区域点列表
}
interface Point {
latitude: number; // 纬度
longitude: number; // 经度
altitude: number; // 高度
}
```
### 响应数据格式
```typescript
// 成功响应
interface ApiResponse<T> {
code: number; // 响应码 (200-成功)
message: string; // 响应消息
data: T; // 响应数据
timestamp: string; // 时间戳
}
// 分页响应
interface PageResponse<T> {
code: number;
message: string;
data: {
records: T[]; // 数据列表
total: number; // 总记录数
size: number; // 每页大小
current: number; // 当前页码
pages: number; // 总页数
};
timestamp: string;
}
```
## ⚠️ 错误处理
### 常见错误码
```javascript
const ERROR_CODES = {
400: '请求参数错误',
401: '未授权访问',
403: '禁止访问',
404: '资源不存在',
500: '服务器内部错误',
1001: '任务名称不能为空',
1002: '区域点列表不能为空',
1003: '任务不存在',
1004: '任务状态不允许此操作'
};
```
### 错误处理示例
```javascript
/**
* 统一错误处理(配合 fetch 请求助手)
* @param {Error} error - 错误对象
* @returns {string} 用户友好的错误信息
*/
function handleApiError(error) {
// request() 已将后端 message 或 HTTP 状态转为 Error(message)
return error?.message || '请求失败';
}
```
## 🔧 工具函数
### 数据验证
```javascript
/**
* 验证任务数据
* @param {Object} taskData - 任务数据
* @returns {Object} 验证结果
*/
function validateTaskData(taskData) {
const errors = [];
if (!taskData.taskName || taskData.taskName.trim() === '') {
errors.push('任务名称不能为空');
}
if (![1, 2].includes(taskData.taskType)) {
errors.push('任务类型必须是1(区域侦查)或2(航线侦查)');
}
if (!taskData.regionZone || !Array.isArray(taskData.regionZone.pointList)) {
errors.push('区域信息不能为空');
} else if (taskData.regionZone.pointList.length < 3) {
errors.push('区域至少需要3个点');
}
return {
isValid: errors.length === 0,
errors
};
}
```
### 数据转换
```javascript
/**
* 转换区域数据为API格式
* @param {Array} points - 前端点数据
* @returns {Object} API格式的区域数据
*/
function convertRegionData(points) {
return {
pointList: points.map(point => ({
latitude: parseFloat(point.latitude),
longitude: parseFloat(point.longitude),
altitude: parseFloat(point.altitude) || 0
}))
};
}
```
## 📱 移动端适配
### 响应式设计
```css
/* 移动端适配 */
@media (max-width: 768px) {
.task-manager {
padding: 10px;
}
.task-item {
margin-bottom: 15px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
}
.task-item h3 {
font-size: 16px;
margin-bottom: 8px;
}
.task-item p {
font-size: 14px;
margin: 4px 0;
}
.task-item button {
width: 100%;
padding: 8px;
margin-top: 10px;
}
}
```
## 🧪 测试示例
### 单元测试
```javascript
// Jest测试示例
describe('RegionReconnaissanceTask API', () => {
test('创建任务', async () => {
const taskData = {
taskName: '测试任务',
taskType: 1,
regionZone: {
pointList: [
{ latitude: 39.9042, longitude: 116.4074, altitude: 100 },
{ latitude: 39.9142, longitude: 116.4174, altitude: 100 },
{ latitude: 39.9242, longitude: 116.4274, altitude: 100 }
]
}
};
const result = await createRegionReconnaissanceTask(taskData);
expect(result.code).toBe(200);
expect(result.data.taskId).toBeDefined();
});
test('获取任务列表', async () => {
const result = await getRegionReconnaissanceTasks();
expect(result.code).toBe(200);
expect(Array.isArray(result.data.records)).toBe(true);
});
});
```
## 📚 最佳实践
### 1. 错误处理
- 始终使用try-catch包装API调用
- 提供用户友好的错误信息
- 记录详细的错误日志用于调试
### 2. 数据验证
- 在发送请求前验证数据格式
- 使用TypeScript或PropTypes进行类型检查
- 提供实时验证反馈
### 3. 用户体验
- 显示加载状态
- 提供操作确认
- 使用乐观更新提升响应速度
### 4. 性能优化
- 实现数据缓存
- 使用分页加载大量数据
- 防抖处理用户输入
## 🔗 相关资源
- [后端API接口说明](./后端API接口说明.md)
- [前端对接指南](./前端对接指南.md)
- [前端集成说明](./前端集成说明.md)
## 📞 技术支持
如有问题,请联系开发团队或查看项目文档。
---
*最后更新: 2025-01-27*