changelog: refactor product-v2 餐饮选项 meal_option 字典化 (#2778)
这个提交包含在:
父节点
9b1f59c96c
当前提交
376e28930f
@ -0,0 +1,119 @@
|
|||||||
|
# refactor(product-v2): 餐饮选项 meal_option 由硬编码改为系统字典 + 新增「含(正餐)」
|
||||||
|
|
||||||
|
**日期**:2026-05-21
|
||||||
|
**PR**:#2783(已合 dev → 已合 dev-v3 → 已部署测试服并验证)
|
||||||
|
**工单**:#2778
|
||||||
|
**影响端**:管理后台前端(hl-ui)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 背景
|
||||||
|
|
||||||
|
原「餐饮安排」下拉框 4 个选项(含酒店 / 含营地 / 含特色餐 / 自理)在前端 `MealConfig.vue` 和后端 `ProductItineraryAggregateFacade` 都是**硬编码**。每次加一个选项都要前后端同时改代码、走 PR、上线。
|
||||||
|
|
||||||
|
本次改造:
|
||||||
|
- 后端 switch 硬编码 → 改为读 `meal_option` 字典
|
||||||
|
- 字典数据库里新加一条 `REGULAR` = 「含(正餐)」
|
||||||
|
- 以后再加选项只在字典管理后台点一下即可,**前后端代码无需任何改动**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 字典数据(meal_option)
|
||||||
|
|
||||||
|
测试服已落库,可通过 `GET /admin/dict/data/meal_option` 拉到:
|
||||||
|
|
||||||
|
| sortOrder | dictValue | dictLabel | 说明 |
|
||||||
|
|-----------|-----------|-----------|------|
|
||||||
|
| 1 | `HOTEL` | 含(酒店) | 历史值 |
|
||||||
|
| 2 | `CAMP` | 含(营地) | 历史值 |
|
||||||
|
| 3 | `SPECIAL` | 含(特色餐) | 历史值 |
|
||||||
|
| 4 | `REGULAR` | **含(正餐)** | **本次新增** |
|
||||||
|
| 5 | `SELF` | 自理 | 历史值(默认值) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚨 前端需要做的事
|
||||||
|
|
||||||
|
### 1. 删除硬编码
|
||||||
|
|
||||||
|
文件:`hl-ui/src/views/product/edit/components/itinerary/MealConfig.vue`
|
||||||
|
|
||||||
|
把第 22-27 行的硬编码数组**删掉**:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// 删掉这段
|
||||||
|
const mealOptions = [
|
||||||
|
{ label: '含(酒店)', value: 'HOTEL' },
|
||||||
|
{ label: '含(营地)', value: 'CAMP' },
|
||||||
|
{ label: '含(特色餐)', value: 'SPECIAL' },
|
||||||
|
{ label: '自理', value: 'SELF' },
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 改成调字典接口
|
||||||
|
|
||||||
|
调用:`GET /admin/dict/data/meal_option`(已存在的字典 API)
|
||||||
|
|
||||||
|
**Header**:需要 admin token
|
||||||
|
|
||||||
|
**响应结构**:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"message": "成功",
|
||||||
|
"data": [
|
||||||
|
{ "dictValue": "HOTEL", "dictLabel": "含(酒店)", "sortOrder": 1, "status": "ACTIVE" },
|
||||||
|
{ "dictValue": "CAMP", "dictLabel": "含(营地)", "sortOrder": 2, "status": "ACTIVE" },
|
||||||
|
{ "dictValue": "SPECIAL", "dictLabel": "含(特色餐)", "sortOrder": 3, "status": "ACTIVE" },
|
||||||
|
{ "dictValue": "REGULAR", "dictLabel": "含(正餐)", "sortOrder": 4, "status": "ACTIVE" },
|
||||||
|
{ "dictValue": "SELF", "dictLabel": "自理", "sortOrder": 5, "status": "ACTIVE" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 下拉绑定动态数据
|
||||||
|
|
||||||
|
`n-popselect` 的 `:options` 改为从接口返回的数组映射(注意现有字典 store 可能已经封装好,可以复用):
|
||||||
|
|
||||||
|
```js
|
||||||
|
// 推荐:直接复用全局 dictStore(如果已有)
|
||||||
|
const mealOptions = computed(() =>
|
||||||
|
dictStore.getDictData('meal_option').map(d => ({
|
||||||
|
label: d.dictLabel,
|
||||||
|
value: d.dictValue
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
如果暂时没全局字典 store,组件级别 `onMounted` 拉一次即可(字典本身后端有 5 分钟 Redis 缓存,不会打到 DB)。
|
||||||
|
|
||||||
|
### 4. 校验逻辑无变化
|
||||||
|
|
||||||
|
`isSelf(value)` 仍然按 `value === 'SELF' || !value` 判断 — `SELF` 是业务语义的「自理」,前端这层判断不动。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 兼容性
|
||||||
|
|
||||||
|
- ✅ 历史数据(HOTEL/CAMP/SPECIAL/SELF)**全兼容**,已上线的产品数据无需迁移
|
||||||
|
- ✅ 字典服务挂掉时后端会 fallback 到 dictValue 字面值(订单详情不会显示空白)
|
||||||
|
- ✅ 字典本身有 Redis 5 分钟缓存,QPS 无压力
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 测试服验证记录
|
||||||
|
|
||||||
|
- 测试服 https://web.test.1814.love:9443 已部署 commit `b28cef1c7`(dev-v3)
|
||||||
|
- 字典查询接口返回 5 条数据 ✓
|
||||||
|
- 产品详情接口对 5 种 meal_option(HOTEL/CAMP/SPECIAL/REGULAR/SELF)全部返回正确 dictLabel ✓
|
||||||
|
- 无 token 调用返 `code: 401` ✓
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 联系人
|
||||||
|
|
||||||
|
后端:wx(呼籁旅行)
|
||||||
|
前端:mmg
|
||||||
|
|
||||||
|
如有疑问或字典接口路径需要确认,可在 [#2778](https://git.1814.love:8443/wx/HL/issues/2778) 评论区留言。
|
||||||
正在加载...
x
在新工单中引用
屏蔽一个用户