胶料快检添加离线模式

This commit is contained in:
2026-06-30 11:28:04 +08:00
parent efcd73a565
commit 840e68a450
19 changed files with 1053 additions and 343 deletions

View File

@@ -195,6 +195,7 @@ namespace YY.Admin.ViewModels
private SubscriptionToken? _openOrActivateTabToken;
private SubscriptionToken? _tabClosedToken;
private SubscriptionToken? _tabCloseRequestToken;
private SubscriptionToken? _refreshTabToken;
private SubscriptionToken? _loginOutToken;
@@ -235,6 +236,7 @@ namespace YY.Admin.ViewModels
// 订阅事件
_openOrActivateTabToken = _eventAggregator.GetEvent<TabSourceSelectedEvent>().Subscribe(OnOpenOrActivateTab);
_tabClosedToken = _eventAggregator.GetEvent<TabClosedEvent>().Subscribe(OnTabClosed);
_tabCloseRequestToken = _eventAggregator.GetEvent<TabCloseRequestEvent>().Subscribe(OnTabCloseRequest, ThreadOption.UIThread);
_refreshTabToken = _eventAggregator.GetEvent<TabRefreshEvent>().Subscribe(OnRefreshTab);
_loginOutToken = _eventAggregator.GetEvent<SysUserEvents.LoginOutEvent>().Subscribe(Destroy);
@@ -489,6 +491,48 @@ namespace YY.Admin.ViewModels
_ = NavigateToViewAsync(CommonConst.ContentRegion, tabItemModel.ViewName, tabItemModel.TabSource.NavigationParameter);
}
/// <summary>
/// 按 ViewName 关闭 Tab并可选激活指定页面
/// </summary>
private void OnTabCloseRequest(TabCloseRequestPayload payload)
{
if (payload == null || string.IsNullOrWhiteSpace(payload.ViewNameToClose))
{
return;
}
var tabsToClose = OpenTabs
.Where(t => t.IsClosable
&& string.Equals(t.ViewName, payload.ViewNameToClose, StringComparison.OrdinalIgnoreCase))
.ToList();
foreach (var tab in tabsToClose)
{
_eventAggregator.GetEvent<TabClosedEvent>().Publish(tab);
OpenTabs.Remove(tab);
}
if (string.IsNullOrWhiteSpace(payload.ActivateViewName))
{
return;
}
var existingTab = OpenTabs.FirstOrDefault(t =>
string.Equals(t.ViewName, payload.ActivateViewName, StringComparison.OrdinalIgnoreCase));
if (existingTab != null)
{
SelectedTab = existingTab;
return;
}
OnOpenOrActivateTab(new TabSource
{
Name = payload.ActivateTabName ?? payload.ActivateViewName,
Icon = "\ue7de",
ViewName = payload.ActivateViewName
});
}
/// <summary>
/// TabItem关闭回调
/// </summary>
@@ -764,6 +808,15 @@ namespace YY.Admin.ViewModels
_tabClosedToken = null;
}
if (_tabCloseRequestToken != null)
{
_eventAggregator
.GetEvent<TabCloseRequestEvent>()
.Unsubscribe(_tabCloseRequestToken);
_tabCloseRequestToken = null;
}
if (_refreshTabToken != null)
{
_eventAggregator

View File

@@ -27,7 +27,7 @@ using YY.Admin.Core.Services;
using YY.Admin.Core.Session;
using YY.Admin.Event;
namespace YY.Admin.ViewModels.RubberQuickTest;
@@ -178,12 +178,17 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
private readonly IRubberQuickTestStdService _stdService;
private readonly INetworkMonitor _networkMonitor;
private readonly Random _rnd = new();
private bool _saveInProgress;
private string? _loadedDetailLocalId;
private string? _loadedDetailMesId;
private string? _editingLocalId;
private DateTime? _originalCreateTime;
private bool _isLoadingForm;
private int _navigationApplyVersion;
private List<MesXslMixingProductionPlan> _allPlans = new();
@@ -196,6 +201,8 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
private SubscriptionToken? _stdChangedToken;
private SubscriptionToken? _networkStatusToken;
private const int ChartPointCount = 5;
/// <summary>曲线横坐标时间点min0、0.5、1、1.5、2</summary>
@@ -215,6 +222,8 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
IRubberQuickTestStdService stdService,
INetworkMonitor networkMonitor,
IContainerExtension container,
IRegionManager regionManager) : base(container, regionManager)
@@ -227,20 +236,20 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
_stdService = stdService;
_networkMonitor = networkMonitor;
_inspectTimesText = "1";
AddInspectRowCommand = new DelegateCommand(AddInspectRow, () => DataPointColumns.Count > 0);
AddInspectRowCommand = new DelegateCommand(AddInspectRow, () => DataPointColumns.Count > 0 && !IsReadOnly);
RemoveInspectRowCommand = new DelegateCommand(() => RemoveInspectRow(SelectedInspectRow), () => SelectedInspectRow != null);
RemoveInspectRowCommand = new DelegateCommand(() => RemoveInspectRow(SelectedInspectRow), () => SelectedInspectRow != null && !IsReadOnly);
SaveCommand = new DelegateCommand(async () => await SaveAsync(), () => CanSave);
RefreshPlansCommand = new DelegateCommand(async () => await LoadLocalDataAsync(showSuccess: true));
RefreshChartDemoCommand = new DelegateCommand(FillRandomChartData);
@@ -268,9 +277,45 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
_stdChangedToken = _eventAggregator.GetEvent<RubberQuickTestStdChangedEvent>()
.Subscribe(async _ => await ReloadLocalDataQuietAsync(), ThreadOption.UIThread);
_networkStatusToken = _eventAggregator.GetEvent<NetworkStatusChangedEvent>()
.Subscribe(OnNetworkStatusChanged, ThreadOption.UIThread);
IsOfflineMode = !_networkMonitor.IsOnline;
RecalculateOverallInspectResult();
}
private void OnNetworkStatusChanged(NetworkStatusChangedPayload payload)
{
IsOfflineMode = !payload.IsOnline;
if (IsOfflineMode)
RefreshRubberMaterialOptions();
}
private bool _isOfflineMode;
/// <summary>断网时自动进入离线模式</summary>
public bool IsOfflineMode
{
get => _isOfflineMode;
private set
{
if (!SetProperty(ref _isOfflineMode, value)) return;
RaisePropertyChanged(nameof(PlanFieldsRequired));
RaisePropertyChanged(nameof(IsOnlineMode));
RaisePropertyChanged(nameof(RubberMaterialName));
if (value)
RefreshRubberMaterialOptions();
}
}
public bool IsOnlineMode => !IsOfflineMode;
public bool PlanFieldsRequired => !IsOfflineMode;
public string OfflineModeHint => IsOfflineMode
? "当前离线:密炼日期、机台、班次、密炼计划可选填;请手动选择胶料名称,保存后待联网同步"
: string.Empty;
private bool _isReadOnly;
public bool IsReadOnly
{
@@ -281,12 +326,16 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
RaisePropertyChanged(nameof(IsEditable));
RaisePropertyChanged(nameof(ShowSaveButton));
NotifySaveStateChanged();
AddInspectRowCommand.RaiseCanExecuteChanged();
RemoveInspectRowCommand.RaiseCanExecuteChanged();
InspectColumnsChanged?.Invoke();
}
}
public bool IsEditable => !IsReadOnly;
public bool ShowSaveButton => !IsReadOnly;
public bool IsEditMode => !string.IsNullOrWhiteSpace(_editingLocalId);
public string SaveButtonText => IsEditMode ? "保存修改" : "保存胶料快检记录";
public bool CanSave => InspectRows.Count > 0 && !_saveInProgress && !IsReadOnly;
private void NotifySaveStateChanged()
@@ -314,6 +363,7 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
{
if (parameters.TryGetValue<string>("localId", out var localId) && !string.IsNullOrWhiteSpace(localId))
{
_editingLocalId = null;
_loadedDetailLocalId = localId;
_loadedDetailMesId = null;
await LoadFromLocalItemAsync(localId);
@@ -322,6 +372,7 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
if (parameters.TryGetValue<string>("mesId", out var mesId) && !string.IsNullOrWhiteSpace(mesId))
{
_editingLocalId = null;
_loadedDetailMesId = mesId;
_loadedDetailLocalId = null;
await LoadFromMesIdAsync(mesId);
@@ -329,10 +380,22 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
}
}
if (parameters.TryGetValue<string>("editLocalId", out var editLocalId) && !string.IsNullOrWhiteSpace(editLocalId))
{
_editingLocalId = editLocalId;
_loadedDetailLocalId = null;
_loadedDetailMesId = null;
IsReadOnly = false;
await LoadForEditAsync(editLocalId);
return;
}
if (version != _navigationApplyVersion) return;
_loadedDetailLocalId = null;
_loadedDetailMesId = null;
_editingLocalId = null;
_originalCreateTime = null;
IsReadOnly = false;
ResetFormForNewEntry();
await LoadLocalDataAsync(showSuccess: false);
@@ -352,7 +415,10 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
return false;
}
return !IsReadOnly && _loadedDetailLocalId == null && _loadedDetailMesId == null;
if (parameters.TryGetValue<string>("editLocalId", out var editLocalId) && !string.IsNullOrWhiteSpace(editLocalId))
return !IsReadOnly && string.Equals(_editingLocalId, editLocalId, StringComparison.OrdinalIgnoreCase);
return !IsReadOnly && _editingLocalId == null && _loadedDetailLocalId == null && _loadedDetailMesId == null;
}
private void ResetFormForNewEntry()
@@ -360,6 +426,7 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
RecordNo = null;
TrainNo = null;
InspectTimesText = "1";
MixingDate = DateTime.Today;
ClearPlanAndStdSelection();
RecalculateOverallInspectResult();
NotifySaveStateChanged();
@@ -420,6 +487,8 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
public ObservableCollection<MesXslRubberQuickTestStd> StdOptions { get; } = new();
public ObservableCollection<string> RubberMaterialOptions { get; } = new();
public ObservableCollection<MesXslRubberQuickTestStdLine> DataPointColumns { get; } = new();
public ObservableCollection<QuickTestInspectRowViewModel> InspectRows { get; } = new();
@@ -448,9 +517,9 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
private DateTime _mixingDate = DateTime.Today;
private DateTime? _mixingDate = DateTime.Today;
public DateTime MixingDate
public DateTime? MixingDate
{
@@ -464,7 +533,8 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
RefreshMachineOptions();
ClearPlanAndStdSelection();
if (!_isLoadingForm)
OnPlanFilterChanged();
}
@@ -488,7 +558,8 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
RefreshShiftOptions();
ClearPlanAndStdSelection();
if (!_isLoadingForm)
OnPlanFilterChanged();
}
@@ -512,7 +583,8 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
RefreshPlanOptions();
ClearPlanAndStdSelection();
if (!_isLoadingForm)
OnPlanFilterChanged();
}
@@ -568,7 +640,30 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
public string? WorkShiftDisplay => SelectedShift?.Name ?? string.Empty;
public string? RubberMaterialName => _selectedPlan?.MaterialName ?? _selectedPlan?.FormulaName;
private string? _selectedRubberMaterial;
/// <summary>离线模式下手动选择的胶料名称</summary>
public string? SelectedRubberMaterial
{
get => _selectedRubberMaterial;
set
{
if (!SetProperty(ref _selectedRubberMaterial, value)) return;
RaisePropertyChanged(nameof(RubberMaterialName));
if (IsOfflineMode && _selectedPlan == null)
{
ClearStdSelection();
RefreshStdOptions();
}
}
}
public string? RubberMaterialName =>
(IsEditMode && !string.IsNullOrWhiteSpace(SelectedRubberMaterial))
? SelectedRubberMaterial
: _selectedPlan?.MaterialName
?? _selectedPlan?.FormulaName
?? (IsOfflineMode ? SelectedRubberMaterial : null);
@@ -699,8 +794,6 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
public DelegateCommand SaveCommand { get; }
public DelegateCommand RefreshPlansCommand { get; }
public DelegateCommand RefreshChartDemoCommand { get; }
@@ -720,6 +813,7 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
_allStds = await _stdService.GetAllCachedAsync();
RefreshMachineOptions();
RefreshRubberMaterialOptions();
if (showSuccess)
@@ -760,8 +854,12 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
_allStds = await _stdService.GetAllCachedAsync();
RefreshMachineOptions();
RefreshRubberMaterialOptions();
RefreshStdOptions();
if (IsEditMode)
EnsureCurrentStdInOptions();
else
RefreshStdOptions();
}
@@ -777,9 +875,27 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
private IEnumerable<MesXslMixingProductionPlan> FilteredByDate =>
private void RefreshRubberMaterialOptions()
{
RubberMaterialOptions.Clear();
foreach (var name in _allStds
.Where(s => s.EnableStatus == "1" && s.AuditStatus == "1")
.Select(s => s.RubberMaterialName?.Trim())
.Where(n => !string.IsNullOrWhiteSpace(n))
.Distinct(StringComparer.OrdinalIgnoreCase)
.OrderBy(n => n, StringComparer.OrdinalIgnoreCase))
RubberMaterialOptions.Add(name!);
_allPlans.Where(p => p.PlanDate?.Date == MixingDate.Date);
if (SelectedRubberMaterial != null && !RubberMaterialOptions.Contains(SelectedRubberMaterial))
SelectedRubberMaterial = null;
}
private IEnumerable<MesXslMixingProductionPlan> FilteredByDate =>
MixingDate == null
? Enumerable.Empty<MesXslMixingProductionPlan>()
: _allPlans.Where(p => p.PlanDate?.Date == MixingDate.Value.Date);
@@ -797,7 +913,7 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
SelectedMachine = null;
if (SelectedMachine == null && MachineOptions.Count > 0)
if (SelectedMachine == null && MachineOptions.Count > 0 && !IsEditMode && !_isLoadingForm)
SelectedMachine = MachineOptions[0];
@@ -835,7 +951,7 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
SelectedShift = null;
if (SelectedShift == null && ShiftOptions.Count > 0)
if (SelectedShift == null && ShiftOptions.Count > 0 && !IsEditMode && !_isLoadingForm)
SelectedShift = ShiftOptions[0];
@@ -873,7 +989,7 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
SelectedPlan = null;
if (SelectedPlan == null && PlanOptions.Count > 0)
if (SelectedPlan == null && PlanOptions.Count > 0 && !IsEditMode && !_isLoadingForm)
SelectedPlan = PlanOptions[0];
@@ -881,6 +997,26 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
/// <summary>密炼日期/机台/班次变更:编辑模式仅重置计划,不清空实验标准与检验明细</summary>
private void OnPlanFilterChanged()
{
if (IsEditMode)
ResetPlanSelectionOnly();
else
ClearPlanAndStdSelection();
}
private void ResetPlanSelectionOnly()
{
_selectedPlan = null;
RaisePropertyChanged(nameof(SelectedPlan));
RaisePropertyChanged(nameof(MachineName));
RaisePropertyChanged(nameof(WorkShiftDisplay));
RaisePropertyChanged(nameof(RubberMaterialName));
}
private void ClearPlanAndStdSelection()
{
@@ -893,6 +1029,11 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
RaisePropertyChanged(nameof(WorkShiftDisplay));
if (!IsOfflineMode)
{
SelectedRubberMaterial = null;
}
RaisePropertyChanged(nameof(RubberMaterialName));
ClearStdSelection();
@@ -920,19 +1061,34 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
private void ApplySelectedPlan()
{
RaisePropertyChanged(nameof(MachineName));
RaisePropertyChanged(nameof(WorkShiftDisplay));
RaisePropertyChanged(nameof(RubberMaterialName));
ClearStdSelection();
if (IsEditMode)
{
EnsureCurrentStdInOptions();
return;
}
RefreshStdOptions();
}
/// <summary>编辑模式下保留已选实验标准,避免下拉选项刷新导致标准与明细被清空</summary>
private void EnsureCurrentStdInOptions()
{
if (_selectedStd == null || string.IsNullOrWhiteSpace(_selectedStd.StdName))
{
return;
}
if (!StdOptions.Any(s => string.Equals(s.Id, _selectedStd.Id, StringComparison.OrdinalIgnoreCase)))
{
StdOptions.Insert(0, _selectedStd);
}
RaisePropertyChanged(nameof(SelectedStd));
}
@@ -986,6 +1142,24 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
{
if (SelectedStd == null || string.IsNullOrWhiteSpace(SelectedStd.Id))
{
if (_currentStd != null || DataPointColumns.Count > 0 || InspectRows.Count > 0)
{
DataPointColumns.Clear();
InspectRows.Clear();
_currentStd = null;
TestMethodName = null;
InspectColumnsChanged?.Invoke();
RecalculateOverallInspectResult();
}
return;
}
if (string.Equals(SelectedStd.Id, _currentStd?.Id, StringComparison.OrdinalIgnoreCase)
&& DataPointColumns.Count > 0)
return;
DataPointColumns.Clear();
InspectRows.Clear();
@@ -998,10 +1172,6 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
RecalculateOverallInspectResult();
if (SelectedStd == null || string.IsNullOrWhiteSpace(SelectedStd.Id)) return;
IsLoading = true;
try
@@ -1213,15 +1383,23 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
return;
}
if (SelectedPlan == null)
if (!IsOfflineMode)
{
Growl.Warning("请选择密炼计划");
return;
}
if (SelectedPlan == null)
{
Growl.Warning("请选择密炼计划");
return;
}
if (string.IsNullOrWhiteSpace(RubberMaterialName))
if (string.IsNullOrWhiteSpace(RubberMaterialName))
{
Growl.Warning("请先选择密炼计划以带出胶料名称");
return;
}
}
else if (string.IsNullOrWhiteSpace(RubberMaterialName))
{
Growl.Warning("请选择密炼计划以带出胶料名称");
Growl.Warning("请选择胶料名称");
return;
}
@@ -1262,16 +1440,25 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
IsLoading = true;
var record = BuildSaveRecord(stdLineList, rawLineList, chartPointList, inspectTimes, user);
var saved = await _recordService.SaveAsync(record);
RubberQuickTestRecordSaveResult saved;
if (!string.IsNullOrWhiteSpace(_editingLocalId))
saved = await _recordService.UpdateLocalAsync(_editingLocalId, record);
else
saved = await _recordService.SaveAsync(record);
RecordNo = saved.Record.RecordNo;
var syncHint = saved.SyncStatus == "Synced" ? "并已同步到 MES" : "MES 同步待重试)";
var syncHint = saved.SyncStatus switch
{
"Synced" => "并已同步到 MES",
"Pending" => "(未同步,联网后可在列表中手动同步)",
_ => "MES 同步失败,可在列表中重试同步)"
};
var actionText = IsEditMode ? "修改已保存" : "胶料快检记录已保存";
Growl.Success(string.IsNullOrWhiteSpace(RecordNo)
? $"胶料快检记录已保存到本地{syncHint}"
: $"胶料快检记录已保存,快检记录号:{RecordNo}{syncHint}");
? $"{actionText}到本地{syncHint}"
: $"{actionText},快检记录号:{RecordNo}{syncHint}");
InspectRows.Clear();
NotifySaveStateChanged();
NavigateBackToRecordList();
}
catch (Exception ex)
{
@@ -1287,6 +1474,16 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
private void NavigateBackToRecordList()
{
_eventAggregator.GetEvent<TabCloseRequestEvent>().Publish(new TabCloseRequestPayload
{
ViewNameToClose = "RubberQuickTestOperationView",
ActivateViewName = "RubberQuickTestRecordListView",
ActivateTabName = "胶料快检记录"
});
}
private bool TryParseInspectTimes(out int value, out string error)
{
@@ -1501,11 +1698,13 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
InspectTime = DateTime.Now,
CreateTime = DateTime.Now,
InspectResult = OverallInspectResultCode,
RecordNo = _recordService.GenerateRecordNo(RubberMaterialName ?? string.Empty)
RecordNo = string.IsNullOrWhiteSpace(RecordNo)
? _recordService.GenerateRecordNo(RubberMaterialName ?? string.Empty)
: RecordNo,
CreateTime = _originalCreateTime ?? DateTime.Now
};
@@ -1545,17 +1744,25 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
if (!string.IsNullOrWhiteSpace(_selectedPlan?.MachineId))
var hasPlanContext = _selectedPlan != null || !IsOfflineMode;
record.ProdEquipmentLedgerId = _selectedPlan.MachineId;
if (hasPlanContext)
{
if (!string.IsNullOrWhiteSpace(_selectedPlan?.MachineId))
record.ProdEquipmentLedgerId = _selectedPlan.MachineId;
if (!string.IsNullOrWhiteSpace(MachineName))
if (!string.IsNullOrWhiteSpace(MachineName))
record.ProdEquipmentName = MachineName;
record.ProdEquipmentName = MachineName;
if (SelectedShift != null && !string.IsNullOrWhiteSpace(SelectedShift.Code))
record.WorkShift = SelectedShift.Code;
if (!string.IsNullOrWhiteSpace(_selectedPlan?.PlanNo))
record.ProductionPlanNo = _selectedPlan.PlanNo;
}
record.ProductionDate = MixingDate;
if (MixingDate != null)
record.ProductionDate = MixingDate;
@@ -1565,22 +1772,10 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
if (SelectedShift != null && !string.IsNullOrWhiteSpace(SelectedShift.Code))
record.WorkShift = SelectedShift.Code;
record.InspectTimes = inspectTimes;
if (!string.IsNullOrWhiteSpace(_selectedPlan?.PlanNo))
record.ProductionPlanNo = _selectedPlan.PlanNo;
var inspectorId = user?.JeecgBizUserId ?? (user != null ? user.Id.ToString() : null);
if (!string.IsNullOrWhiteSpace(inspectorId))
@@ -1649,7 +1844,32 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
return;
}
await ApplyRecordDetailAsync(item.Record);
await ApplyRecordDetailAsync(item.Record, readOnly: true);
}
private async Task LoadForEditAsync(string localId)
{
var item = _recordService.GetByLocalId(localId);
if (item == null)
{
Growl.Warning("未找到快检记录");
return;
}
if (string.Equals(item.SyncStatus, "Synced", StringComparison.OrdinalIgnoreCase))
{
Growl.Warning("已同步记录不可编辑");
return;
}
_editingLocalId = localId;
_originalCreateTime = item.Record.CreateTime;
IsReadOnly = false;
RaisePropertyChanged(nameof(IsEditMode));
RaisePropertyChanged(nameof(SaveButtonText));
await LoadLocalDataAsync(showSuccess: false);
await ApplyRecordDetailAsync(item.Record, readOnly: false);
}
private async Task LoadFromMesIdAsync(string mesId)
@@ -1661,105 +1881,181 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
return;
}
await ApplyRecordDetailAsync(record);
await ApplyRecordDetailAsync(record, readOnly: true);
}
private async Task ApplyRecordDetailAsync(MesXslRubberQuickTestRecord r)
private async Task ApplyRecordDetailAsync(MesXslRubberQuickTestRecord r, bool readOnly)
{
IsReadOnly = true;
RecordNo = r.RecordNo;
MixingDate = r.ProductionDate ?? DateTime.Today;
SelectedMachine = r.ProdEquipmentName;
TrainNo = r.TrainNo;
InspectTimesText = r.InspectTimes?.ToString() ?? "1";
InspectorDisplay = r.InspectorRealname ?? ResolveInspectorDisplay();
OverallInspectResultCode = r.InspectResult ?? "0";
OverallInspectResultDisplay = string.Equals(r.InspectResult, "1", StringComparison.Ordinal) ? "合格" : "不合格";
TestMethodName = r.TestMethodName;
MachineOptions.Clear();
if (!string.IsNullOrWhiteSpace(r.ProdEquipmentName))
MachineOptions.Add(r.ProdEquipmentName);
ShiftOptions.Clear();
var shift = new WorkShiftOption(r.WorkShift ?? "", r.WorkShift ?? "");
ShiftOptions.Add(shift);
SelectedShift = shift;
PlanOptions.Clear();
var plan = new MesXslMixingProductionPlan
_isLoadingForm = true;
try
{
PlanNo = r.ProductionPlanNo,
MaterialName = r.RubberMaterialName,
MachineName = r.ProdEquipmentName
};
PlanOptions.Add(plan);
_selectedPlan = plan;
RaisePropertyChanged(nameof(SelectedPlan));
RaisePropertyChanged(nameof(MachineName));
RaisePropertyChanged(nameof(RubberMaterialName));
IsReadOnly = readOnly;
RecordNo = r.RecordNo;
MixingDate = r.ProductionDate ?? r.CreateTime?.Date;
TrainNo = r.TrainNo;
InspectTimesText = r.InspectTimes?.ToString() ?? "1";
InspectorDisplay = r.InspectorRealname ?? ResolveInspectorDisplay();
OverallInspectResultCode = r.InspectResult ?? "0";
OverallInspectResultDisplay = string.Equals(r.InspectResult, "1", StringComparison.Ordinal) ? "合格" : "不合格";
TestMethodName = r.TestMethodName;
StdOptions.Clear();
var std = new MesXslRubberQuickTestStd { Id = r.StdId, StdName = r.StdName, TestMethodName = r.TestMethodName };
StdOptions.Add(std);
_selectedStd = std;
RaisePropertyChanged(nameof(SelectedStd));
ClearPlanAndStdSelection();
SelectedRubberMaterial = r.RubberMaterialName;
DataPointColumns.Clear();
InspectRows.Clear();
foreach (var sl in (r.StdLineList ?? new List<MesXslRubberQuickTestRecordStdLine>()).OrderBy(x => x.SortNo ?? 0))
{
DataPointColumns.Add(new MesXslRubberQuickTestStdLine
MesXslMixingProductionPlan? matchedPlan = null;
if (!string.IsNullOrWhiteSpace(r.ProductionPlanNo))
{
DataPointId = sl.DataPointId,
PointName = sl.PointName,
LowerLimit = sl.LowerLimit,
LowerWarn = sl.LowerWarn,
TargetValue = sl.TargetValue,
UpperWarn = sl.UpperWarn,
UpperLimit = sl.UpperLimit,
SortNo = sl.SortNo
});
}
InspectColumnsChanged?.Invoke();
var grouped = (r.RawLineList ?? new List<MesXslRubberQuickTestRecordRawLine>())
.GroupBy(x => x.RowNo ?? string.Empty)
.OrderBy(g => g.Key, StringComparer.Ordinal);
foreach (var g in grouped)
{
var row = new QuickTestInspectRowViewModel { RowNo = g.Key };
for (int i = 0; i < DataPointColumns.Count; i++)
{
var col = DataPointColumns[i];
var raw = g.FirstOrDefault(x => x.DataPointId == col.DataPointId || x.InspectItem == col.PointName);
var cell = new QuickTestInspectCellViewModel
{
DataPointId = col.DataPointId,
PointName = col.PointName ?? string.Empty,
LowerLimit = col.LowerLimit,
UpperLimit = col.UpperLimit,
Value = raw?.InspectValue
};
row.Cells.Add(cell);
matchedPlan = _allPlans.FirstOrDefault(p =>
string.Equals(p.PlanNo, r.ProductionPlanNo, StringComparison.OrdinalIgnoreCase));
}
row.RecalculateResult();
InspectRows.Add(row);
}
UpperTempValues.Clear();
LowerTempValues.Clear();
TorqueValues.Clear();
foreach (var pt in (r.ChartPointList ?? new List<MesXslRubberQuickTestRecordChartPoint>()).OrderBy(x => x.SortNo ?? 0))
{
var time = (double)(pt.TimeMin ?? 0);
if (pt.UpperTemp != null) UpperTempValues.Add(new ObservablePoint(time, (double)pt.UpperTemp.Value));
if (pt.LowerTemp != null) LowerTempValues.Add(new ObservablePoint(time, (double)pt.LowerTemp.Value));
if (pt.TorqueS != null) TorqueValues.Add(new ObservablePoint(time, (double)pt.TorqueS.Value));
if (matchedPlan != null)
{
RefreshMachineOptions();
SelectedMachine = matchedPlan.MachineName ?? r.ProdEquipmentName;
RefreshShiftOptions();
if (!string.IsNullOrWhiteSpace(r.WorkShift))
{
SelectedShift = ShiftOptions.FirstOrDefault(s => s.Code == r.WorkShift)
?? ShiftOptions.FirstOrDefault();
}
RefreshPlanOptions();
SelectedPlan = PlanOptions.FirstOrDefault(p => p.Id == matchedPlan.Id)
?? PlanOptions.FirstOrDefault(p => string.Equals(p.PlanNo, matchedPlan.PlanNo, StringComparison.OrdinalIgnoreCase));
}
else if (!string.IsNullOrWhiteSpace(r.ProdEquipmentName) || !string.IsNullOrWhiteSpace(r.ProductionPlanNo))
{
MachineOptions.Clear();
if (!string.IsNullOrWhiteSpace(r.ProdEquipmentName))
MachineOptions.Add(r.ProdEquipmentName);
SelectedMachine = r.ProdEquipmentName;
ShiftOptions.Clear();
var shift = new WorkShiftOption(r.WorkShift ?? "", r.WorkShiftText ?? r.WorkShift ?? "");
ShiftOptions.Add(shift);
SelectedShift = shift;
PlanOptions.Clear();
var plan = new MesXslMixingProductionPlan
{
PlanNo = r.ProductionPlanNo,
MaterialName = r.RubberMaterialName,
MachineName = r.ProdEquipmentName
};
PlanOptions.Add(plan);
_selectedPlan = plan;
RaisePropertyChanged(nameof(SelectedPlan));
RaisePropertyChanged(nameof(MachineName));
RaisePropertyChanged(nameof(RubberMaterialName));
}
else if (!string.IsNullOrWhiteSpace(r.RubberMaterialName))
{
RefreshStdOptions();
}
_currentStd = null;
if (!string.IsNullOrWhiteSpace(r.StdId))
{
var cachedStd = await _stdService.GetWithLinesAsync(r.StdId);
if (cachedStd != null)
{
_currentStd = cachedStd;
StdOptions.Clear();
StdOptions.Add(cachedStd);
_selectedStd = cachedStd;
RaisePropertyChanged(nameof(SelectedStd));
TestMethodName = cachedStd.TestMethodName ?? r.TestMethodName;
}
}
if (_currentStd == null && !string.IsNullOrWhiteSpace(r.StdName))
{
var std = new MesXslRubberQuickTestStd { Id = r.StdId, StdName = r.StdName, TestMethodName = r.TestMethodName };
StdOptions.Clear();
StdOptions.Add(std);
_selectedStd = std;
RaisePropertyChanged(nameof(SelectedStd));
}
DataPointColumns.Clear();
InspectRows.Clear();
if (_currentStd?.LineList != null && _currentStd.LineList.Count > 0)
{
foreach (var line in _currentStd.LineList.OrderBy(x => x.SortNo ?? 0))
DataPointColumns.Add(line);
}
else
{
foreach (var sl in (r.StdLineList ?? new List<MesXslRubberQuickTestRecordStdLine>()).OrderBy(x => x.SortNo ?? 0))
{
DataPointColumns.Add(new MesXslRubberQuickTestStdLine
{
DataPointId = sl.DataPointId,
PointName = sl.PointName,
LowerLimit = sl.LowerLimit,
LowerWarn = sl.LowerWarn,
TargetValue = sl.TargetValue,
UpperWarn = sl.UpperWarn,
UpperLimit = sl.UpperLimit,
SortNo = sl.SortNo
});
}
}
InspectColumnsChanged?.Invoke();
var grouped = (r.RawLineList ?? new List<MesXslRubberQuickTestRecordRawLine>())
.GroupBy(x => x.RowNo ?? string.Empty)
.OrderBy(g => g.Key, StringComparer.Ordinal);
foreach (var g in grouped)
{
var row = new QuickTestInspectRowViewModel { RowNo = g.Key };
for (int i = 0; i < DataPointColumns.Count; i++)
{
var col = DataPointColumns[i];
var raw = g.FirstOrDefault(x => x.DataPointId == col.DataPointId || x.InspectItem == col.PointName);
var cell = new QuickTestInspectCellViewModel
{
DataPointId = col.DataPointId,
PointName = col.PointName ?? string.Empty,
LowerLimit = col.LowerLimit,
UpperLimit = col.UpperLimit,
Value = raw?.InspectValue
};
if (!readOnly)
{
cell.ValueChanged += _ =>
{
row.RecalculateResult();
RecalculateOverallInspectResult();
};
}
row.Cells.Add(cell);
}
row.RecalculateResult();
InspectRows.Add(row);
}
UpperTempValues.Clear();
LowerTempValues.Clear();
TorqueValues.Clear();
foreach (var pt in (r.ChartPointList ?? new List<MesXslRubberQuickTestRecordChartPoint>()).OrderBy(x => x.SortNo ?? 0))
{
var time = (double)(pt.TimeMin ?? 0);
if (pt.UpperTemp != null) UpperTempValues.Add(new ObservablePoint(time, (double)pt.UpperTemp.Value));
if (pt.LowerTemp != null) LowerTempValues.Add(new ObservablePoint(time, (double)pt.LowerTemp.Value));
if (pt.TorqueS != null) TorqueValues.Add(new ObservablePoint(time, (double)pt.TorqueS.Value));
}
if (UpperTempValues.Count > 0) UpperMoldTemp = UpperTempValues[^1].Y ?? 0;
if (LowerTempValues.Count > 0) LowerMoldTemp = LowerTempValues[^1].Y ?? 0;
if (TorqueValues.Count > 0) TorqueS = TorqueValues[^1].Y ?? 0;
RecalculateOverallInspectResult();
NotifySaveStateChanged();
}
finally
{
_isLoadingForm = false;
}
if (UpperTempValues.Count > 0) UpperMoldTemp = UpperTempValues[^1].Y ?? 0;
if (LowerTempValues.Count > 0) LowerMoldTemp = LowerTempValues[^1].Y ?? 0;
if (TorqueValues.Count > 0) TorqueS = TorqueValues[^1].Y ?? 0;
await Task.CompletedTask;
}
@@ -1859,6 +2155,12 @@ public class RubberQuickTestOperationViewModel : BaseViewModel, INavigationAware
}
if (_networkStatusToken != null)
{
_eventAggregator.GetEvent<NetworkStatusChangedEvent>().Unsubscribe(_networkStatusToken);
_networkStatusToken = null;
}
base.CleanUp();
}

