Sprint 6: report review workflow, CI/K8s, and client tabs.
Add coach review APIs, pose calibration thresholds, Gitea CI, Kubernetes skeleton, H5 practice page, and mini program tab bar. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -56,16 +56,18 @@ def create_report_for_task(db: Session, task: AnalysisTask, analysis: dict) -> R
|
||||
)
|
||||
else:
|
||||
payload = {**MOCK_REPORT, **report_data, "childId": task.child_id, "taskId": task.id}
|
||||
risk_level = payload.get("riskLevel", "medium")
|
||||
report_status = "pending_review" if risk_level in ("high", "review_required") else "published"
|
||||
report = Report(
|
||||
child_id=task.child_id,
|
||||
task_id=task.id,
|
||||
report_type="posture_screening",
|
||||
risk_level=payload.get("riskLevel", "medium"),
|
||||
risk_level=risk_level,
|
||||
summary=payload.get("summary", MOCK_REPORT["summary"]),
|
||||
metrics=payload.get("metrics", MOCK_REPORT["metrics"]),
|
||||
recommendations=payload.get("recommendations", MOCK_REPORT["recommendations"]),
|
||||
disclaimer=payload.get("disclaimer", DISCLAIMER_SCREENING),
|
||||
status="published",
|
||||
status=report_status,
|
||||
)
|
||||
db.add(report)
|
||||
db.flush()
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
"""Report review workflow for staff."""
|
||||
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.db.models import Child, Report
|
||||
|
||||
|
||||
def report_admin_dict(report: Report, child: Child | None = None) -> dict:
|
||||
return {
|
||||
"id": report.id,
|
||||
"childId": report.child_id,
|
||||
"childName": child.name if child else None,
|
||||
"taskId": report.task_id,
|
||||
"reportType": report.report_type,
|
||||
"riskLevel": report.risk_level,
|
||||
"summary": report.summary,
|
||||
"status": report.status,
|
||||
"reviewedBy": report.reviewed_by,
|
||||
"createdAt": report.created_at.isoformat() if report.created_at else None,
|
||||
}
|
||||
|
||||
|
||||
def list_pending_reports(db: Session, tenant_id: int | None = None) -> list[dict]:
|
||||
query = (
|
||||
select(Report, Child)
|
||||
.join(Child, Child.id == Report.child_id)
|
||||
.where(Report.status == "pending_review")
|
||||
.order_by(Report.id.desc())
|
||||
)
|
||||
if tenant_id:
|
||||
query = query.where(Child.tenant_id == tenant_id)
|
||||
|
||||
rows = db.execute(query).all()
|
||||
return [report_admin_dict(report, child) for report, child in rows]
|
||||
|
||||
|
||||
def get_report_for_review(db: Session, report_id: int, tenant_id: int | None = None) -> Report | None:
|
||||
report = db.get(Report, report_id)
|
||||
if not report:
|
||||
return None
|
||||
child = db.get(Child, report.child_id)
|
||||
if not child:
|
||||
return None
|
||||
if tenant_id and child.tenant_id != tenant_id:
|
||||
return None
|
||||
return report
|
||||
|
||||
|
||||
def review_report(
|
||||
db: Session,
|
||||
reviewer_id: int,
|
||||
report_id: int,
|
||||
action: str,
|
||||
tenant_id: int | None = None,
|
||||
note: str | None = None,
|
||||
) -> tuple[Report | None, str | None]:
|
||||
report = get_report_for_review(db, report_id, tenant_id)
|
||||
if not report:
|
||||
return None, "report_not_found"
|
||||
if report.status != "pending_review":
|
||||
return None, "invalid_status"
|
||||
|
||||
if action == "approve":
|
||||
report.status = "published"
|
||||
elif action == "reject":
|
||||
report.status = "rejected"
|
||||
else:
|
||||
return None, "invalid_action"
|
||||
|
||||
report.reviewed_by = reviewer_id
|
||||
report.updated_at = datetime.now(timezone.utc)
|
||||
if note:
|
||||
recommendations = list(report.recommendations or [])
|
||||
recommendations.append(f"复核备注:{note}")
|
||||
report.recommendations = recommendations
|
||||
|
||||
db.commit()
|
||||
db.refresh(report)
|
||||
return report, None
|
||||
@@ -37,6 +37,7 @@ def report_to_dict(report: Report) -> dict:
|
||||
"metrics": report.metrics,
|
||||
"recommendations": report.recommendations,
|
||||
"disclaimer": report.disclaimer,
|
||||
"status": report.status,
|
||||
"reviewedBy": report.reviewed_by,
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user