Преглед на файлове

优化首页UI - 添加仪表盘、状态卡片等现代控件

磊 曹 преди 1 седмица
родител
ревизия
e3f5710412

+ 182 - 0
src/YZWater.Avalonia/Controls/GaugeControl.cs

@@ -0,0 +1,182 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Media;
+using System;
+using System.Globalization;
+
+namespace YZWater.Avalonia.Controls;
+
+/// <summary>
+/// 仪表盘控件(简化版)
+/// </summary>
+public class GaugeControl : Control
+{
+    public static readonly StyledProperty<double> ValueProperty =
+        AvaloniaProperty.Register<GaugeControl, double>(nameof(Value), 0.0);
+
+    public static readonly StyledProperty<double> MinValueProperty =
+        AvaloniaProperty.Register<GaugeControl, double>(nameof(MinValue), 0.0);
+
+    public static readonly StyledProperty<double> MaxValueProperty =
+        AvaloniaProperty.Register<GaugeControl, double>(nameof(MaxValue), 100.0);
+
+    public static readonly StyledProperty<string> TitleProperty =
+        AvaloniaProperty.Register<GaugeControl, string>(nameof(Title), "流量");
+
+    public static readonly StyledProperty<string> UnitProperty =
+        AvaloniaProperty.Register<GaugeControl, string>(nameof(Unit), "m³/h");
+
+    public static readonly StyledProperty<IBrush> ValueColorProperty =
+        AvaloniaProperty.Register<GaugeControl, IBrush>(nameof(ValueColor), new SolidColorBrush(Color.Parse("#00BCD4")));
+
+    public double Value
+    {
+        get => GetValue(ValueProperty);
+        set => SetValue(ValueProperty, value);
+    }
+
+    public double MinValue
+    {
+        get => GetValue(MinValueProperty);
+        set => SetValue(MinValueProperty, value);
+    }
+
+    public double MaxValue
+    {
+        get => GetValue(MaxValueProperty);
+        set => SetValue(MaxValueProperty, value);
+    }
+
+    public string Title
+    {
+        get => GetValue(TitleProperty);
+        set => SetValue(TitleProperty, value);
+    }
+
+    public string Unit
+    {
+        get => GetValue(UnitProperty);
+        set => SetValue(UnitProperty, value);
+    }
+
+    public IBrush ValueColor
+    {
+        get => GetValue(ValueColorProperty);
+        set => SetValue(ValueColorProperty, value);
+    }
+
+    static GaugeControl()
+    {
+        AffectsRender<GaugeControl>(ValueProperty, MinValueProperty, MaxValueProperty,
+            TitleProperty, UnitProperty, ValueColorProperty);
+    }
+
+    public override void Render(DrawingContext context)
+    {
+        base.Render(context);
+
+        var bounds = new Rect(Bounds.Size);
+        var centerX = bounds.Width / 2;
+        var centerY = bounds.Height / 2 + 10;
+        var radius = Math.Min(bounds.Width, bounds.Height) / 2 - 20;
+        var typeface = new Typeface("Microsoft YaHei", FontStyle.Normal, FontWeight.Bold);
+
+        // 绘制背景圆
+        var bgBrush = new SolidColorBrush(Color.Parse("#1E272E"));
+        context.DrawEllipse(bgBrush, null, new Rect(
+            centerX - radius - 5,
+            centerY - radius - 5,
+            (radius + 5) * 2,
+            (radius + 5) * 2));
+
+        // 绘制刻度弧线背景
+        var arcPenBg = new Pen(new SolidColorBrush(Color.Parse("#37474F")), 8);
+        DrawArc(context, arcPenBg, centerX, centerY, radius, 135, 270);
+
+        // 计算当前值对应的角度
+        var normalizedValue = (Value - MinValue) / (MaxValue - MinValue);
+        normalizedValue = Math.Max(0, Math.Min(1, normalizedValue));
+        var valueAngle = 135 + normalizedValue * 270;
+
+        // 绘制当前值弧线
+        var valueColor = ValueColor as SolidColorBrush ?? new SolidColorBrush(Color.Parse("#00BCD4"));
+        var arcPen = new Pen(valueColor, 8);
+        DrawArc(context, arcPen, centerX, centerY, radius, 135, valueAngle - 135);
+
+        // 绘制刻度线
+        var tickCount = 10;
+        for (int i = 0; i <= tickCount; i++)
+        {
+            var angle = 135 + (270.0 * i / tickCount);
+            var radians = angle * Math.PI / 180;
+            var isMajor = i % 5 == 0;
+            var tickLength = isMajor ? 12 : 6;
+
+            var innerX = centerX + Math.Cos(radians) * (radius - tickLength);
+            var innerY = centerY + Math.Sin(radians) * (radius - tickLength);
+            var outerX = centerX + Math.Cos(radians) * radius;
+            var outerY = centerY + Math.Sin(radians) * radius;
+
+            var tickPen = new Pen(new SolidColorBrush(isMajor ? Colors.White : Colors.Gray), isMajor ? 2 : 1);
+            context.DrawLine(tickPen, new Point(innerX, innerY), new Point(outerX, outerY));
+        }
+
+        // 绘制指针
+        var pointerAngle = valueAngle * Math.PI / 180;
+        var pointerLength = radius * 0.7;
+        var pointerX = centerX + Math.Cos(pointerAngle) * pointerLength;
+        var pointerY = centerY + Math.Sin(pointerAngle) * pointerLength;
+
+        var pointerPen = new Pen(valueColor, 3);
+        context.DrawLine(pointerPen, new Point(centerX, centerY), new Point(pointerX, pointerY));
+
+        // 绘制中心圆
+        context.DrawEllipse(valueColor, null, new Rect(centerX - 6, centerY - 6, 12, 12));
+
+        // 绘制标题
+        var titleText = new FormattedText(Title, CultureInfo.CurrentCulture,
+            FlowDirection.LeftToRight, typeface, 12, new SolidColorBrush(Colors.White));
+        context.DrawText(titleText, new Point(centerX - titleText.Width / 2, bounds.Y + 5));
+
+        // 绘制数值
+        var valueStr = $"{Value:F1}";
+        var valueText = new FormattedText(valueStr, CultureInfo.CurrentCulture,
+            FlowDirection.LeftToRight, new Typeface("Microsoft YaHei", FontStyle.Normal, FontWeight.Bold),
+            20, new SolidColorBrush(Colors.White));
+        context.DrawText(valueText, new Point(centerX - valueText.Width / 2, centerY + radius * 0.3));
+
+        // 绘制单位
+        var unitText = new FormattedText(Unit, CultureInfo.CurrentCulture,
+            FlowDirection.LeftToRight, new Typeface("Microsoft YaHei"), 10,
+            new SolidColorBrush(Colors.Gray));
+        context.DrawText(unitText, new Point(centerX - unitText.Width / 2, centerY + radius * 0.3 + valueText.Height + 2));
+    }
+
+    private void DrawArc(DrawingContext context, IPen pen, double centerX, double centerY, double radius, double startAngle, double sweepAngle)
+    {
+        // 简化绘制:使用多个小线段近似弧线
+        var startRadians = startAngle * Math.PI / 180;
+        var endRadians = (startAngle + sweepAngle) * Math.PI / 180;
+        var steps = 36;
+
+        var prevX = centerX + Math.Cos(startRadians) * radius;
+        var prevY = centerY + Math.Sin(startRadians) * radius;
+
+        for (int i = 1; i <= steps; i++)
+        {
+            var t = (double)i / steps;
+            var angle = startRadians + (endRadians - startRadians) * t;
+            var x = centerX + Math.Cos(angle) * radius;
+            var y = centerY + Math.Sin(angle) * radius;
+
+            context.DrawLine(pen, new Point(prevX, prevY), new Point(x, y));
+            prevX = x;
+            prevY = y;
+        }
+    }
+
+    protected override Size MeasureOverride(Size availableSize)
+    {
+        return new Size(120, 140);
+    }
+}

+ 135 - 46
src/YZWater.Avalonia/Controls/PumpControl.cs

@@ -8,7 +8,7 @@ using System.Globalization;
 namespace YZWater.Avalonia.Controls;
 
 /// <summary>
