具备界面基础功能

This commit is contained in:
2026-01-01 22:40:32 +08:00
parent 0c86b4dad3
commit d039559402
81 changed files with 8333 additions and 1905 deletions

View File

@@ -2,15 +2,15 @@
x:Class="SHH.CameraDashboard.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ctrl="clr-namespace:SHH.CameraDashboard"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:SHH.CameraDashboard"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="SHH 视频中控"
Width="1366"
Height="768"
Width="1900"
Height="1030"
Background="{DynamicResource Brush.Bg.Window}"
FontFamily="{StaticResource Font.Normal}"
Foreground="{DynamicResource Brush.Text.Primary}"
Topmost="{Binding IsTopMost}"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
@@ -22,223 +22,341 @@
ResizeBorderThickness="5" />
</WindowChrome.WindowChrome>
<Grid x:Name="RootGrid">
<Grid x:Name="AppLayout">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Border
Background="{DynamicResource Brush.Bg.Window}"
BorderBrush="{DynamicResource Brush.Border}"
BorderThickness="1">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="45" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="5" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border
x:Name="TitleBar"
Grid.Row="0"
Height="32"
Background="{DynamicResource Brush.Bg.Panel}"
BorderBrush="{DynamicResource Brush.Border}"
BorderThickness="0,0,0,1"
MouseDown="OnTitleBarMouseDown">
MouseLeftButtonDown="TitleBar_MouseDown">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel
Grid.Column="0"
Margin="10,0"
Margin="12,0"
VerticalAlignment="Center"
Orientation="Horizontal">
<Button
Width="40"
Click="ToggleSidebar"
Content="≡"
FontSize="18"
<TextBlock
Margin="0,0,8,0"
VerticalAlignment="Center"
Text="📷" />
<TextBlock
VerticalAlignment="Center"
FontSize="12"
FontWeight="Bold"
Style="{StaticResource Btn.Ghost}"
ToolTip="展开/收起侧边栏" />
Text="SHH 视频网关 - 中控台" />
</StackPanel>
<TextBlock
Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="{StaticResource Size.Font.Large}"
FontWeight="Bold"
Foreground="{DynamicResource Brush.Text.Primary}"
IsHitTestVisible="False"
Text="SHH 视频中控平台" />
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
<Button
Command="{Binding OpenWizardCommand}"
Style="{StaticResource Btn.TitleBar}"
ToolTip="向导">
<Path
Width="18"
Height="18"
Data="{StaticResource Icon.Wizard}"
Fill="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}"
Stretch="Uniform" />
</Button>
<StackPanel
Grid.Column="2"
Margin="0,0,10,0"
Orientation="Horizontal">
<Button
Width="40"
Margin="0,0,5,0"
Click="OpenWizard"
Content="🧙‍♂️"
Style="{StaticResource Btn.Ghost}"
ToolTip="打开配置向导" />
Height="30"
Click="BtnTheme_Click"
Style="{StaticResource Btn.TitleBar}"
ToolTip="切换皮肤">
<StackPanel VerticalAlignment="Center" Orientation="Horizontal">
<Path
Width="14"
Height="14"
Data="{StaticResource Icon.Theme}"
Fill="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}"
Stretch="Uniform" />
<Path
Width="8"
Height="8"
Margin="4,2,0,0"
VerticalAlignment="Center"
Data="M7,10L12,15L17,10H7Z"
Fill="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}"
Stretch="Uniform" />
</StackPanel>
<Button.ContextMenu>
<ContextMenu Placement="Bottom">
<MenuItem Command="{Binding SwitchThemeCommand}" CommandParameter="Dark">
<MenuItem.Header>
<TextBlock
Margin="0,1,0,0"
VerticalAlignment="Center"
FontSize="13"
Text="🌚 深色模式 (Dark)" />
</MenuItem.Header>
</MenuItem>
<MenuItem Command="{Binding SwitchThemeCommand}" CommandParameter="Light">
<MenuItem.Header>
<TextBlock
Margin="0,1,0,0"
VerticalAlignment="Center"
FontSize="13"
Text="☀️ 浅色模式 (Light)" />
</MenuItem.Header>
</MenuItem>
</ContextMenu>
</Button.ContextMenu>
</Button>
<Button
Width="40"
Margin="0,0,15,0"
Click="ToggleTheme"
Content="🎨"
Style="{StaticResource Btn.Ghost}"
ToolTip="切换皮肤 (Dark/Light)" />
Command="{Binding ToggleTopMostCommand}"
Style="{StaticResource Btn.TitleBar}"
ToolTip="{Binding TopMostTooltip}">
<Path
Width="16"
Height="16"
Fill="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}"
Stretch="Uniform">
<Path.Style>
<Style TargetType="Path">
<Setter Property="Data" Value="{StaticResource Icon.Pin.Outline}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsTopMost}" Value="True">
<Setter Property="Data" Value="{StaticResource Icon.Pin.Fixed}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Path.Style>
</Path>
</Button>
<Rectangle Width="10" Fill="Transparent" />
<Button
Width="40"
Click="OnMinimize"
Command="{Binding MinimizeCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}"
Content="—"
Style="{StaticResource Btn.Ghost}"
ToolTip="最小化" />
Style="{StaticResource Btn.TitleBar}" />
<Button
Width="40"
Margin="5,0,0,0"
Click="OnClose"
Command="{Binding ToggleMaximizeCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}"
Content="{Binding MaxButtonContent}"
Style="{StaticResource Btn.TitleBar}" />
<Button
Command="{Binding CloseCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}"
Content="✕"
Style="{StaticResource Btn.Danger}"
ToolTip="关闭" />
Style="{StaticResource Btn.TitleBar.Close}" />
</StackPanel>
</Grid>
</Border>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ctrl:CameraListControl
x:Name="Sidebar"
Grid.Column="0"
Width="250" />
<DockPanel Grid.Row="1">
<!-- 左侧摄像头列表 -->
<Border
Grid.Column="0"
Width="1"
HorizontalAlignment="Right"
Background="{DynamicResource Brush.Border}" />
Width="320"
BorderBrush="{DynamicResource Brush.Border}"
BorderThickness="0,0,1,0"
DockPanel.Dock="Left">
<local:CameraList x:Name="CameraList" />
</Border>
<Grid
Grid.Column="1"
<!-- 右侧面板 -->
<Border
Width="500"
Background="{DynamicResource Brush.Bg.Window}"
ClipToBounds="True">
<ctrl:DeviceHomeControl x:Name="DeviceHome" Margin="0" />
BorderBrush="{DynamicResource Brush.Border}"
BorderThickness="1,0,0,0"
DockPanel.Dock="Right"
Visibility="{Binding IsRightPanelVisible, Converter={StaticResource BooleanToVisibilityConverter}}">
<Border
x:Name="RightConfigPanel"
Width="350"
<Border.Resources>
<DataTemplate DataType="{x:Type local:CameraEditViewModel}">
<local:CameraEdit />
</DataTemplate>
<DataTemplate DataType="{x:Type local:CameraPtzViewModel}">
<local:CameraPtz />
</DataTemplate>
<DataTemplate DataType="{x:Type local:CameraImgProcViewModel}">
<local:CameraImgProc />
</DataTemplate>
<DataTemplate DataType="{x:Type local:CameraImageSubscriptionViewModels}">
<local:CameraImageSubscription />
</DataTemplate>
</Border.Resources>
<ContentControl Content="{Binding CurrentRightPanelViewModel}" />
</Border>
<DockPanel>
<local:CameraItemTop DataSource="{Binding ElementName=CameraList, Path=DataContext.SelectedCamera}" DockPanel.Dock="Top" />
<Grid />
</DockPanel>
</DockPanel>
<GridSplitter
Grid.Row="2"
Height="5"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Background="Transparent"
ResizeBehavior="PreviousAndNext"
ResizeDirection="Rows"
ShowsPreview="True" />
<Border
x:Name="BottomLogPanel"
Grid.Row="3"
Background="{DynamicResource Brush.Bg.Panel}"
BorderBrush="{DynamicResource Brush.Border}"
BorderThickness="0,1,0,0">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Height" Value="250" />
<Setter Property="MinHeight" Value="100" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsLogPanelExpanded}" Value="False">
<Setter Property="Height" Value="35" />
<Setter Property="MinHeight" Value="35" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<Grid>
<TabControl
Padding="0"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
Background="Transparent"
BorderThickness="0"
ItemContainerStyle="{DynamicResource Style.TabItem.Modern}">
<TabItem Header="WebAPI 诊断">
<local:ServiceNodesDiagnostic DataContext="{Binding DiagnosticVM}" />
</TabItem>
</TabControl>
<StackPanel
Margin="0,2,5,0"
HorizontalAlignment="Right"
Background="{DynamicResource Brush.Bg.Panel}"
BorderBrush="{DynamicResource Brush.Border}"
BorderThickness="1,0,0,0"
Visibility="Collapsed">
<Border.Effect>
<DropShadowEffect
BlurRadius="20"
Direction="180"
Opacity="0.3"
ShadowDepth="5"
Color="Black" />
</Border.Effect>
VerticalAlignment="Top"
Panel.ZIndex="1"
Orientation="Horizontal">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="*" />
<RowDefinition Height="60" />
</Grid.RowDefinitions>
<Button
Width="30"
Height="30"
Command="{Binding DiagnosticVM.ClearCommand}"
Style="{StaticResource Btn.TitleBar}"
ToolTip="清空日志">
<Path
Width="14"
Height="14"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="{StaticResource Icon.Trash}"
Fill="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}"
Stretch="Uniform" />
</Button>
<Border BorderBrush="{DynamicResource Brush.Border}" BorderThickness="0,0,0,1">
<DockPanel Margin="15,0" LastChildFill="False">
<TextBlock
VerticalAlignment="Center"
FontSize="{StaticResource Size.Font.Large}"
FontWeight="Bold"
Text="⚙️ 设备参数配置" />
<Button
Width="30"
Padding="0"
Click="CloseRightPanel"
Content="✕"
DockPanel.Dock="Right"
Style="{StaticResource Btn.Ghost}" />
</DockPanel>
</Border>
<StackPanel Grid.Row="1" Margin="20">
<TextBlock
Margin="0,10,0,5"
Foreground="{DynamicResource Brush.Text.Secondary}"
Text="设备名称" />
<TextBox Padding="5" Text="Camera #01" />
<TextBlock
Margin="0,15,0,5"
Foreground="{DynamicResource Brush.Text.Secondary}"
Text="流媒体协议" />
<ComboBox
Height="32"
Padding="5"
SelectedIndex="0">
<ComboBoxItem>RTSP (TCP)</ComboBoxItem>
<ComboBoxItem>RTSP (UDP)</ComboBoxItem>
<ComboBoxItem>WebRTC</ComboBoxItem>
</ComboBox>
<TextBlock
Margin="0,15,0,5"
Foreground="{DynamicResource Brush.Text.Secondary}"
Text="主码流地址" />
<TextBox
Height="80"
Padding="5"
VerticalContentAlignment="Top"
Text="rtsp://admin:123456@192.168.1.20:554/h264/ch1/main/av_stream"
TextWrapping="Wrap" />
</StackPanel>
<Border
Grid.Row="2"
Background="{DynamicResource Brush.Bg.Window}"
BorderBrush="{DynamicResource Brush.Border}"
BorderThickness="0,1,0,0">
<StackPanel
Margin="15,0"
HorizontalAlignment="Right"
Orientation="Horizontal">
<Button
Margin="0,0,10,0"
Click="CloseRightPanel"
Content="取消"
Style="{StaticResource Btn.Ghost}" />
<Button
Width="100"
Background="{DynamicResource Brush.Accent}"
Click="CloseRightPanel"
Content="保存配置" />
</StackPanel>
</Border>
</Grid>
</Border>
<Button
Width="30"
Height="30"
Command="{Binding ToggleLogPanelCommand}"
Style="{StaticResource Btn.TitleBar}"
ToolTip="展开/收起面板">
<Path
Width="12"
Height="12"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Fill="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}"
Stretch="Uniform">
<Path.Style>
<Style TargetType="Path">
<Setter Property="Data" Value="{StaticResource Icon.ChevronDown}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsLogPanelExpanded}" Value="False">
<Setter Property="Data" Value="{StaticResource Icon.ChevronUp}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Path.Style>
</Path>
</Button>
</StackPanel>
</Grid>
</Border>
<Grid
x:Name="GlobalMask"
Grid.Row="1"
Grid.RowSpan="3"
Background="#CC000000"
Visibility="{Binding IsOverlayVisible, Converter={StaticResource BooleanToVisibilityConverter}}">
<ContentControl
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{Binding OverlayContent}">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding IsOverlayVisible}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="Opacity"
From="0"
To="1"
Duration="0:0:0.2" />
<DoubleAnimation
Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)"
From="0.9"
To="1"
Duration="0:0:0.2" />
<DoubleAnimation
Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)"
From="0.9"
To="1"
Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
<Setter Property="RenderTransform">
<Setter.Value>
<ScaleTransform CenterX="0.5" CenterY="0.5" />
</Setter.Value>
</Setter>
</Style>
</ContentControl.Style>
</ContentControl>
</Grid>
<ctrl:BottomDockControl x:Name="BottomDock" Grid.Row="2" />
</Grid>
<Grid x:Name="ModalLayer" Visibility="Collapsed">
<Border Background="#99000000" MouseDown="CloseModal_Click" />
<ContentControl
x:Name="ModalContainer"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<ContentControl.Effect>
<DropShadowEffect
BlurRadius="30"
Opacity="0.5"
ShadowDepth="10"
Color="Black" />
</ContentControl.Effect>
</ContentControl>
</Grid>
</Grid>
</Border>
</Window>