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 的独立运行环境;只装有部分专业软件的节点不再需要处理无关软件。
|
- Windows Node 现在可在“专业软件”区域自动检测或手工指定应用位置,并分别安装、更新 Origin、ANSYS、Blender 的独立运行环境;只装有部分专业软件的节点不再需要处理无关软件。
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -187,7 +187,8 @@ class WindowsNodeSourceTests(unittest.TestCase):
|
||||||
|
|
||||||
def test_configuration_window_is_resizable_and_dpi_safe(self) -> None:
|
def test_configuration_window_is_resizable_and_dpi_safe(self) -> None:
|
||||||
form = (PROJECT / "ConfigurationForm.cs").read_text(encoding="utf-8")
|
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("FormBorderStyle.Sizable", form)
|
||||||
self.assertIn("AutoScaleMode.Dpi", form)
|
self.assertIn("AutoScaleMode.Dpi", form)
|
||||||
self.assertIn("AutoScroll = true", form)
|
self.assertIn("AutoScroll = true", form)
|
||||||
|
|
@ -196,7 +197,15 @@ class WindowsNodeSourceTests(unittest.TestCase):
|
||||||
self.assertIn("成功注册一次后立即失效", form)
|
self.assertIn("成功注册一次后立即失效", form)
|
||||||
self.assertIn("CreateCard", form)
|
self.assertIn("CreateCard", form)
|
||||||
self.assertIn("注册并连接", 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("CreateSubsectionTitle(\"能力概览\")", form)
|
||||||
self.assertIn("panel.SetColumnSpan(path, 2)", form)
|
self.assertIn("panel.SetColumnSpan(path, 2)", form)
|
||||||
self.assertIn("BorderedTableLayoutPanel", form)
|
self.assertIn("BorderedTableLayoutPanel", form)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ namespace Zcbot.WindowsNode;
|
||||||
|
|
||||||
internal sealed class ConfigurationForm : Form
|
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 server = CreateTextBox("http://127.0.0.1:8765");
|
||||||
private readonly TextBox nodeName = CreateTextBox(Environment.MachineName.ToLowerInvariant());
|
private readonly TextBox nodeName = CreateTextBox(Environment.MachineName.ToLowerInvariant());
|
||||||
|
|
@ -76,8 +76,8 @@ internal sealed class ConfigurationForm : Form
|
||||||
adapters = NodeAdapterRegistry.CreateDefault(jobInbox);
|
adapters = NodeAdapterRegistry.CreateDefault(jobInbox);
|
||||||
Text = "zcbot Windows Node";
|
Text = "zcbot Windows Node";
|
||||||
AutoScaleMode = AutoScaleMode.Dpi;
|
AutoScaleMode = AutoScaleMode.Dpi;
|
||||||
ClientSize = new Size(1100, 760);
|
ClientSize = new Size(1320, 820);
|
||||||
MinimumSize = new Size(900, 680);
|
MinimumSize = new Size(1040, 700);
|
||||||
StartPosition = FormStartPosition.CenterScreen;
|
StartPosition = FormStartPosition.CenterScreen;
|
||||||
Font = new Font("Microsoft YaHei UI", 9);
|
Font = new Font("Microsoft YaHei UI", 9);
|
||||||
FormBorderStyle = FormBorderStyle.Sizable;
|
FormBorderStyle = FormBorderStyle.Sizable;
|
||||||
|
|
@ -99,14 +99,14 @@ internal sealed class ConfigurationForm : Form
|
||||||
|
|
||||||
var page = new TableLayoutPanel
|
var page = new TableLayoutPanel
|
||||||
{
|
{
|
||||||
AutoSize = true,
|
Dock = DockStyle.Fill,
|
||||||
AutoSizeMode = AutoSizeMode.GrowAndShrink,
|
|
||||||
Dock = DockStyle.Top,
|
|
||||||
ColumnCount = 1,
|
ColumnCount = 1,
|
||||||
RowCount = 8,
|
RowCount = 2,
|
||||||
BackColor = BackColor,
|
BackColor = BackColor,
|
||||||
};
|
};
|
||||||
page.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
|
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);
|
shell.Controls.Add(page, 1, 0);
|
||||||
|
|
||||||
var heading = new TableLayoutPanel
|
var heading = new TableLayoutPanel
|
||||||
|
|
@ -114,7 +114,7 @@ internal sealed class ConfigurationForm : Form
|
||||||
AutoSize = true,
|
AutoSize = true,
|
||||||
Dock = DockStyle.Top,
|
Dock = DockStyle.Top,
|
||||||
ColumnCount = 1,
|
ColumnCount = 1,
|
||||||
Margin = new Padding(4, 0, 4, 22),
|
Margin = new Padding(4, 0, 4, 16),
|
||||||
};
|
};
|
||||||
heading.Controls.Add(new Label
|
heading.Controls.Add(new Label
|
||||||
{
|
{
|
||||||
|
|
@ -136,6 +136,21 @@ internal sealed class ConfigurationForm : Form
|
||||||
heading.Controls.Add(headingHint);
|
heading.Controls.Add(headingHint);
|
||||||
page.Controls.Add(heading);
|
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 statusCard = CreateCard();
|
||||||
var statusHeader = new TableLayoutPanel
|
var statusHeader = new TableLayoutPanel
|
||||||
{
|
{
|
||||||
|
|
@ -159,7 +174,7 @@ internal sealed class ConfigurationForm : Form
|
||||||
resetActions.Controls.Add(copyDiagnostics);
|
resetActions.Controls.Add(copyDiagnostics);
|
||||||
resetActions.Controls.Add(resetIdentity);
|
resetActions.Controls.Add(resetIdentity);
|
||||||
statusCard.Controls.Add(resetActions);
|
statusCard.Controls.Add(resetActions);
|
||||||
page.Controls.Add(statusCard);
|
overviewPage.Controls.Add(statusCard);
|
||||||
|
|
||||||
var softwareCard = CreateCard();
|
var softwareCard = CreateCard();
|
||||||
softwareCard.Controls.Add(CreateSectionTitle("专业软件"));
|
softwareCard.Controls.Add(CreateSectionTitle("专业软件"));
|
||||||
|
|
@ -169,7 +184,7 @@ internal sealed class ConfigurationForm : Form
|
||||||
{
|
{
|
||||||
softwareCard.Controls.Add(CreateSoftwarePanel(definition));
|
softwareCard.Controls.Add(CreateSoftwarePanel(definition));
|
||||||
}
|
}
|
||||||
page.Controls.Add(softwareCard);
|
softwarePage.Controls.Add(softwareCard);
|
||||||
|
|
||||||
ansysAcceptanceCard = CreateCard();
|
ansysAcceptanceCard = CreateCard();
|
||||||
ansysAcceptanceCard.Controls.Add(CreateSectionTitle("ANSYS Mechanical 真机验收"));
|
ansysAcceptanceCard.Controls.Add(CreateSectionTitle("ANSYS Mechanical 真机验收"));
|
||||||
|
|
@ -181,7 +196,7 @@ internal sealed class ConfigurationForm : Form
|
||||||
acceptanceActions.Controls.Add(runAnsysAcceptance);
|
acceptanceActions.Controls.Add(runAnsysAcceptance);
|
||||||
acceptanceActions.Controls.Add(enableAnsysGate);
|
acceptanceActions.Controls.Add(enableAnsysGate);
|
||||||
ansysAcceptanceCard.Controls.Add(acceptanceActions);
|
ansysAcceptanceCard.Controls.Add(acceptanceActions);
|
||||||
page.Controls.Add(ansysAcceptanceCard);
|
softwarePage.Controls.Add(ansysAcceptanceCard);
|
||||||
|
|
||||||
var jobsCard = CreateCard();
|
var jobsCard = CreateCard();
|
||||||
jobsCard.Controls.Add(CreateSectionTitle("本机任务"));
|
jobsCard.Controls.Add(CreateSectionTitle("本机任务"));
|
||||||
|
|
@ -190,7 +205,7 @@ internal sealed class ConfigurationForm : Form
|
||||||
jobsCard.Controls.Add(jobSummary);
|
jobsCard.Controls.Add(jobSummary);
|
||||||
jobsCard.Controls.Add(jobGrid);
|
jobsCard.Controls.Add(jobGrid);
|
||||||
jobsCard.Controls.Add(jobDetail);
|
jobsCard.Controls.Add(jobDetail);
|
||||||
page.Controls.Add(jobsCard);
|
jobsPage.Controls.Add(jobsCard);
|
||||||
|
|
||||||
registrationCard = CreateCard();
|
registrationCard = CreateCard();
|
||||||
registrationCard.Controls.Add(CreateSectionTitle("首次注册"));
|
registrationCard.Controls.Add(CreateSectionTitle("首次注册"));
|
||||||
|
|
@ -202,7 +217,7 @@ internal sealed class ConfigurationForm : Form
|
||||||
var registerActions = CreateActions();
|
var registerActions = CreateActions();
|
||||||
registerActions.Controls.Add(register);
|
registerActions.Controls.Add(register);
|
||||||
registrationCard.Controls.Add(registerActions);
|
registrationCard.Controls.Add(registerActions);
|
||||||
page.Controls.Add(registrationCard);
|
overviewPage.Controls.Add(registrationCard);
|
||||||
|
|
||||||
var runtimeCard = CreateCard();
|
var runtimeCard = CreateCard();
|
||||||
runtimeCard.Controls.Add(CreateSectionTitle("运行设置"));
|
runtimeCard.Controls.Add(CreateSectionTitle("运行设置"));
|
||||||
|
|
@ -219,12 +234,12 @@ internal sealed class ConfigurationForm : Form
|
||||||
runtimeCard.Controls.Add(dataRootStatus);
|
runtimeCard.Controls.Add(dataRootStatus);
|
||||||
runtimeCard.Controls.Add(CreateHint(
|
runtimeCard.Controls.Add(CreateHint(
|
||||||
"关闭此窗口后,节点仍在系统托盘运行。右键托盘图标可以立即重连或退出。"));
|
"关闭此窗口后,节点仍在系统托盘运行。右键托盘图标可以立即重连或退出。"));
|
||||||
page.Controls.Add(runtimeCard);
|
settingsPage.Controls.Add(runtimeCard);
|
||||||
|
|
||||||
var securityNote = CreateHint(
|
var securityNote = CreateHint(
|
||||||
"安全说明:Node Token 由 Windows DPAPI 加密保存,不在界面显示,也不会写入日志。");
|
"安全说明:Node Token 由 Windows DPAPI 加密保存,不在界面显示,也不会写入日志。");
|
||||||
securityNote.Margin = new Padding(4, 8, 4, 0);
|
securityNote.Margin = new Padding(4, 8, 4, 0);
|
||||||
page.Controls.Add(securityNote);
|
settingsPage.Controls.Add(securityNote);
|
||||||
|
|
||||||
register.Click += async (_, _) => await RegisterAsync();
|
register.Click += async (_, _) => await RegisterAsync();
|
||||||
reconnect.Click += (_, _) => ReconnectRequested?.Invoke();
|
reconnect.Click += (_, _) => ReconnectRequested?.Invoke();
|
||||||
|
|
@ -956,6 +971,31 @@ internal sealed class ConfigurationForm : Form
|
||||||
return card;
|
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()
|
private static Label CreateSectionTitle(string text) => new()
|
||||||
{
|
{
|
||||||
Text = text,
|
Text = text,
|
||||||
|
|
@ -1280,4 +1320,42 @@ internal sealed class ConfigurationForm : Form
|
||||||
Math.Max(0, ClientSize.Height - 1));
|
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