Bläddra i källkod

refactor: 清理 2D/3D 控件遗留硬编码模式(P5)

- 移除 23 个旧版 StyledProperty(Tank/Pump/Fan/Valve/Flow/HUD)
- 移除 RenderLegacy 方法及 20+ 个仅遗留模式使用的辅助方法
- 移除 IsDynamicMode 属性,统一走动态渲染路径
- ViewAView.axaml 移除 6 个不再需要的绑定
- 2D 控件 1311→~850 行(-35%),3D 控件 684→~440 行(-36%)
DESKTOP-74CLTRG\Leol 1 månad sedan
förälder
incheckning
f3f8c086b7

+ 59 - 383
src/YZWater.Avalonia/Controls/PumpStation2DControl.cs

@@ -18,12 +18,7 @@ namespace YZWater.Avalonia.Controls;
 /// <summary>
 /// 通用泵站 2D 工艺流程图控件 (SCADA 风格)。
 /// 设计画布 960×540,等比缩放适配实际尺寸。
-///
-/// <para>支持两种模式:</para>
-/// <list type="bullet">
-/// <item><b>动态模式</b>:设置 <see cref="Profile"/> 后,根据项目档案自动布局渲染</item>
-/// <item><b>兼容模式</b>:使用旧版硬编码属性(Tank1Level 等),保持向后兼容</item>
-/// </list>
+/// 根据项目档案 (Profile) + 模拟量/数字量字典自动布局渲染。
 /// </summary>
 public class PumpStation2DControl : Control
 {
@@ -41,7 +36,7 @@ public class PumpStation2DControl : Control
     public static readonly StyledProperty<ICommand?> DeviceClickedCommandProperty =
         AvaloniaProperty.Register<PumpStation2DControl, ICommand?>(nameof(DeviceClickedCommand));
 
-    /// <summary>项目档案 — 设置后自动切换到动态模式</summary>
+    /// <summary>项目档案 — 设置后自动布局渲染</summary>
     public ProjectProfile? Profile
     {
         get => GetValue(ProfileProperty);
@@ -69,56 +64,6 @@ public class PumpStation2DControl : Control
         set => SetValue(DeviceClickedCommandProperty, value);
     }
 
-    // ═══ 旧版硬编码属性(兼容模式) ═══
-
-    public static readonly StyledProperty<double> Tank1LevelProperty = AvaloniaProperty.Register<PumpStation2DControl, double>(nameof(Tank1Level));
-    public static readonly StyledProperty<double> Tank2LevelProperty = AvaloniaProperty.Register<PumpStation2DControl, double>(nameof(Tank2Level));
-    public static readonly StyledProperty<double> Tank3LevelProperty = AvaloniaProperty.Register<PumpStation2DControl, double>(nameof(Tank3Level));
-    public static readonly StyledProperty<double> Tank4LevelProperty = AvaloniaProperty.Register<PumpStation2DControl, double>(nameof(Tank4Level));
-    public static readonly StyledProperty<double> InflowRateProperty = AvaloniaProperty.Register<PumpStation2DControl, double>(nameof(InflowRate));
-    public static readonly StyledProperty<double> OutflowRateProperty = AvaloniaProperty.Register<PumpStation2DControl, double>(nameof(OutflowRate));
-    public static readonly StyledProperty<bool> Pump1RunningProperty = AvaloniaProperty.Register<PumpStation2DControl, bool>(nameof(Pump1Running));
-    public static readonly StyledProperty<bool> Pump2RunningProperty = AvaloniaProperty.Register<PumpStation2DControl, bool>(nameof(Pump2Running));
-    public static readonly StyledProperty<bool> Pump3RunningProperty = AvaloniaProperty.Register<PumpStation2DControl, bool>(nameof(Pump3Running));
-    public static readonly StyledProperty<bool> Pump4RunningProperty = AvaloniaProperty.Register<PumpStation2DControl, bool>(nameof(Pump4Running));
-    public static readonly StyledProperty<bool> Pump5RunningProperty = AvaloniaProperty.Register<PumpStation2DControl, bool>(nameof(Pump5Running));
-    public static readonly StyledProperty<bool> Fan1RunningProperty = AvaloniaProperty.Register<PumpStation2DControl, bool>(nameof(Fan1Running));
-    public static readonly StyledProperty<bool> Fan2RunningProperty = AvaloniaProperty.Register<PumpStation2DControl, bool>(nameof(Fan2Running));
-    public static readonly StyledProperty<ValveStatus> Valve1StatusProperty = AvaloniaProperty.Register<PumpStation2DControl, ValveStatus>(nameof(Valve1Status));
-    public static readonly StyledProperty<ValveStatus> Valve2StatusProperty = AvaloniaProperty.Register<PumpStation2DControl, ValveStatus>(nameof(Valve2Status));
-    public static readonly StyledProperty<ValveStatus> Valve3StatusProperty = AvaloniaProperty.Register<PumpStation2DControl, ValveStatus>(nameof(Valve3Status));
-    public static readonly StyledProperty<ValveStatus> Valve4StatusProperty = AvaloniaProperty.Register<PumpStation2DControl, ValveStatus>(nameof(Valve4Status));
-    public static readonly StyledProperty<bool> IsInflowRunningProperty = AvaloniaProperty.Register<PumpStation2DControl, bool>(nameof(IsInflowRunning));
-    public static readonly StyledProperty<bool> IsOutflowRunningProperty = AvaloniaProperty.Register<PumpStation2DControl, bool>(nameof(IsOutflowRunning));
-    public static readonly StyledProperty<bool> HasAlarmProperty = AvaloniaProperty.Register<PumpStation2DControl, bool>(nameof(HasAlarm));
-    public static readonly StyledProperty<int> AlarmCountProperty = AvaloniaProperty.Register<PumpStation2DControl, int>(nameof(AlarmCount));
-    public static readonly StyledProperty<int> RunningDeviceCountProperty = AvaloniaProperty.Register<PumpStation2DControl, int>(nameof(RunningDeviceCount));
-    public static readonly StyledProperty<double> EfficiencyProperty = AvaloniaProperty.Register<PumpStation2DControl, double>(nameof(Efficiency));
-
-    public double Tank1Level { get => GetValue(Tank1LevelProperty); set => SetValue(Tank1LevelProperty, value); }
-    public double Tank2Level { get => GetValue(Tank2LevelProperty); set => SetValue(Tank2LevelProperty, value); }
-    public double Tank3Level { get => GetValue(Tank3LevelProperty); set => SetValue(Tank3LevelProperty, value); }
-    public double Tank4Level { get => GetValue(Tank4LevelProperty); set => SetValue(Tank4LevelProperty, value); }
-    public double InflowRate { get => GetValue(InflowRateProperty); set => SetValue(InflowRateProperty, value); }
-    public double OutflowRate { get => GetValue(OutflowRateProperty); set => SetValue(OutflowRateProperty, value); }
-    public bool Pump1Running { get => GetValue(Pump1RunningProperty); set => SetValue(Pump1RunningProperty, value); }
-    public bool Pump2Running { get => GetValue(Pump2RunningProperty); set => SetValue(Pump2RunningProperty, value); }
-    public bool Pump3Running { get => GetValue(Pump3RunningProperty); set => SetValue(Pump3RunningProperty, value); }
-    public bool Pump4Running { get => GetValue(Pump4RunningProperty); set => SetValue(Pump4RunningProperty, value); }
-    public bool Pump5Running { get => GetValue(Pump5RunningProperty); set => SetValue(Pump5RunningProperty, value); }
-    public bool Fan1Running { get => GetValue(Fan1RunningProperty); set => SetValue(Fan1RunningProperty, value); }
-    public bool Fan2Running { get => GetValue(Fan2RunningProperty); set => SetValue(Fan2RunningProperty, value); }
-    public ValveStatus Valve1Status { get => GetValue(Valve1StatusProperty); set => SetValue(Valve1StatusProperty, value); }
-    public ValveStatus Valve2Status { get => GetValue(Valve2StatusProperty); set => SetValue(Valve2StatusProperty, value); }
-    public ValveStatus Valve3Status { get => GetValue(Valve3StatusProperty); set => SetValue(Valve3StatusProperty, value); }
-    public ValveStatus Valve4Status { get => GetValue(Valve4StatusProperty); set => SetValue(Valve4StatusProperty, value); }
-    public bool IsInflowRunning { get => GetValue(IsInflowRunningProperty); set => SetValue(IsInflowRunningProperty, value); }
-    public bool IsOutflowRunning { get => GetValue(IsOutflowRunningProperty); set => SetValue(IsOutflowRunningProperty, value); }
-    public bool HasAlarm { get => GetValue(HasAlarmProperty); set => SetValue(HasAlarmProperty, value); }
-    public int AlarmCount { get => GetValue(AlarmCountProperty); set => SetValue(AlarmCountProperty, value); }
-    public int RunningDeviceCount { get => GetValue(RunningDeviceCountProperty); set => SetValue(RunningDeviceCountProperty, value); }
-    public double Efficiency { get => GetValue(EfficiencyProperty); set => SetValue(EfficiencyProperty, value); }
-
     // ═══ 动画状态 ═══
 
     private double _phase;
@@ -150,17 +95,6 @@ public class PumpStation2DControl : Control
 
     static PumpStation2DControl()
     {
-        // 旧属性变化 → 兼容模式重绘
-        AffectsRender<PumpStation2DControl>(
-            Tank1LevelProperty, Tank2LevelProperty, Tank3LevelProperty, Tank4LevelProperty,
-            InflowRateProperty, OutflowRateProperty,
-            Pump1RunningProperty, Pump2RunningProperty, Pump3RunningProperty, Pump4RunningProperty, Pump5RunningProperty,
-            Fan1RunningProperty, Fan2RunningProperty,
-            Valve1StatusProperty, Valve2StatusProperty, Valve3StatusProperty, Valve4StatusProperty,
-            IsInflowRunningProperty, IsOutflowRunningProperty, HasAlarmProperty, AlarmCountProperty,
-            RunningDeviceCountProperty, EfficiencyProperty);
-
-        // 新属性变化 → 重算布局 + 重绘
         AffectsRender<PumpStation2DControl>(ProfileProperty, AnalogValuesProperty, DigitalValuesProperty);
     }
 
@@ -194,29 +128,19 @@ public class PumpStation2DControl : Control
         ThemeHelper.ThemeChanged += OnThemeChanged;
         _timer = DispatcherTimer.Run(() =>
         {
-            var needsAnimation = IsDynamicMode ? HasDynamicAnimation : HasLegacyAnimation;
-            if (needsAnimation)
+            if (HasDynamicAnimation)
             {
                 _phase = (_phase + 1) % 360;
                 _faultFlash = (_faultFlash + 0.03) % 1.0;
 
                 // 仅在实际有泵/扇运行时才旋转,避免静止设备无意义转动
-                if (IsDynamicMode)
-                {
-                    var anyPumpRunning = _cachedLayout?.Devices.Any(d =>
-                        d.DeviceType == "Pump" && GetDigitalValue($"{d.DeviceId}.Run")) ?? false;
-                    var anyFanRunning = _cachedLayout?.Devices.Any(d =>
-                        d.DeviceType == "Fan" && GetDigitalValue($"{d.DeviceId}.Run")) ?? false;
-
-                    if (anyPumpRunning) _pumpAngle = (_pumpAngle + 4) % 360;
-                    if (anyFanRunning) _fanAngle = (_fanAngle + 6) % 360;
-                }
-                else
-                {
-                    // 兼容模式:按旧逻辑
-                    if (AnyPumpRunning) _pumpAngle = (_pumpAngle + 4) % 360;
-                    if (Fan1Running || Fan2Running) _fanAngle = (_fanAngle + 6) % 360;
-                }
+                var anyPumpRunning = _cachedLayout?.Devices.Any(d =>
+                    d.DeviceType == "Pump" && GetDigitalValue($"{d.DeviceId}.Run")) ?? false;
+                var anyFanRunning = _cachedLayout?.Devices.Any(d =>
+                    d.DeviceType == "Fan" && GetDigitalValue($"{d.DeviceId}.Run")) ?? false;
+
+                if (anyPumpRunning) _pumpAngle = (_pumpAngle + 4) % 360;
+                if (anyFanRunning) _fanAngle = (_fanAngle + 6) % 360;
 
                 InvalidateVisual();
             }
@@ -234,10 +158,7 @@ public class PumpStation2DControl : Control
 
     private void OnThemeChanged() => InvalidateVisual();
 
-    // ═══ 模式判断 ═══
-
-    /// <summary>是否处于动态模式(已设置 Profile)</summary>
-    public bool IsDynamicMode => Profile != null;
+    // ═══ 动画判断 ═══
 
     private bool HasDynamicAnimation
     {
@@ -252,33 +173,57 @@ public class PumpStation2DControl : Control
         }
     }
 
-    private bool HasLegacyAnimation =>
-        AnyPumpRunning || Fan1Running || Fan2Running || IsInflowRunning || IsOutflowRunning;
+    // ═══ 点击事件 ═══
 
-    private bool AnyPumpRunning =>
-        Pump1Running || Pump2Running || Pump3Running || Pump4Running || Pump5Running;
+    protected override void OnPointerPressed(PointerPressedEventArgs e)
+    {
+        base.OnPointerPressed(e);
 
-    // ═══ 设计坐标常量 (960 × 540) — 仅兼容模式使用 ═══
+        if (_cachedLayout == null) return;
 
-    private const double DW = 960, DH = 540;
+        var pos = e.GetPosition(this);
+        var margin = 8.0;
+        var scaleX = (Bounds.Width - 2 * margin) / DW;
+        var scaleY = (Bounds.Height - 2 * margin) / DH;
+        var scale = Math.Min(scaleX, scaleY);
+        var offsetX = margin + (Bounds.Width - 2 * margin - DW * scale) / 2;
+        var offsetY = margin + (Bounds.Height - 2 * margin - DH * scale) / 2;
 
-    private static readonly Rect DTank1 = new(55, 130, 120, 140);
-    private static readonly Rect DTank2 = new(275, 85, 195, 210);
-    private static readonly Rect DTank3 = new(275, 400, 155, 105);
-    private static readonly Rect DTank4 = new(720, 130, 120, 140);
+        // 将屏幕坐标转换回设计坐标
+        var designX = (pos.X - offsetX) / scale;
+        var designY = (pos.Y - offsetY) / scale;
+        var designPos = new Point(designX, designY);
 
-    private static readonly Point[] DPumps = { new(300, 340), new(338, 340), new(376, 340), new(414, 340), new(452, 340) };
+        var hitDevice = _cachedLayout.Devices.FirstOrDefault(d => d.Bounds.Contains(designPos));
+        if (hitDevice != null && DeviceClickedCommand?.CanExecute(hitDevice.DeviceId) == true)
+        {
+            DeviceClickedCommand.Execute(hitDevice.DeviceId);
+            e.Handled = true;
+        }
+    }
 
-    private static readonly Point DFan1 = new(590, 450);
-    private static readonly Point DFan2 = new(660, 450);
+    // ═══ 值读取辅助 ═══
+
+    private float GetAnalogValue(string key)
+    {
+        return AnalogValues != null && AnalogValues.TryGetValue(key, out var v) ? v : 0f;
+    }
 
-    private static readonly Point DV1 = new(218, 200);
-    private static readonly Point DV2 = new(555, 195);
-    private static readonly Point DV3 = new(420, 395);
-    private static readonly Point DV4 = new(230, 450);
+    private bool GetDigitalValue(string key)
+    {
+        return DigitalValues != null && DigitalValues.TryGetValue(key, out var v) && v;
+    }
+
+    // ═══ 坐标变换辅助 ═══
+
+    private static double S(double offset, double scale, double designVal) => offset + designVal * scale;
+    private static double W(double scale, double designW) => designW * scale;
+    private static double H(double scale, double designH) => designH * scale;
+    private static double R(double scale, double designR) => designR * scale;
 
-    private static readonly Point DFM1 = new(22, 195);
-    private static readonly Point DFM2 = new(870, 195);
+    // ═══ 设计画布常量 ═══
+
+    private const double DW = 960, DH = 540;
 
     // ═══ 主渲染 ═══
 
@@ -292,14 +237,11 @@ public class PumpStation2DControl : Control
         // 背景(工业 SCADA 径向渐变:中心亮→边缘暗)
         context.DrawRectangle(s_bgBrush, null, bounds);
 
-        if (IsDynamicMode)
-            RenderDynamic(context, bounds);
-        else
-            RenderLegacy(context, bounds);
+        RenderDynamic(context, bounds);
     }
 
     // ════════════════════════════════════════════════════════
-    //  动态模式渲染
+    //  渲染
     // ════════════════════════════════════════════════════════
 
     private void RenderDynamic(DrawingContext context, Rect bounds)
@@ -405,7 +347,7 @@ public class PumpStation2DControl : Control
         DrawLegend(context, offsetX, offsetY, scale);
 
         // ─── 报警边框 ───
-        if (GetDigitalValue("Alarm.Active") || HasAlarm)
+        if (GetDigitalValue("Alarm.Active"))
         {
             var sceneRect = new Rect(margin, margin, bounds.Width - 2 * margin, bounds.Height - 2 * margin);
             context.DrawRectangle(null, new Pen(ThemeHelper.Danger, 2), sceneRect, 4);
@@ -867,7 +809,7 @@ public class PumpStation2DControl : Control
     {
         const double lampR = 7;                       // 灯半径(设计坐标)
         const double spacing = 26;                    // 灯间距
-        var hasAlarm = GetDigitalValue("Alarm.Active") || HasAlarm;
+        var hasAlarm = GetDigitalValue("Alarm.Active");
 
         var lampY = offsetY + 16;                     // 与标题同行
         var startX = offsetX + DW * scale - 30 - profile.Pumps.Count * spacing * scale;
@@ -1020,273 +962,7 @@ public class PumpStation2DControl : Control
             ThemeHelper.TextSecondary, stemPenThickness: Math.Max(1, 1.5 * scale));
     }
 
-    // ════════════════════════════════════════════════════════
-    //  兼容模式渲染(旧版硬编码布局)
-    // ════════════════════════════════════════════════════════
-
-    private void RenderLegacy(DrawingContext context, Rect bounds)
-    {
-        var margin = 8.0;
-        var scaleX = (bounds.Width - 2 * margin) / DW;
-        var scaleY = (bounds.Height - 2 * margin) / DH;
-        var scale = Math.Min(scaleX, scaleY);
-        var offsetX = margin + (bounds.Width - 2 * margin - DW * scale) / 2;
-        var offsetY = margin + (bounds.Height - 2 * margin - DH * scale) / 2;
-
-        // 地面线
-        DrawLine(context, offsetX, offsetY, scale, 0, 520, 960, 520, ThemeHelper.Border, 1);
-
-        // ═══ 管道 ═══
-
-        DrawPipeH(context, offsetX, offsetY, scale, 0, 200, 55, IsInflowRunning, 10);
-        DrawFlowMeter(context, offsetX, offsetY, scale, DFM1, "进水", InflowRate, IsInflowRunning);
-        DrawPipeH(context, offsetX, offsetY, scale, 48, 200, 55, IsInflowRunning, 10);
-
-        DrawPipeH(context, offsetX, offsetY, scale, 175, 200, 195, IsInflowRunning, 8);
-        DrawValve(context, offsetX, offsetY, scale, DV1, "V1", Valve1Status);
-        DrawPipeH(context, offsetX, offsetY, scale, 240, 200, 275, IsInflowRunning, 8);
-
-        DrawPipeV(context, offsetX, offsetY, scale, 372, 295, 325, AnyPumpRunning, 8);
-        DrawPipeH(context, offsetX, offsetY, scale, 285, 365, 470, AnyPumpRunning, 10);
-
-        DrawPipeV(context, offsetX, offsetY, scale, 500, 365, 195, IsOutflowRunning, 10);
-        DrawPipeH(context, offsetX, offsetY, scale, 500, 195, 530, IsOutflowRunning, 10);
-        DrawValve(context, offsetX, offsetY, scale, DV2, "V2", Valve2Status);
-        DrawPipeH(context, offsetX, offsetY, scale, 580, 195, 720, IsOutflowRunning, 10);
-
-        DrawPipeH(context, offsetX, offsetY, scale, 840, 200, 860, IsOutflowRunning, 10);
-        DrawFlowMeter(context, offsetX, offsetY, scale, DFM2, "出水", OutflowRate, IsOutflowRunning);
-        DrawPipeH(context, offsetX, offsetY, scale, 896, 200, 960, IsOutflowRunning, 10);
-
-        DrawPipeV(context, offsetX, offsetY, scale, 420, 365, 378, false, 8);
-        DrawValve(context, offsetX, offsetY, scale, DV3, "V3", Valve3Status);
-        DrawPipeV(context, offsetX, offsetY, scale, 420, 412, 400, false, 8);
-
-        DrawPipeV(context, offsetX, offsetY, scale, 230, 295, 430, false, 8);
-        DrawPipeH(context, offsetX, offsetY, scale, 230, 450, 275, false, 8);
-        DrawValve(context, offsetX, offsetY, scale, DV4, "V4", Valve4Status);
-
-        // ═══ 水箱 ═══
-
-        DrawTank(context, offsetX, offsetY, scale, DTank1, Tank1Level, "进水池", "IN",
-            Color.FromRgb(0, 137, 123));
-        DrawTank(context, offsetX, offsetY, scale, DTank2, Tank2Level, "集水井", "SUMP",
-            Color.FromRgb(33, 150, 243));
-        DrawTank(context, offsetX, offsetY, scale, DTank3, Tank3Level, "调蓄池", "BUF",
-            Color.FromRgb(126, 87, 194));
-        DrawTank(context, offsetX, offsetY, scale, DTank4, Tank4Level, "出水池", "OUT",
-            Color.FromRgb(0, 150, 136));
-
-        // ═══ 泵组 ═══
-
-        bool[] pumpRunning = { Pump1Running, Pump2Running, Pump3Running, Pump4Running, Pump5Running };
-        string[] pumpLabels = { "P1", "P2", "P3", "P4", "P5" };
-        for (int i = 0; i < 5; i++)
-            DrawPump(context, offsetX, offsetY, scale, DPumps[i], pumpLabels[i], pumpRunning[i]);
-
-        // ═══ 风机 ═══
-
-        DrawFan(context, offsetX, offsetY, scale, DFan1, "F1", Fan1Running);
-        DrawFan(context, offsetX, offsetY, scale, DFan2, "F2", Fan2Running);
-
-        var fanAreaX = S(offsetX, scale, 555);
-        var fanAreaY = S(offsetY, scale, 418);
-        var fanAreaW = W(scale, 180);
-        var fanAreaH = H(scale, 75);
-        context.DrawRectangle(null, new Pen(ThemeHelper.Border, 1),
-            new Rect(fanAreaX, fanAreaY, fanAreaW, fanAreaH), 3, 3);
-        DrawLabel(context, offsetX, offsetY, scale, 560, 422, "风机区", 10, ThemeHelper.TextTertiary);
-
-        // ═══ 报警边框 ═══
-
-        if (HasAlarm)
-        {
-            var sceneRect = new Rect(margin, margin, bounds.Width - 2 * margin, bounds.Height - 2 * margin);
-            context.DrawRectangle(null, new Pen(ThemeHelper.Danger, 2), sceneRect, 4);
-        }
-
-        // ═══ HUD ═══
-
-        DrawHud(context, bounds, scale);
-    }
-
-    // ═══ 值读取辅助 ═══
-
-    private float GetAnalogValue(string key)
-    {
-        return AnalogValues != null && AnalogValues.TryGetValue(key, out var v) ? v : 0f;
-    }
-
-    private bool GetDigitalValue(string key)
-    {
-        return DigitalValues != null && DigitalValues.TryGetValue(key, out var v) && v;
-    }
-
-    // ═══ 点击事件 ═══
-
-    protected override void OnPointerPressed(PointerPressedEventArgs e)
-    {
-        base.OnPointerPressed(e);
-
-        if (!IsDynamicMode || _cachedLayout == null) return;
-
-        var pos = e.GetPosition(this);
-        var margin = 8.0;
-        var scaleX = (Bounds.Width - 2 * margin) / DW;
-        var scaleY = (Bounds.Height - 2 * margin) / DH;
-        var scale = Math.Min(scaleX, scaleY);
-        var offsetX = margin + (Bounds.Width - 2 * margin - DW * scale) / 2;
-        var offsetY = margin + (Bounds.Height - 2 * margin - DH * scale) / 2;
-
-        // 将屏幕坐标转换回设计坐标
-        var designX = (pos.X - offsetX) / scale;
-        var designY = (pos.Y - offsetY) / scale;
-        var designPos = new Point(designX, designY);
-
-        var hitDevice = _cachedLayout.Devices.FirstOrDefault(d => d.Bounds.Contains(designPos));
-        if (hitDevice != null && DeviceClickedCommand?.CanExecute(hitDevice.DeviceId) == true)
-        {
-            DeviceClickedCommand.Execute(hitDevice.DeviceId);
-            e.Handled = true;
-        }
-    }
-
-    // ═══ 兼容模式绘制辅助 ═══
-
-    private static double S(double offset, double scale, double designVal) => offset + designVal * scale;
-    private static double W(double scale, double designW) => designW * scale;
-    private static double H(double scale, double designH) => designH * scale;
-    private static double R(double scale, double designR) => designR * scale;
-
-    private void DrawTank(DrawingContext context, double ox, double oy, double sc,
-        Rect designRect, double level, string name, string code, Color waterColor)
-    {
-        var x = S(ox, sc, designRect.X);
-        var y = S(oy, sc, designRect.Y);
-        var w = W(sc, designRect.Width);
-        var h = H(sc, designRect.Height);
-        var rect = new Rect(x, y, w, h);
-
-        TankRenderer.Draw(context, rect, level, waterColor, name, code,
-            ThemeHelper.SurfaceBg, ThemeHelper.Border,
-            ThemeHelper.TextPrimary, ThemeHelper.TextTertiary,
-            ThemeHelper.Warning, ThemeHelper.Danger);
-    }
-
-    private void DrawPipeH(DrawingContext context, double ox, double oy, double sc,
-        double x1Design, double yDesign, double x2Design, bool isFlowing, double thicknessDesign)
-    {
-        var x1 = S(ox, sc, x1Design);
-        var y = S(oy, sc, yDesign);
-        var x2 = S(ox, sc, x2Design);
-        var thickness = R(sc, thicknessDesign);
-
-        PipeRenderer.DrawHorizontal(context, x1, y, x2, thickness, isFlowing, _phase);
-    }
-
-    private void DrawPipeV(DrawingContext context, double ox, double oy, double sc,
-        double xDesign, double y1Design, double y2Design, bool isFlowing, double thicknessDesign)
-    {
-        var x = S(ox, sc, xDesign);
-        var y1 = S(oy, sc, y1Design);
-        var y2 = S(oy, sc, y2Design);
-        var thickness = R(sc, thicknessDesign);
-
-        PipeRenderer.DrawVertical(context, x, y1, y2, thickness, isFlowing, _phase);
-    }
-
-    private void DrawPump(DrawingContext context, double ox, double oy, double sc,
-        Point designPos, string label, bool running)
-    {
-        var cx = S(ox, sc, designPos.X);
-        var cy = S(oy, sc, designPos.Y);
-        var r = R(sc, 18);
-        var statusColor = running ? GetColor(ThemeHelper.Success) : GetColor(ThemeHelper.TextDisabled);
-
-        PumpRenderer.Draw(context, new Point(cx, cy), r, running, statusColor,
-            _pumpAngle, label, ThemeHelper.SurfaceBg, ThemeHelper.Border, ThemeHelper.TextPrimary,
-            bladeCount: 4, bladePenThickness: Math.Max(1.5, 2.5 * sc));
-    }
-
-    private void DrawFan(DrawingContext context, double ox, double oy, double sc,
-        Point designPos, string label, bool running)
-    {
-        var cx = S(ox, sc, designPos.X);
-        var cy = S(oy, sc, designPos.Y);
-        var r = R(sc, 20);
-        var statusColor = running ? GetColor(ThemeHelper.Info) : GetColor(ThemeHelper.TextDisabled);
-
-        FanRenderer.Draw(context, new Point(cx, cy), r, running, _fanAngle, label,
-            statusColor, ThemeHelper.SurfaceBg, ThemeHelper.TextPrimary,
-            bladeCount: 5, bladePenThickness: Math.Max(2, 3 * sc));
-    }
-
-    private void DrawValve(DrawingContext context, double ox, double oy, double sc,
-        Point designPos, string label, ValveStatus status)
-    {
-        var cx = S(ox, sc, designPos.X);
-        var cy = S(oy, sc, designPos.Y);
-        var s = R(sc, 12);
-
-        var color = status switch
-        {
-            ValveStatus.Open => GetColor(ThemeHelper.Success),
-            ValveStatus.Middle => GetColor(ThemeHelper.Warning),
-            ValveStatus.Closed => GetColor(ThemeHelper.Danger),
-            _ => GetColor(ThemeHelper.TextDisabled)
-        };
-
-        ValveRenderer.Draw(context, new Point(cx, cy), s, color, label,
-            ThemeHelper.TextSecondary, stemPenThickness: Math.Max(1, 1.5 * sc));
-    }
-
-    private void DrawFlowMeter(DrawingContext context, double ox, double oy, double sc,
-        Point designPos, string label, double value, bool active)
-    {
-        var cx = S(ox, sc, designPos.X);
-        var cy = S(oy, sc, designPos.Y);
-        var w = W(sc, 56);
-        var h = H(sc, 32);
-
-        FlowMeterRenderer.Draw(context, new Point(cx, cy), w, h, label, value, active,
-            GetColor(ThemeHelper.Success), GetColor(ThemeHelper.TextDisabled),
-            ThemeHelper.SurfaceBg, ThemeHelper.TextTertiary);
-    }
-
-    private void DrawHud(DrawingContext context, Rect bounds, double scale)
-    {
-        var panelW = Math.Max(120, 185 * Math.Min(scale, 1.5));
-        var panelH = Math.Max(45, 58 * Math.Min(scale, 1.5));
-        var panelX = bounds.Right - panelW - 10;
-        var panelY = bounds.Top + 8;
-        var panelRect = new Rect(panelX, panelY, panelW, panelH);
-
-        context.DrawRectangle(new SolidColorBrush(GetColor(ThemeHelper.SurfaceBg), 0.92),
-            new Pen(ThemeHelper.Border, 1), panelRect, 3, 3);
-
-        var fontSize = Math.Max(8, 10 * Math.Min(scale, 1.5));
-        var smallFont = Math.Max(7, 9 * Math.Min(scale, 1.5));
-
-        DrawLabelAt(context, panelX + 8, panelY + 6, "泵站总览", fontSize * 1.15, ThemeHelper.TextPrimary, FontWeight.Bold);
-        DrawLabelAt(context, panelX + 8, panelY + 6 + fontSize * 1.5,
-            $"运行 {RunningDeviceCount}  效率 {Efficiency:F0}%", smallFont, ThemeHelper.TextSecondary);
-
-        var alarmColor = HasAlarm ? ThemeHelper.Danger : ThemeHelper.Success;
-        DrawLabelAt(context, panelX + 8, panelY + 6 + fontSize * 1.5 + smallFont * 1.5,
-            $"报警 {AlarmCount}", smallFont, alarmColor, FontWeight.Bold);
-    }
-
-    // ═══ 文字/线条绘制辅助 ═══
-
-    private void DrawLabel(DrawingContext context, double ox, double oy, double sc,
-        double designX, double designY, string text, double designFontSize,
-        IBrush brush, FontWeight weight = FontWeight.Normal)
-    {
-        var x = S(ox, sc, designX);
-        var y = S(oy, sc, designY);
-        var size = Math.Max(8, designFontSize * sc);
-        DrawLabelAt(context, x, y, text, size, brush, weight);
-    }
+    // ═══ 图例绘制辅助 ═══
 
     private static void DrawLabelAt(DrawingContext context, double x, double y, string text,
         double size, IBrush brush, FontWeight weight = FontWeight.Normal)

+ 10 - 257
src/YZWater.Avalonia/Controls/PumpStation3DControl.cs

@@ -16,12 +16,7 @@ namespace YZWater.Avalonia.Controls;
 
 /// <summary>
 /// 通用污水提升泵站 2.5D 工艺总览控件(等轴测投影)。
-///
-/// <para>支持两种模式:</para>
-/// <list type="bullet">
-/// <item><b>动态模式</b>:设置 <see cref="Profile"/> 后,根据项目档案自动布局渲染</item>
-/// <item><b>兼容模式</b>:使用旧版硬编码属性,保持向后兼容</item>
-/// </list>
+/// 根据项目档案 (Profile) + 模拟量/数字量字典自动布局渲染。
 /// </summary>
 public class PumpStation3DControl : Control
 {
@@ -63,56 +58,6 @@ public class PumpStation3DControl : Control
         set => SetValue(DeviceClickedCommandProperty, value);
     }
 
-    // ═══ 旧版硬编码属性 ═══
-
-    public static readonly StyledProperty<double> Tank1LevelProperty = AvaloniaProperty.Register<PumpStation3DControl, double>(nameof(Tank1Level));
-    public static readonly StyledProperty<double> Tank2LevelProperty = AvaloniaProperty.Register<PumpStation3DControl, double>(nameof(Tank2Level));
-    public static readonly StyledProperty<double> Tank3LevelProperty = AvaloniaProperty.Register<PumpStation3DControl, double>(nameof(Tank3Level));
-    public static readonly StyledProperty<double> Tank4LevelProperty = AvaloniaProperty.Register<PumpStation3DControl, double>(nameof(Tank4Level));
-    public static readonly StyledProperty<double> InflowRateProperty = AvaloniaProperty.Register<PumpStation3DControl, double>(nameof(InflowRate));
-    public static readonly StyledProperty<double> OutflowRateProperty = AvaloniaProperty.Register<PumpStation3DControl, double>(nameof(OutflowRate));
-    public static readonly StyledProperty<bool> Pump1RunningProperty = AvaloniaProperty.Register<PumpStation3DControl, bool>(nameof(Pump1Running));
-    public static readonly StyledProperty<bool> Pump2RunningProperty = AvaloniaProperty.Register<PumpStation3DControl, bool>(nameof(Pump2Running));
-    public static readonly StyledProperty<bool> Pump3RunningProperty = AvaloniaProperty.Register<PumpStation3DControl, bool>(nameof(Pump3Running));
-    public static readonly StyledProperty<bool> Pump4RunningProperty = AvaloniaProperty.Register<PumpStation3DControl, bool>(nameof(Pump4Running));
-    public static readonly StyledProperty<bool> Pump5RunningProperty = AvaloniaProperty.Register<PumpStation3DControl, bool>(nameof(Pump5Running));
-    public static readonly StyledProperty<bool> Fan1RunningProperty = AvaloniaProperty.Register<PumpStation3DControl, bool>(nameof(Fan1Running));
-    public static readonly StyledProperty<bool> Fan2RunningProperty = AvaloniaProperty.Register<PumpStation3DControl, bool>(nameof(Fan2Running));
-    public static readonly StyledProperty<ValveStatus> Valve1StatusProperty = AvaloniaProperty.Register<PumpStation3DControl, ValveStatus>(nameof(Valve1Status));
-    public static readonly StyledProperty<ValveStatus> Valve2StatusProperty = AvaloniaProperty.Register<PumpStation3DControl, ValveStatus>(nameof(Valve2Status));
-    public static readonly StyledProperty<ValveStatus> Valve3StatusProperty = AvaloniaProperty.Register<PumpStation3DControl, ValveStatus>(nameof(Valve3Status));
-    public static readonly StyledProperty<ValveStatus> Valve4StatusProperty = AvaloniaProperty.Register<PumpStation3DControl, ValveStatus>(nameof(Valve4Status));
-    public static readonly StyledProperty<bool> IsInflowRunningProperty = AvaloniaProperty.Register<PumpStation3DControl, bool>(nameof(IsInflowRunning));
-    public static readonly StyledProperty<bool> IsOutflowRunningProperty = AvaloniaProperty.Register<PumpStation3DControl, bool>(nameof(IsOutflowRunning));
-    public static readonly StyledProperty<bool> HasAlarmProperty = AvaloniaProperty.Register<PumpStation3DControl, bool>(nameof(HasAlarm));
-    public static readonly StyledProperty<int> AlarmCountProperty = AvaloniaProperty.Register<PumpStation3DControl, int>(nameof(AlarmCount));
-    public static readonly StyledProperty<int> RunningDeviceCountProperty = AvaloniaProperty.Register<PumpStation3DControl, int>(nameof(RunningDeviceCount));
-    public static readonly StyledProperty<double> EfficiencyProperty = AvaloniaProperty.Register<PumpStation3DControl, double>(nameof(Efficiency));
-
-    public double Tank1Level { get => GetValue(Tank1LevelProperty); set => SetValue(Tank1LevelProperty, value); }
-    public double Tank2Level { get => GetValue(Tank2LevelProperty); set => SetValue(Tank2LevelProperty, value); }
-    public double Tank3Level { get => GetValue(Tank3LevelProperty); set => SetValue(Tank3LevelProperty, value); }
-    public double Tank4Level { get => GetValue(Tank4LevelProperty); set => SetValue(Tank4LevelProperty, value); }
-    public double InflowRate { get => GetValue(InflowRateProperty); set => SetValue(InflowRateProperty, value); }
-    public double OutflowRate { get => GetValue(OutflowRateProperty); set => SetValue(OutflowRateProperty, value); }
-    public bool Pump1Running { get => GetValue(Pump1RunningProperty); set => SetValue(Pump1RunningProperty, value); }
-    public bool Pump2Running { get => GetValue(Pump2RunningProperty); set => SetValue(Pump2RunningProperty, value); }
-    public bool Pump3Running { get => GetValue(Pump3RunningProperty); set => SetValue(Pump3RunningProperty, value); }
-    public bool Pump4Running { get => GetValue(Pump4RunningProperty); set => SetValue(Pump4RunningProperty, value); }
-    public bool Pump5Running { get => GetValue(Pump5RunningProperty); set => SetValue(Pump5RunningProperty, value); }
-    public bool Fan1Running { get => GetValue(Fan1RunningProperty); set => SetValue(Fan1RunningProperty, value); }
-    public bool Fan2Running { get => GetValue(Fan2RunningProperty); set => SetValue(Fan2RunningProperty, value); }
-    public ValveStatus Valve1Status { get => GetValue(Valve1StatusProperty); set => SetValue(Valve1StatusProperty, value); }
-    public ValveStatus Valve2Status { get => GetValue(Valve2StatusProperty); set => SetValue(Valve2StatusProperty, value); }
-    public ValveStatus Valve3Status { get => GetValue(Valve3StatusProperty); set => SetValue(Valve3StatusProperty, value); }
-    public ValveStatus Valve4Status { get => GetValue(Valve4StatusProperty); set => SetValue(Valve4StatusProperty, value); }
-    public bool IsInflowRunning { get => GetValue(IsInflowRunningProperty); set => SetValue(IsInflowRunningProperty, value); }
-    public bool IsOutflowRunning { get => GetValue(IsOutflowRunningProperty); set => SetValue(IsOutflowRunningProperty, value); }
-    public bool HasAlarm { get => GetValue(HasAlarmProperty); set => SetValue(HasAlarmProperty, value); }
-    public int AlarmCount { get => GetValue(AlarmCountProperty); set => SetValue(AlarmCountProperty, value); }
-    public int RunningDeviceCount { get => GetValue(RunningDeviceCountProperty); set => SetValue(RunningDeviceCountProperty, value); }
-    public double Efficiency { get => GetValue(EfficiencyProperty); set => SetValue(EfficiencyProperty, value); }
-
     // ═══ 动画 & 布局 ═══
 
     private double _phase;
@@ -122,20 +67,11 @@ public class PumpStation3DControl : Control
     private LayoutResult? _cachedLayout;
     private Size _lastCanvasSize;
 
-    private static readonly SolidColorBrush FlowDotBrush3D = new(Color.FromRgb(3, 169, 244));
     private static readonly SolidColorBrush PumpBodyBrush = new(Color.FromRgb(31, 41, 55));
 
     static PumpStation3DControl()
     {
-        AffectsRender<PumpStation3DControl>(
-            Tank1LevelProperty, Tank2LevelProperty, Tank3LevelProperty, Tank4LevelProperty,
-            InflowRateProperty, OutflowRateProperty,
-            Pump1RunningProperty, Pump2RunningProperty, Pump3RunningProperty, Pump4RunningProperty, Pump5RunningProperty,
-            Fan1RunningProperty, Fan2RunningProperty,
-            Valve1StatusProperty, Valve2StatusProperty, Valve3StatusProperty, Valve4StatusProperty,
-            IsInflowRunningProperty, IsOutflowRunningProperty, HasAlarmProperty, AlarmCountProperty,
-            RunningDeviceCountProperty, EfficiencyProperty,
-            ProfileProperty, AnalogValuesProperty, DigitalValuesProperty);
+        AffectsRender<PumpStation3DControl>(ProfileProperty, AnalogValuesProperty, DigitalValuesProperty);
     }
 
     protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
@@ -161,8 +97,7 @@ public class PumpStation3DControl : Control
         ThemeHelper.ThemeChanged += OnThemeChanged;
         _timer = DispatcherTimer.Run(() =>
         {
-            var needsAnim = IsDynamicMode ? HasDynamicAnimation : HasLegacyAnimation;
-            if (needsAnim)
+            if (HasDynamicAnimation)
             {
                 _phase = (_phase + 1) % 120;
                 _faultFlash = (_faultFlash + 0.025) % 1.0;
@@ -182,19 +117,11 @@ public class PumpStation3DControl : Control
 
     private void OnThemeChanged() { _cachedLayout = null; InvalidateVisual(); }
 
-    // ═══ 模式判断 ═══
-
-    public bool IsDynamicMode => Profile != null;
+    // ═══ 动画判断 ═══
 
     private bool HasDynamicAnimation =>
         _cachedLayout?.Devices.Any(d => d.DeviceType == "Pump" && GetDigitalValue($"{d.DeviceId}.Run")) == true;
 
-    private bool HasLegacyAnimation =>
-        AnyPumpRunning || Fan1Running || Fan2Running || IsInflowRunning || IsOutflowRunning;
-
-    private bool AnyPumpRunning =>
-        Pump1Running || Pump2Running || Pump3Running || Pump4Running || Pump5Running;
-
     // ═══ 值读取 ═══
 
     private float GetAnalogValue(string key) =>
@@ -212,14 +139,11 @@ public class PumpStation3DControl : Control
         if (bounds.Width < 120 || bounds.Height < 120) return;
         context.DrawRectangle(ThemeHelper.PanelBg, null, bounds);
 
-        if (IsDynamicMode)
-            RenderDynamic(context, bounds);
-        else
-            RenderLegacy(context, bounds);
+        RenderDynamic(context, bounds);
     }
 
     // ════════════════════════════════════════════════════════
-    //  动态模式
+    //  渲染
     // ════════════════════════════════════════════════════════
 
     private void RenderDynamic(DrawingContext context, Rect bounds)
@@ -260,7 +184,6 @@ public class PumpStation3DControl : Control
             switch (device.DeviceType)
             {
                 case "Tank":
-                    var level = (double)GetAnalogValue($"{device.DeviceId}.Level");
                     DrawDynamicTank3D(context, origin, scale, cx, cy, device);
                     break;
                 case "Pump":
@@ -294,7 +217,7 @@ public class PumpStation3DControl : Control
         DrawText(context, profile.Description, hudP.Position + new Point(12 * scale, 28 * scale), 10 * scale, ThemeHelper.TextTertiary, FontWeight.Bold);
 
         // 报警边框
-        if (GetDigitalValue("Alarm.Active") || HasAlarm)
+        if (GetDigitalValue("Alarm.Active"))
             context.DrawRectangle(null, new Pen(ThemeHelper.Danger, 2), scene, 4);
     }
 
@@ -405,49 +328,12 @@ public class PumpStation3DControl : Control
         DrawText(context, device.DeviceId, c + new Point(-10 * scale, s + 3 * scale), 10 * scale, ThemeHelper.TextSecondary, FontWeight.Bold);
     }
 
-    // ════════════════════════════════════════════════════════
-    //  兼容模式(旧版硬编码)
-    // ════════════════════════════════════════════════════════
-
-    private void RenderLegacy(DrawingContext context, Rect bounds)
-    {
-        var scene = new Rect(bounds.X + 22, bounds.Y + 16, Math.Max(0, bounds.Width - 44), Math.Max(0, bounds.Height - 32));
-        var scale = Math.Min(scene.Width / 960.0, scene.Height / 540.0);
-        var origin = new Point(scene.Center.X - 132 * scale, scene.Y + scene.Height * 0.10);
-
-        DrawFloor(context, origin, scale);
-
-        DrawChannel(context, origin, scale, new Point(40, 188), "进水渠道", Tank1Level);
-        DrawWetWell(context, origin, scale, new Point(255, 145), Tank2Level);
-        DrawValveChamber(context, origin, scale, new Point(520, 172), Tank4Level);
-        DrawCabinet(context, origin, scale, new Point(430, 64));
-
-        DrawPipe(context, origin, scale, new Point(32, 244), new Point(258, 244), IsInflowRunning, 20);
-        DrawPipe(context, origin, scale, new Point(300, 132), new Point(620, 132), IsOutflowRunning || AnyPumpRunning, 122);
-        DrawPipe(context, origin, scale, new Point(620, 132), new Point(720, 132), IsOutflowRunning, 122);
-
-        DrawRiser(context, origin, scale, new Point(322, 228), "P1", Pump1Running);
-        DrawRiser(context, origin, scale, new Point(382, 228), "P2", Pump2Running);
-        DrawRiser(context, origin, scale, new Point(442, 228), "P3", Pump3Running);
-        DrawRiser(context, origin, scale, new Point(352, 292), "P4", Pump4Running);
-        DrawRiser(context, origin, scale, new Point(412, 292), "P5", Pump5Running);
-
-        DrawValve(context, origin, scale, new Point(550, 132), "V1", Valve2Status);
-        DrawValve(context, origin, scale, new Point(610, 132), "V2", Valve3Status);
-        DrawValve(context, origin, scale, new Point(670, 132), "V3", Valve4Status);
-        DrawFlowMeter(context, origin, scale, new Point(116, 218), "进水", InflowRate, IsInflowRunning);
-        DrawFlowMeter(context, origin, scale, new Point(748, 112), "出水", OutflowRate, IsOutflowRunning);
-        DrawFan(context, origin, scale, new Point(490, 300), "F1", Fan1Running);
-        DrawFan(context, origin, scale, new Point(550, 300), "F2", Fan2Running);
-        DrawHud(context, scene, scale);
-    }
-
     // ═══ 点击事件 ═══
 
     protected override void OnPointerPressed(PointerPressedEventArgs e)
     {
         base.OnPointerPressed(e);
-        if (!IsDynamicMode || _cachedLayout == null) return;
+        if (_cachedLayout == null) return;
 
         var pos = e.GetPosition(this);
         // 反向映射到设计坐标
@@ -472,7 +358,7 @@ public class PumpStation3DControl : Control
         }
     }
 
-    // ═══ 等轴测投影 & 绘制辅助(保留原有逻辑)═══
+    // ═══ 等轴测投影 & 绘制辅助 ═══
 
     private Point Iso(Point p, double z, Point origin, double scale) =>
         new(origin.X + (p.X - p.Y) * 0.78 * scale, origin.Y + (p.X + p.Y) * 0.38 * scale - z * scale);
@@ -489,75 +375,6 @@ public class PumpStation3DControl : Control
             context.DrawLine(gridPen, Iso(new Point(0, y), 0, origin, scale), Iso(new Point(875, y), 0, origin, scale));
     }
 
