diff --git a/admin/routes/web_public.py b/admin/routes/web_public.py index 39f477e..3284149 100644 --- a/admin/routes/web_public.py +++ b/admin/routes/web_public.py @@ -510,6 +510,21 @@ def _build_portal_context(order: Order, settings: Settings) -> dict[str, Any]: title, subtitle = _STAGE_META[stage] latest_station_notice: dict[str, Any] | None = None + intake_summary = None + attachment_count = 0 + if intake is not None: + attachment_count = len(list((intake.payload or {}).get("attachments") or [])) + intake_summary = { + "candidate_score": intake.payload.get("candidate_score"), + "candidate_rank": intake.payload.get("candidate_rank"), + "candidate_subjects": intake.payload.get("candidate_subjects") or [], + "candidate_interests": intake.payload.get("candidate_interests"), + "target_cities": intake.payload.get("target_cities") or [], + "target_majors": intake.payload.get("target_majors") or [], + "university_preferences": intake.payload.get("university_preferences"), + "existing_plan_summary": intake.payload.get("existing_plan_summary"), + "guardian_notes": intake.payload.get("guardian_notes"), + } if sent_station_events: try: latest_payload = json.loads(sent_station_events[-1].payload_json) @@ -524,6 +539,8 @@ def _build_portal_context(order: Order, settings: Settings) -> dict[str, Any]: "stage_subtitle": subtitle, "payment": payment, "intake": intake, + "intake_summary": intake_summary, + "attachment_count": attachment_count, "report_html_ready": report_html_ready, "report_pdf_ready": report_pdf_ready, "order": order, @@ -848,6 +865,10 @@ def _render_info_page(


+
+
+
+

@@ -872,12 +893,18 @@ def _render_info_page( async function submitIntake(mode) {{ const form = new FormData(document.getElementById('intake-form')); const subjects = String(form.get('candidate_subjects') || '').split(',').map(s => s.trim()).filter(Boolean); + const targetCities = String(form.get('target_cities') || '').split(',').map(s => s.trim()).filter(Boolean); + const targetMajors = String(form.get('target_majors') || '').split(',').map(s => s.trim()).filter(Boolean); const payload = {{ mode, candidate_score: form.get('candidate_score') ? Number(form.get('candidate_score')) : null, candidate_rank: form.get('candidate_rank') ? Number(form.get('candidate_rank')) : null, candidate_subjects: subjects, candidate_interests: form.get('candidate_interests') || null, + target_cities: targetCities, + target_majors: targetMajors, + university_preferences: form.get('university_preferences') || null, + existing_plan_summary: form.get('existing_plan_summary') || null, guardian_notes: form.get('guardian_notes') || null, consent_version: form.get('consent_version') || null, consent_scope: form.get('consent_scope') || null, @@ -936,7 +963,13 @@ def _render_status_page(token: str, context: dict[str, Any]) -> str: if isinstance(station_notice, dict): title = escape(str(station_notice.get("title") or "站内通知")) body = escape(str(station_notice.get("body") or "")) - sent_at = escape(str(station_notice.get("sent_at") or "")) + sent_at = escape( + str( + station_notice.get("sent_at") + or station_notice.get("delivered_at") + or "" + ) + ) station_notice_html = f"""

通知已发送

@@ -944,6 +977,26 @@ def _render_status_page(token: str, context: dict[str, Any]) -> str:

{body}

发送时间:{sent_at}

""" + summary_html = "" + intake_summary = context.get("intake_summary") or {} + attachment_count = int(context.get("attachment_count") or 0) + if intake_summary: + summary_items = [ + f"
  • 分数:{escape(str(intake_summary.get('candidate_score') or '-'))}
  • ", + f"
  • 位次:{escape(str(intake_summary.get('candidate_rank') or '-'))}
  • ", + f"
  • 选科:{escape(','.join(intake_summary.get('candidate_subjects') or [])) or '-'}
  • ", + f"
  • 兴趣方向:{escape(str(intake_summary.get('candidate_interests') or '-'))}
  • ", + f"
  • 目标城市:{escape(','.join(intake_summary.get('target_cities') or [])) or '-'}
  • ", + f"
  • 目标专业:{escape(','.join(intake_summary.get('target_majors') or [])) or '-'}
  • ", + f"
  • 院校偏好:{escape(str(intake_summary.get('university_preferences') or '-'))}
  • ", + f"
  • 已有方案说明:{escape(str(intake_summary.get('existing_plan_summary') or '-'))}
  • ", + f"
  • 附件数量:{attachment_count}
  • ", + ] + summary_html = f""" +
    +

    当前资料摘要

    + +
    """ return f""" 订单状态 @@ -955,6 +1008,7 @@ def _render_status_page(token: str, context: dict[str, Any]) -> str:

    服务版本:{escape(order.service_version)}

    当前订单状态:{escape(order.status)}

    + {summary_html} {station_notice_html}

    下一步操作

    diff --git a/admin/tests/test_order_info_form.py b/admin/tests/test_order_info_form.py index 1db2ee4..cf6fac3 100644 --- a/admin/tests/test_order_info_form.py +++ b/admin/tests/test_order_info_form.py @@ -47,6 +47,9 @@ def test_order_info_form_accepts_draft_and_submit(client, settings): assert page.status_code == 200, page.text assert "考生资料填写" in page.text assert "监护人已知情并同意" in page.text + assert "目标城市" in page.text + assert "目标专业" in page.text + assert "已有方案说明" in page.text draft = client.post( f"/portal/{token}/info", @@ -56,6 +59,10 @@ def test_order_info_form_accepts_draft_and_submit(client, settings): "candidate_rank": 12034, "candidate_subjects": ["物理", "化学", "生物"], "candidate_interests": "计算机", + "target_cities": ["长沙", "上海"], + "target_majors": ["计算机科学与技术", "自动化"], + "university_preferences": "更偏向 985 / 211,接受省内优先", + "existing_plan_summary": "已有一份千问方案,需要人工校验是否扎堆", "guardian_notes": "更看重省内城市", "consent_version": "t12-web-mvp-v1", "consent_scope": "web-self-service-order-intake", @@ -76,6 +83,10 @@ def test_order_info_form_accepts_draft_and_submit(client, settings): "candidate_rank": 12034, "candidate_subjects": ["物理", "化学", "生物"], "candidate_interests": "计算机", + "target_cities": ["长沙", "上海"], + "target_majors": ["计算机科学与技术", "自动化"], + "university_preferences": "更偏向 985 / 211,接受省内优先", + "existing_plan_summary": "已有一份千问方案,需要人工校验是否扎堆", "guardian_notes": "更看重省内城市", "consent_version": "t12-web-mvp-v1", "consent_scope": "web-self-service-order-intake", @@ -91,6 +102,10 @@ def test_order_info_form_accepts_draft_and_submit(client, settings): status_page = client.get(f"/portal/{token}/status") assert status_page.status_code == 200, status_page.text assert "处理中" in status_page.text + assert "当前资料摘要" in status_page.text + assert "长沙,上海" in status_page.text + assert "计算机科学与技术,自动化" in status_page.text + assert "已有一份千问方案" in status_page.text def test_order_info_form_becomes_read_only_after_report_ready(