# 保险方案"全程方案"语义对齐 (totalDays 哨兵) **日期**: 2026-04-27 **PR**: #1454 (Closes #1425) **影响端**: 管理端 admin ## 背景 保险方案的「段配置」(InsuranceSchemeSegment) 中 `dayOffsetEnd = -1` 是「行程最后一天/全程」的合法哨兵值。 之前 `computeTotalDays` 算法见到 -1 时会跳过该段、错误返回 maxDay=1,导致「全程方案」入库时 `totalDays=1`。`AdminInsuranceSchemeController.listActiveSchemes` 按 `totalDays.equals(s.getTotalDays())` 精确过滤,结果「全程方案」**只在 1 天行程下拉里能查到**,多天行程查不到,与字段语义不符。 ## 改动 ### 后端 - 新增哨兵常量 `InsuranceConstants.TOTAL_DAYS_FULL_TRIP = -1` - `computeTotalDays` 见到任一段 `dayOffsetEnd == -1` → 返回哨兵 -1 - `listActiveSchemes` 过滤逻辑同步: `totalDays==-1 || totalDays==请求tripDays` 视为命中 ### 接口字段语义变化 **`GET /admin/insurance/scheme/list?totalDays=N`**(启用方案下拉,按行程天数筛选) - 之前: 只返回 `totalDays == N` 的方案 - 现在: 返回 `totalDays == N` 或 `totalDays == -1`(全程方案)的方案 **`POST /admin/insurance/scheme` / `PUT /admin/insurance/scheme/{id}`** - request body 行为不变(前端继续配 `dayOffsetEnd: -1` 表示全程段) - response body 中的 `totalDays` 字段语义变化: - 之前: 全程方案返回 `1`(错误语义) - 现在: 全程方案返回 `-1`(哨兵, 表示"任意天数都适用") - 普通方案不受影响 ## 前端注意 **列表页/详情页展示**: 如果前端 UI 需要展示 `totalDays`, 见到 `-1` 应当展示为「全程」/「任意天数」, 而不是直接显示 "-1天"。 **新增/编辑表单**: `totalDays` 字段是后端计算字段, 前端不需要表单填写, 直接读 response 即可。 ## 数据迁移 - 现存所有方案均为非 -1 段配置, `totalDays` 都是正值, 无需迁移 - 本次上线后用户配置全程段时, 入库 `totalDays=-1` 自动生效 ## 单测 - `InsuranceManageServiceTest`: +3 case (单段全程哨兵 / 多段含全程 / 全部正常段保持原算法) - `AdminInsuranceSchemeControllerTest`: +2 case (5 天行程仅命中全程 / 同时命中全程+精确) - 全部 56 单测绿