zcbot/windows-node/Zcbot.WindowsNode/Presentation/MainWindow.xaml

454 lines
32 KiB
XML

<Window x:Class="Zcbot.WindowsNode.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="zcbot Windows Node"
Icon="pack://application:,,,/Zcbot.WindowsNode;component/Assets/zcbot.ico"
Width="1040"
Height="720"
MinWidth="760"
MinHeight="560"
WindowStartupLocation="CenterScreen">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="210" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Background="{StaticResource SidebarBrush}" Padding="18,26">
<DockPanel>
<StackPanel DockPanel.Dock="Top">
<Grid Margin="4,0,4,24">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border Width="34" Height="34" CornerRadius="9" Background="#FF1C4A42">
<TextBlock Text="Z" Foreground="#FF99F6E4" FontSize="18"
FontWeight="Bold" HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<StackPanel Grid.Column="1" VerticalAlignment="Center">
<TextBlock Text="zcbot" Foreground="White" FontSize="19" FontWeight="SemiBold" />
<TextBlock Text="Windows Node" Foreground="#FF9EB8B1" FontSize="11" />
</StackPanel>
</Grid>
<TextBlock Text="管理" Foreground="#FF78958D" FontSize="11"
FontWeight="SemiBold" Margin="12,0,0,6" />
<ToggleButton Content="节点概览"
Command="{Binding ShowOverviewCommand}"
IsChecked="{Binding IsOverviewPage, Mode=OneWay}" />
<ToggleButton Content="专业软件"
Command="{Binding ShowSoftwareCommand}"
IsChecked="{Binding IsSoftwarePage, Mode=OneWay}" />
<ToggleButton Content="本机任务"
Command="{Binding ShowJobsCommand}"
IsChecked="{Binding IsJobsPage, Mode=OneWay}" />
<ToggleButton Content="运行设置"
Command="{Binding ShowSettingsCommand}"
IsChecked="{Binding IsSettingsPage, Mode=OneWay}" />
</StackPanel>
<Button DockPanel.Dock="Bottom"
Content="隐藏到托盘"
Command="{Binding HideCommand}"
Margin="0"
Style="{StaticResource SidebarButtonStyle}" />
</DockPanel>
</Border>
<Grid Grid.Column="1" Margin="{StaticResource PagePadding}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Margin="0,0,0,22">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel>
<TextBlock x:Name="PageTitleText"
Text="{Binding PageTitle}"
FontSize="27"
FontWeight="SemiBold" />
<TextBlock Text="Windows Node 在后台安全接收并执行专业软件任务。"
Foreground="{StaticResource MutedTextBrush}" Margin="0,5,0,0" />
</StackPanel>
<Border Grid.Column="1" Background="{StaticResource SurfaceBrush}"
BorderBrush="{StaticResource BorderBrush}" BorderThickness="1"
CornerRadius="16" Padding="11,6" VerticalAlignment="Center">
<StackPanel Orientation="Horizontal">
<Ellipse Width="8" Height="8" Margin="0,0,7,0">
<Ellipse.Style>
<Style TargetType="Ellipse">
<Setter Property="Fill" Value="{StaticResource NeutralBrush}" />
<Style.Triggers>
<DataTrigger Binding="{Binding StatusTone}" Value="success">
<Setter Property="Fill" Value="{StaticResource SuccessBrush}" />
</DataTrigger>
<DataTrigger Binding="{Binding StatusTone}" Value="warning">
<Setter Property="Fill" Value="{StaticResource WarningBrush}" />
</DataTrigger>
<DataTrigger Binding="{Binding StatusTone}" Value="error">
<Setter Property="Fill" Value="{StaticResource ErrorBrush}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
<TextBlock Text="{Binding StatusText}" FontSize="12" FontWeight="SemiBold" />
</StackPanel>
</Border>
</Grid>
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Disabled" Padding="0,0,8,0">
<Grid>
<StackPanel x:Name="OverviewPage"
Visibility="{Binding IsOverviewPage, Converter={StaticResource BooleanToVisibilityConverter}}">
<Border Style="{StaticResource CardBorderStyle}"
Margin="0,0,0,16">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border CornerRadius="3" Margin="0,0,0,0">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="{StaticResource NeutralBrush}" />
<Style.Triggers>
<DataTrigger Binding="{Binding StatusTone}" Value="success">
<Setter Property="Background" Value="{StaticResource SuccessBrush}" />
</DataTrigger>
<DataTrigger Binding="{Binding StatusTone}" Value="warning">
<Setter Property="Background" Value="{StaticResource WarningBrush}" />
</DataTrigger>
<DataTrigger Binding="{Binding StatusTone}" Value="error">
<Setter Property="Background" Value="{StaticResource ErrorBrush}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
<StackPanel Grid.Column="1" Margin="18,0,0,0">
<TextBlock Text="当前状态" Foreground="{StaticResource MutedTextBrush}" />
<TextBlock Text="{Binding StatusText}" FontSize="24" FontWeight="SemiBold" Margin="0,5,0,4" />
<TextBlock Text="{Binding StatusDetail}" TextWrapping="Wrap" />
<Separator Margin="0,18" Background="{StaticResource BorderBrush}" />
<TextBlock Text="节点身份" FontWeight="SemiBold" Margin="0,0,0,8" />
<TextBlock Text="{Binding IdentityText}" TextWrapping="Wrap" />
<WrapPanel Margin="0,18,0,0"
Visibility="{Binding IsRegistered, Converter={StaticResource BooleanToVisibilityConverter}}">
<Button Content="立即重连"
Command="{Binding ReconnectCommand}"
Style="{StaticResource PrimaryButtonStyle}" />
<Button Content="清除本机身份"
Command="{Binding ResetIdentityCommand}"
Style="{StaticResource DangerButtonStyle}" />
<Button Content="复制诊断信息"
Command="{Binding CopyDiagnosticsCommand}" />
</WrapPanel>
</StackPanel>
</Grid>
</Border>
<Border Style="{StaticResource CardBorderStyle}"
Visibility="{Binding IsRegistrationVisible, Converter={StaticResource BooleanToVisibilityConverter}}">
<StackPanel MaxWidth="660" HorizontalAlignment="Left">
<TextBlock Text="首次注册" Style="{StaticResource SectionTitleStyle}" />
<TextBlock Text="从 zcbot 管理后台生成一次性注册码;成功注册后注册码立即失效。"
Foreground="{StaticResource MutedTextBrush}"
TextWrapping="Wrap" Margin="0,6,0,18" />
<TextBlock Text="zcbot 服务地址" Margin="0,0,0,5" />
<TextBox Text="{Binding ServerUrl, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Text="节点名称" Margin="0,14,0,5" />
<TextBox Text="{Binding NodeName, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Text="一次性注册码" Margin="0,14,0,5" />
<PasswordBox x:Name="EnrollmentCodeBox"
PasswordChanged="EnrollmentCodeBox_OnPasswordChanged" />
<Button Content="注册并连接"
Command="{Binding RegisterCommand}"
Style="{StaticResource PrimaryButtonStyle}"
HorizontalAlignment="Left"
Margin="0,18,0,0" />
<TextBlock Text="Node Token 使用 Windows DPAPI 加密保存,不在界面显示。"
Foreground="{StaticResource MutedTextBrush}"
TextWrapping="Wrap" Margin="0,14,0,0" />
</StackPanel>
</Border>
</StackPanel>
<StackPanel x:Name="SoftwarePage"
Visibility="{Binding IsSoftwarePage, Converter={StaticResource BooleanToVisibilityConverter}}">
<Grid Margin="0,0,0,14">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel DockPanel.Dock="Left">
<TextBlock Text="本机专业软件" Style="{StaticResource SectionTitleStyle}" />
<TextBlock Text="应用位置与各自的 Python 运行环境相互独立。"
Foreground="{StaticResource MutedTextBrush}"
Margin="0,4,0,0" />
</StackPanel>
<WrapPanel Grid.Column="1" HorizontalAlignment="Right">
<Button Content="重新检测" Command="{Binding SoftwarePage.RefreshCommand}" />
<Button Content="取消安装"
Command="{Binding SoftwarePage.CancelInstallCommand}"
Visibility="{Binding SoftwarePage.IsInstalling, Converter={StaticResource BooleanToVisibilityConverter}}" />
</WrapPanel>
</Grid>
<ProgressBar Height="3" IsIndeterminate="True" Margin="0,0,0,10"
Visibility="{Binding SoftwarePage.IsBusy, Converter={StaticResource BooleanToVisibilityConverter}}" />
<TextBlock Text="{Binding SoftwarePage.Message}"
Foreground="{StaticResource PrimaryBrush}"
TextWrapping="Wrap"
Margin="0,0,0,14" />
<ItemsControl ItemsSource="{Binding SoftwarePage.Cards}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Style="{StaticResource CardBorderStyle}"
Margin="0,0,0,14">
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding DisplayName}"
FontSize="19"
FontWeight="SemiBold"
VerticalAlignment="Center" />
<Border Grid.Column="1" CornerRadius="12" Padding="9,4">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="{StaticResource ErrorSurfaceBrush}" />
<Style.Triggers>
<DataTrigger Binding="{Binding LocationAvailable}" Value="True">
<Setter Property="Background" Value="{StaticResource SuccessSurfaceBrush}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBlock FontSize="11" FontWeight="SemiBold">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="未检测到" />
<Setter Property="Foreground" Value="{StaticResource ErrorBrush}" />
<Style.Triggers>
<DataTrigger Binding="{Binding LocationAvailable}" Value="True">
<Setter Property="Text" Value="已检测" />
<Setter Property="Foreground" Value="{StaticResource SuccessBrush}" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Border>
</Grid>
<TextBox Text="{Binding LocationText, Mode=OneWay}"
IsReadOnly="True"
Margin="0,12,0,8" />
<TextBlock Text="{Binding StatusText}"
Foreground="{StaticResource MutedTextBrush}"
TextWrapping="Wrap" />
<WrapPanel Margin="0,16,0,0">
<Button Content="选择位置" Command="{Binding ChooseLocationCommand}" />
<Button Content="自动检测" Command="{Binding ClearLocationCommand}" />
<Button Content="安装 / 更新环境"
Command="{Binding InstallRuntimeCommand}"
Style="{StaticResource PrimaryButtonStyle}" />
</WrapPanel>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Border Style="{StaticResource CardBorderStyle}"
Visibility="{Binding AcceptancePage.IsAvailable, Converter={StaticResource BooleanToVisibilityConverter}}">
<StackPanel>
<TextBlock Text="ANSYS Mechanical 真机验收"
Style="{StaticResource SectionTitleStyle}" />
<TextBlock Text="使用内置标准试件验证完整进程树取消、连续 20 次真实静力求解和结果释放。"
Foreground="{StaticResource MutedTextBrush}"
TextWrapping="Wrap"
Margin="0,6,0,12" />
<ProgressBar Height="3"
IsIndeterminate="True"
Margin="0,0,0,12"
Visibility="{Binding AcceptancePage.IsRunning, Converter={StaticResource BooleanToVisibilityConverter}}" />
<TextBlock Text="{Binding AcceptancePage.Message}"
TextWrapping="Wrap">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="{StaticResource MutedTextBrush}" />
<Style.Triggers>
<DataTrigger Binding="{Binding AcceptancePage.Tone}" Value="success">
<Setter Property="Foreground" Value="{StaticResource SuccessBrush}" />
</DataTrigger>
<DataTrigger Binding="{Binding AcceptancePage.Tone}" Value="warning">
<Setter Property="Foreground" Value="{StaticResource WarningBrush}" />
</DataTrigger>
<DataTrigger Binding="{Binding AcceptancePage.Tone}" Value="error">
<Setter Property="Foreground" Value="{StaticResource ErrorBrush}" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<WrapPanel Margin="0,16,0,0">
<Button Content="运行内置基准验收"
Command="{Binding AcceptancePage.RunCommand}"
Style="{StaticResource PrimaryButtonStyle}" />
<Button Content="停止验收"
Command="{Binding AcceptancePage.CancelCommand}"
Visibility="{Binding AcceptancePage.IsRunning, Converter={StaticResource BooleanToVisibilityConverter}}" />
<Button Content="开启 ANSYS 执行门"
Command="{Binding AcceptancePage.EnableGateCommand}" />
</WrapPanel>
</StackPanel>
</Border>
</StackPanel>
<StackPanel x:Name="JobsPage"
Visibility="{Binding IsJobsPage, Converter={StaticResource BooleanToVisibilityConverter}}">
<Grid Margin="0,0,0,14">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel>
<TextBlock Text="本机任务" Style="{StaticResource SectionTitleStyle}" />
<TextBlock Text="仅显示已派发到本机的任务;断线或重启后仍可查看。"
Foreground="{StaticResource MutedTextBrush}"
Margin="0,4,0,0" />
</StackPanel>
<Button Grid.Column="1"
Content="立即刷新"
Command="{Binding JobPage.RefreshCommand}"
HorizontalAlignment="Right" />
</Grid>
<TextBlock Text="{Binding JobPage.Summary}"
Foreground="{StaticResource PrimaryBrush}"
Margin="0,0,0,12" />
<Border Style="{StaticResource CardBorderStyle}"
Padding="0"
Margin="0,0,0,14">
<DataGrid ItemsSource="{Binding JobPage.Jobs}"
SelectedItem="{Binding JobPage.SelectedJob, Mode=TwoWay}"
AutoGenerateColumns="False"
CanUserAddRows="False"
CanUserDeleteRows="False"
CanUserReorderColumns="False"
CanUserResizeRows="False"
IsReadOnly="True"
SelectionMode="Single"
SelectionUnit="FullRow"
HeadersVisibility="Column"
GridLinesVisibility="Horizontal"
BorderThickness="0"
Background="Transparent"
MinHeight="180"
MaxHeight="340">
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="Foreground" Value="{StaticResource TextBrush}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Tone}" Value="success">
<Setter Property="Foreground" Value="{StaticResource SuccessBrush}" />
</DataTrigger>
<DataTrigger Binding="{Binding Tone}" Value="error">
<Setter Property="Foreground" Value="{StaticResource ErrorBrush}" />
</DataTrigger>
<DataTrigger Binding="{Binding Tone}" Value="neutral">
<Setter Property="Foreground" Value="{StaticResource MutedTextBrush}" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="状态" Binding="{Binding StageText}" Width="95" />
<DataGridTextColumn Header="任务" Binding="{Binding Title}" Width="*" MinWidth="150" />
<DataGridTextColumn Header="输入" Binding="{Binding InputFilename}" Width="150" />
<DataGridTextColumn Header="进度" Binding="{Binding ProgressText}" Width="90" />
<DataGridTextColumn Header="接收时间" Binding="{Binding AcceptedAtText}" Width="105" />
<DataGridTextColumn Header="Job ID" Binding="{Binding ShortId}" Width="80" />
</DataGrid.Columns>
</DataGrid>
</Border>
<Border Style="{StaticResource CardBorderStyle}">
<StackPanel>
<TextBlock Text="任务详情" Style="{StaticResource SectionTitleStyle}" />
<TextBlock Text="{Binding JobPage.SelectedDetail}"
TextWrapping="Wrap"
Margin="0,12,0,0" />
</StackPanel>
</Border>
</StackPanel>
<StackPanel x:Name="SettingsPage"
Visibility="{Binding IsSettingsPage, Converter={StaticResource BooleanToVisibilityConverter}}">
<Border Style="{StaticResource CardBorderStyle}"
Margin="0,0,0,16">
<StackPanel>
<TextBlock Text="后台运行" Style="{StaticResource SectionTitleStyle}" />
<CheckBox Content="登录 Windows 后自动启动节点"
IsChecked="{Binding IsStartupEnabled, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,16,0,4" />
<TextBlock Text="开机启动保存到当前 Windows 账号,不安装系统服务或计划任务。"
Foreground="{StaticResource MutedTextBrush}"
TextWrapping="Wrap" />
</StackPanel>
</Border>
<Border Style="{StaticResource CardBorderStyle}">
<StackPanel>
<TextBlock Text="数据目录" Style="{StaticResource SectionTitleStyle}" />
<TextBox x:Name="DataRootText"
Text="{Binding DataRootPage.CurrentRoot, Mode=OneWay}"
IsReadOnly="True"
Margin="0,14,0,0" />
<TextBlock Text="保存节点身份、任务、Workspace 和受管 runtime。迁移前需要检查活动任务、磁盘和文件校验。"
Foreground="{StaticResource MutedTextBrush}"
TextWrapping="Wrap" Margin="0,10,0,16" />
<TextBlock Text="{Binding DataRootPage.Status}"
Foreground="{StaticResource MutedTextBrush}"
TextWrapping="Wrap"
Margin="0,0,0,16" />
<ProgressBar Height="3"
IsIndeterminate="True"
Margin="0,0,0,16"
Visibility="{Binding DataRootPage.IsMigrating, Converter={StaticResource BooleanToVisibilityConverter}}" />
<WrapPanel>
<Button Content="更改并迁移"
Command="{Binding DataRootPage.ChangeCommand}"
Style="{StaticResource PrimaryButtonStyle}" />
<Button Content="打开目录"
Command="{Binding DataRootPage.OpenCommand}" />
</WrapPanel>
</StackPanel>
</Border>
</StackPanel>
</Grid>
</ScrollViewer>
<StackPanel Grid.Row="2" Margin="0,16,0,0">
<Border Background="{StaticResource SurfaceMutedBrush}"
BorderBrush="{StaticResource BorderBrush}"
BorderThickness="1"
CornerRadius="8"
Padding="11,8"
Margin="0,0,0,8"
Visibility="{Binding HasOperationMessage, Converter={StaticResource BooleanToVisibilityConverter}}">
<TextBlock Text="{Binding OperationMessage}"
Foreground="{StaticResource PrimaryBrush}"
TextWrapping="Wrap" />
</Border>
<TextBlock Text="关闭窗口不会退出节点;可从系统托盘再次打开。"
Foreground="{StaticResource MutedTextBrush}" FontSize="12" />
</StackPanel>
</Grid>
</Grid>
</Window>