Files
zcglxt/backend_new/app/services/maintenance_service.py

404 lines
13 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
维修管理业务服务层
"""
from typing import List, Optional, Dict, Any
from sqlalchemy.orm import Session, selectinload
from app.crud.maintenance import maintenance_record
from app.crud.asset import asset
from app.schemas.maintenance import (
MaintenanceRecordCreate,
MaintenanceRecordUpdate,
MaintenanceRecordStart,
MaintenanceRecordComplete
)
from app.core.exceptions import NotFoundException, BusinessException
class MaintenanceService:
"""维修管理服务类"""
async def get_record(
self,
db: Session,
record_id: int
) -> Dict[str, Any]:
"""获取维修记录详情"""
# 使用selectinload预加载关联数据避免N+1查询
from app.models.maintenance import MaintenanceRecord
from app.models.asset import Asset
from app.models.user import User
from app.models.brand_supplier import Supplier
obj = db.query(
MaintenanceRecord
).options(
selectinload(MaintenanceRecord.asset.of_type(Asset)),
selectinload(MaintenanceRecord.report_user.of_type(User)),
selectinload(MaintenanceRecord.maintenance_user.of_type(User)),
selectinload(MaintenanceRecord.vendor.of_type(Supplier))
).filter(
MaintenanceRecord.id == record_id
).first()
if not obj:
raise NotFoundException("维修记录")
return self._load_relations(db, obj)
def get_records(
self,
db: Session,
skip: int = 0,
limit: int = 20,
asset_id: Optional[int] = None,
status: Optional[str] = None,
fault_type: Optional[str] = None,
priority: Optional[str] = None,
maintenance_type: Optional[str] = None,
keyword: Optional[str] = None
) -> tuple:
"""获取维修记录列表"""
items, total = maintenance_record.get_multi(
db=db,
skip=skip,
limit=limit,
asset_id=asset_id,
status=status,
fault_type=fault_type,
priority=priority,
maintenance_type=maintenance_type,
keyword=keyword
)
# 加载关联信息
items_with_relations = [self._load_relations(db, item) for item in items]
return items_with_relations, total
async def create_record(
self,
db: Session,
obj_in: MaintenanceRecordCreate,
report_user_id: int,
creator_id: int
):
"""创建维修记录"""
# 验证资产存在
asset_obj = asset.get(db, obj_in.asset_id)
if not asset_obj:
raise NotFoundException("资产")
# 生成维修单号
record_code = await self._generate_record_code(db)
# 创建维修记录
db_obj = maintenance_record.create(
db=db,
obj_in=obj_in,
record_code=record_code,
asset_code=asset_obj.asset_code,
report_user_id=report_user_id,
creator_id=creator_id
)
# 如果资产状态不是维修中,则更新状态
if asset_obj.status != "maintenance":
from app.services.asset_service import asset_service
from app.schemas.asset import AssetStatusTransition
try:
await asset_service.change_asset_status(
db=db,
asset_id=asset_obj.id,
status_transition=AssetStatusTransition(
new_status="maintenance",
remark=f"报修: {record_code}"
),
operator_id=report_user_id
)
except Exception as e:
# 状态更新失败不影响维修记录创建
pass
return self._load_relations(db, db_obj)
def update_record(
self,
db: Session,
record_id: int,
obj_in: MaintenanceRecordUpdate,
updater_id: int
):
"""更新维修记录"""
db_obj = maintenance_record.get(db, record_id)
if not db_obj:
raise NotFoundException("维修记录")
# 已完成的维修记录不能更新
if db_obj.status == "completed":
raise BusinessException("已完成的维修记录不能更新")
return maintenance_record.update(db, db_obj, obj_in, updater_id)
async def start_maintenance(
self,
db: Session,
record_id: int,
start_in: MaintenanceRecordStart,
maintenance_user_id: int
):
"""开始维修"""
db_obj = maintenance_record.get(db, record_id)
if not db_obj:
raise NotFoundException("维修记录")
# 检查状态
if db_obj.status != "pending":
raise BusinessException("只有待处理状态的维修记录可以开始维修")
# 验证维修类型
if start_in.maintenance_type == "vendor_repair" and not start_in.vendor_id:
raise BusinessException("外部维修必须指定维修供应商")
# 开始维修
db_obj = maintenance_record.start_maintenance(
db=db,
db_obj=db_obj,
maintenance_type=start_in.maintenance_type,
maintenance_user_id=maintenance_user_id,
vendor_id=start_in.vendor_id
)
return self._load_relations(db, db_obj)
async def complete_maintenance(
self,
db: Session,
record_id: int,
complete_in: MaintenanceRecordComplete,
maintenance_user_id: int
):
"""完成维修"""
db_obj = maintenance_record.get(db, record_id)
if not db_obj:
raise NotFoundException("维修记录")
# 检查状态
if db_obj.status != "in_progress":
raise BusinessException("只有维修中的记录可以完成")
# 完成维修
db_obj = maintenance_record.complete_maintenance(
db=db,
db_obj=db_obj,
maintenance_result=complete_in.maintenance_result,
maintenance_cost=complete_in.maintenance_cost,
replaced_parts=complete_in.replaced_parts,
images=complete_in.images
)
# 恢复资产状态
from app.services.asset_service import asset_service
from app.schemas.asset import AssetStatusTransition
try:
await asset_service.change_asset_status(
db=db,
asset_id=db_obj.asset_id,
status_transition=AssetStatusTransition(
new_status=complete_in.asset_status,
remark=f"维修完成: {db_obj.record_code}"
),
operator_id=maintenance_user_id
)
except Exception as e:
# 状态更新失败不影响维修记录完成
pass
return self._load_relations(db, db_obj)
def cancel_maintenance(
self,
db: Session,
record_id: int
):
"""取消维修"""
db_obj = maintenance_record.get(db, record_id)
if not db_obj:
raise NotFoundException("维修记录")
# 检查状态
if db_obj.status == "completed":
raise BusinessException("已完成的维修记录不能取消")
# 取消维修
db_obj = maintenance_record.cancel_maintenance(db, db_obj)
# 恢复资产状态
asset_obj = asset.get(db, db_obj.asset_id)
if asset_obj and asset_obj.status == "maintenance":
from app.services.asset_service import asset_service
from app.schemas.asset import AssetStatusTransition
try:
# 根据维修前的状态恢复
target_status = "in_stock" # 默认恢复为库存中
asset_service.change_asset_status(
db=db,
asset_id=asset_obj.id,
status_transition=AssetStatusTransition(
new_status=target_status,
remark=f"取消维修: {db_obj.record_code}"
),
operator_id=db_obj.report_user_id or 0
)
except Exception as e:
# 状态更新失败不影响维修记录取消
pass
return self._load_relations(db, db_obj)
def delete_record(
self,
db: Session,
record_id: int
) -> bool:
"""删除维修记录"""
db_obj = maintenance_record.get(db, record_id)
if not db_obj:
raise NotFoundException("维修记录")
# 只能删除待处理或已取消的记录
if db_obj.status not in ["pending", "cancelled"]:
raise BusinessException("只能删除待处理或已取消的维修记录")
return maintenance_record.delete(db, record_id)
def get_asset_records(
self,
db: Session,
asset_id: int,
skip: int = 0,
limit: int = 50
) -> List:
"""获取资产的维修记录"""
# 验证资产存在
if not asset.get(db, asset_id):
raise NotFoundException("资产")
records = maintenance_record.get_by_asset(db, asset_id, skip, limit)
return [self._load_relations(db, record) for record in records]
def get_statistics(
self,
db: Session,
asset_id: Optional[int] = None
) -> Dict[str, Any]:
"""获取维修统计信息"""
return maintenance_record.get_statistics(db, asset_id)
def _load_relations(
self,
db: Session,
obj
) -> Dict[str, Any]:
"""加载维修记录关联信息"""
from app.models.asset import Asset
from app.models.user import User
from app.models.brand_supplier import Supplier
result = {
"id": obj.id,
"record_code": obj.record_code,
"asset_id": obj.asset_id,
"asset_code": obj.asset_code,
"fault_description": obj.fault_description,
"fault_type": obj.fault_type,
"report_user_id": obj.report_user_id,
"report_time": obj.report_time,
"priority": obj.priority,
"maintenance_type": obj.maintenance_type,
"vendor_id": obj.vendor_id,
"maintenance_cost": float(obj.maintenance_cost) if obj.maintenance_cost else None,
"start_time": obj.start_time,
"complete_time": obj.complete_time,
"maintenance_user_id": obj.maintenance_user_id,
"maintenance_result": obj.maintenance_result,
"replaced_parts": obj.replaced_parts,
"status": obj.status,
"images": obj.images,
"remark": obj.remark,
"created_at": obj.created_at,
"updated_at": obj.updated_at
}
# 加载资产信息
if obj.asset_id:
asset_obj = db.query(Asset).filter(Asset.id == obj.asset_id).first()
if asset_obj:
result["asset"] = {
"id": asset_obj.id,
"asset_code": asset_obj.asset_code,
"asset_name": asset_obj.asset_name,
"status": asset_obj.status
}
# 加载报修人信息
if obj.report_user_id:
report_user = db.query(User).filter(User.id == obj.report_user_id).first()
if report_user:
result["report_user"] = {
"id": report_user.id,
"real_name": report_user.real_name,
"username": report_user.username
}
# 加载维修人员信息
if obj.maintenance_user_id:
maintenance_user = db.query(User).filter(User.id == obj.maintenance_user_id).first()
if maintenance_user:
result["maintenance_user"] = {
"id": maintenance_user.id,
"real_name": maintenance_user.real_name,
"username": maintenance_user.username
}
# 加载供应商信息
if obj.vendor_id:
vendor = db.query(Supplier).filter(Supplier.id == obj.vendor_id).first()
if vendor:
result["vendor"] = {
"id": vendor.id,
"supplier_name": vendor.supplier_name,
"contact_person": vendor.contact_person,
"contact_phone": vendor.contact_phone
}
return result
async def _generate_record_code(self, db: Session) -> str:
"""生成维修单号"""
from datetime import datetime
import random
import string
# 日期部分
date_str = datetime.now().strftime("%Y%m%d")
# 序号部分4位随机数
sequence = "".join(random.choices(string.digits, k=4))
# 组合单号: MT202501240001
record_code = f"MT{date_str}{sequence}"
# 检查是否重复,如果重复则重新生成
while maintenance_record.get_by_code(db, record_code):
sequence = "".join(random.choices(string.digits, k=4))
record_code = f"MT{date_str}{sequence}"
return record_code
# 创建全局实例
maintenance_service = MaintenanceService()