fix(hl-ui): 费用包含手动添加把"手动"塞进 feeType 导致 C 端显示成独立分类

CostDescPanel.vue:159 confirmIncludedAdd 硬编码 feeType:'手动',落库后 C 端
detail.js:428 把它当主标题渲染,在小程序产品详情显示成跟「景区/游玩项目」并列的
独立分类。改 feeType:null + 第 231 行 chip 加 v-if 即可。脏数据 1 条,产品
2056554654480248833 升级满洲里套娃酒店,建议运营 admin 自助删了重加。
纯前端 BUG,无后端接口/SQL/Nacos 改动,接收方 mmg。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
这个提交包含在:
API Changelog Bot 2026-05-19 15:09:58 +08:00
父节点 0bbcdd23e7
当前提交 c03a32b4ac

查看文件

@ -0,0 +1,158 @@
# hl-ui 费用包含: 手动添加项目误把"手动"塞进 feeType 导致 C 端显示成独立分类
> **仓库**: hl-ui (前端)
> **关联 PR/Issue**: (无,前端 BUG 不建工单)
> **日期**: 2026-05-19
> **影响范围**: admin 产品编辑「补充信息 → 费用说明 → 费用包含 → 添加项目」 + 小程序产品详情 C 端「费用包含」区块
> **接收方**: mmg (前端)
> **后端**: 无改动 (hl-product-service-v2 接口/VO/SQL 全部不动)
---
## ⚠️ 关键变化
**前端 `CostDescPanel.vue` 把字符串字面量 `"手动"` 硬编码塞进 `feeType` 字段,导致 C 端小程序把这条"手动添加"的费用项渲染成独立分类卡片"手动",和「景区/游玩项目/餐饮/交通」等自动推导的分类并列,严重混淆视听。改 `feeType: '手动'``feeType: null` 即可。**
---
## 一、现象
正式环境复现路径:
1. admin 产品编辑页 → 补充信息 → 费用说明 → **费用包含** → 点"添加项目" → 输入名称 `升级满洲里套娃酒店` → 保存
2. 打开小程序 C 端「产品详情」→ 滚到「费用包含」区块
3. 这条记录被渲染为:**主标题"手动" + 副标题"升级满洲里套娃酒店"**
用户 (wx) 原话:
> 这种"手动"作为分类名出现在 C 端不合理 — 手动加的也属于费用包含,不需要单独有"手动"分类,改。
预期:这条项目应该和其他自动推导项一样,主标题显示项目名称 `升级满洲里套娃酒店`,**不要有"手动"两字出现在用户可见区域**。
---
## 二、根因
文件: `src/views/product/edit/components/supplement/CostDescPanel.vue`
### 罪魁第 159 行
```js
// confirmAdd 处理"添加项目"弹窗的确认按钮
const confirmAdd = () => {
if (!addForm.value.name?.trim()) return
const name = addForm.value.name.trim()
const item = { feeType: '手动', name, sourceNodeName: '' } // ← 这里硬编码 "手动"
includedItems.value.push(item)
...
}
```
`feeType: '手动'` 这条数据通过 `PUT /admin/product-v2/{id}/supplement` 落到 `product_fee_item.fee_type = '手动'`
### C 端渲染逻辑放大问题
小程序 `packages/product/core/detail/detail.js:428` 渲染费用包含项的逻辑:
```js
// 简化版
const primary = feeType ? feeType : label // 有 feeType 时,把 feeType 作主标题
const secondary = feeType ? label : '' // 项目名降级作副标题
```
- 后端"自动推导"的 `feeType` 来源于资源类型:`景区 / 游玩项目 / 餐饮 / 交通` → 这些是合理的分类主标题。
- 但**手动添加**的项被前端塞了 `feeType="手动"`,走的是同一套逻辑,于是"手动"两个字就赫然摆在主标题位置,看起来像个独立分类。
### 顺带的 admin 侧问题 (第 231 行)
```vue
<div class="included-card__title">
<span class="included-card__type">{{ item.feeType }}</span> <!-- 第 231 行 -->
<span class="included-card__name">{{ item.name }}</span>
</div>
```
`<span class="included-card__type">` 是一个绿色小标签 chip,当 `feeType` 为 null 时会渲染成一个空白小绿块,影响 admin 卡片视觉。需要 `v-if` 跳过。
---
## 三、修复方案
### 改动 1 (必须):去掉硬编码 "手动"
**文件**: `src/views/product/edit/components/supplement/CostDescPanel.vue`
**位置**: 第 159 行 `confirmAdd` 函数内
```diff
- const item = { feeType: '手动', name, sourceNodeName: '' }
+ const item = { feeType: null, name, sourceNodeName: '' }
```
(或者更彻底,直接去掉 `feeType` 字段,JSON 序列化时不带这个 key,后端 VO 字段保持可空即可。两种写法效果等价,推荐 `feeType: null` 以显式表达"无分类"语义。)
### 改动 2 (必须):admin 卡片避免渲染空白 chip
**文件**: 同上
**位置**: 第 231 行模板
```diff
- <span class="included-card__type">{{ item.feeType }}</span>
+ <span v-if="item.feeType" class="included-card__type">{{ item.feeType }}</span>
```
### 改动 3 (可选,建议同步检查)
第 111 行附近 `confirmAdd` for **费用不含** 那一侧的添加逻辑当前是写 `type: 'OTHER'` 而不是 `feeType`,跟"费用包含"侧不是同一字段,C 端渲染也走的另一条路径,**目前看着没问题,可以不动**。但建议 mmg 顺手 grep 一下整个 hl-ui 项目里所有 `feeType:` 的硬编码字符串,确认没有其他类似的字面量泄漏到数据库。
### C 端是否需要同步改
不需要。C 端 `detail.js:428` 那段 `primary = feeType ? feeType : label` 的逻辑本身**是对的** — 当 `feeType` 真的有合法分类值 (景区/餐饮等) 时确实应该作主标题。问题在于**不该有"手动"这种非分类字符串混进 feeType**,所以从源头 (admin 前端) 修就够了。
---
## 四、部署后清理
mmg 前端发版到**正式环境**后,正式数据库有 1 条历史脏数据需要清理:
- **产品 ID**: `2056554654480248833`
- **脏记录**: `product_fee_item` 表中 `name = '升级满洲里套娃酒店' AND fee_type = '手动'` 这条 (sourceNodeName 为空)
- **清理方式**: 运营在 admin 产品编辑页 → 补充信息 → 费用说明 → 费用包含,**找到"升级满洲里套娃酒店"那张卡片,点删除,然后重新点"添加项目"再加一次即可**。新版前端会存 `feeType=null`,C 端就不会再显示"手动"主标题。
- **不需要后端 SQL 操作,运营自助即可完成**
如果运营嫌麻烦不愿意手动重操作,可以让后端 (wx) 跑一条 update:
```sql
UPDATE product_fee_item
SET fee_type = NULL
WHERE name = '升级满洲里套娃酒店' AND fee_type = '手动' AND product_id = 2056554654480248833;
```
但**建议优先走运营自助路径**,避免直接动正式 DB。
---
## 五、不需要后端配合
本次纯前端 BUG:
- ✅ 无后端接口签名/字段/类型变更
- ✅ 无 hl-product-service-v2 / hl-mp-service 代码改动
- ✅ 无 Flyway V*.sql 数据库迁移
- ✅ 无 Nacos 配置变更
- ✅ 无 gateway 路由调整
mmg 直接在 hl-ui 改完 3 行,本地 `npm run build` 后发版即可。
---
## 六、验证步骤 (mmg 自测)
发版到测试环境后,按以下步骤验证:
1. admin 测试环境登录,进入任意产品编辑页 → 补充信息 → 费用说明 → 费用包含
2. 点"添加项目",输入名称 (例如"测试手动项 xxx"),保存
3. 检查 Network 面板:`PUT /admin/product-v2/{id}/supplement` 请求 body 里这条新增项的 `feeType` 字段应为 `null` (或不存在该 key),**不是字符串 "手动"**
4. admin 页面回到查看模式,这张卡片左上角**不应有绿色"手动" chip**
5. 小程序对应产品的详情页「费用包含」区块,这条项**主标题应是项目名 (不是"手动")**
全部 OK 再发正式。