# 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: '其他'`,**一行字面量改动,其他都不动**。**

---

## 一、现象

正式环境复现路径:

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="手动"`,走的是同一套逻辑,于是"手动"两个字就赫然摆在主标题位置,看起来像个独立分类。


---

## 三、修复方案(用户最终决策:**只改这一行,其他都不动**)

### 唯一改动:把硬编码的 "手动" 改成 "其他"

**文件**: `src/views/product/edit/components/supplement/CostDescPanel.vue`
**位置**: 第 159 行 `confirmIncludedAdd` 函数内

```diff
- const item = { feeType: '手动', name, sourceNodeName: '' }
+ const item = { feeType: '其他', name, sourceNodeName: '' }
```

效果:运营手动添加的费用项,C 端主标题显示"其他",和「景区/游玩项目/餐饮/交通」等并列,作为一个合理的"杂项"分类,语义清晰。admin 卡片左上角绿色 chip 显示"其他",也是正常态。

### 用户明确不要的改动(不要做)

- ❌ 不要把 `feeType` 改成 `null` (用户原话:"手动改为其他 不需要改了")
- ❌ 不要给 admin 卡片 chip 加 `v-if` (因为新值"其他"是合法值,需要正常显示)
- ❌ 不要全局 grep 排查其他 `feeType:` 硬编码 (用户判断没必要)
- ❌ 不要动 C 端 `detail.js`
- ❌ 不要动后端任何代码 (不需要加 feeType 枚举校验)

### 一行改动即可,无后续连锁修改

---

## 四、部署后清理

mmg 前端发版到**正式环境**后,正式数据库有 1 条历史脏数据需要清理:

- **产品 ID**: `2056554654480248833`
- **脏记录**: `product_fee_item` 表中 `name = '升级满洲里套娃酒店' AND fee_type = '手动'`
- **清理方式 A (推荐)**: 运营在 admin 产品编辑页 → 补充信息 → 费用说明 → 费用包含,**找到"升级满洲里套娃酒店"那张卡片,点删除,然后重新点"添加项目"再加一次**。新版前端会存 `feeType='其他'`,C 端主标题就变成"其他",不再是"手动"。
- **清理方式 B (兜底,wx 自行决定是否动正式 DB)**:

```sql
UPDATE product_fee_item
SET fee_type = '其他'
WHERE name = '升级满洲里套娃酒店' AND fee_type = '手动' AND product_id = 2056554654480248833;
```

---

## 五、不需要后端配合

本次纯前端 BUG:

- ✅ 无后端接口签名/字段/类型变更
- ✅ 无 hl-product-service-v2 / hl-mp-service 代码改动
- ✅ 无 Flyway V*.sql 数据库迁移
- ✅ 无 Nacos 配置变更
- ✅ 无 gateway 路由调整

mmg 直接在 hl-ui 改完 1 行(L159 `'手动'` → `'其他'`),本地 `npm run build` 后发版即可。

---

## 六、验证步骤 (mmg 自测)

发版到测试环境后,按以下步骤验证:

1. admin 测试环境登录,进入任意产品编辑页 → 补充信息 → 费用说明 → 费用包含
2. 点"添加项目",输入名称 (例如"测试其他项 xxx"),保存
3. 检查 Network 面板:请求 body 里这条新增项的 `feeType` 字段应为 `"其他"`,**不是 `"手动"`**
4. admin 页面回到查看模式,这张卡片左上角绿色 chip 应显示 **"其他"**(不是"手动",也不是空白)
5. 小程序对应产品的详情页「费用包含」区块,这条项**主标题应显示"其他"**(副标题是项目名)

全部 OK 再发正式。
