质量管理: 由平铺记录改为任务制工作流(qc_task/qc_task_item/qc_defect三表) 设备巡检: 由点位+记录改为巡检模板制(eqp_checklist/item/record/detail四表) 前端: Quality.vue 支持任务列表+检验项详情+缺陷记录双Tab 前端: Inspection.vue 支持模板管理+项目维护+巡检记录+明细查看 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
135 lines
6.1 KiB
Python
135 lines
6.1 KiB
Python
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy import select, func, desc
|
|
from typing import Optional
|
|
from datetime import datetime
|
|
|
|
from app.database import get_db
|
|
from app.models.inspection import EqpChecklist, EqpChecklistItem, EqpInspectionRecord, EqpInspectionDetail
|
|
from app.schemas.inspection import (
|
|
EqpChecklistCreate, EqpChecklistUpdate, EqpChecklistOut,
|
|
EqpChecklistItemCreate, EqpChecklistItemOut,
|
|
EqpInspectionRecordCreate, EqpInspectionRecordOut,
|
|
EqpInspectionDetailOut,
|
|
)
|
|
from app.schemas.common import Response, PageResponse
|
|
from app.services.auth_service import get_current_user
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
# ─── 巡检模板 ────────────────────────────────────────────────────────────────
|
|
|
|
@router.get("/checklists", response_model=Response[list[EqpChecklistOut]])
|
|
async def list_checklists(
|
|
equipment_code: Optional[str] = None,
|
|
db: AsyncSession = Depends(get_db),
|
|
_=Depends(get_current_user),
|
|
):
|
|
query = select(EqpChecklist).order_by(EqpChecklist.id)
|
|
if equipment_code:
|
|
query = query.where(EqpChecklist.equipment_code == equipment_code)
|
|
r = await db.execute(query)
|
|
return Response.ok([EqpChecklistOut.model_validate(c) for c in r.scalars()])
|
|
|
|
|
|
@router.post("/checklists", response_model=Response[EqpChecklistOut])
|
|
async def create_checklist(body: EqpChecklistCreate, db: AsyncSession = Depends(get_db), _=Depends(get_current_user)):
|
|
items_data = body.items or []
|
|
data = body.model_dump(exclude={"items"})
|
|
checklist = EqpChecklist(**data)
|
|
db.add(checklist)
|
|
await db.flush()
|
|
for item in items_data:
|
|
ci = EqpChecklistItem(checklist_id=checklist.id, **item.model_dump())
|
|
db.add(ci)
|
|
await db.flush()
|
|
return Response.ok(EqpChecklistOut.model_validate(checklist))
|
|
|
|
|
|
@router.put("/checklists/{checklist_id}", response_model=Response[EqpChecklistOut])
|
|
async def update_checklist(checklist_id: int, body: EqpChecklistUpdate, db: AsyncSession = Depends(get_db), _=Depends(get_current_user)):
|
|
r = await db.execute(select(EqpChecklist).where(EqpChecklist.id == checklist_id))
|
|
checklist = r.scalar_one_or_none()
|
|
if not checklist:
|
|
raise HTTPException(status_code=404, detail="模板不存在")
|
|
for k, v in body.model_dump(exclude_none=True).items():
|
|
setattr(checklist, k, v)
|
|
await db.flush()
|
|
return Response.ok(EqpChecklistOut.model_validate(checklist))
|
|
|
|
|
|
@router.get("/checklists/{checklist_id}/items", response_model=Response[list[EqpChecklistItemOut]])
|
|
async def list_checklist_items(checklist_id: int, db: AsyncSession = Depends(get_db), _=Depends(get_current_user)):
|
|
r = await db.execute(
|
|
select(EqpChecklistItem).where(EqpChecklistItem.checklist_id == checklist_id)
|
|
.order_by(EqpChecklistItem.sort_order, EqpChecklistItem.id)
|
|
)
|
|
return Response.ok([EqpChecklistItemOut.model_validate(i) for i in r.scalars()])
|
|
|
|
|
|
@router.post("/checklist-items", response_model=Response[EqpChecklistItemOut])
|
|
async def create_checklist_item(
|
|
body: EqpChecklistItemCreate,
|
|
checklist_id: int,
|
|
db: AsyncSession = Depends(get_db),
|
|
_=Depends(get_current_user),
|
|
):
|
|
item = EqpChecklistItem(checklist_id=checklist_id, **body.model_dump())
|
|
db.add(item)
|
|
await db.flush()
|
|
return Response.ok(EqpChecklistItemOut.model_validate(item))
|
|
|
|
|
|
# ─── 巡检记录 ────────────────────────────────────────────────────────────────
|
|
|
|
@router.get("/records", response_model=Response[PageResponse[EqpInspectionRecordOut]])
|
|
async def list_records(
|
|
page: int = 1,
|
|
page_size: int = 20,
|
|
checklist_id: Optional[int] = None,
|
|
status: Optional[str] = None,
|
|
start_date: Optional[str] = None,
|
|
end_date: Optional[str] = None,
|
|
db: AsyncSession = Depends(get_db),
|
|
_=Depends(get_current_user),
|
|
):
|
|
query = select(EqpInspectionRecord).order_by(desc(EqpInspectionRecord.created_at))
|
|
if checklist_id:
|
|
query = query.where(EqpInspectionRecord.checklist_id == checklist_id)
|
|
if status:
|
|
query = query.where(EqpInspectionRecord.status == status)
|
|
if start_date:
|
|
query = query.where(EqpInspectionRecord.inspect_time >= datetime.fromisoformat(start_date))
|
|
if end_date:
|
|
query = query.where(EqpInspectionRecord.inspect_time <= datetime.fromisoformat(end_date + "T23:59:59"))
|
|
total = (await db.execute(select(func.count()).select_from(query.subquery()))).scalar()
|
|
rows = await db.execute(query.offset((page - 1) * page_size).limit(page_size))
|
|
items = [EqpInspectionRecordOut.model_validate(r) for r in rows.scalars()]
|
|
return Response.ok(PageResponse(total=total, page=page, page_size=page_size, items=items))
|
|
|
|
|
|
@router.post("/records", response_model=Response[EqpInspectionRecordOut])
|
|
async def create_record(body: EqpInspectionRecordCreate, db: AsyncSession = Depends(get_db), _=Depends(get_current_user)):
|
|
details_data = body.details or []
|
|
# get checklist name
|
|
cl_r = await db.execute(select(EqpChecklist).where(EqpChecklist.id == body.checklist_id))
|
|
cl = cl_r.scalar_one_or_none()
|
|
data = body.model_dump(exclude={"details"})
|
|
record = EqpInspectionRecord(**data, checklist_name=cl.name if cl else None)
|
|
db.add(record)
|
|
await db.flush()
|
|
for d in details_data:
|
|
detail = EqpInspectionDetail(record_id=record.id, **d.model_dump())
|
|
db.add(detail)
|
|
await db.flush()
|
|
return Response.ok(EqpInspectionRecordOut.model_validate(record))
|
|
|
|
|
|
@router.get("/records/{record_id}/details", response_model=Response[list[EqpInspectionDetailOut]])
|
|
async def get_record_details(record_id: int, db: AsyncSession = Depends(get_db), _=Depends(get_current_user)):
|
|
r = await db.execute(
|
|
select(EqpInspectionDetail).where(EqpInspectionDetail.record_id == record_id).order_by(EqpInspectionDetail.id)
|
|
)
|
|
return Response.ok([EqpInspectionDetailOut.model_validate(d) for d in r.scalars()])
|