Skip to content

修复家属问询会话 ID 丢失并字段化基础信息录入 - #129

Merged
cg8-5712 merged 2 commits into
mainfrom
fix/issue-128-family-intake-session-and-basic-form
Jul 26, 2026
Merged

cg8-5712 merged 2 commits into
mainfrom
fix/issue-128-family-intake-session-and-basic-form

Conversation

@cg8-5712

@cg8-5712 cg8-5712 commented Jul 26, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Closes #128.

  • Convert the answer-submission response (session_id) into the page's IntakeSession state shape (id) before storing it, preventing follow-up requests from targeting /intake-sessions/undefined/answers.
  • Replace the basic-information free-text field with labelled controls for name, gender, age, height, and distinguishing appearance.
  • Normalize those fields into a readable unconfirmed draft answer, retain unsubmitted values only in the current tab's session storage, and prefill corresponding fields at human confirmation.
  • Add regression coverage for the real session_id response and structured basic-information submission.

Validation

  • npm test — 8 files, 40 tests passed
  • npm run lint
  • npm run build
  • git diff --check

Summary by CodeRabbit

  • 新功能

    • 基础信息采集改为结构化表单,支持填写姓名、性别、年龄、身高和外观特征。
    • 支持暂存并恢复基础信息,继续填写流程更便捷。
    • 提交基础信息后可生成更准确的待确认资料草稿。
  • 问题修复

    • 优化问询答案提交后的会话更新,提升流程连续性。
    • 改进草稿重新获取及替换提交相关流程。

Copilot AI review requested due to automatic review settings July 26, 2026 07:06

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Jul 26, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@cg8-5712, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 7 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: fe04c044-240f-411d-bf4e-4cac230137a2

📥 Commits

Reviewing files that changed from the base of the PR and between 39901bf and e7dab5c.

📒 Files selected for processing (2)
  • frontend/src/pages/FamilyIntakeForm.test.tsx
  • frontend/src/pages/FamilyIntakeForm.tsx
📝 Walkthrough

Walkthrough

Changes

家属问询流程新增姓名、性别、年龄、身高和外观特征的结构化基础信息表单,并将其持久化到当前标签页草稿。提交答案响应现在通过 session_id 转换为页面会话状态,相关测试覆盖连续提交和答案格式。

Intake 问询流程

Layer / File(s) Summary
提交响应契约与会话状态转换
frontend/src/api/intake.ts, frontend/src/pages/FamilyIntakeForm.tsx, frontend/src/pages/FamilyIntakeForm.test.tsx
新增 IntakeSessionUpdate,使提交答案响应使用 session_id;页面通过统一转换函数恢复 id,并测试基础信息提交及后续会话推进。
结构化基础信息表单与草稿恢复
frontend/src/pages/FamilyIntakeForm.tsx, frontend/src/pages/FamilyIntakeForm.test.tsx
新增基础信息控件、答案与画像描述生成逻辑,并将字段接入 sessionStorage 持久化、类型校验、恢复及确认草稿初始化。

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant FamilyIntakeForm
  participant submitIntakeAnswer
  participant sessionFromAnswerResponse
  FamilyIntakeForm->>submitIntakeAnswer: 提交结构化基础信息答案
  submitIntakeAnswer-->>FamilyIntakeForm: 返回 session_id 和下一问询状态
  FamilyIntakeForm->>sessionFromAnswerResponse: 转换提交响应
  sessionFromAnswerResponse-->>FamilyIntakeForm: 更新页面会话并加载下一阶段
Loading

Possibly related PRs

Suggested reviewers: copilot

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确概括了会话 ID 修复和基础信息结构化录入这两个主要改动。
Linked Issues check ✅ Passed 变更覆盖了 session_id 映射、连续提交保持会话 ID、结构化基础信息表单及相关回归测试。
Out of Scope Changes check ✅ Passed 未见与链接需求无关的明显额外改动,变更集中在问询会话与基础信息录入修复。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/issue-128-family-intake-session-and-basic-form

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

Preview ready

The preview for this build is available at https://pr-129-39901bf1f4c9.angui.cg8.site.

Temporary demo accounts (all use the password 6e7b1f9aa50da2d3afd623f3804531b7926719e91e0ad770):

Role Email
Family family@demo.invalid
Commander commander@demo.invalid
Volunteer volunteer@demo.invalid
Learner learner@demo.invalid
Administrator admin@demo.invalid

