#!/usr/bin/env python # -*- coding: utf-8 -*- """ 库区分层数据模型 管理每个动作点的分层信息和货物状态 """ from sqlalchemy import Column, String, Integer, Boolean, Text, DateTime, ForeignKey, UniqueConstraint from sqlalchemy.orm import relationship from sqlalchemy.dialects.mysql import CHAR from .base import BaseModel import datetime class OperatePointLayer(BaseModel): """ 库区分层数据模型 每个动作点可以有多个层,每层可以独立存放货物 """ __tablename__ = 'vwed_operate_point_layer' id = Column(CHAR(64), primary_key=True, comment='层ID') operate_point_id = Column(CHAR(64), ForeignKey('vwed_operate_point.id'), nullable=False, comment='动作点ID') station_name = Column(String(64), nullable=False, comment='动作点名称') storage_location_name = Column(String(64), nullable=False, comment='库位名称') area_name = Column(String(64), nullable=True, comment='库区名称') scene_id = Column(String(64), nullable=False, comment='场景ID(冗余字段)') layer_index = Column(Integer, nullable=False, comment='层索引(从1开始)') layer_name = Column(String(64), comment='层名称') # 货物状态 is_occupied = Column(Boolean, nullable=False, default=False, comment='是否占用') goods_content = Column(String(100), nullable=False, default='', comment='货物内容') goods_weight = Column(Integer, comment='货物重量(克)') goods_volume = Column(Integer, 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='是否空托盘') locked_by = Column(String(128), nullable=True, comment='锁定者') tags = Column(String(100), nullable=False, default='', comment='标签') # 层属性 max_weight = Column(Integer, comment='最大承重(克)') max_volume = Column(Integer, comment='最大体积(立方厘米)') layer_height = Column(Integer, comment='层高(毫米)') # 时间信息 goods_stored_at = Column(DateTime, comment='货物存放时间') goods_retrieved_at = Column(DateTime, comment='货物取出时间') last_access_at = Column(DateTime, comment='最后访问时间') # 扩展信息 tags = Column(String(255), comment='层标签', nullable=True) description = Column(Text, comment='层描述', nullable=True) config_json = Column(Text, comment='层配置JSON', nullable=True) # 关联关系 operate_point = relationship("OperatePoint", back_populates="layers") # 唯一约束:同一个动作点的层索引不能重复 __table_args__ = ( UniqueConstraint('operate_point_id', 'layer_index', name='uk_operate_point_layer'), ) def __repr__(self): return f"" def can_store_goods(self, weight=None, volume=None): """ 检查是否可以存放货物 Args: weight: 货物重量(克) volume: 货物体积(立方厘米) Returns: bool: 是否可以存放 """ if self.is_disabled or self.is_locked or self.is_occupied: return False # 检查重量限制 if weight is not None and self.max_weight is not None: if weight > self.max_weight: return False # 检查体积限制 if volume is not None and self.max_volume is not None: if volume > self.max_volume: return False return True def can_retrieve_goods(self): """检查是否可以取货""" return (not self.is_disabled and not self.is_locked and self.is_occupied) def store_goods(self, content, weight=None, volume=None): """ 存放货物 Args: content: 货物内容 weight: 货物重量(克) volume: 货物体积(立方厘米) Returns: bool: 是否成功 """ if not self.can_store_goods(weight, volume): return False self.is_occupied = True self.goods_content = content self.goods_weight = weight self.goods_volume = volume self.goods_stored_at = datetime.datetime.now() self.last_access_at = datetime.datetime.now() return True def retrieve_goods(self): """ 取出货物 Returns: dict: 货物信息 """ if not self.can_retrieve_goods(): return None goods_info = { 'content': self.goods_content, 'weight': self.goods_weight, 'volume': self.goods_volume, 'stored_at': self.goods_stored_at } # 清空货物信息 self.is_occupied = False self.goods_content = '' self.goods_weight = None self.goods_volume = None self.goods_retrieved_at = datetime.datetime.now() self.last_access_at = datetime.datetime.now() return goods_info def get_remaining_capacity(self): """获取剩余容量信息""" result = {} if self.max_weight is not None: used_weight = self.goods_weight if self.goods_weight is not None else 0 result['remaining_weight'] = self.max_weight - used_weight if self.max_volume is not None: used_volume = self.goods_volume if self.goods_volume is not None else 0 result['remaining_volume'] = self.max_volume - used_volume return result def is_overweight(self): """检查是否超重""" if self.max_weight is None or self.goods_weight is None: return False return self.goods_weight > self.max_weight def is_overflow(self): """检查是否超体积""" if self.max_volume is None or self.goods_volume is None: return False return self.goods_volume > self.max_volume