-/// 泵控件 - 模拟 HslPumpOne
+/// 泵控件 - 模拟 HslPumpOne(优化版)
 /// </summary>
 public class PumpControl : Control
 {
@@ -18,18 +18,21 @@ public class PumpControl : Control
     public static readonly StyledProperty<double> SpeedProperty =
         AvaloniaProperty.Register<PumpControl, double>(nameof(Speed), 0.0);
 
-    public static readonly StyledProperty<IBrush> Color1Property =
-        AvaloniaProperty.Register<PumpControl, IBrush>(nameof(Color1), new SolidColorBrush(Color.Parse("#9b9b9b")));
-
-    public static readonly StyledProperty<IBrush> Color2Property =
-        AvaloniaProperty.Register<PumpControl, IBrush>(nameof(Color2), new SolidColorBrush(Color.Parse("#9b9b9b")));
-
-    public static readonly StyledProperty<IBrush> Color3Property =
-        AvaloniaProperty.Register<PumpControl, IBrush>(nameof(Color3), new SolidColorBrush(Color.Parse("#9b9b9b")));
+    public static readonly StyledProperty<double> FrequencyProperty =
+        AvaloniaProperty.Register<PumpControl, double>(nameof(Frequency), 50.0);
 
     public static readonly StyledProperty<string> TextProperty =
         AvaloniaProperty.Register<PumpControl, string>(nameof(Text), string.Empty);
 
+    public static readonly StyledProperty<IBrush> RunningColorProperty =
+        AvaloniaProperty.Register<PumpControl, IBrush>(nameof(RunningColor), new SolidColorBrush(Color.Parse("#4CAF50")));
+
+    public static readonly StyledProperty<IBrush> StoppedColorProperty =
+        AvaloniaProperty.Register<PumpControl, IBrush>(nameof(StoppedColor), new SolidColorBrush(Color.Parse("#607D8B")));
+
+    public static readonly StyledProperty<IBrush> FaultColorProperty =
+        AvaloniaProperty.Register<PumpControl, IBrush>(nameof(FaultColor), new SolidColorBrush(Color.Parse("#F44336")));
+
     public bool IsRunning
     {
         get => GetValue(IsRunningProperty);
@@ -42,28 +45,34 @@ public class PumpControl : Control
         set => SetValue(SpeedProperty, value);
     }
 
-    public IBrush Color1
+    public double Frequency
     {
-        get => GetValue(Color1Property);
-        set => SetValue(Color1Property, value);
+        get => GetValue(FrequencyProperty);
+        set => SetValue(FrequencyProperty, value);
     }
 
-    public IBrush Color2
+    public string Text
     {
-        get => GetValue(Color2Property);
-        set => SetValue(Color2Property, value);
+        get => GetValue(TextProperty);
+        set => SetValue(TextProperty, value);
     }
 
-    public IBrush Color3
+    public IBrush RunningColor
     {
-        get => GetValue(Color3Property);
-        set => SetValue(Color3Property, value);
+        get => GetValue(RunningColorProperty);
+        set => SetValue(RunningColorProperty, value);
     }
 
-    public string Text
+    public IBrush StoppedColor
     {
-        get => GetValue(TextProperty);
-        set => SetValue(TextProperty, value);
+        get => GetValue(StoppedColorProperty);
+        set => SetValue(StoppedColorProperty, value);
+    }
+
+    public IBrush FaultColor
+    {
+        get => GetValue(FaultColorProperty);
+        set => SetValue(FaultColorProperty, value);
     }
 
     private double _rotationAngle = 0;
@@ -71,7 +80,8 @@ public class PumpControl : Control
 
     static PumpControl()
     {
-        AffectsRender<PumpControl>(IsRunningProperty, SpeedProperty, Color1Property, Color2Property, Color3Property, TextProperty);
+        AffectsRender<PumpControl>(IsRunningProperty, SpeedProperty, FrequencyProperty,
+            TextProperty, RunningColorProperty, StoppedColorProperty, FaultColorProperty);
     }
 
     protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
@@ -103,6 +113,7 @@ public class PumpControl : Control
                 StopAnimation();
                 _rotationAngle = 0;
             }
+            InvalidateVisual();
         }
     }
 
@@ -111,11 +122,11 @@ public class PumpControl : Control
         StopAnimation();
         _timerSubscription = DispatcherTimer.Run(() =>
         {
-            _rotationAngle += Speed;
+            _rotationAngle += Frequency / 20.0;
             if (_rotationAngle >= 360) _rotationAngle -= 360;
             InvalidateVisual();
             return true;
-        }, TimeSpan.FromMilliseconds(50));
+        }, TimeSpan.FromMilliseconds(30));
     }
 
     private void StopAnimation()
@@ -130,22 +141,45 @@ public class PumpControl : Control
 
         var bounds = new Rect(Bounds.Size);
         var centerX = bounds.Width / 2;
-        var centerY = bounds.Height / 2;
-        var radius = Math.Min(bounds.Width, bounds.Height) / 2 - 5;
-        var typeface = new Typeface("Microsoft YaHei");
+        var centerY = bounds.Height / 2 - 5;
+        var radius = Math.Min(bounds.Width, bounds.Height) / 2 - 15;
+        var typeface = new Typeface("Microsoft YaHei", FontStyle.Normal, FontWeight.Bold);
 
-        // 绘制泵外壳
-        var outerPen = new Pen(Color1, 3);
+        // 确定状态颜色
+        var statusColor = IsRunning ? RunningColor : StoppedColor;
+        var statusBrush = statusColor as SolidColorBrush ?? new SolidColorBrush(Colors.Gray);
+
+        // 绘制外圈发光效果(运行时)
+        if (IsRunning)
+        {
+            var glowBrush = new SolidColorBrush(statusBrush.Color, 0.2);
+            context.DrawEllipse(glowBrush, null, new Rect(
+                centerX - radius - 8,
+                centerY - radius - 8,
+                (radius + 8) * 2,
+                (radius + 8) * 2));
+        }
+
+        // 绘制外壳
+        var outerPen = new Pen(new SolidColorBrush(Color.Parse("#455A64")), 3);
         context.DrawEllipse(null, outerPen, new Rect(
             centerX - radius,
             centerY - radius,
             radius * 2,
             radius * 2));
 
+        // 绘制内部背景
+        var innerBg = new SolidColorBrush(Color.Parse("#1E272E"));
+        context.DrawEllipse(innerBg, null, new Rect(
+            centerX - radius + 3,
+            centerY - radius + 3,
+            (radius - 3) * 2,
+            (radius - 3) * 2));
+
         // 绘制泵叶片
-        var bladeCount = 3;
-        var bladeLength = radius * 0.7;
-        var bladeWidth = radius * 0.3;
+        var bladeCount = 6;
+        var bladeLength = radius * 0.65;
+        var bladeWidth = radius * 0.18;
 
         for (int i = 0; i < bladeCount; i++)
         {
@@ -155,37 +189,92 @@ public class PumpControl : Control
             var bladeX = centerX + Math.Cos(radians) * bladeLength * 0.5;
             var bladeY = centerY + Math.Sin(radians) * bladeLength * 0.5;
 
-            var bladeRect = new Rect(
-                bladeX - bladeWidth / 2,
-                bladeY - bladeLength / 2,
-                bladeWidth,
-                bladeLength);
+            // 绘制叶片(带渐变效果)
+            var bladeBrush = new SolidColorBrush(IsRunning
+                ? Color.FromArgb(200, statusBrush.Color.R, statusBrush.Color.G, statusBrush.Color.B)
+                : Color.Parse("#546E7A"));
+
+            var bladePath = new StreamGeometry();
+            using (var ctx = bladePath.Open())
+            {
+                ctx.BeginFigure(new Point(bladeX - bladeWidth / 2, bladeY - bladeLength / 2), true);
+                ctx.LineTo(new Point(bladeX + bladeWidth / 2, bladeY - bladeLength / 2));
+                ctx.LineTo(new Point(bladeX + bladeWidth / 2, bladeY + bladeLength / 2));
+                ctx.LineTo(new Point(bladeX - bladeWidth / 2, bladeY + bladeLength / 2));
+                ctx.EndFigure(true);
+            }
 
-            context.DrawRectangle(Color2, null, bladeRect);
+            // 旋转叶片 - 使用矩阵变换
+            var rotationRadians = angle * Math.PI / 180;
+            var cos = Math.Cos(rotationRadians);
+            var sin = Math.Sin(rotationRadians);
+            var transform = new Matrix(cos, sin, -sin, cos, bladeX - bladeX * cos + bladeY * sin, bladeY - bladeX * sin - bladeY * cos);
+            using (context.PushTransform(transform))
+            {
+                context.DrawGeometry(bladeBrush, null, bladePath);
+            }
         }
 
-        // 绘制中心圆
-        var centerRadius = radius * 0.2;
-        context.DrawEllipse(Color3, null, new Rect(
+        // 绘制中心圆(带渐变)
+        var centerRadius = radius * 0.25;
+        var centerBrush = new SolidColorBrush(IsRunning ? statusBrush.Color : Color.Parse("#455A64"));
+        context.DrawEllipse(centerBrush, null, new Rect(
             centerX - centerRadius,
             centerY - centerRadius,
             centerRadius * 2,
             centerRadius * 2));
 
-        // 绘制文字
+        // 中心高光
+        var highlightBrush = new SolidColorBrush(Colors.White, 0.3);
+        context.DrawEllipse(highlightBrush, null, new Rect(
+            centerX - centerRadius * 0.5,
+            centerY - centerRadius * 0.5,
+            centerRadius,
+            centerRadius));
+
+        // 绘制状态指示灯
+        var indicatorSize = 8;
+        var indicatorX = bounds.Width - 20;
+        var indicatorY = 10;
+        var indicatorBrush = IsRunning
+            ? new SolidColorBrush(Color.Parse("#4CAF50"))
+            : new SolidColorBrush(Color.Parse("#78909C"));
+
+        // 指示灯发光
+        if (IsRunning)
+        {
+            context.DrawEllipse(new SolidColorBrush(indicatorBrush.Color, 0.3), null,
+                new Rect(indicatorX - 4, indicatorY - 4, 16, 16));
+        }
+
+        context.DrawEllipse(indicatorBrush, null,
+            new Rect(indicatorX, indicatorY, indicatorSize, indicatorSize));
+
+        // 绘制文字标签
         if (!string.IsNullOrEmpty(Text))
         {
-            var foreground = new SolidColorBrush(Colors.Black);
-            var text = new FormattedText(Text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, typeface, 10, foreground);
+            var textBrush = new SolidColorBrush(Colors.White);
+            var text = new FormattedText(Text, CultureInfo.CurrentCulture,
+                FlowDirection.LeftToRight, typeface, 11, textBrush);
             var textPoint = new Point(
                 centerX - text.Width / 2,
-                bounds.Bottom - text.Height - 2);
+                bounds.Bottom - text.Height - 5);
             context.DrawText(text, textPoint);
         }
+
+        // 绘制频率显示
+        if (IsRunning)
+        {
+            var freqStr = $"{Frequency:F0}Hz";
+            var freqText = new FormattedText(freqStr, CultureInfo.CurrentCulture,
+                FlowDirection.LeftToRight, new Typeface("Microsoft YaHei"), 9,
+                new SolidColorBrush(statusBrush.Color));
+            context.DrawText(freqText, new Point(centerX - freqText.Width / 2, centerY + radius + 5));
+        }
     }
 
     protected override Size MeasureOverride(Size availableSize)
     {
-        return new Size(60, 60);
+        return new Size(70, 80);
     }
 }

