QAUP_Management/doc/working/20250110_任务清单接口设计方案.md

808 lines
23 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 任务清单接口设计方案
**日期**: 2025-01-10
**版本**: v1.0
**目标**: 为无人车平台Mock服务增加任务清单接口
---
## 📋 需求背景
由无人车侧的平台mock提供一个单独的任务清单接口可以返回无人车所有的可执行任务。然后我们的应用请求这个接口选择某个任务下发给无人车去执行。
**核心概念**: 任务池/任务库 - 预定义的可执行任务模板清单
---
## 🎯 接口设计
### 接口信息
- **方法**: `GET /api/v1/missions/available`
- **认证**: Bearer Token (JWT)
- **响应**: `application/json; charset=utf-8`
- **功能**: 返回无人车平台的所有可执行任务清单
### 查询参数
| 参数名 | 类型 | 必填 | 描述 | 示例 |
|--------|------|------|------|------|
| missionType | string | 否 | 任务类型筛选 | PATROL_TRANSPORT, CARGO_TRANSPORT |
| priority | integer | 否 | 优先级筛选 | 1-5 |
| minBatteryLevel | integer | 否 | 最低电量要求 | 30 |
| limit | integer | 否 | 返回数量限制 | 10 |
| offset | integer | 否 | 分页偏移量 | 0 |
### 请求头
| Header | 必填 | 示例 | 说明 |
|--------|------|------|------|
| Authorization | 是 | Bearer eyJhbGciOi... | JWT 鉴权令牌 |
| Content-Type | 是 | application/json | 固定为 JSON |
| Accept | 否 | application/json | 建议显式声明 |
---
## 📦 数据结构设计
### 任务对象 (Mission)
```json
{
"missionId": "MISSION_TEMPLATE_001",
"missionName": "T1航站楼巡逻",
"missionType": "PATROL_TRANSPORT",
"description": "T1航站楼周边区域巡逻任务",
"priority": 3,
"estimatedDuration": 1800000,
"totalMileage": 2500.0,
"waypoints": [
{
"waypointId": "WP_001",
"latitude": 36.354068,
"longitude": 120.083410,
"waypointType": "START",
"name": "T1航站楼东侧",
"altitude": 10.5,
"estimatedArrivalTime": null
},
{
"waypointId": "WP_002",
"latitude": 36.355123,
"longitude": 120.084567,
"waypointType": "CHECKPOINT",
"name": "巡逻检查点A",
"altitude": 11.2,
"estimatedArrivalTime": null
},
{
"waypointId": "WP_003",
"latitude": 36.356789,
"longitude": 120.085234,
"waypointType": "END",
"name": "T1航站楼北侧",
"altitude": 10.8,
"estimatedArrivalTime": null
}
],
"requirements": {
"vehicleType": "UNMANNED",
"minBatteryLevel": 30,
"requiredSensors": ["GPS", "LIDAR", "CAMERA"],
"weatherConditions": "CLEAR | LIGHT_RAIN"
},
"metadata": {
"createdTime": 1736175000000,
"createdBy": "system",
"tags": ["patrol", "security", "routine"],
"zone": "TERMINAL_1"
}
}
```
### 字段说明
#### 基础信息
- `missionId` (string): 任务唯一标识
- `missionName` (string): 任务名称
- `missionType` (string): 任务类型
- `description` (string): 任务描述
- `priority` (integer): 优先级 1-5数字越大优先级越高
#### 时间和里程
- `estimatedDuration` (integer): 预计执行时长(毫秒)
- `totalMileage` (number): 预计总里程(米)
#### 路径点 (waypoints)
- `waypointId` (string): 路径点ID
- `latitude` (number): 纬度 (WGS84)
- `longitude` (number): 经度 (WGS84)
- `waypointType` (string): 路径点类型
- `START`: 起点
- `CHECKPOINT`: 检查点
- `WAYPOINT`: 普通路径点
- `END`: 终点
- `name` (string): 路径点名称
- `altitude` (number, 可选): 海拔高度(米)
- `estimatedArrivalTime` (integer, 可选): 预计到达时间毫秒UTC
#### 任务要求 (requirements)
- `vehicleType` (string): 车辆类型要求
- `minBatteryLevel` (integer): 最低电量要求 (0-100)
- `requiredSensors` (array): 必需的传感器列表
- `weatherConditions` (string): 可执行天气条件
#### 元数据 (metadata)
- `createdTime` (integer): 创建时间毫秒UTC
- `createdBy` (string): 创建者
- `tags` (array): 标签列表
- `zone` (string): 区域标识
---
## 📡 响应格式
### 成功响应 (200 OK)
```json
{
"code": 200,
"message": "success",
"timestamp": 1736175610000,
"data": {
"total": 5,
"missions": [
{
"missionId": "MISSION_TEMPLATE_001",
"missionName": "T1航站楼巡逻",
"missionType": "PATROL_TRANSPORT",
"description": "T1航站楼周边区域巡逻任务",
"priority": 3,
"estimatedDuration": 1800000,
"totalMileage": 2500.0,
"waypoints": [...],
"requirements": {...},
"metadata": {...}
},
{
"missionId": "MISSION_TEMPLATE_002",
"missionName": "货物运输-仓库A到登机口B3",
"missionType": "CARGO_TRANSPORT",
"priority": 4,
"estimatedDuration": 900000,
"totalMileage": 1200.0,
"waypoints": [...],
"requirements": {...},
"metadata": {...}
}
]
}
}
```
### 错误响应
#### 401 未授权
```json
{
"code": 401,
"message": "Unauthorized: Invalid or expired token",
"timestamp": 1736175610000,
"data": null
}
```
#### 400 参数错误
```json
{
"code": 400,
"message": "Invalid parameter: missionType must be one of [PATROL_TRANSPORT, CARGO_TRANSPORT, PASSENGER_TRANSPORT]",
"timestamp": 1736175610000,
"data": null
}
```
---
## 🗂️ 任务类型定义
### 标准任务类型
| 任务类型 | 代码 | 描述 |
|---------|------|------|
| 巡逻运输 | PATROL_TRANSPORT | 定期巡逻和安全检查 |
| 货物运输 | CARGO_TRANSPORT | 货物运输和配送 |
| 客运服务 | PASSENGER_TRANSPORT | 旅客运输服务 |
| 应急响应 | EMERGENCY_RESPONSE | 应急事件响应 |
| 维护检查 | MAINTENANCE_INSPECTION | 设施维护和检查 |
| 清洁作业 | CLEANING_OPERATION | 清洁和环境维护 |
---
## 🔧 实现方案
### 1. 数据存储结构
`mock_unmanned_vehicle.py` 中定义任务池:
```python
# 可执行任务清单(任务模板库)
AVAILABLE_MISSIONS = [
{
"missionId": "MISSION_TEMPLATE_001",
"missionName": "T1航站楼巡逻",
"missionType": "PATROL_TRANSPORT",
"description": "T1航站楼周边区域巡逻任务",
"priority": 3,
"estimatedDuration": 1800000,
"totalMileage": 2500.0,
"waypoints": [
{
"waypointId": "WP_T1_001",
"latitude": 36.354068,
"longitude": 120.083410,
"waypointType": "START",
"name": "T1航站楼东侧",
"altitude": 10.5
},
{
"waypointId": "WP_T1_002",
"latitude": 36.355123,
"longitude": 120.084567,
"waypointType": "CHECKPOINT",
"name": "巡逻检查点A",
"altitude": 11.2
},
{
"waypointId": "WP_T1_003",
"latitude": 36.356789,
"longitude": 120.085234,
"waypointType": "END",
"name": "T1航站楼北侧",
"altitude": 10.8
}
],
"requirements": {
"vehicleType": "UNMANNED",
"minBatteryLevel": 30,
"requiredSensors": ["GPS", "LIDAR", "CAMERA"],
"weatherConditions": "CLEAR | LIGHT_RAIN"
},
"metadata": {
"createdTime": 1736175000000,
"createdBy": "system",
"tags": ["patrol", "security", "routine"],
"zone": "TERMINAL_1"
}
},
{
"missionId": "MISSION_TEMPLATE_002",
"missionName": "货物运输-仓库A到登机口B3",
"missionType": "CARGO_TRANSPORT",
"description": "从货物仓库A运输至B3登机口",
"priority": 4,
"estimatedDuration": 900000,
"totalMileage": 1200.0,
"waypoints": [
{
"waypointId": "WP_CARGO_001",
"latitude": 36.352000,
"longitude": 120.082000,
"waypointType": "START",
"name": "货物仓库A",
"altitude": 9.5
},
{
"waypointId": "WP_CARGO_002",
"latitude": 36.353500,
"longitude": 120.083500,
"waypointType": "WAYPOINT",
"name": "运输通道中点",
"altitude": 10.0
},
{
"waypointId": "WP_CARGO_003",
"latitude": 36.355000,
"longitude": 120.085000,
"waypointType": "END",
"name": "B3登机口",
"altitude": 10.2
}
],
"requirements": {
"vehicleType": "UNMANNED",
"minBatteryLevel": 25,
"requiredSensors": ["GPS", "CAMERA"],
"weatherConditions": "CLEAR | LIGHT_RAIN | CLOUDY",
"maxCargoWeight": 500
},
"metadata": {
"createdTime": 1736175100000,
"createdBy": "system",
"tags": ["cargo", "logistics", "high-priority"],
"zone": "CARGO_AREA"
}
},
{
"missionId": "MISSION_TEMPLATE_003",
"missionName": "T2航站楼接驳",
"missionType": "PASSENGER_TRANSPORT",
"description": "T2航站楼旅客接驳服务",
"priority": 5,
"estimatedDuration": 600000,
"totalMileage": 800.0,
"waypoints": [
{
"waypointId": "WP_T2_001",
"latitude": 36.358000,
"longitude": 120.086000,
"waypointType": "START",
"name": "T2到达大厅",
"altitude": 11.0
},
{
"waypointId": "WP_T2_002",
"latitude": 36.359000,
"longitude": 120.087000,
"waypointType": "END",
"name": "T2出发大厅",
"altitude": 11.5
}
],
"requirements": {
"vehicleType": "UNMANNED",
"minBatteryLevel": 40,
"requiredSensors": ["GPS", "LIDAR", "CAMERA", "ULTRASONIC"],
"weatherConditions": "CLEAR | CLOUDY",
"maxPassengerCount": 4
},
"metadata": {
"createdTime": 1736175200000,
"createdBy": "system",
"tags": ["passenger", "shuttle", "high-priority"],
"zone": "TERMINAL_2"
}
},
{
"missionId": "MISSION_TEMPLATE_004",
"missionName": "跑道周边应急巡查",
"missionType": "EMERGENCY_RESPONSE",
"description": "跑道周边区域应急巡查任务",
"priority": 5,
"estimatedDuration": 1200000,
"totalMileage": 3500.0,
"waypoints": [
{
"waypointId": "WP_RUNWAY_001",
"latitude": 36.360000,
"longitude": 120.088000,
"waypointType": "START",
"name": "跑道17端",
"altitude": 8.0
},
{
"waypointId": "WP_RUNWAY_002",
"latitude": 36.365000,
"longitude": 120.090000,
"waypointType": "CHECKPOINT",
"name": "跑道中段检查点",
"altitude": 8.5
},
{
"waypointId": "WP_RUNWAY_003",
"latitude": 36.370000,
"longitude": 120.092000,
"waypointType": "END",
"name": "跑道35端",
"altitude": 9.0
}
],
"requirements": {
"vehicleType": "UNMANNED",
"minBatteryLevel": 50,
"requiredSensors": ["GPS", "LIDAR", "CAMERA", "THERMAL"],
"weatherConditions": "ANY",
"emergencyLightRequired": true
},
"metadata": {
"createdTime": 1736175300000,
"createdBy": "system",
"tags": ["emergency", "runway", "critical"],
"zone": "RUNWAY_AREA"
}
},
{
"missionId": "MISSION_TEMPLATE_005",
"missionName": "停机坪维护巡检",
"missionType": "MAINTENANCE_INSPECTION",
"description": "停机坪设施维护巡检",
"priority": 2,
"estimatedDuration": 2400000,
"totalMileage": 4200.0,
"waypoints": [
{
"waypointId": "WP_APRON_001",
"latitude": 36.351000,
"longitude": 120.081000,
"waypointType": "START",
"name": "停机坪A1",
"altitude": 10.0
},
{
"waypointId": "WP_APRON_002",
"latitude": 36.352500,
"longitude": 120.082500,
"waypointType": "CHECKPOINT",
"name": "停机坪A5",
"altitude": 10.2
},
{
"waypointId": "WP_APRON_003",
"latitude": 36.354000,
"longitude": 120.084000,
"waypointType": "CHECKPOINT",
"name": "停机坪B2",
"altitude": 10.5
},
{
"waypointId": "WP_APRON_004",
"latitude": 36.355500,
"longitude": 120.085500,
"waypointType": "END",
"name": "停机坪B8",
"altitude": 10.8
}
],
"requirements": {
"vehicleType": "UNMANNED",
"minBatteryLevel": 35,
"requiredSensors": ["GPS", "CAMERA", "INSPECTION_TOOLS"],
"weatherConditions": "CLEAR | CLOUDY"
},
"metadata": {
"createdTime": 1736175400000,
"createdBy": "system",
"tags": ["maintenance", "inspection", "routine"],
"zone": "APRON_AREA"
}
}
]
# 任务类型枚举
MISSION_TYPES = {
"PATROL_TRANSPORT": "巡逻运输",
"CARGO_TRANSPORT": "货物运输",
"PASSENGER_TRANSPORT": "客运服务",
"EMERGENCY_RESPONSE": "应急响应",
"MAINTENANCE_INSPECTION": "维护检查",
"CLEANING_OPERATION": "清洁作业"
}
```
### 2. 接口处理函数
```python
@app.route('/api/v1/missions/available', methods=['GET', 'OPTIONS'])
def get_available_missions():
"""
获取可执行任务清单
查询参数:
- missionType: 任务类型筛选
- priority: 优先级筛选
- minBatteryLevel: 最低电量要求
- limit: 返回数量限制
- offset: 分页偏移量
"""
# 处理 CORS 预检请求
if request.method == 'OPTIONS':
return '', 200
try:
# 获取查询参数
mission_type = request.args.get('missionType')
priority = request.args.get('priority', type=int)
min_battery = request.args.get('minBatteryLevel', type=int)
limit = request.args.get('limit', type=int, default=100)
offset = request.args.get('offset', type=int, default=0)
# 筛选任务
filtered_missions = AVAILABLE_MISSIONS.copy()
# 按任务类型筛选
if mission_type:
if mission_type not in MISSION_TYPES:
return jsonify({
"code": 400,
"message": f"Invalid missionType. Must be one of {list(MISSION_TYPES.keys())}",
"timestamp": int(time.time() * 1000),
"data": None
}), 400
filtered_missions = [m for m in filtered_missions if m["missionType"] == mission_type]
# 按优先级筛选
if priority is not None:
if priority < 1 or priority > 5:
return jsonify({
"code": 400,
"message": "Invalid priority. Must be between 1 and 5",
"timestamp": int(time.time() * 1000),
"data": None
}), 400
filtered_missions = [m for m in filtered_missions if m["priority"] == priority]
# 按电量要求筛选
if min_battery is not None:
if min_battery < 0 or min_battery > 100:
return jsonify({
"code": 400,
"message": "Invalid minBatteryLevel. Must be between 0 and 100",
"timestamp": int(time.time() * 1000),
"data": None
}), 400
filtered_missions = [
m for m in filtered_missions
if m["requirements"]["minBatteryLevel"] <= min_battery
]
# 分页处理
total = len(filtered_missions)
paginated_missions = filtered_missions[offset:offset + limit]
# 构造响应
response = {
"code": 200,
"message": "success",
"timestamp": int(time.time() * 1000),
"data": {
"total": total,
"limit": limit,
"offset": offset,
"missions": paginated_missions
}
}
logging.info(f"返回 {len(paginated_missions)} 个可执行任务 (总数: {total})")
return jsonify(response), 200
except Exception as e:
logging.error(f"获取任务清单失败: {str(e)}")
return jsonify({
"code": 500,
"message": f"Internal server error: {str(e)}",
"timestamp": int(time.time() * 1000),
"data": None
}), 500
```
### 3. CORS 配置
确保在文件中已有 CORS 配置:
```python
@app.after_request
def after_request(response):
"""添加 CORS 头"""
response.headers.add('Access-Control-Allow-Origin', '*')
response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization,Accept,X-Request-Id')
response.headers.add('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,OPTIONS')
return response
```
---
## 🧪 测试用例
### 1. 获取所有任务
```bash
curl -X GET "http://localhost:5000/api/v1/missions/available" \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." \
-H "Accept: application/json"
```
### 2. 按任务类型筛选
```bash
curl -X GET "http://localhost:5000/api/v1/missions/available?missionType=CARGO_TRANSPORT" \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." \
-H "Accept: application/json"
```
### 3. 按优先级筛选
```bash
curl -X GET "http://localhost:5000/api/v1/missions/available?priority=5" \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." \
-H "Accept: application/json"
```
### 4. 按电量要求筛选
```bash
curl -X GET "http://localhost:5000/api/v1/missions/available?minBatteryLevel=50" \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." \
-H "Accept: application/json"
```
### 5. 分页查询
```bash
curl -X GET "http://localhost:5000/api/v1/missions/available?limit=2&offset=0" \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." \
-H "Accept: application/json"
```
### 6. 组合筛选
```bash
curl -X GET "http://localhost:5000/api/v1/missions/available?missionType=PATROL_TRANSPORT&priority=3&limit=10" \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." \
-H "Accept: application/json"
```
---
## 📐 实施步骤
### Phase 1: 基础实现 ✅
1.`mock_unmanned_vehicle.py` 中添加任务池数据结构约200行
2. 实现 `/api/v1/missions/available` 接口约80行
3. 添加基本的任务类型和优先级筛选
4. 测试接口基本功能
### Phase 2: 增强功能
1. 添加更多样化的任务模板(不同区域、不同类型)
2. 实现高级筛选(按区域、按标签、按天气条件等)
3. 添加任务搜索功能(按名称、描述关键字)
4. 优化分页性能
### Phase 3: 集成与扩展
1. 与任务下发接口集成(下一步需求)
2. 添加任务状态管理(可执行、进行中、已完成)
3. 实现任务动态更新机制
4. 添加任务执行统计和历史记录
---
## 🔗 与现有系统的集成
### 与 `/status` 接口的关系
- `/status` 接口:返回车辆当前正在执行的任务状态
- `/missions/available` 接口:返回可供选择的任务清单
### 数据一致性
任务模板中的字段结构应与 `missionContext` 保持一致:
```python
# 当任务被分配给车辆时,从任务模板创建任务实例
def assign_mission_to_vehicle(vehicle_id, mission_template_id):
template = get_mission_template(mission_template_id)
# 创建任务实例
mission_instance = {
"missionId": f"{template['missionId']}_INSTANCE_{timestamp}",
"missionType": template["missionType"],
"startTime": int(time.time() * 1000),
"estimatedEndTime": int(time.time() * 1000) + template["estimatedDuration"],
"progress": 0.0,
"totalMileage": template["totalMileage"],
"waypoints": [
{**wp, "status": "PENDING"}
for wp in template["waypoints"]
]
}
# 更新车辆数据
vehicle_data["mission_id"] = mission_instance["missionId"]
vehicle_data["mission_type"] = mission_instance["missionType"]
vehicle_data["mission_start_time"] = mission_instance["startTime"]
return mission_instance
```
---
## 📊 后续扩展方向
### 1. 任务下发接口
```
POST /api/v1/vehicles/{vehicleId}/missions
```
用于将选中的任务分配给指定车辆。
### 2. 任务管理接口
```
GET /api/v1/missions/{missionId} # 获取任务详情
PUT /api/v1/missions/{missionId} # 更新任务
DELETE /api/v1/missions/{missionId} # 删除任务
POST /api/v1/missions # 创建新任务模板
```
### 3. 任务执行控制
```
POST /api/v1/vehicles/{vehicleId}/missions/{missionId}/pause # 暂停任务
POST /api/v1/vehicles/{vehicleId}/missions/{missionId}/resume # 恢复任务
POST /api/v1/vehicles/{vehicleId}/missions/{missionId}/cancel # 取消任务
```
### 4. 任务统计与分析
```
GET /api/v1/missions/statistics # 任务统计信息
GET /api/v1/missions/history # 任务执行历史
```
---
## ✅ 验收标准
1. **接口可访问性**
- [ ] 接口正常响应 200 状态码
- [ ] 支持 CORS 跨域请求
- [ ] JWT 认证正常工作
2. **数据完整性**
- [ ] 每个任务包含所有必需字段
- [ ] 路径点数据完整且符合规范
- [ ] 任务类型和状态枚举值正确
3. **筛选功能**
- [ ] 按任务类型筛选正常
- [ ] 按优先级筛选正常
- [ ] 按电量要求筛选正常
- [ ] 多条件组合筛选正常
4. **分页功能**
- [ ] limit 和 offset 参数正常工作
- [ ] total 字段返回正确的总数
- [ ] 边界情况处理正确
5. **错误处理**
- [ ] 无效参数返回 400 错误
- [ ] 未授权访问返回 401 错误
- [ ] 服务器错误返回 500 错误
- [ ] 错误消息清晰易懂
6. **性能要求**
- [ ] 响应时间 < 500ms
- [ ] 支持并发请求
- [ ] 日志记录完整
---
## 📝 附录
### A. 坐标系统说明
所有坐标使用 **WGS84 坐标系**
- 纬度范围: -90 ~ 90
- 经度范围: -180 ~ 180
- 青岛胶东国际机场参考中心: (120.0834104, 36.35406879)
### B. 时间格式说明
所有时间戳使用 **毫秒级 UTC 时间**
- 格式: Unix timestamp (milliseconds)
- 示例: 1736175610000
- 转换: `int(time.time() * 1000)`
### C. 参考文档
- 通用无人车运行状态API: `doc/requirement/universal_autonomous_vehicle_api_min_required.md`
- Mock服务主文件: `tools/mock_unmanned_vehicle.py`
- 项目说明文档: `CLAUDE.md`
---
**文档结束**