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

6.6 KiB
Raw Blame History

设计文档:/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 * 100c_lmt 为 0 或缺失则该柱记为无数据、不绘制)。

3.2 展示(分组柱状图)

  • x 轴按房间分组,每组 5 根柱(甲醛/TVOC/苯/甲苯/二甲苯,顺序同 POLLUTANTS。4 房间 = 20 柱;房间多时按容器宽度自动换行成多行(每行若干房间组)。
  • 柱高 = min(pct, CAP) / CAPCAP = 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单房间结果表仍用页面选择的标准保持现有行为