Files
OrpaonVision/OrpaonVision.ConfigApp/ViewModels/ProductionSessionManagementViewModel.cs
2026-04-06 22:04:05 +08:00

417 lines
12 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Microsoft.Extensions.Logging;
using OrpaonVision.Core.Abstractions;
using OrpaonVision.Model.Production;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Runtime.CompilerServices;
using System.Windows;
namespace OrpaonVision.ConfigApp.ViewModels;
/// <summary>
/// 产品会话管理ViewModel。
/// </summary>
public sealed class ProductionSessionManagementViewModel : INotifyPropertyChanged, IDisposable
{
private readonly IProductionSessionService _productionSessionService;
private readonly ILogger<ProductionSessionManagementViewModel> _logger;
private string _productTypeCode = string.Empty;
private string _stationId = string.Empty;
private string _operatorId = string.Empty;
private ProductionSessionStatus? _status;
private ProductionSessionResult? _result;
private DateTime? _startTimeUtc;
private DateTime? _endTimeUtc;
private string _statusText = "就绪";
private ObservableCollection<ProductionSessionModel> _sessions = new();
private ProductionSessionStatistics? _statistics;
private int _currentPage = 1;
private int _pageSize = 20;
private int _totalPages = 1;
private int _totalCount = 0;
/// <summary>
/// 构造函数。
/// </summary>
public ProductionSessionManagementViewModel(
IProductionSessionService productionSessionService,
ILogger<ProductionSessionManagementViewModel> logger)
{
_productionSessionService = productionSessionService;
_logger = logger;
// 设置默认时间范围为最近7天
_endTimeUtc = DateTime.UtcNow;
_startTimeUtc = _endTimeUtc.Value.AddDays(-7);
}
/// <summary>
/// 产品类型编码。
/// </summary>
public string ProductTypeCode
{
get => _productTypeCode;
set => SetProperty(ref _productTypeCode, value);
}
/// <summary>
/// 工位ID。
/// </summary>
public string StationId
{
get => _stationId;
set => SetProperty(ref _stationId, value);
}
/// <summary>
/// 操作员ID。
/// </summary>
public string OperatorId
{
get => _operatorId;
set => SetProperty(ref _operatorId, value);
}
/// <summary>
/// 会话状态。
/// </summary>
public ProductionSessionStatus? Status
{
get => _status;
set => SetProperty(ref _status, value);
}
/// <summary>
/// 会话结果。
/// </summary>
public ProductionSessionResult? Result
{
get => _result;
set => SetProperty(ref _result, value);
}
/// <summary>
/// 开始时间UTC
/// </summary>
public DateTime? StartTimeUtc
{
get => _startTimeUtc;
set => SetProperty(ref _startTimeUtc, value);
}
/// <summary>
/// 结束时间UTC
/// </summary>
public DateTime? EndTimeUtc
{
get => _endTimeUtc;
set => SetProperty(ref _endTimeUtc, value);
}
/// <summary>
/// 状态文本。
/// </summary>
public string StatusText
{
get => _statusText;
private set => SetProperty(ref _statusText, value);
}
/// <summary>
/// 会话列表。
/// </summary>
public ObservableCollection<ProductionSessionModel> Sessions
{
get => _sessions;
private set => SetProperty(ref _sessions, value);
}
/// <summary>
/// 统计信息。
/// </summary>
public ProductionSessionStatistics? Statistics
{
get => _statistics;
private set => SetProperty(ref _statistics, value);
}
/// <summary>
/// 当前页码。
/// </summary>
public int CurrentPage
{
get => _currentPage;
private set => SetProperty(ref _currentPage, value);
}
/// <summary>
/// 每页大小。
/// </summary>
public int PageSize
{
get => _pageSize;
set => SetProperty(ref _pageSize, value);
}
/// <summary>
/// 总页数。
/// </summary>
public int TotalPages
{
get => _totalPages;
private set => SetProperty(ref _totalPages, value);
}
/// <summary>
/// 总记录数。
/// </summary>
public int TotalCount
{
get => _totalCount;
private set => SetProperty(ref _totalCount, value);
}
/// <inheritdoc />
public event PropertyChangedEventHandler? PropertyChanged;
/// <summary>
/// 查询会话列表。
/// </summary>
public async Task QuerySessionsAsync()
{
try
{
StatusText = "正在查询会话列表...";
var request = new GetProductionSessionsRequest
{
ProductTypeCode = string.IsNullOrEmpty(ProductTypeCode) ? null : ProductTypeCode,
StationId = string.IsNullOrEmpty(StationId) ? null : StationId,
OperatorId = string.IsNullOrEmpty(OperatorId) ? null : OperatorId,
Status = Status,
Result = Result,
StartTimeUtc = StartTimeUtc,
EndTimeUtc = EndTimeUtc,
PageIndex = CurrentPage,
PageSize = PageSize
};
var result = await Task.Run(() => _productionSessionService.GetSessions(request));
if (!result.Succeeded || result.Data == null)
{
StatusText = $"查询失败: {result.Message}";
MessageBox.Show(result.Message, "查询失败", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
Sessions.Clear();
foreach (var session in result.Data.Items)
{
Sessions.Add(session);
}
TotalCount = result.Data.TotalCount;
TotalPages = (int)Math.Ceiling((double)TotalCount / PageSize);
StatusText = $"查询完成,共 {TotalCount} 条记录";
_logger.LogInformation("查询会话列表成功,记录数: {Count}", TotalCount);
}
catch (Exception ex)
{
StatusText = $"查询失败: {ex.Message}";
_logger.LogError(ex, "查询会话列表失败");
MessageBox.Show($"查询失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
/// <summary>
/// 重置筛选条件。
/// </summary>
public void ResetFilters()
{
ProductTypeCode = string.Empty;
StationId = string.Empty;
OperatorId = string.Empty;
Status = null;
Result = null;
StartTimeUtc = DateTime.UtcNow.AddDays(-7);
EndTimeUtc = DateTime.UtcNow;
CurrentPage = 1;
_logger.LogInformation("筛选条件已重置");
}
/// <summary>
/// 加载统计信息。
/// </summary>
public async Task LoadStatisticsAsync()
{
try
{
StatusText = "正在加载统计信息...";
var request = new GetProductionSessionStatisticsRequest
{
ProductTypeCode = string.IsNullOrEmpty(ProductTypeCode) ? null : ProductTypeCode,
StationId = string.IsNullOrEmpty(StationId) ? null : StationId,
OperatorId = string.IsNullOrEmpty(OperatorId) ? null : OperatorId,
StartTimeUtc = StartTimeUtc ?? DateTime.UtcNow.AddDays(-7),
EndTimeUtc = EndTimeUtc ?? DateTime.UtcNow
};
var result = await Task.Run(() => _productionSessionService.GetStatistics(request));
if (!result.Succeeded || result.Data == null)
{
StatusText = $"加载统计信息失败: {result.Message}";
MessageBox.Show(result.Message, "加载失败", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
Statistics = result.Data;
StatusText = "统计信息加载完成";
_logger.LogInformation("统计信息加载完成,总会话数: {TotalSessions}, 合格率: {PassRate:P1}",
Statistics.TotalSessions, Statistics.PassRate);
}
catch (Exception ex)
{
StatusText = $"加载统计信息失败: {ex.Message}";
_logger.LogError(ex, "加载统计信息失败");
MessageBox.Show($"加载统计信息失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
/// <summary>
/// 导出会话记录。
/// </summary>
public async Task ExportSessionsAsync(string filePath, ExportFormat format)
{
try
{
StatusText = "正在导出会话记录...";
var request = new ExportProductionSessionsRequest
{
ProductTypeCode = string.IsNullOrEmpty(ProductTypeCode) ? null : ProductTypeCode,
StationId = string.IsNullOrEmpty(StationId) ? null : StationId,
OperatorId = string.IsNullOrEmpty(OperatorId) ? null : OperatorId,
Status = Status,
Result = Result,
StartTimeUtc = StartTimeUtc,
EndTimeUtc = EndTimeUtc,
Format = format
};
var result = await Task.Run(() => _productionSessionService.ExportSessions(request));
if (!result.Succeeded || result.Data == null)
{
StatusText = $"导出失败: {result.Message}";
MessageBox.Show(result.Message, "导出失败", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
await File.WriteAllBytesAsync(filePath, result.Data);
StatusText = $"导出成功: {filePath}";
_logger.LogInformation("会话记录导出成功,文件: {FilePath}, 格式: {Format}", filePath, format);
}
catch (Exception ex)
{
StatusText = $"导出失败: {ex.Message}";
_logger.LogError(ex, "导出会话记录失败");
MessageBox.Show($"导出失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
/// <summary>
/// 查看会话详情。
/// </summary>
public void ViewSessionDetail(ProductionSessionModel session)
{
try
{
var detail = $@"会话详情
会话ID: {session.SessionId}
产品类型: {session.ProductTypeCode} - {session.ProductTypeName}
工位: {session.StationId} - {session.StationName}
操作员: {session.OperatorId} - {session.OperatorName}
班次: {session.ShiftId} - {session.ShiftName}
时间信息:
开始时间: {session.StartedAtUtc:yyyy-MM-dd HH:mm:ss} UTC
结束时间: {(session.EndedAtUtc?.ToString("yyyy-MM-dd HH:mm:ss") ?? "")} UTC
:
: {session.Status}
: {session.Result}
: {session.CurrentLayer}/{session.TotalLayers}
:
NG原因: {session.NgReason ?? "无"}
: {session.Remark ?? "无"}
: {session.CreatedAtUtc:yyyy-MM-dd HH:mm:ss} UTC
: {session.UpdatedAtUtc:yyyy-MM-dd HH:mm:ss} UTC";
MessageBox.Show(detail, $"会话详情 - {session.SessionId:N}", MessageBoxButton.OK, MessageBoxImage.Information);
_logger.LogInformation("查看会话详情会话ID: {SessionId}", session.SessionId);
}
catch (Exception ex)
{
_logger.LogError(ex, "查看会话详情失败");
MessageBox.Show($"查看详情失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
/// <summary>
/// 跳转到上一页。
/// </summary>
public async Task GoToPreviousPageAsync()
{
if (CurrentPage > 1)
{
CurrentPage--;
await QuerySessionsAsync();
}
}
/// <summary>
/// 跳转到下一页。
/// </summary>
public async Task GoToNextPageAsync()
{
if (CurrentPage < TotalPages)
{
CurrentPage++;
await QuerySessionsAsync();
}
}
/// <summary>
/// 释放资源。
/// </summary>
public void Dispose()
{
Sessions?.Clear();
Statistics = null;
_logger.LogInformation("产品会话管理ViewModel已释放");
}
private void SetProperty<T>(ref T field, T value, [CallerMemberName] string? propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value))
{
return;
}
field = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}