417 lines
12 KiB
C#
417 lines
12 KiB
C#
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));
|
||
}
|
||
}
|