535 lines
22 KiB
Python
Raw Normal View History

2025-08-13 15:27:04 +08:00
import asyncio
from typing import Dict, Any
2025-08-15 10:58:25 +08:00
EXTERNAL_CALLBACK_URL = "http://roh.vwfawedl.mobi:9001/AGVService/ContainerSendBackRequest" # 生产线到毛坯库任务
2025-08-13 15:27:04 +08:00
async def test1(a: int, b: int) -> int:
return {"name": a + b}
2025-04-30 16:57:46 +08:00
2025-09-09 10:41:27 +08:00
def name1(*args, **kwargs):
return {"test": "12333"}
2025-08-13 15:27:04 +08:00
async def validate_task_condition(function_args: Dict[str, Any]) -> Dict[str, Any]:
"""
任务状态验证功能用于验证关联任务的状态
Args:
function_args: 包含以下参数的字典
- task_code: 任务代码用于查询外部任务记录
- task_type: 任务类型用于判断验证逻辑
- end_node: 终点节点仅对GT类型任务需要
Returns:
Dict[str, Any]: 验证结果
"""
from services.external_task_record_service import ExternalTaskRecordService
from services.task_record_service import TaskRecordService
from data.session import get_async_session
from data.models.operate_point_layer import OperatePointLayer
from data.enum.task_record_enum import TaskStatus
from sqlalchemy import select
from utils.logger import get_logger
logger = get_logger("scripts.user_save.test1")
# print(function_args, "=========================")
try:
# 获取参数
task_code = function_args.get('task_code')
task_type = function_args.get('task_type')
end_node = function_args.get('end_node')
if not task_code:
return {
"success": False,
"message": "task_code参数为空"
}
if not task_type:
return {
"success": False,
"message": "task_type参数为空"
}
# 定义任务类型模板映射
TASK_TYPE_TEMPLATE_MAPPING = {
"GG2MP": "GG",
"GGFK2MP": "GG",
"GT2MP": "GT",
"GTFK2MP": "GT",
"ZG2MP": "ZG",
"QZ2MP": "QZ",
"LG2MP": "LG",
"PHZ2MP": "PHZ",
"MP2GG": "GG",
"MP2GGFK": "GG",
"MP2GT": "GT",
"MP2GTFK": "GT",
"MP2ZG": "ZG",
"MP2QZ": "QZ",
"MP2LG": "LG",
"MP2PHZ": "PHZ"
}
# 根据TaskCode查询external_task_record表获取task_record_id
external_records = await ExternalTaskRecordService.get_task_records_by_task_code(task_code)
logger.info(f"系统相关记录: {external_records}")
if not external_records:
return {
"success": False,
"message": f"找不到TaskCode={task_code}对应的叫料任务记录,无法监控叫料任务状态"
}
# 获取最新的记录
latest_record = max(external_records, key=lambda x: x.created_at)
if not latest_record.task_record_id:
return {
"success": False,
"message": "叫料任务记录对应关键字task_record_id值为空"
}
# 获取TaskType对应的模板类型
template_type = TASK_TYPE_TEMPLATE_MAPPING.get(task_type, "")
logger.info(f"TaskCode={task_code}, TaskType={task_type}, TemplateType={template_type}")
2025-08-15 10:58:25 +08:00
while True:
try:
async with get_async_session() as session:
# 查询end_node对应的库位锁定状态
stmt = select(OperatePointLayer).where(
OperatePointLayer.layer_name == end_node,
OperatePointLayer.is_deleted == False
).limit(1)
result = await session.execute(stmt)
end_layer = result.scalar_one_or_none()
task_detail_result = await TaskRecordService.get_task_record_detail(
latest_record.task_record_id)
2025-08-13 15:27:04 +08:00
task_detail = task_detail_result.get("data", {})
task_status = task_detail.get("status", "")
2025-08-15 10:58:25 +08:00
if task_status == TaskStatus.CANCELED:
2025-08-13 15:27:04 +08:00
return {
"success": True,
2025-08-15 10:58:25 +08:00
"message": f"任务被取消: TaskCode={task_code}, Status={task_status}"
2025-08-13 15:27:04 +08:00
}
2025-08-15 10:58:25 +08:00
if end_layer:
if not end_layer.is_locked:
return {
"success": True,
"message": f"任务验证通过end_node库位已解锁: {end_node}"
}
else:
logger.info(f"任务end_node库位被锁定等待解锁: TaskCode={task_code}, end_node={end_node}, locked_by={end_layer.locked_by}")
await asyncio.sleep(2) # 等待2秒后重试
else:
logger.warning(f"任务未找到end_node对应的库位继续执行: TaskCode={task_code}, end_node={end_node}")
2025-08-13 15:27:04 +08:00
return {
"success": True,
2025-08-15 10:58:25 +08:00
"message": f"任务验证通过,未找到对应库位,继续执行: {end_node}"
2025-08-13 15:27:04 +08:00
}
2025-08-15 10:58:25 +08:00
except Exception as e:
logger.error(f"任务检查end_node库位锁定状态时出现异常: {str(e)}, TaskCode={task_code}, end_node={end_node}")
await asyncio.sleep(2) # 等待2秒后重试
2025-08-13 15:27:04 +08:00
except Exception as e:
logger.error(f"任务状态验证异常: {str(e)}")
return {
"success": False,
"message": f"任务状态验证异常: {str(e)}"
2025-08-15 10:58:25 +08:00
}
async def call_external_callback(req_code: str, task_type: str, arrival_user: str = "000307" ) -> dict:
"""
调用外部回调接口
Args:
req_code: 到货编号ReqCode
task_type: 任务类型
arrival_user: 到货用户固定值 000307
Returns:
bool: 调用是否成功返回result为0
"""
arrival_no = req_code
import aiohttp
from utils.logger import get_logger
logger = get_logger("scripts.user_save.test1")
if task_type not in ["GTFK2MP", "GGFK2MP"]:
return {"message": "不是返空类型 不需要过账"}
payload = {
"arrival_no": arrival_no,
"arrival_user": arrival_user
}
max_retries = 100 # 最大重试次数,防止无限循环
retry_count = 0
while retry_count < max_retries:
try:
async with aiohttp.ClientSession() as sessions:
async with sessions.post(EXTERNAL_CALLBACK_URL, json=payload) as response:
result = await response.json()
logger.info(f"外部接口调用响应: {result}, arrival_no={arrival_no}, 重试次数={retry_count}")
# 检查响应结果
if result.get("result") == "0":
logger.info(f"外部接口调用成功: arrival_no={arrival_no}, 总重试次数={retry_count}")
return {"message": "空托盘过账成功!"}
elif result.get("result") == "1":
logger.info(f"外部接口返回result=1继续重试: arrival_no={arrival_no}, 重试次数={retry_count}")
retry_count += 1
await asyncio.sleep(5) # 等待5秒后重试
else:
logger.error(f"外部接口返回异常结果: {result}, arrival_no={arrival_no}")
retry_count += 1
await asyncio.sleep(5)
except Exception as e:
logger.error(f"调用外部接口异常: {str(e)}, arrival_no={arrival_no}, 重试次数={retry_count}")
retry_count += 1
await asyncio.sleep(5) # 等待5秒后重试
logger.error(f"外部接口调用失败,已达到最大重试次数: arrival_no={arrival_no}, 最大重试次数={max_retries}")
2025-09-09 10:41:27 +08:00
return {"message": "空托盘过账失败,重新尝试次数达到最大值"}
async def get_location(location_list: list, location_key: str) -> dict:
"""
根据当前库位获取下一个库位站点轮回逻辑
Args:
location_list: 库位列表格式如 ["1-1", "1-2", "1-3", "1-4"]
location_key: 当前库位的key "1-2"
Returns:
str: 下一个库位 "1-3"
Example:
location_list = ["1-1", "1-2", "1-3", "1-4"]
await get_location(location_list, "1-2") # 返回 "1-3"
await get_location(location_list, "1-4") # 返回 "1-1" (轮回到第一个)
"""
try:
if not location_list:
raise ValueError("location_list不能为空")
if location_key not in location_list:
raise ValueError(f"location_key '{location_key}' 不存在于location_list中")
# 找到当前库位在列表中的位置
current_index = location_list.index(location_key)
# 计算下一个位置的索引(轮回逻辑)
next_index = (current_index + 1) % len(location_list)
# 返回下一个位置的库位
next_location_key = location_list[next_index]
return {"next_location_key": next_location_key}
except Exception as e:
# 如果出现异常,返回错误信息或默认值
from utils.logger import get_logger
logger = get_logger("scripts.user_save.test1")
logger.error(f"get_location函数执行异常: {str(e)}")
# 可以选择抛出异常或返回默认值
raise ValueError(f"get_location执行失败: {str(e)}")
# print(asyncio.run(get_location(["1-1", "1-2", "1-3", "1-4"], "1-4")))
async def find_movable_vehicle_in_loop(vehicle_list: list, location_list: list) -> dict:
"""
在环线工区中找到可以移动的小车
根据库位锁定者来判断小车现在所在位置并检查前方库位是否可用
Args:
vehicle_list: 小车名称列表 ['amd1', 'amd2', 'amd3']
location_list: 库位名称列表按环线顺序 ['1-1', '1-2', '1-3', '1-4']
环线逻辑1-1->1-2->1-3->1-4->1-1循环
Returns:
dict: {
'movable_vehicle': str or None, # 可以移动的小车名称
'target_location': str or None, # 前方可用的库位名称
'current_location': str or None, # 当前锁定的库位名称
'message': str # 状态描述
}
Example:
vehicle_list = ['amd1', 'amd2', 'amd3']
location_list = ['1-1', '1-2', '1-3', '1-4']
result = await find_movable_vehicle_in_loop(vehicle_list, location_list)
# 返回: {'movable_vehicle': 'amd3', 'target_location': '1-4', 'current_location': '1-3', 'message': '...'}
"""
from data.session import get_async_session
from data.models.operate_point_layer import OperatePointLayer
from sqlalchemy import select
from utils.logger import get_logger
logger = get_logger("scripts.user_save.test1")
try:
if not vehicle_list:
return {
'movable_vehicle': None,
'target_location': None,
'current_location': None,
'message': 'vehicle_list参数为空'
}
if not location_list:
return {
'movable_vehicle': None,
'target_location': None,
'current_location': None,
'message': 'location_list参数为空'
}
async with get_async_session() as session:
# 1. 找出所有被指定小车锁定的库位,记录每个小车的当前位置
vehicle_positions = {} # {vehicle_name: {'location': str, 'location_index': int, 'location_obj': obj}}
# 查询所有库位的锁定情况
stmt = select(OperatePointLayer).where(
OperatePointLayer.layer_name.in_(location_list),
OperatePointLayer.is_deleted == False,
OperatePointLayer.is_locked == True,
OperatePointLayer.locked_by.in_(vehicle_list)
)
result = await session.execute(stmt)
locked_locations = result.scalars().all()
# 建立小车位置映射
for location in locked_locations:
vehicle_name = location.locked_by
if location.layer_name in location_list:
location_index = location_list.index(location.layer_name)
vehicle_positions[vehicle_name] = {
'location': location.layer_name,
'location_index': location_index,
'location_obj': location
}
if not vehicle_positions:
return {
'movable_vehicle': None,
'target_location': None,
'current_location': None,
'message': '环线中没有被指定小车锁定的库位'
}
logger.info(f"当前小车位置: {[(k, v['location']) for k, v in vehicle_positions.items()]}")
# 2. 按环线顺序检查每个小车前方的库位是否可用
location_count = len(location_list)
for vehicle_name, position_info in vehicle_positions.items():
current_location_index = position_info['location_index']
current_location = position_info['location']
# 计算下一个库位位置(环线循环)
next_location_index = (current_location_index + 1) % location_count
next_location_name = location_list[next_location_index]
# 检查下一个库位是否被锁定
stmt = select(OperatePointLayer).where(
OperatePointLayer.layer_name == next_location_name,
OperatePointLayer.is_deleted == False
).limit(1)
result = await session.execute(stmt)
next_location_obj = result.scalar_one_or_none()
if next_location_obj:
if not next_location_obj.is_locked:
# 前方库位没有被锁定,说明这个小车可以移动
message = f'小车 {vehicle_name} 可以从 {current_location} 移动到 {next_location_name}'
logger.info(message)
return {
'movable_vehicle': vehicle_name,
'target_location': next_location_name,
'current_location': current_location,
'message': message
}
else:
logger.info(f'小车 {vehicle_name} 前方库位 {next_location_name} 被锁定,锁定者: {next_location_obj.locked_by}')
else:
logger.warning(f'未找到库位 {next_location_name}')
return {
'movable_vehicle': None,
'target_location': None,
'current_location': None,
'message': '环线中所有小车前方库位都被锁定,暂时无法移动'
}
except Exception as e:
error_msg = f'查找可移动小车时发生错误: {str(e)}'
logger.error(error_msg)
return {
'movable_vehicle': None,
'target_location': None,
'current_location': None,
'message': error_msg
}
async def get_all_movable_vehicles_in_loop(vehicle_list: list, location_list: list) -> dict:
"""
获取环线工区中所有可以移动的小车列表用于一轮调度3次的场景
Args:
vehicle_list: 小车名称列表 ['amd1', 'amd2', 'amd3']
location_list: 库位名称列表按环线顺序 ['1-1', '1-2', '1-3', '1-4']
Returns:
dict: {
'movable_vehicles': list, # [{'vehicle': str, 'target_location': str, 'current_location': str}, ...]
'total_count': int, # 可移动小车总数
'message': str # 状态描述
}
Example:
result = await get_all_movable_vehicles_in_loop(['amd1', 'amd2', 'amd3'], ['1-1', '1-2', '1-3', '1-4'])
# 返回: {
# 'movable_vehicles': [
# {'vehicle': 'amd3', 'target_location': '1-4', 'current_location': '1-3'},
# {'vehicle': 'amd1', 'target_location': '1-2', 'current_location': '1-1'}
# ],
# 'total_count': 2,
# 'message': '找到2个可移动的小车'
# }
"""
from data.session import get_async_session
from data.models.operate_point_layer import OperatePointLayer
from sqlalchemy import select
from utils.logger import get_logger
logger = get_logger("scripts.user_save.test1")
try:
movable_vehicles = []
if not vehicle_list or not location_list:
return {
'movable_vehicles': [],
'total_count': 0,
'message': '参数为空,无法获取可移动小车'
}
async with get_async_session() as session:
# 1. 找出所有被指定小车锁定的库位,记录每个小车的当前位置
vehicle_positions = {} # {vehicle_name: {'location': str, 'location_index': int, 'location_obj': obj}}
print("location_list::", location_list)
print("vehicle_list::", vehicle_list)
# 查询所有库位的锁定情况
stmt = select(OperatePointLayer).where(
OperatePointLayer.layer_name.in_(location_list),
OperatePointLayer.is_deleted == False,
OperatePointLayer.is_locked == True,
OperatePointLayer.locked_by.in_(vehicle_list)
)
result = await session.execute(stmt)
locked_locations = result.scalars().all()
print(locked_locations, "============")
# 建立小车位置映射
for location in locked_locations:
vehicle_name = location.locked_by
print(vehicle_name)
if location.layer_name in location_list:
location_index = location_list.index(location.layer_name)
vehicle_positions[vehicle_name] = {
'location': location.layer_name,
'location_index': location_index,
'location_obj': location
}
if not vehicle_positions:
return {
'movable_vehicles': [],
'total_count': 0,
'message': '环线中没有被指定小车锁定的库位'
}
# 2. 检查每个小车前方的库位是否可用
location_count = len(location_list)
for vehicle_name, position_info in vehicle_positions.items():
current_location_index = position_info['location_index']
current_location = position_info['location']
# 计算下一个库位位置(环线循环)
next_location_index = (current_location_index + 1) % location_count
next_location_name = location_list[next_location_index]
# 检查下一个库位是否被锁定
stmt = select(OperatePointLayer).where(
OperatePointLayer.layer_name == next_location_name,
OperatePointLayer.is_deleted == False
).limit(1)
result = await session.execute(stmt)
next_location_obj = result.scalar_one_or_none()
if next_location_obj and not next_location_obj.is_locked:
movable_vehicles.append({
'vehicle': vehicle_name,
'target_location': next_location_name,
'current_location': current_location
})
total_count = len(movable_vehicles)
if total_count > 0:
vehicle_names = [v['vehicle'] for v in movable_vehicles]
message = f'找到{total_count}个可移动的小车: {", ".join(vehicle_names)}'
else:
message = '环线中所有小车前方库位都被锁定,暂时无法移动'
logger.info(message)
return {
'movable_vehicles': movable_vehicles[0],
# 'total_count': total_count,
# 'message': message
}
except Exception as e:
error_msg = f'获取可移动小车列表时发生错误: {str(e)}'
logger.error(error_msg)
return {
'movable_vehicles': [],
'total_count': 0,
'message': error_msg
}
async def judgment_condition(location: str, batteryLevel: float, threshold: float, back_task_id: str) -> dict:
if location.find("CP") != -1 and batteryLevel >= threshold:
return {"bool": True}
else:
return {"bool": False}
# pass
# 测试示例(注释掉的测试代码)
# async def test_movable_functions():
# """测试可移动小车功能的示例代码"""
# vehicle_list = ['amd1', 'amd2', 'amd3']
# action_point_list = ['1-1', '1-2', '1-3', '1-4']
#
# # 测试找到一个可移动的小车
# movable = await find_movable_vehicle_in_loop(vehicle_list, action_point_list)
# print("可移动小车:", movable)
#
# # 测试获取所有可移动的小车
# # all_movable = await get_all_movable_vehicles_in_loop(vehicle_list, action_point_list)
# # print("所有可移动小车:", all_movable)
#
# print(asyncio.run(test_movable_functions()))