6.6 KiB
6.6 KiB
设计文档:/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 污染源。当前只预测选中的一个房间。
本次新增两个可视化:
- 全屋污染柱状图:一套住宅各房间、5 种污染物浓度占 GB50325 限值的百分比,每房间 5 根柱。
- 材料贡献饼图:某污染物下各材料贡献率用饼图 + 百分比展示,配色按占比从高到低 红→橙→黄→青→蓝(越低越淡越冷),替换现有横条。
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 校准):- 红
#C0392B2. 橙#E67E223. 黄#F1C40F4. 青#16A0855. 蓝#2980B96. 浅蓝#5DADE27+. 冷灰#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;单房间结果表仍用页面选择的标准(保持现有行为)。