feat(chart): 实现Ploss和Qfod图表真实数据加载
This commit is contained in:
@@ -1,8 +1,11 @@
|
|||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
using LiveChartsCore;
|
using LiveChartsCore;
|
||||||
using LiveChartsCore.SkiaSharpView;
|
using LiveChartsCore.SkiaSharpView;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using WCTDataMiner.Core.Services;
|
using WCTDataMiner.Core.Services;
|
||||||
|
using WCTDataMiner.Wpf.Messages;
|
||||||
|
|
||||||
namespace WCTDataMiner.Wpf.ViewModels;
|
namespace WCTDataMiner.Wpf.ViewModels;
|
||||||
|
|
||||||
@@ -26,6 +29,12 @@ public partial class PlossChartViewModel : ObservableObject
|
|||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private Axis[] _yAxes;
|
private Axis[] _yAxes;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool _isLoading;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _loadingMessage = "";
|
||||||
|
|
||||||
public PlossChartViewModel(
|
public PlossChartViewModel(
|
||||||
ScenarioService scenarioService,
|
ScenarioService scenarioService,
|
||||||
ILogger<PlossChartViewModel> logger)
|
ILogger<PlossChartViewModel> logger)
|
||||||
@@ -39,28 +48,93 @@ public partial class PlossChartViewModel : ObservableObject
|
|||||||
YAxes = new Axis[] { new Axis { Name = "Power Loss (mW)" } };
|
YAxes = new Axis[] { new Axis { Name = "Power Loss (mW)" } };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ScenarioId 属性变更时自动触发数据加载
|
||||||
|
/// </summary>
|
||||||
|
partial void OnScenarioIdChanged(Guid value)
|
||||||
|
{
|
||||||
|
if (value != Guid.Empty)
|
||||||
|
{
|
||||||
|
_ = LoadDataAsync().ContinueWith(t =>
|
||||||
|
{
|
||||||
|
if (t.Exception != null)
|
||||||
|
{
|
||||||
|
_logger.LogError(t.Exception, "LoadDataAsync 失败: ScenarioId={ScenarioId}", value);
|
||||||
|
}
|
||||||
|
}, TaskContinuationOptions.OnlyOnFaulted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void SwitchToTable()
|
||||||
|
{
|
||||||
|
WeakReferenceMessenger.Default.Send(new NavigateToPlossTableMessage(ScenarioId));
|
||||||
|
}
|
||||||
|
|
||||||
public async Task LoadDataAsync()
|
public async Task LoadDataAsync()
|
||||||
{
|
{
|
||||||
|
if (IsLoading) return; // 防并发
|
||||||
|
|
||||||
|
IsLoading = true;
|
||||||
|
LoadingMessage = "正在加载数据...";
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// TODO: 从数据库加载 Ploss 数据并构建图表
|
var records = await _scenarioService.GetPlossRecordsByScenarioIdAsync(ScenarioId);
|
||||||
|
|
||||||
|
if (records.Count == 0)
|
||||||
|
{
|
||||||
|
Series = Array.Empty<ISeries>();
|
||||||
|
_logger.LogWarning("未找到 Ploss 数据: ScenarioId={ScenarioId}", ScenarioId);
|
||||||
|
LoadingMessage = "无数据";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建 Ploss 曲线 (Field7) 和 Threshold 阈值线 (Field8)
|
||||||
|
var plossValues = records.Select(r => (double)r.Field7).ToArray();
|
||||||
|
var thresholdValues = records.Select(r => (double)r.Field8).ToArray();
|
||||||
|
var triggerLabels = records.Select(r => r.Field9.ToString()).ToArray();
|
||||||
|
|
||||||
Series = new ISeries[]
|
Series = new ISeries[]
|
||||||
{
|
{
|
||||||
new LineSeries<double>
|
new LineSeries<double>
|
||||||
{
|
{
|
||||||
Name = "Ploss",
|
Name = "Ploss",
|
||||||
Values = new double[] { -2882, -3500, -4200, -3800, -4500 }
|
Values = plossValues,
|
||||||
|
Fill = null,
|
||||||
|
GeometrySize = 5
|
||||||
},
|
},
|
||||||
new LineSeries<double>
|
new LineSeries<double>
|
||||||
{
|
{
|
||||||
Name = "Threshold",
|
Name = "Threshold",
|
||||||
Values = new double[] { -3000, -3000, -3000, -3000, -3000 }
|
Values = thresholdValues,
|
||||||
|
Fill = null,
|
||||||
|
GeometrySize = 0,
|
||||||
|
LineSmoothness = 0 // 直线
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 更新 X 轴标签
|
||||||
|
XAxes = new Axis[]
|
||||||
|
{
|
||||||
|
new Axis
|
||||||
|
{
|
||||||
|
Name = "Trigger Count",
|
||||||
|
Labels = triggerLabels
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_logger.LogInformation("加载 Ploss 图表数据成功: ScenarioId={ScenarioId}, 记录数={Count}", ScenarioId, records.Count);
|
||||||
|
LoadingMessage = "";
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "加载 Ploss 图表数据失败: ScenarioId={ScenarioId}", ScenarioId);
|
_logger.LogError(ex, "加载 Ploss 图表数据失败: ScenarioId={ScenarioId}", ScenarioId);
|
||||||
|
LoadingMessage = $"加载失败: {ex.Message}";
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IsLoading = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,11 @@
|
|||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
using LiveChartsCore;
|
using LiveChartsCore;
|
||||||
using LiveChartsCore.SkiaSharpView;
|
using LiveChartsCore.SkiaSharpView;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using WCTDataMiner.Core.Services;
|
using WCTDataMiner.Core.Services;
|
||||||
|
using WCTDataMiner.Wpf.Messages;
|
||||||
|
|
||||||
namespace WCTDataMiner.Wpf.ViewModels;
|
namespace WCTDataMiner.Wpf.ViewModels;
|
||||||
|
|
||||||
@@ -26,6 +29,12 @@ public partial class QfodChartViewModel : ObservableObject
|
|||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private Axis[] _yAxes;
|
private Axis[] _yAxes;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool _isLoading;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _loadingMessage = "";
|
||||||
|
|
||||||
public QfodChartViewModel(
|
public QfodChartViewModel(
|
||||||
ScenarioService scenarioService,
|
ScenarioService scenarioService,
|
||||||
ILogger<QfodChartViewModel> logger)
|
ILogger<QfodChartViewModel> logger)
|
||||||
@@ -39,28 +48,97 @@ public partial class QfodChartViewModel : ObservableObject
|
|||||||
YAxes = new Axis[] { new Axis { Name = "Q Value" } };
|
YAxes = new Axis[] { new Axis { Name = "Q Value" } };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ScenarioId 属性变更时自动触发数据加载
|
||||||
|
/// </summary>
|
||||||
|
partial void OnScenarioIdChanged(Guid value)
|
||||||
|
{
|
||||||
|
if (value != Guid.Empty)
|
||||||
|
{
|
||||||
|
_ = LoadDataAsync().ContinueWith(t =>
|
||||||
|
{
|
||||||
|
if (t.Exception != null)
|
||||||
|
{
|
||||||
|
_logger.LogError(t.Exception, "LoadDataAsync 失败: ScenarioId={ScenarioId}", value);
|
||||||
|
}
|
||||||
|
}, TaskContinuationOptions.OnlyOnFaulted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void SwitchToTable()
|
||||||
|
{
|
||||||
|
WeakReferenceMessenger.Default.Send(new NavigateToQfodTableMessage(ScenarioId));
|
||||||
|
}
|
||||||
|
|
||||||
public async Task LoadDataAsync()
|
public async Task LoadDataAsync()
|
||||||
{
|
{
|
||||||
|
if (IsLoading) return; // 防并发
|
||||||
|
|
||||||
|
IsLoading = true;
|
||||||
|
LoadingMessage = "正在加载数据...";
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// TODO: 从数据库加载 Qfod 数据并构建图表
|
var records = await _scenarioService.GetQfodRecordsByScenarioIdAsync(ScenarioId);
|
||||||
|
|
||||||
|
if (records.Count == 0)
|
||||||
|
{
|
||||||
|
Series = Array.Empty<ISeries>();
|
||||||
|
_logger.LogWarning("未找到 Qfod 数据: ScenarioId={ScenarioId}", ScenarioId);
|
||||||
|
LoadingMessage = "无数据";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建 DeltaQ、CurrentQ、RawQ 三条曲线
|
||||||
|
var deltaQValues = records.Select(r => (double)r.DeltaQ).ToArray();
|
||||||
|
var currentQValues = records.Select(r => (double)r.CurrentQ).ToArray();
|
||||||
|
var rawQValues = records.Select(r => (double)r.RawQ).ToArray();
|
||||||
|
var coilLabels = records.Select(r => $"{r.ChargerIndex}-{r.CoilIndex}").ToArray();
|
||||||
|
|
||||||
Series = new ISeries[]
|
Series = new ISeries[]
|
||||||
{
|
{
|
||||||
new LineSeries<double>
|
new LineSeries<double>
|
||||||
{
|
{
|
||||||
Name = "DeltaQ",
|
Name = "DeltaQ",
|
||||||
Values = new double[] { 25, 30, 28 }
|
Values = deltaQValues,
|
||||||
|
GeometrySize = 5
|
||||||
},
|
},
|
||||||
new LineSeries<double>
|
new LineSeries<double>
|
||||||
{
|
{
|
||||||
Name = "CurrentQ",
|
Name = "CurrentQ",
|
||||||
Values = new double[] { 45.5, 50.2, 48.8 }
|
Values = currentQValues,
|
||||||
|
GeometrySize = 5
|
||||||
|
},
|
||||||
|
new LineSeries<double>
|
||||||
|
{
|
||||||
|
Name = "RawQ",
|
||||||
|
Values = rawQValues,
|
||||||
|
GeometrySize = 5
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 更新 X 轴标签
|
||||||
|
XAxes = new Axis[]
|
||||||
|
{
|
||||||
|
new Axis
|
||||||
|
{
|
||||||
|
Name = "Charger-Coil Index",
|
||||||
|
Labels = coilLabels
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_logger.LogInformation("加载 Qfod 图表数据成功: ScenarioId={ScenarioId}, 记录数={Count}", ScenarioId, records.Count);
|
||||||
|
LoadingMessage = "";
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "加载 Qfod 图表数据失败: ScenarioId={ScenarioId}", ScenarioId);
|
_logger.LogError(ex, "加载 Qfod 图表数据失败: ScenarioId={ScenarioId}", ScenarioId);
|
||||||
|
LoadingMessage = $"加载失败: {ex.Message}";
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IsLoading = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,16 +9,21 @@
|
|||||||
d:DesignHeight="400" d:DesignWidth="600">
|
d:DesignHeight="400" d:DesignWidth="600">
|
||||||
<Grid Margin="10">
|
<Grid Margin="10">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,10">
|
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,10">
|
||||||
<TextBlock Text="Ploss 功率损耗趋势图" FontSize="18" FontWeight="Bold"/>
|
<TextBlock Text="Ploss 功率损耗趋势图" FontSize="18" FontWeight="Bold"/>
|
||||||
<TextBlock Text="{Binding ScenarioId, StringFormat=' - 场景 {0}'}" FontSize="18" Margin="5,0,0,0"/>
|
<TextBlock Text="{Binding ScenarioId, StringFormat=' - 场景 {0}'}" FontSize="14" Foreground="Gray" Margin="10,5,0,0"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<lvc:CartesianChart Grid.Row="1"
|
<StackPanel Grid.Row="1" Orientation="Horizontal" Margin="0,0,0,10">
|
||||||
|
<Button Content="切换到表格" Command="{Binding SwitchToTableCommand}" Padding="10,5"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<lvc:CartesianChart Grid.Row="2"
|
||||||
Series="{Binding Series}"
|
Series="{Binding Series}"
|
||||||
XAxes="{Binding XAxes}"
|
XAxes="{Binding XAxes}"
|
||||||
YAxes="{Binding YAxes}"
|
YAxes="{Binding YAxes}"
|
||||||
|
|||||||
@@ -9,16 +9,21 @@
|
|||||||
d:DesignHeight="400" d:DesignWidth="600">
|
d:DesignHeight="400" d:DesignWidth="600">
|
||||||
<Grid Margin="10">
|
<Grid Margin="10">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,10">
|
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,10">
|
||||||
<TextBlock Text="Qfod Q值变化图" FontSize="18" FontWeight="Bold"/>
|
<TextBlock Text="Qfod Q值变化图" FontSize="18" FontWeight="Bold"/>
|
||||||
<TextBlock Text="{Binding ScenarioId, StringFormat=' - 场景 {0}'}" FontSize="18" Margin="5,0,0,0"/>
|
<TextBlock Text="{Binding ScenarioId, StringFormat=' - 场景 {0}'}" FontSize="14" Foreground="Gray" Margin="10,5,0,0"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<lvc:CartesianChart Grid.Row="1"
|
<StackPanel Grid.Row="1" Orientation="Horizontal" Margin="0,0,0,10">
|
||||||
|
<Button Content="切换到表格" Command="{Binding SwitchToTableCommand}" Padding="10,5"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<lvc:CartesianChart Grid.Row="2"
|
||||||
Series="{Binding Series}"
|
Series="{Binding Series}"
|
||||||
XAxes="{Binding XAxes}"
|
XAxes="{Binding XAxes}"
|
||||||
YAxes="{Binding YAxes}"
|
YAxes="{Binding YAxes}"
|
||||||
|
|||||||
Reference in New Issue
Block a user