Ver código fonte

feat: 多项目页面模板系统(P6)

- ProjectProfile 新增 PageLayoutConfig(rightColumnWidth + hiddenSections)
- ProjectViewModel 暴露布局属性(RightColumnWidth/HasRightPanel/各区块 IsHidden)
- ProjectView.axaml 各区块绑定 IsVisible 到配置
- ProjectView.axaml.cs 动态调整 Grid 列宽(ApplyLayout)
- yangjie2.json 增加默认 layout 配置示范
- 新项目可通过 JSON 配置隐藏特定区块或调整右栏宽度
DESKTOP-74CLTRG\Leol 1 mês atrás
pai
commit
86638fd69d

+ 4 - 0
projects/yangjie2.json

@@ -8,6 +8,10 @@
     "allowManualControl": true,
     "allowParameterSync": true
   },
+  "layout": {
+    "rightColumnWidth": 300,
+    "hiddenSections": []
+  },
   "modeSelectAddress": "M1.0",
   "pumps": [
     {

+ 10 - 7
src/YZWater.Avalonia/Views/ProjectView.axaml

@@ -68,7 +68,7 @@
             </Border>
 
             <!-- ═══ 主内容区:左侧 2D 图 + 泵控制条 | 右侧数据栏 ═══ -->
-            <Grid Grid.Row="1" ColumnDefinitions="*,300" Margin="14,12">
+            <Grid x:Name="MainGrid" Grid.Row="1" ColumnDefinitions="*,300" Margin="14,12">
 
                 <!-- 左列:2D 工艺图(占满)+ 底部泵控制条(一屏无滚动) -->
                 <Grid Grid.Column="0" RowDefinitions="*,Auto" Margin="0,0,10,0">
@@ -382,10 +382,11 @@
                 </Grid>
 
                 <!-- 右侧数据栏:液位阈值 → 仪表 → 累计 → 故障 -->
-                <Grid Grid.Column="1" RowDefinitions="Auto,Auto,Auto,*">
+                <Grid x:Name="RightPanel" Grid.Column="1" RowDefinitions="Auto,Auto,Auto,*">
 
                     <!-- 液位阈值(紧凑列表,大水箱图取消——2D 图已含水池可视化) -->
-                    <Border Grid.Row="0" Classes="surface-card" Background="{DynamicResource SurfaceBgBrush}" Padding="14,12" Margin="0,0,0,8">
+                    <Border Grid.Row="0" Classes="surface-card" Background="{DynamicResource SurfaceBgBrush}" Padding="14,12" Margin="0,0,0,8"
+                            IsVisible="{Binding !IsTanksSectionHidden}">
                         <StackPanel>
                             <StackPanel Orientation="Horizontal" Spacing="6" Margin="0,0,0,8">
                                 <Border Background="{DynamicResource InfoBrush}" Width="3" Height="14" CornerRadius="1"/>
@@ -462,7 +463,8 @@
                     </Border>
 
                     <!-- 仪表 -->
-                    <Border Grid.Row="1" Classes="surface-card" Background="{DynamicResource SurfaceBgBrush}" Padding="14,12" Margin="0,0,0,8">
+                    <Border Grid.Row="1" Classes="surface-card" Background="{DynamicResource SurfaceBgBrush}" Padding="14,12" Margin="0,0,0,8"
+                            IsVisible="{Binding !IsGaugesSectionHidden}">
                         <StackPanel>
                             <StackPanel Orientation="Horizontal" Spacing="6" Margin="0,0,0,8">
                                 <Border Background="{DynamicResource WarningBrush}" Width="3" Height="14" CornerRadius="1"/>
@@ -516,7 +518,8 @@
                     </Border>
 
                     <!-- 累计数据 -->
-                    <Border Grid.Row="2" Classes="surface-card" Background="{DynamicResource SurfaceBgBrush}" Padding="14,12" Margin="0,0,0,8">
+                    <Border Grid.Row="2" Classes="surface-card" Background="{DynamicResource SurfaceBgBrush}" Padding="14,12" Margin="0,0,0,8"
+                            IsVisible="{Binding !IsSensorsSectionHidden}">
                         <StackPanel>
                             <StackPanel Orientation="Horizontal" Spacing="6" Margin="0,0,0,8">
                                 <Border Background="{DynamicResource InfoBrush}" Width="3" Height="14" CornerRadius="1"/>
@@ -537,9 +540,9 @@
                         </StackPanel>
                     </Border>
 
-                    <!-- 故障状态(无内容时隐藏:无泵/无数字量/无报警) -->
+                    <!-- 故障状态(无内容时隐藏:无泵/无数字量/无报警,或被配置隐藏) -->
                     <Border Grid.Row="3" Classes="surface-card" Background="{DynamicResource SurfaceBgBrush}" Padding="14,12"
-                            IsVisible="{Binding HasFaultContent}">
+                            IsVisible="{Binding ShowFaultSection}">
                         <ScrollViewer>
                             <StackPanel>
                                 <StackPanel Orientation="Horizontal" Spacing="6" Margin="0,0,0,8">

+ 35 - 0
src/YZWater.Avalonia/Views/ProjectView.axaml.cs

@@ -1,3 +1,5 @@
+using System.ComponentModel;
+using Avalonia.Controls;
 using YZWater.Avalonia.Controls;
 
 namespace YZWater.Avalonia.Views;
@@ -7,5 +9,38 @@ public partial class ProjectView : ThemedUserControl
     public ProjectView()
     {
         InitializeComponent();
+        DataContextChanged += OnDataContextChanged;
+    }
+
+    private void OnDataContextChanged(object? sender, System.EventArgs e)
+    {
+        if (DataContext is INotifyPropertyChanged vm)
+            vm.PropertyChanged += OnViewModelPropertyChanged;
+        ApplyLayout();
+    }
+
+    private void OnViewModelPropertyChanged(object? sender, PropertyChangedEventArgs e)
+    {
+        if (e.PropertyName is nameof(Core.ViewModels.ProjectViewModel.RightColumnWidth)
+                                or nameof(Core.ViewModels.ProjectViewModel.HasRightPanel))
+            ApplyLayout();
+    }
+
+    /// <summary>根据 ViewModel 的布局属性动态调整主 Grid 列宽</summary>
+    private void ApplyLayout()
+    {
+        if (DataContext is not Core.ViewModels.ProjectViewModel vm) return;
+
+        // 动态设置主 Grid 的右列宽度
+        if (vm.HasRightPanel && MainGrid.ColumnDefinitions.Count > 1)
+        {
+            MainGrid.ColumnDefinitions[1].Width = new GridLength(vm.RightColumnWidth);
+            RightPanel.IsVisible = true;
+        }
+        else
+        {
+            MainGrid.ColumnDefinitions[1].Width = new GridLength(0);
+            RightPanel.IsVisible = false;
+        }
     }
 }

+ 18 - 0
src/YZWater.Core/Models/ProjectProfile.cs

@@ -47,6 +47,24 @@ public class ProjectProfile
 
     /// <summary>控制策略配置 — 决定上位机是否参与自动控制</summary>
     public ControlConfig Control { get; set; } = new();
+
+    /// <summary>页面布局配置 — 决定 ProjectView 的 UI 区域显隐和尺寸</summary>
+    public PageLayoutConfig Layout { get; set; } = new();
+}
+
+/// <summary>
+/// 页面布局配置 — 控制 ProjectView 各区域显隐和尺寸
+/// 缺失字段使用默认值,旧 JSON 无需改动即可兼容
+/// </summary>
+public class PageLayoutConfig
+{
+    /// <summary>右侧数据面板宽度(像素),0 = 隐藏整个右列。默认 300</summary>
+    public int RightColumnWidth { get; set; } = 300;
+
+    /// <summary>隐藏的区块名称列表。
+    /// 可选值:"Tanks"(液位监控), "Gauges"(仪表), "Sensors"(累计), "Faults"(故障状态)
+    /// 被隐藏的区块即使有数据也不显示</summary>
+    public List<string> HiddenSections { get; set; } = new();
 }
 
 /// <summary>