-    private void DrawChannel(DrawingContext context, Point origin, double scale, Point p, string name, double level)
-    {
-        DrawBox(context, origin, scale, p, 180, 112, 44, StructureColor, ThemeHelper.Border);
-        DrawBox(context, origin, scale, new Point(p.X + 10, p.Y + 10), 160, 92, Math.Max(8, 34 * Math.Clamp(level, 0, 100) / 100), GetColor(ThemeHelper.Success), null, 0.66);
-        var gridPen = new Pen(ThemeHelper.TextTertiary, Math.Max(1, scale));
-        for (var x = p.X + 128; x < p.X + 168; x += 8)
-            context.DrawLine(gridPen, Iso(new Point(x, p.Y + 20), 46, origin, scale), Iso(new Point(x, p.Y + 92), 46, origin, scale));
-        DrawText(context, name, Iso(new Point(p.X + 25, p.Y + 14), 62, origin, scale), 12 * scale, ThemeHelper.TextPrimary, FontWeight.Bold);
-        DrawText(context, "粗格栅", Iso(new Point(p.X + 146, p.Y + 64), 57, origin, scale), 10 * scale, ThemeHelper.TextSecondary, FontWeight.Bold);
-    }
-
-    private void DrawWetWell(DrawingContext context, Point origin, double scale, Point p, double level)
-    {
-        const double width = 255, depth = 214, wallHeight = 82;
-        DrawCutawayWellWalls(context, origin, scale, p, width, depth, wallHeight);
-        var waterHeight = 14 + 74 * Math.Clamp(level, 0, 100) / 100;
-        var water = new[]
-        {
-            Iso(new Point(p.X + 16, p.Y + 16), waterHeight, origin, scale),
-            Iso(new Point(p.X + width - 16, p.Y + 16), waterHeight, origin, scale),
-            Iso(new Point(p.X + width - 16, p.Y + depth - 16), waterHeight, origin, scale),
-            Iso(new Point(p.X + 16, p.Y + depth - 16), waterHeight, origin, scale)
-        };
-        context.DrawGeometry(new SolidColorBrush(GetColor(ThemeHelper.Info), 0.60), new Pen(ThemeHelper.Info, Math.Max(1, scale)), Polygon(water));
-        var title = Iso(new Point(p.X + 70, p.Y + 14), wallHeight + 26, origin, scale);
-        DrawText(context, "集水湿井", title, 14 * scale, ThemeHelper.TextPrimary, FontWeight.Bold);
-        DrawText(context, $"液位 {level:F1}%", title + new Point(0, 15 * scale), 10 * scale, ThemeHelper.Info, FontWeight.Bold);
-        DrawText(context, "潜水泵组 (3 用 2 备)", Iso(new Point(p.X + 55, p.Y + depth - 18), waterHeight + 6, origin, scale), 10 * scale, ThemeHelper.TextSecondary, FontWeight.Bold);
-    }
-
-    private void DrawCutawayWellWalls(DrawingContext context, Point origin, double scale, Point p, double width, double depth, double height)
-    {
-        var wallBrush = new SolidColorBrush(StructureColor, 0.96);
-        var rearWall = new[] { Iso(p, 0, origin, scale), Iso(new Point(p.X + width, p.Y), 0, origin, scale), Iso(new Point(p.X + width, p.Y), height, origin, scale), Iso(p, height, origin, scale) };
-        var sideWall = new[] { Iso(new Point(p.X + width, p.Y), 0, origin, scale), Iso(new Point(p.X + width, p.Y + depth), 0, origin, scale), Iso(new Point(p.X + width, p.Y + depth), height, origin, scale), Iso(new Point(p.X + width, p.Y), height, origin, scale) };
-        context.DrawGeometry(wallBrush, new Pen(ThemeHelper.Border, Math.Max(1, scale)), Polygon(rearWall));
-        context.DrawGeometry(new SolidColorBrush(Darken(StructureColor, 0.82), 0.98), new Pen(ThemeHelper.Border, Math.Max(1, scale)), Polygon(sideWall));
-        var rimPen = new Pen(ThemeHelper.TextSecondary, Math.Max(1.2, 1.5 * scale));
-        context.DrawLine(rimPen, Iso(p, height, origin, scale), Iso(new Point(p.X + width, p.Y), height, origin, scale));
-        context.DrawLine(rimPen, Iso(new Point(p.X + width, p.Y), height, origin, scale), Iso(new Point(p.X + width, p.Y + depth), height, origin, scale));
-    }
-
-    private void DrawValveChamber(DrawingContext context, Point origin, double scale, Point p, double level)
-    {
-        DrawBox(context, origin, scale, p, 168, 145, 58, StructureColor, ThemeHelper.Border);
-        DrawBox(context, origin, scale, new Point(p.X + 12, p.Y + 12), 144, 121, Math.Max(6, 22 * Math.Clamp(level, 0, 100) / 100), GetColor(ThemeHelper.Success), null, 0.48);
-        DrawText(context, "阀门井", Iso(new Point(p.X + 55, p.Y + 12), 76, origin, scale), 12 * scale, ThemeHelper.TextPrimary, FontWeight.Bold);
-        DrawText(context, "止回阀 / 闸阀", Iso(new Point(p.X + 35, p.Y + 124), 67, origin, scale), 10 * scale, ThemeHelper.TextSecondary, FontWeight.Bold);
-    }
-
-    private void DrawCabinet(DrawingContext context, Point origin, double scale, Point p)
-    {
-        DrawBox(context, origin, scale, p, 150, 82, 84, StructureColor, ThemeHelper.Border);
-        DrawText(context, "电控柜 / 变频柜", Iso(new Point(p.X + 20, p.Y + 22), 102, origin, scale), 11 * scale, ThemeHelper.TextPrimary, FontWeight.Bold);
-        DrawText(context, "干区", Iso(new Point(p.X + 48, p.Y + 70), 95, origin, scale), 10 * scale, ThemeHelper.TextSecondary, FontWeight.Bold);
-    }
-
-    private void DrawRiser(DrawingContext context, Point origin, double scale, Point p, string label, bool running)
-    {
-        var basePoint = Iso(p, 20, origin, scale);
-        var topPoint = Iso(p, 122, origin, scale);
-        var status = running ? ThemeHelper.Success : ThemeHelper.TextDisabled;
-        context.DrawLine(new Pen(new SolidColorBrush(Darken(StructureColor, 0.70)), 12 * scale), basePoint, topPoint);
-        context.DrawLine(new Pen(status, 4 * scale), basePoint, topPoint);
-        var headerTap = new Point(p.X, 132);
-        DrawPipe(context, origin, scale, p, headerTap, running, 122);
-        DrawPump(context, origin, scale, p, label, running);
-    }
-
     private void DrawBox(DrawingContext context, Point origin, double scale, Point p, double w, double d, double h, Color color, IBrush? stroke, double opacity = 1)
     {
         var top = new[] { Iso(p, h, origin, scale), Iso(new Point(p.X + w, p.Y), h, origin, scale), Iso(new Point(p.X + w, p.Y + d), h, origin, scale), Iso(new Point(p.X, p.Y + d), h, origin, scale) };
@@ -582,72 +399,8 @@ public class PumpStation3DControl : Control
         {
             var t = ((_phase / 120.0) + i / 9.0) % 1.0;
             var pt = new Point(a.X + (b.X - a.X) * t, a.Y + (b.Y - a.Y) * t);
-            context.DrawEllipse(FlowDotBrush3D, null, new Rect(pt.X - 4 * scale, pt.Y - 4 * scale, 8 * scale, 8 * scale));
-        }
-    }
-
-    private void DrawPump(DrawingContext context, Point origin, double scale, Point p, string label, bool running)
-    {
-        var c = Iso(p, 30, origin, scale);
-        var status = running ? GetColor(ThemeHelper.Success) : GetColor(ThemeHelper.TextDisabled);
-        var radius = 15 * scale;
-        var body = new Rect(c.X - radius, c.Y - radius * 1.4, radius * 2, radius * 2.25);
-        context.DrawRectangle(new SolidColorBrush(Darken(StructureColor, 0.78)), new Pen(new SolidColorBrush(status), Math.Max(1, 1.4 * scale)), body, radius * 0.42);
-        context.DrawEllipse(new SolidColorBrush(Lighten(StructureColor, 0.12)), new Pen(new SolidColorBrush(status), Math.Max(1, scale)), new Rect(c.X - radius, c.Y - radius * 1.7, radius * 2, radius * 0.78));
-        context.DrawEllipse(new SolidColorBrush(status), null, new Rect(c.X - 3 * scale, c.Y - radius * 0.55, 6 * scale, 6 * scale));
-        DrawText(context, label, c + new Point(-9 * scale, radius * 1.3), 10 * scale, ThemeHelper.TextPrimary, FontWeight.Bold);
-    }
-
-    private void DrawFan(DrawingContext context, Point origin, double scale, Point p, string label, bool running)
-    {
-        var c = Iso(p, 34, origin, scale);
-        var r = 24 * scale;
-        var status = running ? GetColor(ThemeHelper.Info) : GetColor(ThemeHelper.TextDisabled);
-        context.DrawEllipse(PumpBodyBrush, new Pen(new SolidColorBrush(status), 1.5 * scale), new Rect(c.X - r, c.Y - r, r * 2, r * 2));
-        for (var i = 0; i < 5; i++)
-        {
-            var a = (_phase * 7 + i * 72) * Math.PI / 180.0;
-            context.DrawLine(new Pen(new SolidColorBrush(status, running ? 0.9 : 0.45), 5 * scale), c, new Point(c.X + Math.Cos(a) * r * 0.7, c.Y + Math.Sin(a) * r * 0.7));
+            context.DrawEllipse(new SolidColorBrush(Color.FromRgb(3, 169, 244)), null, new Rect(pt.X - 4 * scale, pt.Y - 4 * scale, 8 * scale, 8 * scale));
         }
-        context.DrawEllipse(new SolidColorBrush(status), null, new Rect(c.X - 5 * scale, c.Y - 5 * scale, 10 * scale, 10 * scale));
-        DrawText(context, label, c + new Point(-10 * scale, r + 5 * scale), 11 * scale, ThemeHelper.TextPrimary, FontWeight.Bold);
-    }
-
-    private void DrawValve(DrawingContext context, Point origin, double scale, Point p, string label, ValveStatus status)
-    {
-        var c = Iso(p, 42, origin, scale);
-        var color = status switch
-        {
-            ValveStatus.Open => GetColor(ThemeHelper.Success),
-            ValveStatus.Closed => GetColor(ThemeHelper.Warning),
-            _ => GetColor(ThemeHelper.TextDisabled)
-        };
-        var s = 18 * scale;
-        var points = new[] { c + new Point(0, -s), c + new Point(s, 0), c + new Point(0, s), c + new Point(-s, 0) };
-        context.DrawGeometry(new SolidColorBrush(color, 0.85), new Pen(ThemeHelper.Border, 1), Polygon(points));
-        context.DrawLine(new Pen(ThemeHelper.TextPrimary, 2 * scale), c + new Point(-s * 0.55, 0), c + new Point(s * 0.55, 0));
-        DrawText(context, label, c + new Point(-10 * scale, s + 3 * scale), 10 * scale, ThemeHelper.TextSecondary, FontWeight.Bold);
-    }
-
-    private void DrawFlowMeter(DrawingContext context, Point origin, double scale, Point p, string label, double value, bool active)
-    {
-        var c = Iso(p, 52, origin, scale);
-        var color = active ? GetColor(ThemeHelper.Success) : GetColor(ThemeHelper.TextDisabled);
-        var rect = new Rect(c.X - 34 * scale, c.Y - 18 * scale, 68 * scale, 36 * scale);
-        context.DrawRectangle(new SolidColorBrush(GetColor(ThemeHelper.SurfaceBg), 0.95), new Pen(new SolidColorBrush(color), 1.2 * scale), rect, 4 * scale);
-        DrawText(context, label, rect.Position + new Point(8 * scale, 3 * scale), 10 * scale, ThemeHelper.TextTertiary, FontWeight.Bold);
-        DrawText(context, $"{value:F1}", rect.Position + new Point(28 * scale, 16 * scale), 12 * scale, new SolidColorBrush(color), FontWeight.Bold);
-    }
-
-    private void DrawHud(DrawingContext context, Rect scene, double scale)
-    {
-        var panel = new Rect(scene.X + 10, scene.Y + 10, 218 * scale, 78 * scale);
-        context.DrawRectangle(new SolidColorBrush(GetColor(ThemeHelper.SurfaceBg), 0.9), new Pen(ThemeHelper.Border, 1), panel, 4 * scale);
-        DrawText(context, "通用泵站 3D 总览", panel.Position + new Point(12 * scale, 8 * scale), 13 * scale, ThemeHelper.TextPrimary, FontWeight.Bold);
-        DrawText(context, "进水渠 -> 集水井 -> 泵组 -> 出水总管", panel.Position + new Point(12 * scale, 30 * scale), 10 * scale, ThemeHelper.TextTertiary, FontWeight.Bold);
-        DrawText(context, $"RUN {RunningDeviceCount}  EFF {Efficiency:F0}%  ALM {AlarmCount}", panel.Position + new Point(12 * scale, 50 * scale), 11 * scale, HasAlarm ? ThemeHelper.Danger : ThemeHelper.Success, FontWeight.Bold);
-        if (HasAlarm)
-            context.DrawRectangle(null, new Pen(ThemeHelper.Danger, 2), scene, 4);
     }
 
     // ═══ 通用辅助 ═══

+ 2 - 14
src/YZWater.Avalonia/Views/ViewAView.axaml

@@ -68,24 +68,12 @@
                                     IsVisible="{Binding Is2DView}"
                                     Profile="{Binding Profile}"
                                     AnalogValues="{Binding AnalogValues}"
-                                    DigitalValues="{Binding DigitalValues}"
-                                    IsInflowRunning="{Binding IsInflowRunning}"
-                                    IsOutflowRunning="{Binding IsOutflowRunning}"
-                                    HasAlarm="{Binding HasAlarm}"
-                                    AlarmCount="{Binding AlarmCount}"
-                                    RunningDeviceCount="{Binding RunningDeviceCount}"
-                                    Efficiency="{Binding Efficiency}"/>
+                                    DigitalValues="{Binding DigitalValues}"/>
                                 <controls:PumpStation3DControl
                                     IsVisible="{Binding Is3DView}"
                                     Profile="{Binding Profile}"
                                     AnalogValues="{Binding AnalogValues}"
-                                    DigitalValues="{Binding DigitalValues}"
-                                    IsInflowRunning="{Binding IsInflowRunning}"
-                                    IsOutflowRunning="{Binding IsOutflowRunning}"
-                                    HasAlarm="{Binding HasAlarm}"
-                                    AlarmCount="{Binding AlarmCount}"
-                                    RunningDeviceCount="{Binding RunningDeviceCount}"
-                                    Efficiency="{Binding Efficiency}"/>
+                                    DigitalValues="{Binding DigitalValues}"/>
                             </Grid>
                         </Border>