This commit is contained in:
njdaoyehu 2024-11-26 11:24:25 +08:00
parent 5e661d51e5
commit fca338b0da
20 changed files with 668 additions and 33 deletions

View File

@ -8,12 +8,15 @@
<entry key="detect.gui/Assets/RadioButton.axaml" value="detect.gui/detect.gui.csproj" />
<entry key="detect.gui/Controls/Arrow.axaml" value="detect.gui/detect.gui.csproj" />
<entry key="detect.gui/Controls/PageControl.axaml" value="detect.gui/detect.gui.csproj" />
<entry key="detect.gui/VWS/LoginControl.axaml" value="detect.gui/detect.gui.csproj" />
<entry key="detect.gui/VWS/MainWindow.axaml" value="detect.gui/detect.gui.csproj" />
<entry key="detect.gui/Views/Camera/VideoFullWindow.axaml" value="detect.gui/detect.gui.csproj" />
<entry key="detect.gui/Views/DetectTaskView.axaml" value="detect.gui/detect.gui.csproj" />
<entry key="detect.gui/Views/DeviceView.axaml" value="detect.gui/detect.gui.csproj" />
<entry key="detect.gui/Views/HomeView.axaml" value="detect.gui/detect.gui.csproj" />
<entry key="detect.gui/Views/ImportWindow.axaml" value="detect.gui/detect.gui.csproj" />
<entry key="detect.gui/Views/LogView.axaml" value="detect.gui/detect.gui.csproj" />
<entry key="detect.gui/Views/LoginView.axaml" value="detect.gui/detect.gui.csproj" />
<entry key="detect.gui/Views/MainView.axaml" value="detect.gui/detect.gui.csproj" />
<entry key="detect.gui/Views/MainWindow.axaml" value="detect.gui/detect.gui.csproj" />
<entry key="detect.gui/Views/Settings/WebBrowserWindow.axaml" value="detect.gui/detect.gui.csproj" />

View File

@ -15,13 +15,9 @@ public class ApiService
{
private static ApiService? _instance;
public static ApiService Instance
public static ApiService Instance()
{
get
{
_instance = new ApiService();
return _instance;
}
return _instance ??= new ApiService();
}
private WebApplication? _webApp = null;

View File

@ -5,7 +5,9 @@ using detect.gui.Drivers;
using detect.gui.Services;
using detect.gui.Services.Detect;
using detect.gui.ViewModels;
using detect.gui.Views;
using detect.gui.VWMS;
// using detect.gui.Views;
using detect.gui.VWS;
using ReactiveUI;
using Splat;
@ -22,26 +24,22 @@ public class App : Application
RxApp.SuspensionHost.SetupDefaultSuspendResume(new NewtonsoftJsonSuspensionDriver("app.state.json"));
suspension.OnFrameworkInitializationCompleted();
Locator.CurrentMutable.RegisterConstant<IScreen>(RxApp.SuspensionHost.GetAppState<MainViewModel>());
Locator.CurrentMutable.Register(() => new LoginView(), typeof(IViewFor<LoginViewModel>));
Locator.CurrentMutable.Register(() => new HomeView(), typeof(IViewFor<HomeViewModel>));
Locator.CurrentMutable.Register(() => new DetectTaskView(), typeof(IViewFor<DetectTaskViewModel>));
Locator.CurrentMutable.Register(() => new DeviceView(), typeof(IViewFor<DeviceViewModel>));
Locator.CurrentMutable.Register(() => new LogView(), typeof(IViewFor<LogViewModel>));
Locator.CurrentMutable.Register(() => new UserView(), typeof(IViewFor<UserViewModel>));
Locator.CurrentMutable.Register(() => new DetectUserService(), typeof(DetectUserService));
Locator.CurrentMutable.Register(() => new DetectAuthorityService(), typeof(DetectAuthorityService));
Locator.CurrentMutable.Register(() => new DetectDeviceService(), typeof(DetectDeviceService));
Locator.CurrentMutable.Register(() => new DetectTaskService(), typeof(DetectTaskService));
Locator.CurrentMutable.Register(() => new DetectTaskLogService(), typeof(DetectTaskLogService));
Locator.CurrentMutable.Register(() => new DetectTaskProgressService(), typeof(DetectTaskProgressService));
Locator.CurrentMutable.Register(() => new DetectLogService(), typeof(DetectLogService));
Locator.CurrentMutable.Register(DetectUserService.Instance, typeof(DetectUserService));
Locator.CurrentMutable.Register(DetectAuthorityService.Instance, typeof(DetectAuthorityService));
Locator.CurrentMutable.Register(DetectDeviceService.Instance, typeof(DetectDeviceService));
Locator.CurrentMutable.Register( DetectTaskService.Instance, typeof(DetectTaskService));
Locator.CurrentMutable.Register(DetectTaskLogService.Instance, typeof(DetectTaskLogService));
Locator.CurrentMutable.Register(DetectTaskProgressService.Instance, typeof(DetectTaskProgressService));
Locator.CurrentMutable.Register(DetectLogService.Instance, typeof(DetectLogService));
Locator.CurrentMutable.Register(DeviceClientService.Instance, typeof(DeviceClientService));
Locator.Current.GetService<DeviceClientService>();
new MainView { DataContext = Locator.Current.GetService<IScreen>() }.Show();
Locator.CurrentMutable.Register( MainWindow.Instance, typeof(MainWindow));
Locator.CurrentMutable.Register(MainWindowModel.Instance, typeof(MainWindowModel));
Locator.CurrentMutable.Register(LoginControlModel.Instance, typeof(LoginControlModel));
Locator.Current.GetService<MainWindow>()!.Show();
base.OnFrameworkInitializationCompleted();
}