These accounts and all preview data belong only to this deployment. The next preview deployment resets the SQLite database and invalidates these credentials.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
frontend/src/pages/FamilyIntakeForm.tsx (3)

520-524: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

手动"重新获取草稿"按钮未传入当前 basicInformation,会导致画像草稿初始化为空白姓名/性别/年龄。

loadDraft 的第三个参数默认值是 blankBasicInformation;其余调用点(Line 167、242)都显式传入了当前/恢复的 basicInformation,唯独这里的手动重试按钮遗漏了该参数,与函数签名新增的语义不一致。

🐛 建议修复
-          <Button className="mt-3" size="sm" variant="ghost" onPress={() => void loadDraft(session.id, true)} isDisabled={isBusy}>重新获取草稿</Button>
+          <Button className="mt-3" size="sm" variant="ghost" onPress={() => void loadDraft(session.id, true, basicInformation)} isDisabled={isBusy}>重新获取草稿</Button>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/pages/FamilyIntakeForm.tsx` around lines 520 - 524, Update the
manual retry handler in the draft-loading UI to pass the current
basicInformation as loadDraft’s third argument, matching the existing calls at
the other loadDraft call sites while preserving the current session.id and retry
flag.

187-195: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

离开前的未保存提示未覆盖结构化的 basicInformation 草稿。

beforeunload 监听器(187-195)与 requestCancel(312-318)仍只检查 answer.trim()。当当前问题是 basic_information 时,家属填写的内容存放在 basicInformation 而非 answer,即便已填写但未点击"保存并继续",关闭标签页或点击"暂时离开"都不会触发提示,与"其余答案未提交会提醒"的既有行为不一致。

🛡️ 建议修复
   useEffect(() => {
-    if (!answer.trim() || typeof window === 'undefined') return
+    if ((!answer.trim() && !basicInformationAnswer(basicInformation)) || typeof window === 'undefined') return
     const warnBeforeLeave = (event: BeforeUnloadEvent) => {
       event.preventDefault()
       event.returnValue = ''
     }
     window.addEventListener('beforeunload', warnBeforeLeave)
     return () => window.removeEventListener('beforeunload', warnBeforeLeave)
-  }, [answer])
+  }, [answer, basicInformation])
   function requestCancel() {
-    if (answer.trim() && typeof window !== 'undefined') {
+    if ((answer.trim() || basicInformationAnswer(basicInformation)) && typeof window !== 'undefined') {
       const proceed = window.confirm('当前答案尚未提交。它会仅保留在此标签页草稿中;确定暂时离开吗?')
       if (!proceed) return
     }
     onCancel()
   }

Also applies to: 312-318

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/pages/FamilyIntakeForm.tsx` around lines 187 - 195, 扩展
FamilyIntakeForm 中 useEffect 的 beforeunload 条件和 requestCancel 的未保存判断,使当前问题为
basic_information 时也检查 basicInformation 是否包含已填写内容,而不是仅检查
answer.trim()。保留现有普通答案的提醒行为,并确保未点击“保存并继续”的结构化草稿在关闭页面或暂时离开时触发提示。

304-310: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

"返回修改"流程未适配结构化的 basic_information,修订会覆盖并丢失姓名/性别/年龄等字段。

openSourceEditor 与其对应的编辑区块始终使用通用的 editAnswer + TextArea,且 editAnswer 只回填 draft.profile[source.field](例如 physical_description 的文本,如"佩戴眼镜,穿蓝色外套。")。但当 source.source_field === 'basic_information' 时(测试 mock 中确有此映射),点击"保存修订并刷新草稿"会以 replace: true 把 field: 'basic_information' 的答案整体替换为这段自由文本——先前通过结构化表单提交的姓名、性别、年龄、身高会被静默丢弃,仅留下体貌描述片段。

建议:当 editSource.source_field === 'basic_information' 时,改用 BasicInformationForm(以当前 basicInformation 状态或从既有草稿反解出的值作为初始值)进行编辑,并在保存时调用 basicInformationAnswer(...) 生成完整的带标签答案后再提交,而不是复用通用自由文本编辑框。

As per path instructions, frontend changes should be reviewed for "validation, data exposure, and user-visible failure paths" — this correction flow can silently discard previously confirmed structured data, which is a user-visible data-loss failure path.

