VWED_server/routes/external_task_api.py
2025-07-30 15:11:59 +08:00

383 lines
14 KiB
Python
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.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
外部任务接口API模块
提供外部系统调用的任务创建接口
"""
import json
from typing import Dict, Any
from fastapi import APIRouter, Body, Request
from routes.model.external_task_model import ExternalTaskRequest, ExternalTaskResponse, TaskTypeEnum, GenAgvSchedulingTaskRequest
from routes.model.task_edit_model import TaskEditRunRequest, TaskInputParamNew, InputParamType
from services.task_edit_service import TaskEditService
from routes.common_api import format_response, error_response
from utils.logger import get_logger
from data.enum.task_record_enum import SourceType
from config.tf_api_config import TF_API_TOKEN
# tf_api_config = get_tf_api_config()
# 创建路由
router = APIRouter(
prefix="",
tags=["外部任务接口"]
)
# 设置日志
logger = get_logger("app.external_task_api")
# 任务类型到模板ID的映射
TASK_TYPE_TEMPLATE_MAPPING = {
TaskTypeEnum.GG2MP: "template_gg2mp_id", # 高柜到MP模板ID
TaskTypeEnum.GGFK2MP: "template_ggfk2mp_id", # 高柜发库到MP模板ID
TaskTypeEnum.GT2MP: "571985c1-cfa5-4186-8acd-6e3868a5e08c", # 高台到MP模板ID
TaskTypeEnum.GTFK2MP: "template_gtfk2mp_id", # 高台发库到MP模板ID
TaskTypeEnum.ZG2MP: "template_zg2mp_id", # 中柜到MP模板ID
TaskTypeEnum.QZ2MP: "template_qz2mp_id", # 清洗到MP模板ID
TaskTypeEnum.LG2MP: "template_lg2mp_id", # 料柜到MP模板ID
TaskTypeEnum.PHZ2MP: "template_phz2mp_id", # 配货站到MP模板ID
TaskTypeEnum.MP2GG: "template_mp2gg_id", # MP到高柜模板ID
TaskTypeEnum.MP2GGFK: "571985c1-cfa5-4186-8acd-6e3868a5e08c", # MP到高柜发库模板ID
TaskTypeEnum.MP2GT: "template_mp2gt_id", # MP到高台模板ID
TaskTypeEnum.MP2GTFK: "template_mp2gtfk_id", # MP到高台发库模板ID
TaskTypeEnum.MP2ZG: "template_mp2zg_id", # MP到中柜模板ID
TaskTypeEnum.MP2QZ: "template_mp2qz_id", # MP到清洗模板ID
TaskTypeEnum.MP2LG: "template_mp2lg_id", # MP到料柜模板ID
TaskTypeEnum.MP2PHZ: "template_mp2phz_id", # MP到配货站模板ID
}
@router.post("/newTask")
async def create_new_task(request: Request, task_request: ExternalTaskRequest = Body(...)):
"""
创建新任务接口
根据任务类型自动选择对应的任务模板并执行任务
Args:
task_request: 外部任务创建请求包含ReqCode、SourceID、TargetID、TaskType
Returns:
ExternalTaskResponse: 包含code、reqCode、message、rowCount的响应
"""
try:
logger.info(f"收到外部任务创建请求: ReqCode={task_request.ReqCode}, TaskType={task_request.TaskType}")
# 根据任务类型获取对应的模板ID
template_id = TASK_TYPE_TEMPLATE_MAPPING.get(task_request.TaskType)
# print("template_id::::", template_id, "==========")
if not template_id:
logger.error(f"不支持的任务类型: {task_request.TaskType}")
return ExternalTaskResponse(
code=400,
reqCode=task_request.ReqCode,
message=f"不支持的任务类型: {task_request.TaskType}",
rowCount=0
)
# 构造任务运行参数
task_params = []
# 添加SourceID参数如果提供
if task_request.SourceID:
task_params.append(TaskInputParamNew(
name="sourceId",
type=InputParamType.STRING,
label="来源ID",
required=False,
defaultValue=task_request.SourceID,
remark="外部接口传入的来源ID"
))
# 添加TargetID参数
task_params.append(TaskInputParamNew(
name="targetId",
type=InputParamType.STRING,
label="目标ID",
required=True,
defaultValue=task_request.TargetID,
remark="外部接口传入的目标ID"
))
# 添加ReqCode参数
task_params.append(TaskInputParamNew(
name="reqCode",
type=InputParamType.STRING,
label="请求标识码",
required=True,
defaultValue=task_request.ReqCode,
remark="外部接口传入的请求唯一标识码"
))
# 构造任务执行请求
run_request = TaskEditRunRequest(
taskId=template_id,
params=task_params,
source_type=SourceType.SYSTEM_SCHEDULING, # 第三方系统
source_system="EXTERNAL_API", # 外部接口系统标识
source_device=request.client.host if request.client else "unknown", # 使用客户端IP作为设备标识
use_modbus=False,
modbus_timeout=5000
)
# 获取客户端信息
client_ip = request.client.host if request.client else None
user_agent = request.headers.get("user-agent", "")
tf_api_token = TF_API_TOKEN
client_info = {
"user_agent": user_agent,
"headers": dict(request.headers),
"method": request.method,
"url": str(request.url)
}
client_info_str = json.dumps(client_info, ensure_ascii=False)
# print("tf_api_config::::::::::::", tf_api_token)
# print("run_request:::::::::", run_request)
# print("client_ip:::::::::", client_ip)
# print("client_info:::::::::", client_info)
# print("client_info_str:::::::::", client_info_str)
# print("tf_api_token:::::::::", tf_api_token)
# 调用任务执行服务
result = await TaskEditService.run_task(
run_request,
client_ip=client_ip,
client_info=client_info_str,
tf_api_token=tf_api_token
)
if result is None:
logger.error(f"任务启动失败: ReqCode={task_request.ReqCode}")
return ExternalTaskResponse(
code=500,
reqCode=task_request.ReqCode,
message="任务启动失败",
rowCount=0
)
if not result.get("success", False):
logger.error(f"任务启动失败: {result.get('message')}, ReqCode={task_request.ReqCode}")
return ExternalTaskResponse(
code=500,
reqCode=task_request.ReqCode,
message=result.get("message", "任务启动失败"),
rowCount=0
)
logger.info(f"任务启动成功: ReqCode={task_request.ReqCode}, TaskRecordId={result.get('taskRecordId')}")
return ExternalTaskResponse(
code=0,
reqCode=task_request.ReqCode,
message="成功",
rowCount=1
)
except Exception as e:
logger.error(f"创建外部任务异常: {str(e)}, ReqCode={task_request.ReqCode}")
return ExternalTaskResponse(
code=500,
reqCode=task_request.ReqCode,
message=f"创建任务失败: {str(e)}",
rowCount=0
)
@router.post("/GenAgvSchedulingTask")
async def gen_agv_scheduling_task(request: Request, task_request: GenAgvSchedulingTaskRequest = Body(...)):
"""
AGV调度任务接口
用于生成AGV调度任务
Args:
task_request: AGV调度任务请求包含ReqCode、TaskTyp、SecurityKey等参数
Returns:
ExternalTaskResponse: 包含code、reqCode、message、rowCount的响应
"""
try:
logger.info(f"收到AGV调度任务请求: ReqCode={task_request.ReqCode}, TaskTyp={task_request.TaskTyp}")
# # 验证安全密钥(可根据实际需求实现验证逻辑)
# if not task_request.SecurityKey:
# logger.error(f"安全密钥不能为空: ReqCode={task_request.ReqCode}")
# return ExternalTaskResponse(
# code=400,
# reqCode=task_request.ReqCode,
# message="安全密钥不能为空",
# rowCount=0GenAgvSchedulingTaskRequest
# )
# 根据任务类型获取对应的模板ID
template_id = TASK_TYPE_TEMPLATE_MAPPING.get(task_request.TaskTyp)
# if not template_id:
# logger.error(f"不支持的任务类型: {task_request.TaskTyp}, ReqCode={task_request.ReqCode}")
# return ExternalTaskResponse(
# code=400,
# reqCode=task_request.ReqCode,
# message=f"不支持的任务类型: {task_request.TaskTyp}",
# rowCount=0
# )
# 构造任务运行参数
task_params = []
# 添加任务代码参数
task_params.append(TaskInputParamNew(
name="taskCode",
type=InputParamType.STRING,
label="任务代码",
required=True,
defaultValue=task_request.TaskCode,
remark="AGV调度任务代码"
))
# 添加类型参数
task_params.append(TaskInputParamNew(
name="type",
type=InputParamType.STRING,
label="类型",
required=True,
defaultValue=task_request.Type,
remark="任务类型标识"
))
# 添加子类型参数
task_params.append(TaskInputParamNew(
name="subType",
type=InputParamType.STRING,
label="子类型",
required=True,
defaultValue=task_request.SubType,
remark="任务子类型标识"
))
# 添加区域位置代码参数
task_params.append(TaskInputParamNew(
name="areaPositonCode",
type=InputParamType.STRING,
label="区域位置代码",
required=True,
defaultValue=task_request.AreaPositonCode,
remark="区域位置代码"
))
# 添加区域位置名称参数
task_params.append(TaskInputParamNew(
name="areaPositonName",
type=InputParamType.STRING,
label="区域位置名称",
required=True,
defaultValue=task_request.AreaPositonName,
remark="区域位置名称"
))
# 添加位置代码路径参数转为JSON字符串
position_path_json = json.dumps([path.dict() for path in task_request.PositionCodePath], ensure_ascii=False)
task_params.append(TaskInputParamNew(
name="positionCodePath",
type=InputParamType.STRING,
label="位置代码路径",
required=True,
defaultValue=position_path_json,
remark="位置代码路径JSON数组"
))
# 添加客户端代码参数(如果提供)
if task_request.ClientCode:
task_params.append(TaskInputParamNew(
name="clientCode",
type=InputParamType.STRING,
label="客户端代码",
required=False,
defaultValue=task_request.ClientCode,
remark="客户端代码"
))
# 添加令牌代码参数(如果提供)
if task_request.TokenCode:
task_params.append(TaskInputParamNew(
name="tokenCode",
type=InputParamType.STRING,
label="令牌代码",
required=False,
defaultValue=task_request.TokenCode,
remark="令牌代码"
))
# 添加ReqCode参数
task_params.append(TaskInputParamNew(
name="reqCode",
type=InputParamType.STRING,
label="请求标识码",
required=True,
defaultValue=task_request.ReqCode,
remark="请求唯一标识码"
))
# 构造任务执行请求
run_request = TaskEditRunRequest(
taskId=template_id,
params=task_params,
source_type=SourceType.SYSTEM_SCHEDULING, # 第三方系统
source_system="AGV_SCHEDULING", # AGV调度系统标识
source_device=request.client.host if request.client else "unknown", # 使用客户端IP作为设备标识
use_modbus=False,
modbus_timeout=5000
)
# 获取客户端信息
client_ip = request.client.host if request.client else None
user_agent = request.headers.get("user-agent", "")
tf_api_token = TF_API_TOKEN
client_info = {
"user_agent": user_agent,
"headers": dict(request.headers),
"method": request.method,
"url": str(request.url)
}
client_info_str = json.dumps(client_info, ensure_ascii=False)
# 调用任务执行服务
result = await TaskEditService.run_task(
run_request,
client_ip=client_ip,
client_info=client_info_str,
tf_api_token=tf_api_token
)
if result is None:
logger.error(f"AGV调度任务启动失败: ReqCode={task_request.ReqCode}")
return ExternalTaskResponse(
code=500,
reqCode=task_request.ReqCode,
message="任务启动失败",
rowCount=0
)
if not result.get("success", False):
logger.error(f"AGV调度任务启动失败: {result.get('message')}, ReqCode={task_request.ReqCode}")
return ExternalTaskResponse(
code=500,
reqCode=task_request.ReqCode,
message=result.get("message", "任务启动失败"),
rowCount=0
)
logger.info(f"AGV调度任务启动成功: ReqCode={task_request.ReqCode}, TaskRecordId={result.get('taskRecordId')}")
return ExternalTaskResponse(
code=0,
reqCode=task_request.ReqCode,
message="成功",
rowCount=0
)
except Exception as e:
logger.error(f"创建AGV调度任务异常: {str(e)}, ReqCode={task_request.ReqCode}")
return ExternalTaskResponse(
code=500,
reqCode=task_request.ReqCode,
message=f"创建任务失败: {str(e)}",
rowCount=0
)