352 lines
9.8 KiB
Python
352 lines
9.8 KiB
Python
"""
|
||
机构网点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()
|