+ 30 - 0
src/YZWater.Core/ViewModels/ProjectViewModel.cs

@@ -63,6 +63,33 @@ public partial class ProjectViewModel : ObservableObject, IDisposable
     /// <summary>项目档案(供动态布局引擎使用)</summary>
     public ProjectProfile Profile => _profile;
 
+    // ─── 页面布局属性(供 AXAML 绑定)───
+
+    /// <summary>右侧数据面板宽度(像素),0 = 隐藏</summary>
+    public int RightColumnWidth => _profile.Layout.RightColumnWidth;
+
+    /// <summary>右侧面板是否可见(宽度 > 0 且未配置全宽布局)</summary>
+    public bool HasRightPanel => RightColumnWidth > 0;
+
+    /// <summary>指定区块是否被项目配置隐藏</summary>
+    public bool IsSectionHidden(string sectionName) =>
+        _profile.Layout.HiddenSections.Contains(sectionName, StringComparer.OrdinalIgnoreCase);
+
+    /// <summary>液位监控区块是否隐藏</summary>
+    public bool IsTanksSectionHidden => IsSectionHidden("Tanks");
+
+    /// <summary>仪表区块是否隐藏</summary>
+    public bool IsGaugesSectionHidden => IsSectionHidden("Gauges");
+
+    /// <summary>累计(传感器)区块是否隐藏</summary>
+    public bool IsSensorsSectionHidden => IsSectionHidden("Sensors");
+
+    /// <summary>故障状态区块是否隐藏</summary>
+    public bool IsFaultsSectionHidden => IsSectionHidden("Faults");
+
+    /// <summary>故障区块是否应显示(有内容 且 未被配置隐藏)</summary>
+    public bool ShowFaultSection => HasFaultContent && !IsFaultsSectionHidden;
+
     /// <summary>模拟量字典 — 键为 "设备名.属性",如 "集水池.Level"</summary>
     [ObservableProperty] private Dictionary<string, float> _analogValues = new();
     private HashSet<string> _analogKeys = new();
@@ -92,6 +119,7 @@ public partial class ProjectViewModel : ObservableObject, IDisposable
         {
             RecentAlarms.Clear();
             OnPropertyChanged(nameof(HasFaultContent));
+            OnPropertyChanged(nameof(ShowFaultSection));
         });
     }
 
@@ -202,6 +230,7 @@ public partial class ProjectViewModel : ObservableObject, IDisposable
             while (RecentAlarms.Count > 6)
                 RecentAlarms.RemoveAt(RecentAlarms.Count - 1);
             OnPropertyChanged(nameof(HasFaultContent));
+            OnPropertyChanged(nameof(ShowFaultSection));
         });
     }
 
@@ -221,6 +250,7 @@ public partial class ProjectViewModel : ObservableObject, IDisposable
         HasActiveAlarm = AlarmService.Instance.HasActiveAlarm;
         ActiveAlarmCount = AlarmService.Instance.ActiveAlarmCount;
         OnPropertyChanged(nameof(HasFaultContent));
+        OnPropertyChanged(nameof(ShowFaultSection));
     }
 
     /// <summary>SuggestedPumpName 变化时联动刷新 HasSuggestedPump</summary>