diff --git a/changelogs/2026-04/2026-04-22_mp-traveler-birthday-auto-from-idcard.md b/changelogs/2026-04/2026-04-22_mp-traveler-birthday-auto-from-idcard.md new file mode 100644 index 0000000..57b2b4d --- /dev/null +++ b/changelogs/2026-04/2026-04-22_mp-traveler-birthday-auto-from-idcard.md @@ -0,0 +1,70 @@ +--- +date: 2026-04-22 +type: docs +scope: hl-mp-service,hl-user-service +pr: "#待填" +issue: "#1205" +breaking: false +audience: frontend +--- + +# 小程序添加出行人: 身份证场景 birthday 可空(后端自动解析回填) + +## TL;DR(前端行动点) + +小程序 "添加出行人" 表单,当 `idCardType === 'ID_CARD'` 时, **不要再要求用户手动选 birthday**。两种任选其一: + +1. **推荐**: 前端按身份证号第 7-14 位本地解析 `YYYYMMDD` 自动回填 input (与后端一致, 所见即所得) +2. **最小改动**: 前端表单 validator 对 `birthday` 必填校验放行 `idCardType=ID_CARD` 场景, 让请求直接发后端, 后端解析后 GET 详情时前端再刷新展示 + +## 背景 + +用户反馈: 身份证类型下, 填好证件号 + 姓名 + 手机号点 "确认添加", 被前端 Toast `请选择出生日期` 拦截。 + +后端早已支持 "填身份证 idCardNo 可不传 birthday" 契约 —— `TravelerService.addTraveler()` 在 `save()` **前**调用 `parseIdCardInfo()`, 按 `idCardNo.substring(6,14)` 用 `LocalDate.parse(str, BASIC_ISO_DATE)` 自动回填 `birthday` 写入 DB。 + +但此契约在 `@ApiModelProperty` 里没写清楚, 前端未读到导致表单校验写死 birthday 必填。 + +## 接口契约(本次明确) + +POST `/mp/user/traveler` (添加出行人) — 请求字段规则: + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| `name` | String | ✅ | 姓名 | +| `idCardType` | String | 推荐填 | `ID_CARD`(身份证) / `PASSPORT`(护照) / 其它 | +| `idCardNo` | String | 依业务 | 身份证 18 位 / 护照号等 | +| `birthday` | yyyy-MM-dd | **条件性** | **填身份证(ID_CARD)时可空, 后端自动解析 idCardNo 第 7-14 位回填; 护照等其它证件类型需前端传值** | +| `gender` | String | 否 | 身份证时后端从 idCardNo 第 17 位奇偶推断(填了则覆盖) | +| `phone` | String | 否 | 手机号 | +| 其余 | - | 否 | 见 knife4j | + +PUT `/mp/user/traveler/{id}` (编辑) 同样规则。 + +## 后端行为(只读参考) + +```java +// hl-user-service: TravelerService.parseIdCardInfo +if (!"ID_CARD".equals(idCardType) || idCardNo == null || idCardNo.length() != 18) return; +if (traveler.getBirthday() == null) { + String birthStr = idCardNo.substring(6, 14); + traveler.setBirthday(LocalDate.parse(birthStr, DateTimeFormatter.BASIC_ISO_DATE)); +} +``` + +- 身份证号位数不对 / 解析失败: 后端仅 `log.debug` 不抛异常, birthday 留 null +- 证件类型非 `ID_CARD`: 后端不解析, 前端必须传 birthday, 否则 `travelerType` 会默认 ADULT + +## 护照场景(保持不变) + +护照等非 ID_CARD 证件, 后端**不会**自动回填 birthday, 前端表单需要保留 birthday 选择器并要求用户填写 (否则后端按 `traveler_type_age_rule` 兜底为 ADULT)。 + +## 本次后端改动 + +仅 2 个 DTO 的 `@ApiModelProperty` 文案补充(`MpTravelerRequest.birthday` / `TravelerRequest.birthday`), 无业务逻辑变化、无签名变化、无字段增减。前端零风险, 本 changelog 是提醒前端调整表单校验。 + +## 关联 Issue / PR + +- Issue #1205 (前端 BUG: 前端表单校验写死 birthday 必填, 未识别身份证自动解析契约) +- PR #待填 +- 关联前期 PR 链: #1197 (travelerType 不入参+实时算) / #1198 (冷启动 SysDictService 回源) / #1199 (删 TravelerTypeResolver)