feat(ui): implement Device→DB template sync view
Device→DB template sync UI wired to TemplateSyncService.main
parent
87aacbea64
commit
059b667901
|
|
@ -1,22 +1,168 @@
|
||||||
<UserControl x:Class="HikvisionAttendanceManager.App.DeviceToDbView"
|
<UserControl x:Class="HikvisionAttendanceManager.App.DeviceToDbView"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<Style x:Key="DeviceToDbCard" TargetType="Border">
|
||||||
|
<Setter Property="Background" Value="White"/>
|
||||||
|
<Setter Property="BorderBrush" Value="#DDE5F0"/>
|
||||||
|
<Setter Property="BorderThickness" Value="1"/>
|
||||||
|
<Setter Property="CornerRadius" Value="10"/>
|
||||||
|
<Setter Property="Padding" Value="30,34"/>
|
||||||
|
<Setter Property="SnapsToDevicePixels" Value="True"/>
|
||||||
|
<Setter Property="Effect">
|
||||||
|
<Setter.Value>
|
||||||
|
<DropShadowEffect BlurRadius="18" ShadowDepth="3" Opacity="0.08" Color="#4A5D78"/>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style x:Key="DeviceToDbCaption" TargetType="TextBlock">
|
||||||
|
<Setter Property="Foreground" Value="#65748C"/>
|
||||||
|
<Setter Property="FontSize" Value="12"/>
|
||||||
|
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||||
|
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style x:Key="DeviceToDbComboBox" TargetType="ComboBox">
|
||||||
|
<Setter Property="Width" Value="520"/>
|
||||||
|
<Setter Property="Height" Value="44"/>
|
||||||
|
<Setter Property="FontSize" Value="14"/>
|
||||||
|
<Setter Property="Foreground" Value="#334155"/>
|
||||||
|
<Setter Property="Background" Value="White"/>
|
||||||
|
<Setter Property="BorderBrush" Value="#CBD7E6"/>
|
||||||
|
<Setter Property="BorderThickness" Value="1"/>
|
||||||
|
<Setter Property="ItemTemplate" Value="{StaticResource DeviceComboItemTemplate}"/>
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="ComboBox">
|
||||||
|
<Grid>
|
||||||
|
<ToggleButton Background="White"
|
||||||
|
BorderBrush="{TemplateBinding BorderBrush}"
|
||||||
|
BorderThickness="{TemplateBinding BorderThickness}"
|
||||||
|
Focusable="False"
|
||||||
|
IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
|
||||||
|
ClickMode="Press">
|
||||||
|
<ToggleButton.Template>
|
||||||
|
<ControlTemplate TargetType="ToggleButton">
|
||||||
|
<Border Background="{TemplateBinding Background}"
|
||||||
|
BorderBrush="{TemplateBinding BorderBrush}"
|
||||||
|
BorderThickness="{TemplateBinding BorderThickness}"
|
||||||
|
CornerRadius="5">
|
||||||
|
<Path Width="10"
|
||||||
|
Height="6"
|
||||||
|
Stretch="Uniform"
|
||||||
|
Fill="#526A8A"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Margin="0,0,16,0"
|
||||||
|
Data="M 0 0 L 5 5 L 10 0 Z"/>
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</ToggleButton.Template>
|
||||||
|
</ToggleButton>
|
||||||
|
<ContentPresenter x:Name="ContentSite"
|
||||||
|
Content="{TemplateBinding SelectionBoxItem}"
|
||||||
|
ContentTemplate="{TemplateBinding ItemTemplate}"
|
||||||
|
IsHitTestVisible="False"
|
||||||
|
Margin="18,0,48,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
HorizontalAlignment="Left"/>
|
||||||
|
<TextBlock x:Name="PlaceholderText"
|
||||||
|
Text="Select a source device..."
|
||||||
|
Foreground="#78869A"
|
||||||
|
FontSize="{TemplateBinding FontSize}"
|
||||||
|
Margin="18,0,48,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
IsHitTestVisible="False"
|
||||||
|
Visibility="Collapsed"/>
|
||||||
|
<Popup Placement="Bottom"
|
||||||
|
IsOpen="{TemplateBinding IsDropDownOpen}"
|
||||||
|
AllowsTransparency="True"
|
||||||
|
Focusable="False"
|
||||||
|
PopupAnimation="Slide">
|
||||||
|
<Border Background="White"
|
||||||
|
BorderBrush="#CBD7E6"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="5"
|
||||||
|
MinWidth="{Binding ActualWidth, RelativeSource={RelativeSource TemplatedParent}}">
|
||||||
|
<ScrollViewer MaxHeight="260">
|
||||||
|
<ItemsPresenter/>
|
||||||
|
</ScrollViewer>
|
||||||
|
</Border>
|
||||||
|
</Popup>
|
||||||
|
</Grid>
|
||||||
|
<ControlTemplate.Triggers>
|
||||||
|
<Trigger Property="SelectedIndex" Value="-1">
|
||||||
|
<Setter TargetName="ContentSite" Property="Visibility" Value="Collapsed"/>
|
||||||
|
<Setter TargetName="PlaceholderText" Property="Visibility" Value="Visible"/>
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="IsKeyboardFocusWithin" Value="True">
|
||||||
|
<Setter Property="BorderBrush" Value="#7AA7F8"/>
|
||||||
|
</Trigger>
|
||||||
|
</ControlTemplate.Triggers>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style x:Key="DeviceToDbPrimaryButton" TargetType="Button" BasedOn="{StaticResource PrimaryButton}">
|
||||||
|
<Setter Property="Height" Value="46"/>
|
||||||
|
<Setter Property="Padding" Value="18,0"/>
|
||||||
|
<Setter Property="FontSize" Value="14"/>
|
||||||
|
<Setter Property="HorizontalAlignment" Value="Left"/>
|
||||||
|
<Setter Property="Margin" Value="0,28,0,0"/>
|
||||||
|
</Style>
|
||||||
|
</UserControl.Resources>
|
||||||
|
|
||||||
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||||
<StackPanel>
|
<StackPanel Margin="8,8,8,0">
|
||||||
<TextBlock Text="Device → DB" FontSize="25" FontWeight="SemiBold" Foreground="#17233B"/>
|
<Border Style="{StaticResource DeviceToDbCard}" MinHeight="220" Margin="0,0,0,16">
|
||||||
<TextBlock Text="Read Hikvision users and face templates from a device and save them to attendance_machine_user and attendance_machine_face_templates." Margin="0,6,0,22" Foreground="#66758C"/>
|
<StackPanel HorizontalAlignment="Left">
|
||||||
<Border Style="{StaticResource CardStyle}" Margin="0,0,0,14">
|
<Grid Width="520">
|
||||||
<StackPanel>
|
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
|
||||||
<TextBlock Text="SOURCE DEVICE" Style="{StaticResource CardCaption}"/>
|
<TextBlock Text="SOURCE DEVICE" Style="{StaticResource DeviceToDbCaption}"/>
|
||||||
<ComboBox x:Name="DeviceCombo" DisplayMemberPath="Name" MinWidth="320" HorizontalAlignment="Left" Margin="0,12,0,0"/>
|
<Grid Width="16" Height="16" Margin="8,0,0,0" VerticalAlignment="Center">
|
||||||
<Button Content="Sync Device → DB" Style="{StaticResource PrimaryButton}" HorizontalAlignment="Left" Margin="0,14,0,0" Click="StartSync_Click"/>
|
<Ellipse Stroke="#6B8FC6" StrokeThickness="1.4"/>
|
||||||
|
<TextBlock Text="i"
|
||||||
|
Foreground="#6B8FC6"
|
||||||
|
FontSize="11"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Margin="0,-1,0,0"/>
|
||||||
|
</Grid>
|
||||||
|
</StackPanel>
|
||||||
|
<Button x:Name="RefreshButton" Content="↻ Refresh" Style="{StaticResource HeaderRefreshButton}" HorizontalAlignment="Right" VerticalAlignment="Center" Click="Refresh_Click"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<ComboBox x:Name="DeviceCombo"
|
||||||
|
Style="{StaticResource DeviceToDbComboBox}"
|
||||||
|
Margin="0,18,0,0"/>
|
||||||
|
|
||||||
|
<Button Style="{StaticResource DeviceToDbPrimaryButton}" Click="StartSync_Click">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<Path Width="18"
|
||||||
|
Height="18"
|
||||||
|
Stretch="Uniform"
|
||||||
|
Stroke="White"
|
||||||
|
StrokeThickness="1.7"
|
||||||
|
StrokeStartLineCap="Round"
|
||||||
|
StrokeEndLineCap="Round"
|
||||||
|
StrokeLineJoin="Round"
|
||||||
|
Fill="Transparent"
|
||||||
|
Margin="0,0,9,0"
|
||||||
|
Data="M 9 2 V 11 M 5 7 L 9 11 L 13 7 M 3 13 V 16 H 15 V 13"/>
|
||||||
|
<TextBlock Text="Sync Device -> DB"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
<Border x:Name="ProgressCard" Style="{StaticResource CardStyle}" Visibility="Collapsed">
|
|
||||||
|
<Border x:Name="ProgressCard" Style="{StaticResource DeviceToDbCard}" Visibility="Collapsed">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<ProgressBar x:Name="ProgressBar" Height="12" Margin="0,0,0,8"/>
|
<ProgressBar x:Name="ProgressBar" Height="10" Margin="0,0,0,12"/>
|
||||||
<TextBlock x:Name="ProgressText" Foreground="#475569"/>
|
<TextBlock x:Name="ProgressText" Foreground="#475569" FontSize="13" TextWrapping="Wrap"/>
|
||||||
<TextBlock x:Name="CounterText" Margin="0,8,0,0" Foreground="#475569"/>
|
<TextBlock x:Name="CounterText" Margin="0,8,0,0" Foreground="#475569" FontSize="13"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,32 @@ public partial class DeviceToDbView : UserControl
|
||||||
{
|
{
|
||||||
if (_initialized) return;
|
if (_initialized) return;
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
DeviceCombo.ItemsSource = await _devices.LoadUnifiedAsync();
|
await RefreshAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task RefreshAsync()
|
||||||
|
{
|
||||||
|
var originalContent = RefreshButton.Content;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
RefreshButton.IsEnabled = false;
|
||||||
|
RefreshButton.Content = "Refreshing...";
|
||||||
|
DeviceCombo.SelectedItem = null;
|
||||||
|
DeviceCombo.ItemsSource = await _devices.LoadUnifiedAsync();
|
||||||
|
ProgressCard.Visibility = Visibility.Collapsed;
|
||||||
|
ProgressBar.Value = 0;
|
||||||
|
ProgressText.Text = "";
|
||||||
|
CounterText.Text = "";
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
RefreshButton.IsEnabled = true;
|
||||||
|
RefreshButton.Content = originalContent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void Refresh_Click(object sender, RoutedEventArgs e) => await RefreshAsync();
|
||||||
|
|
||||||
private async void StartSync_Click(object sender, RoutedEventArgs e)
|
private async void StartSync_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (DeviceCombo.SelectedItem is not Device device) { MessageBox.Show("Select a device."); return; }
|
if (DeviceCombo.SelectedItem is not Device device) { MessageBox.Show("Select a device."); return; }
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue