QDAirPortBackend0122/doc/work/20250110_任务清单接口设计方案.md
2026-01-22 13:19:47 +08:00

23 KiB
Raw Blame History

任务清单接口设计方案

日期: 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)

{
  "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)

{
  "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 未授权

{
  "code": 401,
  "message": "Unauthorized: Invalid or expired token",
  "timestamp": 1736175610000,
  "data": null
}

400 参数错误

{
  "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 中定义任务池:

# 可执行任务清单(任务模板库)
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. 接口处理函数

@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 配置:

@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. 获取所有任务

curl -X GET "http://localhost:5000/api/v1/missions/available" \
  -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." \
  -H "Accept: application/json"

2. 按任务类型筛选

curl -X GET "http://localhost:5000/api/v1/missions/available?missionType=CARGO_TRANSPORT" \
  -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." \
  -H "Accept: application/json"

3. 按优先级筛选

curl -X GET "http://localhost:5000/api/v1/missions/available?priority=5" \
  -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." \
  -H "Accept: application/json"

4. 按电量要求筛选

curl -X GET "http://localhost:5000/api/v1/missions/available?minBatteryLevel=50" \
  -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." \
  -H "Accept: application/json"

5. 分页查询

curl -X GET "http://localhost:5000/api/v1/missions/available?limit=2&offset=0" \
  -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." \
  -H "Accept: application/json"

6. 组合筛选

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 保持一致:

# 当任务被分配给车辆时,从任务模板创建任务实例
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

文档结束