View File

@ -7,7 +7,7 @@ using detect.gui.Models.Entities;
namespace detect.gui.Services.Detect;
public class DetectAuthorityService : ServiceBase<AuthorityEntity>
public class DetectAuthorityService : ServiceBase<DetectAuthorityService, AuthorityEntity>
{
public ApiResponse<PagedResult<AuthorityEntity>> Search(int? id, string? name = "", int pageNum = 1, int pageSize = 10)
{

View File

@ -7,7 +7,7 @@ using detect.gui.Models.Entities;
namespace detect.gui.Services.Detect;
public class DetectDeviceService : ServiceBase<DeviceEntity>
public class DetectDeviceService : ServiceBase<DetectDeviceService, DeviceEntity>
{
public ApiResponse<DeviceEntity?> ListByDeviceIp(string ip)
{

View File

@ -7,7 +7,7 @@ using detect.gui.Models.Entities;
namespace detect.gui.Services.Detect;
public class DetectLogService : ServiceBase<LogEntity>
public class DetectLogService : ServiceBase<DetectLogService, LogEntity>
{
public ApiResponse<PagedResult<LogEntity>> Search(int? userId, string? description = "", int pageNum = 1, int pageSize = 10)
{

View File

@ -7,7 +7,7 @@ using detect.gui.Models.Entities;
namespace detect.gui.Services.Detect;
public class DetectTaskLogService : ServiceBase<DetectTaskLogEntity>
public class DetectTaskLogService : ServiceBase<DetectTaskLogService, DetectTaskLogEntity>
{
public ApiResponse<DetectTaskLogEntity?> ListById(long id)
{

View File

@ -7,7 +7,7 @@ using detect.gui.Models.Entities;
namespace detect.gui.Services.Detect;
public class DetectTaskProgressService : ServiceBase<DetectTaskProgressEntity>
public class DetectTaskProgressService : ServiceBase<DetectTaskProgressService, DetectTaskProgressEntity>
{
public ApiResponse<DetectTaskProgressEntity?> ListById(long id)
{

View File

@ -7,7 +7,7 @@ using detect.gui.Models.Entities;
namespace detect.gui.Services.Detect;
public class DetectTaskService : ServiceBase<DetectTaskEntity>
public class DetectTaskService : ServiceBase<DetectTaskService, DetectTaskEntity>
{
public ApiResponse<DetectTaskEntity?> ListById(long id)
{

View File

@ -8,7 +8,7 @@ using Microsoft.EntityFrameworkCore;
namespace detect.gui.Services.Detect;
public class DetectUserService : ServiceBase<UserEntity>
public class DetectUserService : ServiceBase<DetectUserService, UserEntity>
{
public ApiResponse<UserEntity?> Login(string? username, string? password)
{

View File

@ -6,8 +6,15 @@ using detect.gui.Context;
namespace detect.gui.Services;
public class ServiceBase<T> where T : class
public class ServiceBase<S, T> where S : new() where T : class
{
private static S? _instance;
public static S Instance()
{
return _instance ??= new S();
}
protected readonly DetectContext? Context = new DetectContext();
protected T Add(T entity)

View File

@ -0,0 +1,82 @@
using System.Reactive;
using System.Threading.Tasks;
using Avalonia.Controls.Notifications;
using detect.gui.Api.Helpers;
using detect.gui.Commons;
using detect.gui.Models;
using detect.gui.Models.Entities;
using ReactiveUI;
using Splat;
namespace detect.gui.VWMS;
public class LoginControlModel : ViewModelBase<LoginControlModel>
{
private long? _userId;
public long? UserId
{
get => _userId;
set => this.RaiseAndSetIfChanged(ref _userId, value);
}
private string? _username;
public string? Username
{
get => _username;
set => this.RaiseAndSetIfChanged(ref _username, value);
}
private string? _password;
public string? Password
{
get => _password;
set => this.RaiseAndSetIfChanged(ref _password, value);
}
private string? _realName;
public string? RealName
{
get => _realName;
set => this.RaiseAndSetIfChanged(ref _realName, value);
}
public LoginControlModel()
{
Username = "admin";
Password = "winner!";
LoginCommand = ReactiveCommand.Create(Login);
}
public ReactiveCommand<Unit, Unit> LoginCommand { get; }
/// <summary>
/// 登录
/// </summary>
public async void Login()
{
Message = null;
IsLoading = true;
await Task.Factory.StartNew(() =>
{
var data = UserHelper.Login(Username, Password);
if (data?.Code != 0)
{
Message = new MessageItem(data?.Message, NotificationType.Error);
return;
}
Locator.Current.GetService<MainWindowModel>()!.CurrentUser = data.Result?.Convert<UserEntity, UserModel>();;
// RootViewModel!.CurrentUser = data.Result?.Convert<UserEntity, UserModel>();
Message = new MessageItem("欢迎," + data.Result?.RealName, NotificationType.Success);
});
IsLoading = false;
if (Message is not { NotificationType: NotificationType.Error })
Locator.Current.GetService<MainWindowModel>()!.IsHomeView = true;
// HostScreen?.Router.Navigate.Execute(new HomeViewModel());
}
}

View File

@ -0,0 +1,141 @@
using System;
using System.Reactive;
using detect.gui.Api;
using detect.gui.Models;
using ReactiveUI;
using Serilog;
using xwd.utils;
namespace detect.gui.VWMS;
public class MainWindowModel : ViewModelBase<MainWindowModel>
{
/// <summary>
/// 当前登录用户
/// </summary>
private UserModel? _currentUser;
public UserModel? CurrentUser
{
get => _currentUser;
set => this.RaiseAndSetIfChanged(ref _currentUser, value);
}
private bool _isHomeView;
public bool IsHomeView
{
get => _isHomeView;
set => this.RaiseAndSetIfChanged(ref _isHomeView, value);
}
private bool _isDetectTaskView;
public bool IsDetectTaskView
{
get => _isDetectTaskView;
set => this.RaiseAndSetIfChanged(ref _isDetectTaskView, value);
}
private bool _isDeviceView;
public bool IsDeviceView
{
get => _isDeviceView;
set => this.RaiseAndSetIfChanged(ref _isDeviceView, value);
}
private bool _isLogView;
public bool IsLogView
{
get => _isLogView;
set => this.RaiseAndSetIfChanged(ref _isLogView, value);
}
private bool _isUserView;
public bool IsUserView
{
get => _isUserView;
set => this.RaiseAndSetIfChanged(ref _isUserView, value);
}
private readonly string[] _localRoutes =
[
"#/dashboard",
"#/data/task",
"#/data/device",
"#/system/log",
"#/system/user"
];
private string? _address;
public string? Address
{
get => _address;
set => this.RaiseAndSetIfChanged(ref _address, value);
}
// public ReactiveCommand<string, Unit> GotoCommand { get; }
public ReactiveCommand<Unit, Unit> LogoutCommand { get; }
public MainWindowModel()
{
ApiService.Instance().StartService();
// GotoCommand = ReactiveCommand.Create<string>((p) => Goto(p));
LogoutCommand = ReactiveCommand.Create(Logout);
this.WhenAnyValue(x => x.IsHomeView).Subscribe(p =>
{
if (!p) return;
SetAddress(0);
});
this.WhenAnyValue(x => x.IsDetectTaskView).Subscribe(p =>
{
if (!p) return;
SetAddress(1);
});
this.WhenAnyValue(x => x.IsDeviceView).Subscribe(p =>
{
if (!p) return;
SetAddress(2);
});
this.WhenAnyValue(x => x.IsLogView).Subscribe(p =>
{
if (!p) return;
SetAddress(3);
});
this.WhenAnyValue(x => x.IsUserView).Subscribe(p =>
{
if (!p) return;
SetAddress(4);
});
}
public void Dispose()
{
ApiService.Instance().StopService();
}
private void Logout()
{
CurrentUser = null;
}
public void SetAddress(int index)
{
var isOnLine = AppSettingsManager.Manager().GetBool("Embedded.IsOnline");
var path = AppSettingsManager.Manager().GetString("Embedded.Path", "./dist/index.html");
var prefix = isOnLine ? path : AppDomain.CurrentDomain.BaseDirectory + path;
Address = $"{prefix}{_localRoutes[index]}";
Log.Information("current address: {address}", Address);
}
}

View File

@ -0,0 +1,78 @@
using System;
using Avalonia.Controls.Notifications;
using Avalonia.Threading;
using detect.gui.Classes;
using detect.gui.ViewModels;
using detect.gui.VWS;
using ReactiveUI;
namespace detect.gui.VWMS;
public class ViewModelBase<T> : ReactiveObject where T : new()
{
private static T? _instance;
public static T Instance()
{
return _instance ??= new T();
}
private bool _isLoading;
public bool IsLoading
{
get => _isLoading;
set => this.RaiseAndSetIfChanged(ref _isLoading, value);
}
private MessageItem? _message;
protected MessageItem? Message
{
get => _message;
set => this.RaiseAndSetIfChanged(ref _message, value);
}
protected ViewModelBase()
{
this.WhenAnyValue(x => x.Message).Subscribe(m =>
{
if (m == null) return;
Dispatcher.UIThread.Invoke(() =>
{
var title = m.NotificationType switch
{
NotificationType.Error => "错误信息",
NotificationType.Success => "成功信息",
NotificationType.Information => "提示信息",
NotificationType.Warning => "警告信息",
_ => ""
};
NotificationService.Show(title, m.Text, m.NotificationType);
});
});
}
}
public class MessageItem : ReactiveObject
{
private readonly string? _text;
public string? Text
{
get => _text;
init => this.RaiseAndSetIfChanged(ref _text, value);
}
private readonly NotificationType _notificationType;
public NotificationType NotificationType
{
get => _notificationType;
init => this.RaiseAndSetIfChanged(ref _notificationType, value);
}
public MessageItem(string? text, NotificationType notificationType)
{
_text = text;
_notificationType = notificationType;
}
}

View File

@ -0,0 +1,93 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vwms="clr-namespace:detect.gui.VWMS"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="detect.gui.VWS.LoginControl"
x:DataType="vwms:LoginControlModel">
<Grid>
<Border Background="{StaticResource DialogBackground}" />
<Border HorizontalAlignment="Center"
VerticalAlignment="Center"
CornerRadius="10"
BoxShadow="{StaticResource LoginDialogShadows}">
<Border.Background>
<SolidColorBrush Color="#2D77F3" Opacity="0.3"></SolidColorBrush>
</Border.Background>
<Grid ColumnDefinitions="30, 1*, 1, 1*">
<Border Grid.Column="1" Width="460" Height="460" HorizontalAlignment="Center" VerticalAlignment="Center">
<Border.Background>
<ImageBrush Source="avares://detect.gui/Assets/Images/login.png" Stretch="Fill" />
</Border.Background>
</Border>
<Border Grid.Column="2" Height="250">
<Border.Background>
<LinearGradientBrush StartPoint="0% 0%" EndPoint="0% 100%">
<GradientStop Offset="0.0" Color="Transparent" />
<GradientStop Offset="0.2" Color="#3A62CB" />
<GradientStop Offset="0.5" Color="#34DEFC" />
<GradientStop Offset="0.8" Color="#3A62CB" />
<GradientStop Offset="1" Color="Transparent" />
</LinearGradientBrush>
</Border.Background>
</Border>
<Border Grid.Column="3" Margin="70, 0, 70, 0"
VerticalAlignment="Center"
CornerRadius="5"
Width="340">
<StackPanel>
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center">
<PathIcon Classes="login-user">
<PathIcon.Foreground>
<LinearGradientBrush StartPoint="0% 0%" EndPoint="0% 100%">
<GradientStop Offset="0.0" Color="#34DEFC" />
<GradientStop Offset="0.5" Color="#FFFFFF" />
<GradientStop Offset="1.0" Color="#34DEFC" />
</LinearGradientBrush>
</PathIcon.Foreground>
</PathIcon>
<Border Width="10" />
<TextBlock Classes="login-header" Text="欢迎登录">
<TextBlock.Foreground>
<LinearGradientBrush StartPoint="0% 0%" EndPoint="0% 100%">
<GradientStop Offset="0.0" Color="#34DEFC" />
<GradientStop Offset="0.5" Color="#FFFFFF" />
<GradientStop Offset="1.0" Color="#34DEFC" />
</LinearGradientBrush>
</TextBlock.Foreground>
</TextBlock>
</StackPanel>
<Border Margin="0,30,0,0">
<Grid RowDefinitions="*,20,*,10,*,20,*">
<TextBox Grid.Row="0"
Name="TbUsername"
Height="36"
Classes="login"
Text="{Binding Username}"
Watermark="用户名" />
<TextBox Grid.Row="2"
Name="TbPassword"
Height="36"
Classes="login"
PasswordChar="*"
Text="{Binding Password}"
Watermark="密码" />
<TextBlock Name="TbErrorMessage" Grid.Row="4" />
<Button Grid.Row="6"
Name="BtnLogin"
Width="{Binding Path=Bounds.Width, ElementName=TbUsername}"
Height="{Binding Path=Bounds.Height, ElementName=TbUsername}"
Classes="rect-button blue login"
Content="登录"
IsEnabled="{Binding !IsLoading}"
Command="{Binding LoginCommand}"/>
</Grid>
</Border>
</StackPanel>
</Border>
</Grid>
</Border>
</Grid>
</UserControl>

View File

@ -0,0 +1,23 @@
using Avalonia.Controls;
using Avalonia.Media;
using detect.gui.VWMS;
using Splat;
namespace detect.gui.VWS;
public partial class LoginControl : UserControl
{
public LoginControl()
{
InitializeComponent();
DataContext = Locator.Current.GetService<LoginControlModel>();
}
// public override void Render(DrawingContext context)
// {
// base.Render(context);
// // if (DataContext != null) return;
// var ddd = TopLevel.GetTopLevel(this);
// Locator.Current.GetService<LoginControlModel>()!.TopWindow = TopLevel.GetTopLevel(this) as MainWindow;
// }
}

View File

@ -0,0 +1,127 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="clr-namespace:detect.gui.Controls"
xmlns:vm="clr-namespace:detect.gui.VWMS"
xmlns:webViewControl="clr-namespace:WebViewControl;assembly=WebViewControl.Avalonia"
xmlns:viewModels="clr-namespace:detect.gui.ViewModels"
xmlns:vws="clr-namespace:detect.gui.VWS"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="detect.gui.VWS.MainWindow"
Title="MainWindow"
x:DataType="vm:MainWindowModel">
<Window.Background>
<ImageBrush Source="avares://detect.gui/Assets/Images/bg.png" Stretch="Fill" />
</Window.Background>
<Grid RowDefinitions="Auto, Auto, 0, *">
<Border Height="70">
<Border.Background>
<ImageBrush Source="avares://detect.gui/Assets/Images/header.png" Stretch="None" />
</Border.Background>
<Grid>
<Border>
<TextBlock Classes="logo-text" Text="中核集团预埋件检测系统" VerticalAlignment="Center">
<TextBlock.Foreground>
<LinearGradientBrush StartPoint="0% 0%" EndPoint="0% 100%">
<GradientStop Offset="0.0" Color="#34DEFC" />
<GradientStop Offset="0.5" Color="#FFFFFF" />
<GradientStop Offset="1.0" Color="#34DEFC" />
</LinearGradientBrush>
</TextBlock.Foreground>
</TextBlock>
<Border.Background>
<LinearGradientBrush StartPoint="0% 0%" EndPoint="0% 100%" Opacity="0.25">
<GradientStop Offset="0.8" Color="Transparent" />
<GradientStop Offset="1.0" Color="#34DEFC" />
</LinearGradientBrush>
</Border.Background>
</Border>
</Grid>
</Border>
<Border Grid.Row="1" Height="4">
<Border.Background>
<LinearGradientBrush StartPoint="0% 0%" EndPoint="100% 0%">
<GradientStop Offset="0.0" Color="#2F1A9A" />
<GradientStop Offset="0.3" Color="#3A62CB" />
<GradientStop Offset="0.5" Color="#34DEFC" />
<GradientStop Offset="0.7" Color="#3A62CB" />
<GradientStop Offset="1" Color="#2F1A9A" />
</LinearGradientBrush>
</Border.Background>
</Border>
<Grid Grid.Row="0" HorizontalAlignment="Right" ColumnDefinitions="Auto,5,Auto,5,Auto,5,Auto,15">
<Button Grid.Column="0"
Classes="icon-button circle logout window"
ToolTip.Tip="注销"
VerticalAlignment="Center"
IsVisible="{Binding CurrentUser, Converter={x:Static ObjectConverters.IsNotNull}}"
Command="{Binding LogoutCommand}">
</Button>
<Button Grid.Column="2"
Classes="icon-button circle min window"
ToolTip.Tip="最小化"
Click="MinClick"/>
<Button Grid.Column="4"
IsEnabled="False"
IsVisible="{Binding $parent[Window;0].WindowState, Converter={StaticResource WindowStateConverter}, ConverterParameter=2}"
Classes="icon-button circle max window"
CornerRadius="100"
ToolTip.Tip="最大化"
Click="MaxClick"/>
<Button Grid.Column="4"
Classes="icon-button circle restore window"
ToolTip.Tip="恢复"
IsEnabled="False"
IsVisible="{Binding $parent[Window;0].WindowState, Converter={StaticResource WindowStateConverter}, ConverterParameter=1}"
Click="RestoreClick"/>
<Button Grid.Column="6"
Classes="icon-button circle close window"
ToolTip.Tip="关闭"
Click="CloseClick"/>
</Grid>
<Border Grid.Row="3">
<Border.Margin>
<MultiBinding Converter="{StaticResource SidebarMarginConverter}">
<Binding Path="CurrentUser" />
<Binding Path="#Sidebar.Bounds.Height" />
</MultiBinding>
</Border.Margin>
<Grid>
<webViewControl:WebView x:Name="WebView"
Focusable="True"
IsHistoryDisabled="True"
IgnoreCertificateErrors="True"
DisableBuiltinContextMenus="True"
AllowDeveloperTools="True"
Address="{Binding Address}"/>
<Grid IsVisible="{Binding CurrentUser, Converter={x:Static ObjectConverters.IsNull}}" >
<vws:LoginControl x:DataType="vm:LoginControlModel" />
</Grid>
</Grid>
</Border>
<Grid Grid.Row="3" x:Name="Sidebar" VerticalAlignment="Bottom" IsVisible="{Binding CurrentUser, Converter={x:Static ObjectConverters.IsNotNull}}">
<Grid.Background>
<SolidColorBrush Color="#2D77F3" Opacity="0.4"></SolidColorBrush>
</Grid.Background>
<Border Margin="0, 10" HorizontalAlignment="Center">
<StackPanel Orientation="Horizontal">
<RadioButton Classes="sidebar home-app" Content="首页" GroupName="SideBar" IsChecked="{Binding IsHomeView}" />
<Border Width="15" />
<RadioButton Classes="sidebar home-task" Content="任务管理" GroupName="SideBar" IsChecked="{Binding IsDetectTaskView}" />
<Border Width="15" />
<RadioButton Classes="sidebar home-device" Content="设备管理" GroupName="SideBar" IsChecked="{Binding IsDeviceView}" />
<Border Width="15" />
<RadioButton Classes="sidebar home-log" Content="日志查看" GroupName="SideBar" IsChecked="{Binding IsLogView}" />
<Border Width="15" />
<RadioButton Classes="sidebar home-user" Content="用户管理" GroupName="SideBar" IsChecked="{Binding IsUserView}" />
</StackPanel>
</Border>
</Grid>
<controls:ProgressBox Grid.Row="2"
IconWidth="64"
IconHeight="64"
Foreground="{StaticResource Orange}"
IsVisible="{Binding IsLoading}" />
</Grid>
</Window>

View File

@ -0,0 +1,82 @@
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Avalonia.Platform;
using detect.gui.Classes;
using detect.gui.VWMS;
using Splat;
namespace detect.gui.VWS;
public partial class MainWindow : Window
{
private static MainWindow? _instance;
public static MainWindow Instance()
{
return _instance ??= new MainWindow();
}
public MainWindow()
{
InitializeComponent();
Icon = new WindowIcon(AssetLoader.Open(new Uri("avares://detect.gui/Assets/logo.ico")));
Title = "AI智能视频分析平台";
ExtendClientAreaToDecorationsHint = true;
ExtendClientAreaChromeHints = ExtendClientAreaChromeHints.NoChrome;
ExtendClientAreaTitleBarHeightHint = -1;
SystemDecorations = SystemDecorations.None;
Topmost = false;
CanResize = false;
if (Screens.Primary == null) return;
Width = Screens.Primary.Bounds.Width / Screens.Primary.Scaling;
Height = Screens.Primary.Bounds.Height / Screens.Primary.Scaling;
Position = new PixelPoint(0, 0);
DataContext = Locator.Current.GetService<MainWindowModel>();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
#if DEBUG
this.AttachDevTools();
#endif
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
NotificationService.SetHostWindow(this);
}
private void MinClick(object? sender, RoutedEventArgs e)
{
WindowState = WindowState.Minimized;
}
private void MaxClick(object? sender, RoutedEventArgs e)
{
WindowState = WindowState.Maximized;
}
private void RestoreClick(object? sender, RoutedEventArgs e)
{
WindowState = WindowState.Normal;
}
private void CloseClick(object? sender, RoutedEventArgs e)
{
Close();
}
// private void OnClosing(object? sender, WindowClosingEventArgs e)
// {
// WebWindow.Close();
// }
}

View File

@ -35,7 +35,7 @@ namespace detect.gui.ViewModels;
public bool IsUserView { get; set; }
public MainViewModel()
{
ApiService.Instance.StartService();
// ApiService.Instance().StartService();
_router = new RoutingState();
@ -63,7 +63,7 @@ namespace detect.gui.ViewModels;
public void Dispose()
{
ApiService.Instance.StopService();
// ApiService.Instance().StopService();
}
#region

View File

@ -3,14 +3,19 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACastHelpers_002Ecs_002Fl_003AC_0021_003FUsers_003FNick_0020Wang_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F59109b68aa8966a8b4c17bb8642684239e9598dc1f117d294c355534a932786_003FCastHelpers_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AControl_002Ecs_002Fl_003AC_0021_003FUsers_003Fxiongwei_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Ff963a2a29ea2bb2d4ad8737293b45c4edbd94e55219dc42cf68343d6d91d9_003FControl_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADependencyResolverMixins_002Ecs_002Fl_003AC_0021_003FUsers_003FNick_0020Wang_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fca0d4592dc494bbaa872fd9db942335922638_003Ff9_003Fb0105fc3_003FDependencyResolverMixins_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADispatcher_002Ecs_002Fl_003AC_0021_003FUsers_003FNick_0020Wang_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fdca7348132fe2a808736081c225b26e395f2581aa576813f1316ca11ec2_003FDispatcher_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AExecutionContext_002Ecs_002Fl_003AC_0021_003FUsers_003FNick_0020Wang_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F9eda537f15ea23cdfae523c19e87eb303a3ded88937ae7e55919387a43f70_003FExecutionContext_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFileDialogFilter_002Ecs_002Fl_003AC_0021_003FUsers_003FNick_0020Wang_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8c5be7826d6a434f911dfe811b698519eca00_003F96_003F3ad872d1_003FFileDialogFilter_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFilePickerFileType_002Ecs_002Fl_003AC_0021_003FUsers_003FNick_0020Wang_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fba3ea9c1caf09c71e5e1a6f29cc110e55f6baaeffa8a3c2a8743035da53a0ce_003FFilePickerFileType_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFilePickerOpenOptions_002Ecs_002Fl_003AC_0021_003FUsers_003FNick_0020Wang_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F64c077c15772bb4c699bdf49a561c536eb480867eabb4544519519e287c16_003FFilePickerOpenOptions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIMutableDependencyResolver_002Ecs_002Fl_003AC_0021_003FUsers_003FNick_0020Wang_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F8b99e74e8ee64f66aa5cc8aff4c46fee71daf7d40bad1c7fe28b4c7487d74_003FIMutableDependencyResolver_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIReadonlyDependencyResolver_002Ecs_002Fl_003AC_0021_003FUsers_003FNick_0020Wang_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F18efc112e37199e67bda7b42bd6b28f86385c9c3ae7761a86d0c8b0cc5e9631_003FIReadonlyDependencyResolver_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AJsonSerializerInternalReader_002Ecs_002Fl_003AC_0021_003FUsers_003FNick_0020Wang_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F29ea32a76b2a6b8eb246f247df6a6a86d887384b4c31db2a35effccdd86c24_003FJsonSerializerInternalReader_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AJsonStringEnumConverter_002Ecs_002Fl_003AC_0021_003FUsers_003Fxiongwei_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fe8fd44bb4fe5af449849853612f32962e78c0e82a7b6a4307a7bcae61a547a_003FJsonStringEnumConverter_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ALocator_002Ecs_002Fl_003AC_0021_003FUsers_003FNick_0020Wang_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fcf54cc1573c8f4a376437dc7b76dc8161cde5af828e4b880c5826778c7de6ae5_003FLocator_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMethodBaseInvoker_002Ecs_002Fl_003AC_0021_003FUsers_003FNick_0020Wang_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fd882146b4f265f10bcbec2663fce248db9ffec5fa1aeaf76e32a11ba5eafcd6_003FMethodBaseInvoker_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AReactiveUserControl_002Ecs_002Fl_003AC_0021_003FUsers_003FNick_0020Wang_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F4d7c93652a64ddcaeff466d4c6bae2d847fe753565401deac6d1e5995386b1_003FReactiveUserControl_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AReactiveWindow_002Ecs_002Fl_003AC_0021_003FUsers_003FNick_0020Wang_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fc4eef4eafc39988bdaab8c4a1d0f8111e1dbccb114415665cd8ec36241960_003FReactiveWindow_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AReactiveWindow_00601_002Ecs_002Fl_003AC_0021_003FUsers_003Fxiongwei_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fe4ef1a6c8fbf4ab1a0360a42a1854b208c00_003F5d_003Fbfa2c6a3_003FReactiveWindow_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARxApp_002Ecs_002Fl_003AC_0021_003FUsers_003FNick_0020Wang_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F4c75a39152c6ea672be27a386dbf424c0f2d222d51114dffb436ecd6b570ce_003FRxApp_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASingleQueryingEnumerable_002Ecs_002Fl_003AC_0021_003FUsers_003FNick_0020Wang_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F7b3b6985aad11c5d633d75b545f5f5f4fc7e50918ad1cb9f6b615682f5bfb76d_003FSingleQueryingEnumerable_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>