diff --git a/CHANGELOG.md b/CHANGELOG.md index 047f305..12dac06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ - 修复国际旗舰模型输出思考过程时偶尔无法及时停止的问题;即使模型暂时没有返回新的流式片段,点击“停止”也会迅速中断当前回答。 -- Windows Node 主窗口改为简洁的单层自适应布局:移除固定宽度与重复卡片边框,窗口缩放时内容和页签会随可用宽度调整,专业软件的状态与操作也会在窄窗口中自然换行;能力概览按软件归并,不再为同一软件或同名能力重复显示名称。Origin、ANSYS、Blender 均可手工选择位置,Origin 自动检测也会在 COM 路径无效时继续查找注册表和标准安装目录。 +- Windows Node 主窗口改为简洁的单层自适应布局:顶部只保留产品名与节点状态,移除固定宽度、重复卡片边框和说明性大标题;默认窗口适当增高,缩放时内容和页签会随可用宽度调整,专业软件的状态与操作也会在窄窗口中自然换行。可用软件按名称归并,不再重复显示同一软件或能力;托盘右键菜单中的长状态也会自动截断,不再把菜单横向撑宽。Origin、ANSYS、Blender 均可手工选择位置,Origin 自动检测也会在 COM 路径无效时继续查找注册表和标准安装目录。 - Windows Node 从托盘退出时会保护已有任务:可以停止接单并等待任务完成后退出,也可以经二次确认取消任务并终止对应的软件进程,不再直接关闭节点而留下状态不明的任务。 diff --git a/PROGRESS.md b/PROGRESS.md index 9954783..8429cf2 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -24,7 +24,7 @@ - **08-21 / Unreleased / Blender 多视图与剖切 v2**:以 `blender.scene.author@v2` 直接替换 v1,目标节点为 Blender 5.2 LTS;`rotary_kiln` 一次建模后可连续渲染等轴测、侧视、窑头、窑尾、纵向剖切和横截面,完整工程保持未剖切状态;固定等轴测预览外,其他选定 PNG 可动态自动回传,GLB 排除仅供剖切渲染的辅助几何。专业软件提交工具改为区分缺失参数与合法空数组,允许 Blender 这类无输入、无额外导出请求的纯生成任务进入合同校验;90 项 Blender/合同/Job/Node/预览专项 unittest、.NET build、独立 adapter 打包和 Blender 3.6.12 兼容烟测通过,全量 698 项仍仅 3 个既有数据库集成模块因显式测试库缺少 `users` 表未通过(另跳过 4 项),目标节点 5.2 真机验收待部署后执行,未连接或迁移生产数据库。 -- **08-21 / Unreleased / Windows Node 软件地址选择、Origin 检测与自适应界面**:专业软件保留一层带边界的独立配置行和通栏只读地址框,Origin、ANSYS、Blender 均可手选位置。Origin 自动检测由单一 COM 路径扩展为 COM、卸载注册表和标准目录回退,手选的 `Origin*.exe` 同时用于 Worker 版本识别,COM 执行健康仍由 probe 独立校验。主窗口移除固定宽度居中容器和普通内容卡片边框,改为单层全宽页面;页签使用 WinForms 内置 `FillToRight` 模式跟随窗口调整,避免手工尺寸回调递归触发布局栈溢出;软件状态与操作分行并允许按钮自然换行,能力概览按软件与能力名称归并旧、新 adapter 的重复文案。Windows Node 23 项源码 unittest、.NET build、启动烟测与 diff 检查通过,无 DB、schema、HTTP API、依赖或运行方式变化。 +- **08-21 / Unreleased / Windows Node 软件地址选择、Origin 检测与自适应界面**:专业软件保留一层带边界的独立配置行和通栏只读地址框,Origin、ANSYS、Blender 均可手选位置。Origin 自动检测由单一 COM 路径扩展为 COM、卸载注册表和标准目录回退,手选的 `Origin*.exe` 同时用于 Worker 版本识别,COM 执行健康仍由 probe 独立校验。主窗口移除固定宽度居中容器、普通内容卡片边框和重复说明标题,顶部压缩为产品名与状态单行,默认高度增至 1050;页签使用 WinForms 内置 `FillToRight` 模式跟随窗口调整,软件状态与操作分行并允许按钮自然换行,可用软件按名称归并旧、新 adapter 的重复文案。托盘右键状态规范为单行并在 24 字符处省略,完整信息继续在主窗口显示,托盘悬浮保留较长摘要。Windows Node 23 项源码 unittest、.NET build、启动烟测与 diff 检查通过,无 DB、schema、HTTP API、依赖或运行方式变化。 - **08-20 / Unreleased / Windows Node 专业软件独立配置与 runtime 安装**:主窗口新增 Origin、ANSYS Mechanical 2024 R2、Blender 软件卡,分别显示应用位置来源和受管 runtime 状态;三种软件均可由 UI 选择自定义位置,清除后按各自的环境变量、COM、卸载注册表、PATH 或标准目录自动检测。每个软件可单独创建或更新隔离的 Python 3.12 runtime,安装只使用内置 runtime 定义与固定 requirements,拒绝活动任务期间替换,并先在临时目录完成后再切换;配置后的路径由 Host 作为固定子进程环境传给 Worker,任务请求仍不能提供路径或命令。移除重复承担软件安装和开机启动的统一 BAT,发布包直接运行 EXE,当前账号的开机启动也完全由 UI 管理;全新节点默认使用可写的 `%LocalAppData%` 数据根目录,已有 `%ProgramData%` 节点原位兼容。 diff --git a/tests/test_windows_node_source.py b/tests/test_windows_node_source.py index 27fc0fb..37ff611 100644 --- a/tests/test_windows_node_source.py +++ b/tests/test_windows_node_source.py @@ -187,7 +187,7 @@ class WindowsNodeSourceTests(unittest.TestCase): def test_configuration_window_is_resizable_and_dpi_safe(self) -> None: form = (PROJECT / "ConfigurationForm.cs").read_text(encoding="utf-8") - self.assertIn("ClientSize = new Size(1080, 720)", form) + self.assertIn("ClientSize = new Size(1080, 1050)", form) self.assertIn("MinimumSize = new Size(760, 560)", form) self.assertIn("FormBorderStyle.Sizable", form) self.assertIn("AutoScaleMode.Dpi", form) @@ -210,7 +210,10 @@ class WindowsNodeSourceTests(unittest.TestCase): self.assertIn("Appearance = TabAppearance.FlatButtons", form) self.assertNotIn("protected override void OnResize", form) self.assertIn("tab.Controls.Add(content)", form) - self.assertIn("CreateSubsectionTitle(\"能力概览\")", form) + self.assertIn("CreateSectionTitle(\"节点信息\")", form) + self.assertIn("CreateSubsectionTitle(\"可用软件\")", form) + self.assertIn("heading.Controls.Add(state, 1, 0)", form) + self.assertNotIn("headingHint", form) self.assertIn("panel.SetColumnSpan(path, 2)", form) self.assertIn("panel.SetColumnSpan(status, 2)", form) self.assertIn("panel.SetColumnSpan(actions, 2)", form) @@ -235,6 +238,8 @@ class WindowsNodeSourceTests(unittest.TestCase): tray = (PROJECT / "TrayApplicationContext.cs").read_text(encoding="utf-8") self.assertIn("form.ReconnectRequested += RestartConnection", tray) + self.assertIn("statusItem.Text = CompactMenuText(status.Message, 24)", tray) + self.assertIn('singleLine[..(length - 1)] + "…"', tray) def test_tray_exit_waits_for_or_cancels_active_jobs(self) -> None: tray = (PROJECT / "TrayApplicationContext.cs").read_text(encoding="utf-8") diff --git a/windows-node/Zcbot.WindowsNode/ConfigurationForm.cs b/windows-node/Zcbot.WindowsNode/ConfigurationForm.cs index 6d1876c..82ce6cc 100644 --- a/windows-node/Zcbot.WindowsNode/ConfigurationForm.cs +++ b/windows-node/Zcbot.WindowsNode/ConfigurationForm.cs @@ -74,7 +74,7 @@ internal sealed class ConfigurationForm : Form adapters = NodeAdapterRegistry.CreateDefault(jobInbox); Text = "zcbot Windows Node"; AutoScaleMode = AutoScaleMode.Dpi; - ClientSize = new Size(1080, 720); + ClientSize = new Size(1080, 1050); MinimumSize = new Size(760, 560); StartPosition = FormStartPosition.CenterScreen; Font = new Font("Microsoft YaHei UI", 9); @@ -109,19 +109,20 @@ internal sealed class ConfigurationForm : Form { AutoSize = true, Dock = DockStyle.Top, - ColumnCount = 1, + ColumnCount = 2, Margin = new Padding(2, 0, 2, 14), }; + heading.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100)); + heading.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize)); heading.Controls.Add(new Label { Text = "zcbot Windows Node", AutoSize = true, - Font = new Font("Microsoft YaHei UI", 18, FontStyle.Bold), + Anchor = AnchorStyles.Left, + Font = new Font("Microsoft YaHei UI", 16, FontStyle.Bold), ForeColor = Color.FromArgb(15, 23, 42), - }); - var headingHint = CreateHint("连接本机科研软件与 zcbot,安全执行受控任务"); - headingHint.Font = new Font("Microsoft YaHei UI", 10); - heading.Controls.Add(headingHint); + }, 0, 0); + heading.Controls.Add(state, 1, 0); page.Controls.Add(heading); var tabs = new NavigationTabControl @@ -139,22 +140,11 @@ internal sealed class ConfigurationForm : Form page.Controls.Add(tabs, 0, 1); var statusCard = CreateSection(); - var statusHeader = new TableLayoutPanel - { - AutoSize = true, - Dock = DockStyle.Top, - ColumnCount = 2, - Margin = new Padding(0, 0, 0, 8), - }; - statusHeader.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100)); - statusHeader.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize)); - statusHeader.Controls.Add(CreateSectionTitle("节点状态"), 0, 0); - statusHeader.Controls.Add(state, 1, 0); - statusCard.Controls.Add(statusHeader); + statusCard.Controls.Add(CreateSectionTitle("节点信息")); statusCard.Controls.Add(detail); statusCard.Controls.Add(identity); statusCard.Controls.Add(CreateDivider()); - statusCard.Controls.Add(CreateSubsectionTitle("能力概览")); + statusCard.Controls.Add(CreateSubsectionTitle("可用软件")); statusCard.Controls.Add(capabilitySummary); var resetActions = CreateActions(); resetActions.Controls.Add(reconnect); @@ -1356,9 +1346,7 @@ internal sealed class ConfigurationForm : Form { var selected = eventArgs.Index == SelectedIndex; var bounds = eventArgs.Bounds; - using var background = new SolidBrush(selected - ? Color.White - : Color.FromArgb(241, 245, 249)); + using var background = new SolidBrush(Color.White); eventArgs.Graphics.FillRectangle(background, bounds); TextRenderer.DrawText( eventArgs.Graphics, diff --git a/windows-node/Zcbot.WindowsNode/TrayApplicationContext.cs b/windows-node/Zcbot.WindowsNode/TrayApplicationContext.cs index 540aeab..0c17f3d 100644 --- a/windows-node/Zcbot.WindowsNode/TrayApplicationContext.cs +++ b/windows-node/Zcbot.WindowsNode/TrayApplicationContext.cs @@ -201,7 +201,7 @@ internal sealed class TrayApplicationContext : ApplicationContext { current = status; form.ApplyStatus(status, config); - statusItem.Text = status.Message; + statusItem.Text = CompactMenuText(status.Message, 24); tray.Text = Limit($"zcbot Windows Node - {status.Message}", 63); var oldIcon = tray.Icon; tray.Icon = TrayIconFactory.Create(status.State); @@ -279,4 +279,12 @@ internal sealed class TrayApplicationContext : ApplicationContext private static string Limit(string value, int length) => value.Length <= length ? value : value[..length]; + + private static string CompactMenuText(string value, int length) + { + var singleLine = value.Replace('\r', ' ').Replace('\n', ' ').Trim(); + return singleLine.Length <= length + ? singleLine + : singleLine[..(length - 1)] + "…"; + } }