Ver Fonte

上传代码

luo há 1 semana atrás
pai
commit
890cf35227
27 ficheiros alterados com 1229 adições e 4 exclusões
  1. 0 1
      Client/Dynamicloadsimulationdevice/Dynamicloadsimulationdevice.csproj
  2. 1 1
      Client/IViewModel/PropertyAssociationAttribute.cs
  3. 74 0
      Client/IViewModel/Tools/ResourceBinding.cs
  4. 1 1
      Client/IViewModel/ViewModels/Log/LogViewModel.cs
  5. 18 0
      Client/OilSourceControl/IOilSourceControl/IOilSourceControl.cs
  6. 14 0
      Client/OilSourceControl/IOilSourceControl/IOilSourceControl.csproj
  7. 26 0
      Client/OilSourceControl/OilSourceControl/OilSourceControl.cs
  8. 16 0
      Client/OilSourceControl/OilSourceControl/OilSourceControl.csproj
  9. 40 0
      Client/OilSourceControl/OilSourceControl/View/LEDControl.axaml
  10. 13 0
      Client/OilSourceControl/OilSourceControl/View/LEDControl.axaml.cs
  11. 94 0
      Client/OilSourceControl/OilSourceControl/View/OilAnalogView.axaml
  12. 13 0
      Client/OilSourceControl/OilSourceControl/View/OilAnalogView.axaml.cs
  13. 190 0
      Client/OilSourceControl/OilSourceControl/View/OilControlView.axaml
  14. 13 0
      Client/OilSourceControl/OilSourceControl/View/OilControlView.axaml.cs
  15. 60 0
      Client/OilSourceControl/OilSourceControl/View/OilMinView.axaml
  16. 13 0
      Client/OilSourceControl/OilSourceControl/View/OilMinView.axaml.cs
  17. 160 0
      Client/OilSourceControl/OilSourceControl/View/PumpControlView.axaml
  18. 13 0
      Client/OilSourceControl/OilSourceControl/View/PumpControlView.axaml.cs
  19. 123 0
      Client/OilSourceControl/OilSourceControl/ViewModel/CircuitViewModel.cs
  20. 39 0
      Client/OilSourceControl/OilSourceControl/ViewModel/OilErrorInfoViewModel.cs
  21. 64 0
      Client/OilSourceControl/OilSourceControl/ViewModel/OilSourceAnalogViewModel.cs
  22. 199 0
      Client/OilSourceControl/OilSourceControl/ViewModel/OilSourceStatusViewModel.cs
  23. 17 0
      Dynamicloadsimulationdevice.sln
  24. 5 1
      Service/ShakerService/Service.cs
  25. 20 0
      Shaker.Model/Models/AllConfig.cs
  26. 1 0
      Shaker.Model/Shaker.Model.csproj
  27. 2 0
      Shaker.Model/Topic.cs

+ 0 - 1
Client/Dynamicloadsimulationdevice/Dynamicloadsimulationdevice.csproj

@@ -29,7 +29,6 @@
     <ProjectReference Include="..\..\Avalonia\IconResourceSourceGenerator\IconResourceSourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
     <ProjectReference Include="..\..\Avalonia\IconResource\IconResource.csproj" />
     <ProjectReference Include="..\IViewModel\IViewModel.csproj" />
-    <ProjectReference Include="..\Language\LanguageSourceGenerator\LanguageSourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
     <ProjectReference Include="..\OxyPlot\OxyPlot.Avalonia\OxyPlot.Avalonia.csproj" />
   </ItemGroup>
 </Project>

+ 1 - 1
Client/IViewModel/ViewModels/PropertyAssociationAttribute.cs → Client/IViewModel/PropertyAssociationAttribute.cs

@@ -1,7 +1,7 @@
 using System;
 using System.Collections.Generic;
 
-namespace IViewModel.ViewModels
+namespace IViewModel
 {
     [AttributeUsage(AttributeTargets.Property)]
     public sealed class PropertyAssociationAttribute: Attribute 

+ 74 - 0
Client/IViewModel/Tools/ResourceBinding.cs

@@ -0,0 +1,74 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Data;
+using Avalonia.Data.Converters;
+using Avalonia.Markup.Xaml;
+using Avalonia.Markup.Xaml.MarkupExtensions;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+
+namespace IViewModel
+{
+    /// <summary>
+    /// 多语言绑定时使用,没有其他任何功能
+    /// </summary>
+    public class ResourceBindingExtensions
+    {
+        public static readonly AttachedProperty<object?> BindingExtensionProperty = AvaloniaProperty.RegisterAttached<Control, object?>("BindingExtension", typeof(Control), defaultValue: null);
+        public static object? GetBindingExtension(Control control) => control.GetValue(BindingExtensionProperty);
+        public static void SetBindingExtension(Control control, object? value) => control.SetValue(BindingExtensionProperty, value);
+    }
+    public class ResourceBinding : MarkupExtension
+    {
+        private PathConverter converter = new PathConverter();
+
+        public ResourceBinding(string path)
+        {
+            this.Path = path;
+        }
+
+        public override object ProvideValue(IServiceProvider serviceProvider)
+        {
+            var provideValueTargetService = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget))!;
+
+            var targetObject = provideValueTargetService.TargetObject as Control;
+            var targetProperty = provideValueTargetService.TargetProperty as AvaloniaProperty;
+            if (targetObject == null || targetProperty == null) return null;
+            Binding binding = new Binding()
+            {
+                Path = Path,
+                Converter = converter,
+                ConverterParameter = new KeyValuePair<Control,AvaloniaProperty>(targetObject,targetProperty),
+                Mode = BindingMode.OneWay,
+                UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
+            };
+            targetObject.Bind(ResourceBindingExtensions.BindingExtensionProperty, binding);
+
+            return null;
+        }
+
+        /// <summary>
+        /// The source path (for CLR bindings).
+        /// </summary>
+        public string Path { get; set; }
+
+        private class PathConverter : IValueConverter
+        {
+            public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
+            {
+                if (parameter is KeyValuePair<Control, AvaloniaProperty> p && value is string v)
+                {
+                    p.Key.Bind(p.Value, new DynamicResourceExtension(v));
+                }
+                return "";
+            }
+
+            public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
+            {
+                throw new NotImplementedException();
+            }
+        }
+
+    }
+}

