Files

87 lines
2.9 KiB
Python
Raw Permalink 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.
"""线索看板与处置 APIR7/R17/R18/R20)。
注意:不提供删除线索的端点(R19 线索不可删,独立性硬约束)。
"""
from __future__ import annotations
import uuid
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from app.api.schemas import (
AdjudicateRequest,
AssignRequest,
ClueOut,
DashboardSummary,
)
from app.clues import service as clue_svc
from app.clues.models import Clue, ClueStatus, ConfidenceTier
from app.db import get_session
router = APIRouter(prefix="/clues", tags=["clues"])
@router.get("", response_model=list[ClueOut])
def list_clues(
status: ClueStatus | None = Query(default=None),
scenario_code: str | None = Query(default=None),
confidence: ConfidenceTier | None = Query(default=None),
session: Session = Depends(get_session),
) -> list[Clue]:
return clue_svc.list_clues(
session, status=status, scenario_code=scenario_code, confidence=confidence
)
@router.get("/summary", response_model=DashboardSummary)
def summary(session: Session = Depends(get_session)) -> DashboardSummary:
"""运营看板汇总(R18/R21 的基础指标)。"""
clues = session.query(Clue).all()
by_status: dict[str, int] = {}
by_conf: dict[str, int] = {}
by_scenario: dict[str, int] = {}
total_amount = 0.0
for c in clues:
by_status[c.status.value] = by_status.get(c.status.value, 0) + 1
by_conf[c.confidence.value] = by_conf.get(c.confidence.value, 0) + 1
by_scenario[c.scenario_code] = by_scenario.get(c.scenario_code, 0) + 1
total_amount += c.amount_involved or 0.0
return DashboardSummary(
total=len(clues),
by_status=by_status,
by_confidence=by_conf,
by_scenario=by_scenario,
total_amount_involved=total_amount,
)
@router.get("/{clue_id}", response_model=ClueOut)
def get_clue(clue_id: uuid.UUID, session: Session = Depends(get_session)) -> Clue:
clue = session.get(Clue, clue_id)
if clue is None:
raise HTTPException(status_code=404, detail="线索不存在")
return clue
@router.post("/{clue_id}/assign", response_model=ClueOut)
def assign_clue(
clue_id: uuid.UUID, req: AssignRequest, session: Session = Depends(get_session)
) -> Clue:
clue = session.get(Clue, clue_id)
if clue is None:
raise HTTPException(status_code=404, detail="线索不存在")
return clue_svc.assign(session, clue, assignee=req.assignee, actor=req.actor)
@router.post("/{clue_id}/adjudicate", response_model=ClueOut)
def adjudicate_clue(
clue_id: uuid.UUID, req: AdjudicateRequest, session: Session = Depends(get_session)
) -> Clue:
clue = session.get(Clue, clue_id)
if clue is None:
raise HTTPException(status_code=404, detail="线索不存在")
clue_svc.adjudicate(session, clue, confirmed=req.confirmed, actor=req.actor, note=req.note)
return clue