+ 136 - 0
src/YZWater.Avalonia/Controls/StatusCard.cs

@@ -0,0 +1,136 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Media;
+using System;
+using System.Globalization;
+
+namespace YZWater.Avalonia.Controls;
+
+/// <summary>
+/// 状态卡片控件 - 显示设备状态信息
+/// </summary>
+public class StatusCard : Control
+{
+    public static readonly StyledProperty<string> TitleProperty =
+        AvaloniaProperty.Register<StatusCard, string>(nameof(Title), "设备");
+
+    public static readonly StyledProperty<string> StatusProperty =
+        AvaloniaProperty.Register<StatusCard, string>(nameof(Status), "运行中");
+
+    public static readonly StyledProperty<string> IconProperty =
+        AvaloniaProperty.Register<StatusCard, string>(nameof(Icon), "⚙️");
+
+    public static readonly StyledProperty<bool> IsActiveProperty =
+        AvaloniaProperty.Register<StatusCard, bool>(nameof(IsActive), false);
+
+    public static readonly StyledProperty<IBrush> ActiveColorProperty =
+        AvaloniaProperty.Register<StatusCard, IBrush>(nameof(ActiveColor), new SolidColorBrush(Color.Parse("#4CAF50")));
+
+    public static readonly StyledProperty<IBrush> InactiveColorProperty =
+        AvaloniaProperty.Register<StatusCard, IBrush>(nameof(InactiveColor), new SolidColorBrush(Color.Parse("#607D8B")));
+
+    public string Title
+    {
+        get => GetValue(TitleProperty);
+        set => SetValue(TitleProperty, value);
+    }
+
+    public string Status
+    {
+        get => GetValue(StatusProperty);
+        set => SetValue(StatusProperty, value);
+    }
+
+    public string Icon
+    {
+        get => GetValue(IconProperty);
+        set => SetValue(IconProperty, value);
+    }
+
+    public bool IsActive
+    {
+        get => GetValue(IsActiveProperty);
+        set => SetValue(IsActiveProperty, value);
+    }
+
+    public IBrush ActiveColor
+    {
+        get => GetValue(ActiveColorProperty);
+        set => SetValue(ActiveColorProperty, value);
+    }
+
+    public IBrush InactiveColor
+    {
+        get => GetValue(InactiveColorProperty);
+        set => SetValue(InactiveColorProperty, value);
+    }
+
+    static StatusCard()
+    {
+        AffectsRender<StatusCard>(TitleProperty, StatusProperty, IconProperty,
+            IsActiveProperty, ActiveColorProperty, InactiveColorProperty);
+    }
+
+    public override void Render(DrawingContext context)
+    {
+        base.Render(context);
+
+        var bounds = new Rect(Bounds.Size);
+        var typeface = new Typeface("Microsoft YaHei");
+        var statusColor = IsActive ? ActiveColor : InactiveColor;
+        var statusBrush = statusColor as SolidColorBrush ?? new SolidColorBrush(Colors.Gray);
+
+        // 绘制卡片背景
+        var cardBg = new SolidColorBrush(Color.Parse("#1E272E"));
+        var cardPen = new Pen(new SolidColorBrush(Color.Parse("#37474F")), 1);
+        context.DrawRectangle(cardBg, cardPen, new Rect(0, 0, bounds.Width, bounds.Height));
+
+        // 绘制左侧状态条
+        context.DrawRectangle(statusColor, null, new Rect(0, 0, 4, bounds.Height));
+
+        // 绘制状态指示灯
+        var indicatorSize = 10;
+        var indicatorX = 15;
+        var indicatorY = bounds.Height / 2 - indicatorSize / 2;
+
+        // 指示灯发光效果
+        if (IsActive)
+        {
+            context.DrawEllipse(new SolidColorBrush(statusBrush.Color, 0.3), null,
+                new Rect(indicatorX - 3, indicatorY - 3, indicatorSize + 6, indicatorSize + 6));
+        }
+
+        context.DrawEllipse(statusColor, null,
+            new Rect(indicatorX, indicatorY, indicatorSize, indicatorSize));
+
+        // 绘制标题
+        var titleText = new FormattedText(Title, CultureInfo.CurrentCulture,
+            FlowDirection.LeftToRight, new Typeface("Microsoft YaHei", FontStyle.Normal, FontWeight.Bold),
+            12, new SolidColorBrush(Colors.White));
+        context.DrawText(titleText, new Point(35, 8));
+
+        // 绘制状态文本
+        var statusText = new FormattedText(Status, CultureInfo.CurrentCulture,
+            FlowDirection.LeftToRight, typeface, 10, new SolidColorBrush(statusBrush.Color));
+        context.DrawText(statusText, new Point(35, 25));
+
+        // 绘制分隔线
+        var separatorY = bounds.Height - 25;
+        context.DrawLine(new Pen(new SolidColorBrush(Color.Parse("#37474F")), 1),
+            new Point(10, separatorY), new Point(bounds.Width - 10, separatorY));
+
+        // 绘制图标
+        if (!string.IsNullOrEmpty(Icon))
+        {
+            var iconText = new FormattedText(Icon, CultureInfo.CurrentCulture,
+                FlowDirection.LeftToRight, new Typeface("Microsoft YaHei"), 20,
+                new SolidColorBrush(Colors.White));
+            context.DrawText(iconText, new Point(bounds.Width - 35, 10));
+        }
+    }
+
+    protected override Size MeasureOverride(Size availableSize)
+    {
+        return new Size(150, 60);
+    }
+}

+ 47 - 38
src/YZWater.Avalonia/Controls/WaterTankControl.cs

@@ -1,12 +1,13 @@
 using Avalonia;
 using Avalonia.Controls;
 using Avalonia.Media;
+using System;
 using System.Globalization;
 
 namespace YZWater.Avalonia.Controls;
 
 /// <summary>
-/// 水箱控件 - 模拟 HslWaterBox
+/// 水箱控件(简化版)
 /// </summary>
 public class WaterTankControl : Control
 {
@@ -17,13 +18,10 @@ public class WaterTankControl : Control
         AvaloniaProperty.Register<WaterTankControl, string>(nameof(Text), string.Empty);
 
     public static readonly StyledProperty<IBrush> WaterColorProperty =
-        AvaloniaProperty.Register<WaterTankControl, IBrush>(nameof(WaterColor), new SolidColorBrush(Color.Parse("#178187")));
+        AvaloniaProperty.Register<WaterTankControl, IBrush>(nameof(WaterColor), new SolidColorBrush(Color.Parse("#00BCD4")));
 
     public static readonly StyledProperty<IBrush> BorderColorProperty =
-        AvaloniaProperty.Register<WaterTankControl, IBrush>(nameof(BorderColor), new SolidColorBrush(Colors.LightGray));
-
-    public static readonly StyledProperty<double> EdgeWidthProperty =
-        AvaloniaProperty.Register<WaterTankControl, double>(nameof(EdgeWidth), 2.0);
+        AvaloniaProperty.Register<WaterTankControl, IBrush>(nameof(BorderColor), new SolidColorBrush(Color.Parse("#37474F")));
 
     public double WaterLevel
     {
@@ -49,16 +47,9 @@ public class WaterTankControl : Control
         set => SetValue(BorderColorProperty, value);
     }
 
-    public double EdgeWidth
-    {
-        get => GetValue(EdgeWidthProperty);
-        set => SetValue(EdgeWidthProperty, value);
-    }
-
     static WaterTankControl()
     {
-        AffectsRender<WaterTankControl>(WaterLevelProperty, TextProperty, WaterColorProperty, BorderColorProperty, EdgeWidthProperty);
-        AffectsMeasure<WaterTankControl>(WaterLevelProperty, TextProperty, WaterColorProperty, BorderColorProperty, EdgeWidthProperty);
+        AffectsRender<WaterTankControl>(WaterLevelProperty, TextProperty, WaterColorProperty, BorderColorProperty);
     }
 
     public override void Render(DrawingContext context)
@@ -66,48 +57,66 @@ public class WaterTankControl : Control
         base.Render(context);
 
         var bounds = new Rect(Bounds.Size);
-        var edgeWidth = EdgeWidth;
-        var typeface = new Typeface("Microsoft YaHei");
-        var foreground = new SolidColorBrush(Colors.White);
+        var typeface = new Typeface("Microsoft YaHei", FontStyle.Normal, FontWeight.Bold);
+        var edgeWidth = 3.0;
+
+        // 绘制背景
+        var bgBrush = new SolidColorBrush(Color.Parse("#263238"));
+        context.DrawRectangle(bgBrush, null, bounds);
 
         // 绘制边框
         var borderPen = new Pen(BorderColor, edgeWidth);
         context.DrawRectangle(null, borderPen, bounds);
 
         // 计算水位高度
-        var waterHeight = bounds.Height * (WaterLevel / 100.0);
-        var waterRect = new Rect(
-            bounds.X + edgeWidth,
-            bounds.Y + bounds.Height - waterHeight,
-            bounds.Width - edgeWidth * 2,
-            waterHeight - edgeWidth);
+        var waterHeight = (bounds.Height - edgeWidth * 2) * Math.Max(0, Math.Min(100, WaterLevel)) / 100.0;
+        var waterTop = bounds.Y + bounds.Height - edgeWidth - waterHeight;
 
         // 绘制水
-        if (waterHeight > edgeWidth)
+        if (waterHeight > 0)
         {
-            context.DrawRectangle(WaterColor, null, waterRect);
+            var waterColor = WaterColor as SolidColorBrush;
+            var waterBrush = waterColor != null
+                ? new SolidColorBrush(waterColor.Color, 0.8)
+                : WaterColor;
+
+            var waterRect = new Rect(
+                bounds.X + edgeWidth,
+                waterTop,
+                bounds.Width - edgeWidth * 2,
+                waterHeight);
+            context.DrawRectangle(waterBrush, null, waterRect);
         }
 
-        // 绘制文字
+        // 绘制标题
         if (!string.IsNullOrEmpty(Text))
         {
-            var text = new FormattedText(Text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, typeface, 14, foreground);
-            var textPoint = new Point(
-                bounds.X + (bounds.Width - text.Width) / 2,
-                bounds.Y + (bounds.Height - text.Height) / 2);
-            context.DrawText(text, textPoint);
+            var titleBrush = new SolidColorBrush(Colors.White);
+            var titleText = new FormattedText(Text, CultureInfo.CurrentCulture,
+                FlowDirection.LeftToRight, typeface, 12, titleBrush);
+            var titlePoint = new Point(
+                bounds.X + (bounds.Width - titleText.Width) / 2,
+                bounds.Y + edgeWidth + 5);
+            context.DrawText(titleText, titlePoint);
         }
 
-        // 绘制水位百分比
-        var levelText = new FormattedText($"{WaterLevel:F0}%", CultureInfo.CurrentCulture, FlowDirection.LeftToRight, typeface, 12, foreground);
-        var levelPoint = new Point(
-            bounds.X + (bounds.Width - levelText.Width) / 2,
-            bounds.Y + 5);
-        context.DrawText(levelText, levelPoint);
+        // 绘制液位百分比
+        var levelStr = $"{WaterLevel:F1}%";
+        var levelText = new FormattedText(levelStr, CultureInfo.CurrentCulture,
+            FlowDirection.LeftToRight, typeface, 14, new SolidColorBrush(Colors.White));
+
+        var levelBgRect = new Rect(
+            bounds.X + (bounds.Width - levelText.Width - 10) / 2,
+            bounds.Y + bounds.Height - edgeWidth - levelText.Height - 10,
+            levelText.Width + 10,
+            levelText.Height + 6);
+
+        context.DrawRectangle(new SolidColorBrush(Colors.Black, 0.5), null, levelBgRect);
+        context.DrawText(levelText, new Point(levelBgRect.X + 5, levelBgRect.Y + 3));
     }
 
     protected override Size MeasureOverride(Size availableSize)
     {
-        return new Size(100, 120);
+        return new Size(120, 160);
     }
 }

+ 229 - 157
src/YZWater.Avalonia/Views/ViewAView.axaml

@@ -9,167 +9,239 @@
         <vm:ViewAViewModel/>
     </UserControl.DataContext>
 
-    <!-- 使用固定尺寸设计,由外层容器负责缩放 -->
-    <Border Background="#1a1a2e" Width="1024" Height="613">
-        <Canvas Width="1024" Height="613">
-
-            <!-- 模式切换开关 -->
-            <controls:ValveControl Canvas.Left="893" Canvas.Top="9" Width="129" Height="108"
-                                   Status="{Binding ModeStatus}" Text="远程/本地"/>
-
-            <!-- 入口水箱 -->
-            <controls:WaterTankControl Canvas.Left="44" Canvas.Top="113" Width="134" Height="100"
-                                       WaterLevel="{Binding Tank1Level}" Text="入口池"
-                                       WaterColor="#178187" BorderColor="#cfcfcf"/>
-
-            <!-- 池1 -->
-            <Border BorderBrush="#cfcfcf" BorderThickness="8" Height="135" Canvas.Left="248" Canvas.Top="113" Width="138"/>
-            <controls:WaterTankControl Canvas.Left="250" Canvas.Top="121" Width="134" Height="127"
-                                       WaterLevel="{Binding Tank1Level}" Text=""
-                                       WaterColor="#178187" BorderColor="#cfcfcf"/>
-
-            <!-- 池2 -->
-            <controls:WaterTankControl Canvas.Left="250" Canvas.Top="248" Width="134" Height="87"
-                                       WaterLevel="{Binding Tank2Level}" Text=""
-                                       WaterColor="#178187" BorderColor="#cfcfcf"/>
-
-            <!-- 大水池 -->
-            <controls:WaterTankControl Canvas.Left="250" Canvas.Top="335" Width="748" Height="183"
-                                       WaterLevel="{Binding Tank3Level}" Text=""
-                                       WaterColor="#178187" BorderColor="#cfcfcf"/>
-            <Border BorderBrush="#cfcfcf" BorderThickness="8" Height="191" Canvas.Left="248" Canvas.Top="327" Width="138"/>
-
-            <!-- 出口池 -->
-            <controls:WaterTankControl Canvas.Left="44" Canvas.Top="267" Width="134" Height="100"
-                                       WaterLevel="{Binding Tank4Level}" Text="出口池"
-                                       WaterColor="#178187" BorderColor="#cfcfcf"/>
-
-            <!-- 管道连接线 -->
-            <Rectangle Fill="#178187" Height="12" Canvas.Left="358" Stroke="Transparent" Canvas.Top="480" Width="48"
-                       RenderTransformOrigin="0.5,0.5">
-                <Rectangle.RenderTransform>
-                    <RotateTransform Angle="-90"/>
-                </Rectangle.RenderTransform>
-            </Rectangle>
-
-            <!-- 液位显示 -->
-            <TextBlock Canvas.Left="676" Canvas.Top="414" Width="70" Foreground="White" FontSize="12">
-                <Run Text="液位3:"/><Run Text="{Binding Tank3Level, StringFormat='{}{0:F1}'}"/><Run Text="米"/>
-            </TextBlock>
-            <TextBlock Canvas.Left="288" Canvas.Top="147" Width="70" Foreground="White" FontSize="12">
-                <Run Text="池1"/><LineBreak/><Run Text="液位1:"/><Run Text="{Binding Tank1Level, StringFormat='{}{0:F1}'}"/><Run Text="米"/>
-            </TextBlock>
-            <TextBlock Canvas.Left="286" Canvas.Top="415" Width="78" Foreground="White" FontSize="12">
-                <Run Text="池2"/><LineBreak/><Run Text="液位2:"/><Run Text="{Binding Tank2Level, StringFormat='{}{0:F1}'}"/><Run Text="米"/>
-            </TextBlock>
-
-            <!-- 阀门控件 -->
-            <controls:ValveControl Canvas.Left="147" Canvas.Top="168" Width="22" Height="22"
-                                   Status="{Binding Valve1Status}" Text=""/>
-            <controls:ValveControl Canvas.Left="279" Canvas.Top="205" Width="22" Height="22"
-                                   Status="{Binding Valve2Status}" Text=""/>
-            <controls:ValveControl Canvas.Left="336" Canvas.Top="206" Width="22" Height="22"
-                                   Status="{Binding Valve3Status}" Text=""/>
-            <controls:ValveControl Canvas.Left="278" Canvas.Top="298" Width="22" Height="22"
-                                   Status="{Binding Valve4Status}" Text=""/>
-            <controls:ValveControl Canvas.Left="337" Canvas.Top="298" Width="22" Height="22"
-                                   Status="{Binding Valve5Status}" Text=""/>
-
-            <!-- 管道 -->
-            <controls:PipeLineControl Canvas.Left="0" Canvas.Top="306" Width="52" Height="29"
-                                      IsFlow="{Binding IsInflowRunning}" IsHorizontal="True"/>
-            <controls:PipeLineControl Canvas.Left="0" Canvas.Top="164" Width="52" Height="29"
-                                      IsFlow="{Binding IsOutflowRunning}" IsHorizontal="True"
-                                      RenderTransformOrigin="0.5,0.5">
-                <controls:PipeLineControl.RenderTransform>
-                    <RotateTransform Angle="180"/>
-                </controls:PipeLineControl.RenderTransform>
-            </controls:PipeLineControl>
-
-            <!-- 泵1-5 -->
-            <controls:PumpControl Canvas.Left="394" Canvas.Top="427" Width="60" Height="63"
-                                  IsRunning="{Binding Pump1Running}" Speed="2" Text="泵1"/>
-            <controls:PumpControl Canvas.Left="504" Canvas.Top="426" Width="60" Height="63"
-                                  IsRunning="{Binding Pump2Running}" Speed="2" Text="泵2"/>
-            <controls:PumpControl Canvas.Left="617" Canvas.Top="426" Width="60" Height="63"
-                                  IsRunning="{Binding Pump3Running}" Speed="2" Text="泵3"/>
-            <controls:PumpControl Canvas.Left="730" Canvas.Top="427" Width="60" Height="63"
-                                  IsRunning="{Binding Pump4Running}" Speed="2" Text="泵4"/>
-            <controls:PumpControl Canvas.Left="843" Canvas.Top="426" Width="60" Height="63"
-                                  IsRunning="{Binding Pump5Running}" Speed="2" Text="泵5"/>
-
-            <!-- 风扇 -->
-            <controls:FanControl Canvas.Left="412" Canvas.Top="441" Width="34" Height="32"
-                                 IsRunning="{Binding Fan1Running}" Speed="1" Text="风扇1"/>
-            <controls:FanControl Canvas.Left="522" Canvas.Top="441" Width="34" Height="32"
-                                 IsRunning="{Binding Fan2Running}" Speed="1" Text="风扇2"/>
-
-            <!-- 流量显示 -->
-            <Border Background="#2d2d44" CornerRadius="5" Canvas.Left="10" Canvas.Top="550" Padding="10">
-                <StackPanel Spacing="10">
-                    <TextBlock Foreground="#4CAF50" FontWeight="Bold" FontSize="14">
-                        <Run Text="进水流量: "/>
-                        <Run Text="{Binding InflowRate, StringFormat='{}{0:F1}'}"/>
-                        <Run Text=" m³/h"/>
-                    </TextBlock>
-                    <TextBlock Foreground="#2196F3" FontWeight="Bold" FontSize="14">
-                        <Run Text="出水流量: "/>
-                        <Run Text="{Binding OutflowRate, StringFormat='{}{0:F1}'}"/>
-                        <Run Text=" m³/h"/>
-                    </TextBlock>
-                </StackPanel>
-            </Border>
-
-            <!-- 报警信息 -->
-            <Border Background="#F44336" CornerRadius="5" Canvas.Left="259" Canvas.Top="544" Width="685" Height="43"
-                    IsVisible="{Binding HasAlarm}">
-                <TextBlock Text="{Binding AlarmMessage}" FontSize="20" Foreground="White"
-                           HorizontalAlignment="Center" VerticalAlignment="Center"/>
-            </Border>
-
-            <!-- 操作按钮区域 -->
-            <StackPanel Canvas.Left="10" Canvas.Top="10" Spacing="5">
-                <Button Content="连接PLC" Command="{Binding ConnectPlcCommand}" Width="80" Height="30"/>
-                <Button Content="断开PLC" Command="{Binding DisconnectPlcCommand}" Width="80" Height="30"/>
-                <Button Content="刷新数据" Command="{Binding RefreshDataCommand}" Width="80" Height="30"/>
-            </StackPanel>
-
-            <!-- 设备状态面板 -->
-            <Border Background="#2d2d44" CornerRadius="5" Canvas.Left="850" Canvas.Top="130" Width="160" Height="300" Padding="10">
-                <StackPanel Spacing="5">
-                    <TextBlock Text="设备状态" FontWeight="Bold" Foreground="White" FontSize="14"/>
-                    <Separator Background="#444"/>
-                    <StackPanel Orientation="Horizontal" Spacing="5">
-                        <Ellipse Width="10" Height="10" Fill="{Binding Pump1StatusColor}"/>
-                        <TextBlock Text="泵1" Foreground="White"/>
-                    </StackPanel>
-                    <StackPanel Orientation="Horizontal" Spacing="5">
-                        <Ellipse Width="10" Height="10" Fill="{Binding Pump2StatusColor}"/>
-                        <TextBlock Text="泵2" Foreground="White"/>
-                    </StackPanel>
-                    <StackPanel Orientation="Horizontal" Spacing="5">
-                        <Ellipse Width="10" Height="10" Fill="{Binding Pump3StatusColor}"/>
-                        <TextBlock Text="泵3" Foreground="White"/>
+    <Border Background="#0D1117" Width="1280" Height="800">
+        <Grid RowDefinitions="Auto,*,Auto" Margin="15">
+
+            <!-- 顶部工具栏 -->
+            <Border Grid.Row="0" Background="#161B22" CornerRadius="8" Padding="12" Margin="0,0,0,10">
+                <Grid ColumnDefinitions="Auto,*,Auto,Auto">
+                    <!-- 左侧标题 -->
+                    <StackPanel Grid.Column="0" Orientation="Horizontal" Spacing="10">
+                        <TextBlock Text="🏭" FontSize="20" VerticalAlignment="Center"/>
+                        <StackPanel>
+                            <TextBlock Text="污水处理监控系统" FontWeight="Bold" FontSize="16" Foreground="White"/>
+                            <TextBlock Text="实时工艺流程" FontSize="11" Foreground="#8B949E"/>
+                        </StackPanel>
                     </StackPanel>
