fajiao
2 years ago
41 changed files with 2210 additions and 172 deletions
@ -0,0 +1,12 @@ |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace EC.Util.Common; |
|||
|
|||
public static class SystemUtil |
|||
{ |
|||
[DllImport("Kernel32")] |
|||
public static extern void AllocConsole(); |
|||
|
|||
[DllImport("Kernel32")] |
|||
public static extern void FreeConsole(); |
|||
} |
Binary file not shown.
@ -1,10 +1,18 @@ |
|||
<Application xmlns="https://github.com/avaloniaui" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
xmlns:icons="using:Material.Icons.Avalonia" |
|||
xmlns:styles="using:Material.Styles.Themes" |
|||
x:Class="JiLinApp.App" |
|||
RequestedThemeVariant="Default"> |
|||
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. --> |
|||
|
|||
<Application.Styles> |
|||
<FluentTheme /> |
|||
</Application.Styles> |
|||
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. --> |
|||
<Application.Styles> |
|||
<icons:MaterialIconStyles /> |
|||
<styles:MaterialTheme BaseTheme="Light" PrimaryColor="Blue" SecondaryColor="Lime" /> |
|||
<Style Selector="ComboBox"> |
|||
<Setter Property="MaxDropDownHeight" Value="350" /> |
|||
</Style> |
|||
<Style Selector="ComboBox:disabled Border[Name=PART_Border]"> |
|||
<Setter Property="BorderBrush" Value="#a6a6a6" /> |
|||
</Style> |
|||
</Application.Styles> |
|||
</Application> |
@ -0,0 +1,156 @@ |
|||
<Window xmlns="https://github.com/avaloniaui" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
|||
xmlns:components="using:JiLinApp.Components" |
|||
xmlns:controls="using:Material.Styles.Controls" |
|||
xmlns:assists="using:Material.Styles.Assists" |
|||
xmlns:icons="using:Material.Icons.Avalonia" |
|||
x:Class="JiLinApp.Components.CameraRealPlay" |
|||
Icon="/Assets/avalonia-logo.ico" |
|||
Title="RealPlay" Width="769" Height="397"> |
|||
<Window.Styles> |
|||
<!--PtzCtrlPanel--> |
|||
<Style Selector="#RealPlayGrid StackPanel[Name=PtzCtrlPanel]"> |
|||
<Setter Property="HorizontalAlignment" Value="Center" /> |
|||
<Setter Property="VerticalAlignment" Value="Center" /> |
|||
</Style> |
|||
<Style Selector="#PtzCtrlPanel StackPanel"> |
|||
<Setter Property="HorizontalAlignment" Value="Center" /> |
|||
<Setter Property="VerticalAlignment" Value="Center" /> |
|||
</Style> |
|||
<Style Selector="#PtzCtrlPanel StackPanel Button"> |
|||
<Setter Property="Width" Value="32" /> |
|||
<Setter Property="Height" Value="32" /> |
|||
<Setter Property="Padding" Value="0" /> |
|||
</Style> |
|||
<Style Selector="#PtzCtrlPanel StackPanel[(Grid.Column)=1] TextBlock"> |
|||
<Setter Property="Foreground" Value="#2b1f19" /> |
|||
<Setter Property="FontSize" Value="13" /> |
|||
</Style> |
|||
<Style Selector="#PtzCtrlPanel StackPanel:nth-child(n+10) Button"> |
|||
<Setter Property="Width" Value="27" /> |
|||
<Setter Property="Height" Value="27" /> |
|||
<Setter Property="Padding" Value="0" /> |
|||
</Style> |
|||
<Style Selector="#PtzCtrlPanel ComboBox[Name=PresetIdCbx] > StackPanel"> |
|||
<Setter Property="Width" Value="100" /> |
|||
</Style> |
|||
<Style Selector="#PtzCtrlPanel Button[Name=GotoBtn]"> |
|||
<Setter Property="Width" Value="100" /> |
|||
<Setter Property="Height" Value="30" /> |
|||
</Style> |
|||
<Style Selector="Window Panel#PART_MinimiseButton"> |
|||
<Setter Property="IsVisible" Value="False" /> |
|||
</Style> |
|||
<Style Selector="Window Panel#PART_RestoreButton"> |
|||
<Setter Property="IsVisible" Value="False" /> |
|||
</Style> |
|||
</Window.Styles> |
|||
|
|||
<Grid Name="RealPlayGrid" ColumnDefinitions="640*,114*"> |
|||
<DockPanel Grid.Column="0"> |
|||
<components:NativeHost Name="player" /> |
|||
</DockPanel> |
|||
|
|||
<StackPanel Name="PtzCtrlPanel" Grid.Column="1"> |
|||
<Grid RowDefinitions="35,35,35,5,30,30,30,5,60,35" ColumnDefinitions="35,35,35"> |
|||
<StackPanel Grid.Row="0" Grid.Column="0"> |
|||
<Button Name="LeftTopBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="ArrowTopLeft" /> |
|||
</Button> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="0" Grid.Column="1"> |
|||
<Button Name="TopBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="ArrowTop" /> |
|||
</Button> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="0" Grid.Column="2"> |
|||
<Button Name="RightTopBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="ArrowTopRight" /> |
|||
</Button> |
|||
</StackPanel> |
|||
|
|||
<StackPanel Grid.Row="1" Grid.Column="0"> |
|||
<Button Name="LeftBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="ArrowLeft" /> |
|||
</Button> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="1" Grid.Column="1"> |
|||
<Button Name="AutoMoveBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="Circle" /> |
|||
</Button> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="1" Grid.Column="2"> |
|||
<Button Name="RightBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="ArrowRight" /> |
|||
</Button> |
|||
</StackPanel> |
|||
|
|||
<StackPanel Grid.Row="2" Grid.Column="0"> |
|||
<Button Name="LeftDownBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="ArrowBottomLeft" /> |
|||
</Button> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="2" Grid.Column="1"> |
|||
<Button Name="DownBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="ArrowBottom" /> |
|||
</Button> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="2" Grid.Column="2"> |
|||
<Button Name="RightDownBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="ArrowBottomRight" /> |
|||
</Button> |
|||
</StackPanel> |
|||
|
|||
<StackPanel Grid.Row="4" Grid.Column="0"> |
|||
<Button Name="ZoomInBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="PlusBold" /> |
|||
</Button> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="4" Grid.Column="1"> |
|||
<TextBlock Text="调焦" /> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="4" Grid.Column="2"> |
|||
<Button Name="ZoomOutBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="MinusThick" /> |
|||
</Button> |
|||
</StackPanel> |
|||
|
|||
<StackPanel Grid.Row="5" Grid.Column="0"> |
|||
<Button Name="FocusNearBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="PlusThick" /> |
|||
</Button> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="5" Grid.Column="1"> |
|||
<TextBlock Text="聚焦" /> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="5" Grid.Column="2"> |
|||
<Button Name="FocusFarBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="MinusThick" /> |
|||
</Button> |
|||
</StackPanel> |
|||
|
|||
<StackPanel Grid.Row="6" Grid.Column="0"> |
|||
<Button Name="IrisOpenBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="PlusThick" /> |
|||
</Button> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="6" Grid.Column="1"> |
|||
<TextBlock Text="光焦" /> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="6" Grid.Column="2"> |
|||
<Button Name="IrisCloseBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="MinusThick" /> |
|||
</Button> |
|||
</StackPanel> |
|||
|
|||
<StackPanel Grid.Row="8" Grid.ColumnSpan="3"> |
|||
<ComboBox Name="PresetIdCbx" Classes="Outline" ContextFlyout="{x:Null}" assists:ComboBoxAssist.Label="预置点" /> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="9" Grid.ColumnSpan="3"> |
|||
<Button Name="GotoBtn" Classes="Light" Content="前往预置点" /> |
|||
</StackPanel> |
|||
</Grid> |
|||
</StackPanel> |
|||
</Grid> |
|||
</Window> |
@ -0,0 +1,180 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Input; |
|||
using Avalonia.Interactivity; |
|||
using Avalonia.Threading; |
|||
using EC.Util.CameraSDK; |
|||
using JiLinApp.Core.Avalonia; |
|||
using JiLinApp.Docking.Ptz; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace JiLinApp.Components; |
|||
|
|||
public partial class CameraRealPlay : Window |
|||
{ |
|||
#region
|
|||
|
|||
private ICameraSdk? CameraSdk { get; set; } |
|||
|
|||
#endregion
|
|||
|
|||
public CameraRealPlay() |
|||
{ |
|||
InitializeComponent(); |
|||
|
|||
//绑定云台响应事件
|
|||
List<Button> btnList = new(); |
|||
ControlsUtil.FindChild(PtzCtrlPanel, ref btnList); |
|||
foreach (var btn in btnList) |
|||
{ |
|||
if ((btn.Name ?? string.Empty).StartsWith("goto", StringComparison.OrdinalIgnoreCase)) btn.Click += GotoBtn_Click; |
|||
else |
|||
{ |
|||
btn.AddHandler(PointerPressedEvent, PtzBtn_MouseDown, RoutingStrategies.Tunnel); |
|||
btn.AddHandler(PointerReleasedEvent, PtzBtn_MouseUp, RoutingStrategies.Tunnel); |
|||
} |
|||
} |
|||
// 初始化预置点 id 下拉框
|
|||
for (int i = 1; i <= 10; i++) PresetIdCbx.Items.Add(new ComboBoxItem { Content = i }); |
|||
PresetIdCbx.SelectedIndex = 0; |
|||
} |
|||
|
|||
public CameraRealPlay(ICameraSdk cameraSdk) : this() |
|||
{ |
|||
SetCameraSdk(cameraSdk); |
|||
} |
|||
|
|||
#region Inner
|
|||
|
|||
public void SetCameraSdk(ICameraSdk cameraSdk) |
|||
{ |
|||
CameraSdk = cameraSdk; |
|||
} |
|||
|
|||
public IntPtr GetHwnd() |
|||
{ |
|||
return player.Handle; |
|||
} |
|||
|
|||
public bool IsClosed { get; private set; } |
|||
|
|||
protected override void OnClosing(WindowClosingEventArgs e) |
|||
{ |
|||
base.OnClosing(e); |
|||
IsClosed = true; |
|||
StopPlay(); |
|||
} |
|||
|
|||
#endregion Inner
|
|||
|
|||
#region Play
|
|||
|
|||
public void StartPlay() |
|||
{ |
|||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) |
|||
{ |
|||
} |
|||
if (CameraSdk is HiKSdk hikSdk) |
|||
{ |
|||
if (RealplayPort < 0) |
|||
{ |
|||
int nPort = -1; |
|||
bool ret = PlayCtrlSdk.PlayM4_GetPort(ref nPort); |
|||
if (!ret) hikSdk.BuildPlayCtrlException(nPort); |
|||
RealplayPort = nPort; |
|||
} |
|||
hikSdk.RealDataCallBack = HikRealDataCallBack; |
|||
} |
|||
else if (CameraSdk is DaHuaSdk dhSdk) |
|||
{ |
|||
} |
|||
else if (CameraSdk is YuShiSdk ysSdk) |
|||
{ |
|||
} |
|||
CameraSdk?.StartPlay(player.Handle); |
|||
} |
|||
|
|||
public void StopPlay() |
|||
{ |
|||
Dispatcher.UIThread.InvokeAsync(() => CameraSdk?.StopPlay()); |
|||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) |
|||
{ |
|||
} |
|||
if (CameraSdk is HiKSdk hikSdk) |
|||
{ |
|||
if (RealplayPort >= 0) |
|||
{ |
|||
PlayCtrlSdk.PlayM4_Stop(RealplayPort); |
|||
PlayCtrlSdk.PlayM4_CloseStream(RealplayPort); |
|||
PlayCtrlSdk.PlayM4_FreePort(RealplayPort); |
|||
RealplayPort = -1; |
|||
} |
|||
hikSdk.RealDataCallBack = null; |
|||
} |
|||
else if (CameraSdk is DaHuaSdk dhSdk) |
|||
{ |
|||
} |
|||
else if (CameraSdk is YuShiSdk ysSdk) |
|||
{ |
|||
} |
|||
} |
|||
|
|||
public bool IsPlaying() |
|||
{ |
|||
return CameraSdk?.IsPlaying() ?? false; |
|||
} |
|||
|
|||
private int RealplayPort { get; set; } = -1; |
|||
|
|||
private void HikRealDataCallBack(int lRealHandle, uint dwDataType, IntPtr pBuffer, uint dwBufSize, IntPtr pUser) |
|||
{ |
|||
if (RealplayPort < 0 || dwBufSize <= 0) return; |
|||
Dispatcher.UIThread.Invoke(() => |
|||
{ |
|||
switch (dwDataType) |
|||
{ |
|||
case HiKOriSdk.NET_DVR_SYSHEAD: |
|||
PlayCtrlSdk.PlayM4_SetStreamOpenMode(RealplayPort, 0); |
|||
PlayCtrlSdk.PlayM4_OpenStream(RealplayPort, pBuffer, dwBufSize, 2 * 1024 * 1024); |
|||
PlayCtrlSdk.PlayM4_SetDisplayBuf(RealplayPort, 5); |
|||
PlayCtrlSdk.PlayM4_Play(RealplayPort, GetHwnd()); |
|||
break; |
|||
|
|||
case HiKOriSdk.NET_DVR_STREAMDATA: |
|||
PlayCtrlSdk.PlayM4_InputData(RealplayPort, pBuffer, dwBufSize); |
|||
break; |
|||
} |
|||
}); |
|||
} |
|||
|
|||
#endregion Play
|
|||
|
|||
#region ElementEvent
|
|||
|
|||
private void PtzBtn_MouseDown(object? sender, PointerPressedEventArgs e) |
|||
{ |
|||
if (CameraSdk == null || sender is not Button btn) return; |
|||
PtzCmdType cmdType = PtzCmd.GetCmdType((btn.Name ?? string.Empty).Replace("Btn", "")); |
|||
int stop = 0; |
|||
PtzCameraCmd.PtzMove(CameraSdk, cmdType, new int[] { stop }); |
|||
} |
|||
|
|||
private void PtzBtn_MouseUp(object? sender, PointerReleasedEventArgs e) |
|||
{ |
|||
if (CameraSdk == null || sender is not Button btn) return; |
|||
PtzCmdType cmdType = PtzCmd.GetCmdType((btn.Name ?? string.Empty).Replace("Btn", "")); |
|||
int stop = 1; |
|||
PtzCameraCmd.PtzMove(CameraSdk, cmdType, new int[] { stop }); |
|||
} |
|||
|
|||
private void GotoBtn_Click(object? sender, RoutedEventArgs e) |
|||
{ |
|||
if (CameraSdk == null) return; |
|||
PtzCmdType cmdType = PtzCmdType.PresetGoto; |
|||
int presetId = int.Parse(PresetIdCbx.GetText()); |
|||
PtzCameraCmd.PtzMove(CameraSdk, cmdType, new int[] { presetId }); |
|||
} |
|||
|
|||
#endregion ElementEvent
|
|||
} |
@ -0,0 +1,22 @@ |
|||
using JiLinApp.Biz.TransmitAlarm; |
|||
using JiLinApp.Docking.Military; |
|||
using JiLinApp.Docking.Ptz; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace JiLinApp.Core; |
|||
|
|||
public class AppConfig |
|||
{ |
|||
public BaseConfig Base { get; set; } |
|||
|
|||
public MilitaryConfig Military { get; set; } |
|||
|
|||
public AlarmPlatformConfig AlarmPlatform { get; set; } |
|||
} |
|||
|
|||
public class BaseConfig |
|||
{ |
|||
public bool Console { get; set; } |
|||
|
|||
public List<PtzControlTypeConfig> PtzCtrlTypes { get; set; } |
|||
} |
@ -0,0 +1,65 @@ |
|||
using EC.Util.CameraSDK; |
|||
using EC.Util.Common; |
|||
using JiLinApp.Biz.TransmitAlarm; |
|||
using JiLinApp.Docking.Alarm; |
|||
using JiLinApp.Docking.Military; |
|||
using JiLinApp.Docking.Ptz; |
|||
using NewLife.Configuration; |
|||
using System; |
|||
using System.IO; |
|||
|
|||
namespace JiLinApp.Core; |
|||
|
|||
public static class Global |
|||
{ |
|||
#region Fields
|
|||
|
|||
private static JsonConfigProvider ConfigProvider { get; } |
|||
|
|||
public static AppConfig AppConfig { get; } |
|||
|
|||
public static MilitaryService MilitaryService { get; } |
|||
|
|||
public static IAlarmService AlarmService { get; } |
|||
|
|||
#endregion Fields
|
|||
|
|||
static Global() |
|||
{ |
|||
try |
|||
{ |
|||
// Config
|
|||
string filePath = Path.Combine("config", "appconfig.json"); |
|||
if (!File.Exists(filePath)) throw new FileNotFoundException(filePath); |
|||
ConfigProvider = new() { FileName = filePath }; |
|||
AppConfig = new AppConfig(); |
|||
ConfigProvider.Bind(AppConfig); |
|||
|
|||
// BaseConfig
|
|||
BaseConfig baseConfig = AppConfig.Base; |
|||
// ptzCtrlTypes
|
|||
PtzControlTypeConfigHelper.Init(baseConfig.PtzCtrlTypes); |
|||
|
|||
// MilitaryConfig
|
|||
MilitaryConfig militaryConfig = AppConfig.Military; |
|||
MilitaryService = new MilitaryService(militaryConfig); |
|||
|
|||
// AlarmPlatformConfig
|
|||
AlarmPlatformConfig alarmPlatformConfig = AppConfig.AlarmPlatform; |
|||
AlarmService = AlarmServiceFactory.CreateService(alarmPlatformConfig); |
|||
AlarmService.Start(); |
|||
} |
|||
catch (Exception) |
|||
{ |
|||
throw; |
|||
} |
|||
} |
|||
|
|||
public static void Init() |
|||
{ |
|||
// 静态类在调用之后才会初始化静态类构造方法
|
|||
CameraFactory.VirtualInit(); |
|||
LogUnit.VirtualInit(); |
|||
AlarmCodeHelper.VirtualInit(); |
|||
} |
|||
} |
@ -0,0 +1,13 @@ |
|||
using JiLinApp.Docking.FenceAlarm; |
|||
using JiLinApp.Docking.VibrateAlarm; |
|||
using ReactiveUI; |
|||
using System; |
|||
|
|||
namespace JiLinApp.Core.App; |
|||
|
|||
public class MessageEvent |
|||
{ |
|||
public static IObservable<TcpAlarmHostMessage> VibrateAlarm { get; } = MessageBus.Current.Listen<TcpAlarmHostMessage>("VibrateAlarm"); |
|||
|
|||
public static IObservable<UdpAlarmHostMessage> FenceAlarm { get; } = MessageBus.Current.Listen<UdpAlarmHostMessage>("FenceAlarm"); |
|||
} |
@ -0,0 +1,150 @@ |
|||
using Avalonia.Controls; |
|||
using Material.Dialog; |
|||
using Material.Dialog.Icons; |
|||
using System.Collections.Generic; |
|||
using System.Reflection; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace JiLinApp.Core.Avalonia; |
|||
|
|||
public static class ControlsUtil |
|||
{ |
|||
/// <summary>
|
|||
/// 查找子控件
|
|||
/// </summary>
|
|||
/// <typeparam name="T">控件类型</typeparam>
|
|||
/// <param name="parent">父控件依赖对象</param>
|
|||
/// <param name="list">子控件列表</param>
|
|||
public static void FindChild<T>(Control parent, ref List<T> list) where T : Control |
|||
{ |
|||
if (parent == null) return; |
|||
if (parent is Panel pParent) |
|||
{ |
|||
foreach (Control item in pParent.Children) |
|||
{ |
|||
if (item is Panel panel) FindChild(panel, ref list); |
|||
else if (item is T child) list.Add(child); |
|||
} |
|||
} |
|||
else if (parent is Decorator dParent) |
|||
{ |
|||
if (dParent.Child != null) FindChild(dParent.Child, ref list); |
|||
} |
|||
} |
|||
|
|||
public static Window? GetWindow(Control control) |
|||
{ |
|||
Control? temp = control; |
|||
while (temp?.Parent != null) |
|||
{ |
|||
if (temp.Parent is Window w) return w; |
|||
else temp = temp.Parent is Control c ? c : null; |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
public static bool TryGetWindow(Control control, out Window? window) |
|||
{ |
|||
Control? temp = control; |
|||
window = null; |
|||
while (temp?.Parent != null) |
|||
{ |
|||
if (temp.Parent is Window w) { window = w; break; } |
|||
else temp = temp.Parent is Control c ? c : null; |
|||
} |
|||
return window != null; |
|||
} |
|||
|
|||
public static string GetText(this TextBox tb) |
|||
{ |
|||
return tb.Text ?? string.Empty; |
|||
} |
|||
|
|||
public static bool GetText(this TextBox tb, out string? text) |
|||
{ |
|||
text = tb.Text; |
|||
return text != null; |
|||
} |
|||
|
|||
public static string GetText(this ComboBox cbx) |
|||
{ |
|||
string? val = string.Empty; |
|||
var item = cbx.SelectedItem; |
|||
if (item == null) return val; |
|||
if (item is Control) |
|||
{ |
|||
if (TryGetValue(item, "Content", out object? content)) val = content?.ToString(); |
|||
else if (TryGetValue(item, "Text", out string? text)) val = text; |
|||
} |
|||
else val = item.ToString(); |
|||
return val ?? string.Empty; |
|||
} |
|||
|
|||
public static bool GetText(this ComboBox cbx, out string? val) |
|||
{ |
|||
var item = cbx.SelectedItem; |
|||
if (item is Control) |
|||
{ |
|||
if (TryGetValue(item, "Content", out object? content)) val = content?.ToString(); |
|||
else if (TryGetValue(item, "Text", out string? text)) val = text; |
|||
else val = null; |
|||
} |
|||
else val = item?.ToString(); |
|||
return val != null; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 利用反射来判断对象是否包含某个属性
|
|||
/// </summary>
|
|||
/// <param name="instance">object</param>
|
|||
/// <param name="propertyName">需要判断的属性</param>
|
|||
/// <returns>是否包含</returns>
|
|||
private static bool ContainProperty(object instance, string propertyName) |
|||
{ |
|||
if (instance == null || string.IsNullOrEmpty(propertyName)) return false; |
|||
PropertyInfo? property = instance.GetType()?.GetProperty(propertyName); |
|||
return property != null; |
|||
} |
|||
|
|||
private static bool TryGetValue<T>(object instance, string propertyName, out T? val) |
|||
{ |
|||
if (instance == null || string.IsNullOrEmpty(propertyName)) |
|||
{ |
|||
val = default; |
|||
return false; |
|||
} |
|||
PropertyInfo? property = instance.GetType()?.GetProperty(propertyName); |
|||
val = (T?)property?.GetValue(instance, null); |
|||
return val != null; |
|||
} |
|||
|
|||
public static async Task<DialogResult> ShowDialog(Window? window, string title = "Info", string message = "") |
|||
{ |
|||
if (window == null) return DialogResult.NoResult; |
|||
var dialog = DialogHelper.CreateAlertDialog(new AlertDialogBuilderParams |
|||
{ |
|||
Borderless = true, |
|||
Width = 300, |
|||
DialogHeaderIcon = DialogIconKind.Info, |
|||
ContentHeader = title, |
|||
SupportingText = message, |
|||
StartupLocation = WindowStartupLocation.CenterOwner, |
|||
}); |
|||
return await dialog.ShowDialog(window); |
|||
} |
|||
|
|||
public static async Task<DialogResult> ShowWarnDialog(Window? window, string title = "Warning", string message = "") |
|||
{ |
|||
if (window == null) return DialogResult.NoResult; |
|||
var dialog = DialogHelper.CreateAlertDialog(new AlertDialogBuilderParams |
|||
{ |
|||
Borderless = true, |
|||
Width = 300, |
|||
DialogHeaderIcon = DialogIconKind.Warning, |
|||
ContentHeader = title, |
|||
SupportingText = message, |
|||
StartupLocation = WindowStartupLocation.CenterOwner, |
|||
}); |
|||
return await dialog.ShowDialog(window); |
|||
} |
|||
} |
@ -0,0 +1,54 @@ |
|||
<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:controls="using:Material.Styles.Controls" |
|||
xmlns:assists="using:Material.Styles.Assists" |
|||
x:Class="JiLinApp.Pages.FenceServer.Fence" |
|||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"> |
|||
<UserControl.Styles> |
|||
<Style Selector="#FencePanel TextBox"> |
|||
<Setter Property="Width" Value="200" /> |
|||
<Setter Property="UseFloatingWatermark" Value="True"/> |
|||
</Style> |
|||
<Style Selector="#FencePanel TextBlock[Name=PART_LabelText]"> |
|||
<Setter Property="Foreground" Value="#272727"/> |
|||
</Style> |
|||
<Style Selector="#FencePanel TextBox:focus TextBlock[Name=PART_LabelText]"> |
|||
<Setter Property="Foreground" Value="#2196f3"/> |
|||
</Style> |
|||
<Style Selector="#FencePanel StackPanel"> |
|||
<Setter Property="VerticalAlignment" Value="Center" /> |
|||
</Style> |
|||
<Style Selector="#FencePanel WrapPanel"> |
|||
<Setter Property="HorizontalAlignment" Value="Center" /> |
|||
<Setter Property="VerticalAlignment" Value="Center" /> |
|||
</Style> |
|||
<Style Selector="#FencePanel WrapPanel Button"> |
|||
<Setter Property="Width" Value="100" /> |
|||
<Setter Property="Margin" Value="5" /> |
|||
</Style> |
|||
</UserControl.Styles> |
|||
|
|||
<Grid Name="FencePanel" RowDefinitions="250,1*"> |
|||
<Border Grid.Row="0" BorderBrush="#2196f3" BorderThickness="1"> |
|||
<Grid RowDefinitions="30,1*"> |
|||
<Border Grid.Row="0" Height="30" Background="#2196f3" Padding="8 0 0 0"> |
|||
<TextBlock Text="优周围网服务器设置(UDP)" FontSize="14" VerticalAlignment="Center" MaxLines="1" Foreground="#F0F0F0" /> |
|||
</Border> |
|||
<Grid Grid.Row="1" RowDefinitions="1*,1*,1*" ColumnDefinitions="1*,1*,1*"> |
|||
<StackPanel Grid.Row="0" Grid.Column="0"> |
|||
<TextBox Name="ServerPortTb" Classes="outline" Text="23039" assists:TextFieldAssist.Label="本地端口" /> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="1" Grid.Column="0"> |
|||
<TextBox Name="HeartKeepTb" Classes="outline" Text="10" assists:TextFieldAssist.Label="心跳间隔" /> |
|||
</StackPanel> |
|||
<WrapPanel Grid.Row="2" Grid.Column="0"> |
|||
<Button Name="OpenBtn" Classes="Light" Content="开启服务" Width="100" Margin="5" /> |
|||
<Button Name="CloseBtn" Classes="Light" Content="关闭服务" Width="100" Margin="5" IsEnabled="False" /> |
|||
</WrapPanel> |
|||
</Grid> |
|||
</Grid> |
|||
</Border> |
|||
</Grid> |
|||
</UserControl> |
@ -0,0 +1,174 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Interactivity; |
|||
using Avalonia.Media; |
|||
using EC.Util.Common; |
|||
using JiLinApp.Biz.TransmitAlarm; |
|||
using JiLinApp.Core; |
|||
using JiLinApp.Core.App; |
|||
using JiLinApp.Core.Avalonia; |
|||
using JiLinApp.Docking.FenceAlarm; |
|||
using Material.Dialog; |
|||
using Newtonsoft.Json.Linq; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Reactive.Linq; |
|||
|
|||
namespace JiLinApp.Pages.FenceServer; |
|||
|
|||
public partial class Fence : UserControl |
|||
{ |
|||
#region Fields
|
|||
|
|||
private UdpManager Manager { get; } = new(); |
|||
|
|||
private IAlarmService AlarmService { get; set; } |
|||
|
|||
private Window? _win; |
|||
|
|||
private Window? Wdw |
|||
{ |
|||
get |
|||
{ |
|||
_win ??= ControlsUtil.GetWindow(this); |
|||
return _win; |
|||
} |
|||
} |
|||
|
|||
#endregion Fields
|
|||
|
|||
public Fence() |
|||
{ |
|||
InitializeComponent(); |
|||
|
|||
AlarmService = Global.AlarmService; |
|||
OpenBtn.Click += OpenBtn_Click; |
|||
CloseBtn.Click += CloseBtn_Click; |
|||
|
|||
Manager.OnFenceUdpDeviceState += Manager_OnFenceUdpDeviceState; |
|||
Manager.OnFenceUdpSectorState += Manager_OnFenceUdpSensorState; |
|||
Manager.OnFenceUdpAlarm += Manager_OnFenceUdpAlarm; |
|||
AlarmService.OnFenceUdpSendDevices += AlarmService_OnFenceUdpSendDevices; |
|||
AlarmService.OnFenceUdpSendSensors += AlarmService_OnFenceUdpSendSensors; |
|||
} |
|||
|
|||
#region ElementEvent
|
|||
|
|||
private void OpenBtn_Click(object? sender, RoutedEventArgs e) |
|||
{ |
|||
if (Manager.IsRunning()) return; |
|||
try |
|||
{ |
|||
UdpManagerConfig config = new() |
|||
{ |
|||
ServerPort = int.Parse(ServerPortTb.GetText()), |
|||
DeviceHeartKeep = int.Parse(HeartKeepTb.GetText()) |
|||
}; |
|||
Manager.Start(config); |
|||
ChangeServerBtnState(true); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
_ = ControlsUtil.ShowWarnDialog(Wdw, message: ex.ToString()); |
|||
LogUnit.Error(ex); |
|||
} |
|||
} |
|||
|
|||
private void CloseBtn_Click(object? sender, RoutedEventArgs e) |
|||
{ |
|||
if (!Manager.IsRunning()) return; |
|||
try |
|||
{ |
|||
Manager.Stop(); |
|||
ChangeServerBtnState(false); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
_ = ControlsUtil.ShowWarnDialog(Wdw, message: ex.ToString()); |
|||
LogUnit.Error(ex); |
|||
} |
|||
} |
|||
|
|||
private void ChangeServerBtnState(bool openState) |
|||
{ |
|||
OpenBtn.IsEnabled = !openState; |
|||
CloseBtn.IsEnabled = openState; |
|||
} |
|||
|
|||
#endregion ElementEvent
|
|||
|
|||
#region Manager Event
|
|||
|
|||
private void Manager_OnFenceUdpDeviceState(UdpAlarmHost device) |
|||
{ |
|||
object deviceObj = new |
|||
{ |
|||
id = device.DeviceId, |
|||
onlineState = device.OnlineState, |
|||
defenceState = device.DefenceState |
|||
}; |
|||
AlarmService.SendDeviceState(DeviceType.Fence, deviceObj); |
|||
} |
|||
|
|||
private void Manager_OnFenceUdpSensorState(SectorState sector) |
|||
{ |
|||
object sensorObj = new |
|||
{ |
|||
id = sector.Id, |
|||
deviceId = sector.DeviceId, |
|||
state = sector.State, |
|||
type = sector.Type, |
|||
}; |
|||
AlarmService.SendSensorState(DeviceType.Fence, sensorObj); |
|||
} |
|||
|
|||
private void Manager_OnFenceUdpAlarm(UdpAlarmHostMessage msg) |
|||
{ |
|||
AlarmMessage alarm = msg.ToAlarmMessage(); |
|||
AlarmService.SendAlarm(alarm); |
|||
MessageEvent.FenceAlarm.Publish(msg); |
|||
} |
|||
|
|||
#endregion Manager Event
|
|||
|
|||
#region SubCmd Event
|
|||
|
|||
private void AlarmService_OnFenceUdpSendDevices(JObject reqObj) |
|||
{ |
|||
List<object> respDeviceList = new(); |
|||
List<UdpAlarmHost> deviceList = Manager.GetDeviceList(); |
|||
foreach (var item in deviceList) |
|||
{ |
|||
if (item.DeviceId <= 0) continue; |
|||
respDeviceList.Add(new |
|||
{ |
|||
id = item.DeviceId, |
|||
//groupId = item.GroupId,
|
|||
//userId = item.UserId,
|
|||
onlineState = item.OnlineState, |
|||
defenceState = item.DefenceState |
|||
}); |
|||
} |
|||
AlarmService.SendDevices(DeviceType.Fence, respDeviceList); |
|||
} |
|||
|
|||
private void AlarmService_OnFenceUdpSendSensors(JObject reqObj) |
|||
{ |
|||
int deviceId = reqObj.GetValue("deviceId", StringComparison.OrdinalIgnoreCase).ToInt(); |
|||
List<SectorState> sectorList = Manager.TryGetDevice(deviceId, out UdpAlarmHost device) ? device.SectorDict.Values.ToList() : new(); |
|||
List<object> respSensorList = new(); |
|||
foreach (var item in sectorList) |
|||
{ |
|||
respSensorList.Add(new |
|||
{ |
|||
id = item.Id, |
|||
deviceId = item.DeviceId, |
|||
state = item.State, |
|||
type = item.Type, |
|||
}); |
|||
} |
|||
AlarmService.SendSensors(DeviceType.Fence, deviceId, respSensorList); |
|||
} |
|||
|
|||
#endregion SubCmd Event
|
|||
} |
@ -0,0 +1,10 @@ |
|||
using JiLinApp.Core.Avalonia; |
|||
|
|||
namespace JiLinApp.Pages.FenceServer; |
|||
|
|||
public class FenceViewModel : ViewModelBase |
|||
{ |
|||
public FenceViewModel() |
|||
{ |
|||
} |
|||
} |
@ -1,20 +1,91 @@ |
|||
<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="using:Material.Styles.Controls" |
|||
xmlns:icons="using:Material.Icons.Avalonia" |
|||
xmlns:vm="using:JiLinApp.Pages.Main" |
|||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" |
|||
xmlns:fenceServer="using:JiLinApp.Pages.FenceServer" |
|||
xmlns:ptzServer="using:JiLinApp.Pages.PtzServer" |
|||
xmlns:vibrateServer="using:JiLinApp.Pages.VibrateServer" |
|||
x:Class="JiLinApp.Pages.Main.MainWindow" |
|||
x:DataType="vm:MainWindowViewModel" |
|||
Width="900" Height="560" MinWidth="775" MinHeight="560" |
|||
Icon="/Assets/avalonia-logo.ico" |
|||
Title="JiLinApp"> |
|||
<Design.DataContext> |
|||
<vm:MainWindowViewModel /> |
|||
</Design.DataContext> |
|||
|
|||
<Design.DataContext> |
|||
<!-- This only sets the DataContext for the previewer in an IDE, |
|||
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) --> |
|||
<vm:MainWindowViewModel/> |
|||
</Design.DataContext> |
|||
<Window.Styles> |
|||
<Style Selector="TabControl"> |
|||
<Setter Property="TabStripPlacement" Value="Left" /> |
|||
<Setter Property="Background" Value="#2196f3" /> |
|||
</Style> |
|||
<Style Selector="TabControl /template/ ContentPresenter"> |
|||
<Setter Property="Background" Value="#F0F0F0" /> |
|||
<Setter Property="Padding" Value="4" /> |
|||
</Style> |
|||
|
|||
<TextBlock Text="{Binding Greeting}" HorizontalAlignment="Center" VerticalAlignment="Center"/> |
|||
<Style Selector="TabItem"> |
|||
<Setter Property="FontSize" Value="12" /> |
|||
<Setter Property="Width" Value="84" /> |
|||
<Setter Property="Height" Value="63" /> |
|||
<Setter Property="Background" Value="#2196f3" /> |
|||
<Setter Property="Foreground" Value="#F0F0F0" /> |
|||
</Style> |
|||
<Style Selector="TabItem TextBlock"> |
|||
<Setter Property="HorizontalAlignment" Value="Center" /> |
|||
</Style> |
|||
<Style Selector="TabItem /template/ ContentPresenter#PART_ContentPresenter"> |
|||
<Setter Property="Width" Value="80" /> |
|||
<Setter Property="Height" Value="56" /> |
|||
<Setter Property="HorizontalAlignment" Value="Center" /> |
|||
<Setter Property="VerticalAlignment" Value="Center" /> |
|||
<Setter Property="HorizontalContentAlignment" Value="Center" /> |
|||
<Setter Property="VerticalContentAlignment" Value="Center" /> |
|||
<Setter Property="Padding" Value="2 5 2 1" /> |
|||
</Style> |
|||
<Style Selector="TabItem:pointerover /template/ ContentPresenter#PART_ContentPresenter"> |
|||
<Setter Property="Foreground" Value="#2B579A" /> |
|||
<Setter Property="Background" Value="#F0F0F0" /> |
|||
</Style> |
|||
<Style Selector="TabItem:focus /template/ ContentPresenter#PART_ContentPresenter"> |
|||
<Setter Property="Foreground" Value="#2B579A" /> |
|||
<Setter Property="Background" Value="#F0F0F0" /> |
|||
</Style> |
|||
<Style Selector="TabItem:selected /template/ ContentPresenter#PART_ContentPresenter"> |
|||
<Setter Property="Foreground" Value="#2B579A" /> |
|||
<Setter Property="Background" Value="#F0F0F0" /> |
|||
</Style> |
|||
</Window.Styles> |
|||
|
|||
</Window> |
|||
<TabControl> |
|||
<TabItem> |
|||
<TabItem.Header> |
|||
<StackPanel> |
|||
<icons:MaterialIcon Kind="CogOutline" Width="30" Height="30" /> |
|||
<TextBlock Text="Ptz服务" /> |
|||
</StackPanel> |
|||
</TabItem.Header> |
|||
<ptzServer:Ptz DataContext="{Binding PtzViewModel}" /> |
|||
</TabItem> |
|||
<TabItem> |
|||
<TabItem.Header> |
|||
<StackPanel> |
|||
<icons:MaterialIcon Kind="Server" Width="30" Height="30" /> |
|||
<TextBlock Text="震动报警服务" /> |
|||
</StackPanel> |
|||
</TabItem.Header> |
|||
<vibrateServer:Vibrate DataContext="{Binding VibrateViewModel}" /> |
|||
</TabItem> |
|||
<TabItem> |
|||
<TabItem.Header> |
|||
<StackPanel> |
|||
<icons:MaterialIcon Kind="Server" Width="30" Height="30" /> |
|||
<TextBlock Text="优周围网服务" /> |
|||
</StackPanel> |
|||
</TabItem.Header> |
|||
<fenceServer:Fence DataContext="{Binding FenceViewModel}"/> |
|||
</TabItem> |
|||
</TabControl> |
|||
</Window> |
@ -1,8 +1,19 @@ |
|||
using JiLinApp.Core.Avalonia; |
|||
using JiLinApp.Pages.FenceServer; |
|||
using JiLinApp.Pages.PtzServer; |
|||
using JiLinApp.Pages.VibrateServer; |
|||
|
|||
namespace JiLinApp.Pages.Main; |
|||
|
|||
public class MainWindowViewModel : ViewModelBase |
|||
{ |
|||
public string Greeting => "Welcome to Avalonia!"; |
|||
#region Fields
|
|||
|
|||
internal PtzViewModel PtzViewModel { get; } = new(); |
|||
|
|||
internal VibrateViewModel VibrateViewModel { get; } = new(); |
|||
|
|||
internal FenceViewModel FenceViewModel { get; } = new(); |
|||
|
|||
#endregion Fields
|
|||
} |
@ -0,0 +1,261 @@ |
|||
<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:controls="using:Material.Styles.Controls" |
|||
xmlns:assists="using:Material.Styles.Assists" |
|||
xmlns:icons="using:Material.Icons.Avalonia" |
|||
x:Class="JiLinApp.Pages.PtzServer.Ptz" |
|||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="550"> |
|||
<UserControl.Styles> |
|||
<Style Selector="StackPanel"> |
|||
<Setter Property="VerticalAlignment" Value="Center" /> |
|||
</Style> |
|||
|
|||
<!--ComSetPanel--> |
|||
<Style Selector="#ComSetPanel ComboBox"> |
|||
<Setter Property="Width" Value="200" /> |
|||
</Style> |
|||
<Style Selector="#ComSetPanel WrapPanel"> |
|||
<Setter Property="HorizontalAlignment" Value="Center" /> |
|||
<Setter Property="VerticalAlignment" Value="Center" /> |
|||
</Style> |
|||
<Style Selector="#ComSetPanel WrapPanel Button"> |
|||
<Setter Property="Width" Value="100" /> |
|||
<Setter Property="Margin" Value="5" /> |
|||
</Style> |
|||
|
|||
<!--DeviceSetPanel--> |
|||
<Style Selector="#DeviceSetPanel ComboBox"> |
|||
<Setter Property="Width" Value="200" /> |
|||
</Style> |
|||
<Style Selector="#DeviceSetPanel Button"> |
|||
<Setter Property="Width" Value="100" /> |
|||
<Setter Property="Margin" Value="5" /> |
|||
</Style> |
|||
|
|||
<!--PtzSetPanel--> |
|||
<Style Selector="#PtzSetPanel ComboBox"> |
|||
<Setter Property="Width" Value="160" /> |
|||
</Style> |
|||
<!--PtzSelectPanel--> |
|||
<!--PtzCtrlPanel--> |
|||
<Style Selector="#PtzSetPanel Grid[Name=PtzCtrlPanel]"> |
|||
<Setter Property="HorizontalAlignment" Value="Center" /> |
|||
</Style> |
|||
<Style Selector="#PtzCtrlPanel StackPanel"> |
|||
<Setter Property="HorizontalAlignment" Value="Center" /> |
|||
<Setter Property="VerticalAlignment" Value="Center" /> |
|||
</Style> |
|||
<Style Selector="#PtzCtrlPanel StackPanel Button"> |
|||
<Setter Property="Width" Value="45" /> |
|||
<Setter Property="Height" Value="45" /> |
|||
<Setter Property="Padding" Value="0" /> |
|||
</Style> |
|||
<Style Selector="#PtzCtrlPanel StackPanel[(Grid.Column)=4] Button"> |
|||
<Setter Property="Width" Value="35" /> |
|||
<Setter Property="Height" Value="35" /> |
|||
<Setter Property="Padding" Value="0" /> |
|||
</Style> |
|||
<Style Selector="#PtzCtrlPanel StackPanel[(Grid.Column)=5] TextBlock"> |
|||
<Setter Property="Foreground" Value="#2b1f19" /> |
|||
</Style> |
|||
<Style Selector="#PtzCtrlPanel StackPanel[(Grid.Column)=6] Button"> |
|||
<Setter Property="Width" Value="35" /> |
|||
<Setter Property="Height" Value="35" /> |
|||
<Setter Property="Padding" Value="0" /> |
|||
</Style> |
|||
<!--PtzPresetPanel--> |
|||
<Style Selector="#PtzPresetPanel Button"> |
|||
<Setter Property="Width" Value="105" /> |
|||
<Setter Property="Margin" Value="5" /> |
|||
</Style> |
|||
</UserControl.Styles> |
|||
|
|||
<Grid RowDefinitions="300,250,auto" ColumnDefinitions="2*,1*"> |
|||
<Border Name="ComSetPanel" Grid.Row="0" Grid.Column="0" BorderBrush="#2196f3" BorderThickness="1" Margin="0 0 4 0"> |
|||
<Grid RowDefinitions="30,1*"> |
|||
<Border Grid.Row="0" Height="30" Background="#2196f3" Padding="8 0 0 0"> |
|||
<TextBlock Text="串口设置" FontSize="14" VerticalAlignment="Center" MaxLines="1" Foreground="#F0F0F0" /> |
|||
</Border> |
|||
<Grid Grid.Row="1" RowDefinitions="1*,1*,1*,1*" ColumnDefinitions="1*,1*"> |
|||
<StackPanel Grid.Row="0" Grid.Column="0"> |
|||
<ComboBox Name="ComNameCbx" Classes="Outline" ContextFlyout="{x:Null}" assists:ComboBoxAssist.Label="本地端口" /> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="0" Grid.Column="1"> |
|||
<ComboBox Name="BaudRateCbx" Classes="Outline" ContextFlyout="{x:Null}" SelectedIndex="3" assists:ComboBoxAssist.Label="波特率"> |
|||
<ComboBoxItem Content="1200" /> |
|||
<ComboBoxItem Content="2400" /> |
|||
<ComboBoxItem Content="4800" /> |
|||
<ComboBoxItem Content="9600" /> |
|||
<ComboBoxItem Content="19200" /> |
|||
</ComboBox> |
|||
</StackPanel> |
|||
|
|||
<StackPanel Grid.Row="1" Grid.Column="0"> |
|||
<ComboBox Name="ParityCbx" Classes="Outline" ContextFlyout="{x:Null}" SelectedIndex="0" assists:ComboBoxAssist.Label="校验位"> |
|||
<ComboBoxItem Content="无" /> |
|||
</ComboBox> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="1" Grid.Column="1"> |
|||
<ComboBox Name="DataBitsCbx" Classes="Outline" ContextFlyout="{x:Null}" SelectedIndex="4" assists:ComboBoxAssist.Label="数据位"> |
|||
<ComboBoxItem Content="4" /> |
|||
<ComboBoxItem Content="5" /> |
|||
<ComboBoxItem Content="6" /> |
|||
<ComboBoxItem Content="7" /> |
|||
<ComboBoxItem Content="8" /> |
|||
</ComboBox> |
|||
</StackPanel> |
|||
|
|||
<StackPanel Grid.Row="2" Grid.Column="0"> |
|||
<ComboBox Name="StopBitsCbx" Classes="Outline" ContextFlyout="{x:Null}" SelectedIndex="0" assists:ComboBoxAssist.Label="停止位"> |
|||
<ComboBoxItem Content="1" /> |
|||
<ComboBoxItem Content="1.5" /> |
|||
<ComboBoxItem Content="2" /> |
|||
</ComboBox> |
|||
</StackPanel> |
|||
<WrapPanel Grid.Row="2" Grid.Column="1"> |
|||
<Button Name="OpenComBtn" Classes="Light" Content="连接" /> |
|||
<Button Name="CloseComBtn" Classes="Light" Content="关闭" IsEnabled="False" /> |
|||
</WrapPanel> |
|||
</Grid> |
|||
</Grid> |
|||
</Border> |
|||
|
|||
<Border Name="DeviceSetPanel" Grid.Row="0" Grid.Column="1" BorderBrush="#2196f3" BorderThickness="1"> |
|||
<Grid RowDefinitions="30,1*"> |
|||
<Border Grid.Row="0" Height="30" Background="#2196f3" Padding="8 0 0 0"> |
|||
<TextBlock Text="设备设置" FontSize="14" VerticalAlignment="Center" MaxLines="1" Foreground="#F0F0F0" /> |
|||
</Border> |
|||
<Grid Grid.Row="1" RowDefinitions="1*,1*,1*,1*"> |
|||
<StackPanel Grid.Row="0" Grid.Column="0"> |
|||
<ComboBox Name="CameraIpCbx" Classes="Outline" ContextFlyout="{x:Null}" assists:ComboBoxAssist.Label="相机Ip" /> |
|||
</StackPanel> |
|||
|
|||
<StackPanel Grid.Row="1" Grid.Column="0"> |
|||
<Button Name="ShowLiveVideoBtn" Classes="Light" Content="实时视频" /> |
|||
</StackPanel> |
|||
</Grid> |
|||
</Grid> |
|||
</Border> |
|||
|
|||
<Border Name="PtzSetPanel" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" BorderBrush="#2196f3" BorderThickness="1" Margin="0 4 0 0"> |
|||
<Grid RowDefinitions="30,1*"> |
|||
<Border Grid.Row="0" Height="30" Background="#2196f3" Padding="8 0 0 0"> |
|||
<TextBlock Text="云台控制" FontSize="14" VerticalAlignment="Center" MaxLines="1" Foreground="#F0F0F0" /> |
|||
</Border> |
|||
<Grid Grid.Row="1" ColumnDefinitions="1*,2*,1*"> |
|||
<Grid Name="PtzSelectPanel" Grid.Column="0" RowDefinitions="60,60,1*"> |
|||
<StackPanel Grid.Row="0"> |
|||
<ComboBox Name="ControlTypeNameCbx" Classes="Outline" ContextFlyout="{x:Null}" assists:ComboBoxAssist.Label="控制类型" /> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="1"> |
|||
<ComboBox Name="CameraIdCbx" Classes="Outline" ContextFlyout="{x:Null}" assists:ComboBoxAssist.Label="相机Id" /> |
|||
</StackPanel> |
|||
</Grid> |
|||
|
|||
<Grid Name="PtzCtrlPanel" Grid.Column="1" RowDefinitions="50,50,50,1*" ColumnDefinitions="50,50,50,15,40,40,40"> |
|||
<StackPanel Grid.Row="0" Grid.Column="0"> |
|||
<Button Name="LeftTopBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="ArrowTopLeft" /> |
|||
</Button> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="0" Grid.Column="1"> |
|||
<Button Name="TopBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="ArrowTop" /> |
|||
</Button> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="0" Grid.Column="2"> |
|||
<Button Name="RightTopBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="ArrowTopRight" /> |
|||
</Button> |
|||
</StackPanel> |
|||
|
|||
<StackPanel Grid.Row="1" Grid.Column="0"> |
|||
<Button Name="LeftBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="ArrowLeft" /> |
|||
</Button> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="1" Grid.Column="1"> |
|||
<Button Name="AutoMoveBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="Circle" /> |
|||
</Button> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="1" Grid.Column="2"> |
|||
<Button Name="RightBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="ArrowRight" /> |
|||
</Button> |
|||
</StackPanel> |
|||
|
|||
<StackPanel Grid.Row="2" Grid.Column="0"> |
|||
<Button Name="LeftDownBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="ArrowBottomLeft" /> |
|||
</Button> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="2" Grid.Column="1"> |
|||
<Button Name="DownBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="ArrowBottom" /> |
|||
</Button> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="2" Grid.Column="2"> |
|||
<Button Name="RightDownBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="ArrowBottomRight" /> |
|||
</Button> |
|||
</StackPanel> |
|||
|
|||
<StackPanel Grid.Row="0" Grid.Column="4"> |
|||
<Button Name="ZoomInBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="PlusBold" /> |
|||
</Button> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="0" Grid.Column="5"> |
|||
<TextBlock Text="调焦" /> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="0" Grid.Column="6"> |
|||
<Button Name="ZoomOutBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="MinusThick" /> |
|||
</Button> |
|||
</StackPanel> |
|||
|
|||
<StackPanel Grid.Row="1" Grid.Column="4"> |
|||
<Button Name="FocusNearBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="PlusThick" /> |
|||
</Button> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="1" Grid.Column="5"> |
|||
<TextBlock Text="聚焦" /> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="1" Grid.Column="6"> |
|||
<Button Name="FocusFarBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="MinusThick" /> |
|||
</Button> |
|||
</StackPanel> |
|||
|
|||
<StackPanel Grid.Row="2" Grid.Column="4"> |
|||
<Button Name="IrisOpenBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="PlusThick" /> |
|||
</Button> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="2" Grid.Column="5"> |
|||
<TextBlock Text="光焦" /> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="2" Grid.Column="6"> |
|||
<Button Name="IrisCloseBtn" Classes="Outline"> |
|||
<icons:MaterialIcon Kind="MinusThick" /> |
|||
</Button> |
|||
</StackPanel> |
|||
</Grid> |
|||
|
|||
<Grid Name="PtzPresetPanel" Grid.Column="2" RowDefinitions="60,60,1*"> |
|||
<StackPanel Grid.Row="0"> |
|||
<ComboBox Name="PresetIdCbx" Classes="Outline" ContextFlyout="{x:Null}" assists:ComboBoxAssist.Label="预置点" /> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="1"> |
|||
<Button Name="GotoBtn" Classes="Light" Content="前往预置点" /> |
|||
</StackPanel> |
|||
</Grid> |
|||
</Grid> |
|||
</Grid> |
|||
</Border> |
|||
</Grid> |
|||
</UserControl> |
@ -0,0 +1,405 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Input; |
|||
using Avalonia.Interactivity; |
|||
using Avalonia.Threading; |
|||
using EC.Util.CameraSDK; |
|||
using EC.Util.Common; |
|||
using EC.Util.Port; |
|||
using JiLinApp.Biz.TransmitAlarm; |
|||
using JiLinApp.Components; |
|||
using JiLinApp.Core; |
|||
using JiLinApp.Core.App; |
|||
using JiLinApp.Core.Avalonia; |
|||
using JiLinApp.Docking.FenceAlarm; |
|||
using JiLinApp.Docking.Military; |
|||
using JiLinApp.Docking.Ptz; |
|||
using JiLinApp.Docking.VibrateAlarm; |
|||
using System; |
|||
using System.Collections.Concurrent; |
|||
using System.Collections.Generic; |
|||
using System.IO.Ports; |
|||
using System.Linq; |
|||
using System.Text.RegularExpressions; |
|||
using System.Threading; |
|||
|
|||
namespace JiLinApp.Pages.PtzServer; |
|||
|
|||
public partial class Ptz : UserControl |
|||
{ |
|||
#region Fields
|
|||
|
|||
private AppConfig AppConfig { get; } = Global.AppConfig; |
|||
|
|||
private MilitaryService MilitaryService { get; } = Global.MilitaryService; |
|||
|
|||
private List<CameraLinkageInfo> CameraLinkageList { get; set; } = new(); |
|||
|
|||
private ConcurrentDictionary<string, ICameraSdk> CameraSdkDict { get; } = new(); |
|||
|
|||
private ConcurrentDictionary<string, CameraRealPlay> RealPlayDict { get; } = new(); |
|||
|
|||
private Window? _win; |
|||
|
|||
private Window? Wdw |
|||
{ |
|||
get |
|||
{ |
|||
_win ??= ControlsUtil.GetWindow(this); |
|||
return _win; |
|||
} |
|||
} |
|||
|
|||
#endregion Fields
|
|||
|
|||
public Ptz() |
|||
{ |
|||
InitializeComponent(); |
|||
|
|||
//绑定串口服务开关响应事件
|
|||
OpenComBtn.Click += OpenComBtn_Click; |
|||
CloseComBtn.Click += CloseComBtn_Click; |
|||
//绑定实时视频响应事件
|
|||
ShowLiveVideoBtn.Click += ShowLiveVideoBtn_Click; |
|||
//绑定云台响应事件
|
|||
List<Button> btnList = new(); |
|||
ControlsUtil.FindChild(PtzCtrlPanel, ref btnList); |
|||
foreach (var btn in btnList) |
|||
{ |
|||
btn.AddHandler(PointerPressedEvent, PtzBtn_MouseDown, RoutingStrategies.Tunnel); |
|||
btn.AddHandler(PointerReleasedEvent, PtzBtn_MouseUp, RoutingStrategies.Tunnel); |
|||
} |
|||
GotoBtn.Click += GotoBtn_Click; |
|||
//绑定云台控制类型更改事件
|
|||
ControlTypeNameCbx.SelectionChanged += ControlTypeName_SelectionChanged; |
|||
|
|||
MessageEvent.VibrateAlarm.Subscribe(HandleVibrateAlarm); |
|||
MessageEvent.FenceAlarm.Subscribe(HandleFenceAlarm); |
|||
|
|||
// 初始化串口下拉框
|
|||
string[] ports = SerialPort.GetPortNames().OrderBy(s => int.Parse(Regex.Match(s, @"\d+").Value)).ToArray(); |
|||
foreach (string port in ports) ComNameCbx.Items.Add(new ComboBoxItem { Content = port }); |
|||
ComNameCbx.SelectedIndex = 0; |
|||
// 初始化相机 sdk 和相机 ip 下拉框
|
|||
CameraLinkageList = MilitaryService.GetCameraLinkageList(); |
|||
TaskUtil.RunCatch(() => Dispatcher.UIThread.Invoke(() => LoadCameraSdkDict(MilitaryService.GetCameraList()))); |
|||
// 初始化云台控制类型下拉框
|
|||
foreach (var cfg in AppConfig.Base.PtzCtrlTypes) ControlTypeNameCbx.Items.Add(new ComboBoxItem { Content = cfg.Name }); |
|||
ControlTypeNameCbx.SelectedIndex = 0; |
|||
// 初始化相机 id 下拉框
|
|||
for (int i = 1; i <= 5; i++) CameraIdCbx.Items.Add(new ComboBoxItem { Content = i }); |
|||
CameraIdCbx.SelectedIndex = 0; |
|||
// 初始化预置点 id 下拉框
|
|||
for (int i = 1; i <= 10; i++) PresetIdCbx.Items.Add(new ComboBoxItem { Content = i }); |
|||
PresetIdCbx.SelectedIndex = 0; |
|||
} |
|||
|
|||
#region Com
|
|||
|
|||
private YcSerialPort? Port { get; set; } |
|||
|
|||
private bool IsComConnect() |
|||
{ |
|||
return Port != null && Port.IsOpen(); |
|||
} |
|||
|
|||
private void ChangeState(bool openState) |
|||
{ |
|||
OpenComBtn.IsEnabled = !openState; |
|||
CloseComBtn.IsEnabled = openState; |
|||
} |
|||
|
|||
#endregion Com
|
|||
|
|||
#region Element Event
|
|||
|
|||
private void OpenComBtn_Click(object? sender, RoutedEventArgs e) |
|||
{ |
|||
if (IsComConnect()) return; |
|||
try |
|||
{ |
|||
SerialPortParam param = new() |
|||
{ |
|||
ComName = ComNameCbx.GetText(), |
|||
BaudRate = int.Parse(BaudRateCbx.GetText()), |
|||
Parity = 0, |
|||
DataBits = int.Parse(DataBitsCbx.GetText()), |
|||
StopBits = int.Parse(StopBitsCbx.GetText()), |
|||
}; |
|||
Port = new YcSerialPort(param); |
|||
Port.OpenCom(); |
|||
ChangeState(true); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
Port = null; |
|||
_ = ControlsUtil.ShowWarnDialog(Wdw, message: ex.ToString()); |
|||
LogUnit.Error(ex); |
|||
} |
|||
} |
|||
|
|||
private void CloseComBtn_Click(object? sender, RoutedEventArgs e) |
|||
{ |
|||
if (!IsComConnect()) return; |
|||
try |
|||
{ |
|||
Port?.CloseCom(); |
|||
Port = null; |
|||
ChangeState(false); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
_ = ControlsUtil.ShowWarnDialog(Wdw, message: ex.ToString()); |
|||
LogUnit.Error(ex); |
|||
} |
|||
} |
|||
|
|||
private void PtzBtn_MouseDown(object? sender, PointerPressedEventArgs e) |
|||
{ |
|||
if (sender is not Button btn) return; |
|||
PtzControlType ctrlType = PtzControlTypeConfigHelper.GetControlType(ControlTypeNameCbx.GetText()); |
|||
PtzCmdType cmdType = PtzCmd.GetCmdType((btn.Name ?? string.Empty).Replace("Btn", "")); |
|||
switch (ctrlType) |
|||
{ |
|||
case PtzControlType.PelcoD: |
|||
case PtzControlType.PelcoP: |
|||
if (!IsComConnect()) break; |
|||
byte cameraId = byte.Parse(CameraIdCbx.GetText()); |
|||
byte[] cmd = PtzComCmd.GetCmd(ctrlType, cmdType, new object[] { cameraId }); |
|||
if (cmd != null && cmd.Length > 0) Port?.SendHex(cmd); |
|||
break; |
|||
|
|||
case PtzControlType.DCamera: |
|||
if (!IsComConnect()) break; |
|||
cmd = PtzComCmd.GetCmd(ctrlType, cmdType); |
|||
if (cmd != null && cmd.Length > 0) Port?.SendHex(cmd); |
|||
break; |
|||
|
|||
case PtzControlType.CameraSdk: |
|||
string cameraIp = CameraIpCbx.GetText(); |
|||
CameraSdkDict.TryGetValue(cameraIp, out ICameraSdk? cameraSdk); |
|||
if (cameraSdk == null) break; |
|||
int stop = 0; |
|||
PtzCameraCmd.PtzMove(cameraSdk, cmdType, new int[] { stop }); |
|||
break; |
|||
|
|||
default: break; |
|||
} |
|||
} |
|||
|
|||
private void PtzBtn_MouseUp(object? sender, PointerReleasedEventArgs e) |
|||
{ |
|||
if (sender is not Button btn) return; |
|||
PtzControlType ctrlType = PtzControlTypeConfigHelper.GetControlType(ControlTypeNameCbx.GetText()); |
|||
PtzCmdType cmdType = PtzCmdType.Stop; |
|||
switch (ctrlType) |
|||
{ |
|||
case PtzControlType.PelcoD: |
|||
case PtzControlType.PelcoP: |
|||
if (!IsComConnect()) break; |
|||
byte cameraId = byte.Parse(CameraIdCbx.GetText()); |
|||
byte[] cmd = PtzComCmd.GetCmd(ctrlType, cmdType, new object[] { cameraId }); |
|||
if (cmd != null && cmd.Length > 0) Port?.SendHex(cmd); |
|||
break; |
|||
|
|||
case PtzControlType.DCamera: |
|||
if (!IsComConnect()) break; |
|||
cmd = PtzComCmd.GetCmd(ctrlType, cmdType); |
|||
if (cmd != null && cmd.Length > 0) Port?.SendHex(cmd); |
|||
break; |
|||
|
|||
case PtzControlType.CameraSdk: |
|||
string cameraIp = CameraIpCbx.GetText(); |
|||
CameraSdkDict.TryGetValue(cameraIp, out ICameraSdk? cameraSdk); |
|||
if (cameraSdk == null) break; |
|||
cmdType = PtzCmd.GetCmdType((btn.Name ?? string.Empty).Replace("Btn", "")); |
|||
int stop = 1; |
|||
PtzCameraCmd.PtzMove(cameraSdk, cmdType, new int[] { stop }); |
|||
break; |
|||
|
|||
default: break; |
|||
} |
|||
} |
|||
|
|||
private void GotoBtn_Click(object? sender, RoutedEventArgs e) |
|||
{ |
|||
PtzControlType ctrlType = PtzControlTypeConfigHelper.GetControlType(ControlTypeNameCbx.GetText()); |
|||
PtzCmdType cmdType = PtzCmdType.PresetGoto; |
|||
byte presetId = byte.Parse(PresetIdCbx.GetText()); |
|||
switch (ctrlType) |
|||
{ |
|||
case PtzControlType.PelcoD: |
|||
case PtzControlType.PelcoP: |
|||
if (!IsComConnect()) break; |
|||
byte cameraId = byte.Parse(CameraIdCbx.GetText()); |
|||
byte[] cmd = PtzComCmd.GetCmd(ctrlType, cmdType, new object[] { cameraId, presetId }); |
|||
if (cmd != null && cmd.Length > 0) Port?.SendHex(cmd); |
|||
break; |
|||
|
|||
case PtzControlType.CameraSdk: |
|||
string cameraIp = CameraIpCbx.GetText(); |
|||
CameraSdkDict.TryGetValue(cameraIp, out ICameraSdk? cameraSdk); |
|||
if (cameraSdk == null) break; |
|||
PtzCameraCmd.PtzMove(cameraSdk, cmdType, new int[] { presetId }); |
|||
break; |
|||
|
|||
default: break; |
|||
} |
|||
} |
|||
|
|||
private void ShowLiveVideoBtn_Click(object? sender, RoutedEventArgs e) |
|||
{ |
|||
string cameraIp = CameraIpCbx.GetText(); |
|||
if (!CameraSdkDict.TryGetValue(cameraIp, out ICameraSdk? sdk)) return; |
|||
Dispatcher.UIThread.Invoke(() => ShowLiveVideo(sdk)); |
|||
} |
|||
|
|||
private void ControlTypeName_SelectionChanged(object? sender, SelectionChangedEventArgs e) |
|||
{ |
|||
if (e.AddedItems[0] is not ComboBoxItem cbxItem) return; |
|||
string ctrlTypeName = cbxItem?.Content?.ToString() ?? string.Empty; |
|||
PtzControlType ctrlType = PtzControlTypeConfigHelper.GetControlType(ctrlTypeName); |
|||
switch (ctrlType) |
|||
{ |
|||
case PtzControlType.PelcoD: |
|||
case PtzControlType.PelcoP: |
|||
case PtzControlType.DCamera: |
|||
CameraIdCbx.IsEnabled = true; |
|||
CameraIpCbx.IsEnabled = false; |
|||
ShowLiveVideoBtn.IsEnabled = false; |
|||
break; |
|||
|
|||
case PtzControlType.CameraSdk: |
|||
CameraIdCbx.IsEnabled = false; |
|||
CameraIpCbx.IsEnabled = true; |
|||
ShowLiveVideoBtn.IsEnabled = true; |
|||
break; |
|||
|
|||
default: |
|||
CameraIdCbx.IsEnabled = false; |
|||
CameraIpCbx.IsEnabled = false; |
|||
ShowLiveVideoBtn.IsEnabled = false; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
#endregion Element Event
|
|||
|
|||
#region Invoke Event
|
|||
|
|||
private void ShowLiveVideo(ICameraSdk sdk) |
|||
{ |
|||
if (!sdk.ConnectSuccess()) { LogUnit.Error(this, $"CameraSdk(cameraIp:{sdk.CameraInfo.Ip}) connect failure."); return; } |
|||
if (!ControlsUtil.TryGetWindow(this, out Window? w)) return; |
|||
string cameraIp = sdk.CameraInfo.Ip; |
|||
RealPlayDict.TryGetValue(cameraIp, out CameraRealPlay? realPlay); |
|||
if (realPlay == null || realPlay.IsClosed) |
|||
{ |
|||
realPlay = new(sdk) |
|||
{ |
|||
Title = $"RealPlay({sdk.CameraInfo.Name})", |
|||
CanResize = false, |
|||
ShowInTaskbar = true |
|||
}; |
|||
RealPlayDict[cameraIp] = realPlay; |
|||
} |
|||
realPlay.Show(w); |
|||
realPlay.WindowState = WindowState.Normal; |
|||
realPlay.StartPlay(); |
|||
} |
|||
|
|||
private void HandleVibrateAlarm(TcpAlarmHostMessage msg) |
|||
{ |
|||
AlarmMessage alarm = msg.ToAlarmMessage(); |
|||
TaskUtil.RunCatch(() => HandleAlarmInvoke(alarm)); |
|||
} |
|||
|
|||
private void HandleFenceAlarm(UdpAlarmHostMessage msg) |
|||
{ |
|||
AlarmMessage alarm = msg.ToAlarmMessage(); |
|||
TaskUtil.RunCatch(() => HandleAlarmInvoke(alarm)); |
|||
} |
|||
|
|||
private void HandleAlarmInvoke(AlarmMessage alarm) |
|||
{ |
|||
if (alarm == null) return; |
|||
bool realPlay = AppConfig.AlarmPlatform.RealPlay; |
|||
string deviceId = alarm.LabelCode; |
|||
string sensorId = alarm.ChannelId; |
|||
List<CameraLinkageInfo> cameraLinkages = GetCameraLinkageList(sensorId); |
|||
foreach (var item in cameraLinkages) |
|||
{ |
|||
if (item == null) { LogUnit.Error(this, $"CameraLinkageInfo(sensorId:{sensorId}) not found."); return; } |
|||
string cameraId = item.CameraId; |
|||
ICameraSdk? cameraSdk = GetCameraSdk(cameraId); |
|||
if (cameraSdk == null) { LogUnit.Error(this, $"CameraSdk(cameraId:{cameraId}) not found."); return; } |
|||
if (realPlay) Dispatcher.UIThread.Invoke(() => ShowLiveVideo(cameraSdk)); |
|||
// TODO: 设计 PriorityQueue
|
|||
int len = item.PresetIds.Length; |
|||
for (int i = 0; i < len; i++) |
|||
{ |
|||
int presetId = item.PresetIds[i]; |
|||
PtzCameraCmd.PtzMove(cameraSdk, PtzCmdType.PresetGoto, new int[] { presetId }); |
|||
if (i != len) Thread.Sleep(5000); |
|||
} |
|||
} |
|||
} |
|||
|
|||
#endregion Invoke Event
|
|||
|
|||
#region Military
|
|||
|
|||
private void LoadCameraSdkDict(List<CameraInfo> cameraList) |
|||
{ |
|||
int tryTime = 5, tryInterval = 500; |
|||
for (int i = 0; i < cameraList.Count; i++) |
|||
{ |
|||
CameraInfo info = cameraList[i]; |
|||
string ip = info.Ip; |
|||
if (CameraSdkDict.ContainsKey(ip)) continue; |
|||
ICameraSdk sdk = CameraFactory.BuildCameraSdk(info); |
|||
CameraSdkDict[ip] = sdk; |
|||
CameraIpCbx.Items.Add(new ComboBoxItem { Content = ip }); |
|||
TaskUtil.RunCatch(() => |
|||
{ |
|||
bool flag = false; |
|||
for (int i = 0; i < tryTime; i++) |
|||
{ |
|||
flag = sdk.Init(); |
|||
if (flag) break; |
|||
Thread.Sleep(tryInterval); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
|
|||
private CameraLinkageInfo? GetCameraLinkage(string sensorId) |
|||
{ |
|||
foreach (var item in CameraLinkageList) |
|||
{ |
|||
if (sensorId.Equals(item.SensorId)) return item; |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
private List<CameraLinkageInfo> GetCameraLinkageList(string sensorId) |
|||
{ |
|||
List<CameraLinkageInfo> list = new(); |
|||
foreach (var item in CameraLinkageList) |
|||
{ |
|||
if (sensorId.Equals(item.SensorId)) list.Add(item); |
|||
} |
|||
return list; |
|||
} |
|||
|
|||
private ICameraSdk? GetCameraSdk(string cameraId) |
|||
{ |
|||
foreach (var item in CameraSdkDict.Values) |
|||
{ |
|||
if (item == null) continue; |
|||
if (cameraId.Equals(item.CameraInfo.Id)) return item; |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
#endregion Military
|
|||
} |
@ -0,0 +1,10 @@ |
|||
using JiLinApp.Core.Avalonia; |
|||
|
|||
namespace JiLinApp.Pages.PtzServer; |
|||
|
|||
public class PtzViewModel : ViewModelBase |
|||
{ |
|||
public PtzViewModel() |
|||
{ |
|||
} |
|||
} |
@ -0,0 +1,54 @@ |
|||
<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:controls="using:Material.Styles.Controls" |
|||
xmlns:assists="using:Material.Styles.Assists" |
|||
x:Class="JiLinApp.Pages.VibrateServer.Vibrate" |
|||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"> |
|||
<UserControl.Styles> |
|||
<Style Selector="#VibratePanel TextBox"> |
|||
<Setter Property="Width" Value="200" /> |
|||
<Setter Property="UseFloatingWatermark" Value="True"/> |
|||
</Style> |
|||
<Style Selector="#VibratePanel TextBlock[Name=PART_LabelText]"> |
|||
<Setter Property="Foreground" Value="#272727"/> |
|||
</Style> |
|||
<Style Selector="#VibratePanel TextBox:focus TextBlock[Name=PART_LabelText]"> |
|||
<Setter Property="Foreground" Value="#2196f3"/> |
|||
</Style> |
|||
<Style Selector="#VibratePanel StackPanel"> |
|||
<Setter Property="VerticalAlignment" Value="Center" /> |
|||
</Style> |
|||
<Style Selector="#VibratePanel WrapPanel"> |
|||
<Setter Property="HorizontalAlignment" Value="Center" /> |
|||
<Setter Property="VerticalAlignment" Value="Center" /> |
|||
</Style> |
|||
<Style Selector="#VibratePanel WrapPanel Button"> |
|||
<Setter Property="Width" Value="100" /> |
|||
<Setter Property="Margin" Value="5" /> |
|||
</Style> |
|||
</UserControl.Styles> |
|||
|
|||
<Grid RowDefinitions="250,1*"> |
|||
<Border Name="VibratePanel" Grid.Row="0" BorderBrush="#2196f3" BorderThickness="1"> |
|||
<Grid RowDefinitions="30,1*"> |
|||
<Border Grid.Row="0" Height="30" Background="#2196f3" Padding="8 0 0 0"> |
|||
<TextBlock Text="震动报警服务器设置(TCP)" FontSize="14" VerticalAlignment="Center" MaxLines="1" Foreground="#F0F0F0" /> |
|||
</Border> |
|||
<Grid Grid.Row="1" RowDefinitions="1*,1*,1*" ColumnDefinitions="1*,1*,1*"> |
|||
<StackPanel Grid.Row="0" Grid.Column="0"> |
|||
<TextBox Name="ServerPortTb" Classes="outline" Text="9000" assists:TextFieldAssist.Label="本地端口" /> |
|||
</StackPanel> |
|||
<StackPanel Grid.Row="1" Grid.Column="0"> |
|||
<TextBox Name="HeartKeepTb" Classes="outline" Text="10" assists:TextFieldAssist.Label="心跳间隔" /> |
|||
</StackPanel> |
|||
<WrapPanel Grid.Row="2" Grid.Column="0"> |
|||
<Button Name="OpenBtn" Classes="Light" Content="开启服务" Width="100" Margin="5" /> |
|||
<Button Name="CloseBtn" Classes="Light" Content="关闭服务" Width="100" Margin="5" IsEnabled="False" /> |
|||
</WrapPanel> |
|||
</Grid> |
|||
</Grid> |
|||
</Border> |
|||
</Grid> |
|||
</UserControl> |
@ -0,0 +1,168 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Interactivity; |
|||
using EC.Util.Common; |
|||
using JiLinApp.Biz.TransmitAlarm; |
|||
using JiLinApp.Core; |
|||
using JiLinApp.Core.App; |
|||
using JiLinApp.Core.Avalonia; |
|||
using JiLinApp.Docking.VibrateAlarm; |
|||
using Newtonsoft.Json.Linq; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Reactive.Linq; |
|||
|
|||
namespace JiLinApp.Pages.VibrateServer; |
|||
|
|||
public partial class Vibrate : UserControl |
|||
{ |
|||
#region Fields
|
|||
|
|||
private TcpManager Manager { get; } = new(); |
|||
|
|||
private IAlarmService AlarmService { get; set; } |
|||
|
|||
private Window? _win; |
|||
|
|||
private Window? Wdw |
|||
{ |
|||
get |
|||
{ |
|||
_win ??= ControlsUtil.GetWindow(this); |
|||
return _win; |
|||
} |
|||
} |
|||
|
|||
#endregion Fields
|
|||
|
|||
public Vibrate() |
|||
{ |
|||
InitializeComponent(); |
|||
|
|||
AlarmService = Global.AlarmService; |
|||
OpenBtn.Click += OpenBtn_Click; |
|||
CloseBtn.Click += CloseBtn_Click; |
|||
|
|||
Manager.OnVibrateTcpDeviceState += Manager_OnVibrateTcpDeviceState; |
|||
Manager.OnVibrateTcpSensorState += Manager_OnVibrateTcpSensorSate; |
|||
Manager.OnVibrateTcpAlarm += Manager_OnVibrateTcpAlarm; |
|||
AlarmService.OnVibrateTcpSendDevices += AlarmService_OnVibrateTcpSendDevices; |
|||
AlarmService.OnVibrateTcpSendSensors += AlarmService_OnVibrateTcpSendSensors; |
|||
} |
|||
|
|||
#region ElementEvent
|
|||
|
|||
private void OpenBtn_Click(object? sender, RoutedEventArgs e) |
|||
{ |
|||
if (Manager.IsRunning()) return; |
|||
try |
|||
{ |
|||
TcpManagerConfig config = new() |
|||
{ |
|||
ServerPort = int.Parse(ServerPortTb.GetText()), |
|||
DeviceHeartKeep = int.Parse(HeartKeepTb.GetText()) |
|||
}; |
|||
Manager.Start(config); |
|||
ChangeServerBtnState(true); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
_ = ControlsUtil.ShowWarnDialog(Wdw, message: ex.ToString()); |
|||
LogUnit.Error(ex); |
|||
} |
|||
} |
|||
|
|||
private void CloseBtn_Click(object? sender, RoutedEventArgs e) |
|||
{ |
|||
if (!Manager.IsRunning()) return; |
|||
try |
|||
{ |
|||
Manager.Stop(); |
|||
ChangeServerBtnState(false); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
_ = ControlsUtil.ShowWarnDialog(Wdw, message: ex.ToString()); |
|||
LogUnit.Error(ex); |
|||
} |
|||
} |
|||
|
|||
private void ChangeServerBtnState(bool openState) |
|||
{ |
|||
OpenBtn.IsEnabled = !openState; |
|||
CloseBtn.IsEnabled = openState; |
|||
} |
|||
|
|||
#endregion ElementEvent
|
|||
|
|||
#region Manager Event
|
|||
|
|||
private void Manager_OnVibrateTcpDeviceState(ClientMessage device) |
|||
{ |
|||
object deviceObj = new |
|||
{ |
|||
id = device.Host.Id, |
|||
onlineState = device.OnlineState |
|||
}; |
|||
AlarmService.SendDeviceState(DeviceType.Vibrate, deviceObj); |
|||
} |
|||
|
|||
private void Manager_OnVibrateTcpSensorSate(SensorState sensor) |
|||
{ |
|||
object sensorObj = new |
|||
{ |
|||
id = sensor.Addr, |
|||
deviceId = sensor.DeviceId, |
|||
onlineState = sensor.OnlineState, |
|||
alarmState = sensor.AlarmState, |
|||
}; |
|||
AlarmService.SendSensorState(DeviceType.Vibrate, sensorObj); |
|||
} |
|||
|
|||
private void Manager_OnVibrateTcpAlarm(TcpAlarmHostMessage msg) |
|||
{ |
|||
AlarmMessage alarm = msg.ToAlarmMessage(); |
|||
AlarmService.SendAlarm(alarm); |
|||
MessageEvent.VibrateAlarm.Publish(msg); |
|||
} |
|||
|
|||
#endregion Manager Event
|
|||
|
|||
#region SubCmd Event
|
|||
|
|||
private void AlarmService_OnVibrateTcpSendDevices(JObject reqObj) |
|||
{ |
|||
List<object> respDeviceList = new(); |
|||
List<ClientMessage> deviceList = Manager.GetDeviceList(); |
|||
foreach (var item in deviceList) |
|||
{ |
|||
if (item.Host.Id <= 0) continue; |
|||
respDeviceList.Add(new |
|||
{ |
|||
id = item.Host.Id, |
|||
onlineState = item.OnlineState |
|||
}); |
|||
} |
|||
AlarmService.SendDevices(DeviceType.Vibrate, respDeviceList); |
|||
} |
|||
|
|||
private void AlarmService_OnVibrateTcpSendSensors(JObject reqObj) |
|||
{ |
|||
int deviceId = reqObj.GetValue("deviceId", StringComparison.OrdinalIgnoreCase).ToInt(); |
|||
List<SensorState> sensorList = Manager.TryGetDevice(deviceId, out ClientMessage device) ? device.SensorDict.Values.ToList() : new(); |
|||
List<object> respSensorList = new(); |
|||
foreach (var item in sensorList) |
|||
{ |
|||
respSensorList.Add(new |
|||
{ |
|||
id = item.Addr, |
|||
deviceId = item.DeviceId, |
|||
onlineState = item.OnlineState, |
|||
alarmState = item.AlarmState, |
|||
}); |
|||
} |
|||
AlarmService.SendSensors(DeviceType.Vibrate, deviceId, respSensorList); |
|||
} |
|||
|
|||
#endregion SubCmd Event
|
|||
} |
@ -0,0 +1,10 @@ |
|||
using JiLinApp.Core.Avalonia; |
|||
|
|||
namespace JiLinApp.Pages.VibrateServer; |
|||
|
|||
public class VibrateViewModel : ViewModelBase |
|||
{ |
|||
public VibrateViewModel() |
|||
{ |
|||
} |
|||
} |
@ -0,0 +1,50 @@ |
|||
{ |
|||
"base": { |
|||
"console": true, |
|||
"ptzCtrlTypes": [ |
|||
{ |
|||
"type": "CameraSdk", |
|||
"Name": "协议HDY" |
|||
}, |
|||
{ |
|||
"type": "PelcoD", |
|||
"Name": "协议Pd" |
|||
}, |
|||
{ |
|||
"type": "PelcoP", |
|||
"Name": "协议Pp" |
|||
}, |
|||
{ |
|||
"type": "DCamera", |
|||
"Name": "协议D508" |
|||
} |
|||
|
|||
] |
|||
}, |
|||
"military": { |
|||
"url": "http://192.168.1.119:8080/military", |
|||
"username": "admin", |
|||
"password": "123456", |
|||
"requestTryTime": "5", |
|||
"requestTryInterval": "200" |
|||
}, |
|||
"alarmPlatform": { |
|||
"realPlay": true, |
|||
"type": "mqtt", |
|||
"mqtt": { |
|||
"ip": "192.168.1.200", |
|||
"port": "1883", |
|||
"username": "admin", |
|||
"password": "public", |
|||
"clientId": "alarm-platform1", |
|||
"retryTime": "5", |
|||
"retryInterval": "200", |
|||
"pubDevicesTopic": "PPS/Devices", |
|||
"pubSensorsTopic": "PPS/Sensors", |
|||
"pubDeviceStateTopic": "PPS/DeviceState", |
|||
"pubSensorStateTopic": "PPS/SensorState", |
|||
"pubAlarmTopic": "PPS/AlarmMessage/Fence", |
|||
"subCmdTopic": "PPS/Cmd" |
|||
} |
|||
} |
|||
} |
Loading…
Reference in new issue