16 KiB
广寒基地时态拓扑页面适配审计报告
日期:2026-07-09
测试目标:
http://localhost:8080/guanghan_topology_demo.html?mission=GHC-01
审计范围:
- 页面初始加载和默认快照;
- 全部 9 个任务选项;
- 明确时间查询、任务与时间并存、基地建立前时间点;
- 无效时间、不存在任务、API 异常呈现;
- 浏览器回退与 URL 状态一致性;
- GHC-05 全部 14 个可视节点的详情弹窗;
- 鼠标、键盘、关闭按钮、遮罩和 Escape 交互;
- 1440×1000 桌面视图与 390×844 窄屏视图;
- API 响应、数据库任务事件、布局数据;
- 既有自动化回归测试;
- 页面、API、种子数据和近期改动的根因检查。
本轮只检查、截图和出具报告,没有修改页面、API、数据库或测试代码。
1. 总结结论
当前版本不建议确认完成或发布。
它已经具备可工作的基本链路:页面能从 API 取得数据,9 个任务均可查询,GHC-05 最终拓扑的空间骨架基本正确,14 个可视节点均能打开详情弹窗,弹窗在桌面和窄屏下都可用。
但适配仍存在发布阻断问题:
- 页面并未真正由数据库拓扑和布局驱动,仍是固定 SVG 加少量显隐逻辑;
- 历史任务会显示不存在的悬空连接线,散热器在基地不存在时仍出现;
- 5 个任务的“最后一条任务记录时间”与 Timeline 不一致;
- GHC-05 图中文字大面积越界,严重影响工程总图可读性;
- 页面写死
localhost:5000,部署到真正 Wiki 后,其他访问者会请求自己电脑的 localhost; - 无效时间导致 API 返回 HTML 500,页面显示 JSON 解析错误;
- 自动化回归测试 8 项中有 4 项失败;
- 后端配置文件包含已提交的明文默认数据库凭据。
2. 测试结果概览
| 测试项 | 结果 | 说明 |
|---|---|---|
| API 健康检查 | 通过 | /health 返回 200 |
| 无参数默认快照 | 部分通过 | 页面能显示最新数据,但数据库“最新事件”本身不完整 |
| 9 个任务逐项查询 | 接口通过、呈现部分失败 | 全部返回数据并截图;早期任务拓扑线和散热器错误 |
| 明确时间优先 | 部分通过 | 时间生效,但任务上下文从 API 请求和副标题中丢失 |
| 基地建立前时间 | 部分通过 | 组件和连接为空,但 4 个散热器仍显示 |
| 无效时间 | 失败 | API 500 HTML;页面显示 Unexpected token '<' |
| 不存在任务 | 基本通过 | 404 能显示,但下拉框丢失请求值,错误文案为英文 |
| 浏览器回退 | 失败 | URL 回到 GHC-01,页面仍显示 GHC-05 |
| 14 个节点点击弹窗 | 通过 | 全部能打开和关闭 |
| Enter / Space 打开弹窗 | 通过 | 两种键盘操作均有效 |
| × / 遮罩 / Escape 关闭 | 通过 | 三种方式均有效 |
| 关闭后焦点恢复 | 失败 | 焦点落到 BODY,未返回触发节点 |
| 390×844 页面布局 | 部分通过 | 页面本身无横向溢出,地图可横向滚动;图中文字仍越界 |
| 390×844 弹窗 | 通过 | 弹窗完整落在视口内 |
| 既有自动化测试 | 失败 | 8 项中 4 项失败 |
3. 全部任务测试
所有任务都通过页面下拉框和“查询”按钮实际执行,并分别截图。
| 任务 | API 快照时间(页面显示,UTC+8) | 组件数 | API 连接数 | 页面结果 | 截图 |
|---|---|---|---|---|---|
| BL-01 | 2024-04-20 06:58 | 1 | 0 | 失败:仍显示一条供电/燃料线;4 个散热器始终存在 | 截图 |
| GHC-01 | 2024-06-16 15:23 | 2 | 0 | 失败:核心舱四条结构线悬空,冰轮线悬空 | 截图 |
| JC-01 | 2024-06-17 16:19 | 2 | 0 | 失败:与 GHC-01 相同 | 截图 |
| BL-02 | 2024-06-23 13:23 | 3 | 0 | 失败:显示 6 条并不存在的固定线 | 截图 |
| GHC-02 | 2024-07-01 18:37 | 3 | 1 | 失败:页面固定线不能表达 API 中实际的冰轮连接 | 截图 |
| GHC-03 | 2024-08-19 08:00 | 9 | 7 | 失败:显示核心舱未来安装口悬空线和不存在的电力东侧线 | 截图 |
| BL-03 | 2024-09-24 03:20 | 10 | 7 | 失败:固定线仍多于该时刻实际拓扑 | 截图 |
| GHC-04 | 2024-11-08 08:00 | 12 | 14 | 部分通过:主要电力拓扑可见,但固定图不能忠实反映连接记录 | 截图 |
| GHC-05 | 2025-01-02 08:00 | 17 | 19 | 空间骨架基本正确;文字越界、信息缺失和时间锚点错误 | 截图 |
说明:17 个数据库组件被合并成 14 个可视节点,电力模块东、西两组分别使用组合节点。这种组合可以保留,但组合关系目前硬编码在页面中。
4. 发布阻断问题
P0-1 页面没有真正使用数据库拓扑和布局
表现:
- API 返回
layout,页面没有读取currentData.layout; - SVG 节点、连接线和散热器全部写死在 HTML 中;
- 任务列表也由
loadMissions()返回固定数组; - 数据库新增模块、连接或未来十字结构后,页面不会自动出现;
- 数据库 17 个组件只能依赖页面中的
GROUP_MEMBERS硬编码压成 14 个节点。
证据:
data/wiki/guanghan_topology_demo.html:258写死 API 地址;data/wiki/guanghan_topology_demo.html:282写死任务列表;data/wiki/guanghan_topology_demo.html:301仅对固定节点执行显隐;- 页面没有任何
currentData.layout使用点; topology_api/queries/snapshot_queries.py已返回布局,但前端丢弃。
根因:
这次改动保留了原始静态 SVG,只将部分文字和显隐状态接到了 API。它不是“从数据库渲染拓扑”,而是“数据库数据覆盖固定模板”。
影响:
- 无法满足未来扩建;
- 无法保证任意历史快照准确;
- 数据库和页面会持续形成两套事实来源。
P0-2 正式 Wiki 部署后 API 地址不可用
页面写死:
const API_BASE = 'http://localhost:5000';
在当前开发机上可以工作,但真正的 Wiki 访问者打开页面后,浏览器会请求访问者自己电脑的 localhost:5000,而不是服务器。
根因:
缺少同源反向代理路径或部署时可注入的 API 基址。
影响:
除开发机外,页面大概率完全无法加载。
P0-3 后端源码包含明文默认数据库凭据
topology_api/config.py 在环境变量缺失时使用硬编码用户名和密码,并已进入 Git 历史。
报告中不重复凭据内容。
影响:
- 凭据泄露;
- 环境变量遗漏时会静默连接真实数据库;
- 后续即使删除源码中的字符串,Git 历史仍保留旧值。
需要在修复阶段先轮换凭据,再移除默认密码并检查 Git 历史处置方案。
5. 高优先级功能问题
P1-1 历史拓扑连接线不可信
页面没有根据 currentData.connections 画线,而是给固定线配置粗粒度的组件依赖:
const connTypes = {
'core-structural': ['core_cabin'],
...
};
随后使用“任意一个依赖组件存在即可显示”:
needed.some(k => existing.has(k))
因此:
- GHC-01 只有核心舱和冰轮一号、API 连接数为 0,但页面显示核心舱四条悬空线和冰轮线;
- 基地建立前 0 组件时,4 个散热器仍显示;
- GHC-03 电力东部模块尚不存在,东侧结构线仍显示。
相关截图:
P1-2 任务默认时间不符合已确认规则
已确认规则是:仅传任务编号时,采用该任务最后一条记录的时间。
数据库目前只录入少量拓扑变化事件,导致 5 个任务的最大事件时间早于 Timeline 中最后一条任务记录。
下表均以 Timeline 原始时间(UTC)比较:
| 任务 | 数据库最后事件 | Timeline 最后记录 | 结果 |
|---|---|---|---|
| BL-01 | 2024-04-19 22:58 | 2024-05-17 23:01 | 错误 |
| GHC-01 | 2024-06-16 07:23 | 2024-06-16 07:23 | 正确 |
| JC-01 | 2024-06-17 08:19 | 2024-06-17 08:19 | 正确 |
| BL-02 | 2024-06-23 05:23 | 2024-06-23 05:23 | 正确 |
| GHC-02 | 2024-07-01 10:37 | 2024-07-15 03:16 | 错误 |
| GHC-03 | 2024-08-19 00:00 | 2024-08-30 12:45 | 错误 |
| BL-03 | 2024-09-23 19:20 | 2024-09-23 19:20 | 正确 |
| GHC-04 | 2024-11-08 00:00 | 2024-11-20 13:57 | 错误 |
| GHC-05 | 2025-01-02 00:00 | 2025-01-22 10:52 | 错误 |
根因:
种子数据将 mission_events 当成“拓扑变化事件”,但查询规则将其当成“完整任务时间线”。两种语义冲突。
P1-3 GHC-05 图中文字严重越界
updateNodeLabels() 将数据库中的长摘要直接写入固定大小 SVG <text>,没有截断、换行或 foreignObject 布局。
同时它把原本的安装位置说明替换成泛化类型,如“舱段模块”“设备模块”,使工程图信息反而减少。
核心舱和北部模块仍残留“加载中...”占位文本。
截图:
P1-4 同时提供任务和时间时,页面丢失任务上下文
页面 URL 正确保留:
?mission=GHC-01&at=2025-01-02T08:00:00+08:00
但 fetchSnapshot() 使用:
if (at) ...
else if (mission) ...
所以 API 请求只携带 at,没有携带 mission。最终副标题显示“(最新)”,而不是保留 GHC-01 上下文。
API 本身在同时收到两个参数时行为正确,缺陷位于页面请求组装。
截图:任务与时间并存
P1-5 浏览器回退后 URL 与页面状态不一致
页面查询时调用 history.pushState(),但没有监听 popstate。
复现:
- 查询 GHC-01;
- 查询 GHC-05;
- 浏览器后退;
- URL 已回到
mission=GHC-01; - 下拉框、副标题和拓扑仍是 GHC-05。
截图:浏览器回退错位
P1-6 无效时间产生 500 和技术性错误文案
输入 not-a-time 后:
- API 将原字符串直接送入 PostgreSQL
timestamptz强制转换; - PostgreSQL 抛错;
- Flask 返回 HTML 500;
- 页面对错误响应强制执行
res.json(); - 用户看到
Unexpected token '<'; - 旧副标题仍保留,形成新旧状态混杂。
截图:无效时间错误
P1-7 “任务节点”字段并不是任务信息
弹窗中的“任务节点”实际显示 detailUrl:
详见 Wiki: /home/Spacecraft/...
没有链接时显示“资料未记录”。
API 没有返回组件引入任务、最后状态任务或生效事件,因此页面无法正确展示任务节点。
P1-8 模块尺寸和详情数据不完整
GHC-05 的 17 个组件中:
- 只有居住舱一号、居住舱二号、温室舱和实验舱具有完整几何尺寸;
- 核心舱只有质量,没有长宽高;
- 其余 12 个组件的
dimensions为空; - 多个电力设备只有一句摘要,没有描述和规格;
- 电力东、西组合弹窗以第一个成员作为标题、位置和状态,其他成员只被拼进“关键参数”。
全部 14 个可视节点的弹窗操作都成功,但信息完整性未达到“模块状态、模块信息等均从数据库读取并完整呈现”的目标。
代表截图:
P1-9 冰轮连接端口数据与空间位置冲突
视觉图将冰轮一号、二号、三号分别放在电力模块西、南、东。
但数据库中的 6 条燃料/供电连接全部指向:
power_module_hub.west
这使弹窗连接数据与工程图位置矛盾。至少冰轮二号、三号应分别核对南、东端口语义。
6. 中优先级问题
P2-1 任务下拉框不是数据库数据
loadMissions() 返回固定任务数组。数据库新增任务后页面不会出现,删除或更名也不会同步。
需要任务列表 API,或在快照 API 中返回可选任务。
P2-2 自动化测试与适配代码不同步
执行:
python -m unittest tests.test_guanghan_topology_demo tests.test_guanghan_topology_e2e -v
结果:
Ran 8 tests
FAILED (failures=4)
失败项:
- 加压走道连接契约;
- 每个可点击模块的尺寸字段契约;
- 未来扩展锚点注释;
- 渲染和弹窗 E2E。
部分失败是适配后没有同步测试,部分对应真实回归:
- 原来要求保留的
FUTURE_EXPANSION_ANCHOR:north/east/west注释已被删除; - 新 E2E 没有启动或模拟拓扑 API;
- 测试仍检查旧
data-connection契约。
此外,当前没有 API 查询、时间优先级、数据库约束和 9 个任务快照的自动化测试。
P2-3 详情弹窗关闭后不恢复焦点
Enter 和 Space 可以打开弹窗,Escape 可以关闭;但关闭后焦点落在 BODY,没有返回原节点。
这会影响键盘连续浏览和无障碍体验。
窄屏证据:
P2-4 时间显示依赖访问者本地时区
页面使用 toLocaleString('zh-CN'),没有固定时区或显示 UTC 偏移。不同地区的访问者可能看到不同日期和时间。
P2-5 页面显示内部枚举值
页面直接显示:
mission_latest_event
latest_recorded_state
explicit_time
这些是 API 内部值,不适合作为最终 Wiki 文案。
P2-6 数据库内容进入 innerHTML 时未转义
尺寸、关键参数和连接关系通过模板字符串写入 innerHTML。当前种子数据可信,但未来如果后台编辑内容含 HTML,会形成存储型脚本注入风险。
7. 已确认通过的部分
以下部分不应在修复时无故推翻:
- GHC-05 核心舱十字结构与电力模块十字结构的整体空间关系;
- 两条加压走道为绿色实线;
- 四组散热器的视觉样式和文字标注;
- 14 个可视节点均可点击;
- 弹窗 ×、遮罩和 Escape 关闭;
- 节点 Enter / Space 键打开弹窗;
- 窄屏弹窗尺寸和内部信息布局;
- API 的明确时间优先规则;
- API 的未知基地 404 和未知任务 404;
- 无参数查询采用数据库内已发生任务的最大事件时间这一查询逻辑。
最后一项的查询代码逻辑正确,但种子事件不完整,所以实际得到的“最新时间”仍错误。
8. 建议修复边界
如果本报告获确认,建议按以下顺序实施:
- 先处理凭据轮换与部署 API 地址;
- 为页面/API/数据库补充失败测试,固定已确认语义;
- 补齐任务末条事件或拆分“拓扑事件”和“任务时间锚点”;
- 用 API 的组件、连接和布局数据真正生成图,不再维护固定拓扑事实;
- 修复历史快照连接、散热器和组合节点;
- 修复图中文字布局和残留占位符;
- 修复时间校验、任务上下文、回退导航和错误状态;
- 补齐任务列表、模块引入任务、尺寸与详情数据;
- 完成 9 个任务、明确时间、异常输入、桌面和窄屏全量回归并重新截图。
修复过程中应保留目前已通过的 GHC-05 空间骨架、绿色加压走道、散热器样式和弹窗视觉风格。
9. 截图目录
全部测试截图位于:
demo/topology_audit/
其中包括:
- 9 个任务各 1 张完整页面截图;
- GHC-05 上、中、下三段人工视觉检查;
- 3 个代表性详情弹窗;
- 明确时间、无效时间、基地建立前、不存在任务和浏览器回退;
- 390×844 页面和弹窗。
其他异常截图: