워크시트 검수 UI와 세션 다크톤 정리
This commit is contained in:
parent
f7aae885b2
commit
30441bd93b
7 changed files with 404 additions and 121 deletions
|
|
@ -10,6 +10,7 @@ from pydantic import BaseModel, Field
|
|||
from .. import session_persistence
|
||||
from ..deps import Principal, Role, require_role
|
||||
from ..runtime_policy import require_runtime_fallback_allowed
|
||||
from ..session_read_model import StageLabel, stage_label
|
||||
from ..services import session_metrics
|
||||
from ..store import InProcSession, store
|
||||
|
||||
|
|
@ -26,7 +27,7 @@ class TeacherSessionSummary(BaseModel):
|
|||
persona_name: str
|
||||
session_no: int
|
||||
status: str
|
||||
stage: str
|
||||
stage: StageLabel
|
||||
turn_count: int
|
||||
learner_turn_count: int
|
||||
client_turn_count: int
|
||||
|
|
@ -40,6 +41,8 @@ class TeacherSessionSummary(BaseModel):
|
|||
class TeacherSessionReviewStatusRequest(BaseModel):
|
||||
status: Literal["viewed", "closed"] = "closed"
|
||||
note: str = Field(default="", max_length=2000)
|
||||
worksheet_status: Literal["approved", "changes_requested", "rejected", "pending"] | None = None
|
||||
worksheet_note: str | None = Field(default=None, max_length=2000)
|
||||
|
||||
|
||||
class TeacherSessionReviewStatusResponse(BaseModel):
|
||||
|
|
@ -49,13 +52,16 @@ class TeacherSessionReviewStatusResponse(BaseModel):
|
|||
reviewer_id: str | None = None
|
||||
reviewed_at: str | None = None
|
||||
updated_at: str | None = None
|
||||
worksheet_status: Literal["pending", "approved", "changes_requested", "rejected"] = "pending"
|
||||
worksheet_note: str = ""
|
||||
worksheet_reviewed_at: str | None = None
|
||||
|
||||
|
||||
class TeacherGrowthPoint(BaseModel):
|
||||
session_id: str
|
||||
session_no: int
|
||||
persona_code: str
|
||||
stage: str
|
||||
stage: StageLabel
|
||||
started_at: str
|
||||
ended_at: str | None = None
|
||||
score: float | None = None
|
||||
|
|
@ -118,7 +124,7 @@ def _growth_point(point: session_metrics.SessionGrowthPoint) -> TeacherGrowthPoi
|
|||
session_id=point.session_id,
|
||||
session_no=point.session_no,
|
||||
persona_code=point.persona_code,
|
||||
stage=point.stage,
|
||||
stage=stage_label(point.stage),
|
||||
started_at=point.started_at,
|
||||
ended_at=point.ended_at,
|
||||
score=point.score,
|
||||
|
|
@ -161,6 +167,15 @@ def _review_status_value(record: dict[str, object] | None) -> Literal["pending",
|
|||
return "pending"
|
||||
|
||||
|
||||
def _worksheet_review_status_value(
|
||||
record: dict[str, object] | None,
|
||||
) -> Literal["pending", "approved", "changes_requested", "rejected"]:
|
||||
value = str((record or {}).get("worksheet_status") or "pending")
|
||||
if value in {"approved", "changes_requested", "rejected"}:
|
||||
return value # type: ignore[return-value]
|
||||
return "pending"
|
||||
|
||||
|
||||
def _summary(
|
||||
sess: InProcSession,
|
||||
review_status: dict[str, object] | None = None,
|
||||
|
|
@ -175,7 +190,7 @@ def _summary(
|
|||
persona_name=sess.persona.display_name,
|
||||
session_no=sess.session_no,
|
||||
status="ended" if sess.ended else "active",
|
||||
stage=sess.state.stage.value,
|
||||
stage=stage_label(sess.state.stage),
|
||||
turn_count=len(sess.turns),
|
||||
learner_turn_count=learner_turns,
|
||||
client_turn_count=client_turns,
|
||||
|
|
@ -286,6 +301,8 @@ async def update_session_review_status(
|
|||
status=request.status,
|
||||
note=request.note,
|
||||
principal=principal,
|
||||
worksheet_status=request.worksheet_status,
|
||||
worksheet_note=request.worksheet_note,
|
||||
)
|
||||
if saved is None:
|
||||
raise HTTPException(
|
||||
|
|
@ -299,4 +316,7 @@ async def update_session_review_status(
|
|||
reviewer_id=str(saved.get("reviewer_id") or "") or None,
|
||||
reviewed_at=str(saved.get("reviewed_at") or "") or None,
|
||||
updated_at=str(saved.get("updated_at") or "") or None,
|
||||
worksheet_status=_worksheet_review_status_value(saved),
|
||||
worksheet_note=str(saved.get("worksheet_note") or ""),
|
||||
worksheet_reviewed_at=str(saved.get("worksheet_reviewed_at") or "") or None,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -212,6 +212,9 @@ class TeacherDashboardGrowthTest(unittest.IsolatedAsyncioTestCase):
|
|||
"reviewer_id": principal.user_id,
|
||||
"status": "closed",
|
||||
"note": "다음 회기에서 반영 질문을 늘리도록 지도",
|
||||
"worksheet_status": "changes_requested",
|
||||
"worksheet_note": "보호요인 근거를 한 줄 더 보강",
|
||||
"worksheet_reviewed_at": "2026-06-27T10:05:00Z",
|
||||
"reviewed_at": "2026-06-27T10:00:00Z",
|
||||
"updated_at": "2026-06-27T10:00:00Z",
|
||||
},
|
||||
|
|
@ -225,13 +228,21 @@ class TeacherDashboardGrowthTest(unittest.IsolatedAsyncioTestCase):
|
|||
teacher.TeacherSessionReviewStatusRequest(
|
||||
status="closed",
|
||||
note="다음 회기에서 반영 질문을 늘리도록 지도",
|
||||
worksheet_status="changes_requested",
|
||||
worksheet_note="보호요인 근거를 한 줄 더 보강",
|
||||
),
|
||||
principal,
|
||||
)
|
||||
|
||||
save_status.assert_awaited_once()
|
||||
save_kwargs = save_status.await_args.kwargs
|
||||
self.assertEqual(save_kwargs["worksheet_status"], "changes_requested")
|
||||
self.assertIn("보호요인", save_kwargs["worksheet_note"])
|
||||
self.assertEqual(response.status, "closed")
|
||||
self.assertIn("반영 질문", response.note)
|
||||
self.assertEqual(response.worksheet_status, "changes_requested")
|
||||
self.assertIn("보호요인", response.worksheet_note)
|
||||
self.assertEqual(response.worksheet_reviewed_at, "2026-06-27T10:05:00Z")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue