Добавьте файлы проекта.

This commit is contained in:
Курнат Андрей
2026-04-04 10:52:30 +03:00
parent 9b34a92f15
commit 5a55bc5f4c
30 changed files with 3446 additions and 0 deletions

View File

@@ -0,0 +1,266 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CRAWLER.Infrastructure;
using CRAWLER.Models;
using CRAWLER.Services;
namespace CRAWLER.ViewModels;
internal sealed class MainWindowViewModel : ObservableObject
{
private readonly InstrumentCatalogService _catalogService;
private readonly IPdfOpener _pdfOpener;
private InstrumentSummary _selectedSummary;
private InstrumentRecord _selectedInstrument;
private string _searchText;
private int _pagesToScan;
private string _statusText;
private bool _isBusy;
private CancellationTokenSource _selectionCancellationTokenSource;
public MainWindowViewModel(InstrumentCatalogService catalogService, IPdfOpener pdfOpener)
{
_catalogService = catalogService;
_pdfOpener = pdfOpener;
_pagesToScan = _catalogService.DefaultPagesToScan;
_statusText = "Готово.";
Instruments = new ObservableCollection<InstrumentSummary>();
}
public ObservableCollection<InstrumentSummary> Instruments { get; }
public InstrumentSummary SelectedSummary
{
get { return _selectedSummary; }
set
{
if (SetProperty(ref _selectedSummary, value))
{
_ = LoadSelectedInstrumentAsync(value?.Id);
}
}
}
public InstrumentRecord SelectedInstrument
{
get { return _selectedInstrument; }
private set { SetProperty(ref _selectedInstrument, value); }
}
public string SearchText
{
get { return _searchText; }
set { SetProperty(ref _searchText, value); }
}
public int PagesToScan
{
get { return _pagesToScan; }
set { SetProperty(ref _pagesToScan, value < 1 ? 1 : value); }
}
public string StatusText
{
get { return _statusText; }
private set { SetProperty(ref _statusText, value); }
}
public bool IsBusy
{
get { return _isBusy; }
private set { SetProperty(ref _isBusy, value); }
}
public async Task InitializeAsync()
{
await RunBusyAsync(async () =>
{
StatusText = "Подготовка базы данных...";
await _catalogService.InitializeAsync(CancellationToken.None);
await RefreshAsync();
});
}
public async Task RefreshAsync(long? selectId = null)
{
await RunBusyAsync(async () =>
{
StatusText = "Загрузка списка записей...";
var items = await _catalogService.SearchAsync(SearchText, CancellationToken.None);
Instruments.Clear();
foreach (var item in items)
{
Instruments.Add(item);
}
if (Instruments.Count == 0)
{
SelectedInstrument = null;
SelectedSummary = null;
StatusText = "Записи не найдены.";
return;
}
var summary = selectId.HasValue
? Instruments.FirstOrDefault(item => item.Id == selectId.Value)
: SelectedSummary == null
? Instruments.FirstOrDefault()
: Instruments.FirstOrDefault(item => item.Id == SelectedSummary.Id) ?? Instruments.FirstOrDefault();
SelectedSummary = summary;
StatusText = $"Загружено записей: {Instruments.Count}.";
});
}
public async Task<SyncResult> SyncAsync()
{
SyncResult result = null;
await RunBusyAsync(async () =>
{
var progress = new Progress<string>(message => StatusText = message);
result = await _catalogService.SyncFromSiteAsync(PagesToScan, progress, CancellationToken.None);
await RefreshAsync(SelectedSummary?.Id);
});
return result;
}
public InstrumentRecord CreateNewDraft()
{
return new InstrumentRecord
{
SourceSystem = "Manual"
};
}
public InstrumentRecord CreateDraftFromSelected()
{
return SelectedInstrument?.Clone();
}
public async Task<long> SaveAsync(InstrumentRecord draft, System.Collections.Generic.IEnumerable<string> pendingPdfPaths)
{
long id = 0;
await RunBusyAsync(async () =>
{
StatusText = "Сохранение записи...";
id = await _catalogService.SaveInstrumentAsync(draft, pendingPdfPaths, CancellationToken.None);
await RefreshAsync(id);
StatusText = "Изменения сохранены.";
});
return id;
}
public async Task DeleteSelectedAsync()
{
if (SelectedInstrument == null)
{
return;
}
var deletedId = SelectedInstrument.Id;
await RunBusyAsync(async () =>
{
StatusText = "Удаление записи...";
await _catalogService.DeleteInstrumentAsync(SelectedInstrument, CancellationToken.None);
await RefreshAsync();
StatusText = $"Запись {deletedId} удалена.";
});
}
public async Task AddAttachmentsToSelectedAsync(System.Collections.Generic.IEnumerable<string> paths)
{
if (SelectedInstrument == null)
{
return;
}
await RunBusyAsync(async () =>
{
StatusText = "Копирование PDF-файлов...";
await _catalogService.AddManualAttachmentsAsync(SelectedInstrument.Id, SelectedInstrument.RegistryNumber, paths, CancellationToken.None);
await LoadSelectedInstrumentAsync(SelectedInstrument.Id);
StatusText = "PDF-файлы добавлены.";
});
}
public async Task RemoveAttachmentAsync(PdfAttachment attachment)
{
if (attachment == null || SelectedInstrument == null)
{
return;
}
await RunBusyAsync(async () =>
{
StatusText = "Удаление PDF-файла...";
await _catalogService.RemoveAttachmentAsync(attachment, CancellationToken.None);
await LoadSelectedInstrumentAsync(SelectedInstrument.Id);
StatusText = "PDF-файл удалён.";
});
}
public void OpenAttachment(PdfAttachment attachment)
{
_pdfOpener.OpenAttachment(attachment);
}
public void OpenSourceUrl()
{
if (SelectedInstrument != null && !string.IsNullOrWhiteSpace(SelectedInstrument.DetailUrl))
{
_pdfOpener.OpenUri(SelectedInstrument.DetailUrl);
}
}
private async Task LoadSelectedInstrumentAsync(long? id)
{
_selectionCancellationTokenSource?.Cancel();
_selectionCancellationTokenSource = new CancellationTokenSource();
var token = _selectionCancellationTokenSource.Token;
if (!id.HasValue)
{
SelectedInstrument = null;
return;
}
try
{
var instrument = await _catalogService.GetByIdAsync(id.Value, token);
if (!token.IsCancellationRequested)
{
SelectedInstrument = instrument;
}
}
catch (OperationCanceledException)
{
}
}
private async Task RunBusyAsync(Func<Task> action)
{
if (IsBusy)
{
return;
}
try
{
IsBusy = true;
await action();
}
finally
{
IsBusy = false;
}
}
}