This commit is contained in:
Курнат Андрей
2026-03-22 21:44:29 +03:00
parent a47a7a5a3b
commit 7bbca6ba55
750 changed files with 13718 additions and 43 deletions

View File

@@ -0,0 +1,566 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
namespace XLAB2
{
internal sealed class EkzDirectoryWindowViewModel : ObservableObject
{
private readonly IEkzDirectoryDialogService _dialogService;
private readonly EkzDirectoryService _service;
private List<EkzDirectoryItem> _ekzCache;
private bool _isApplyingFilter;
private bool _isBusy;
private string _searchText;
private EkzDirectoryItem _selectedEkz;
private int _selectedOwnerFilterId;
private string _statusText;
public EkzDirectoryWindowViewModel(EkzDirectoryService service, IEkzDirectoryDialogService dialogService)
{
_service = service;
_dialogService = dialogService;
_ekzCache = new List<EkzDirectoryItem>();
EkzItems = new ObservableCollection<EkzDirectoryItem>();
EkzMkItems = new ObservableCollection<EkzMkDirectoryItem>();
OwnerFilterItems = new ObservableCollection<DirectoryLookupItem>();
OwnerFilterItems.Add(new DirectoryLookupItem { Id = 0, Name = "Все организации" });
AddEkzCommand = new RelayCommand(delegate { AddEkzAsync(); }, delegate { return !IsBusy; });
EditEkzCommand = new RelayCommand(delegate { EditEkzAsync(); }, delegate { return !IsBusy && SelectedEkz != null; });
DeleteEkzCommand = new RelayCommand(delegate { DeleteEkzWithPreviewAsync(); }, delegate { return !IsBusy && SelectedEkz != null; });
RefreshCommand = new RelayCommand(delegate { RefreshAsync(); }, delegate { return !IsBusy; });
UpdateStatus();
}
public ICommand AddEkzCommand { get; private set; }
public ICommand DeleteEkzCommand { get; private set; }
public ICommand EditEkzCommand { get; private set; }
public ObservableCollection<EkzDirectoryItem> EkzItems { get; private set; }
public ObservableCollection<EkzMkDirectoryItem> EkzMkItems { get; private set; }
public bool IsBusy
{
get { return _isBusy; }
private set
{
if (SetProperty(ref _isBusy, value))
{
RaiseCommandStates();
}
}
}
public ObservableCollection<DirectoryLookupItem> OwnerFilterItems { get; private set; }
public ICommand RefreshCommand { get; private set; }
public string SearchText
{
get { return _searchText; }
set
{
if (SetProperty(ref _searchText, value))
{
ApplyFilter(SelectedEkz == null ? (int?)null : SelectedEkz.Id);
}
}
}
public EkzDirectoryItem SelectedEkz
{
get { return _selectedEkz; }
set
{
if (SetProperty(ref _selectedEkz, value))
{
RaiseCommandStates();
if (!_isApplyingFilter)
{
LoadEkzMkForSelection();
}
UpdateStatus();
}
}
}
public int SelectedOwnerFilterId
{
get { return _selectedOwnerFilterId; }
set
{
if (SetProperty(ref _selectedOwnerFilterId, value))
{
ApplyFilter(SelectedEkz == null ? (int?)null : SelectedEkz.Id);
}
}
}
public string StatusText
{
get { return _statusText; }
private set { SetProperty(ref _statusText, value); }
}
public async Task InitializeAsync()
{
await ExecuteBusyOperationAsync(delegate { return RefreshCoreAsync(null); });
}
private void AddEkzAsync()
{
var result = _dialogService.ShowEkzEditDialog(new EkzDirectoryItem(), true, _ekzCache.ToList(), _service);
if (result == null)
{
return;
}
RunMutationOperation(async delegate
{
var createdId = await Task.Run(delegate { return _service.AddEkzItem(result); });
await RefreshCoreAsync(createdId);
_dialogService.ShowInfo("Запись EKZ добавлена.");
});
}
private void ApplyFilter(int? preferredId)
{
var filteredItems = _ekzCache.Where(delegate(EkzDirectoryItem item)
{
return MatchesOwnerFilter(item) && MatchesSearch(item);
}).ToList();
_isApplyingFilter = true;
try
{
EkzItems.Clear();
foreach (var item in filteredItems)
{
EkzItems.Add(item);
}
SelectedEkz = preferredId.HasValue
? EkzItems.FirstOrDefault(delegate(EkzDirectoryItem item) { return item.Id == preferredId.Value; })
: EkzItems.FirstOrDefault();
}
finally
{
_isApplyingFilter = false;
}
if (!IsBusy)
{
LoadEkzMkForSelection();
}
UpdateStatus();
}
private static EkzDirectoryItem CloneEkz(EkzDirectoryItem source)
{
return new EkzDirectoryItem
{
Id = source.Id,
TypeSizeId = source.TypeSizeId,
MeasurementAreaName = source.MeasurementAreaName,
InstrumentName = source.InstrumentName,
TypeName = source.TypeName,
RangeText = source.RangeText,
AccuracyText = source.AccuracyText,
RegistryNumber = source.RegistryNumber,
OwnerOrganizationId = source.OwnerOrganizationId,
OwnerOrganizationName = source.OwnerOrganizationName,
SerialNumber = source.SerialNumber,
InventoryNumber = source.InventoryNumber,
Notes = source.Notes
};
}
private async void DeleteEkzWithPreviewAsync()
{
if (SelectedEkz == null)
{
return;
}
var selected = SelectedEkz;
EkzDeletePreview preview;
try
{
IsBusy = true;
preview = await Task.Run(delegate { return _service.GetEkzDeletePreview(selected.Id); });
}
catch (InvalidOperationException ex)
{
_dialogService.ShowWarning(ex.Message);
return;
}
catch (Exception ex)
{
_dialogService.ShowError(ex.Message);
return;
}
finally
{
IsBusy = false;
}
if (preview == null)
{
return;
}
if (!preview.CanDelete)
{
_dialogService.ShowWarning(preview.WarningMessage);
return;
}
if (!_dialogService.Confirm(BuildDeleteConfirmationMessage(selected, preview)))
{
return;
}
RunMutationOperation(async delegate
{
var result = await Task.Run(delegate { return _service.DeleteEkzItem(selected.Id); });
if (!result.IsDeleted)
{
_dialogService.ShowWarning(result.WarningMessage);
return;
}
await RefreshCoreAsync(null);
_dialogService.ShowInfo(BuildDeleteResultMessage(result));
});
}
private async void DeleteEkzAsync()
{
if (SelectedEkz == null)
{
return;
}
var selected = SelectedEkz;
EkzDeletePreview preview;
try
{
IsBusy = true;
preview = await Task.Run(delegate { return _service.GetEkzDeletePreview(selected.Id); });
}
catch (InvalidOperationException ex)
{
_dialogService.ShowWarning(ex.Message);
return;
}
catch (Exception ex)
{
_dialogService.ShowError(ex.Message);
return;
}
finally
{
IsBusy = false;
}
if (preview == null)
{
return;
}
if (!preview.CanDelete)
{
_dialogService.ShowWarning(preview.WarningMessage);
return;
}
if (!_dialogService.Confirm(string.Format("Удалить экземпляр \"{0}\"?", selected.SerialNumber)))
{
return;
}
RunMutationOperation(async delegate
{
var result = await Task.Run(delegate { return _service.DeleteEkzItem(selected.Id); });
if (!result.IsDeleted)
{
_dialogService.ShowWarning(result.WarningMessage);
return;
}
await RefreshCoreAsync(null);
_dialogService.ShowInfo("Запись EKZ удалена.");
});
}
private void EditEkzAsync()
{
if (SelectedEkz == null)
{
return;
}
var result = _dialogService.ShowEkzEditDialog(CloneEkz(SelectedEkz), false, _ekzCache.ToList(), _service);
if (result == null)
{
return;
}
RunMutationOperation(async delegate
{
await Task.Run(delegate { _service.UpdateEkzItem(result); });
await RefreshCoreAsync(result.Id);
_dialogService.ShowInfo("Запись EKZ обновлена.");
});
}
private async Task ExecuteBusyOperationAsync(Func<Task> operation)
{
try
{
IsBusy = true;
await operation();
}
catch (Exception ex)
{
_dialogService.ShowError(ex.Message);
}
finally
{
IsBusy = false;
}
}
private async Task ExecuteMutationOperationAsync(Func<Task> operation)
{
try
{
IsBusy = true;
await operation();
}
catch (InvalidOperationException ex)
{
_dialogService.ShowWarning(ex.Message);
}
catch (Exception ex)
{
_dialogService.ShowError(ex.Message);
}
finally
{
IsBusy = false;
}
}
private string[] GetSearchTokens()
{
return (SearchText ?? string.Empty)
.Split(new[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
.Select(delegate(string token) { return token.Trim().ToUpperInvariant(); })
.Where(delegate(string token) { return token.Length > 0; })
.ToArray();
}
private void LoadEkzMkForSelection()
{
if (IsBusy)
{
return;
}
RunBusyOperation(async delegate
{
if (SelectedEkz == null)
{
EkzMkItems.Clear();
UpdateStatus();
return;
}
await RefreshEkzMkCoreAsync(SelectedEkz.Id);
});
}
private bool MatchesOwnerFilter(EkzDirectoryItem item)
{
return SelectedOwnerFilterId <= 0
|| (item != null && item.OwnerOrganizationId == SelectedOwnerFilterId);
}
private bool MatchesSearch(EkzDirectoryItem item)
{
var tokens = GetSearchTokens();
if (tokens.Length == 0)
{
return true;
}
var haystack = string.Join(
" ",
new[]
{
item == null ? null : item.Id.ToString(),
item == null ? null : item.OwnerOrganizationName,
item == null ? null : item.MeasurementAreaName,
item == null ? null : item.InstrumentName,
item == null ? null : item.TypeName,
item == null ? null : item.RangeText,
item == null ? null : item.AccuracyText,
item == null ? null : item.RegistryNumber,
item == null ? null : item.SerialNumber,
item == null ? null : item.InventoryNumber,
item == null ? null : item.Notes
}.Where(delegate(string value) { return !string.IsNullOrWhiteSpace(value); }))
.ToUpperInvariant();
return tokens.All(delegate(string token) { return haystack.IndexOf(token, StringComparison.Ordinal) >= 0; });
}
private async Task RefreshCoreAsync(int? idToSelect)
{
var currentSelectedId = idToSelect ?? (SelectedEkz == null ? (int?)null : SelectedEkz.Id);
var currentOwnerFilterId = SelectedOwnerFilterId;
var ekzTask = Task.Run(delegate { return _service.LoadEkzItems(); });
var ownerTask = Task.Run(delegate { return _service.LoadFrpdReferences(); });
await Task.WhenAll(ekzTask, ownerTask);
_ekzCache = ekzTask.Result.ToList();
RebuildOwnerFilters(ownerTask.Result, currentOwnerFilterId);
ApplyFilter(currentSelectedId);
if (SelectedEkz == null)
{
EkzMkItems.Clear();
UpdateStatus();
return;
}
await RefreshEkzMkCoreAsync(SelectedEkz.Id);
UpdateStatus();
}
private async Task RefreshEkzMkCoreAsync(int instrumentId)
{
var items = await Task.Run(delegate { return _service.LoadEkzMkItems(instrumentId); });
EkzMkItems.Clear();
foreach (var item in items)
{
EkzMkItems.Add(item);
}
}
private void RebuildOwnerFilters(IReadOnlyList<DirectoryLookupItem> owners, int selectedId)
{
OwnerFilterItems.Clear();
OwnerFilterItems.Add(new DirectoryLookupItem { Id = 0, Name = "Все организации" });
foreach (var owner in owners ?? Array.Empty<DirectoryLookupItem>())
{
OwnerFilterItems.Add(owner);
}
_selectedOwnerFilterId = OwnerFilterItems.Any(delegate(DirectoryLookupItem item) { return item.Id == selectedId; })
? selectedId
: 0;
OnPropertyChanged("SelectedOwnerFilterId");
}
private void RefreshAsync()
{
RunBusyOperation(delegate { return RefreshCoreAsync(SelectedEkz == null ? (int?)null : SelectedEkz.Id); });
}
private void RaiseCommandStates()
{
((RelayCommand)AddEkzCommand).RaiseCanExecuteChanged();
((RelayCommand)EditEkzCommand).RaiseCanExecuteChanged();
((RelayCommand)DeleteEkzCommand).RaiseCanExecuteChanged();
((RelayCommand)RefreshCommand).RaiseCanExecuteChanged();
}
private async void RunBusyOperation(Func<Task> operation)
{
try
{
await ExecuteBusyOperationAsync(operation);
}
catch (Exception ex)
{
IsBusy = false;
_dialogService.ShowError(ex.Message);
}
}
private async void RunMutationOperation(Func<Task> operation)
{
try
{
await ExecuteMutationOperationAsync(operation);
}
catch (Exception ex)
{
IsBusy = false;
_dialogService.ShowError(ex.Message);
}
}
private static string BuildDeleteConfirmationMessage(EkzDirectoryItem selected, EkzDeletePreview preview)
{
return string.Format(
"Удалить экземпляр \"{0}\"?{1}{1}{2}",
selected == null || string.IsNullOrWhiteSpace(selected.SerialNumber) ? "(без номера)" : selected.SerialNumber,
Environment.NewLine,
preview == null ? string.Empty : preview.ConfirmationMessage ?? string.Empty);
}
private static string BuildDeleteResultMessage(EkzDeleteResult result)
{
var impacts = result == null || result.ImpactItems == null
? new List<EkzDeleteImpactItem>()
: result.ImpactItems.Where(delegate(EkzDeleteImpactItem item) { return item != null && item.RowCount > 0; }).ToList();
if (impacts.Count == 0)
{
return "Запись EKZ удалена.";
}
return "Удалены записи: " + string.Join(", ", impacts.Select(delegate(EkzDeleteImpactItem item)
{
return string.Format("{0}: {1}", item.TableName, item.RowCount);
})) + ".";
}
private void UpdateStatus()
{
var searchPrefix = string.IsNullOrWhiteSpace(SearchText)
? string.Empty
: string.Format("Поиск: \"{0}\". ", SearchText.Trim());
var ownerName = OwnerFilterItems.FirstOrDefault(delegate(DirectoryLookupItem item) { return item.Id == SelectedOwnerFilterId; });
var ownerPrefix = SelectedOwnerFilterId <= 0 || ownerName == null
? string.Empty
: string.Format("Владелец: \"{0}\". ", ownerName.Name);
StatusText = string.Format(
"{0}{1}EKZ: {2}/{3}. EKZMK: {4}.",
searchPrefix,
ownerPrefix,
EkzItems.Count,
_ekzCache.Count,
EkzMkItems.Count);
}
}
}