feat(node): organize console into tabs
This commit is contained in:
parent
2a7c6a0fb2
commit
bf6f8aa1f6
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
- 修复国际旗舰模型输出思考过程时偶尔无法及时停止的问题;即使模型暂时没有返回新的流式片段,点击“停止”也会迅速中断当前回答。
|
||||
|
||||
- Windows Node 主窗口重新整理为更宽、更清晰的桌面控制台:节点状态、能力概览和维护操作分层展示,专业软件改为独立配置行和通栏地址框,Origin、ANSYS、Blender 均可手工选择位置;软件卡的操作按钮在高 DPI 下也会完整显示,Origin 自动检测也会在 COM 路径无效时继续查找注册表和标准安装目录。
|
||||
- Windows Node 主窗口重新整理为更宽、更清晰的桌面控制台:节点概览、专业软件、本机任务和运行设置改用独立标签页,节点状态、能力概览和维护操作分层展示;专业软件使用独立配置行和通栏地址框,Origin、ANSYS、Blender 均可手工选择位置,软件卡的操作按钮在高 DPI 下也会完整显示;Origin 自动检测也会在 COM 路径无效时继续查找注册表和标准安装目录。
|
||||
|
||||
- Windows Node 现在可在“专业软件”区域自动检测或手工指定应用位置,并分别安装、更新 Origin、ANSYS、Blender 的独立运行环境;只装有部分专业软件的节点不再需要处理无关软件。
|
||||
|
||||
|
|
|
|||
|
|
@ -187,7 +187,8 @@ 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(1100, 760)", form)
|
||||
self.assertIn("ClientSize = new Size(1320, 820)", form)
|
||||
self.assertIn("MinimumSize = new Size(1040, 700)", form)
|
||||
self.assertIn("FormBorderStyle.Sizable", form)
|
||||
self.assertIn("AutoScaleMode.Dpi", form)
|
||||
self.assertIn("AutoScroll = true", form)
|
||||
|
|
@ -196,7 +197,15 @@ class WindowsNodeSourceTests(unittest.TestCase):
|
|||
self.assertIn("成功注册一次后立即失效", form)
|
||||
self.assertIn("CreateCard", form)
|
||||
self.assertIn("注册并连接", form)
|
||||
self.assertIn("ContentWidth = 1020", form)
|
||||
self.assertIn("ContentWidth = 1180", form)
|
||||
self.assertIn('AddTab(tabs, "节点概览")', form)
|
||||
self.assertIn('AddTab(tabs, "专业软件")', form)
|
||||
self.assertIn('AddTab(tabs, "本机任务")', form)
|
||||
self.assertIn('AddTab(tabs, "运行设置")', form)
|
||||
self.assertIn("SizeMode = TabSizeMode.Fixed", form)
|
||||
self.assertIn("new NavigationTabControl", form)
|
||||
self.assertIn("DrawMode = TabDrawMode.OwnerDrawFixed", form)
|
||||
self.assertIn("tab.Controls.Add(content)", form)
|
||||
self.assertIn("CreateSubsectionTitle(\"能力概览\")", form)
|
||||
self.assertIn("panel.SetColumnSpan(path, 2)", form)
|
||||
self.assertIn("BorderedTableLayoutPanel", form)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace Zcbot.WindowsNode;
|
|||
|
||||
internal sealed class ConfigurationForm : Form
|
||||
{
|
||||
private const int ContentWidth = 1020;
|
||||
private const int ContentWidth = 1180;
|
||||
|
||||
private readonly TextBox server = CreateTextBox("http://127.0.0.1:8765");
|
||||
private readonly TextBox nodeName = CreateTextBox(Environment.MachineName.ToLowerInvariant());
|
||||
|
|
@ -76,8 +76,8 @@ internal sealed class ConfigurationForm : Form
|
|||
adapters = NodeAdapterRegistry.CreateDefault(jobInbox);
|
||||
Text = "zcbot Windows Node";
|
||||
AutoScaleMode = AutoScaleMode.Dpi;
|
||||
ClientSize = new Size(1100, 760);
|
||||
MinimumSize = new Size(900, 680);
|
||||
ClientSize = new Size(1320, 820);
|
||||
MinimumSize = new Size(1040, 700);
|
||||
StartPosition = FormStartPosition.CenterScreen;
|
||||
Font = new Font("Microsoft YaHei UI", 9);
|
||||
FormBorderStyle = FormBorderStyle.Sizable;
|
||||
|
|
@ -99,14 +99,14 @@ internal sealed class ConfigurationForm : Form
|
|||
|
||||
var page = new TableLayoutPanel
|
||||
{
|
||||
AutoSize = true,
|
||||
AutoSizeMode = AutoSizeMode.GrowAndShrink,
|
||||
Dock = DockStyle.Top,
|
||||
Dock = DockStyle.Fill,
|
||||
ColumnCount = 1,
|
||||
RowCount = 8,
|
||||
RowCount = 2,
|
||||
BackColor = BackColor,
|
||||
};
|
||||
page.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
|
||||
page.RowStyles.Add(new RowStyle(SizeType.AutoSize));
|
||||
page.RowStyles.Add(new RowStyle(SizeType.Percent, 100));
|
||||
shell.Controls.Add(page, 1, 0);
|
||||
|
||||
var heading = new TableLayoutPanel
|
||||
|
|
@ -114,7 +114,7 @@ internal sealed class ConfigurationForm : Form
|
|||
AutoSize = true,
|
||||
Dock = DockStyle.Top,
|
||||
ColumnCount = 1,
|
||||
Margin = new Padding(4, 0, 4, 22),
|
||||
Margin = new Padding(4, 0, 4, 16),
|
||||
};
|
||||
heading.Controls.Add(new Label
|
||||
{
|
||||
|
|
@ -136,6 +136,21 @@ internal sealed class ConfigurationForm : Form
|
|||
heading.Controls.Add(headingHint);
|
||||
page.Controls.Add(heading);
|
||||
|
||||
var tabs = new NavigationTabControl
|
||||
{
|
||||
Dock = DockStyle.Fill,
|
||||
Margin = new Padding(0),
|
||||
Font = new Font("Microsoft YaHei UI", 9, FontStyle.Bold),
|
||||
ItemSize = new Size(142, 38),
|
||||
Padding = new Point(18, 6),
|
||||
SizeMode = TabSizeMode.Fixed,
|
||||
};
|
||||
var overviewPage = AddTab(tabs, "节点概览");
|
||||
var softwarePage = AddTab(tabs, "专业软件");
|
||||
var jobsPage = AddTab(tabs, "本机任务");
|
||||
var settingsPage = AddTab(tabs, "运行设置");
|
||||
page.Controls.Add(tabs, 0, 1);
|
||||
|
||||
var statusCard = CreateCard();
|
||||
var statusHeader = new TableLayoutPanel
|
||||
{
|
||||
|
|
@ -159,7 +174,7 @@ internal sealed class ConfigurationForm : Form
|
|||
resetActions.Controls.Add(copyDiagnostics);
|
||||
resetActions.Controls.Add(resetIdentity);
|
||||
statusCard.Controls.Add(resetActions);
|
||||
page.Controls.Add(statusCard);
|
||||
overviewPage.Controls.Add(statusCard);
|
||||
|
||||
var softwareCard = CreateCard();
|
||||
softwareCard.Controls.Add(CreateSectionTitle("专业软件"));
|
||||
|
|
@ -169,7 +184,7 @@ internal sealed class ConfigurationForm : Form
|
|||
{
|
||||
softwareCard.Controls.Add(CreateSoftwarePanel(definition));
|
||||
}
|
||||
page.Controls.Add(softwareCard);
|
||||
softwarePage.Controls.Add(softwareCard);
|
||||
|
||||
ansysAcceptanceCard = CreateCard();
|
||||
ansysAcceptanceCard.Controls.Add(CreateSectionTitle("ANSYS Mechanical 真机验收"));
|
||||
|
|
@ -181,7 +196,7 @@ internal sealed class ConfigurationForm : Form
|
|||
acceptanceActions.Controls.Add(runAnsysAcceptance);
|
||||
acceptanceActions.Controls.Add(enableAnsysGate);
|
||||
ansysAcceptanceCard.Controls.Add(acceptanceActions);
|
||||
page.Controls.Add(ansysAcceptanceCard);
|
||||
softwarePage.Controls.Add(ansysAcceptanceCard);
|
||||
|
||||
var jobsCard = CreateCard();
|
||||
jobsCard.Controls.Add(CreateSectionTitle("本机任务"));
|
||||
|
|
@ -190,7 +205,7 @@ internal sealed class ConfigurationForm : Form
|
|||
jobsCard.Controls.Add(jobSummary);
|
||||
jobsCard.Controls.Add(jobGrid);
|
||||
jobsCard.Controls.Add(jobDetail);
|
||||
page.Controls.Add(jobsCard);
|
||||
jobsPage.Controls.Add(jobsCard);
|
||||
|
||||
registrationCard = CreateCard();
|
||||
registrationCard.Controls.Add(CreateSectionTitle("首次注册"));
|
||||
|
|
@ -202,7 +217,7 @@ internal sealed class ConfigurationForm : Form
|
|||
var registerActions = CreateActions();
|
||||
registerActions.Controls.Add(register);
|
||||
registrationCard.Controls.Add(registerActions);
|
||||
page.Controls.Add(registrationCard);
|
||||
overviewPage.Controls.Add(registrationCard);
|
||||
|
||||
var runtimeCard = CreateCard();
|
||||
runtimeCard.Controls.Add(CreateSectionTitle("运行设置"));
|
||||
|
|
@ -219,12 +234,12 @@ internal sealed class ConfigurationForm : Form
|
|||
runtimeCard.Controls.Add(dataRootStatus);
|
||||
runtimeCard.Controls.Add(CreateHint(
|
||||
"关闭此窗口后,节点仍在系统托盘运行。右键托盘图标可以立即重连或退出。"));
|
||||
page.Controls.Add(runtimeCard);
|
||||
settingsPage.Controls.Add(runtimeCard);
|
||||
|
||||
var securityNote = CreateHint(
|
||||
"安全说明:Node Token 由 Windows DPAPI 加密保存,不在界面显示,也不会写入日志。");
|
||||
securityNote.Margin = new Padding(4, 8, 4, 0);
|
||||
page.Controls.Add(securityNote);
|
||||
settingsPage.Controls.Add(securityNote);
|
||||
|
||||
register.Click += async (_, _) => await RegisterAsync();
|
||||
reconnect.Click += (_, _) => ReconnectRequested?.Invoke();
|
||||
|
|
@ -956,6 +971,31 @@ internal sealed class ConfigurationForm : Form
|
|||
return card;
|
||||
}
|
||||
|
||||
private static TableLayoutPanel AddTab(TabControl tabs, string text)
|
||||
{
|
||||
var tab = new TabPage
|
||||
{
|
||||
Text = text,
|
||||
AutoScroll = true,
|
||||
BackColor = Color.FromArgb(246, 248, 252),
|
||||
Padding = new Padding(18, 20, 18, 20),
|
||||
UseVisualStyleBackColor = false,
|
||||
};
|
||||
var content = new TableLayoutPanel
|
||||
{
|
||||
AutoSize = true,
|
||||
AutoSizeMode = AutoSizeMode.GrowAndShrink,
|
||||
Dock = DockStyle.Top,
|
||||
ColumnCount = 1,
|
||||
BackColor = tab.BackColor,
|
||||
Margin = new Padding(0),
|
||||
};
|
||||
content.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
|
||||
tab.Controls.Add(content);
|
||||
tabs.TabPages.Add(tab);
|
||||
return content;
|
||||
}
|
||||
|
||||
private static Label CreateSectionTitle(string text) => new()
|
||||
{
|
||||
Text = text,
|
||||
|
|
@ -1280,4 +1320,42 @@ internal sealed class ConfigurationForm : Form
|
|||
Math.Max(0, ClientSize.Height - 1));
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class NavigationTabControl : TabControl
|
||||
{
|
||||
internal NavigationTabControl()
|
||||
{
|
||||
DrawMode = TabDrawMode.OwnerDrawFixed;
|
||||
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
|
||||
}
|
||||
|
||||
protected override void OnDrawItem(DrawItemEventArgs eventArgs)
|
||||
{
|
||||
var selected = eventArgs.Index == SelectedIndex;
|
||||
var bounds = eventArgs.Bounds;
|
||||
using var background = new SolidBrush(selected
|
||||
? Color.White
|
||||
: Color.FromArgb(241, 245, 249));
|
||||
eventArgs.Graphics.FillRectangle(background, bounds);
|
||||
TextRenderer.DrawText(
|
||||
eventArgs.Graphics,
|
||||
TabPages[eventArgs.Index].Text,
|
||||
Font,
|
||||
bounds,
|
||||
selected ? Color.FromArgb(29, 78, 216) : Color.FromArgb(71, 85, 105),
|
||||
TextFormatFlags.HorizontalCenter
|
||||
| TextFormatFlags.VerticalCenter
|
||||
| TextFormatFlags.SingleLine);
|
||||
if (selected)
|
||||
{
|
||||
using var accent = new SolidBrush(Color.FromArgb(37, 99, 235));
|
||||
eventArgs.Graphics.FillRectangle(
|
||||
accent,
|
||||
bounds.Left + 12,
|
||||
bounds.Bottom - 3,
|
||||
Math.Max(0, bounds.Width - 24),
|
||||
3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue