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
在新工单中引用
屏蔽一个用户