add - 添加码垛线 HMI 界面

dev
WenJY 7 hours ago
parent c76bb985fe
commit fef4b32c41

@ -19,7 +19,8 @@
"Bash(git status *)",
"Bash(dotnet /Users/wenxiansheng/.nuget/packages/avalonia/11.1.5/lib/netstandard2.0/Avalonia.Base.dll type list)",
"Bash(dotnet new *)",
"Bash(dotnet add *)"
"Bash(dotnet add *)",
"Bash(python3 *)"
]
}
}

@ -92,6 +92,7 @@ public partial class App : Application
services.AddTransient<ViewModels.Path.PathDetailsViewModel>();
services.AddTransient<ViewModels.Task.TaskQueueViewModel>();
services.AddTransient<ViewModels.Task.TaskDetailViewModel>();
services.AddTransient<ViewModels.HMI.PalletizerHMIViewModel>();
// 引擎进程管理
services.AddSingleton<IEngineProcessService, EngineProcessService>();

@ -0,0 +1,99 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Avalonia.Controls;
namespace Sln.Wcs.UI.ViewModels.HMI;
public class HmiSignalItem
{
public string Name { get; set; } = "";
public string Address { get; set; } = "";
public string Value { get; set; } = "OFF";
public bool IsOn => Value == "ON";
}
public partial class PalletizerHMIViewModel
{
public string PageTitle => "码垛机 HMI";
public ObservableCollection<HmiSignalItem> Manual1Items { get; } = new();
public ObservableCollection<HmiSignalItem> Manual2Items { get; } = new();
public ObservableCollection<HmiSignalItem> AlarmItems { get; } = new();
public ObservableCollection<HmiSignalItem> InputItems { get; } = new();
public ObservableCollection<HmiSignalItem> OutputItems { get; } = new();
public PalletizerHMIViewModel()
{
// 手动操作
Manual1Items = new ObservableCollection<HmiSignalItem>
{
new(){Name="1#滚筒线正转",Address="DB100.DBX0.0"}, new(){Name="1#皮带线正转",Address="DB100.DBX0.1"},
new(){Name="1#侧推机构伸出",Address="DB100.DBX0.2"}, new(){Name="1#侧推机构缩回",Address="DB100.DBX0.3"},
new(){Name="1#阻挡上升",Address="DB100.DBX0.4"}, new(){Name="1#阻挡下降",Address="DB100.DBX0.5"},
new(){Name="1#侧推转弯伸出",Address="DB100.DBX0.6"}, new(){Name="1#侧推转弯缩回",Address="DB100.DBX0.7"},
};
Manual2Items = new ObservableCollection<HmiSignalItem>
{
new(){Name="2#滚筒线正转",Address="DB100.DBX16.0"}, new(){Name="2#皮带线正转",Address="DB100.DBX16.1"},
new(){Name="2#侧推机构伸出",Address="DB100.DBX16.2"}, new(){Name="2#侧推机构缩回",Address="DB100.DBX16.3"},
new(){Name="2#阻挡上升",Address="DB100.DBX16.4"}, new(){Name="2#阻挡下降",Address="DB100.DBX16.5"},
new(){Name="2#侧推机构2伸出",Address="DB100.DBX16.6"}, new(){Name="2#侧推机构2缩回",Address="DB100.DBX16.7"},
};
// 报警
AlarmItems = new ObservableCollection<HmiSignalItem>
{
new(){Name="1号滚筒线异常",Address="DB102.DBX0.0"}, new(){Name="1号皮带线异常",Address="DB102.DBX0.1"},
new(){Name="2号滚筒线异常",Address="DB102.DBX0.2"}, new(){Name="2号皮带线异常",Address="DB102.DBX0.3"},
new(){Name="1号侧推伸出超时",Address="DB102.DBX0.4"}, new(){Name="1号侧推缩回超时",Address="DB102.DBX0.5"},
new(){Name="1号阻挡伸出超时",Address="DB102.DBX0.6"}, new(){Name="1号阻挡缩回超时",Address="DB102.DBX0.7"},
new(){Name="1号侧推转弯伸出超时",Address="DB102.DBX1.0"}, new(){Name="1号侧推转弯缩回超时",Address="DB102.DBX1.1"},
new(){Name="2号侧推伸出超时",Address="DB102.DBX1.2"}, new(){Name="2号侧推缩回超时",Address="DB102.DBX1.3"},
new(){Name="2号阻挡伸出超时",Address="DB102.DBX1.4"}, new(){Name="2号阻挡缩回超时",Address="DB102.DBX1.5"},
};
// 输入
InputItems = new ObservableCollection<HmiSignalItem>
{
new(){Name="急停",Address="DB103.DBX0.0"}, new(){Name="复位1",Address="DB103.DBX0.1"},
new(){Name="手动1",Address="DB103.DBX0.2"}, new(){Name="自动1",Address="DB103.DBX0.3"},
new(){Name="实施1",Address="DB103.DBX0.4"}, new(){Name="复位2",Address="DB103.DBX0.5"},
new(){Name="手动2",Address="DB103.DBX0.6"}, new(){Name="自动2",Address="DB103.DBX0.7"},
new(){Name="实施2",Address="DB103.DBX1.0"}, new(){Name="1号入口到位",Address="DB103.DBX1.1"},
new(){Name="1号出口到位",Address="DB103.DBX1.2"}, new(){Name="1号喷码到位",Address="DB103.DBX1.3"},
new(){Name="1号阻挡原位",Address="DB103.DBX1.4"}, new(){Name="1号阻挡工作位",Address="DB103.DBX1.5"},
new(){Name="1号侧推原位",Address="DB103.DBX1.6"}, new(){Name="1号侧推工作位",Address="DB103.DBX1.7"},
new(){Name="1号扫码位置",Address="DB103.DBX2.0"}, new(){Name="2号入口到位",Address="DB103.DBX2.1"},
new(){Name="2号出口到位",Address="DB103.DBX2.2"}, new(){Name="2号喷码到位",Address="DB103.DBX2.3"},
new(){Name="2号阻挡原位",Address="DB103.DBX2.4"}, new(){Name="2号阻挡工作位",Address="DB103.DBX2.5"},
new(){Name="2号侧推原位",Address="DB103.DBX2.6"}, new(){Name="2号侧推工作位",Address="DB103.DBX2.7"},
new(){Name="2号扫码位置",Address="DB103.DBX3.0"}, new(){Name="1号滚筒电机异常",Address="DB103.DBX3.1"},
new(){Name="1号皮带电机异常",Address="DB103.DBX3.2"}, new(){Name="2号滚筒电机异常",Address="DB103.DBX3.3"},
new(){Name="2号皮带电机异常",Address="DB103.DBX3.4"}, new(){Name="1号侧推转弯原位",Address="DB103.DBX3.5"},
new(){Name="1号侧推转弯工作位",Address="DB103.DBX3.6"},
};
// 输出
OutputItems = new ObservableCollection<HmiSignalItem>
{
new(){Name="1号滚筒线正转",Address="DB103.DBX4.0"}, new(){Name="1号皮带线正转",Address="DB103.DBX4.1"},
new(){Name="2号滚筒线正转",Address="DB103.DBX4.2"}, new(){Name="2号皮带线正转",Address="DB103.DBX4.3"},
new(){Name="1号侧推机构伸出",Address="DB103.DBX4.4"}, new(){Name="1号侧推机构缩回",Address="DB103.DBX4.5"},
new(){Name="2号侧推机构伸出",Address="DB103.DBX4.6"}, new(){Name="2号侧推机构缩回",Address="DB103.DBX4.7"},
new(){Name="1号阻挡器伸出",Address="DB103.DBX5.0"}, new(){Name="1号阻挡器缩回",Address="DB103.DBX5.1"},
new(){Name="2号阻挡器伸出",Address="DB103.DBX5.2"}, new(){Name="2号阻挡器缩回",Address="DB103.DBX5.3"},
new(){Name="1号侧推转弯伸出",Address="DB103.DBX5.4"}, new(){Name="1号侧推转弯缩回",Address="DB103.DBX5.5"},
new(){Name="电源指示灯",Address="DB103.DBX5.6"}, new(){Name="红灯",Address="DB103.DBX5.7"},
new(){Name="黄灯",Address="DB103.DBX6.0"}, new(){Name="绿灯",Address="DB103.DBX6.1"},
new(){Name="蜂鸣",Address="DB103.DBX6.2"}, new(){Name="运行灯1",Address="DB103.DBX6.3"},
new(){Name="复位灯1",Address="DB103.DBX6.4"}, new(){Name="运行灯2",Address="DB103.DBX6.5"},
new(){Name="复位灯2",Address="DB103.DBX6.6"},
};
}
public Control CreateView()
{
var view = new Views.HMI.PalletizerHMIView { DataContext = this };
return view;
}
}

@ -6,6 +6,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.Extensions.DependencyInjection;
using Sln.Wcs.UI.ViewModels.Base;
using Sln.Wcs.UI.ViewModels.Device;
using Sln.Wcs.UI.ViewModels.HMI;
using Sln.Wcs.UI.ViewModels.Path;
using Sln.Wcs.UI.ViewModels.Task;
using Sln.Wcs.UI.Views;
@ -15,7 +16,7 @@ namespace Sln.Wcs.UI.ViewModels;
public partial class NavigationViewModel : ObservableObject
{
private readonly IServiceProvider _sp;
private readonly Dictionary<Type, ICrudPageViewModel> _vmCache = new();
private readonly Dictionary<Type, object> _vmCache = new();
private readonly Dictionary<Type, Control> _viewCache = new();
private Control? _homeView;
@ -61,6 +62,10 @@ public partial class NavigationViewModel : ObservableObject
new("任务队列", () => NavigateTo<TaskQueueViewModel>("任务管理")),
new("任务明细", () => NavigateTo<TaskDetailViewModel>("任务管理")),
}));
TopMenuItems.Add(new TopMenuItem("HMI", new List<SubMenuItem>
{
new("码垛机监控", () => NavigateTo<PalletizerHMIViewModel>("HMI")),
}));
}
private string? _currentModule;
@ -82,23 +87,27 @@ public partial class NavigationViewModel : ObservableObject
PageChanged?.Invoke(new SystemMonitorView(_sp.GetRequiredService<SystemMonitorViewModel>()));
}
private void NavigateTo<T>(string module) where T : ICrudPageViewModel
private void NavigateTo<T>(string module) where T : class
{
var type = typeof(T);
if (!_vmCache.TryGetValue(type, out var vm))
if (!_vmCache.TryGetValue(type, out var obj))
{
vm = _sp.GetRequiredService<T>();
_vmCache[type] = vm;
obj = _sp.GetRequiredService<T>();
_vmCache[type] = obj;
}
if (!_viewCache.TryGetValue(type, out var view))
{
view = vm.CreateView();
view.DataContext = vm;
view = ((dynamic)obj).CreateView();
view.DataContext = obj;
_viewCache[type] = view;
}
CurrentPageTitle = $"{module} > {vm.PageTitle}";
var title = (obj as dynamic).PageTitle ?? type.Name;
CurrentPageTitle = $"{module} > {title}";
PageChanged?.Invoke(view);
vm.Load();
var load = obj.GetType().GetMethod("Load");
load?.Invoke(obj, null);
}
}

@ -0,0 +1,194 @@
<UserControl x:CompileBindings="False" xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Sln.Wcs.UI.Views.HMI.PalletizerHMIView">
<UserControl.Styles>
<Style Selector="ToggleButton.hmiKnob">
<Setter Property="Width" Value="48" />
<Setter Property="Height" Value="24" />
<Setter Property="Padding" Value="0" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<ControlTemplate>
<Panel Width="48" Height="24">
<Border CornerRadius="12" Background="{DynamicResource PageBgBrush}" BorderBrush="{DynamicResource BorderBrush}" BorderThickness="1" />
<Border CornerRadius="10" Background="{DynamicResource CardBgBrush}" Margin="3" />
<Border Name="PART_Knob" Width="18" Height="18" CornerRadius="9"
HorizontalAlignment="Left" Margin="3,3,0,0">
<Border.Background>
<LinearGradientBrush StartPoint="0%,0%" EndPoint="0%,100%">
<GradientStop Color="#FF5252" Offset="0" />
<GradientStop Color="#B71C1C" Offset="0.5" />
<GradientStop Color="#8B0000" Offset="1" />
</LinearGradientBrush>
</Border.Background>
<Border.BorderBrush>
<LinearGradientBrush StartPoint="0%,0%" EndPoint="0%,100%">
<GradientStop Color="#FF8A80" Offset="0" />
<GradientStop Color="#C62828" Offset="1" />
</LinearGradientBrush>
</Border.BorderBrush>
<Border BorderThickness="1" CornerRadius="9" />
</Border>
</Panel>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="ToggleButton.hmiKnob:checked /template/ Border#PART_Knob">
<Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="Margin" Value="0,3,3,0" />
<Setter Property="Background">
<LinearGradientBrush StartPoint="0%,0%" EndPoint="0%,100%">
<GradientStop Color="#69F0AE" Offset="0" />
<GradientStop Color="#00C853" Offset="0.5" />
<GradientStop Color="#006C2E" Offset="1" />
</LinearGradientBrush>
</Setter>
<Setter Property="BorderBrush">
<LinearGradientBrush StartPoint="0%,0%" EndPoint="0%,100%">
<GradientStop Color="#B9F6CA" Offset="0" />
<GradientStop Color="#00A844" Offset="1" />
</LinearGradientBrush>
</Setter>
</Style>
</UserControl.Styles>
<ScrollViewer Margin="16,12,16,12">
<StackPanel Spacing="10">
<!-- Title -->
<StackPanel Orientation="Horizontal" Spacing="10" Margin="0,0,0,4">
<Rectangle Width="4" Height="22" Fill="{DynamicResource AccentTextBrush}" RadiusX="2" RadiusY="2" VerticalAlignment="Center" />
<TextBlock Text="码垛机 HMI 监控界面" FontSize="17" FontWeight="Bold" Foreground="{DynamicResource TitleTextBrush}" VerticalAlignment="Center" />
</StackPanel>
<!-- ===== 1. 手动操作区 ===== -->
<Border Background="{DynamicResource CardBgBrush}" CornerRadius="6" Padding="14,12" BorderBrush="{DynamicResource BorderBrush}" BorderThickness="1">
<StackPanel Spacing="10">
<TextBlock Text="手动操作" FontSize="14" FontWeight="SemiBold" Foreground="{DynamicResource AccentTextBrush}" />
<Grid ColumnDefinitions="*,*">
<!-- 1# -->
<Border Grid.Column="0" Background="{DynamicResource SurfaceBgBrush}" CornerRadius="4" Padding="12,12" Margin="0,0,6,0" BorderBrush="{DynamicResource BorderBrush}" BorderThickness="1">
<StackPanel Spacing="6">
<TextBlock Text="1# 工位" FontSize="13" FontWeight="SemiBold" Foreground="{DynamicResource PrimaryTextBrush}" Margin="0,0,0,4" />
<ItemsControl ItemsSource="{Binding Manual1Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate><WrapPanel /></ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Padding="6,5" Margin="0,1" Background="Transparent">
<Grid ColumnDefinitions="120,100,50">
<TextBlock Grid.Column="0" Text="{Binding Name}" FontSize="11" Foreground="{DynamicResource PrimaryTextBrush}" VerticalAlignment="Center" HorizontalAlignment="Left" />
<TextBlock Grid.Column="1" Text="{Binding Address}" FontSize="9" Foreground="{DynamicResource SubtleTextBrush}" VerticalAlignment="Center" FontFamily="Menlo,Consolas,monospace" HorizontalAlignment="Left" />
<ToggleButton Grid.Column="2" Classes="hmiKnob" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
<!-- 2# -->
<Border Grid.Column="1" Background="{DynamicResource SurfaceBgBrush}" CornerRadius="4" Padding="12,10" Margin="6,0,0,0" BorderBrush="{DynamicResource BorderBrush}" BorderThickness="1">
<StackPanel Spacing="4">
<TextBlock Text="2# 工位" FontSize="13" FontWeight="SemiBold" Foreground="{DynamicResource PrimaryTextBrush}" Margin="0,0,0,4" />
<ItemsControl ItemsSource="{Binding Manual2Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate><WrapPanel /></ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Padding="6,5" Margin="0,1" Background="Transparent">
<Grid ColumnDefinitions="120,100,50">
<TextBlock Grid.Column="0" Text="{Binding Name}" FontSize="11" Foreground="{DynamicResource PrimaryTextBrush}" VerticalAlignment="Center" HorizontalAlignment="Left" />
<TextBlock Grid.Column="1" Text="{Binding Address}" FontSize="9" Foreground="{DynamicResource SubtleTextBrush}" VerticalAlignment="Center" FontFamily="Menlo,Consolas,monospace" HorizontalAlignment="Left" />
<ToggleButton Grid.Column="2" Classes="hmiKnob" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
</Grid>
</StackPanel>
</Border>
<!-- ===== 2. 报警信息区 ===== -->
<Border Background="{DynamicResource CardBgBrush}" CornerRadius="6" Padding="14,12" BorderBrush="{DynamicResource BorderBrush}" BorderThickness="1">
<StackPanel Spacing="8">
<StackPanel Orientation="Horizontal" Spacing="8">
<TextBlock Text="报警信息" FontSize="14" FontWeight="SemiBold" Foreground="{DynamicResource WarningBrush}" />
<TextBlock Text="(全部正常)" FontSize="11" Foreground="{DynamicResource MutedTextBrush}" VerticalAlignment="Center" />
</StackPanel>
<WrapPanel>
<ItemsControl ItemsSource="{Binding AlarmItems}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate><WrapPanel /></ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Width="230" Padding="6,4" Margin="0,0,8,4" Background="{DynamicResource SurfaceBgBrush}" CornerRadius="3" BorderBrush="{DynamicResource BorderBrush}" BorderThickness="1">
<Grid ColumnDefinitions="Auto,*,Auto">
<Ellipse Grid.Column="0" Width="8" Height="8" Fill="#00E676" VerticalAlignment="Center" Margin="0,0,6,0" />
<TextBlock Grid.Column="1" Text="{Binding Name}" FontSize="11" Foreground="{DynamicResource SecondaryTextBrush}" VerticalAlignment="Center" />
<TextBlock Grid.Column="2" Text="{Binding Address}" FontSize="9" Foreground="{DynamicResource SubtleTextBrush}" VerticalAlignment="Center" FontFamily="Menlo,Consolas,monospace" Margin="6,0,0,0" />
</Grid>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</WrapPanel>
</StackPanel>
</Border>
<!-- ===== 3 & 4. IO 输入 / IO 输出并排 ===== -->
<Grid ColumnDefinitions="*,*">
<!-- IO 输入 -->
<Border Grid.Column="0" Background="{DynamicResource CardBgBrush}" CornerRadius="6" Padding="14,12" Margin="0,0,6,0" BorderBrush="{DynamicResource BorderBrush}" BorderThickness="1">
<StackPanel Spacing="6">
<TextBlock Text="IO 输入信号" FontSize="14" FontWeight="SemiBold" Foreground="{DynamicResource AccentTextBrush}" />
<ItemsControl ItemsSource="{Binding InputItems}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate><WrapPanel /></ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Width="210" Padding="3,2" Margin="0,1" Background="Transparent">
<Grid ColumnDefinitions="Auto,*,80">
<Ellipse Grid.Column="0" Width="7" Height="7" Fill="#555" VerticalAlignment="Center" Margin="0,0,6,0" />
<TextBlock Grid.Column="1" Text="{Binding Name}" FontSize="11" Foreground="{DynamicResource SecondaryTextBrush}" VerticalAlignment="Center" HorizontalAlignment="Left" />
<TextBlock Grid.Column="2" Text="{Binding Address}" FontSize="9" Foreground="{DynamicResource SubtleTextBrush}" VerticalAlignment="Center" FontFamily="Menlo,Consolas,monospace" />
</Grid>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
<!-- IO 输出 -->
<Border Grid.Column="1" Background="{DynamicResource CardBgBrush}" CornerRadius="6" Padding="14,12" Margin="6,0,0,0" BorderBrush="{DynamicResource BorderBrush}" BorderThickness="1">
<StackPanel Spacing="6">
<TextBlock Text="IO 输出信号" FontSize="14" FontWeight="SemiBold" Foreground="{DynamicResource AccentTextBrush}" />
<ItemsControl ItemsSource="{Binding OutputItems}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate><WrapPanel /></ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Width="210" Padding="3,2" Margin="0,1" Background="Transparent">
<Grid ColumnDefinitions="Auto,*,80">
<Ellipse Grid.Column="0" Width="7" Height="7" Fill="#555" VerticalAlignment="Center" Margin="0,0,6,0" />
<TextBlock Grid.Column="1" Text="{Binding Name}" FontSize="11" Foreground="{DynamicResource SecondaryTextBrush}" VerticalAlignment="Center" HorizontalAlignment="Left" />
<TextBlock Grid.Column="2" Text="{Binding Address}" FontSize="9" Foreground="{DynamicResource SubtleTextBrush}" VerticalAlignment="Center" FontFamily="Menlo,Consolas,monospace" />
</Grid>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
</Grid>
</StackPanel>
</ScrollViewer>
</UserControl>

@ -0,0 +1,11 @@
using Avalonia.Controls;
namespace Sln.Wcs.UI.Views.HMI;
public partial class PalletizerHMIView : UserControl
{
public PalletizerHMIView()
{
InitializeComponent();
}
}
Loading…
Cancel
Save