887 lines
36 KiB
Python
887 lines
36 KiB
Python
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, agv_id: str) -> dict:
|
||
"""
|
||
判断是否满足执行条件
|
||
|
||
Args:
|
||
location: 当前位置
|
||
batteryLevel: 电池电量
|
||
threshold: 电量阈值
|
||
back_task_id: 任务模板ID
|
||
agv_id: AGV设备ID
|
||
|
||
Returns:
|
||
dict: {"bool": True/False}
|
||
"""
|
||
from data.session import get_async_session
|
||
from data.models.taskrecord import VWEDTaskRecord
|
||
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")
|
||
|
||
try:
|
||
# 首先检查位置和电量条件
|
||
if location.find("CP") == -1 or batteryLevel < threshold:
|
||
return {"bool": False}
|
||
|
||
# 检查是否有相同任务模板的运行任务且AGV相同
|
||
async with get_async_session() as session:
|
||
stmt = select(VWEDTaskRecord).where(
|
||
VWEDTaskRecord.def_id == back_task_id,
|
||
VWEDTaskRecord.agv_id == agv_id,
|
||
VWEDTaskRecord.status == TaskStatus.RUNNING,
|
||
VWEDTaskRecord.is_deleted == False
|
||
)
|
||
result = await session.execute(stmt)
|
||
running_tasks = result.scalars().all()
|
||
|
||
if running_tasks:
|
||
logger.info(f"发现相同任务模板的运行任务,AGV: {agv_id}, 任务模板: {back_task_id}, 运行任务数量: {len(running_tasks)}")
|
||
return {"bool": False}
|
||
|
||
logger.info(f"条件检查通过,位置: {location}, 电量: {batteryLevel}, 阈值: {threshold}, AGV: {agv_id}")
|
||
return {"bool": True}
|
||
|
||
except Exception as e:
|
||
logger.error(f"判断条件时发生错误: {str(e)}")
|
||
return {"bool": False}
|
||
|
||
|
||
async def check_location_lock_status(location_id: str) -> dict:
|
||
"""
|
||
查询库位是否被锁定
|
||
|
||
Args:
|
||
location_id: 库位ID(layer_name字段的值)
|
||
|
||
Returns:
|
||
dict: {
|
||
"is_locked": bool, # 是否被锁定
|
||
"locked_by": str or None, # 锁定者,如果未锁定则为None
|
||
"location_exists": bool, # 库位是否存在
|
||
"message": str # 状态描述
|
||
}
|
||
"""
|
||
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 location_id:
|
||
return {
|
||
"is_locked": False,
|
||
"locked_by": None,
|
||
"location_exists": False,
|
||
"message": "库位ID参数为空"
|
||
}
|
||
|
||
async with get_async_session() as session:
|
||
# 查询指定库位的锁定状态
|
||
stmt = select(OperatePointLayer).where(
|
||
OperatePointLayer.layer_name == location_id,
|
||
OperatePointLayer.is_deleted == False
|
||
).limit(1)
|
||
|
||
result = await session.execute(stmt)
|
||
location = result.scalar_one_or_none()
|
||
|
||
if not location:
|
||
logger.warning(f"未找到库位: {location_id}")
|
||
return {
|
||
"is_locked": False,
|
||
"locked_by": None,
|
||
"location_exists": False,
|
||
"message": f"库位 {location_id} 不存在"
|
||
}
|
||
|
||
is_locked = bool(location.is_locked)
|
||
locked_by = location.locked_by if is_locked else None
|
||
|
||
if is_locked:
|
||
message = f"库位 {location_id} 已被锁定,锁定者: {locked_by}"
|
||
logger.info(message)
|
||
else:
|
||
message = f"库位 {location_id} 未被锁定"
|
||
logger.info(message)
|
||
|
||
return {
|
||
"is_locked": is_locked,
|
||
"locked_by": locked_by,
|
||
"location_exists": True,
|
||
"message": message
|
||
}
|
||
|
||
except Exception as e:
|
||
error_msg = f"查询库位锁定状态时发生错误: {str(e)}"
|
||
logger.error(error_msg)
|
||
return {
|
||
"is_locked": False,
|
||
"locked_by": None,
|
||
"location_exists": False,
|
||
"message": error_msg
|
||
}
|
||
|
||
|
||
async def unlock_locations_when_last(current_location: str, location_list: list) -> dict:
|
||
"""
|
||
检查当前库位是否为库位集合的最后一个,如果是则解锁所有库位
|
||
|
||
Args:
|
||
current_location: 当前库位名称
|
||
location_list: 按照获取顺序的库位集合列表
|
||
|
||
Returns:
|
||
dict: {
|
||
"is_last": bool, # 是否为最后一个库位
|
||
"unlocked": bool, # 是否执行了解锁操作
|
||
"unlocked_count": int, # 解锁的库位数量
|
||
"message": str # 状态描述
|
||
}
|
||
"""
|
||
from data.session import get_db
|
||
from services.operate_point_service import OperatePointService
|
||
from routes.model.operate_point_model import BatchStorageLocationStatusUpdateRequest, StorageLocationActionEnum
|
||
from utils.logger import get_logger
|
||
|
||
logger = get_logger("scripts.user_save.test1")
|
||
|
||
try:
|
||
if not current_location:
|
||
return {
|
||
"is_last": False,
|
||
"unlocked": False,
|
||
"unlocked_count": 0,
|
||
"message": "当前库位参数为空"
|
||
}
|
||
|
||
if not location_list:
|
||
return {
|
||
"is_last": False,
|
||
"unlocked": False,
|
||
"unlocked_count": 0,
|
||
"message": "库位集合列表为空"
|
||
}
|
||
|
||
# 检查当前库位是否在列表中
|
||
if current_location not in location_list:
|
||
return {
|
||
"is_last": False,
|
||
"unlocked": False,
|
||
"unlocked_count": 0,
|
||
"message": f"当前库位 {current_location} 不在库位集合中"
|
||
}
|
||
|
||
# 检查是否为最后一个库位
|
||
is_last = current_location == location_list[-1]
|
||
|
||
if not is_last:
|
||
return {
|
||
"is_last": False,
|
||
"unlocked": False,
|
||
"unlocked_count": 0,
|
||
"message": f"当前库位 {current_location} 不是最后一个库位(最后一个为:{location_list[-1]})"
|
||
}
|
||
|
||
# 当前库位是最后一个,执行批量解锁操作
|
||
logger.info(f"当前库位 {current_location} 是最后一个库位,开始解锁所有库位")
|
||
|
||
try:
|
||
# 创建批量解锁请求对象
|
||
batch_request = BatchStorageLocationStatusUpdateRequest(
|
||
layer_names=location_list,
|
||
action=StorageLocationActionEnum.UNLOCK,
|
||
reason="任务完成,自动解锁所有库位"
|
||
)
|
||
|
||
# 使用数据库会话调用服务方法
|
||
db = next(get_db())
|
||
try:
|
||
# 调用批量更新库位状态服务
|
||
result = OperatePointService.batch_update_storage_location_status(db, batch_request)
|
||
|
||
logger.info(f"批量解锁完成:成功 {result.success_count} 个,失败 {result.failed_count} 个")
|
||
|
||
return {
|
||
"is_last": True,
|
||
"unlocked": True,
|
||
"unlocked_count": result.success_count,
|
||
"message": f"当前库位是最后一个,已执行批量解锁:成功 {result.success_count} 个库位,失败 {result.failed_count} 个库位"
|
||
}
|
||
|
||
finally:
|
||
db.close()
|
||
|
||
except Exception as e:
|
||
logger.error(f"执行批量解锁时发生异常: {str(e)}")
|
||
return {
|
||
"is_last": True,
|
||
"unlocked": False,
|
||
"unlocked_count": 0,
|
||
"message": f"当前库位是最后一个,但解锁操作失败:{str(e)}"
|
||
}
|
||
|
||
except Exception as e:
|
||
error_msg = f"检查库位和执行解锁时发生错误: {str(e)}"
|
||
logger.error(error_msg)
|
||
return {
|
||
"is_last": False,
|
||
"unlocked": False,
|
||
"unlocked_count": 0,
|
||
"message": error_msg
|
||
}
|
||
|
||
|
||
async def check_vehicle_at_location(vehicle_name: str, location_list: list, vehicle_current_position: str) -> dict:
|
||
"""
|
||
检查小车是否在被其锁定的库位对应的站点位置
|
||
|
||
Args:
|
||
vehicle_name: 小车名称
|
||
location_list: 库位列表
|
||
vehicle_current_position: 小车当前所在的位置/站点
|
||
|
||
Returns:
|
||
dict: {
|
||
"at_locked_location": bool, # 是否在被锁定的库位对应站点
|
||
"locked_location": str or None, # 被锁定的库位名称
|
||
"location_station": str or None,# 库位对应的站点名称
|
||
"vehicle_position": str, # 小车当前位置
|
||
"message": str # 状态描述
|
||
}
|
||
"""
|
||
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_name:
|
||
return {
|
||
"at_locked_location": False,
|
||
"locked_location": None,
|
||
"location_station": None,
|
||
"vehicle_position": vehicle_current_position,
|
||
"message": "小车名称参数为空"
|
||
}
|
||
|
||
if not location_list:
|
||
return {
|
||
"at_locked_location": False,
|
||
"locked_location": None,
|
||
"location_station": None,
|
||
"vehicle_position": vehicle_current_position,
|
||
"message": "库位列表为空"
|
||
}
|
||
|
||
if not vehicle_current_position:
|
||
return {
|
||
"at_locked_location": False,
|
||
"locked_location": None,
|
||
"location_station": None,
|
||
"vehicle_position": vehicle_current_position,
|
||
"message": "小车当前位置参数为空"
|
||
}
|
||
|
||
async with get_async_session() as session:
|
||
# 查询库位列表中被当前小车锁定的库位
|
||
stmt = select(OperatePointLayer).where(
|
||
OperatePointLayer.layer_name.in_(location_list),
|
||
OperatePointLayer.is_deleted == False,
|
||
OperatePointLayer.is_locked == True,
|
||
OperatePointLayer.locked_by == vehicle_name
|
||
)
|
||
|
||
result = await session.execute(stmt)
|
||
locked_locations = result.scalars().all()
|
||
|
||
if not locked_locations:
|
||
logger.info(f"小车 {vehicle_name} 未锁定库位列表中的任何库位")
|
||
return {
|
||
"at_locked_location": False,
|
||
"locked_location": None,
|
||
"location_station": None,
|
||
"vehicle_position": vehicle_current_position,
|
||
"message": f"小车 {vehicle_name} 未锁定库位列表中的任何库位"
|
||
}
|
||
|
||
# 检查每个被锁定的库位
|
||
for locked_location in locked_locations:
|
||
location_station = locked_location.station_name
|
||
location_layer_name = locked_location.layer_name
|
||
|
||
logger.info(f"检查小车 {vehicle_name} 锁定的库位 {location_layer_name},对应站点: {location_station},小车当前位置: {vehicle_current_position}")
|
||
|
||
# 检查小车当前位置是否与库位对应的站点匹配
|
||
if vehicle_current_position == location_station:
|
||
logger.info(f"小车 {vehicle_name} 在被锁定的库位 {location_layer_name} 对应的站点 {location_station}")
|
||
return {
|
||
"at_locked_location": False,
|
||
"locked_location": location_layer_name,
|
||
"location_station": location_station,
|
||
"vehicle_position": vehicle_current_position,
|
||
"message": f"小车 {vehicle_name} 在被锁定的库位 {location_layer_name} 对应的站点 {location_station}"
|
||
}
|
||
|
||
# 如果有锁定库位但位置不匹配
|
||
locked_location_info = []
|
||
for locked_location in locked_locations:
|
||
locked_location_info.append(f"{locked_location.layer_name}(站点:{locked_location.station_name})")
|
||
|
||
message = f"小车 {vehicle_name} 不在被锁定库位的站点,当前位置: {vehicle_current_position},已锁定库位: {', '.join(locked_location_info)}"
|
||
logger.info(message)
|
||
|
||
return {
|
||
"at_locked_location": True,
|
||
"locked_location": locked_locations[0].layer_name if locked_locations else None,
|
||
"location_station": locked_locations[0].station_name if locked_locations else None,
|
||
"vehicle_position": vehicle_current_position,
|
||
"message": message
|
||
}
|
||
|
||
except Exception as e:
|
||
error_msg = f"检查小车位置时发生错误: {str(e)}"
|
||
logger.error(error_msg)
|
||
return {
|
||
"at_locked_location": False,
|
||
"locked_location": None,
|
||
"location_station": None,
|
||
"vehicle_position": vehicle_current_position,
|
||
"message": error_msg
|
||
}
|
||
|
||
|
||
# 测试示例(注释掉的测试代码)
|
||
# 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())) |