diff --git a/docs/ai/handoff.md b/docs/ai/handoff.md index 5648aa1..e6198eb 100644 --- a/docs/ai/handoff.md +++ b/docs/ai/handoff.md @@ -5,7 +5,7 @@ ## 当前状态 - 分支:`main` -- 核心软件闭环已经可用:HMI 编辑、结构化梯形图、离线仿真、工程 JSON、独立 HMI 运行窗口、自由监控和 Modbus RTU 真机读写均已实现 +- 核心软件闭环已经可用:HMI 编辑、结构化梯形图、离线仿真、工程 JSON、统一运行监控大屏、自由监控和 Modbus RTU 真机读写均已实现 - HMI 外观属性和梯形图十列可选插入网格均已按逻辑完成提交;开始工作前仍需先看 `git status` 和相关 diff,不要重置来源不明的改动 - `docs/二次开发/` 是已有未跟踪资料,不能因当前任务删除 - 当前没有代码阻塞;下一里程碑是实际设备 RUN 联动和交付整理 @@ -15,7 +15,7 @@ - 工程格式为严格的 `1.0`,保存多 HMI 页面、初始页、报警定义、M/D 注释、多控制逻辑和结构化梯形图;不读取旧 `dataPoints` 或 `stages/branches` 格式 - HMI 现有 8 类控件:Button、Indicator、NumericDisplay、NumericInput、Label、PageJump、AlarmList、ProgressBar - HMI 控件支持静态文字外观:`textColor` 使用 `#RRGGBB`,字体使用 `fontSize`、`fontBold` 和 `fontItalic`;缺失时使用原有默认样式,属性经现有 `properties` 保存,无需升级 JSON 版本 -- 字体颜色和基础字体设置在编辑画布、主窗口只读 HMI 和独立操作员 HMI 窗口中共享同一绘制实现;它们不参与 M/D 绑定、PLC 轮询或离线控制逻辑 +- 字体颜色和基础字体设置在编辑画布和统一运行监控 HMI 中共享同一绘制实现;它们不参与 M/D 绑定、PLC 轮询或离线控制逻辑 - 梯形图使用 `Node / Wire / Series / Parallel` 表达式树和正交网格,不保存自由线段;前 10 列为条件区,输出最多位于第 11 列 - 每个新建或已有网络都投影出 10 个可独立点击的条件网格;空网格横线只属于 UI 插入光标,不写入工程,点击远端空格后才按需保存前置 `Wire(span)` 和真实条件节点 - 已保存的多列 `Wire` 也按单格提供点击目标;在其中一格插入触点时,服务层原子拆分为前置横线、触点和后置横线,继续点击条件工具会逐格消费右侧横线,保持原总列宽以及撤销/重做语义 @@ -26,11 +26,17 @@ - 自由监控属于当前会话,支持 M/D 批量添加、去重、读取和单点写入,不写入工程 JSON - PLC 通信使用异步 Qt Modbus RTU;轮询地址来自 HMI、报警、梯形图和自由监控的引用并集,写入后等待轮询确认,不乐观修改缓存 - 真机进入要求当前连接完成首次读取;通信故障撤销首读资格并退出真机运行,恢复通信后仍停留在编辑态 -- 进入离线或真机运行后会打开最大化的独立 HMI 窗口,主窗口保留工程师诊断工作台;两个视图共享运行页面和寄存器数据源,关闭独立窗口会统一返回编辑态 +- 进入离线或真机运行后,弹出并最大化唯一的工程师运行监控窗口,主编程器保留在后面且布局不变;离线时组合可交互 HMI、软件梯形图轨迹和自由监控,真机时组合可交互 HMI 和自由监控 - 所有数量上限和超限处理见 `docs/用户使用/数量边界确认方案.md`,核心常量集中在 `app/src/domain/project_limits.h` ## 最近完成 +- 根据编程器面向设备交付、调试和验证工程师的需求定位,不恢复旧的纯 HMI 操作员窗口;新增职责明确的 `RuntimeMonitorWindow`,承载离线和真机共用的完整运行监控大屏 +- 主窗口已移除运行监控页签和运行时布局切换;点击离线或真机运行会弹出最大化监控窗口,右上角返回、关闭弹窗和应用退出分别按统一生命周期处理,且全应用只创建一份 `RuntimeMonitorWidget` +- CTU/CTD 输出节点保持现有梯形图网格宽度,将 CV 和 PV 拆成带水平内边距的两行显示,避免 `D4000`、`32767` 等边界配置在右侧电源轨处被裁剪 +- 报警列表标题输入上限为 12 个字符,报警文本输入上限为 20 个字符;运行消息保持单行并在空间不足时显示省略号 +- 新建报警列表默认尺寸调整为 `360×136`,默认字号比应用字体小 2pt;运行态按当前页 1~5 条记录收缩高度,超过 5 条可通过表头按钮翻页且确认命中使用当前页索引 +- 主窗口默认工具栏布局调整为运行模式栏第一行,HMI 或梯形图编辑工具栏第二行;编辑工具栏仍允许用户拖动重新停靠 - 新增 HMI 保留外观属性键和领域校验:颜色为严格 `#RRGGBB`,字号为 `6~72`,粗体和斜体为 `true/false` - 属性面板新增颜色输入与选择按钮、字号、粗体、斜体;通过既有 `HmiEditorService::updateControl()` 原子提交并保留撤销/重做 - `HmiGraphicsItem` 统一应用文字外观,保留地址提示、按钮禁用色、指示灯状态色、控件边框和选中框的原有语义 @@ -40,6 +46,13 @@ ## 最近验证 +- 独立运行监控窗口改动已通过重新生成 qmake 构建后的 `main_window_tests`、`hmi_editor_service_tests`、`offline_simulation_service_tests`、`runtime_mode_service_tests` 和 `plc_runtime_tests`;主窗口测试覆盖最大化弹窗、唯一监控实例、主窗口布局不变、离线与模拟真机 HMI 写入、页面跳转、返回编辑、关闭弹窗、通信故障隐藏、重复进入刷新和应用退出 +- 独立运行监控窗口改动后的 Qt Release 主程序已在 `build/runtime-monitor-window-release` 完整构建并链接成功 +- 2026-08-20 使用 `COM3 / 9600 / 8E1 / 站号 1` 完成真实 PLC 安全读写:读取 `D4000=0`,临时写入并读回 `1`,随后恢复并读回 `0`;没有下载 PLC 程序,也没有执行切换 RUN 的动作 +- CTU/CTD 显示修复已通过 `main_window_tests`(`QT_QPA_PLATFORM=offscreen`)和 Qt Release 主程序重新构建;改动仅涉及梯形图 UI 投影,因此未连接真实 PLC +- 报警列表和分页改动已通过 `domain_tests`、`alarm_service_tests`、`hmi_editor_service_tests`、`project_management_tests` 和 `main_window_tests`;覆盖输入长度、默认五行尺寸、默认字号、运行态高度收缩、六条报警翻页和跨页确认 +- 报警列表改动后的 Qt Release 主程序已重新构建并链接成功;改动不涉及 PLC 通信、Modbus 地址或运行模式,因此未连接真实 PLC +- 默认工具栏布局改动已通过 `main_window_tests`(`QT_QPA_PLATFORM=offscreen`)和 Qt Release 主程序重新构建 - 批量删除并联支路回归已通过专项探针、`logic_editor_service_tests` 和 `main_window_tests`;逐个删除、删除完整支路和部分批量删除均保持有效 - 修复后全量测试目标均通过:`alarm_service_tests`、`domain_tests`、`hmi_editor_service_tests`、`logic_editor_service_tests`、`main_window_tests`、`offline_simulation_service_tests`、`plc_runtime_tests`、`project_management_tests`、`register_monitor_service_tests`、`runtime_mode_service_tests` - 本次字体外观改动后的全量测试目标均通过,`main_window_tests` 使用 `QT_QPA_PLATFORM=offscreen` 覆盖了属性面板提交 @@ -48,7 +61,8 @@ - 真实 PLC 已使用 `COM3 / 9600 / 8E1 / 站号 1` 验证首次读取、断线恢复和重新首读 - 2026-08-19 已读取 `D4000=0`,写入并读回 `1`,随后恢复并读回 `0`;没有下载 PLC 程序 - 本次修复只影响梯形图编辑结构归一化和删除校验,不涉及 PLC 通信或真机运行,因此没有重复写 PLC -- 独立 HMI 窗口改动已通过 `main_window_tests`(显示、关闭退出、页面同步,以及退出编辑后新增控件再次运行的页面刷新)及 `runtime_mode_service_tests`,Qt Release 主程序重新构建通过 +- 运行界面此前的双投影生命周期测试已由独立顶层工程师运行监控窗口的唯一投影测试替代,不再构建或保留旧的纯 HMI 操作员窗口 +- 本次窗口改动不改变 PLC 通信、Modbus 地址或寄存器读写实现;模拟真机 UI 路径已由假 PLC 仓库覆盖,真实 PLC 安全读写已在同日完成,因此未因窗口承载方式变化重复写设备 - 本次只修改静态 HMI 外观、领域校验和工程持久化,不改变 PLC 通信、Modbus 地址、寄存器读写或运行模式,因此未进行额外真机读写 - 梯形图网格专项覆盖了新网络 10 个点击目标、第五列和第十列插入、前置空档、持久横线首格/中格/末格/单格拆分、满横线连续替换 10 个触点、多网络、满列拒绝、非法配置、原子失败、撤销/重做,以及主窗口真实 `QAction` 点击链路;同时验证普通/置位/复位线圈复用同一固定输出节点,`logic_editor_service_tests` 和 `main_window_tests` 均通过 - 梯形图网格改动后的 `domain_tests`、`project_management_tests`、`offline_simulation_service_tests` 和 `runtime_mode_service_tests` 回归均通过,确认空网格不进入 JSON 或离线执行语义;Qt Release 主程序已在 `build/grid-feature-release` 完整构建并链接成功 diff --git a/docs/architecture.md b/docs/architecture.md index 5ad4e30..76e86b6 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -2,7 +2,7 @@ ## 目标与范围 -项目是单工程、单 PLC、多 HMI 页面和多控制逻辑的 Qt 桌面编程器,提供 HMI 编辑、结构化梯形图、离线仿真和 Modbus RTU 真机联机。 +项目是面向设备交付、调试和验证工程师的单工程、单 PLC、多 HMI 页面和多控制逻辑 Qt 桌面编程器,提供 HMI 编辑、结构化梯形图、离线仿真和 Modbus RTU 真机联机。 本项目不生成、编译或下载 PLC 程序,不读取 PLC 内部程序与网络轨迹,不实现完整 XDPPro 指令集,也不支持任意自由画线。真机运行时 PLC 内部程序是唯一控制源,PC 只读写工程实际引用的 M/D 地址。 @@ -37,15 +37,18 @@ main.cpp -> UI + Services + Infrastructure | --- | --- | | `ProjectWorkspaceController` | 工程树、当前页面/逻辑会话选择和编辑对象刷新 | | `PropertyPanelController` | HMI/梯形图选择、属性表单和编辑服务调用 | -| `RuntimePanelController` | 运行会话、操作员 HMI 窗口、诊断工作台、运行值刷新和仿真故障反馈 | -| `HmiRuntimeWindow` | 独立顶层操作窗口,只投影 HMI 页面并转发运行时交互和退出请求 | +| `RuntimePanelController` | 运行会话、顶层运行监控窗口、运行值刷新和仿真故障反馈 | +| `RuntimeMonitorWindow` | 独立顶层窗口的显示、隐藏、关闭请求和应用退出生命周期 | +| `RuntimeMonitorWidget` | 全应用唯一运行投影,组合可交互 HMI、梯形图轨迹和自由监控 | | `MainWindow` | 窗口级动作、工程文件操作、控制器组合和模式切换 | -运行界面按使用角色分为两个投影,二者共享同一份 `HmiNavigationService` 和活动寄存器仓库,不能各自维护页面或运行状态: +运行界面统一投影到独立顶层 `RuntimeMonitorWindow` 中的唯一 `RuntimeMonitorWidget`。该窗口是编程器的工程师运行监控大屏,不是旧的纯 HMI 操作员窗口: -- `HmiRuntimeWindow` 是操作员窗口。进入离线或真机运行后最大化显示,只包含 HMI 页面、当前页面、运行数据源状态和退出运行入口;不显示工程树、属性、梯形图编辑或 PLC 配置 -- 主窗口中的 `RuntimeMonitorWidget` 是工程师诊断工作台。离线时显示只读 HMI、软件梯形图轨迹和自由监控;真机时显示只读 HMI 和自由监控,不能显示本地梯形图伪轨迹。页面跳转会同步到操作员窗口,但按钮和数值输入不能从诊断 HMI 写入 -- 关闭独立 HMI 窗口不是单纯隐藏窗口,而是请求 `MainWindow -> RuntimeModeService` 返回编辑态。离线时先停止软件扫描,真机时保留 PLC 连接但撤销运行会话 +- 进入离线或真机运行后,弹出并最大化运行监控窗口;主编程器窗口保留在后面且不改变布局,运行期间由同一份 `ModePolicy` 禁用编辑入口 +- 主窗口不保留运行监控页签,也不创建第二份监控控件;工程对象刷新和运行交互始终指向弹窗中的唯一实例 +- 离线时显示可交互 HMI、软件梯形图轨迹和自由监控;真机时显示可交互 HMI 和自由监控,不能显示本地梯形图伪轨迹 +- HMI 页面跳转、按钮和数值输入都通过同一份 `HmiNavigationService` 和活动寄存器仓库完成;离线写虚拟 M/D,真机写 PLC,仿真停止或通信不可用时禁止写入 +- 运行监控的返回编辑按钮或窗口关闭按钮都请求 `MainWindow -> RuntimeModeService` 返回编辑态。离线时先停止软件扫描,真机时保留 PLC 连接但撤销运行会话;应用退出时允许顶层窗口真正关闭 ## 工程模型与持久化 @@ -111,13 +114,13 @@ ConditionExpression 编辑:UI -> Editor Services -> ProjectService -> Project └── ProjectStorage -> JSON -离线:HMI 运行窗口 / 诊断工作台 -> ActiveRegisterRepository -> VirtualRegisterRepository - ^ - OfflineSimulationService(SoftwareLogicExecutor) +离线:运行监控弹窗 -> ActiveRegisterRepository -> VirtualRegisterRepository + ^ + OfflineSimulationService(SoftwareLogicExecutor) -真机:HMI 运行窗口 / 诊断工作台 -> ActiveRegisterRepository -> PlcRegisterRepository(cache) - ^ -PLC <-> PlcCommunicationService <---------------------------------┘ +真机:运行监控弹窗 -> ActiveRegisterRepository -> PlcRegisterRepository(cache) + ^ +PLC <-> PlcCommunicationService <--------------------┘ ``` | 模式 | 允许工程编辑 | 寄存器来源 | 软件逻辑执行器 | 进入条件 | diff --git a/docs/工程格式说明.md b/docs/工程格式说明.md index 1c791c9..fec4e8f 100644 --- a/docs/工程格式说明.md +++ b/docs/工程格式说明.md @@ -77,7 +77,7 @@ 编辑草稿允许 `targetPageId` 为空字符串,但进入运行态前必须配置为现存页面 ID。任何页面被 PageJump 引用时不得删除。 -AlarmList 只负责显示项目级当前报警,不保存独立触发逻辑,也不直接绑定单个寄存器。多个页面放置 AlarmList 时共享同一组当前报警和确认状态。运行态没有报警时控件隐藏;报警恢复后对应记录立即移除,最后一条报警恢复后控件再次隐藏。 +AlarmList 只负责显示项目级当前报警,不保存独立触发逻辑,也不直接绑定单个寄存器。编辑界面的标题输入上限为 12 个字符。多个页面放置 AlarmList 时共享同一组当前报警和确认状态。运行态没有报警时控件隐藏;有报警时按当前页的实际记录数收缩高度,每页最多显示 5 条。超过 5 条时通过表头翻页按钮查看,记录不会被丢弃。标题和报警文本按单行绘制,空间不足时显示省略号。报警恢复后对应记录立即移除,最后一条报警恢复后控件再次隐藏。 ProgressBar 使用绑定 D 地址的有符号 16 位字值,并将其限制在 `minimumValue` 到 `maximumValue` 的范围后映射为百分比。`minimumValue` 和 `maximumValue` 必须是有符号 16 位整数, @@ -104,11 +104,11 @@ ProgressBar 使用绑定 D 地址的有符号 16 位字值,并将其限制在 | `dHigh` | D | 字值大于等于 `threshold` | | `dLow` | D | 字值小于等于 `threshold` | -`threshold` 使用有符号 16 位范围;M 报警仍保留该必填字段但不参与判断。报警文本不能为空。发生时间、活动状态、确认状态和清除时间属于运行会话,不进入工程 JSON。 +`threshold` 使用有符号 16 位范围;M 报警仍保留该必填字段但不参与判断。报警文本不能为空,编辑界面的输入上限为 20 个字符。运行界面按单行绘制,超出当前消息列宽度时显示省略号。发生时间、活动状态、确认状态和清除时间属于运行会话,不进入工程 JSON。 ## 地址注释与网络注释 -`registerComments` 是工程级 M/D 地址元数据数组。每个元素必须包含有效的 `address` 和非空 `text`,同一地址只能出现一次: +`registerComments` 是工程级 M/D 地址元数据数组。每个元素必须包含有效的 `address` 和非空 `text`,同一地址只能出现一次。软元件注释只能使用单行文本,不能包含回车或换行,且不能超过 64 个 UTF-8 字节: ```json { @@ -117,7 +117,7 @@ ProgressBar 使用绑定 D 地址的有符号 16 位字值,并将其限制在 } ``` -注释不保存寄存器当前值,也不自动把地址加入 Modbus 轮询。网络注释属于 `LadderRung`,与网络 ID、名称、条件和输出并列保存: +注释不保存寄存器当前值,也不自动把地址加入 Modbus 轮询。网络注释属于 `LadderRung`,与网络 ID、名称、条件和输出并列保存。网络注释允许为空;非空时只能使用单行文本,不能包含回车或换行,且不能超过 128 个 UTF-8 字节: ```json { diff --git a/docs/用户使用/数量边界确认方案.md b/docs/用户使用/数量边界确认方案.md index 1d7ca37..bcf17ed 100644 --- a/docs/用户使用/数量边界确认方案.md +++ b/docs/用户使用/数量边界确认方案.md @@ -22,6 +22,9 @@ | HMI | 单控件扩展属性 | 0 对 | 64 对 | 第 65 对属性不能加载或保存 | 防止属性对象无限增长 | | HMI | 字号 | 6 | 72 | 拒绝保存、加载或编辑 | 控制文字可读性和控件布局开销 | | 报警 | 报警定义数量 | 0 | 512 | 第 513 条报警不能创建或加载 | 报警每个刷新周期都要判断 | +| 报警 | 报警列表标题输入长度 | 0 字符 | 12 个字符 | 编辑界面限制继续输入 | 标题需要在表头为翻页控件保留空间,显示不下时使用省略号 | +| 报警 | 单条报警文本输入长度 | 1 字符 | 20 个字符 | 编辑界面限制继续输入 | 报警信息按单行显示并在宽度不足时使用省略号 | +| 报警 | 单页同时可见行数 | 1 行 | 5 行 | 超出后通过表头按钮翻页,活动记录不丢失 | 控制默认控件高度并避免少量报警产生大块留白 | | 注释 | M/D 软元件注释数量 | 0 | 8002 | 超出后拒绝保存或加载 | M0~M4000 和 D0~D4000 每个地址最多一条,共 8002 条 | | 控制逻辑 | 控制逻辑数量 | 0 | 128 | 第 129 组不能创建或加载 | 控制工程树和扫描工作量 | | 控制逻辑 | 每组逻辑的网络数量 | 0 | 1024 | 第 1025 个网络不能创建或加载 | 每次软件扫描都要执行这些网络 | @@ -33,7 +36,9 @@ | 单个网络 | 逻辑网格行数 | 1 | 256 | 超出后编辑操作回退,加载失败 | 防止并联支路纵向无限扩展 | | 横线 | 单段横线跨度 | 1 列 | 10 列 | 拒绝编辑或加载 | 横线只能占用条件区,不能占用输出列 | | 字符串 | ID、格式版本、页面跳转目标 ID | 0 字节 | 128 个 UTF-8 字节 | 拒绝保存或加载;业务要求非空的 ID 仍必须非空 | ID 只用于稳定识别,不需要长文本 | -| 字符串 | 工程名、页面名、控件文本、报警文本、注释 | 0 字节 | 4096 个 UTF-8 字节 | 拒绝保存或加载;业务要求非空的字段仍必须非空 | 给中文说明留足空间,同时防止异常长文本 | +| 字符串 | 工程名、页面名、控件文本、报警文本、网络名称 | 0 字节 | 4096 个 UTF-8 字节 | 拒绝保存或加载;业务要求非空的字段仍必须非空 | 防止异常工程数据无限增长;报警编辑界面另使用上方的 12/20 字符输入限制 | +| 注释 | 软元件注释 | 1 字节 | 64 个 UTF-8 字节 | 拒绝编辑、保存或加载;禁止回车和换行 | 注释绘制在梯形图节点下方,必须保持紧凑单行 | +| 注释 | 梯形图网络注释 | 0 字节 | 128 个 UTF-8 字节 | 拒绝编辑、保存或加载;禁止回车和换行 | 注释绘制在网络标题下方,换行会挤占梯形图区域 | | 字符串 | HMI 属性名称 | 1 字节 | 128 个 UTF-8 字节 | 拒绝保存或加载 | 属性名是短标识 | | 字符串 | HMI 属性值 | 0 字节 | 4096 个 UTF-8 字节 | 拒绝保存或加载 | 属性值可能保存显示配置,但不能无限增长 | | 自由监控 | 去重后的监控地址 | 0 | 64 | 第 65 个监控地址不能加入 | 这是用户临时监控区,不应拖慢 PLC 轮询 |