Files
BR_YKC/上位机/YKC/Pages/RealtimePage.xaml.cs

215 lines
9.4 KiB
C#
Raw Permalink Normal View History

2026-05-21 12:56:29 +08:00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using Newtonsoft.Json.Linq;
using OxyPlot;
using OxyPlot.Axes;
using OxyPlot.Series;
namespace YKC
{
public partial class RealtimePage : Page
{
private Timer _pollTimer;
private int _currentPile = 1;
private int _currentGun = 1;
public RealtimePage()
{
InitializeComponent();
InitLinePlot(plotCurrent, OxyColor.Parse("#3B82F6"));
InitLinePlot(plotVoltage, OxyColor.Parse("#8B5CF6"));
InitLinePlot(plotPower, OxyColor.Parse("#F59E0B"));
InitBarPlot(plotAmount);
Loaded += (s, e) =>
{
Dispatcher.BeginInvoke(new Action(RefreshData),
System.Windows.Threading.DispatcherPriority.Background);
_pollTimer = new Timer((_) =>
Dispatcher.BeginInvoke(new Action(RefreshData)), null, 2000, 2000);
};
Unloaded += (s, e) => _pollTimer?.Dispose();
}
private void InitLinePlot(OxyPlot.Wpf.PlotView pv, OxyColor color)
{
var model = new PlotModel { PlotAreaBorderColor = OxyColors.Transparent };
model.Axes.Add(new DateTimeAxis
{
Position = AxisPosition.Bottom,
TextColor = OxyColor.Parse("#94A3B8"),
AxislineColor = OxyColor.Parse("#E2E8F0"),
TicklineColor = OxyColor.Parse("#E2E8F0"),
MajorGridlineColor = OxyColor.Parse("#F1F5F9"),
StringFormat = "HH:mm:ss",
FontSize = 10
});
model.Axes.Add(new LinearAxis
{
Position = AxisPosition.Left,
TextColor = OxyColor.Parse("#94A3B8"),
AxislineColor = OxyColors.Transparent,
TicklineColor = OxyColors.Transparent,
MajorGridlineStyle = LineStyle.Dash,
MajorGridlineColor = OxyColor.Parse("#F1F5F9"),
FontSize = 10,
MinimumPadding = 0.1,
MaximumPadding = 0.1
});
model.Series.Add(new LineSeries
{
Color = color,
StrokeThickness = 2,
MarkerType = MarkerType.None,
CanTrackerInterpolatePoints = false
});
pv.Model = model;
}
private void InitBarPlot(OxyPlot.Wpf.PlotView pv)
{
var model = new PlotModel { PlotAreaBorderColor = OxyColors.Transparent };
var catAxis = new CategoryAxis
{
Position = AxisPosition.Bottom,
TextColor = OxyColor.Parse("#64748B"),
FontSize = 12,
AxislineColor = OxyColor.Parse("#E2E8F0"),
TicklineColor = OxyColor.Parse("#E2E8F0")
};
catAxis.Labels.Add("服务费");
catAxis.Labels.Add("电费");
catAxis.Labels.Add("总金额");
model.Axes.Add(catAxis);
model.Axes.Add(new LinearAxis
{
Position = AxisPosition.Left,
Title = "元",
TextColor = OxyColor.Parse("#94A3B8"),
FontSize = 10,
AxislineColor = OxyColors.Transparent,
TicklineColor = OxyColors.Transparent,
MajorGridlineStyle = LineStyle.Dash,
MajorGridlineColor = OxyColor.Parse("#F1F5F9"),
MinimumPadding = 0,
MaximumPadding = 0.15
});
model.Series.Add(new RectangleBarSeries { FillColor = OxyColor.Parse("#1E9FFF") });
model.Series.Add(new RectangleBarSeries { FillColor = OxyColor.Parse("#10B981") });
model.Series.Add(new RectangleBarSeries { FillColor = OxyColor.Parse("#6366F1") });
pv.Model = model;
}
private void PileGun_Changed(object sender, SelectionChangedEventArgs e)
{
try
{
if (cmbPile == null || cmbGun == null) return;
_currentPile = cmbPile.SelectedIndex + 1;
_currentGun = cmbGun.SelectedIndex + 1;
RefreshData();
}
catch { }
}
private void RefreshData()
{
try
{
if (txtCurrent == null || plotCurrent == null || plotCurrent.Model == null) return;
var latest = PilesStoreHolder.Instance.GetLatest(_currentPile, _currentGun);
if (latest == null) return;
txtCurrent.Text = FormatValue(latest.Value<double?>("current")) + " A";
txtVoltage.Text = FormatValue(latest.Value<double?>("voltage")) + " V";
txtPower.Text = FormatValue(latest.Value<double?>("power")) + " kW";
txtEnergy.Text = FormatValue(latest.Value<double?>("energy")) + " kWh";
txtTotalAmount.Text = "¥ " + FormatValue(latest.Value<double?>("total_amount"));
int? st = latest.Value<int?>("status");
if (st == 0) { txtStatus.Text = "离线"; txtStatus.Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#909399")); }
else if (st == 1) { txtStatus.Text = "故障"; txtStatus.Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#EF4444")); }
else if (st == 2) { txtStatus.Text = "空闲"; txtStatus.Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#10B981")); }
else if (st == 3) { txtStatus.Text = "充电中"; txtStatus.Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#3B82F6")); }
else { txtStatus.Text = "--"; }
txtOrderNo.Text = latest.Value<string>("order_no") ?? "--";
txtSoc.Text = latest.Value<double?>("soc") != null ? latest.Value<double>("soc").ToString("F1") + "%" : "--";
txtCumTime.Text = FormatMin(latest.Value<double?>("cumulative_time"));
txtRemTime.Text = FormatMin(latest.Value<double?>("remaining_time"));
UpdateCharts();
}
catch { }
}
private void UpdateCharts()
{
try
{
if (plotCurrent == null || plotCurrent.Model == null || plotCurrent.Model.Series.Count == 0) return;
if (plotAmount == null || plotAmount.Model == null || plotAmount.Model.Series.Count == 0) return;
var chartData = PilesStoreHolder.Instance.GetChartData(_currentPile, _currentGun);
if (chartData == null || chartData.Count == 0) return;
var curPoints = new List<DataPoint>();
var volPoints = new List<DataPoint>();
var powPoints = new List<DataPoint>();
foreach (var item in chartData)
{
long unixTs = item.Value<long>("t");
var dt = DateTimeOffset.FromUnixTimeSeconds(unixTs).DateTime;
double oxyTime = DateTimeAxis.ToDouble(dt);
curPoints.Add(new DataPoint(oxyTime, item.Value<double?>("current") ?? 0));
volPoints.Add(new DataPoint(oxyTime, item.Value<double?>("voltage") ?? 0));
powPoints.Add(new DataPoint(oxyTime, item.Value<double?>("power") ?? 0));
}
((LineSeries)plotCurrent.Model.Series[0]).Points.Clear();
((LineSeries)plotCurrent.Model.Series[0]).Points.AddRange(curPoints);
((LineSeries)plotVoltage.Model.Series[0]).Points.Clear();
((LineSeries)plotVoltage.Model.Series[0]).Points.AddRange(volPoints);
((LineSeries)plotPower.Model.Series[0]).Points.Clear();
((LineSeries)plotPower.Model.Series[0]).Points.AddRange(powPoints);
plotCurrent.InvalidatePlot(true);
plotVoltage.InvalidatePlot(true);
plotPower.InvalidatePlot(true);
var latest = PilesStoreHolder.Instance.GetLatest(_currentPile, _currentGun);
if (latest != null)
{
double sf = latest.Value<double?>("service_fee") ?? 0;
double ef = latest.Value<double?>("electricity_fee") ?? 0;
double ta = latest.Value<double?>("total_amount") ?? 0;
((RectangleBarSeries)plotAmount.Model.Series[0]).Items.Clear();
((RectangleBarSeries)plotAmount.Model.Series[0]).Items.Add(new RectangleBarItem(-0.25, 0, 0.25, sf));
((RectangleBarSeries)plotAmount.Model.Series[1]).Items.Clear();
((RectangleBarSeries)plotAmount.Model.Series[1]).Items.Add(new RectangleBarItem(0.75, 0, 1.25, ef));
((RectangleBarSeries)plotAmount.Model.Series[2]).Items.Clear();
((RectangleBarSeries)plotAmount.Model.Series[2]).Items.Add(new RectangleBarItem(1.75, 0, 2.25, ta));
plotAmount.InvalidatePlot(true);
}
}
catch { }
}
private string FormatValue(double? v)
{
return v.HasValue ? v.Value.ToString("F2") : "--";
}
private string FormatMin(double? v)
{
return v.HasValue ? Math.Round(v.Value).ToString() + " min" : "--";
}
}
}