from app.extensions import db from app.models.material import MaterialBase from app.models.stock import StockBuy # 需要引入库存表做删除时的依赖检查 from sqlalchemy import or_ import traceback class MaterialBaseService: @staticmethod def get_list(page, limit, filters=None): """ 获取基础信息列表 :param page: 页码 :param limit: 每页条数 :param filters: 筛选条件字典 {keyword, category, type, isEnabled} """ try: query = MaterialBase.query if filters: # 1. 关键词模糊搜索 (名称 或 规格型号) if filters.get('keyword'): kw = f"%{filters['keyword']}%" query = query.filter(or_( MaterialBase.name.like(kw), MaterialBase.spec_model.like(kw) )) # 2. 精确筛选 if filters.get('category'): query = query.filter_by(category=filters['category']) if filters.get('type'): query = query.filter_by(material_type=filters['type']) if filters.get('isEnabled') is not None: # 前端传 1/0,转为 Boolean is_active = bool(int(filters['isEnabled'])) query = query.filter_by(is_enabled=is_active) # 按 ID 倒序排列 pagination = query.order_by(MaterialBase.id.desc()).paginate(page=page, per_page=limit, error_out=False) items = [item.to_dict() for item in pagination.items] return {"total": pagination.total, "items": items} except Exception as e: print(f"查询基础信息列表失败: {e}") # 生产环境建议记录日志 return {"total": 0, "items": []} @staticmethod def create_material(data): """新增基础信息""" try: # 0. 基础校验 if not data.get('name') or not data.get('spec'): raise ValueError("名称和规格型号不能为空") # 1. 查重 (名称+规格型号 唯一) exist = MaterialBase.query.filter_by( name=data['name'], spec_model=data['spec'] ).first() if exist: raise ValueError(f"已存在相同名称和规格的数据 (ID: {exist.id})") # 2. 创建对象 (注意前端驼峰 -> 后端下划线映射) new_material = MaterialBase( name=data['name'], spec_model=data['spec'], # 映射 category=data.get('category'), material_type=data.get('type'), # 映射 unit=data.get('unit'), visibility_level=data.get('visibilityLevel'), # 映射 manual_link=data.get('generalManual'), # 映射 product_image=data.get('generalImage'), # 映射 is_enabled=True if data.get('isEnabled', 1) == 1 else False ) db.session.add(new_material) db.session.commit() return new_material except Exception as e: db.session.rollback() raise e @staticmethod def update_material(m_id, data): """修改基础信息""" try: material = MaterialBase.query.get(m_id) if not material: raise ValueError("数据不存在") # 更新字段 (仅更新传入的字段) if 'name' in data: material.name = data['name'] if 'spec' in data: material.spec_model = data['spec'] if 'category' in data: material.category = data['category'] if 'type' in data: material.material_type = data['type'] if 'unit' in data: material.unit = data['unit'] if 'visibilityLevel' in data: material.visibility_level = data['visibilityLevel'] if 'generalManual' in data: material.manual_link = data['generalManual'] if 'generalImage' in data: material.product_image = data['generalImage'] if 'isEnabled' in data: material.is_enabled = bool(int(data['isEnabled'])) db.session.commit() return material except Exception as e: db.session.rollback() raise e @staticmethod def delete_material(m_id): """删除基础信息 (带依赖检查)""" try: material = MaterialBase.query.get(m_id) if not material: raise ValueError("数据不存在") # 1. 依赖检查:如果该基础信息已经在库存表(StockBuy)中使用,禁止物理删除 # 这里假设 StockBuy 表有一个外键或字段指向 MaterialBase (e.g., base_id) usage_count = StockBuy.query.filter_by(base_id=m_id).count() if usage_count > 0: raise ValueError(f"无法删除:该基础信息已被 {usage_count} 条库存记录引用,请先清理库存或仅禁用此条目。") # 2. 执行删除 db.session.delete(material) db.session.commit() return True except Exception as e: db.session.rollback() print(f"删除基础信息失败: {e}") raise e