Files
AquaControlAI/docs/development-log.md
T
2026-07-13 00:44:09 +08:00

161 lines
16 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.
# 开发维护记录
## 2026-07-12|需求分析
- 研读 `spec-数据管理.md` v1.2、`spec-历史数据.md` v1.1、`code-standards.md` v1.2 和一致性决策基线 v1.0。
- 确认采用单进程 Go 服务、Handler → Service → Repository、每设备独立协议连接、同设备读写串行、PostgreSQL 当前元数据权威、TDengine 子表由 UUID 派生。
- 历史查询边界统一为最多 20 点、31 天;曲线默认 2000 样本;表格使用精确半间隔最近邻;CSV 最大 50,000 行。
## 技术与视觉决策
- 前端使用 Vue 3 + TypeScript + Pinia + Vue Router + Axios + ECharts。
- 视觉采用深石墨底、荧光绿主色、青色辅助数据序列;避免卡片堆叠,保持工业数据表和图表的高信息密度。
- 非线性分段轴算法位于 `web/src/components/charts/`API 和导出只使用原始值。
- PostgreSQL 使用 pgx 连接池;TDengine 使用官方 Go REST 驱动,连接信息全部来自环境变量。
## 已识别问题与处理
- 现场给出的读取地址 `DB2.DB2.1186.0` 与规格 `DB{db}.{byte}.{bit}` 冲突。实现严格接受 `DB2.1186.0`;现场测试前需由用户/PLC 工程师确认前一形式是否只是录入笔误。
- PLC `192.168.107.10:102` 在 2026-07-12 的 TCP 探测未在 30 秒窗口内完成;未执行任何写入。
- 用户提供的数据库凭据仅用于本次环境验证,不写入代码、示例或日志。
## 变更摘要
- 新增 PostgreSQL/TDengine 幂等迁移。
- 新增设备、采集点、写入点、历史数据四个桌面工作区。
- 新增设备 API、点位/日志列表、历史树、曲线、表格和 CSV 导出。
- 新增协议注册表、S7/Modbus 地址与配置校验骨架。
## 测试记录
- PostgreSQL `101.35.54.96:5432`:TCP 可达;目标库最初不存在,已通过受控标识符创建 `aquacontrolai` 并成功执行迁移。
- TDengine `101.35.54.96:6041`:TCP 可达;已创建/确认数据库及两个超级表,REST 驱动健康检查通过。
- PLC `192.168.107.10:102`:早期 TCP 探测超时,后续通过 S7 客户端成功连接并完成受控读写联调,详见下方补充记录。
- `go test ./...`:通过。
- `npm run build`:通过;Vite 提示 ECharts 主包超过 500 kB,后续可拆为异步图表 chunk。
- `GET /api/v1/health`:真实数据库配置下返回 `code=0`
- Playwright Chromium 1600×1000:历史页可渲染,无框架错误覆盖层;空库状态正确显示 0/20 和空图表。应用内浏览器缺少必需控制入口,按规范使用 Playwright 回退。
- 视觉比对:应用壳、色板、导航、紧凑工具栏、开放式图表/表格容器与概念一致;空库无法验证多序列曲线、点位树密度和游标数据态。
## 2026-07-12|现场 S7 联调补充
- 用户确认采集地址为 `DB2.1186.0`、类型 REAL。考虑现场工程记法,校验器仅对 DB 数值地址兼容末尾 `.0`;驱动实际按 DB2、字节偏移 1186 连续读取 4 字节。
- 写入地址 `MD540` 按 M 区字节偏移 540 连续读写 4 字节 IEEE-754 REAL。
- PLC 建立连接成功;`DB2.1186.0` 实际读值 `724.0000610351562`,质量 `good`
- 写入测试成功:`MD540=10.0`,回读 `10.0`,日志 ID `36d173ec-a496-495b-ba6a-d7048e616afa`
- 强制恢复成功:`MD540=0.0`,回读 `0.0`,日志 ID `88c0d3dc-3988-46b9-9e98-d03819f6dbbc`
- TDengine REST 驱动不支持在 `USING ... TAGS` 中绑定参数;动态表名仍只由 UUID 派生,标签/字符串采用单引号倍增转义,数值使用 `strconv.FormatFloat`,并增加表名和转义单元测试。
- 修复 TDengine REST 时间语义:API 的 ISO 8601 时间统一换算为 `Asia/Shanghai` 后生成 TDengine 查询字面量,现场最近一小时查询返回 28 条记录并成功绘制曲线。
- 修复 `vue-tsc -b``src/` 旁生成陈旧 `.js` 并覆盖 TypeScript 模块解析的问题:启用 `noEmit`、删除生成物;Playwright 验证控制台无 warning/error。
- Playwright 1600×1000 验证:历史树 1 个可选现场点位、默认勾选、ECharts canvas 正常、曲线显示真实 TDengine 数据;切换表格模式后渲染 7 行最近邻数据。
## 2026-07-12|剩余功能收尾
- 补齐设备、采集点、写入点详情 API,采集分组 API,以及三类配置 CSV 导入/导出。
- CSV 真实回灌验证:三类各 1 行,均为 `created=0, updated=1, failed=0`,名称幂等规则有效且没有产生重复记录。
- 补齐采集点和写入点新增、编辑、删除弹窗;三类页面导入文件选择与导出下载按钮已接入真实 API。
- 新增历史保留策略 GET/PUT;更新顺序为 TDengine `ALTER DATABASE KEEP` 成功后再提交 PostgreSQL 生效值。真实环境以 365 天原值回写验证成功。
- Playwright 逐页验证:设备、采集点、写入点三个新增弹窗均可打开并取消;历史保留配置可见;表格模式渲染 7 行;控制台无 warning/error。
- 补齐设备列表的协议/启用筛选,采集点和写入点的设备/分组/类型/启用/写入开关筛选,以及统一 `page/page_size`(最大 100)分页;写入日志支持点位、设备、结果和关键词筛选。
- 历史页新增精确到秒的自定义起止时间输入;快捷时间与自定义时间共用查询缓存键。
- 最终浏览器回归:三类页面导入/导出入口均可见,三个新增弹窗均可打开;历史页 2 个时间输入、保留策略控件和 7 行表格数据正常;控制台无 warning/error。
## 2026-07-12|设备状态展示调整
- 设备管理表头由“运行状态”改为“设备状态”。
- 后端状态映射为:`connected → 在线``disconnected → 离线``disabled → 禁用`
- 前端使用无圆点的文字卡片:在线绿色、离线红色、禁用灰色。
- 1600×1000 Playwright 回归:设备状态列标题与“离线”红色文字卡片正常显示,控制台无错误。
- 设备管理表格进一步调整:连接地址拆为“地址”和“端口”;移除“启用”列;新增“最近在线”和“最近离线”。时间由采集引擎连接状态事件维护,接口字段为 `last_online_at``last_offline_at`
- 真实接口回归返回在线设备时间戳,页面列顺序为:名称、协议、地址、端口、设备状态、最近在线、最近离线、操作。
## 2026-07-12|数据采集分组与 REAL 解析调整
- 新增 `collection_groups` 表及幂等迁移;启动时同步历史 `group_name` 并删除 `collection_points.valid_min/valid_max`
- 新增分组 GET/POST/PUT/DELETE API。删除分组前端二次提示,后端事务内逻辑删除该分组全部采集点;`default` 分组禁止删除。
- 数据采集页新增左侧分组栏、分组添加/改名/删除操作,新建采集点改为分组下拉选择。
- 采集列表将“地址 / 类型”拆成“地址”和“类型”;新建/编辑表单移除有效最小值和有效最大值。
- S7 REAL 解析统一四舍五入到小数点后最多 3 位;采集质量不再执行有效范围判断。
- 真实数据库验证:分组新增、改名、删除级联均通过;删除后采集点查询总数为 0;现场 REAL 值示例 `1411.719`
## 2026-07-12|设备与采集点弹窗复选框优化
- 设备新增弹窗的“启用设备”与采集点新增弹窗的“启用采集”“存储历史”统一为整行可点击的文字卡片控件。
- 复选框采用隐藏原生控件 + 自定义勾选方块,提供未选中、荧光绿色选中和键盘聚焦态;保留原有 `v-model` 数据绑定,不改变接口语义。
- 收紧通用表单输入选择器,避免复选框继承文本输入框的 `width: 100%` 导致位置异常。
- `npm run build`:通过(Vite 仍提示 ECharts 主包超过 500 kB 的既有拆包建议)。
- Playwright Chromium 回归:设备弹窗 1 个复选框、采集点弹窗 2 个复选框均正常渲染;设备默认勾选后点击可取消,采集点“存储历史”点击后可取消;两个弹窗无控制台错误。
- 回归截图:`C:\Users\Administrator\AppData\Local\Temp\aquacontrol-device-checkbox-final.png``C:\Users\Administrator\AppData\Local\Temp\aquacontrol-collection-checkbox-final.png`
## 2026-07-12|数据写入分组与回读展示调整
- 数据写入页新增与数据采集一致的左侧分组栏,分组名称、添加、改名和删除均复用 `collection_groups` 接口;后端改为同步维护采集点和写入点的分组归属,删除分组时两类点位一起逻辑删除。
- 写入点列表将“地址 / 类型”拆为独立列,移除回读容差列,改为展示该写入点最近一次写入日志中的 `readback_value`;无回读记录时显示“—”。
- 写入点数据库迁移 `000003_write_points_simplify.up.sql` 合并 `enabled``write_enabled` 为单一 `write_enabled`,移除 `readback_tolerance`;迁移具备重启幂等性,旧数据先保留原有效权限再删除冗余列。
- 写入点新增/编辑表单移除回读容差和启用字段,仅保留统一的“允许写入”自定义复选框;CSV 导入/导出同步移除冗余字段。
- REAL 回读验证保留固定协议精度 `0.0001`,不再作为点位配置或 API 字段暴露。
- 真实环境回归:`GET /api/v1/write-points` 返回不含 `enabled``readback_tolerance`,分组接口同时返回 `collection_count``write_count`;写入点 CSV 表头已更新为 `write_enabled`
- Playwright Chromium 1600×1000:写入页列表、共享分组筛选和新增弹窗均正常;弹窗无“启用/回读容差”,允许写入卡片可切换;控制台无 warning/error。未执行现场 PLC 写入,避免改变控制状态。
- 回归截图:`C:\Users\Administrator\AppData\Local\Temp\aquacontrol-write-point-table-final.png``C:\Users\Administrator\AppData\Local\Temp\aquacontrol-write-point-final.png`
## 2026-07-12|三类数据页面刷新与采集点编辑修复
- 修复采集点编辑无法更换所属设备的问题:移除 PostgreSQL 更新语句中对 `history_started_at`、旧设备和旧数据类型的限制,编辑请求现在可以正常提交新的 `device_id`;前端保存失败时显示明确错误提示。
- 数据采集列表在质量列后新增“更新时间”,取点位 `updated_at` 并按中文本地时间格式展示。
- 数据采集、设备管理、数据写入均新增“刷新数据”按钮,刷新按钮执行期间禁用并显示旋转图标。
- 数据采集刷新同时重新加载采集点分组;采集点新增/编辑/删除及 CSV 导入后刷新列表和分组;设备新增/编辑/删除及 CSV 导入后刷新列表;写入点新增/编辑/删除、执行写入及 CSV 导入后刷新列表和共享分组。
- Playwright Chromium 1600×1000 回归:三个页面刷新按钮各 1 个;采集列表包含“更新时间”;编辑弹窗包含设备选择器;三个页面刷新交互无控制台 warning/error。现场 PLC 写入未执行。
- 回归截图:`C:\Users\Administrator\AppData\Local\Temp\aquacontrol-collection-refresh-final.png`
- 更正“更新时间”字段:列表现在展示实时采集数据 `latest_value.ts`,不再展示配置的 `updated_at`
## 2026-07-12|分组删除改为点位迁移
- 删除非 `default` 分组时,后端事务先将该分组下未逻辑删除的采集点和写入点统一迁移到 `default`,再删除分组记录;不再逻辑删除任何点位。
- 事务内确保 `default` 分组存在,`default` 分组仍禁止删除。
- 数据采集和数据写入页面的删除确认提示同步改为“自动转移到 default 分组”。
- 开发验证:使用临时写入点执行“建组→建点→删组”回归,点位保留且 `group_name` 已迁移为 `default`,随后清理临时点;Go 测试和静态检查、前端构建均通过,未执行现场 PLC 写入。
# 2026-07-12 · 历史数据增强与归档清理
## 需求分析
- 历史点位树支持分组折叠/展开、分组全选/取消;点位、时间范围和表格间隔变化后自动查询,保留最多 20 个点位限制。
- 曲线横轴必须与系统时间一致并按选择范围固定起止点;无数据序列不显示;bad 质量值使用虚线;图例状态保留并控制对应曲线;游标采用非吸附、带动画的轴指示器。
- 曲线高度提升,游标明细最多显示约 5 行并在点位较多时纵向滚动;表格点位列较多时横向滚动。
- 已逻辑删除点位的历史子表提供显式清理入口,禁用但仍可恢复的点位不纳入清理。
## 技术方案与变更
- PostgreSQL 新增只读查询已删除采集点 UUID 的方法;TDengine 新增按 UUID 派生子表的安全删除方法,API 增加 `POST /api/v1/history/archive/cleanup`,前端增加清理确认和结果反馈。
- TDengine REST 驱动返回的本地墙上时间改为显式重建为 `Asia/Shanghai`,避免重复施加时区偏移;表格时间列统一输出上海时区。
- 历史页面增加自动查询防抖和请求序列保护,曲线传入选定时间范围并动态设置时间刻度;bad 数据拆分为虚线序列,且共享逻辑图例名称。
## 验证记录
- `go test ./...`:通过。
- `npm run build`:通过;仅保留既有 ECharts 体积提示。
- `GET /api/v1/health`:真实 PostgreSQL/TDengine 配置下返回 `code=0`
- Playwright Chromium 1600×1000:验证分组全选、点位变更自动曲线查询、曲线/表格切换自动查询、间隔变化自动表格查询;曲线高度 520px;控制台无错误。截图:`C:\Users\Administrator\AppData\Local\Temp\aquacontrol-history-curve-final.png``C:\Users\Administrator\AppData\Local\Temp\aquacontrol-history-final.png`
- 归档清理接口真实回归时识别并清理了 13 个已逻辑删除点位的历史子表;活跃点位和仅禁用点位未清理。清理为不可逆操作,前端已增加二次确认。
## 2026-07-12 · 自定义时间与任意时刻游标
- 修复固定快捷范围切换后编辑自定义时间可能被旧范围覆盖的问题:时间输入在 `input``change` 阶段均同步,先保存被编辑的端点,再校验起止时间,允许用户分两步完成暂时不完整的自定义范围。
- 游标改为基于鼠标在时间轴上的实际像素位置换算时间,不再使用最近存储点作为游标时间;对每条曲线按前后有效样本进行线性插值,游标表格中的所有曲线使用同一时间戳,边界使用最近有效值,质量戳为 bad 或跨越 bad 样本时保留 bad 标识。
- 插值结果在游标表格中使用 `≈` 标记,ECharts 轴指示器继续关闭吸附并保留平滑动画;图例隐藏的曲线不参与游标结果。
## 2026-07-12 · 本轮验证
- Playwright 验证固定范围后编辑起止时间保持 `custom` 状态;鼠标移动到非存储时刻时,两条曲线游标显示相同时间 `2026/7/12 23:08:03`,无控制台错误。
## 2026-07-13 · 游标视觉跟随与离开区域保持
- 移除 ECharts 默认会吸附存储点的轴指示线,改用图表内独立的垂直游标线;鼠标像素位置先换算为时间,再用 `requestAnimationFrame` 更新线位置,避免在 ECharts 事件处理期间调用 `setOption`
- 游标线仅覆盖绘图区,和插值明细使用同一时间;鼠标离开曲线区域不再清空最后一次游标时间和明细数据。
- 回归验证连续移动得到 `23:41:48``23:44:25``23:47:00``23:49:38` 四个不同时间点;离开图表后仍保留 2 条曲线明细,控制台无错误。
## 2026-07-13 · 设备状态与采集成功状态同步
- 根因:采集读失败后 `Manager` 将设备状态置为 `disconnected`;缓存连接后续读取成功时此前只更新点位最新数据,没有恢复设备状态,因此设备管理页持续显示离线。
- 修复:采集成功后调用 `Manager.MarkConnected` 恢复在线状态;`MarkConnected``MarkDisconnected` 仅在状态发生变化时更新时间戳,避免每个采集周期反复刷新最近在线/离线时间。
- 验证:真实环境中 PLC1、PLC2、PLC3 均显示 `connected`40 个采集点的 `latest_value.ts` 持续更新;新增设备状态恢复及时间戳稳定性单元测试。