VWED_server/data/models/operate_point.py
2025-07-17 15:47:56 +08:00

127 lines
4.6 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
动作点数据模型
基于现有的vwed_operate_point表结构进行扩展
动作点和库位是同一个概念
"""
from sqlalchemy import Column, String, Integer, Boolean, Text, DateTime, ForeignKey, Enum
from sqlalchemy.orm import relationship
from sqlalchemy.dialects.mysql import CHAR
from .base import BaseModel
from .storage_area import StorageAreaType
class OperatePoint(BaseModel):
"""
动作点数据模型
继承现有的vwed_operate_point表结构并扩展
"""
__tablename__ = 'vwed_operate_point'
id = Column(CHAR(64), primary_key=True, comment='动作点ID')
station_name = Column(String(64), nullable=False, comment='动作站点名称')
# storage_location_name = Column(String(64), nullable=False, comment='库位名称')
scene_id = Column(String(64), nullable=False, comment='场景ID')
# 原有字段
# is_occupied = Column(Boolean, nullable=False, default=False, comment='是否占用')
# is_locked = Column(Boolean, nullable=False, default=False, comment='是否锁定')
is_disabled = Column(Boolean, nullable=False, default=False, comment='是否禁用')
# is_empty_tray = Column(Boolean, nullable=False, default=False, comment='是否空托盘')
content = Column(String(100), nullable=False, default='', comment='内容')
tags = Column(String(100), nullable=False, default='', comment='标签')
# 库区关联
storage_area_id = Column(CHAR(64), ForeignKey('vwed_storage_area.id'), nullable=True, comment='所属库区ID')
# 库区类型
storage_area_type = Column(Enum(StorageAreaType), nullable=True, comment='库区类型')
# 库区名称
area_name = Column(String(64), nullable=True, comment='库区名称')
# 动作点属性
max_layers = Column(Integer, nullable=False, default=1, comment='最大层数')
current_layers = Column(Integer, nullable=False, default=0, comment='当前使用层数')
# 动作点位置信息
position_x = Column(Integer, comment='X坐标', nullable=True)
position_y = Column(Integer, comment='Y坐标', nullable=True)
position_z = Column(Integer, comment='Z坐标', nullable=True)
# 动作点配置
description = Column(Text, comment='动作点描述')
# 关联关系
storage_area = relationship("StorageArea", back_populates="operate_points")
layers = relationship(
"OperatePointLayer",
back_populates="operate_point",
cascade="all, delete-orphan",
order_by="OperatePointLayer.layer_index"
)
def __repr__(self):
return f"<OperatePoint(id={self.id}, station_name={self.station_name}, storage_area_id={self.storage_area_id}, storage_area_type={self.storage_area_type}, area_name={self.area_name})>"
def get_available_layers(self):
"""获取可用层数"""
return self.max_layers - self.current_layers
def get_layer_usage_rate(self):
"""获取层使用率"""
if self.max_layers == 0:
return 0.0
return (self.current_layers / self.max_layers) * 100.0
def is_full(self):
"""是否已满"""
return self.current_layers >= self.max_layers
def is_empty(self):
"""是否为空"""
return self.current_layers == 0
def can_store_goods(self):
"""是否可以存放货物"""
return (not self.is_disabled and
not self.is_full() and
self.max_layers > 0)
def can_retrieve_goods(self):
"""是否可以取货"""
return (not self.is_disabled and
not self.is_empty())
def get_occupied_layers(self):
"""获取有货物的层列表"""
return [layer for layer in self.layers if layer.is_occupied]
def get_empty_layers(self):
"""获取空层列表"""
return [layer for layer in self.layers if not layer.is_occupied]
def has_storage_area(self):
"""是否属于某个库区"""
return self.storage_area_id is not None
def get_storage_area_info(self):
"""获取库区信息"""
if self.storage_area_id is None:
return None
return self.storage_area
def is_dense_storage(self):
"""是否为密集库区类型"""
return self.storage_area_type == StorageAreaType.DENSE
def is_general_storage(self):
"""是否为一般库区类型"""
return self.storage_area_type == StorageAreaType.GENERAL
def get_storage_area_display_name(self):
"""获取库区显示名称"""
return self.area_name or "未分配库区"