| 项 | 内容 |
|---|---|
| 功能名称 | 座椅通风 / 加热(在空调温控面板内扩展) |
| 所属模块 | Robotaxi 接驾界面(begin-route / 行程开始页) |
| 目标分支 | rt/feature/v2.0_ui_xj_730 |
| 文档状态 | 概要设计(需求已对齐,待评审后进入编码) |
| 关联能力 | 空调温控(temperature-control.tsx)—— 复用其 setTemperature / airConditionerUnlock 及温度区间/防抖逻辑 |
| 参照文档 | docs/车载香氛系统概要设计.md(同一套接驾态远控范式) |
Robotaxi 接驾阶段(TripStatus.VehicleApproaching)已支持空调温控、车门/后备箱、车载香氛远控。本次在**空调能力基础上扩展座椅通风 / 加热**:
采用**方案 A**:重构空调卡片为「展示态 + 面板」,温控迁入面板(滚动温度选择器 + 面板内开关),座椅区位于面板顶部。空调下发逻辑**复用现有接口**。
┌─────────────┬─────────────┐
│ ❄ 空调 [开关]│ 智能香氛 │
│ 23.5 度 │ (右卡片) │
│ 调节温度|通风加热 │ │
└─────────────┴─────────────┘
┌───────────────────────────────┐
│ 温度调节 [ × ]│ ← 顶部:标题居中 + 关闭
├───────────────────────────────┤
│ [车内俯视图 · 座椅区] │
│ ┌──────────┐ ┌──────────┐ │
│ │第二排左侧座椅 │ │第二排右侧座椅 │ │
│ │ ❋通风 ⌇加热 │ │ ❋通风 ⌇加热 │ │ ← 每座椅两个档位按钮
│ └──────────┘ └──────────┘ │
├───────────────────────────────┤
│ 空调 │
│ …23.5 [24]℃ 24.5… │ ← 横向温度滚动选择器
│ ——● 空调开关 │ ← 面板内空调开关
└───────────────────────────────┘
面板自上而下分两区:
1. 座椅区(本次新增):车内俯视图 + 按接口返回渲染的座椅,每座椅含「通风」「加热」两个档位按钮
2. 空调区(迁移自现有卡片):横向温度滚动选择器 + 空调开关
seats 数组渲染,兼容二排 / 三排(position 决定座位标签文案)ventilationLevels === 0 → 该座椅**通风按钮置灰/不可点**(如三排不支持通风),仅保留加热按钮heatingLevels === 0 → 加热按钮置灰/不可点档位循环:点击按钮在 0 → 1 → 2 → … → N → 0 间循环,上限 N 由该座椅对应的 ventilationLevels / heatingLevels 决定(0 = 关)。
- 例:ventilationLevels=3 → 循环 0→1→2→3→0
- 例:heatingLevels=2 → 循环 0→1→2→0
互斥规则:同一座椅通风与加热不能同时开启。
- 用户将**通风**调到非 0 档 → 该座椅**加热自动回退至 0**
- 反之,将**加热**调到非 0 档 → 该座椅**通风自动回退至 0**
即时下发(对齐香氛,无独立"应用"按钮):
1. 点击某座椅的通风/加热按钮 → 计算该座椅下一档位 + 互斥联动
2. 仅下发该被改动的座椅,ventilationLevel 与 heatingLevel 一起下发
3. 下发期间该座椅按钮置灰防重复点击
4. 成功:按钮档位更新,Toast 提示(文案见 §8)
5. 失败:该座椅状态回滚到下发前,Toast「网络异常,请重试」,面板保持
15.5 ~ 32.5℃、步进 0.5,**复用现有 setTemperature + 防抖(500ms)**airConditionerUnlocktemperature-control 实现**,本次不改其接口契约服务域 vehicleConvoy,路径前缀 _ROBOTAXI_HOST,段为 base(vehicleConvoy/base/v1/...)。鉴权:needLogin=true、needSign=false(对齐香氛/空调)。
响应遵循项目统一两层结构(见
src/utils/request.ts):{ code, msg, data },code===CODE_SUCCESS视为成功,request默认解包返回第二层data。
GET /vehicleConvoy/base/v1/mini-program/cabin/seat/hv?orderId={orderId}
请求参数(query):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| orderId | string | 是 | 订单 ID |
响应示例:
{
"code": 200,
"msg": null,
"data": {
"seats": [
{ "position": "SECOND_ROW_LEFT", "ventilation": 1, "ventilationLevels": 3, "heating": 0, "heatingLevels": 3 },
{ "position": "SECOND_ROW_RIGHT", "ventilation": 0, "ventilationLevels": 3, "heating": 3, "heatingLevels": 3 },
{ "position": "THIRD_ROW_LEFT", "ventilation": 0, "ventilationLevels": 0, "heating": 0, "heatingLevels": 3 },
{ "position": "THIRD_ROW_RIGHT", "ventilation": 0, "ventilationLevels": 0, "heating": 0, "heatingLevels": 3 }
]
}
}
data.seats[] 字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
| position | string | 座位标识:SECOND_ROW_LEFT / SECOND_ROW_RIGHT(目前仅支持二排,前端兼容三排 THIRD_ROW_*) |
| ventilation | int | 通风当前档位 0~3,0=关 |
| ventilationLevels | int | 通风支持的总档数(如 3 即可设 0~3);0 表示不支持通风 |
| heating | int | 加热当前档位 0~3,0=关 |
| heatingLevels | int | 加热支持的总档数(如 3 即可设 0~3);0 表示不支持加热 |
POST /vehicleConvoy/base/v1/mini-program/cabin/seat/hv
请求体:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| orderId | string/number | 是 | 订单 ID |
| seats | SeatSet[] | 是 | 本次改动的座椅集合(**仅传被改动座椅**) |
| SeatSet.position | string | 是 | 座位标识 |
| SeatSet.ventilationLevel | int | 是 | 目标通风档位 0~N |
| SeatSet.heatingLevel | int | 是 | 目标加热档位 0~N(互斥:与 ventilationLevel 至多一个非 0) |
请求示例(仅下发改动的座椅,通风与加热一起下发):
{
"orderId": 123456,
"seats": [
{ "position": "SECOND_ROW_LEFT", "ventilationLevel": 2, "heatingLevel": 0 },
{ "position": "THIRD_ROW_RIGHT", "ventilationLevel": 0, "heatingLevel": 3 }
]
}
响应示例:
{ "code": 200, "msg": null, "data": null }
成功判定:code===CODE_SUCCESS 即视为下发成功,data 可为 null。
进入接驾态 (VehicleApproaching)
│
├─ 查询座椅状态 GET .../cabin/seat/hv(面板打开时或进入接驾态时)
│ ├─ 成功 → 渲染座椅区,按 levels 决定档位上限与按钮可用性
│ └─ 失败 → 座椅区兜底(见 8)
├─ 空调温度/开关:沿用现有 temperature-control 初始化
│
用户点击「空调」卡片(主体) → 打开「温度调节」面板
│
用户点击某座椅的 通风/加热 按钮:
│
├─ 计算下一档位:curr → (curr+1) % (levels+1)
├─ 互斥联动:通风非0 ⇒ 加热=0;加热非0 ⇒ 通风=0
├─ 该座椅按钮置灰防重复
├─ POST .../cabin/seat/hv
│ payload: { orderId, seats: [{ position, ventilationLevel, heatingLevel }] }
│
├─ 成功 → 该座椅档位更新 + Toast
└─ 失败 → 该座椅状态回滚 + Toast"网络异常,请重试";面板保持
│
(空调温度/开关:复用现有下发逻辑,防抖 500ms)
| 接口字段 | 通风按钮 | 加热按钮 |
|---|---|---|
| ventilationLevels>0 & heatingLevels>0 | 可点,循环 0~V | 可点,循环 0~H |
| ventilationLevels=0 | 置灰/隐藏 | 可点 |
| heatingLevels=0 | 可点 | 置灰/隐藏 |
| seats 为空 | 座椅区占位提示(见 8) | — |
通风:0 → 1 → 2 → … → V → 0 (V = ventilationLevels)
加热:0 → 1 → 2 → … → H → 0 (H = heatingLevels)
| 用户操作 | 联动结果 | 下发 payload(该座椅) |
|---|---|---|
| 通风 0→非0 | 加热强制 0 | { ventilationLevel: n, heatingLevel: 0 } |
| 加热 0→非0 | 通风强制 0 | { ventilationLevel: 0, heatingLevel: n } |
| 通风 →0(关) | 加热保持 0 | { ventilationLevel: 0, heatingLevel: 0 } |
| 加热 →0(关) | 通风保持 0 | { ventilationLevel: 0, heatingLevel: 0 } |
[座椅按钮] --点击--> [该座椅 applying(置灰,禁点)]
│
┌─────────┴─────────┐
成功 失败
│ │
档位更新 + Toast 该座椅状态回滚 + Toast"网络异常,请重试"
(面板保持) (面板保持)
方案 A:新建独立座椅组件,空调卡片改造为「展示 + 面板」。座椅与空调温控同处「温度调节」面板。
src/robotaxi/pages/begin-route/components/calling-car-modules/
├── temperature-control.tsx (改造:卡片展示态 + 卡片开关 + 打开面板)
├── climate-panel/ (新增:温度调节面板容器,可选)
│ └── index.tsx 面板:座椅区 + 空调温度选择器 + 开关
├── seat-hv-control/ (新增:座椅通风加热)
│ └── index.tsx 座椅区渲染 + 档位循环 + 互斥 + 即时下发
└── ...
src/robotaxi/pages/begin-route/components/css-folder/
├── climate-panel.less (新增)
└── seat-hv-control.less (新增)
面板容器
climate-panel是否单独拆分可在编码时按复杂度决定;核心是座椅逻辑独立在seat-hv-control。
| 组件/文件 | 职责 |
|---|---|
TemperatureControl(改造) |
卡片展示当前温度 + 卡片空调开关 + 点击打开面板;温度/开关下发逻辑复用现有 |
| 「温度调节」面板 | 承载座椅区 + 空调温度滚动选择器 + 面板内开关;底部弹窗动画复用 use-bottom-popup-animation |
SeatHvControl(新增) |
查询座椅状态、渲染座椅、档位循环、互斥联动、点击即时下发(仅改动座椅) |
use-bottom-popup-animation |
复用现有底部弹窗滑入/滑出动画 |
type Props = {
tripStatus: TripStatus; // 仅 VehicleApproaching 展示
orderId?: string;
pageDidShowVersion?: number; // 页面 didShow 版本,触发重查
hasPreviousOrder?: boolean; // 连环单时不展示/不下发
}
新增 src/robotaxi/api/seat-hv.ts:
querySeatHv(orderId) // GET .../cabin/seat/hv
setSeatHv(payload) // POST .../cabin/seat/hv(seats 仅含改动座椅)
类型新增 src/robotaxi/api/types/seat-hv.ts:SeatHvItem、QuerySeatHvResponse、SetSeatHvPayload、SeatSetItem、SeatPosition。
position 映射:SECOND_ROW_LEFT→「第二排左侧座椅」等沿用项目 xpReport(this.$app.xpReportSend({ pageId, buttonId, para })),接驾页 pageId 沿用 begin-route 现有值,buttonId 待与埋点侧确认,建议:
| 事件 | 时机 | 建议 para |
|---|---|---|
| 打开温度调节面板 | 点击空调卡片 | {} |
| 座椅通风点击下发 | 点击通风按钮 | { position, ventilationLevel } |
| 座椅加热点击下发 | 点击加热按钮 | { position, heatingLevel } |
| 座椅下发结果 | 成功/失败回调 | { position, ventilationLevel, heatingLevel, success } |
空调温度/开关埋点沿用现有实现,不在本次新增范围。
| 场景 | 处理 |
|---|---|
| 查询座椅状态失败 | 座椅区兜底:展示占位提示(如「座椅调节暂不可用」)或空态;不阻塞空调温控 |
| seats 为空 | 座椅区展示占位提示,不渲染座椅按钮 |
| ventilationLevels=0 | 该座椅通风按钮置灰/隐藏,仅保留加热 |
| heatingLevels=0 | 该座椅加热按钮置灰/隐藏,仅保留通风 |
| 下发接口失败/超时 | 该座椅状态回滚到下发前 + Toast「网络异常,请重试」+ 面板保持 |
| 下发进行中重复点击 | 该座椅 applying 期间按钮置灰禁点,防重复下发 |
| 连环单(hasPreviousOrder=true) | 空调卡片与座椅区均不展示/不查询/不下发(对齐空调,避免影响上一单乘客) |
| 非接驾态(tripStatus≠VehicleApproaching) | 组件返回 null,不展示 |
| 面板打开期间订单切换 | 按 orderId 重新查询并刷新状态,避免串单 |
| 文件 | 类型 | 说明 | 落地 |
|---|---|---|---|
src/robotaxi/api/seat-hv.ts |
新增 | querySeatHv / setSeatHv |
✅ |
src/robotaxi/api/types/seat-hv.ts |
新增 | 座椅通风加热请求/响应类型 | ✅ |
.../calling-car-modules/seat-hv-control/index.tsx |
新增 | 入口 + 座椅面板 + 档位循环 + 互斥 + 即时下发 | ✅ |
.../css-folder/seat-hv-control.less |
新增 | 座椅区样式(俯视图 + 按钮) | ✅ |
.../components/calling-car.tsx |
改 | 挂载 <SeatHvControl />(空调卡片下方) |
✅ |
本期实现说明:座椅通风加热作为**独立组件
SeatHvControl** 落地(含自带入口 + 底部弹窗面板),未改动已上线的temperature-control.tsx,降低回归风险。温度选择器/空调开关合并进「温度调节」面板(方案 A 完整形态)作为**后续迭代**,待设计切图到位后再合并;当前空调仍沿用现有内联卡片,座椅入口以独立一行挂在其下。
ventilationLevels=0 通风置灰/隐藏仅留加热。0→1→…→N→0,上限 N 由该座椅 ventilationLevels/heatingLevels 决定。seats 数组含该座椅 ventilation+heating 两字段)。setTemperature / airConditionerUnlock 及温区/防抖逻辑。needLogin=true、needSign=false。