feat: 重构质量管理和设备巡检模块
质量管理: 由平铺记录改为任务制工作流(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>
This commit is contained in:
@@ -1,13 +1,16 @@
|
||||
from fastapi import APIRouter, Depends
|
||||
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 InspectionLocation, InspectionRecord
|
||||
from app.models.inspection import EqpChecklist, EqpChecklistItem, EqpInspectionRecord, EqpInspectionDetail
|
||||
from app.schemas.inspection import (
|
||||
InspectionLocationCreate, InspectionLocationOut,
|
||||
InspectionRecordCreate, InspectionRecordOut,
|
||||
EqpChecklistCreate, EqpChecklistUpdate, EqpChecklistOut,
|
||||
EqpChecklistItemCreate, EqpChecklistItemOut,
|
||||
EqpInspectionRecordCreate, EqpInspectionRecordOut,
|
||||
EqpInspectionDetailOut,
|
||||
)
|
||||
from app.schemas.common import Response, PageResponse
|
||||
from app.services.auth_service import get_current_user
|
||||
@@ -15,61 +18,117 @@ from app.services.auth_service import get_current_user
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/locations", response_model=Response[list[InspectionLocationOut]])
|
||||
async def list_locations(
|
||||
# ─── 巡检模板 ────────────────────────────────────────────────────────────────
|
||||
|
||||
@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),
|
||||
_=Depends(get_current_user),
|
||||
):
|
||||
result = await db.execute(
|
||||
select(InspectionLocation).order_by(InspectionLocation.sort_order, InspectionLocation.id)
|
||||
)
|
||||
items = [InspectionLocationOut.model_validate(r) for r in result.scalars()]
|
||||
return Response.ok(items)
|
||||
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("/locations", response_model=Response[InspectionLocationOut])
|
||||
async def create_location(
|
||||
body: InspectionLocationCreate,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
_ = Depends(get_current_user),
|
||||
):
|
||||
loc = InspectionLocation(**body.model_dump())
|
||||
db.add(loc)
|
||||
@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()
|
||||
return Response.ok(InspectionLocationOut.model_validate(loc))
|
||||
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.get("/records", response_model=Response[PageResponse[InspectionRecordOut]])
|
||||
@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 = 30,
|
||||
location_id: Optional[int] = None,
|
||||
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),
|
||||
_=Depends(get_current_user),
|
||||
):
|
||||
query = select(InspectionRecord).order_by(desc(InspectionRecord.created_at))
|
||||
if location_id:
|
||||
query = query.where(InspectionRecord.location_id == location_id)
|
||||
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()
|
||||
result = await db.execute(query.offset((page - 1) * page_size).limit(page_size))
|
||||
items = [InspectionRecordOut.model_validate(r) for r in result.scalars()]
|
||||
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[InspectionRecordOut])
|
||||
async def create_record(
|
||||
body: InspectionRecordCreate,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
_ = Depends(get_current_user),
|
||||
):
|
||||
loc_result = await db.execute(
|
||||
select(InspectionLocation).where(InspectionLocation.id == body.location_id)
|
||||
)
|
||||
loc = loc_result.scalar_one_or_none()
|
||||
record = InspectionRecord(
|
||||
**body.model_dump(),
|
||||
location_name=loc.name if loc else None,
|
||||
)
|
||||
@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()
|
||||
return Response.ok(InspectionRecordOut.model_validate(record))
|
||||
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()])
|
||||
|
||||
Reference in New Issue
Block a user