airpredict/空气质量预测/源码/docs/superpowers/specs/2026-07-07-source-charts-de...

114 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 设计文档:/source 污染源识别页 数据可视化
- 日期2026-07-07
- 目标项目:`C:\code\空气质量预测\源码\用户端\iapip-web`(纯前端,不涉及后端/数据库)
- 页面:`src/pages/source/index.tsx`(污染源识别 / 预测页)
- 状态:已通过需求评审,待写实现计划
---
## 1. 背景与目标
`/source` 现状:左侧单房间输入(预设样板间 + 面积/层高/温湿度/换气 + 材料勾选右侧结果为「5 项污染物浓度表」+「公式溯源·各材料贡献」(横向 CSS 条) +「整改建议」。预测走 `api.predict.space`(免认证),返回 `Space`:每污染物 `*_c` 浓度、`*_c_exceed` 超标、`materials[].*_cr` 贡献率、`is_*_ps` 污染源。当前**只预测选中的一个房间**。
本次新增两个可视化:
1. **全屋污染柱状图**一套住宅各房间、5 种污染物浓度**占 GB50325 限值的百分比**,每房间 5 根柱。
2. **材料贡献饼图**:某污染物下各材料贡献率用饼图 + 百分比展示,配色按占比从高到低 红→橙→黄→青→蓝(越低越淡越冷),替换现有横条。
---
## 2. 技术选择:纯 SVG/CSS 手写图表(不引图表库)
项目无任何图表库。决定**手写 SVG/CSS**,不安装 `@ant-design/plots` 等:
- npmmirror 装包在本环境不稳定,避免引入构建风险。
- 需要精确的配色(饼图按排名的红→冷渐变)与百分比柱,手写完全可控。
- 页面现有贡献率即 CSS 条,风格一致。
实现时先加载 `dataviz` 技能校准配色的可访问性与一致性。
---
## 3. 图 1全屋污染柱状图新增
### 3.1 数据
- 页面加载时,对 `PRESET_ROOMS`(当前 4 个:标准间/主卧/客厅/儿童房,组件按 N 个通用)**各跑一次** `api.predict.space`,并发执行,单个失败则跳过该房间。
- **固定使用 GB50325 限值**`standards` 中 id 含 `GB50325` 的那条),不受页面上方「限值标准」选择器影响。
- 每房间每污染物计算:`pct = c / c_lmt * 100``c_lmt` 为 0 或缺失则该柱记为无数据、不绘制)。
### 3.2 展示(分组柱状图)
- x 轴按**房间**分组,每组 **5 根柱**(甲醛/TVOC/苯/甲苯/二甲苯,顺序同 `POLLUTANTS`。4 房间 = 20 柱;房间多时按容器宽度**自动换行**成多行(每行若干房间组)。
- 柱高 = `min(pct, CAP) / CAP``CAP = 150`%)。柱顶标注实际百分比数值。
- 画一条 **100% 虚线基准线**
- 柱**按污染物着色**5 色分类调色板,图例:颜色 → 污染物);`pct >= 100`(超标)的柱额外加**红色描边 + 红色数值**以突出。
- 组下方标注房间名。
- 无任何房间预测成功时,整个图区显示占位文案「暂无全屋数据」,不报错。
### 3.3 位置
- 作为一张新 card放在右侧结果 `stack` 的**最顶部**(在「识别结论」表之上),标题「全屋污染概览 · 各房间占 GB50325 限值百分比」。
---
## 4. 图 2材料贡献饼图替换现有横条
### 4.1 数据
- 复用现有 `pol`(污染物切换)与 `ranked`(当前选中房间、该污染物下 `*_cr>0` 的材料,按贡献率降序,含 `isSrc`)。
- 饼图各扇区占比 = 该材料贡献率归一化(`ranked` 的 rate 之和作分母;后端 `cr` 之和可能略小于 1用其和归一以保证扇区闭合到 360°
### 4.2 展示
- SVG 饼图(各扇区用 `path` 弧或 `stroke-dasharray` 圆环),右侧/下方**百分比图例**:色块 + 材料名 + `(cr*100).toFixed(1)%`,污染源材料标注「(污染源)」。
- **配色(按 `ranked` 排名从高到低,越低越淡越冷)**,起始调色板(实现时经 dataviz 校准):
1.`#C0392B` 2. 橙 `#E67E22` 3. 黄 `#F1C40F` 4. 青 `#16A085` 5. 蓝 `#2980B9` 6. 浅蓝 `#5DADE2` 7+. 冷灰 `#AEB6BF`
超出 7 项时后续用更浅的冷灰循环递减。
- `ranked` 为空(该污染物无材料释放)时显示「该污染物无材料释放」占位(沿用现有文案)。
### 4.3 位置
- 替换「公式溯源·各材料贡献」card 内的横条 `contrib` 区,保留该 card 标题与污染物切换 `pol-seg`
---
## 5. 组件拆分
- `src/pages/source/RoomBarChart.tsx` — 输入 `{ rooms: { name: string; pct: (number|null)[] }[], pollutantLabels: string[], colors: string[] }`,渲染分组柱状图(含 100% 线、换行、超标高亮)。纯展示,无数据请求。
- `src/pages/source/ContribPie.tsx` — 输入 `{ items: { name: string; rate: number; isSrc: boolean }[] }`,渲染饼图 + 图例(内部按序取配色)。纯展示。
- `src/pages/source/index.tsx` — 新增「加载时并发预测全屋」逻辑与状态 `homeStats`,组织两个子组件;替换 `contrib` 区为 `<ContribPie>`
- `src/pages/source/source.css` — 新增柱状图/饼图相关样式类。
---
## 6. 数据流与错误处理
- 全屋预测:`Promise.allSettled` 并发 4 次 `api.predict.space`(各房间的 `buildPayload` 用其预设面积/材料/温湿度 + GB50325 限值);仅保留 fulfilled 的房间。
- GB50325 标准若在 `standards` 中不存在:柱状图整体显示占位、不报错(其余页面功能不受影响)。
- 饼图:贡献率和为 0 时显示占位。
- 全程无新增网络失败提示(沿用页面「静默」策略)。
---
## 7. 测试
- **类型检查**`npx tsc --noEmit -p tsconfig.json` 新增文件零错误(仅剩既有 2 条 eslint 类型根告警)。
- **浏览器**(登录后 `#/source`
- 顶部出现「全屋污染概览」柱状图4 房间 × 5 柱柱顶百分比、100% 基准线;某柱超 100% 时标红。
- 「各材料贡献」显示为饼图 + 百分比图例;切换污染物(甲醛/TVOC/…)饼图与配色随之更新;占比最高扇区为红、依次转橙黄青蓝、越低越淡冷。
- 编辑单房间输入不影响顶部全屋概览(概览为加载时的预设快照)。
- 控制台无报错GB50325 缺失或某房间预测失败时页面不崩。
---
## 8. 涉及文件清单
- 新建:`src/pages/source/RoomBarChart.tsx`
- 新建:`src/pages/source/ContribPie.tsx`
- 修改:`src/pages/source/index.tsx`(全屋并发预测 + 组织图表 + 替换 contrib
- 修改:`src/pages/source/source.css`(图表样式)
---
## 9. 范围与非目标
- 不改后端、不改预测算法、不改数据库。
- 全屋柱状图为**加载时的预设快照**不随单房间编辑实时联动YAGNI如需联动为后续增强
- 不引入任何图表/绘图第三方库。
- 柱状图固定 GB50325单房间结果表仍用页面选择的标准保持现有行为