""" 机构网点CRUD操作 """ from typing import List, Optional, Tuple from sqlalchemy import select, and_, or_, func from sqlalchemy.orm import Session from app.models.organization import Organization from app.schemas.organization import OrganizationCreate, OrganizationUpdate class OrganizationCRUD: """机构网点CRUD操作类""" def get(self, db: Session, id: int) -> Optional[Organization]: """ 根据ID获取机构 Args: db: 数据库会话 id: 机构ID Returns: Organization对象或None """ return db.query(Organization).filter( and_( Organization.id == id, Organization.deleted_at.is_(None) ) ).first() def get_by_code(self, db: Session, code: str) -> Optional[Organization]: """ 根据代码获取机构 Args: db: 数据库会话 code: 机构代码 Returns: Organization对象或None """ return db.query(Organization).filter( and_( Organization.org_code == code, Organization.deleted_at.is_(None) ) ).first() def get_multi( self, db: Session, skip: int = 0, limit: int = 20, org_type: Optional[str] = None, status: Optional[str] = None, keyword: Optional[str] = None ) -> Tuple[List[Organization], int]: """ 获取机构列表 Args: db: 数据库会话 skip: 跳过条数 limit: 返回条数 org_type: 机构类型筛选 status: 状态筛选 keyword: 搜索关键词 Returns: (机构列表, 总数) """ query = db.query(Organization).filter(Organization.deleted_at.is_(None)) # 筛选条件 if org_type: query = query.filter(Organization.org_type == org_type) if status: query = query.filter(Organization.status == status) if keyword: query = query.filter( or_( Organization.org_code.ilike(f"%{keyword}%"), Organization.org_name.ilike(f"%{keyword}%") ) ) # 排序 query = query.order_by(Organization.tree_level.asc(), Organization.sort_order.asc(), Organization.id.asc()) # 总数 total = query.count() # 分页 items = query.offset(skip).limit(limit).all() return items, total def get_tree(self, db: Session, status: Optional[str] = None) -> List[Organization]: """ 获取机构树 Args: db: 数据库会话 status: 状态筛选 Returns: 机构树列表 """ query = db.query(Organization).filter(Organization.deleted_at.is_(None)) if status: query = query.filter(Organization.status == status) # 获取所有机构 all_orgs = query.order_by(Organization.tree_level.asc(), Organization.sort_order.asc()).all() # 构建树形结构 org_map = {org.id: org for org in all_orgs} tree = [] for org in all_orgs: # 清空children列表 org.children = [] if org.parent_id is None: # 根节点 tree.append(org) else: # 添加到父节点的children parent = org_map.get(org.parent_id) if parent: if not hasattr(parent, 'children'): parent.children = [] parent.children.append(org) return tree def get_children(self, db: Session, parent_id: int) -> List[Organization]: """ 获取子机构列表(直接子节点) Args: db: 数据库会话 parent_id: 父机构ID Returns: 子机构列表 """ return db.query(Organization).filter( and_( Organization.parent_id == parent_id, Organization.deleted_at.is_(None) ) ).order_by(Organization.sort_order.asc(), Organization.id.asc()).all() def get_all_children(self, db: Session, parent_id: int) -> List[Organization]: """ 递归获取所有子机构(包括子节点的子节点) Args: db: 数据库会话 parent_id: 父机构ID Returns: 所有子机构列表 """ # 获取父节点的tree_path parent = self.get(db, parent_id) if not parent: return [] # 构建查询路径 if parent.tree_path: search_path = f"{parent.tree_path}{parent.id}/" else: search_path = f"/{parent.id}/" # 查询所有以该路径开头的机构 return db.query(Organization).filter( and_( Organization.tree_path.like(f"{search_path}%"), Organization.deleted_at.is_(None) ) ).order_by(Organization.tree_level.asc(), Organization.sort_order.asc()).all() def get_parents(self, db: Session, child_id: int) -> List[Organization]: """ 递归获取所有父机构(从根到直接父节点) Args: db: 数据库会话 child_id: 子机构ID Returns: 所有父机构列表(从根到父) """ child = self.get(db, child_id) if not child or not child.tree_path: return [] # 解析tree_path,提取所有ID path_ids = [int(id) for id in child.tree_path.split("/") if id] if not path_ids: return [] # 查询所有父机构 return db.query(Organization).filter( and_( Organization.id.in_(path_ids), Organization.deleted_at.is_(None) ) ).order_by(Organization.tree_level.asc()).all() def create( self, db: Session, obj_in: OrganizationCreate, creator_id: Optional[int] = None ) -> Organization: """ 创建机构 Args: db: 数据库会话 obj_in: 创建数据 creator_id: 创建人ID Returns: 创建的Organization对象 """ # 检查代码是否已存在 if self.get_by_code(db, obj_in.org_code): raise ValueError(f"机构代码 '{obj_in.org_code}' 已存在") # 计算tree_path和tree_level tree_path = None tree_level = 0 if obj_in.parent_id: parent = self.get(db, obj_in.parent_id) if not parent: raise ValueError(f"父机构ID {obj_in.parent_id} 不存在") # 构建tree_path if parent.tree_path: tree_path = f"{parent.tree_path}{parent.id}/" else: tree_path = f"/{parent.id}/" tree_level = parent.tree_level + 1 db_obj = Organization( **obj_in.model_dump(), tree_path=tree_path, tree_level=tree_level, created_by=creator_id ) db.add(db_obj) db.commit() db.refresh(db_obj) return db_obj def update( self, db: Session, db_obj: Organization, obj_in: OrganizationUpdate, updater_id: Optional[int] = None ) -> Organization: """ 更新机构 Args: db: 数据库会话 db_obj: 数据库对象 obj_in: 更新数据 updater_id: 更新人ID Returns: 更新后的Organization对象 """ obj_data = obj_in.model_dump(exclude_unset=True) # 如果更新了parent_id,需要重新计算tree_path和tree_level if "parent_id" in obj_data: new_parent_id = obj_data["parent_id"] old_parent_id = db_obj.parent_id if new_parent_id != old_parent_id: # 重新计算当前节点的路径 if new_parent_id: new_parent = self.get(db, new_parent_id) if not new_parent: raise ValueError(f"父机构ID {new_parent_id} 不存在") if new_parent.tree_path: db_obj.tree_path = f"{new_parent.tree_path}{new_parent.id}/" else: db_obj.tree_path = f"/{new_parent.id}/" db_obj.tree_level = new_parent.tree_level + 1 else: # 变为根节点 db_obj.tree_path = None db_obj.tree_level = 0 # TODO: 需要递归更新所有子节点的tree_path和tree_level # 这里需要批量更新,暂时跳过 for field, value in obj_data.items(): if field != "parent_id": # parent_id已经处理 setattr(db_obj, field, value) db_obj.updated_by = updater_id db.add(db_obj) db.commit() db.refresh(db_obj) return db_obj def delete(self, db: Session, id: int, deleter_id: Optional[int] = None) -> bool: """ 删除机构(软删除) Args: db: 数据库会话 id: 机构ID deleter_id: 删除人ID Returns: 是否删除成功 """ obj = self.get(db, id) if not obj: return False # 检查是否有子机构 children = self.get_children(db, id) if children: raise ValueError("该机构下存在子机构,无法删除") obj.deleted_at = func.now() obj.deleted_by = deleter_id db.add(obj) db.commit() return True # 创建全局实例 organization = OrganizationCRUD()