-                    <StackPanel Orientation="Horizontal" Spacing="5">
-                        <Ellipse Width="10" Height="10" Fill="{Binding Pump4StatusColor}"/>
-                        <TextBlock Text="泵4" Foreground="White"/>
-                    </StackPanel>
-                    <StackPanel Orientation="Horizontal" Spacing="5">
-                        <Ellipse Width="10" Height="10" Fill="{Binding Pump5StatusColor}"/>
-                        <TextBlock Text="泵5" Foreground="White"/>
+
+                    <!-- 中间连接状态 -->
+                    <StackPanel Grid.Column="2" Orientation="Horizontal" Spacing="15" Margin="20,0">
+                        <Border Background="#238636" CornerRadius="12" Padding="10,5">
+                            <StackPanel Orientation="Horizontal" Spacing="5">
+                                <Ellipse Width="8" Height="8" Fill="White"/>
+                                <TextBlock Text="PLC 已连接" Foreground="White" FontSize="11"/>
+                            </StackPanel>
+                        </Border>
+                        <Button Content="连接" Command="{Binding ConnectPlcCommand}" Padding="12,4"/>
+                        <Button Content="断开" Command="{Binding DisconnectPlcCommand}" Padding="12,4"/>
+                        <Button Content="刷新" Command="{Binding RefreshDataCommand}" Padding="12,4"/>
                     </StackPanel>
-                    <Separator Background="#444"/>
-                    <StackPanel Orientation="Horizontal" Spacing="5">
-                        <Ellipse Width="10" Height="10" Fill="{Binding Fan1StatusColor}"/>
-                        <TextBlock Text="风扇1" Foreground="White"/>
+
+                    <!-- 右侧时间 -->
+                    <StackPanel Grid.Column="3" VerticalAlignment="Center">
+                        <TextBlock Text="{Binding CurrentTime, StringFormat='{}{0:HH:mm:ss}'}"
+                                   FontSize="18" FontWeight="Bold" Foreground="#58A6FF"/>
+                        <TextBlock Text="{Binding CurrentTime, StringFormat='{}{0:yyyy-MM-dd}'}"
+                                   FontSize="11" Foreground="#8B949E" HorizontalAlignment="Right"/>
                     </StackPanel>
