# 任务清单接口设计方案 **日期**: 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` --- **文档结束**