from typing import Optional import enum from sqlalchemy import Column, Integer, String, DECIMAL, DateTime, Enum, ForeignKey from sqlalchemy.sql import func from pydantic import BaseModel, Field, model_validator from .database import Base from sqlalchemy.orm import relationship, backref from app.core.imageprocessor import process_image, ImageFormat from app.core import utils class CommunityStatus(str, enum.Enum): UNOPEN = "UNOPEN" # 未运营 OPENING = "OPENING" # 已运营 # 数据库模型 class CommunityDB(Base): __tablename__ = "communities" id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(100), nullable=False) address = Column(String(200), nullable=False) longitude = Column(DECIMAL(9,6), nullable=False) # 经度,精确到小数点后6位 latitude = Column(DECIMAL(9,6), nullable=False) # 纬度,精确到小数点后6位 status = Column(Enum(CommunityStatus), nullable=False, default=CommunityStatus.UNOPEN) qy_group_qrcode = Column(String(200), nullable=True) # 企业微信群二维码地址 webot_webhook = Column(String(200), nullable=True) # 企业微信机器人webhook # 小区定价 base_price = Column(DECIMAL(10,2), nullable=False, default=3.0) # 基础费用 extra_package_price = Column(DECIMAL(10,2), nullable=False, default=0.5) # 额外包裹费用 extra_package_threshold = Column(Integer, nullable=False, default=5) # 额外收费阈值 create_time = Column(DateTime(timezone=True), server_default=func.now()) update_time = Column(DateTime(timezone=True), onupdate=func.now()) admin_id = Column(Integer, ForeignKey("users.userid"), nullable=True) # 关联管理员 - 明确指定外键 admin = relationship("UserDB", foreign_keys=[admin_id], backref=backref("managed_communities", lazy="dynamic")) # 通过映射表关联的社区分润 community_profit_sharing = relationship("CommunityProfitSharing", backref="community", uselist=False) # 关联社区集合 community_set_mappings = relationship("CommunitySetMapping", backref="community") @property def optimized_qy_group_qrcode(self): if self.qy_group_qrcode: return process_image(self.qy_group_qrcode).thumbnail(800, 800).format(ImageFormat.WEBP).build() return None # Pydantic 模型 class CommunityCreate(BaseModel): name: str = Field(..., max_length=100) address: str = Field(..., max_length=200) longitude: float = Field(..., ge=-180, le=180) latitude: float = Field(..., ge=-90, le=90) status: CommunityStatus = Field(default=CommunityStatus.UNOPEN) qy_group_qrcode: Optional[str] = Field(None, max_length=200) webot_webhook: Optional[str] = Field(None, max_length=200) class CommunityUpdate(BaseModel): name: Optional[str] = Field(None, max_length=100) address: Optional[str] = Field(None, max_length=200) longitude: Optional[float] = Field(None, ge=-180, le=180) latitude: Optional[float] = Field(None, ge=-90, le=90) status: Optional[CommunityStatus] = None qy_group_qrcode: Optional[str] = Field(None, max_length=200) webot_webhook: Optional[str] = Field(None, max_length=200) base_price: Optional[float] = Field(None) extra_package_price: Optional[float] = Field(None) extra_package_threshold: Optional[int] = Field(None) admin_id: Optional[int] = Field(None) class CommunityInfo(BaseModel): id: int name: str address: str latitude: float longitude: float admin_id: Optional[int] = None status: CommunityStatus qy_group_qrcode: Optional[str] = None webot_webhook: Optional[str] = None base_price: Optional[float] = None extra_package_price: Optional[float] = None extra_package_threshold: Optional[int] = None optimized_qy_group_qrcode: Optional[str] = None distance: Optional[float] = None # 距离,单位:米 # 添加分润信息字段 profit_sharing: Optional[dict] = None # 添加管理员信息字段 admin: Optional[object] = None class Config: from_attributes = True @model_validator(mode='after') def set_admin(self): if hasattr(self, 'admin') and getattr(self, 'admin') is not None: admin = getattr(self, 'admin') # 检查admin是否已经是字典类型 if isinstance(admin, dict): return self # 处理UserDB对象 try: self.admin = { "id": admin.userid, "nickname": admin.nickname if hasattr(admin, 'nickname') else None, "phone": utils.CommonUtils.desensitize_phone(admin.phone) if hasattr(admin, 'phone') and admin.phone else None, "avatar": admin.avatar if hasattr(admin, 'avatar') else None } except Exception as e: # 如果处理失败,设置为None self.admin = None return self @model_validator(mode='after') def set_profit_sharing(self): # 从ORM对象中获取分润信息 if hasattr(self, 'community_profit_sharing') and getattr(self, 'community_profit_sharing') is not None: profit_sharing = getattr(self, 'community_profit_sharing') self.profit_sharing = { "id": profit_sharing.id, "platform_rate": profit_sharing.platform_rate, "partner_rate": profit_sharing.partner_rate, "admin_rate": profit_sharing.admin_rate, "delivery_rate": profit_sharing.delivery_rate } return self