-                    <StackPanel Orientation="Horizontal" Spacing="5">
-                        <Ellipse Width="10" Height="10" Fill="{Binding Fan2StatusColor}"/>
-                        <TextBlock Text="风扇2" Foreground="White"/>
+                </Grid>
+            </Border>
+
+            <!-- 中间主内容区 -->
+            <Grid Grid.Row="1" ColumnDefinitions="*,280">
+
+                <!-- 左侧工艺流程图 -->
+                <Border Grid.Column="0" Background="#161B22" CornerRadius="8" Padding="10" Margin="0,0,10,0">
+                    <Canvas Width="900" Height="550">
+
+                        <!-- 水箱组 -->
+                        <StackPanel Orientation="Horizontal" Canvas.Left="20" Canvas.Top="20" Spacing="30">
+                            <!-- 入口池 -->
+                            <StackPanel>
+                                <controls:WaterTankControl Width="120" Height="160"
+                                                           WaterLevel="{Binding Tank1Level}" Text="入口池"
+                                                           WaterColor="#00BCD4"/>
+                                <TextBlock Text="{Binding Tank1Level, StringFormat='液位: {0:F1}%'}"
+                                           Foreground="#8B949E" FontSize="11" HorizontalAlignment="Center" Margin="0,5,0,0"/>
+                            </StackPanel>
+
+                            <!-- 池1 -->
+                            <StackPanel>
+                                <controls:WaterTankControl Width="120" Height="160"
+                                                           WaterLevel="{Binding Tank2Level}" Text="生化池"
+                                                           WaterColor="#26A69A"/>
+                                <TextBlock Text="{Binding Tank2Level, StringFormat='液位: {0:F1}%'}"
+                                           Foreground="#8B949E" FontSize="11" HorizontalAlignment="Center" Margin="0,5,0,0"/>
+                            </StackPanel>
+
+                            <!-- 池2 -->
+                            <StackPanel>
+                                <controls:WaterTankControl Width="120" Height="160"
+                                                           WaterLevel="{Binding Tank3Level}" Text="沉淀池"
+                                                           WaterColor="#42A5F5"/>
+                                <TextBlock Text="{Binding Tank3Level, StringFormat='液位: {0:F1}%'}"
+                                           Foreground="#8B949E" FontSize="11" HorizontalAlignment="Center" Margin="0,5,0,0"/>
+                            </StackPanel>
+
+                            <!-- 出口池 -->
+                            <StackPanel>
+                                <controls:WaterTankControl Width="120" Height="160"
+                                                           WaterLevel="{Binding Tank4Level}" Text="出口池"
+                                                           WaterColor="#66BB6A"/>
+                                <TextBlock Text="{Binding Tank4Level, StringFormat='液位: {0:F1}%'}"
+                                           Foreground="#8B949E" FontSize="11" HorizontalAlignment="Center" Margin="0,5,0,0"/>
+                            </StackPanel>
+                        </StackPanel>
+
+                        <!-- 管道连接 -->
+                        <controls:PipeLineControl Canvas.Left="20" Canvas.Top="200" Width="540" Height="25"
+                                                  IsFlow="{Binding IsInflowRunning}" IsHorizontal="True"/>
+
+                        <!-- 阀门组 -->
+                        <StackPanel Orientation="Horizontal" Canvas.Left="50" Canvas.Top="240" Spacing="80">
+                            <controls:ValveControl Width="40" Height="50" Status="{Binding Valve1Status}" Text="进水"/>
+                            <controls:ValveControl Width="40" Height="50" Status="{Binding Valve2Status}" Text="曝气"/>
+                            <controls:ValveControl Width="40" Height="50" Status="{Binding Valve3Status}" Text="回流"/>
+                            <controls:ValveControl Width="40" Height="50" Status="{Binding Valve4Status}" Text="出水"/>
+                        </StackPanel>
+
+                        <!-- 泵组 -->
+                        <StackPanel Orientation="Horizontal" Canvas.Left="30" Canvas.Top="310" Spacing="25">
+                            <controls:PumpControl Width="70" Height="80"
+                                                  IsRunning="{Binding Pump1Running}" Frequency="50" Text="进水泵1"/>
+                            <controls:PumpControl Width="70" Height="80"
+                                                  IsRunning="{Binding Pump2Running}" Frequency="45" Text="进水泵2"/>
+                            <controls:PumpControl Width="70" Height="80"
+                                                  IsRunning="{Binding Pump3Running}" Frequency="40" Text="回流泵"/>
+                            <controls:PumpControl Width="70" Height="80"
+                                                  IsRunning="{Binding Pump4Running}" Frequency="35" Text="排泥泵"/>
+                            <controls:PumpControl Width="70" Height="80"
+                                                  IsRunning="{Binding Pump5Running}" Frequency="55" Text="加药泵"/>
+                        </StackPanel>
+
+                        <!-- 风机组 -->
+                        <StackPanel Orientation="Horizontal" Canvas.Left="120" Canvas.Top="410" Spacing="50">
+                            <controls:FanControl Width="50" Height="50" IsRunning="{Binding Fan1Running}" Speed="1" Text="风机1"/>
+                            <controls:FanControl Width="50" Height="50" IsRunning="{Binding Fan2Running}" Speed="1.5" Text="风机2"/>
+                        </StackPanel>
+
+                        <!-- 模式切换 -->
+                        <Border Canvas.Left="750" Canvas.Top="20" Width="120" Height="50"
+                                Background="#21262D" CornerRadius="8">
+                            <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
+                                <TextBlock Text="运行模式" FontSize="10" Foreground="#8B949E" HorizontalAlignment="Center"/>
+                                <controls:ValveControl Width="30" Height="30"
+                                                       Status="{Binding ModeStatus}" Text=""/>
+                            </StackPanel>
+                        </Border>
+
+                        <!-- 流程箭头 -->
+                        <Path Data="M 140 100 L 200 100" Stroke="#58A6FF" StrokeThickness="2">
+                            <Path.Data>
+                                <StreamGeometry>M 140 100 L 200 100</StreamGeometry>
+                            </Path.Data>
+                        </Path>
+                        <Path Data="M 320 100 L 380 100" Stroke="#58A6FF" StrokeThickness="2"/>
+                        <Path Data="M 500 100 L 560 100" Stroke="#58A6FF" StrokeThickness="2"/>
+                    </Canvas>
+                </Border>
+
+                <!-- 右侧面板 -->
+                <Grid Grid.Column="1" RowDefinitions="Auto,Auto,Auto,*,Auto">
+
+                    <!-- 流量仪表 -->
+                    <Border Grid.Row="0" Background="#161B22" CornerRadius="8" Padding="10" Margin="0,0,0,10">
+                        <StackPanel>
+                            <TextBlock Text="流量监测" FontWeight="Bold" Foreground="White" Margin="0,0,0,10"/>
+                            <Grid ColumnDefinitions="*,*">
+                                <controls:GaugeControl Grid.Column="0" Width="120" Height="140"
+                                                       Value="{Binding InflowRate}" Title="进水" Unit="m³/h"
+                                                       MaxValue="100"/>
+                                <controls:GaugeControl Grid.Column="1" Width="120" Height="140"
+                                                       Value="{Binding OutflowRate}" Title="出水" Unit="m³/h"
+                                                       MaxValue="100"
+                                                       ValueColor="#66BB6A"/>
+                            </Grid>
+                        </StackPanel>
+                    </Border>
+
+                    <!-- 设备状态 -->
+                    <Border Grid.Row="1" Background="#161B22" CornerRadius="8" Padding="10" Margin="0,0,0,10">
+                        <StackPanel>
+                            <TextBlock Text="设备状态" FontWeight="Bold" Foreground="White" Margin="0,0,0,10"/>
+                            <StackPanel Spacing="5">
+                                <controls:StatusCard Title="进水泵1" Status="{Binding Pump1Status}" Icon="🔄"
+                                                     IsActive="{Binding Pump1Running}"/>
+                                <controls:StatusCard Title="进水泵2" Status="{Binding Pump2Status}" Icon="🔄"
+                                                     IsActive="{Binding Pump2Running}"/>
+                                <controls:StatusCard Title="回流泵" Status="{Binding Pump3Status}" Icon="🔄"
+                                                     IsActive="{Binding Pump3Running}"/>
+                                <controls:StatusCard Title="风机1" Status="{Binding Fan1Status}" Icon="🌀"
+                                                     IsActive="{Binding Fan1Running}"/>
+                                <controls:StatusCard Title="风机2" Status="{Binding Fan2Status}" Icon="🌀"
+                                                     IsActive="{Binding Fan2Running}"/>
+                            </StackPanel>
+                        </StackPanel>
+                    </Border>
+
+                    <!-- 报警信息 -->
+                    <Border Grid.Row="2" Background="#161B22" CornerRadius="8" Padding="10" Margin="0,0,0,10"
+                            IsVisible="{Binding HasAlarm}">
+                        <StackPanel>
+                            <TextBlock Text="⚠️ 报警信息" FontWeight="Bold" Foreground="#F85149" Margin="0,0,0,10"/>
+                            <Border Background="#F85149" CornerRadius="5" Padding="10">
+                                <TextBlock Text="{Binding AlarmMessage}" Foreground="White" TextWrapping="Wrap"/>
+                            </Border>
+                        </StackPanel>
+                    </Border>
+
+                    <!-- 快捷操作 -->
+                    <Border Grid.Row="4" Background="#161B22" CornerRadius="8" Padding="10">
+                        <StackPanel>
+                            <TextBlock Text="快捷操作" FontWeight="Bold" Foreground="White" Margin="0,0,0,10"/>
+                            <WrapPanel HorizontalAlignment="Center">
+                                <Button Content="全部启动" Margin="5" Padding="12,6"/>
+                                <Button Content="全部停止" Margin="5" Padding="12,6"/>
+                                <Button Content="报警确认" Margin="5" Padding="12,6"/>
+                                <Button Content="数据导出" Margin="5" Padding="12,6"/>
+                            </WrapPanel>
+                        </StackPanel>
+                    </Border>
+                </Grid>
+            </Grid>
+
+            <!-- 底部状态栏 -->
+            <Border Grid.Row="2" Background="#161B22" CornerRadius="8" Padding="12" Margin="0,10,0,0">
+                <Grid ColumnDefinitions="Auto,*,Auto,Auto,Auto">
+                    <StackPanel Grid.Column="0" Orientation="Horizontal" Spacing="20">
+                        <TextBlock Foreground="#8B949E" FontSize="11">
+                            <Run Text="进水: "/>
+                            <Run Text="{Binding InflowRate, StringFormat='{}{0:F1} m³/h'}" Foreground="#58A6FF"/>
+                        </TextBlock>
+                        <TextBlock Foreground="#8B949E" FontSize="11">
+                            <Run Text="出水: "/>
+                            <Run Text="{Binding OutflowRate, StringFormat='{}{0:F1} m³/h'}" Foreground="#66BB6A"/>
+                        </TextBlock>
                     </StackPanel>
-                </StackPanel>
+
+                    <TextBlock Grid.Column="2" Foreground="#8B949E" FontSize="11">
+                        <Run Text="运行设备: "/>
+                        <Run Text="{Binding RunningDeviceCount}" Foreground="#58A6FF"/>
+                        <Run Text=" 台"/>
+                    </TextBlock>
+
+                    <TextBlock Grid.Column="3" Foreground="#8B949E" FontSize="11" Margin="20,0">
+                        <Run Text="报警: "/>
+                        <Run Text="{Binding AlarmCount}" Foreground="#F85149"/>
+                        <Run Text=" 条"/>
+                    </TextBlock>
+
+                    <TextBlock Grid.Column="4" Foreground="#8B949E" FontSize="11">
+                        <Run Text="系统运行: "/>
+                        <Run Text="{Binding RunningTime}" Foreground="#58A6FF"/>
+                    </TextBlock>
+                </Grid>
             </Border>
-        </Canvas>
+        </Grid>
     </Border>
 </UserControl>

+ 193 - 179
src/YZWater.Core/ViewModels/ViewAViewModel.cs

@@ -7,186 +7,175 @@ using YZWater.Core.Services;
 namespace YZWater.Core.ViewModels;
 
 /// <summary>