Also applies to: 380-400

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/pages/FamilyIntakeForm.tsx` around lines 304 - 310, Update the
correction flow around openSourceEditor and its save handler to special-case
editSource.source_field === 'basic_information': render BasicInformationForm
with the current structured basicInformation values (or values reconstructed
from the draft), and on save generate the complete labeled answer via
basicInformationAnswer before submitting. Keep the generic editAnswer/TextArea
path for other source fields, and validate the structured form before allowing
submission so existing name, gender, age, height, and description data cannot be
silently replaced.

Source: Path instructions

🧹 Nitpick comments (1)
frontend/src/pages/FamilyIntakeForm.test.tsx (1)

168-193: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

测试覆盖了结构化基础信息提交的主路径,契约断言到位。

建议后续在 FamilyIntakeForm.tsx 中的 validInteger 缺陷修复后,补充一条"年龄留空"用例(断言拼接文本中不出现"年龄:0 岁"),以防回归。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/pages/FamilyIntakeForm.test.tsx` around lines 168 - 193, Extend
the FamilyIntakeForm tests with an “年龄” left blank scenario after fixing
validInteger in FamilyIntakeForm.tsx, and assert the submitted basic_information
answer omits the “年龄:0 岁” entry while preserving the other populated fields.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/src/pages/FamilyIntakeForm.tsx`:
- Around line 671-722: Update validInteger to treat a blank or whitespace-only
value as invalid and return null before applying numeric conversion and range
validation. Preserve valid zero when explicitly entered, so
basicInformationAnswer omits only empty ages and profileFromDraft initializes
them as null while existing height validation remains unchanged.

---

Outside diff comments:
In `@frontend/src/pages/FamilyIntakeForm.tsx`:
- Around line 520-524: Update the manual retry handler in the draft-loading UI
to pass the current basicInformation as loadDraft’s third argument, matching the
existing calls at the other loadDraft call sites while preserving the current
session.id and retry flag.
- Around line 187-195: 扩展 FamilyIntakeForm 中 useEffect 的 beforeunload 条件和
requestCancel 的未保存判断,使当前问题为 basic_information 时也检查 basicInformation
是否包含已填写内容,而不是仅检查 answer.trim()。保留现有普通答案的提醒行为,并确保未点击“保存并继续”的结构化草稿在关闭页面或暂时离开时触发提示。
- Around line 304-310: Update the correction flow around openSourceEditor and
its save handler to special-case editSource.source_field ===
'basic_information': render BasicInformationForm with the current structured
basicInformation values (or values reconstructed from the draft), and on save
generate the complete labeled answer via basicInformationAnswer before
submitting. Keep the generic editAnswer/TextArea path for other source fields,
and validate the structured form before allowing submission so existing name,
gender, age, height, and description data cannot be silently replaced.

---

Nitpick comments:
In `@frontend/src/pages/FamilyIntakeForm.test.tsx`:
- Around line 168-193: Extend the FamilyIntakeForm tests with an “年龄” left blank
scenario after fixing validInteger in FamilyIntakeForm.tsx, and assert the
submitted basic_information answer omits the “年龄:0 岁” entry while preserving the
other populated fields.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 973fe6a2-25cb-4751-80bd-e3095c027339

📥 Commits

Reviewing files that changed from the base of the PR and between 4b2bb45 and 39901bf.

📒 Files selected for processing (3)
  • frontend/src/api/intake.ts
  • frontend/src/pages/FamilyIntakeForm.test.tsx
  • frontend/src/pages/FamilyIntakeForm.tsx

Comment thread frontend/src/pages/FamilyIntakeForm.tsx
@github-actions

Copy link
Copy Markdown

Preview ready

The preview for this build is available at https://pr-129-e7dab5cda278.angui.cg8.site.

Temporary demo accounts (all use the password 1b2e237f1061758c360e6b6fe2d9f98d1d2b81eb833355f4):

Role Email
Family family@demo.invalid
Commander commander@demo.invalid
Volunteer volunteer@demo.invalid
Learner learner@demo.invalid
Administrator admin@demo.invalid

These accounts and all preview data belong only to this deployment. The next preview deployment resets the SQLite database and invalidates these credentials.

@cg8-5712
cg8-5712 merged commit 0b96aa6 into main Jul 26, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

修复家属问询第二题请求 undefined,并将基础信息改为结构化表单

2 participants