+ 1 - 1
Client/IViewModel/ViewModels/Log/LogViewModel.cs

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
 
 namespace IViewModel.ViewModels
 {
-    internal class LogViewModel:DisplayViewModelBase<IModel.IModel>
+    public sealed class LogViewModel:DisplayViewModelBase<IModel.IModel>
     {
         public AvaloniaList<IndexValueItemViewModel<LogItemViewModel>> Logs { get; } = new AvaloniaList<IndexValueItemViewModel<LogItemViewModel>>();
         private LogViewModel()

+ 18 - 0
Client/OilSourceControl/IOilSourceControl/IOilSourceControl.cs

@@ -0,0 +1,18 @@
+using IViewModel.ViewModels;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace IOilSourceControl
+{
+    public interface IOilSourceControl
+    {
+        public Func<ICommunication.ICommunication> LocalCommunication { get; set; }
+        public Func<ICommunication.ICommunication> RemoteCommunication { get; set; }
+        public ViewModelBase ViewModel { get; }
+        public Type MainViewType { get; }
+        public Type MinViewType { get; }
+    }
+}

+ 14 - 0
Client/OilSourceControl/IOilSourceControl/IOilSourceControl.csproj

@@ -0,0 +1,14 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net8.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\Communication\ICommunication\ICommunication.csproj" />
+    <ProjectReference Include="..\..\IViewModel\IViewModel.csproj" />
+  </ItemGroup>
+
+</Project>

+ 26 - 0
Client/OilSourceControl/OilSourceControl/OilSourceControl.cs

@@ -0,0 +1,26 @@
+using IViewModel.ViewModels;
+using OilSourceControl.ViewModel;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace OilSourceControl
+{
+    internal sealed class OilSourceControl : IOilSourceControl.IOilSourceControl
+    {
+        [AllowNull]
+        public Func<ICommunication.ICommunication> LocalCommunication { get; set; }
+        [AllowNull]
+        public Func<ICommunication.ICommunication> RemoteCommunication { get; set; }
+
+        public ViewModelBase ViewModel => OilSourceStatusViewModel.Instance;
+
+        public Type MainViewType => throw new NotImplementedException();
+
+        public Type MinViewType => throw new NotImplementedException();
+
+    }
+}

+ 16 - 0
Client/OilSourceControl/OilSourceControl/OilSourceControl.csproj

@@ -0,0 +1,16 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net8.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\EventBroker\EventBroker\EventBroker.csproj" />
+    <ProjectReference Include="..\..\..\OilSourceModel\OilSourceModel.csproj" />
+    <ProjectReference Include="..\..\Avalonia\Avalonia.Xaml.Behaviors\Avalonia.Xaml.Behaviors.csproj" />
+    <ProjectReference Include="..\IOilSourceControl\IOilSourceControl.csproj" />
+  </ItemGroup>
+
+</Project>

+ 40 - 0
Client/OilSourceControl/OilSourceControl/View/LEDControl.axaml

@@ -0,0 +1,40 @@
+<UserControl
+    x:Class="OilSourceControl.View.LEDControl"
+    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"
+    d:DesignHeight="450"
+    d:DesignWidth="450"
+    mc:Ignorable="d">
+    <Viewbox Stretch="Fill">
+        <Grid
+            Width="56"
+            Height="56"
+            Margin="0"
+            HorizontalAlignment="Center"
+            VerticalAlignment="Center">
+            <Ellipse
+                Width="46"
+                Height="46"
+                HorizontalAlignment="Center"
+                VerticalAlignment="Center">
+                <Ellipse.Fill>
+                    <RadialGradientBrush Center="50% 50%" GradientOrigin="50% 50%">
+                        <GradientStop Offset="0" Color="{Binding $parent[UserControl].Foreground, Converter={StaticResource BrushToColorConverter}, ConverterParameter=10}" />
+                        <GradientStop Offset="0.7" Color="{Binding $parent[UserControl].Foreground, Converter={StaticResource BrushToColorConverter}, ConverterParameter=180}" />
+                        <GradientStop Offset="1" Color="{Binding $parent[UserControl].Foreground, Converter={StaticResource BrushToColorConverter}}" />
+                    </RadialGradientBrush>
+                </Ellipse.Fill>
+            </Ellipse>
+            <Ellipse
+                Width="56"
+                Height="56"
+                HorizontalAlignment="Center"
+                VerticalAlignment="Center"
+                Fill="Transparent"
+                Stroke="{Binding $parent[UserControl].Foreground}"
+                StrokeThickness="2" />
+        </Grid>
+    </Viewbox>
+</UserControl>

+ 13 - 0
Client/OilSourceControl/OilSourceControl/View/LEDControl.axaml.cs

@@ -0,0 +1,13 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace OilSourceControl.View;
+
+public partial class LEDControl : UserControl
+{
+    public LEDControl()
+    {
+        InitializeComponent();
+    }
+}

+ 94 - 0
Client/OilSourceControl/OilSourceControl/View/OilAnalogView.axaml

@@ -0,0 +1,94 @@
+<UserControl
+    x:Class="OilSourceControl.View.OilAnalogView"
+    xmlns="https://github.com/avaloniaui"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:local="using:OilSourceControl"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    xmlns:vm="using:OilSourceControl.ViewModel"
+    xmlns:ivm="using:IViewModel"
+    Height="140"
+    d:DesignHeight="450"
+    d:DesignWidth="800"
+    x:DataType="vm:OilSourceAnalogViewModel"
+    mc:Ignorable="d">
+    <StackPanel
+        MinWidth="220"
+        HorizontalAlignment="Center"
+        VerticalAlignment="Center">
+        <StackPanel
+            HorizontalAlignment="Center"
+            VerticalAlignment="Center"
+            Orientation="Horizontal">
+            <TextBlock
+                HorizontalAlignment="Center"
+                VerticalAlignment="Center"
+                FontSize="36"
+                Foreground="{StaticResource OilDefaultColor}"
+                Text="{ivm:ResourceBinding Name}" />
+            <PathIcon
+                Width="32"
+                Height="24"
+                Margin="10,0,0,0"
+                VerticalAlignment="Center"
+                Classes.IsError="{Binding IsError}"
+                Classes.IsWarn="{Binding IsWarn}"
+                Data="M16,0 L32,24 L0,24Z"
+                IsVisible="{Binding IsUpper}">
+                <PathIcon.Styles>
+                    <Style Selector="PathIcon">
+                        <Setter Property="Foreground" Value="{StaticResource OilDefaultColor}" />
+                    </Style>
+                    <Style Selector="PathIcon.IsError">
+                        <Setter Property="Foreground" Value="{StaticResource ErrorColor}" />
+                    </Style>
+                    <Style Selector="PathIcon.IsWarn">
+                        <Setter Property="Foreground" Value="{StaticResource WarnColor}" />
+                    </Style>
+                </PathIcon.Styles>
+            </PathIcon>
+            <PathIcon
+                Width="32"
+                Height="24"
+                HorizontalAlignment="Right"
+                VerticalAlignment="Center"
+                Classes.IsError="{Binding IsError}"
+                Classes.IsWarn="{Binding IsWarn}"
+                Data="M0,0 L32,0 L16,24Z"
+                IsVisible="{Binding IsLower}">
+                <PathIcon.Styles>
+                    <Style Selector="PathIcon">
+                        <Setter Property="Foreground" Value="{StaticResource OilDefaultColor}" />
+                    </Style>
+                    <Style Selector="PathIcon.IsError">
+                        <Setter Property="Foreground" Value="{StaticResource ErrorColor}" />
+                    </Style>
+                    <Style Selector="PathIcon.IsWarn">
+                        <Setter Property="Foreground" Value="{StaticResource WarnColor}" />
+                    </Style>
+                </PathIcon.Styles>
+            </PathIcon>
+        </StackPanel>
+        <TextBlock
+            HorizontalAlignment="Center"
+            VerticalAlignment="Center"
+            Classes.IsError="{Binding IsError}"
+            Classes.IsWarn="{Binding IsWarn}"
+            FontSize="74"
+            FontWeight="Bold">
+            <Run Text="{Binding Value, StringFormat='{}{0:0.00} '}" />
+            <Run Text="{Binding Unit}" />
+            <TextBlock.Styles>
+                <Style Selector="TextBlock">
+                    <Setter Property="Foreground" Value="{StaticResource OilDefaultColor}" />
+                </Style>
+                <Style Selector="TextBlock.IsError">
+                    <Setter Property="Foreground" Value="{StaticResource ErrorColor}" />
+                </Style>
+                <Style Selector="TextBlock.IsWarn">
+                    <Setter Property="Foreground" Value="{StaticResource WarnColor}" />
+                </Style>
+            </TextBlock.Styles>
+        </TextBlock>
+    </StackPanel>
+</UserControl>

+ 13 - 0
Client/OilSourceControl/OilSourceControl/View/OilAnalogView.axaml.cs

@@ -0,0 +1,13 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace OilSourceControl.View;
+
+public partial class OilAnalogView : UserControl
+{
+    public OilAnalogView()
+    {
+        InitializeComponent();
+    }
+}

+ 190 - 0
Client/OilSourceControl/OilSourceControl/View/OilControlView.axaml

@@ -0,0 +1,190 @@
+<UserControl
+    x:Class="OilSourceControl.View.OilControlView"
+    xmlns="https://github.com/avaloniaui"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:ivm="using:IViewModel"
+    xmlns:local="using:OilSourceControl"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    xmlns:suki="https://github.com/kikipoulet/SukiUI"
+    xmlns:view="using:OilSourceControl.View"
+    xmlns:vm="using:OilSourceControl.ViewModel"
+    d:DesignHeight="450"
+    d:DesignWidth="800"
+    x:DataType="vm:OilSourceStatusViewModel"
+    DataContext="{Binding Source={x:Static vm:OilSourceStatusViewModel.Instance}}"
+    mc:Ignorable="d">
+    <UserControl.IsEnabled>
+        <MultiBinding Converter="{StaticResource MutliBoolConverter}">
+            <Binding Path="IsConnect" />
+            <Binding Path="IsRemote" />
+            <Binding Path="IsEnabled" />
+        </MultiBinding>
+    </UserControl.IsEnabled>
+    <Grid>
+        <Grid.RowDefinitions>
+            <RowDefinition />
+            <RowDefinition Height="auto" />
+        </Grid.RowDefinitions>
+
+        <Grid>
+            <Grid.ColumnDefinitions>
+                <ColumnDefinition Width="*" />
+                <ColumnDefinition Width="2*" />
+            </Grid.ColumnDefinitions>
+
+            <ItemsControl
+                VerticalAlignment="Center"
+                IsEnabled="False"
+                ItemsSource="{Binding OilSourceAnalogs}">
+                <ItemsControl.ItemTemplate>
+                    <DataTemplate>
+                        <view:OilAnalogView IsVisible="{Binding IsVisible}" />
+                    </DataTemplate>
+                </ItemsControl.ItemTemplate>
+            </ItemsControl>
+            <StackPanel Grid.Column="1">
+                <ItemsControl ItemsSource="{Binding Circuit}">
+                    <ItemsControl.ItemTemplate>
+                        <DataTemplate>
+                            <suki:GroupBox IsVisible="{Binding IsVisible}">
+                                <suki:GroupBox.Header>
+                                    <StackPanel Orientation="Horizontal">
+                                        <TextBlock
+                                            VerticalAlignment="Center"
+                                            FontSize="{StaticResource TabItemFontSize}"
+                                            FontWeight="Bold"
+                                            Text="{Binding Index, StringFormat='{}{0}#'}" />
+                                        <TextBlock
+                                            VerticalAlignment="Center"
+                                            FontSize="{StaticResource TabItemFontSize}"
+                                            FontWeight="Bold"
+                                            Text="{ivm:ResourceBinding Value.Name}" />
+                                    </StackPanel>
+                                </suki:GroupBox.Header>
+                                <view:PumpControlView DataContext="{Binding Value}" IsVisible="{Binding IsVisible}" />
+                            </suki:GroupBox>
+                        </DataTemplate>
+                    </ItemsControl.ItemTemplate>
+                </ItemsControl>
+
+                <suki:GroupBox DataContext="{Binding Assistant}" IsVisible="{Binding IsVisible}">
+                    <suki:GroupBox.Header>
+                        <TextBlock
+                            VerticalAlignment="Center"
+                            FontSize="{StaticResource TabItemFontSize}"
+                            FontWeight="Bold"
+                            Text="{ivm:ResourceBinding Name}" />
+                    </suki:GroupBox.Header>
+                    <view:PumpControlView IsVisible="{Binding IsVisible}" />
+                </suki:GroupBox>
+                <suki:GroupBox DataContext="{Binding Forerunner}" IsVisible="{Binding IsVisible}">
+                    <suki:GroupBox.Header>
+                        <TextBlock
+                            VerticalAlignment="Center"
+                            FontSize="{StaticResource TabItemFontSize}"
+                            FontWeight="Bold"
+                            Text="{ivm:ResourceBinding Name}" />
+                    </suki:GroupBox.Header>
+                    <view:PumpControlView IsVisible="{Binding IsVisible}" />
+                </suki:GroupBox>
+
+                <suki:GroupBox DataContext="{Binding Circulate}" IsVisible="{Binding IsVisible}">
+                    <suki:GroupBox.Header>
+                        <TextBlock
+                            VerticalAlignment="Center"
+                            FontSize="{StaticResource TabItemFontSize}"
+                            FontWeight="Bold"
+                            Text="{ivm:ResourceBinding Name}" />
+                    </suki:GroupBox.Header>
+                    <view:PumpControlView IsVisible="{Binding IsVisible}" />
+                </suki:GroupBox>
+            </StackPanel>
+        </Grid>
+
+        <Grid
+            Grid.Row="1"
+            Height="86"
+            Margin="10"
+            ColumnDefinitions="*,2*">
+            <Border
+                Margin="20,10,20,10"
+                Classes.Error="{Binding IsError}"
+                CornerRadius="10">
+                <Border.Styles>
+                    <Style Selector="Border">
+                        <Setter Property="Background" Value="Green" />
+                    </Style>
+                    <Style Selector="Border.Error">
+                        <Setter Property="Background" Value="Red" />
+                    </Style>
+                </Border.Styles>
+                <TextBlock
+                    HorizontalAlignment="Center"
+                    VerticalAlignment="Center"
+                    FontSize="36"
+                    FontStyle="Normal"
+                    FontWeight="Bold"
+                    Text="{Binding OilStatus}" />
+            </Border>
+            <Grid Grid.Column="1" Margin="10">
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition />
+                    <ColumnDefinition Width="86" />
+                    <ColumnDefinition Width="86" />
+                </Grid.ColumnDefinitions>
+                <Border
+                    BorderBrush="Gray"
+                    BorderThickness="1"
+                    CornerRadius="6"
+                    IsVisible="{Binding OilErrors.Count}">
+                    <ItemsControl ItemsSource="{Binding OilErrors}">
+                        <ItemsControl.ItemTemplate>
+                            <DataTemplate>
+                                <StackPanel>
+                                    <TextBlock
+                                        HorizontalAlignment="Center"
+                                        VerticalAlignment="Center"
+                                        Text="{ivm:ResourceBinding Name}" />
+                                    <view:LEDControl
+                                        Width="56"
+                                        Height="56"
+                                        Classes.Error="{Binding Status}" />
+                                </StackPanel>
+                            </DataTemplate>
+                        </ItemsControl.ItemTemplate>
+                    </ItemsControl>
+                </Border>
+                <StackPanel Grid.Column="1">
+                    <TextBlock
+                        HorizontalAlignment="Center"
+                        VerticalAlignment="Center"
+                        Text="{DynamicResource PLCConnectStatus}" />
+                    <view:LEDControl
+                        Width="56"
+                        Height="56"
+                        Classes.Error="{Binding !IsConnect}" />
+                </StackPanel>
+                <StackPanel Grid.Column="2">
+                    <TextBlock
+                        HorizontalAlignment="Center"
+                        VerticalAlignment="Center"
+                        Classes.Warn="{Binding IsRemote}">
+                        <TextBlock.Styles>
+                            <Style Selector="TextBlock">
+                                <Setter Property="Text" Value="{DynamicResource OilLocalControl}" />
+                            </Style>
+                            <Style Selector="TextBlock.Warn">
+                                <Setter Property="Text" Value="{DynamicResource OilRemoteControl}" />
+                            </Style>
+                        </TextBlock.Styles>
+                    </TextBlock>
+                    <view:LEDControl
+                        Width="56"
+                        Height="56"
+                        Classes.Warn="{Binding !IsRemote}" />
+                </StackPanel>
+            </Grid>
+        </Grid>
+    </Grid>
+</UserControl>

+ 13 - 0
Client/OilSourceControl/OilSourceControl/View/OilControlView.axaml.cs

@@ -0,0 +1,13 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace OilSourceControl.View;
+
+public partial class OilControlView : UserControl
+{
+    public OilControlView()
+    {
+        InitializeComponent();
+    }
+}

+ 60 - 0
Client/OilSourceControl/OilSourceControl/View/OilMinView.axaml

@@ -0,0 +1,60 @@
+<UserControl
+    x:Class="OilSourceControl.View.OilMinView"
+    xmlns="https://github.com/avaloniaui"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:ivm="using:IViewModel"
+    xmlns:local="using:OilSourceControl"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    xmlns:suki="https://github.com/kikipoulet/SukiUI"
+    xmlns:vm="using:OilSourceControl.ViewModel"
+    d:DesignHeight="450"
+    d:DesignWidth="150"
+    x:DataType="vm:OilSourceStatusViewModel"
+    DataContext="{Binding Source={x:Static vm:OilSourceStatusViewModel.Instance}}"
+    mc:Ignorable="d">
+    <Expander ExpandDirection="Down">
+        <Expander.Header>
+            <TextBlock
+                FontSize="24"
+                FontWeight="Bold"
+                Text="{DynamicResource OilStatus}" />
+        </Expander.Header>
+
+        <ItemsControl ItemsSource="{Binding OilSourceAnalogs}">
+            <ItemsControl.ItemTemplate>
+                <DataTemplate>
+                    <StackPanel>
+                        <TextBlock
+                            HorizontalAlignment="Center"
+                            VerticalAlignment="Center"
+                            FontSize="24"
+                            Foreground="{StaticResource OilDefaultColor}"
+                            Text="{ivm:ResourceBinding Name}" />
+                        <TextBlock
+                            HorizontalAlignment="Center"
+                            VerticalAlignment="Center"
+                            Classes.IsError="{Binding IsError}"
+                            Classes.IsWarn="{Binding IsWarn}"
+                            FontSize="26"
+                            FontWeight="Bold">
+                            <Run Text="{Binding Value, StringFormat='{}{0:0.00}'}" />
+                            <Run Text="{Binding Unit}" />
+                            <TextBlock.Styles>
+                                <Style Selector="TextBlock">
+                                    <Setter Property="Foreground" Value="{StaticResource OilDefaultColor}" />
+                                </Style>
+                                <Style Selector="TextBlock.IsError">
+                                    <Setter Property="Foreground" Value="{StaticResource ErrorColor}" />
+                                </Style>
+                                <Style Selector="TextBlock.IsWarn">
+                                    <Setter Property="Foreground" Value="{StaticResource WarnColor}" />
+                                </Style>
+                            </TextBlock.Styles>
+                        </TextBlock>
+                    </StackPanel>
+                </DataTemplate>
+            </ItemsControl.ItemTemplate>
+        </ItemsControl>
+    </Expander>
+</UserControl>

+ 13 - 0
Client/OilSourceControl/OilSourceControl/View/OilMinView.axaml.cs

@@ -0,0 +1,13 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace OilSourceControl.View;
+
+public partial class OilMinView : UserControl
+{
+    public OilMinView()
+    {
+        InitializeComponent();
+    }
+}

+ 160 - 0
Client/OilSourceControl/OilSourceControl/View/PumpControlView.axaml

@@ -0,0 +1,160 @@
+<UserControl
+    x:Class="OilSourceControl.View.PumpControlView"
+    xmlns="https://github.com/avaloniaui"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:local="using:OilSourceControl"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    xmlns:suki="https://github.com/kikipoulet/SukiUI"
+    xmlns:vm="using:OilSourceControl.ViewModel"
+    Height="80"
+    Margin="4"
+    d:DesignHeight="450"
+    d:DesignWidth="800"
+    x:DataType="vm:CircuitViewModel"
+    mc:Ignorable="d">
+    <Grid Height="60">
+        <Grid.ColumnDefinitions>
+            <ColumnDefinition Width="{Binding $parent[Grid].Height}" />
+            <ColumnDefinition Width="3*" />
+            <ColumnDefinition Width="*" />
+            <ColumnDefinition Width="*" />
+        </Grid.ColumnDefinitions>
+        <PathIcon
+            Width="{Binding $parent[Grid].Height}"
+            Height="{Binding $parent[Grid].Height}"
+            Classes.IsRunning="{Binding IsStart}"
+            Data="{StaticResource PumpOuterGeometry}">
+            <PathIcon.Styles>
+                <Style Selector="PathIcon">
+                    <Setter Property="Foreground" Value="Gray" />
+                </Style>
+                <Style Selector="PathIcon.IsRunning">
+                    <Setter Property="Foreground" Value="Green" />
+                </Style>
+            </PathIcon.Styles>
+        </PathIcon>
+        <PathIcon
+            Width="30"
+            Height="30"
+            Margin="0,8,0,0"
+            VerticalAlignment="Top"
+            Classes.IsRunning="{Binding IsStart}"
+            Data="{StaticResource PumpInGeometry}">
+            <PathIcon.Styles>
+                <Style Selector="PathIcon">
+                    <Setter Property="Foreground" Value="Gray" />
+                </Style>
+                <Style Selector="PathIcon.IsRunning">
+                    <Setter Property="Foreground" Value="Green" />
+                    <Style.Animations>
+                        <Animation IterationCount="INFINITE" Duration="0:0:2">
+                            <KeyFrame Cue="0%">
+                                <Setter Property="RotateTransform.Angle" Value="0" />
+                            </KeyFrame>
+                            <KeyFrame Cue="100%">
+                                <Setter Property="RotateTransform.Angle" Value="360" />
+                            </KeyFrame>
+                        </Animation>
+                    </Style.Animations>
+                </Style>
+            </PathIcon.Styles>
+        </PathIcon>
+
+
+
+        <Grid Grid.Column="1" Classes.EnablePressure="{Binding !EnablePressure}">
+            <Grid.Styles>
+                <Style Selector="Grid.EnablePressure">
+                    <Setter Property="IsEnabled" Value="False" />
+                </Style>
+            </Grid.Styles>
+            <Grid.ColumnDefinitions>
+                <ColumnDefinition Width="*" />
+                <ColumnDefinition Width="*" />
+                <ColumnDefinition Width="*" />
+            </Grid.ColumnDefinitions>
+            <StackPanel Grid.Column="0">
+                <TextBlock Text="{DynamicResource Pressure}" />
+                <NumericUpDown
+                    IsEnabled="{Binding IsLoadPressure}"
+                    Minimum="0"
+                    Value="{Binding Pressure}" />
+            </StackPanel>
+            <Button
+                Grid.Column="1"
+                Width="120"
+                Height="42"
+                Command="{Binding LoadPressureCommand}">
+                <Button.IsEnabled>
+                    <MultiBinding Converter="{StaticResource MutliBoolConverter}">
+                        <MultiBinding.Bindings>
+                            <Binding Path="!IsLoadPressure" />
+                            <Binding Path="IsStart" />
+                        </MultiBinding.Bindings>
+                    </MultiBinding>
+                </Button.IsEnabled>
+                <StackPanel Orientation="Horizontal">
+                    <PathIcon Data="{StaticResource LoadGeometry}" RenderTransform="rotate(180deg)" />
+                    <TextBlock
+                        Margin="4,0,0,0"
+                        VerticalAlignment="Center"
+                        Text="{DynamicResource LoadPressure}" />
+                </StackPanel>
+            </Button>
+            <Button
+                Grid.Column="2"
+                Width="120"
+                Height="42"
+                Command="{Binding UnloadPressureCommand}">
+                <Button.IsEnabled>
+                    <MultiBinding Converter="{StaticResource MutliBoolConverter}">
+                        <MultiBinding.Bindings>
+                            <Binding Path="IsLoadPressure" />
+                            <Binding Path="IsStart" />
+                        </MultiBinding.Bindings>
+                    </MultiBinding>
+                </Button.IsEnabled>
+                <StackPanel Orientation="Horizontal">
+                    <PathIcon Data="{StaticResource LoadGeometry}" />
+                    <TextBlock
+                        Margin="4,0,0,0"
+                        VerticalAlignment="Center"
+                        Text="{DynamicResource UnloadPressure}" />
+                </StackPanel>
+            </Button>
+        </Grid>
+        <Button
+            Grid.Column="2"
+            Width="120"
+            Height="42"
+            Command="{Binding StartCommand}"
+            IsEnabled="{Binding !IsStart}">
+            <StackPanel Orientation="Horizontal">
+                <PathIcon Data="{StaticResource StartGeometry}" />
+                <TextBlock VerticalAlignment="Center" Text="{DynamicResource Start}" />
+            </StackPanel>
+        </Button>
+        <Button
+            Grid.Column="3"
+            Width="120"
+            Height="42"
+            Command="{Binding StopCommand}">
+            <Button.IsEnabled>
+                <MultiBinding Converter="{StaticResource MutliBoolConverter}">
+                    <MultiBinding.Bindings>
+                        <Binding Path="!IsLoadPressure" />
+                        <Binding Path="IsStart" />
+                    </MultiBinding.Bindings>
+                </MultiBinding>
+            </Button.IsEnabled>
+            <StackPanel Orientation="Horizontal">
+                <PathIcon Data="{StaticResource StopGeometry}" />
+                <TextBlock
+                    Margin="4,0,0,0"
+                    VerticalAlignment="Center"
+                    Text="{DynamicResource Stop}" />
+            </StackPanel>
+        </Button>
+    </Grid>
+</UserControl>

+ 13 - 0
Client/OilSourceControl/OilSourceControl/View/PumpControlView.axaml.cs

@@ -0,0 +1,13 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace OilSourceControl.View;
+
+public partial class PumpControlView : UserControl
+{
+    public PumpControlView()
+    {
+        InitializeComponent();
+    }
+}

+ 123 - 0
Client/OilSourceControl/OilSourceControl/ViewModel/CircuitViewModel.cs

@@ -0,0 +1,123 @@
+using Avalonia;
+using Avalonia.Controls;
+using CommunityToolkit.Mvvm.Input;
+using IViewModel;
+using IViewModel.Models;
+using IViewModel.ViewModels;
+using OilSourceModel.Models;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Input;
+
+namespace OilSourceControl.ViewModel
+{
+    internal sealed class CircuitViewModel:DisplayViewModelBase<CircuitModel>
+    {
+        private int waitTime = 2000;
+        public CircuitViewModel()
+        {
+            //Content = typeof(Views.PumpControlView);
+        }
+        public override bool CanCancel => false;
+        public CircuitViewModel(CircuitModel model) : this()
+        {
+            UpDateModel(model);
+        }
+        [PropertyAssociation(nameof(CircuitModel.IsLoadPressure))]
+        public bool IsLoadPressure { get => Model.IsLoadPressure; set => SetProperty(ref Model.IsLoadPressure, value); }
+        [PropertyAssociation(nameof(CircuitModel.IsEnablePressure))]
+        public bool IsEnablePressure => Model.IsEnablePressure; 
+        [PropertyAssociation(nameof(CircuitModel.Name))]
+        public string Name => Model.Name;
+        private float _Pressure = 0;
+        public float Pressure { get => _Pressure; set => SetProperty(ref _Pressure, value); }
+        [PropertyAssociation(nameof(CircuitModel.IsStart))]
+        public bool IsStart { get => Model.IsStart; set => SetProperty(ref Model.IsStart, value); }
+
+        [PropertyAssociation(nameof(CircuitModel.Name))]
+        public bool IsVisible => !string.IsNullOrEmpty(Name);
+        public ICommand StartCommand => new RelayCommand(Start);
+        private async void Start()
+        {
+            StartAction?.Invoke(true);
+            await Task.Delay(waitTime);
+            if(!IsStart)
+            {
+                string msg = string.Format(Application.Current?.FindResource("PumpStartError")+"",Application.Current?.FindResource(Name));
+                OilSourceStatusViewModel.Instance.ShowToast(msg, Avalonia.Controls.Notifications.NotificationType.Error);
+                LogViewModel.Instance.AddLog(msg, LogType.Error);
+                return;
+            }
+            LogViewModel.Instance.AddLog(string.Format(Application.Current?.FindResource("PumpStartSuccess")+"",Application.Current?.FindResource(Name)), LogType.Info);
+        }
+        public ICommand StopCommand => new RelayCommand(Stop);
+        private async void Stop()
+        {
+            StartAction?.Invoke(false); 
+            await Task.Delay(waitTime);
+            if (IsStart)
+            {
+                string msg = string.Format(Application.Current?.FindResource("PumpStopError") + "", Application.Current?.FindResource(Name));
+                OilSourceStatusViewModel.Instance.ShowToast(msg, Avalonia.Controls.Notifications.NotificationType.Error);
+                LogViewModel.Instance.AddLog(msg, LogType.Error);
+                return;
+            }
+            LogViewModel.Instance.AddLog(string.Format(Application.Current?.FindResource("PumpStopSuccess") + "", Application.Current?.FindResource(Name)), LogType.Info);
+        }
+        public ICommand LoadPressureCommand => new RelayCommand(LoadPressure);
+        private async void LoadPressure()
+        {
+            LoadAction?.Invoke(true); 
+            await Task.Delay(waitTime);
+            if (!IsLoadPressure)
+            {
+                string msg = string.Format(Application.Current?.FindResource("PumpLoadError") + "", Application.Current?.FindResource(Name));
+                OilSourceStatusViewModel.Instance.ShowToast(msg, Avalonia.Controls.Notifications.NotificationType.Error);
+                LogViewModel.Instance.AddLog(msg, LogType.Error);
+                return;
+            }
+            LogViewModel.Instance.AddLog(string.Format(Application.Current?.FindResource("PumpLoadSuccess") + "", Application.Current?.FindResource(Name)), LogType.Info);
+        }
+        [AllowNull]
+        public Action<bool> StartAction { get; set; }
+        [AllowNull]
+        public Action<bool> LoadAction { get; set; }
+        [AllowNull]
+        public Action<float> PressureAction { get; set; }
+        public ICommand UnloadPressureCommand => new RelayCommand(UnloadPressure);
+        private async void UnloadPressure()
+        {
+            Pressure = 0;
+            LoadAction?.Invoke(false); 
+            await Task.Delay(waitTime);
+            if (IsLoadPressure)
+            {
+                string msg = string.Format(Application.Current?.FindResource("PumpUnloadError") + "", Application.Current?.FindResource(Name));
+                OilSourceStatusViewModel.Instance.ShowToast(msg, Avalonia.Controls.Notifications.NotificationType.Error);
+                LogViewModel.Instance.AddLog(msg, LogType.Error);
+                return;
+            }
+            LogViewModel.Instance.AddLog(string.Format(Application.Current?.FindResource("PumpUnloadSuccess") + "", Application.Current?.FindResource(Name)), LogType.Info);
+        }
+        protected override void OnPropertyChanged(PropertyChangedEventArgs e)
+        {
+            base.OnPropertyChanged(e);
+            if (e.PropertyName == nameof(Pressure) && IsLoadPressure)
+            {
+                SetPressure(Pressure);
+            }
+        }
+        private void SetPressure(float pressure)
+        {
+            PressureAction?.Invoke(pressure);
+            LogViewModel.Instance.AddLog(string.Format(Application.Current?.FindResource("PumpPressure") + "", Application.Current?.FindResource(Name), pressure,"MPa"), LogType.Info);
+        }
+
+
+    }
+}

+ 39 - 0
Client/OilSourceControl/OilSourceControl/ViewModel/OilErrorInfoViewModel.cs

@@ -0,0 +1,39 @@
+using Avalonia;
+using Avalonia.Controls;
+using IViewModel.ViewModels;
+using IViewModel;
+using OilSourceModel.Models;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace OilSourceControl.ViewModel
+{
+    public sealed class OilErrorInfoViewModel : ViewModelBase<ErrorInfoModel>
+    {
+        public OilErrorInfoViewModel()
+        {
+
+        }
+        public OilErrorInfoViewModel(ErrorInfoModel model) : base(model)
+        {
+        }
+        [PropertyAssociation(nameof(ErrorInfoModel.Name))]
+        public string Name => Model.Name;
+        [PropertyAssociation(nameof(ErrorInfoModel.Status))]
+        public bool Status { get => Model.Status; set => SetProperty(ref Model.Status, value); }
+        [PropertyAssociation(nameof(ErrorInfoModel.Name))]
+        public bool IsVisibily => !string.IsNullOrEmpty(Name);
+        public override void UpDateModel(ErrorInfoModel model)
+        {
+            bool lastStatus = Model.Status;
+            base.UpDateModel(model);
+            if (model.Status != lastStatus && model.Status)
+            {
+                LogViewModel.Instance.AddLog($"{Application.Current?.FindResource(Name)}{Application.Current?.FindResource("OilError")}");
+            }
+        }
+    }
+}

+ 64 - 0
Client/OilSourceControl/OilSourceControl/ViewModel/OilSourceAnalogViewModel.cs

@@ -0,0 +1,64 @@
+using Avalonia;
+using Avalonia.Controls;
+using IViewModel;
+using OilSourceModel.Models;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace OilSourceControl.ViewModel
+{
+    internal sealed class OilSourceAnalogViewModel:IViewModel.ViewModels.DisplayViewModelBase<OilSourceModel.Models.OilSourceAnalogModel>
+    {
+        public OilSourceAnalogViewModel()
+        {
+            //Content = typeof(Views.OilAnalogView);
+        }
+        public OilSourceAnalogViewModel(OilSourceModel.Models.OilSourceAnalogModel model) : this()
+        {
+            UpDateModel(model);
+        }
+        public override bool CanCancel => false;
+        [PropertyAssociation(nameof(OilSourceAnalogModel.Name))]
+        public bool IsVisible => !string.IsNullOrEmpty(Name);
+        [PropertyAssociation(nameof(OilSourceAnalogModel.Name))]
+        public string Name => Model.Name;
+        [PropertyAssociation(nameof(OilSourceAnalogModel.Value))]
+        public float Value { get => Model.Value; set => SetProperty(ref Model.Value, value); }
+        [PropertyAssociation(nameof(OilSourceAnalogModel.IsUpperWarn))]
+        public bool IsUpperWarn { get => Model.IsUpperWarn; set => SetProperty(ref Model.IsUpperWarn, value); }
+        [PropertyAssociation(nameof(OilSourceAnalogModel.IsUpperError))]
+        public bool IsUpperError { get => Model.IsUpperError; set => SetProperty(ref Model.IsUpperError, value); }
+        [PropertyAssociation(nameof(OilSourceAnalogModel.IsLowerWarn))]
+        public bool IsLowerWarn { get => Model.IsLowerWarn; set => SetProperty(ref Model.IsLowerWarn, value); }
+        [PropertyAssociation(nameof(OilSourceAnalogModel.IsLowerError))]
+        public bool IsLowerError { get => Model.IsLowerError; set => SetProperty(ref Model.IsLowerError, value); }
+        [PropertyAssociation(nameof(OilSourceAnalogModel.Unit))]
+        public string Unit { get => Model.Unit; set => SetProperty(ref Model.Unit, value); }
+        [PropertyAssociation(nameof(OilSourceAnalogModel.IsUpperError), nameof(OilSourceAnalogModel.IsLowerError))]
+        public bool IsError => IsUpperError || IsLowerError;
+        [PropertyAssociation(nameof(OilSourceAnalogModel.IsLowerError), nameof(OilSourceAnalogModel.IsUpperError), nameof(OilSourceAnalogModel.IsLowerWarn), nameof(OilSourceAnalogModel.IsUpperWarn))]
+        public bool IsWarn => !IsError && (IsLowerWarn || IsUpperWarn);
+        [PropertyAssociation(nameof(OilSourceAnalogModel.IsUpperError), nameof(OilSourceAnalogModel.IsUpperWarn))]
+        public bool IsUpper => IsUpperError || IsUpperWarn;
+        [PropertyAssociation(nameof(OilSourceAnalogModel.IsLowerWarn), nameof(OilSourceAnalogModel.IsLowerError))]
+        public bool IsLower => IsLowerError || IsLowerWarn;
+
+        private readonly string[] errornames = new string[4] { "UpperWarn", "LowerWarn", "UpperError", "LowerError" };
+        public override void UpDateModel(OilSourceAnalogModel model)
+        {
+            bool[] laststate = new bool[4] { IsUpperWarn, IsLowerWarn, IsUpperError, IsLowerError };
+            base.UpDateModel(model);
+            bool[] currentstate = new bool[4] { IsUpperWarn, IsLowerWarn, IsUpperError, IsLowerError };
+            for (int i = 0; i < laststate.Length; i++)
+            {
+                if (laststate[i] != currentstate[i] && !laststate[i])
+                {
+                    IViewModel.ViewModels.LogViewModel.Instance.AddLog($"{Application.Current?.FindResource(Name)}{Application.Current?.FindResource(errornames[i])}", i >= 2 ? IViewModel.Models.LogType.Error : IViewModel.Models.LogType.Warn);
+                }
+            }
+        }
+    }
+}

+ 199 - 0
Client/OilSourceControl/OilSourceControl/ViewModel/OilSourceStatusViewModel.cs

@@ -0,0 +1,199 @@
+using Avalonia;
+using Avalonia.Collections;
+using Avalonia.Controls;
+using IViewModel.Models;
+using IViewModel.ViewModels;
+using IViewModel;
+using OilSourceModel;
+using OilSourceModel.Models;
+using Shaker.Models;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace OilSourceControl.ViewModel
+{
+    internal sealed class OilSourceStatusViewModel:IViewModel.ViewModels.DisplayViewModelBase<OilSourceModel.Models.OilSourceStatusModel>
+    {        public override double Width => 1300;
+        public override double Height => 800;
+        public override bool CanResize => false;
+        private OilSourceStatusViewModel()
+        {
+            ButtonVisibily = false;
+            //Content = typeof(Views.OilControlView);
+            Circulate?.UpDateModel(Model.Circulate);
+            for (int i = 0; i < Model.OilSourceAnalogs.Count; i++)
+            {
+                OilSourceAnalogs.Add(new OilSourceAnalogViewModel(Model.OilSourceAnalogs[i]));
+            }
+            for (int i = 0; i < Model.Circuit.Count; i++)
+            {
+                Circuit.Add(new IndexValueItemViewModel<CircuitViewModel>(i + 1, new CircuitViewModel(Model.Circuit[i])));
+            }
+            for (int i = 0; i < Model.OilErrors.Count; i++)
+            {
+                OilErrors.Add(new OilErrorInfoViewModel(Model.OilErrors[i]));
+            }
+            Forerunner.UpDateModel(Model.Forerunner);
+            Assistant?.UpDateModel(Model.Assistant);
+            GetEvent<AllConfig>().Subscrip((sender, args) =>
+            {
+                UpDateModel(args.Data.OilSource);
+                CommunicationViewModel.Instance.LocalCommunication?.GetEvent<OilSourceStatusModel>()?.Subscrip((sender, args) =>
+                {
+                    UpDateModel(args.Data);
+                    CommunicationViewModel.Instance.ServiceCommunication?.GetEvent<OilSourceStatusModel>()?.Publish(this, args.Data);
+                });
+                CommunicationViewModel.Instance.LocalCommunication?.GetEvent(Topic.OilStatusChanged)?.Subscrip((sender, args) =>
+                {
+                    if(args.Data.Length>=1 && args.Data[0] is bool state)
+                    {
+                        string msg = Application.Current?.FindResource(state ? "OilConnect" : "OilDisConnect") + "";
+                        if(state)
+                        {
+                            EventBus.EventBroker.Instance.GetEvent(Shaker.Model.Topic.MIANWINDOWTOAST).Publish(this, null, msg, Avalonia.Controls.Notifications.NotificationType.Information);
+                        }
+                        else
+                        {
+                            EventBus.EventBroker.Instance.GetEvent(Shaker.Model.Topic.MIANWINDOWTOAST).Publish(this, null, msg, Avalonia.Controls.Notifications.NotificationType.Error);
+                        }
+                        LogViewModel.Instance.AddLog(msg,state ? LogType.Info : LogType.Error);
+                        CommunicationViewModel.Instance.ServiceCommunication?.GetEvent(Topic.OilStatusChanged)?.Publish(this,null, state);
+                    }
+                });
+            });
+        }
+        static OilSourceStatusViewModel()
+        {
+
+        }
+        public void EmergencyStop()
+        {
+            CommunicationViewModel.Instance.LocalCommunication.GetEvent(Topic.OilEmergencyStop)?.Publish(this, null, false);
+        }
+        public override bool CanCancel => false;
+        public static OilSourceStatusViewModel Instance { get; } = new OilSourceStatusViewModel();
+
+
+        public CircuitViewModel Circulate { get; } = new CircuitViewModel()
+        {
+            PressureAction = (pressure) => CommunicationViewModel.Instance.LocalCommunication?.GetEvent(Topic.CirculatePressure)?.Publish(OilSourceStatusViewModel.Instance.Forerunner, null, pressure),
+            StartAction = (state) => CommunicationViewModel.Instance.LocalCommunication?.GetEvent(Topic.CirculateStart)?.Publish(OilSourceStatusViewModel.Instance.Forerunner, null, state),
+            LoadAction = (state) => CommunicationViewModel.Instance.LocalCommunication?.GetEvent(Topic.CirculateLoad)?.Publish(OilSourceStatusViewModel.Instance.Forerunner, null, state)
+        };
+        [PropertyAssociation(nameof(OilSourceStatusModel.IsRemote))]
+        public bool IsRemote
+        {
+            get => Model.IsRemote;
+            set => SetProperty(ref Model.IsRemote, value);
+        }
+        [PropertyAssociation(nameof(OilSourceStatusModel.IsEnabled))]
+        public bool IsEnabled
+        {
+            get => Model.IsEnabled;
+            set => SetProperty(ref Model.IsEnabled, value);
+        }
+        [PropertyAssociation(nameof(OilSourceStatusModel.IsConnect))]
+        public bool IsConnect { get => Model.IsConnect; set => SetProperty(ref Model.IsConnect, value); }
+        /// <summary>
+        /// 先导油路
+        /// </summary>
+        public CircuitViewModel Forerunner { get; } = new CircuitViewModel()
+        {
+            PressureAction = (pressure)=> CommunicationViewModel.Instance.LocalCommunication?.GetEvent(Topic.ForerunnerPressure)?.Publish(OilSourceStatusViewModel.Instance.Forerunner, null, pressure),
+            StartAction = (state) => CommunicationViewModel.Instance.LocalCommunication?.GetEvent(Topic.ForerunnerStart)?.Publish(OilSourceStatusViewModel.Instance.Forerunner, null, state),
+            LoadAction = (state) => CommunicationViewModel.Instance.LocalCommunication?.GetEvent(Topic.ForerunnerLoad)?.Publish(OilSourceStatusViewModel.Instance.Forerunner, null, state)
+        };
+        /// <summary>
+        /// 主油路
+        /// </summary>
+        public AvaloniaList<IndexValueItemViewModel<CircuitViewModel>> Circuit { get; } = new AvaloniaList<IndexValueItemViewModel<CircuitViewModel>>();
+        public AvaloniaList<OilSourceAnalogViewModel> OilSourceAnalogs { get; } = new AvaloniaList<OilSourceAnalogViewModel>();
+
+        public CircuitViewModel Assistant { get; } = new CircuitViewModel()
+        {
+            PressureAction = (pressure) => CommunicationViewModel.Instance.LocalCommunication?.GetEvent(Topic.AssistantPressure)?.Publish(OilSourceStatusViewModel.Instance.Forerunner, null, pressure),
+            StartAction = (state) => CommunicationViewModel.Instance.LocalCommunication?.GetEvent(Topic.AssistantStart)?.Publish(OilSourceStatusViewModel.Instance.Forerunner, null, state),
+            LoadAction = (state) => CommunicationViewModel.Instance.LocalCommunication?.GetEvent(Topic.AssistantLoad)?.Publish(OilSourceStatusViewModel.Instance.Forerunner, null, state)
+        };
+
+        public AvaloniaList<OilErrorInfoViewModel> OilErrors { get; } = new AvaloniaList<OilErrorInfoViewModel>();
+        public bool IsError => (OilErrors.Count > 0 ? OilErrors.Any(x => x.Status) : false) | (OilSourceAnalogs.Count > 0 ? OilSourceAnalogs.Any(x => x.IsError) : false);
+        protected override void Cancel()
+        {
+        }
+        public override void UpDateModel(OilSourceStatusModel model)
+        {
+            bool lasterror = IsError;
+            base.UpDateModel(model);
+            Forerunner?.UpDateModel(model.Forerunner);
+            Circulate?.UpDateModel(model.Circulate);
+            int count = Circuit.Count;
+            if (count < model.Circuit.Count)
+            {
+                for (int i = 0; i <  model.Circuit.Count-count; i++)
+                {
+                    Circuit.Add(new IndexValueItemViewModel<CircuitViewModel>(Circuit.Count + 1, new CircuitViewModel()));
+                }
+            }
+            else if (count > model.Circuit.Count)
+            {
+                Circuit.RemoveRange(model.Circuit.Count, count - model.Circuit.Count);
+            }
+            if (model.Circuit.Count > 0)
+            {
+                for (int i = 0; i < model.Circuit.Count; i++)
+                {
+                    Circuit[i].Value?.UpDateModel(model.Circuit[i]);
+                    Circuit[i].Value.StartAction = (state) => CommunicationViewModel.Instance.LocalCommunication?.GetEvent(Topic.CircuitStart)?.Publish(this, null,i, state);
+                    Circuit[i].Value.LoadAction = (state) => CommunicationViewModel.Instance.LocalCommunication?.GetEvent(Topic.CircuitLoad)?.Publish(this, null,i, state);
+                    Circuit[i].Value.PressureAction = (pressure) => CommunicationViewModel.Instance.LocalCommunication?.GetEvent(Topic.CircuitPressure)?.Publish(this, null,i, pressure);
+                }
+            }
+            Assistant?.UpDateModel(model.Assistant);
+            count = OilSourceAnalogs.Count;
+            if (count < model.OilSourceAnalogs.Count)
+            {
+                for (int i = 0; i < model.OilSourceAnalogs.Count-count; i++)
+                {
+                    OilSourceAnalogs.Add(new OilSourceAnalogViewModel());
+                }
+            }
+            else if (count > model.OilSourceAnalogs.Count)
+            {
+                OilSourceAnalogs.RemoveRange(model.OilSourceAnalogs.Count, count - model.OilSourceAnalogs.Count);
+            }
+            if (model.OilSourceAnalogs.Count > 0)
+            {
+                for (int i = 0; i < model.OilSourceAnalogs.Count; i++)
+                {
+                    OilSourceAnalogs[i].UpDateModel(model.OilSourceAnalogs[i]);
+                }
+            }
+            count = OilErrors.Count;
+            if (count < model.OilErrors.Count)
+            {
+                for (int i = 0; i < model.OilErrors.Count-count; i++)
+                {
+                    OilErrors.Add(new OilErrorInfoViewModel());
+                }
+            }
+            else if (count > model.OilErrors.Count)
+            {
+                OilErrors.RemoveRange(model.OilErrors.Count, count - model.OilErrors.Count);
+            }
+            if (model.OilErrors.Count > 0)
+            {
+                for (int i = 0; i < model.OilErrors.Count; i++)
+                {
+                    OilErrors[i].UpDateModel(model.OilErrors[i]);
+                }
+            }
+            OnPropertyChanged(nameof(IsError));
+            if(IsError!=lasterror)OnPropertyChanged(nameof(OilStatus));
+        }
+        public string OilStatus => Application.Current?.FindResource(IsError ? "OilError" : "OilSuccess") + "";
+    }
+}

+ 17 - 0
Dynamicloadsimulationdevice.sln

@@ -135,6 +135,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OilSourceService", "Service
 		{FC393EB6-F363-96FA-5B6B-BF46E5E40116} = {FC393EB6-F363-96FA-5B6B-BF46E5E40116}
 	EndProjectSection
 EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OilSourceControl", "OilSourceControl", "{4E77A433-DD36-41EB-917D-63C367F33D05}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OilSourceControl", "Client\OilSourceControl\OilSourceControl\OilSourceControl.csproj", "{4D46BC91-0A6A-8259-D8D4-39AE3BB4EDDA}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IOilSourceControl", "Client\OilSourceControl\IOilSourceControl\IOilSourceControl.csproj", "{6C214328-C279-4884-A781-6386E576295B}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -277,6 +283,14 @@ Global
 		{92CFF711-EF42-414A-BE8D-5571396FC3B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{92CFF711-EF42-414A-BE8D-5571396FC3B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{92CFF711-EF42-414A-BE8D-5571396FC3B6}.Release|Any CPU.Build.0 = Release|Any CPU
+		{4D46BC91-0A6A-8259-D8D4-39AE3BB4EDDA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{4D46BC91-0A6A-8259-D8D4-39AE3BB4EDDA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{4D46BC91-0A6A-8259-D8D4-39AE3BB4EDDA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{4D46BC91-0A6A-8259-D8D4-39AE3BB4EDDA}.Release|Any CPU.Build.0 = Release|Any CPU
+		{6C214328-C279-4884-A781-6386E576295B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{6C214328-C279-4884-A781-6386E576295B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{6C214328-C279-4884-A781-6386E576295B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{6C214328-C279-4884-A781-6386E576295B}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -333,6 +347,9 @@ Global
 		{187086F1-9C0A-F787-85AA-074352771224} = {60C945FF-D313-498B-9B0F-A0CC30084207}
 		{04AA6DCF-3584-49F7-A84D-E55983B16E57} = {251D12FC-0350-4148-A678-0A3C2E4468E7}
 		{92CFF711-EF42-414A-BE8D-5571396FC3B6} = {251D12FC-0350-4148-A678-0A3C2E4468E7}
+		{4E77A433-DD36-41EB-917D-63C367F33D05} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
+		{4D46BC91-0A6A-8259-D8D4-39AE3BB4EDDA} = {4E77A433-DD36-41EB-917D-63C367F33D05}
+		{6C214328-C279-4884-A781-6386E576295B} = {4E77A433-DD36-41EB-917D-63C367F33D05}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {E85FCA00-949A-4609-92F5-C2C61F01B355}

+ 5 - 1
Service/ShakerService/Service.cs

@@ -61,8 +61,12 @@ namespace ShakerService
         {
             while(!maintokenSource.IsCancellationRequested)
             {
-
+                RTInit();
             }
         }
+        private void RTInit()
+        {
+
+        }
     }
 }

+ 20 - 0
Shaker.Model/Models/AllConfig.cs

@@ -0,0 +1,20 @@
+using OilSourceModel.Models;
+using Shaker.Models;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Shaker.Models
+{
+    public class AllConfig
+    {
+        public required  OilSourceStatusModel OilSource { get; init; }
+
+
+        public required ShakerConfigModel ShakerConfig { get; init; }
+
+    }
+}

+ 1 - 0
Shaker.Model/Shaker.Model.csproj

@@ -12,6 +12,7 @@
 
   <ItemGroup>
     <ProjectReference Include="..\IModel\IModel.csproj" />
+    <ProjectReference Include="..\OilSourceModel\OilSourceModel.csproj" />
   </ItemGroup>
 
 </Project>

+ 2 - 0
Shaker.Model/Topic.cs

@@ -17,5 +17,7 @@ namespace Shaker.Model
         public const int DISCOVERYPORT = 16656;
         public const string MulticastGroup = "239.1.0.3";
         public const string LOG="Log";
+
+        public const string MIANWINDOWTOAST = "MainWindowToast";
     }
 }