- GET /admin/product/item/{id}/daily-mileage 已删除
- 新增 POST /admin/product/item/{id}/daily-mileage
- 前端在 Step3 路线设计过程中可传当前编辑态节点顺序实时试算
- 不再依赖必须先保存 Step2 行程
- 破坏性变更,前端必须切换新接口
5.6 KiB
5.6 KiB
每日行程里程接口重构:GET 改 POST,前端传节点顺序实时试算
服务: hl-product-service-v2 (端口 8083,经网关 8080) PR: #744 Issue: #737 提交:
7143671a日期: 2026-04-17 类型: refactor (破坏性变更) 影响范围: 管理端产品编辑 Step3「路线设计」
⚠️ 破坏性变更(Breaking Change)⚠️
旧的 GET /admin/product/item/{id}/daily-mileage 接口已删除,前端必须切换到新的 POST 接口,否则页面上的里程/时长数据将无法获取。
改动概述
每日行程距离/时长的计算接口,由"后端从 DB 读取已保存的节点"改为"前端把当前编辑态的节点顺序传过来",使得 Step3 路线设计过程中即可实时试算,不再依赖必须先保存 Step2。
使用场景变化
| 场景 | 旧方案 | 新方案 |
|---|---|---|
| 触发时机 | 必须先保存 Step2 行程,再点按钮查询 | Step3 路线设计过程中随时触发 |
| 数据来源 | 后端从 DB 按产品 ID 读取已保存节点 | 前端将"编辑态"节点顺序传给后端 |
| 前端体验 | 改了顺序必须保存才能看新距离 | 拖动节点后立即可试算 |
旧接口(已删除)
| 方法 | 路径 |
|---|---|
/admin/product/item/{id}/daily-mileage |
旧接口无请求体,后端从 DB 读取。调用会返回 404/405,请立即切换。
新接口
| 方法 | 路径 |
|---|---|
| POST | /admin/product/item/{id}/daily-mileage |
路径参数:
id:产品 ID(Long,Path Variable),保持与其他接口一致;当前后端不依赖它从 DB 读节点,仅用于日志/鉴权上下文
请求体:DailyMileageCalcReqVO
请求体字段表
顶层:DailyMileageCalcReqVO
| 字段 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|
days |
List<Day> |
是 | @NotEmpty,最多 30 天(@Size(max=30)) |
按天分组的节点列表 |
days[]:Day(每日行程)
| 字段 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|
dayNumber |
Integer |
是 | ≥1 | 天序号(1,2,3...),与响应中的 dayNumber 对应 |
nodes |
List<Node> |
是 | @NotEmpty,单日最多 50 个(@Size(max=50)) |
该天的节点列表,按驾车顺序 |
days[].nodes[]:Node(节点)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
nodeType |
String |
是 | 节点类型,见下方「节点类型处理规则」 |
resourceId |
Long |
是 | 资源 ID,对应资源服务主键 |
节点类型处理规则
只有以下 5 种"有坐标"的节点会被计算距离:
| nodeType | 说明 |
|---|---|
SCENIC |
景点 |
ACTIVITY |
活动 |
HOTEL |
酒店 |
RESTAURANT |
餐厅 |
SERVICE |
服务/服务区 |
以下类型会被静默忽略(传了也不报错,但不参与计算):
| nodeType | 说明 |
|---|---|
TRANSPORT |
交通段 |
PHOTOGRAPHY |
拍摄/打卡 |
FREE |
自由活动 |
CUSTOM |
自定义 |
NOTE |
备注 |
前端可以放心把整天的节点全部传过来,后端会自行过滤。
响应字段表
响应结构不变:Result<List<DailyMileageVO>>
| 字段 | 类型 | 说明 |
|---|---|---|
dayNumber |
Integer |
天序号,与请求中的 dayNumber 一一对应 |
mileage |
BigDecimal |
里程,单位:公里(km),保留 1 位小数 |
duration |
Integer |
驾车时长,单位:分钟(min) |
请求示例
POST /admin/product/item/123/daily-mileage
Content-Type: application/json
{
"days": [
{
"dayNumber": 1,
"nodes": [
{ "nodeType": "SCENIC", "resourceId": 3001 },
{ "nodeType": "ACTIVITY", "resourceId": 5001 },
{ "nodeType": "RESTAURANT", "resourceId": 6001 },
{ "nodeType": "HOTEL", "resourceId": 7001 }
]
},
{
"dayNumber": 2,
"nodes": [
{ "nodeType": "HOTEL", "resourceId": 7001 },
{ "nodeType": "SCENIC", "resourceId": 3002 },
{ "nodeType": "SERVICE", "resourceId": 8001 },
{ "nodeType": "SCENIC", "resourceId": 3003 }
]
}
]
}
响应示例
{
"code": 0,
"data": [
{ "dayNumber": 1, "mileage": 52.3, "duration": 78 },
{ "dayNumber": 2, "mileage": 143.7, "duration": 195 }
],
"msg": ""
}
前端使用建议(Step3 路线设计实时试算)
- 触发时机:用户在 Step3 拖动/增删节点后(推荐 debounce 300~500ms 再请求),或点击"重新计算里程"按钮
- 数据来源:直接用前端当前"编辑态"的节点顺序组装请求体,不需要先保存草稿
- 渲染:按
dayNumber匹配回请求中的每一天,展示mileage公里 +duration分钟 - 类型过滤:无需前端过滤节点类型,整天节点直接传即可
- 空值处理:如果某一天节点都没有坐标(例如全是 FREE/CUSTOM),后端会返回
mileage=0, duration=0
校验约束汇总
| 规则 | 违反时错误码 |
|---|---|
days 不能为空 |
400 参数校验失败 |
days 最多 30 天 |
400 参数校验失败 |
days[].nodes 不能为空 |
400 参数校验失败 |
days[].nodes 单日最多 50 个 |
400 参数校验失败 |
需要重启的服务
hl-product-service-v2(端口 8083,经网关 8080)—— 通过 Deploy Panel 重新部署最新 jar。
前端测试前请确认该服务已重启。