import asyncio from typing import Dict, Any EXTERNAL_CALLBACK_URL = "http://roh.vwfawedl.mobi:9001/AGVService/ContainerSendBackRequest" # 生产线到毛坯库任务 async def test1(a: int, b: int) -> int: return {"name": a + b} def name1(*args, **kwargs): return {"test": "12333"} 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}") 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) task_detail = task_detail_result.get("data", {}) task_status = task_detail.get("status", "") if task_status == TaskStatus.CANCELED: return { "success": True, "message": f"任务被取消: TaskCode={task_code}, Status={task_status}" } 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}") return { "success": True, "message": f"任务验证通过,未找到对应库位,继续执行: {end_node}" } except Exception as e: logger.error(f"任务,检查end_node库位锁定状态时出现异常: {str(e)}, TaskCode={task_code}, end_node={end_node}") await asyncio.sleep(2) # 等待2秒后重试 except Exception as e: logger.error(f"任务状态验证异常: {str(e)}") return { "success": False, "message": f"任务状态验证异常: {str(e)}" } 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}") 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()))