17 KiB
17 KiB
schema, ticket, title, consumer, author, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
| schema | ticket | title | consumer | author | change_type | backend_status | gateway_status | frontend_status | frontend_owner | frontend_ref | target_release | verified_at | status_note | updated_at | base |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| hl-changelog/v2 | 7947 | 餐食删除编码,关联餐厅(含全部),增加桌/人 | admin | lc(GIT) | 修改接口 | deployed | verified | verified | mmg | e0d613c113fb5268e9cd2f790885046fce8ab1d0 | 2026-09-20 | 餐食接口去掉编码 dishCode;新增餐厅 restaurantId(不传为全部)与桌/人 priceUnit(person/table,不传按人);出参新增 restaurantId、restaurantName(全部返回「全部」)、priceUnit。编码、图片 URL、餐厅 ID 不需要展示。前端需按本文对接。前端已交付(hl-ui v2.1 @ e0d613c1):列表删编码列、加餐厅列(restaurantName,餐厅已删 null 显 -)、单价带 /人/桌后缀、keyword placeholder 去编码;编辑弹窗删 dishCode 表单项/rules/回填/提交,加餐厅远程候选(分页 options 首焦拉首页+防抖+请求序号防旧响应,编辑回显餐厅不在候选时注入当前项,清空=「全部」create 不带键/update 传 null)与桌/人 radio(默认 person、编辑带回显值);两 spec 重写 17/17,scoped checkpoint 全绿。 | 2026-09-19 | dev-v3 |
resource: 餐食删除编码,关联餐厅(含全部),增加桌/人
服务: hl-resource-service(dish 表随服务部署由 Flyway 迁移) PR: #7958 Issue: #7947 日期: 2026-09-19 影响范围: 管理后台「餐食管理」5 个接口(分页、列表、详情、新建、修改)
⚠️ 关键变化
- 🗑️ 编码
dishCode删除:新建、修改不再有编码,分页不再按编码筛选,分页、列表、详情不再返回编码。340002「编码已存在」停用。 - 🆕 餐食关联餐厅:入参新增
restaurantId(餐厅资源里的餐厅 ID),不传为「全部」;出参新增restaurantId(全部为null)与restaurantName(全部返回「全部」)。 - 🆕 桌/人
priceUnit:person按人 /table按桌,表示单价是每人还是每桌;不传按人。 - 🔁 名称唯一范围变了:同一餐厅(「全部」算一组)内名称不能重复,报 340003;不同餐厅可以同名、单价各自维护。
- 👁️ 不需要展示:编码、图片 URL、餐厅 ID。
一、背景
餐食不再需要编码;餐食按餐厅维护,同一道餐食在不同餐厅价格不同,另有一种餐厅是「全部」(没有餐厅 ID);新增「桌/人」。已有餐食上线后都归「全部」、桌/人为「人」。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 分页查询餐食 | GET | /admin/dish/items/page |
修改 | 去掉查询参数 dishCode,keyword 只匹配名称;出参去掉 dishCode,加 restaurantId/restaurantName/priceUnit |
| 2 | 查询餐食列表 | GET | /admin/dish/items/list |
修改 | keyword 只匹配名称;出参同接口 1 |
| 3 | 查询餐食详情 | GET | /admin/dish/items/{dishId}/view |
修改 | 出参同接口 1 |
| 4 | 新建餐食 | POST | /admin/dish/items/add |
修改 | 去掉入参 dishCode;加 restaurantId、priceUnit;重名按餐厅分组 |
| 5 | 修改餐食 | PUT | /admin/dish/items/{dishId}/update |
修改 | 同接口 4;整份覆盖,restaurantId 不传即改为全部,priceUnit 不传即按人 |
三、接口详情
1. 分页查询餐食 GET /admin/dish/items/page
VO: DishPageReqVO → PageResult<DishListItemRespVO>
使用场景
餐食管理列表分页查询。
入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| keyword | Query | String | 否 | 去首尾空格后 ≤64 | 只模糊匹配名称(原来同时匹配编码) |
| Query | — | — | — | 已删除;继续传会被忽略 | |
| status / settleType / createdByName / page / pageSize | Query | — | 否 | 不变 | 不变 |
出参字段表
| 字段 | 类型 | 说明 |
|---|---|---|
| records[]. |
— | 已删除 |
| records[].restaurantId | String | null | 新增。餐厅 ID;「全部」为 null |
| records[].restaurantName | String | null | 新增。餐厅名称;「全部」返回 "全部";餐厅已删除为 null |
| records[].priceUnit | String | 新增。person 按人 / table 按桌 |
| records[] 其余字段、total / page / pageSize | — | 不变 |
请求示例
GET /admin/dish/items/page?page=1&pageSize=20&keyword=团队
Authorization: Bearer <admin token>
响应示例
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"records": [
{
"dishId": "2100767707048636418",
"restaurantId": null,
"restaurantName": "全部",
"dishName": "团队标准餐(八菜一汤)",
"unitPrice": 40.00,
"priceUnit": "person",
"imageUrl": null,
"settleType": "cash",
"status": 1,
"remark": null,
"createdBy": "1900000000000000001",
"createdByName": "张三",
"createdAt": "2026-09-18 10:02:11"
},
{
"dishId": "2100767707048636501",
"restaurantId": "2023382100664676353",
"restaurantName": "菌香园火锅",
"dishName": "团队升级餐(十菜一汤)",
"unitPrice": 600.00,
"priceUnit": "table",
"imageUrl": null,
"settleType": "cash",
"status": 1,
"remark": "含一道特色菜",
"createdBy": "1900000000000000001",
"createdByName": "张三",
"createdAt": "2026-09-18 10:05:40"
}
],
"total": 2,
"page": 1,
"pageSize": 20
}
}
空数据 / 降级响应
不变:无数据时 records 为 []、total 为 0。
错误响应
{ "code": 400, "message": "每页条数最大为100", "success": false, "data": null }
业务边界
- 旧前端继续传
dishCode查询参数不报错,但不再筛选。
2. 查询餐食列表 GET /admin/dish/items/list
VO: DishListReqVO → List<DishListItemRespVO>
使用场景
餐食下拉数据源(只返回上架餐食,不按餐厅过滤)。
入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| keyword | Query | String | 否 | 去首尾空格后 ≤64 | 只模糊匹配名称 |
| settleType / limit | Query | — | 否 | 不变 | 不变 |
出参字段表
| 字段 | 类型 | 说明 |
|---|---|---|
| [] | — | 字段同接口 1 的 records[]:去掉 dishCode,新增 restaurantId、restaurantName、priceUnit |
请求示例
GET /admin/dish/items/list?limit=50
Authorization: Bearer <admin token>
响应示例
{
"code": 200,
"message": "成功",
"success": true,
"data": [
{
"dishId": "2100767707048636418",
"restaurantId": null,
"restaurantName": "全部",
"dishName": "团队标准餐(八菜一汤)",
"unitPrice": 40.00,
"priceUnit": "person",
"imageUrl": null,
"settleType": "cash",
"status": 1,
"remark": null,
"createdBy": "1900000000000000001",
"createdByName": "张三",
"createdAt": "2026-09-18 10:02:11"
}
]
}
空数据 / 降级响应
不变:没有上架餐食时 data 为 []。
错误响应
{ "code": 400, "message": "limit最大为200", "success": false, "data": null }
业务边界
- 同名餐食在「全部」和各餐厅下各有一条时会同时出现,用
restaurantName区分。
3. 查询餐食详情 GET /admin/dish/items/{dishId}/view
VO: DishRespVO
使用场景
编辑回显。
入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| dishId | Path | String | 是 | 正数 | 餐食 ID(不变) |
出参字段表
| 字段 | 类型 | 说明 |
|---|---|---|
| 全部字段 | — | 同接口 1 的 records[]:去掉 dishCode,新增 restaurantId、restaurantName、priceUnit |
请求示例
GET /admin/dish/items/2100767707048636501/view
Authorization: Bearer <admin token>
响应示例
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"dishId": "2100767707048636501",
"restaurantId": "2023382100664676353",
"restaurantName": "菌香园火锅",
"dishName": "团队升级餐(十菜一汤)",
"unitPrice": 600.00,
"priceUnit": "table",
"imageUrl": null,
"settleType": "cash",
"status": 1,
"remark": "含一道特色菜",
"createdBy": "1900000000000000001",
"createdByName": "张三",
"createdAt": "2026-09-18 10:05:40"
}
}
空数据 / 降级响应
不变:餐食不存在或已删除返回 340001。
错误响应
{ "code": 340001, "message": "餐食不存在", "success": false, "data": null }
业务边界
- 回显时
restaurantId为null即「全部」。
4. 新建餐食 POST /admin/dish/items/add
VO: DishCreateReqVO → DishWriteRespVO
使用场景
新建餐食。
入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| Body | — | — | — | 已删除;继续传会被忽略,不再校验 | |
| restaurantId | Body | String | 否 | 餐厅资源里的餐厅 ID | 新增。不传为「全部」 |
| priceUnit | Body | String | 否 | person / table |
新增。不传按 person 存 |
| dishName | Body | String | 是 | 去首尾空格后 1–500 | 同一餐厅(全部算一组)内不能重复 |
| unitPrice / imageUrl / settleType / status / remark | Body | — | — | 不变 | 不变 |
出参字段表
| 字段 | 类型 | 说明 |
|---|---|---|
| dishId | String | 新餐食 ID(不变) |
| dishName | String | 餐食名称(不变) |
请求示例
{
"restaurantId": "2023382100664676353",
"dishName": "团队升级餐(十菜一汤)",
"unitPrice": 600.00,
"priceUnit": "table",
"settleType": "cash",
"remark": "含一道特色菜"
}
响应示例
{
"code": 200,
"message": "成功",
"success": true,
"data": { "dishId": "2100767707048636501", "dishName": "团队升级餐(十菜一汤)" }
}
空数据 / 降级响应
不变:要么 200 写入,要么返回错误码且零写入。
错误响应
{ "code": 340003, "message": "餐食名称已存在:团队升级餐(十菜一汤)", "success": false, "data": null }
{ "code": 400, "message": "桌/人必须是 person 或 table", "success": false, "data": null }
业务边界
- 同名餐食可以在「全部」和不同餐厅下各建一条;同一餐厅(或都不传餐厅)下重名报 340003。
5. 修改餐食 PUT /admin/dish/items/{dishId}/update
VO: DishUpdateReqVO → DishWriteRespVO
使用场景
修改餐食(整份覆盖)。
入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| dishId | Path | String | 是 | 正数 | 餐食 ID(不变) |
| Body | — | — | — | 已删除;继续传会被忽略 | |
| restaurantId | Body | String | 否 | 餐厅资源里的餐厅 ID | 新增。整份覆盖:不传即改为「全部」,编辑时须带回原值 |
| priceUnit | Body | String | 否 | person / table |
新增。整份覆盖:不传即按 person 存,编辑时须带回原值 |
| 其余入参 | Body | — | — | 不变 | dishName、unitPrice、imageUrl、settleType、status、remark 不变 |
出参字段表
| 字段 | 类型 | 说明 |
|---|---|---|
| dishId | String | 餐食 ID(不变) |
| dishName | String | 修改后的名称(不变) |
请求示例
{
"restaurantId": "2023382100664676353",
"dishName": "团队升级餐(十菜一汤)",
"unitPrice": 620.00,
"priceUnit": "table",
"imageUrl": null,
"settleType": "cash",
"status": 1,
"remark": "含一道特色菜"
}
响应示例
{
"code": 200,
"message": "成功",
"success": true,
"data": { "dishId": "2100767707048636501", "dishName": "团队升级餐(十菜一汤)" }
}
空数据 / 降级响应
不变:要么 200 覆盖写入,要么返回错误码且不改动数据。
错误响应
{ "code": 340003, "message": "餐食名称已存在:团队升级餐(十菜一汤)", "success": false, "data": null }
业务边界
- 查重在修改后的餐厅内进行,排除自己。
四、契约约束与正确调用方式
| 场景 | payload |
|---|---|
| ✅ 「全部」下按人的餐食 | { "dishName": "素斋套餐", "unitPrice": 50.00 } |
| ✅ 某餐厅下按桌的餐食 | { "restaurantId": "2023382100664676353", "dishName": "团队升级餐(十菜一汤)", "unitPrice": 600.00, "priceUnit": "table" } |
| ✅ 同名餐食在另一家餐厅 | 换一个 restaurantId 再建同名,单价可不同 |
| ❌ 同一餐厅(或「全部」)下重名 | 340003「餐食名称已存在」 |
❌ priceUnit 传 seat |
400「桌/人必须是 person 或 table」 |
⚠️ 修改时漏传 restaurantId / priceUnit |
整份覆盖:会改成「全部」/按人 |
五、数据库行为
dish 表删除 dish_code,新增 restaurant_id(空即全部)、price_unit(默认 person);名称唯一改为同一餐厅(全部算一组)内唯一。已有餐食迁移后都是「全部」、按人,其余字段不变。
六、边界行为
- 未登录 → 401(网关拦截),不变。
- 餐厅被删除后,其下餐食的
restaurantName为null,restaurantId仍返回。
六.6、修改前后对比
字段级对比
| 字段 | 改前 | 改后 |
|---|---|---|
dishCode(入参、出参、分页查询参数) |
必填,≤20,唯一 | 删除 |
restaurantId(入参、出参) |
无 | 新增,空即全部 |
restaurantName(出参) |
无 | 新增,全部返回「全部」 |
priceUnit(入参、出参) |
无 | 新增,person / table,不传按人 |
keyword |
匹配编码或名称 | 只匹配名称 |
行为级对比
| 行为 | 改前 | 改后 |
|---|---|---|
| 名称唯一 | 全部未删除餐食内唯一 | 同一餐厅(全部算一组)内唯一 |
| 340002 编码已存在 | 会返回 | 停用 |
六.7、影响评估
- 是否破坏向后兼容: 是(出参去掉
dishCode;旧前端多传的dishCode会被忽略,不报错) - 前端是否必须同步上线: 是,按本文对接餐厅与桌/人;编码、图片 URL、餐厅 ID 不需要展示
- 前端 workaround 清理点: 去掉编码相关的传参与展示
七、不影响范围
- 仅影响: 餐食接口 1–5
- 零影响:
- 餐食上下架
PUT /admin/dish/items/{dishId}/status/update、删除DELETE /admin/dish/items/{dishId}/del - 订单用餐信息、用餐模版接口(其中的「餐食编码快照」以后不会再有值)
- 餐食上下架
八、测试环境已验证
部署提交 4cbccc26b,经 Gateway 用真实身份实测 34 项全部通过:
已有 9 行餐食(含已删除) → 编码列已删,其余列与部署前一致;全部归「全部」、按人 ✓
分页、列表、7 个详情 → 不再有 dishCode,其余字段与部署前逐字段一致 ✓
不传编码新建、修改;传空串 / 25 字符 / 重复编码 → 均成功,编码被忽略 ✓
按 22 行数据表新建(全部 10 道 + 3 家餐厅各 4 道) → 全部成功,详情逐字段一致;同名在全部与 3 家餐厅各一条、单价不同 ✓
不传 priceUnit 新建、修改 → 存为 person ✓
全部下 / 同一餐厅下重名,修改成已有名称 → 340003,零写入 ✓
Swagger 部署前后 → 餐食模型只去 dishCode、加 restaurantId/restaurantName/priceUnit,其余一致 ✓
十、相关文档
- 关联 Issue: wx/HL#7947
- 关联 PR: wx/HL#7958
关联 / 联系人
链接
联系人
- 后端负责人: @lc