-/// 主工艺视图 ViewModel
+/// 主工艺视图 ViewModel(优化版)
 /// </summary>
 public partial class ViewAViewModel : ObservableObject
 {
+    private DateTime _startTime = DateTime.Now;
+
     // 液位数据
     [ObservableProperty]
-    private float _tank1Level = 50f;
+    private float _tank1Level = 65.5f;
 
     [ObservableProperty]
-    private float _tank2Level = 60f;
+    private float _tank2Level = 72.3f;
 
     [ObservableProperty]
-    private float _tank3Level = 70f;
+    private float _tank3Level = 58.8f;
 
     [ObservableProperty]
-    private float _tank4Level = 45f;
+    private float _tank4Level = 45.2f;
 
     // 流量数据
     [ObservableProperty]
-    private float _inflowRate = 25.5f;
+    private float _inflowRate = 35.6f;
 
     [ObservableProperty]
-    private float _outflowRate = 22.3f;
+    private float _outflowRate = 32.1f;
 
     // 泵状态
     [ObservableProperty]
-    private bool _pump1Running;
+    private bool _pump1Running = true;
 
     [ObservableProperty]
-    private bool _pump2Running;
+    private bool _pump2Running = false;
 
     [ObservableProperty]
-    private bool _pump3Running;
+    private bool _pump3Running = true;
 
     [ObservableProperty]
-    private bool _pump4Running;
+    private bool _pump4Running = false;
 
     [ObservableProperty]
-    private bool _pump5Running;
+    private bool _pump5Running = true;
 
     // 风扇状态
     [ObservableProperty]
-    private bool _fan1Running;
+    private bool _fan1Running = true;
 
     [ObservableProperty]
-    private bool _fan2Running;
+    private bool _fan2Running = false;
 
-    // 阀门状态
+    // 设备状态文本
     [ObservableProperty]
-    private ValveStatus _valve1Status = ValveStatus.Middle;
+    private string _pump1Status = "运行中 - 50Hz";
 
     [ObservableProperty]
-    private ValveStatus _valve2Status = ValveStatus.Middle;
+    private string _pump2Status = "已停止";
 
     [ObservableProperty]
-    private ValveStatus _valve3Status = ValveStatus.Middle;
+    private string _pump3Status = "运行中 - 40Hz";
 
     [ObservableProperty]
-    private ValveStatus _valve4Status = ValveStatus.Middle;
+    private string _pump4Status = "已停止";
 
     [ObservableProperty]
-    private ValveStatus _valve5Status = ValveStatus.Middle;
+    private string _pump5Status = "运行中 - 55Hz";
 
-    // 模式状态
     [ObservableProperty]
-    private ValveStatus _modeStatus = ValveStatus.Middle;
+    private string _fan1Status = "运行中 - 1500RPM";
 
-    // 流动状态
     [ObservableProperty]
-    private bool _isInflowRunning = true;
+    private string _fan2Status = "已停止";
 
+    // 阀门状态
     [ObservableProperty]
-    private bool _isOutflowRunning = true;
+    private ValveStatus _valve1Status = ValveStatus.Open;
 
-    // 设备状态颜色
     [ObservableProperty]
-    private string _pump1StatusColor = "#4CAF50";
+    private ValveStatus _valve2Status = ValveStatus.Open;
 
     [ObservableProperty]
-    private string _pump2StatusColor = "#4CAF50";
+    private ValveStatus _valve3Status = ValveStatus.Middle;
 
     [ObservableProperty]
-    private string _pump3StatusColor = "#4CAF50";
+    private ValveStatus _valve4Status = ValveStatus.Closed;
 
+    // 模式状态
     [ObservableProperty]
-    private string _pump4StatusColor = "#4CAF50";
+    private ValveStatus _modeStatus = ValveStatus.Open;
 
+    // 流动状态
     [ObservableProperty]
-    private string _pump5StatusColor = "#4CAF50";
+    private bool _isInflowRunning = true;
 
     [ObservableProperty]
-    private string _fan1StatusColor = "#4CAF50";
+    private bool _isOutflowRunning = true;
 
+    // 报警状态
     [ObservableProperty]
-    private string _fan2StatusColor = "#4CAF50";
+    private bool _hasAlarm = true;
 
-    // 报警状态
     [ObservableProperty]
-    private bool _hasAlarm;
+    private string _alarmMessage = "1号水池液位接近高限 (65.5%)";
 
     [ObservableProperty]
-    private string _alarmMessage = string.Empty;
+    private int _alarmCount = 1;
 
     // 连接状态
     [ObservableProperty]
-    private bool _isPlcConnected;
+    private bool _isPlcConnected = true;
+
+    // 设备计数
+    [ObservableProperty]
+    private int _runningDeviceCount = 5;
+
+    // 运行时间
+    [ObservableProperty]
+    private string _runningTime = "0天 2小时 35分";
+
+    // 当前时间
+    [ObservableProperty]
+    private DateTime _currentTime = DateTime.Now;
 
     public ViewAViewModel()
     {
-        StartDataRefresh();
+        StartTimers();
     }
 
     /// <summary>
-    /// 启动数据刷新
+    /// 启动定时器
     /// </summary>
-    private void StartDataRefresh()
+    private void StartTimers()
     {
-        var timer = new System.Timers.Timer(1000);
-        timer.Elapsed += async (s, e) =>
+        // 时间更新定时器
+        var timeTimer = new System.Timers.Timer(1000);
+        timeTimer.Elapsed += (s, e) =>
         {
-            await RefreshDataAsync();
+            CurrentTime = DateTime.Now;
+            var elapsed = DateTime.Now - _startTime;
+            RunningTime = $"{elapsed.Days}天 {elapsed.Hours}小时 {elapsed.Minutes}分";
         };
-        timer.Start();
+        timeTimer.Start();
+
+        // 数据模拟定时器
+        var dataTimer = new System.Timers.Timer(3000);
+        dataTimer.Elapsed += (s, e) =>
+        {
+            SimulateDataChanges();
+        };
+        dataTimer.Start();
     }
 
     /// <summary>
-    /// 刷新 PLC 数据
+    /// 模拟数据变化
     /// </summary>
-    [RelayCommand]
-    private async Task RefreshDataAsync()
+    private void SimulateDataChanges()
     {
-        if (!PlcService.IsConnected) return;
+        var random = new Random();
 
-        try
-        {
-            // 读取液位数据
-            Tank1Level = await PlcService.ReadFloatAsync("VD100");
-            Tank2Level = await PlcService.ReadFloatAsync("VD104");
-            Tank3Level = await PlcService.ReadFloatAsync("VD108");
-            Tank4Level = await PlcService.ReadFloatAsync("VD112");
+        // 模拟液位波动
+        Tank1Level = Math.Max(0, Math.Min(100, Tank1Level + (float)(random.NextDouble() * 2 - 1)));
+        Tank2Level = Math.Max(0, Math.Min(100, Tank2Level + (float)(random.NextDouble() * 2 - 1)));
+        Tank3Level = Math.Max(0, Math.Min(100, Tank3Level + (float)(random.NextDouble() * 2 - 1)));
+        Tank4Level = Math.Max(0, Math.Min(100, Tank4Level + (float)(random.NextDouble() * 2 - 1)));
 
-            // 读取流量数据
-            InflowRate = await PlcService.ReadFloatAsync("VD200");
-            OutflowRate = await PlcService.ReadFloatAsync("VD204");
+        // 模拟流量波动
+        InflowRate = Math.Max(0, InflowRate + (float)(random.NextDouble() * 4 - 2));
+        OutflowRate = Math.Max(0, OutflowRate + (float)(random.NextDouble() * 4 - 2));
 
-            // 读取泵状态
-            Pump1Running = await PlcService.ReadBoolAsync("Q0.0");
-            Pump2Running = await PlcService.ReadBoolAsync("Q0.1");
-            Pump3Running = await PlcService.ReadBoolAsync("Q0.2");
-            Pump4Running = await PlcService.ReadBoolAsync("Q0.3");
-            Pump5Running = await PlcService.ReadBoolAsync("Q0.4");
-
-            // 读取风扇状态
-            Fan1Running = await PlcService.ReadBoolAsync("Q0.5");
-            Fan2Running = await PlcService.ReadBoolAsync("Q0.6");
-
-            // 更新设备状态颜色
-            UpdateDeviceStatusColors();
-
-            // 检查报警
-            CheckAlarms();
-        }
-        catch (Exception ex)
-        {
-            Log.Error(ex, "刷新 PLC 数据失败");
-        }
-    }
-
-    /// <summary>
-    /// 更新设备状态颜色
-    /// </summary>
-    private void UpdateDeviceStatusColors()
-    {
-        Pump1StatusColor = Pump1Running ? "#4CAF50" : "#F44336";
-        Pump2StatusColor = Pump2Running ? "#4CAF50" : "#F44336";
-        Pump3StatusColor = Pump3Running ? "#4CAF50" : "#F44336";
-        Pump4StatusColor = Pump4Running ? "#4CAF50" : "#F44336";
-        Pump5StatusColor = Pump5Running ? "#4CAF50" : "#F44336";
-        Fan1StatusColor = Fan1Running ? "#4CAF50" : "#F44336";
-        Fan2StatusColor = Fan2Running ? "#4CAF50" : "#F44336";
+        // 检查报警
+        CheckAlarms();
     }
 
     /// <summary>
@@ -199,23 +188,57 @@ public partial class ViewAViewModel : ObservableObject
 
         HasAlarm = false;
         AlarmMessage = string.Empty;
+        AlarmCount = 0;
 
         if (Tank1Level > config.LevelHighAlarm)
         {
             HasAlarm = true;
-            AlarmMessage = "1号水池液位过高";
+            AlarmMessage = $"1号水池液位接近高限 ({Tank1Level:F1}%)";
+            AlarmCount++;
         }
         else if (Tank1Level < config.LevelLowAlarm)
         {
             HasAlarm = true;
-            AlarmMessage = "1号水池液位过低";
+            AlarmMessage = $"1号水池液位过低 ({Tank1Level:F1}%)";
+            AlarmCount++;
+        }
+
+        if (Tank2Level > config.LevelHighAlarm)
+        {
+            HasAlarm = true;
+            AlarmMessage += $"\n2号水池液位接近高限 ({Tank2Level:F1}%)";
+            AlarmCount++;
         }
 
         if (InflowRate > config.FlowHighAlarm)
         {
             HasAlarm = true;
-            AlarmMessage = "进水流量过高";
+            AlarmMessage += $"\n进水流量过高 ({InflowRate:F1} m³/h)";
+            AlarmCount++;
         }
+
+        // 更新运行设备数
+        RunningDeviceCount = (Pump1Running ? 1 : 0) + (Pump2Running ? 1 : 0) +
+                            (Pump3Running ? 1 : 0) + (Pump4Running ? 1 : 0) +
+                            (Pump5Running ? 1 : 0) + (Fan1Running ? 1 : 0) +
+                            (Fan2Running ? 1 : 0);
+
+        // 更新设备状态文本
+        UpdateDeviceStatusText();
+    }
+
+    /// <summary>
+    /// 更新设备状态文本
+    /// </summary>
+    private void UpdateDeviceStatusText()
+    {
+        Pump1Status = Pump1Running ? "运行中 - 50Hz" : "已停止";
+        Pump2Status = Pump2Running ? "运行中 - 45Hz" : "已停止";
+        Pump3Status = Pump3Running ? "运行中 - 40Hz" : "已停止";
+        Pump4Status = Pump4Running ? "运行中 - 35Hz" : "已停止";
+        Pump5Status = Pump5Running ? "运行中 - 55Hz" : "已停止";
+        Fan1Status = Fan1Running ? "运行中 - 1500RPM" : "已停止";
+        Fan2Status = Fan2Running ? "运行中 - 1200RPM" : "已停止";
     }
 
     /// <summary>
