from datetime import datetime from app import db class Version(db.Model): """版本模型""" __tablename__ = 'version' version_id = db.Column(db.Integer, primary_key=True) product_id = db.Column(db.String(32), db.ForeignKey('product.product_id'), nullable=False) version_num = db.Column(db.String(16), nullable=False) # 添加新字段 platform = db.Column(db.String(32), nullable=True) # 平台信息 description = db.Column(db.Text, nullable=True) # 版本描述 update_log = db.Column(db.Text, nullable=True) download_url = db.Column(db.String(255), nullable=True) min_license_version = db.Column(db.String(16), nullable=True) # 兼容最低卡密版本 force_update = db.Column(db.Integer, nullable=False, default=0) # 0=否, 1=是 download_status = db.Column(db.Integer, nullable=False, default=1) # 0=禁用, 1=启用 publish_status = db.Column(db.Integer, nullable=False, default=0) # 0=草稿, 1=已发布, 2=已回滚 file_hash = db.Column(db.String(64), nullable=True) # 文件SHA256哈希值 create_time = db.Column(db.DateTime, default=datetime.utcnow) update_time = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) # 关联关系 # devices 和 version 之间通过 software_version 字段关联,而不是直接的外键关系 # tickets 和 version 之间通过 software_version 字段关联,而不是直接的外键关系 # 复合唯一索引 __table_args__ = ( db.UniqueConstraint('product_id', 'version_num', name='uk_product_version'), ) def __init__(self, **kwargs): super(Version, self).__init__(**kwargs) def is_published(self): """版本是否已发布""" return self.publish_status == 1 def is_download_enabled(self): """下载是否启用""" return self.download_status == 1 def is_force_update(self): """是否强制更新""" return self.force_update == 1 def get_download_count(self): """获取下载次数""" # 如果已经有缓存的统计信息(来自批量查询),直接使用 if hasattr(self, '_cached_stats'): return self._cached_stats.get('download_count', 0) # 否则执行单个查询(用于单个版本详情等场景) from app.models.device import Device return Device.query.filter_by( product_id=self.product_id, software_version=self.version_num ).count() def get_active_device_count(self): """获取活跃设备数""" # 如果已经有缓存的统计信息(来自批量查询),直接使用 if hasattr(self, '_cached_stats'): return self._cached_stats.get('active_device_count', 0) # 否则执行单个查询(用于单个版本详情等场景) from app.models.device import Device return Device.query.filter_by( product_id=self.product_id, software_version=self.version_num, status=1 ).count() def check_compatibility(self, license_version): """检查版本兼容性""" if not self.min_license_version: return True # 未设置最低版本要求,全部兼容 # 简单的版本号比较,实际应用中可能需要更复杂的版本比较逻辑 try: license_parts = [int(x) for x in license_version.split('.')] min_parts = [int(x) for x in self.min_license_version.split('.')] # 补齐版本号长度 max_len = max(len(license_parts), len(min_parts)) license_parts.extend([0] * (max_len - len(license_parts))) min_parts.extend([0] * (max_len - len(min_parts))) return license_parts >= min_parts except (ValueError, AttributeError): return True # 版本号格式异常时默认兼容 def publish(self): """发布版本""" self.publish_status = 1 db.session.commit() def rollback(self): """回滚版本""" self.publish_status = 2 db.session.commit() def unpublish(self): """取消发布版本""" self.publish_status = 0 db.session.commit() def to_dict(self, include_stats=False): """转换为字典""" data = { 'version_id': self.version_id, 'product_id': self.product_id, 'product_name': self.product.product_name if self.product else None, 'version_num': self.version_num, 'platform': self.platform, # 添加新字段 'description': self.description, # 添加新字段 'update_log': self.update_log, 'download_url': self.download_url, 'file_hash': self.file_hash, 'min_license_version': self.min_license_version, 'force_update': self.force_update, 'force_update_name': '是' if self.force_update == 1 else '否', 'download_status': self.download_status, 'download_status_name': '启用' if self.download_status == 1 else '禁用', 'publish_status': self.publish_status, 'publish_status_name': { 0: '草稿', 1: '已发布', 2: '已回滚' }.get(self.publish_status, '未知'), 'create_time': self.create_time.strftime('%Y-%m-%d %H:%M:%S'), 'update_time': self.update_time.strftime('%Y-%m-%d %H:%M:%S') } if include_stats: data.update({ 'download_count': self.get_download_count(), 'active_device_count': self.get_active_device_count() }) return data def __repr__(self): return f''