View File

@@ -49,7 +49,9 @@ public class RubberQuickTestRecordListViewModel : BaseViewModel
public DelegateCommand ResetCommand { get; }
public DelegateCommand AddCommand { get; }
public DelegateCommand<RubberQuickTestRecordListRow> ViewDetailCommand { get; }
public DelegateCommand<RubberQuickTestRecordListRow> EditCommand { get; }
public DelegateCommand<RubberQuickTestRecordListRow> DeleteCommand { get; }
public DelegateCommand<RubberQuickTestRecordListRow> SyncCommand { get; }
public DelegateCommand PrevPageCommand { get; }
public DelegateCommand NextPageCommand { get; }
@@ -73,9 +75,13 @@ public class RubberQuickTestRecordListViewModel : BaseViewModel
});
AddCommand = new DelegateCommand(OpenAddPage);
ViewDetailCommand = new DelegateCommand<RubberQuickTestRecordListRow>(async r => await ShowDetailAsync(r));
EditCommand = new DelegateCommand<RubberQuickTestRecordListRow>(OpenEditPage, r => r != null && r.CanEdit);
DeleteCommand = new DelegateCommand<RubberQuickTestRecordListRow>(
async r => await DeleteAsync(r),
r => r != null && r.CanDelete);
SyncCommand = new DelegateCommand<RubberQuickTestRecordListRow>(
async r => await SyncAsync(r),
r => r != null && r.CanSync);
PrevPageCommand = new DelegateCommand(async () => { if (PageNo > 1) { PageNo--; await LoadAsync(); } });
NextPageCommand = new DelegateCommand(async () => { if ((long)PageNo * PageSize < Total) { PageNo++; await LoadAsync(); } });
@@ -137,6 +143,27 @@ public class RubberQuickTestRecordListViewModel : BaseViewModel
});
}
private void OpenEditPage(RubberQuickTestRecordListRow? row)
{
if (row == null || !row.CanEdit || string.IsNullOrWhiteSpace(row.LocalId))
return;
if (_recordService.GetByLocalId(row.LocalId) == null)
{
Growl.Warning("未找到快检记录");
return;
}
var label = row.RecordNo ?? row.LocalId;
_eventAggregator.GetEvent<TabSourceSelectedEvent>().Publish(new TabSource
{
Name = $"编辑快检记录 {label}",
Icon = "\ue7de",
ViewName = "RubberQuickTestOperationView",
NavigationParameter = new NavigationParameters { { "editLocalId", row.LocalId } }
});
}
private async Task DeleteAsync(RubberQuickTestRecordListRow? row)
{
if (row == null || !row.CanDelete || string.IsNullOrWhiteSpace(row.LocalId))
@@ -144,7 +171,7 @@ public class RubberQuickTestRecordListViewModel : BaseViewModel
var label = row.RecordNo ?? row.LocalId;
var confirm = System.Windows.MessageBox.Show(
$"确定删除同步失败的快检记录「{label}」?\n此操作仅删除本地记录不可恢复。",
$"确定删除同步的快检记录「{label}」?\n此操作仅删除本地记录不可恢复。",
"确认删除",
System.Windows.MessageBoxButton.YesNo,
System.Windows.MessageBoxImage.Warning);
@@ -153,14 +180,14 @@ public class RubberQuickTestRecordListViewModel : BaseViewModel
try
{
if (_recordService.DeleteFailedLocal(row.LocalId))
if (_recordService.DeleteUnsyncedLocal(row.LocalId))
{
Growl.Success("删除成功");
await LoadAsync();
}
else
{
Growl.Warning("仅同步失败的本地记录可删除");
Growl.Warning("仅同步的本地记录可删除");
}
}
catch (Exception ex)
@@ -169,6 +196,36 @@ public class RubberQuickTestRecordListViewModel : BaseViewModel
}
}
private async Task SyncAsync(RubberQuickTestRecordListRow? row)
{
if (row == null || !row.CanSync || string.IsNullOrWhiteSpace(row.LocalId))
return;
try
{
IsLoading = true;
var result = await _recordService.SyncLocalAsync(row.LocalId);
if (result.Success)
{
var no = result.RecordNo ?? row.RecordNo ?? row.LocalId;
Growl.Success($"同步成功,快检记录号:{no}");
await LoadAsync();
}
else
{
Growl.Warning(result.Message ?? "同步失败");
}
}
catch (Exception ex)
{
Growl.Error($"同步失败:{ex.Message}");
}
finally
{
IsLoading = false;
}
}
private async Task ShowDetailAsync(RubberQuickTestRecordListRow? row)
{
if (row == null) return;