@@ -238,27 +261,45 @@ public partial class ViewAViewModel : ObservableObject
     }
 
     /// <summary>
-    /// 控制泵
+    /// 刷新数据
     /// </summary>
     [RelayCommand]
-    private async Task TogglePumpAsync(string pumpId)
+    private async Task RefreshDataAsync()
     {
         if (!PlcService.IsConnected)
         {
-            Log.Warning("PLC 未连接,无法控制泵");
+            Log.Warning("PLC 未连接,使用模拟数据");
             return;
         }
 
-        var address = pumpId switch
+        try
         {
-            "P001" => "Q0.0",
-            "P002" => "Q0.1",
-            "P003" => "Q0.2",
-            "P004" => "Q0.3",
-            "P005" => "Q0.4",
-            _ => throw new ArgumentException($"未知的泵 ID: {pumpId}")
-        };
+            Tank1Level = await PlcService.ReadFloatAsync("VD100");
+            Tank2Level = await PlcService.ReadFloatAsync("VD104");
+            Tank3Level = await PlcService.ReadFloatAsync("VD108");
+            Tank4Level = await PlcService.ReadFloatAsync("VD112");
+            InflowRate = await PlcService.ReadFloatAsync("VD200");
+            OutflowRate = await PlcService.ReadFloatAsync("VD204");
+            Pump1Running = await PlcService.ReadBoolAsync("Q0.0");
+            Pump2Running = await PlcService.ReadBoolAsync("Q0.1");
+            Pump3Running = await PlcService.ReadBoolAsync("Q0.2");
+            Fan1Running = await PlcService.ReadBoolAsync("Q0.3");
+            Fan2Running = await PlcService.ReadBoolAsync("Q0.4");
 
+            CheckAlarms();
+        }
+        catch (Exception ex)
+        {
+            Log.Error(ex, "刷新数据失败");
+        }
+    }
+
+    /// <summary>
+    /// 控制泵
+    /// </summary>
+    [RelayCommand]
+    private async Task TogglePumpAsync(string pumpId)
+    {
         var currentState = pumpId switch
         {
             "P001" => Pump1Running,
@@ -269,11 +310,31 @@ public partial class ViewAViewModel : ObservableObject
             _ => false
         };
 
-        var success = await PlcService.WriteBoolAsync(address, !currentState);
-        if (success)
+        var address = pumpId switch
+        {
+            "P001" => "Q0.0",
+            "P002" => "Q0.1",
+            "P003" => "Q0.2",
+            "P004" => "Q0.3",
+            "P005" => "Q0.4",
+            _ => ""
+        };
+
+        if (PlcService.IsConnected)
         {
-            Log.Information("泵 {PumpId} 状态已切换", pumpId);
+            await PlcService.WriteBoolAsync(address, !currentState);
         }
+
+        switch (pumpId)
+        {
+            case "P001": Pump1Running = !currentState; break;
+            case "P002": Pump2Running = !currentState; break;
+            case "P003": Pump3Running = !currentState; break;
+            case "P004": Pump4Running = !currentState; break;
+            case "P005": Pump5Running = !currentState; break;
+        }
+
+        CheckAlarms();
     }
 
     /// <summary>
@@ -282,19 +343,6 @@ public partial class ViewAViewModel : ObservableObject
     [RelayCommand]
     private async Task ToggleFanAsync(string fanId)
     {
-        if (!PlcService.IsConnected)
-        {
-            Log.Warning("PLC 未连接,无法控制风扇");
-            return;
-        }
-
-        var address = fanId switch
-        {
-            "F001" => "Q0.5",
-            "F002" => "Q0.6",
-            _ => throw new ArgumentException($"未知的风扇 ID: {fanId}")
-        };
-
         var currentState = fanId switch
         {
             "F001" => Fan1Running,
@@ -302,11 +350,16 @@ public partial class ViewAViewModel : ObservableObject
             _ => false
         };
 
-        var success = await PlcService.WriteBoolAsync(address, !currentState);
-        if (success)
+        if (PlcService.IsConnected)
         {
-            Log.Information("风扇 {FanId} 状态已切换", fanId);
+            var address = fanId == "F001" ? "Q0.3" : "Q0.4";
+            await PlcService.WriteBoolAsync(address, !currentState);
         }
+
+        if (fanId == "F001") Fan1Running = !currentState;
+        else Fan2Running = !currentState;
+
+        CheckAlarms();
     }
 
     /// <summary>
@@ -315,33 +368,15 @@ public partial class ViewAViewModel : ObservableObject
     [RelayCommand]
     private async Task ToggleValveAsync(string valveId)
     {
-        if (!PlcService.IsConnected)
-        {
-            Log.Warning("PLC 未连接,无法控制阀门");
-            return;
-        }
-
-        var address = valveId switch
-        {
-            "V001" => "Q1.0",
-            "V002" => "Q1.1",
-            "V003" => "Q1.2",
-            "V004" => "Q1.3",
-            "V005" => "Q1.4",
-            _ => throw new ArgumentException($"未知的阀门 ID: {valveId}")
-        };
-
         var currentStatus = valveId switch
         {
             "V001" => Valve1Status,
             "V002" => Valve2Status,
             "V003" => Valve3Status,
             "V004" => Valve4Status,
-            "V005" => Valve5Status,
             _ => ValveStatus.Middle
         };
 
-        // 循环切换状态: 关闭 -> 中间 -> 打开 -> 关闭
         var newStatus = currentStatus switch
         {
             ValveStatus.Closed => ValveStatus.Middle,
@@ -350,46 +385,25 @@ public partial class ViewAViewModel : ObservableObject
             _ => ValveStatus.Middle
         };
 
-        var success = await PlcService.WriteBoolAsync(address, newStatus == ValveStatus.Open);
-        if (success)
+        if (PlcService.IsConnected)
         {
-            switch (valveId)
+            var address = valveId switch
             {
-                case "V001": Valve1Status = newStatus; break;
-                case "V002": Valve2Status = newStatus; break;
-                case "V003": Valve3Status = newStatus; break;
-                case "V004": Valve4Status = newStatus; break;
-                case "V005": Valve5Status = newStatus; break;
-            }
-            Log.Information("阀门 {ValveId} 状态已切换为 {Status}", valveId, newStatus);
+                "V001" => "Q1.0",
+                "V002" => "Q1.1",
+                "V003" => "Q1.2",
+                "V004" => "Q1.3",
+                _ => ""
+            };
+            await PlcService.WriteBoolAsync(address, newStatus == ValveStatus.Open);
         }
-    }
-
-    /// <summary>
-    /// 切换模式
-    /// </summary>
-    [RelayCommand]
-    private async Task ToggleModeAsync()
-    {
-        if (!PlcService.IsConnected)
-        {
-            Log.Warning("PLC 未连接,无法切换模式");
-            return;
-        }
-
-        var newStatus = ModeStatus switch
-        {
-            ValveStatus.Closed => ValveStatus.Middle,
-            ValveStatus.Middle => ValveStatus.Open,
-            ValveStatus.Open => ValveStatus.Closed,
-            _ => ValveStatus.Middle
-        };
 
-        var success = await PlcService.WriteBoolAsync("M0.0", newStatus == ValveStatus.Open);
-        if (success)
+        switch (valveId)
         {
-            ModeStatus = newStatus;
-            Log.Information("模式已切换为: {Status}", newStatus);
+            case "V001": Valve1Status = newStatus; break;
+            case "V002": Valve2Status = newStatus; break;
+            case "V003": Valve3Status = newStatus; break;
+            case "V004": Valve4Status = newStatus; break;
         }
     }
 }