������� �� Avalonia 2.0 (�����-���������, ����������, �������� ��������) #1
@ -123,8 +123,8 @@
|
|||||||
<Setter Property="Padding" Value="0"/>
|
<Setter Property="Padding" Value="0"/>
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="ListBox.topnav ListBoxItem">
|
<Style Selector="ListBox.topnav ListBoxItem">
|
||||||
<Setter Property="Padding" Value="10,7"/>
|
<Setter Property="Padding" Value="6,7"/>
|
||||||
<Setter Property="Margin" Value="3,0"/>
|
<Setter Property="Margin" Value="2,0"/>
|
||||||
<Setter Property="CornerRadius" Value="10"/>
|
<Setter Property="CornerRadius" Value="10"/>
|
||||||
<Setter Property="Cursor" Value="Hand"/>
|
<Setter Property="Cursor" Value="Hand"/>
|
||||||
</Style>
|
</Style>
|
||||||
|
|||||||
78
src/Elfisa.Avalonia/ViewModels/LoadPriceViewModel.cs
Normal file
78
src/Elfisa.Avalonia/ViewModels/LoadPriceViewModel.cs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using Elfisa.Core;
|
||||||
|
|
||||||
|
namespace Elfisa.Avalonia.ViewModels;
|
||||||
|
|
||||||
|
/// <summary>«Загрузить» — скачивание актуального прайса с сервера в память.</summary>
|
||||||
|
public partial class LoadPriceViewModel : ViewModelBase
|
||||||
|
{
|
||||||
|
private readonly ApiClient _api = new();
|
||||||
|
|
||||||
|
[ObservableProperty] private bool _busy;
|
||||||
|
[ObservableProperty] private double _progress; // 0..100
|
||||||
|
[ObservableProperty] private string _progressText = "";
|
||||||
|
[ObservableProperty] private string? _result;
|
||||||
|
|
||||||
|
public string LastLoaded =>
|
||||||
|
PriceCache.LoadedAt is { } dt
|
||||||
|
? $"Последняя загрузка: {dt:dd.MM.yyyy HH:mm} — {PriceCache.Items.Count} позиций"
|
||||||
|
: "Прайс ещё не загружался в этой сессии.";
|
||||||
|
|
||||||
|
public LoadPriceViewModel()
|
||||||
|
{
|
||||||
|
_api.SetToken(Session.Current.Token);
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task LoadAsync()
|
||||||
|
{
|
||||||
|
Result = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Busy = true;
|
||||||
|
Progress = 0;
|
||||||
|
ProgressText = "Соединение с сервером…";
|
||||||
|
|
||||||
|
var all = new List<PriceItem>();
|
||||||
|
const int page = 500;
|
||||||
|
int offset = 0, total = 0;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var resp = await _api.GetPriceSummaryAsync(null, limit: page, offset: offset);
|
||||||
|
var batch = resp.Summary ?? new();
|
||||||
|
if (resp.TotalDrugs > 0) total = resp.TotalDrugs;
|
||||||
|
all.AddRange(batch);
|
||||||
|
|
||||||
|
Progress = total > 0 ? Math.Min(100.0, all.Count * 100.0 / total) : 0;
|
||||||
|
ProgressText = total > 0
|
||||||
|
? $"Загружено {all.Count} из {total} позиций…"
|
||||||
|
: $"Загружено {all.Count} позиций…";
|
||||||
|
|
||||||
|
offset += batch.Count;
|
||||||
|
if (batch.Count < page || (total > 0 && all.Count >= total) || offset > 30000)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
PriceCache.Items = all;
|
||||||
|
PriceCache.LoadedAt = DateTime.Now;
|
||||||
|
Progress = 100;
|
||||||
|
ProgressText = "Готово.";
|
||||||
|
|
||||||
|
var suppliers = all.Select(x => x.SupplierName).Where(s => !string.IsNullOrWhiteSpace(s)).Distinct().Count();
|
||||||
|
Result = $"Прайс загружен: {all.Count} позиций от {suppliers} поставщик(ов).";
|
||||||
|
OnPropertyChanged(nameof(LastLoaded));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Result = "Ошибка загрузки: " + ex.Message;
|
||||||
|
ProgressText = "";
|
||||||
|
}
|
||||||
|
finally { Busy = false; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -46,6 +46,7 @@ public partial class ShellViewModel : ViewModelBase
|
|||||||
new("Заказы", "🛒", () => new OrdersViewModel()),
|
new("Заказы", "🛒", () => new OrdersViewModel()),
|
||||||
new("Накладные", "📄", () => new InvoicesViewModel()),
|
new("Накладные", "📄", () => new InvoicesViewModel()),
|
||||||
new("Отчёты", "📊", () => new ReportsViewModel()),
|
new("Отчёты", "📊", () => new ReportsViewModel()),
|
||||||
|
new("Загрузить", "📥", () => new LoadPriceViewModel()),
|
||||||
new("Отправить", "📤", () => new SendOrderViewModel()),
|
new("Отправить", "📤", () => new SendOrderViewModel()),
|
||||||
new("Отказы", "⛔", () => new PlaceholderPageViewModel("Отказы",
|
new("Отказы", "⛔", () => new PlaceholderPageViewModel("Отказы",
|
||||||
"Отказные позиции по заказам. Нужен серверный эндпоинт: данные (RefuseItemsCount) сейчас есть только в локальной БД WinForms-клиента.")),
|
"Отказные позиции по заказам. Нужен серверный эндпоинт: данные (RefuseItemsCount) сейчас есть только в локальной БД WinForms-клиента.")),
|
||||||
|
|||||||
39
src/Elfisa.Avalonia/Views/LoadPriceView.axaml
Normal file
39
src/Elfisa.Avalonia/Views/LoadPriceView.axaml
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:vm="using:Elfisa.Avalonia.ViewModels"
|
||||||
|
xmlns:conv="using:Avalonia.Data.Converters"
|
||||||
|
x:Class="Elfisa.Avalonia.Views.LoadPriceView"
|
||||||
|
x:DataType="vm:LoadPriceViewModel">
|
||||||
|
|
||||||
|
<Grid Margin="24" RowDefinitions="Auto,*">
|
||||||
|
<StackPanel Grid.Row="0" Spacing="2">
|
||||||
|
<TextBlock Text="Загрузить" Classes="h1"/>
|
||||||
|
<TextBlock Text="Скачать актуальный прайс с сервера" Classes="muted"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<Border Grid.Row="1" Classes="card" MaxWidth="560" Padding="30"
|
||||||
|
HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||||
|
<StackPanel Spacing="18" HorizontalAlignment="Center">
|
||||||
|
<Border Width="60" Height="60" CornerRadius="30" Background="{DynamicResource AccentSoft}">
|
||||||
|
<TextBlock Text="📥" FontSize="26" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<TextBlock Text="{Binding LastLoaded}" Classes="muted" HorizontalAlignment="Center" TextAlignment="Center"/>
|
||||||
|
|
||||||
|
<Button Classes="primary" Content="Загрузить прайс" HorizontalAlignment="Center"
|
||||||
|
Padding="28,12" Command="{Binding LoadCommand}" IsEnabled="{Binding !Busy}"/>
|
||||||
|
|
||||||
|
<StackPanel Spacing="6" IsVisible="{Binding Busy}">
|
||||||
|
<ProgressBar Minimum="0" Maximum="100" Value="{Binding Progress}" Height="8" Width="360"/>
|
||||||
|
<TextBlock Text="{Binding ProgressText}" Classes="muted" HorizontalAlignment="Center"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<Border Background="{DynamicResource AccentSoft}" CornerRadius="8" Padding="14,10"
|
||||||
|
IsVisible="{Binding Result, Converter={x:Static conv:ObjectConverters.IsNotNull}}">
|
||||||
|
<TextBlock Text="{Binding Result}" Foreground="{DynamicResource AccentPressed}"
|
||||||
|
TextWrapping="Wrap" TextAlignment="Center"/>
|
||||||
|
</Border>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
9
src/Elfisa.Avalonia/Views/LoadPriceView.axaml.cs
Normal file
9
src/Elfisa.Avalonia/Views/LoadPriceView.axaml.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
|
||||||
|
namespace Elfisa.Avalonia.Views;
|
||||||
|
|
||||||
|
public partial class LoadPriceView : UserControl
|
||||||
|
{
|
||||||
|
public LoadPriceView() => AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
@ -11,9 +11,9 @@
|
|||||||
<Grid ColumnDefinitions="Auto,*,Auto" Margin="18,0">
|
<Grid ColumnDefinitions="Auto,*,Auto" Margin="18,0">
|
||||||
|
|
||||||
<!-- Логотип -->
|
<!-- Логотип -->
|
||||||
<StackPanel Grid.Column="0" VerticalAlignment="Center" Margin="0,0,22,0">
|
<StackPanel Grid.Column="0" VerticalAlignment="Center" Margin="0,0,14,0">
|
||||||
<TextBlock Text="ЭльФиСА" FontSize="19" FontWeight="Bold" Foreground="White"/>
|
<TextBlock Text="ЭльФиСА" FontSize="18" FontWeight="Bold" Foreground="White"/>
|
||||||
<TextBlock Text="Электронная Фармация" Foreground="{DynamicResource SidebarText}" FontSize="10.5"/>
|
<TextBlock Text="Электронная Фармация" Foreground="{DynamicResource SidebarText}" FontSize="10"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<!-- Навигация -->
|
<!-- Навигация -->
|
||||||
@ -26,10 +26,10 @@
|
|||||||
</ListBox.ItemsPanel>
|
</ListBox.ItemsPanel>
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
<DataTemplate x:DataType="vm:NavItem">
|
<DataTemplate x:DataType="vm:NavItem">
|
||||||
<StackPanel Orientation="Vertical" Width="76" Spacing="3">
|
<StackPanel Orientation="Vertical" Width="66" Spacing="2">
|
||||||
<TextBlock Text="{Binding Icon}" FontSize="17" HorizontalAlignment="Center"/>
|
<TextBlock Text="{Binding Icon}" FontSize="16" HorizontalAlignment="Center"/>
|
||||||
<TextBlock Text="{Binding Title}" Foreground="{DynamicResource SidebarText}"
|
<TextBlock Text="{Binding Title}" Foreground="{DynamicResource SidebarText}"
|
||||||
FontSize="11.5" HorizontalAlignment="Center"
|
FontSize="11" HorizontalAlignment="Center"
|
||||||
TextTrimming="CharacterEllipsis"/>
|
TextTrimming="CharacterEllipsis"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
@ -37,7 +37,7 @@
|
|||||||
</ListBox>
|
</ListBox>
|
||||||
|
|
||||||
<!-- Пользователь + выход -->
|
<!-- Пользователь + выход -->
|
||||||
<StackPanel Grid.Column="2" Orientation="Horizontal" Spacing="14" VerticalAlignment="Center" Margin="18,0,0,0">
|
<StackPanel Grid.Column="2" Orientation="Horizontal" Spacing="12" VerticalAlignment="Center" Margin="8,0,0,0">
|
||||||
<StackPanel VerticalAlignment="Center">
|
<StackPanel VerticalAlignment="Center">
|
||||||
<TextBlock Text="{Binding UserName}" Foreground="White" FontSize="12" FontWeight="SemiBold"
|
<TextBlock Text="{Binding UserName}" Foreground="White" FontSize="12" FontWeight="SemiBold"
|
||||||
HorizontalAlignment="Right" TextTrimming="CharacterEllipsis"/>
|
HorizontalAlignment="Right" TextTrimming="CharacterEllipsis"/>
|
||||||
|
|||||||
9
src/Elfisa.Core/PriceCache.cs
Normal file
9
src/Elfisa.Core/PriceCache.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace Elfisa.Core;
|
||||||
|
|
||||||
|
/// <summary>Загруженный прайс в памяти (наполняется разделом «Загрузить»).</summary>
|
||||||
|
public static class PriceCache
|
||||||
|
{
|
||||||
|
public static List<PriceItem> Items { get; set; } = new();
|
||||||
|
public static DateTime? LoadedAt { get; set; }
|
||||||
|
public static bool HasData => Items.Count > 0;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user