версия 2.0.7: надёжный автоапдейт (CDN) + кнопка проверки + без лимита листания
- UpdateService: проверка через публичный CDN latest.json (тот же хост, что и установщик — надёжнее поддомена git), fallback на Gitea, лог в %TEMP%\elfisa-update.log - Настройки: кнопка «Проверить обновления» (ручной триггер + видимый результат) - Прайс-лист: убран лимит показа (300 → весь прайс/все совпадения одним запросом) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
23f34cc769
commit
4e341f76c3
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#define MyAppName "Электронная Фармация"
|
#define MyAppName "Электронная Фармация"
|
||||||
#define MyAppBrand "ЭльФиСА"
|
#define MyAppBrand "ЭльФиСА"
|
||||||
#define MyAppVersion "2.0.6"
|
#define MyAppVersion "2.0.7"
|
||||||
#define MyAppPublisher "PharmData"
|
#define MyAppPublisher "PharmData"
|
||||||
#define MyAppURL "https://cdn.24pharmdata.ru"
|
#define MyAppURL "https://cdn.24pharmdata.ru"
|
||||||
#define MyAppSupportURL "https://24pharmdata.ru"
|
#define MyAppSupportURL "https://24pharmdata.ru"
|
||||||
|
|||||||
@ -5,9 +5,9 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||||
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
|
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
|
||||||
<Version>2.0.6</Version>
|
<Version>2.0.7</Version>
|
||||||
<AssemblyVersion>2.0.6.0</AssemblyVersion>
|
<AssemblyVersion>2.0.7.0</AssemblyVersion>
|
||||||
<FileVersion>2.0.6.0</FileVersion>
|
<FileVersion>2.0.7.0</FileVersion>
|
||||||
<Product>ЭльФиСА — Электронная Фармация</Product>
|
<Product>ЭльФиСА — Электронная Фармация</Product>
|
||||||
<Company>PharmData</Company>
|
<Company>PharmData</Company>
|
||||||
<!-- Кросс-платформенная публикация задаётся флагами CLI (RID + self-contained). -->
|
<!-- Кросс-платформенная публикация задаётся флагами CLI (RID + self-contained). -->
|
||||||
|
|||||||
@ -128,7 +128,9 @@ public partial class PriceListViewModel : ViewModelBase
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
Busy = true;
|
Busy = true;
|
||||||
var resp = await _api.GetPriceSummaryAsync(Search, limit: 300, priceListId: SelectedPriceList?.PriceListId);
|
// Без лимита показа: тянем весь прайс/все совпадения одним запросом (сервер
|
||||||
|
// при одном большом запросе прогоняет дедупликацию один раз, без COUNT).
|
||||||
|
var resp = await _api.GetPriceSummaryAsync(Search, limit: 500000, priceListId: SelectedPriceList?.PriceListId);
|
||||||
RebuildIndex(resp.Summary ?? new());
|
RebuildIndex(resp.Summary ?? new());
|
||||||
Total = resp.TotalDrugs;
|
Total = resp.TotalDrugs;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
xmlns:vm="using:Elfisa.Avalonia.ViewModels"
|
xmlns:vm="using:Elfisa.Avalonia.ViewModels"
|
||||||
x:Class="Elfisa.Avalonia.Views.SettingsWindow"
|
x:Class="Elfisa.Avalonia.Views.SettingsWindow"
|
||||||
x:DataType="vm:SettingsViewModel"
|
x:DataType="vm:SettingsViewModel"
|
||||||
Width="460" Height="360" CanResize="False"
|
Width="460" Height="440" CanResize="False"
|
||||||
WindowStartupLocation="CenterOwner"
|
WindowStartupLocation="CenterOwner"
|
||||||
Background="{DynamicResource Bg}"
|
Background="{DynamicResource Bg}"
|
||||||
Title="Настройки">
|
Title="Настройки">
|
||||||
@ -26,6 +26,15 @@
|
|||||||
<ComboBox ItemsSource="{Binding Locations}" SelectedItem="{Binding SelectedLocation}" HorizontalAlignment="Stretch"/>
|
<ComboBox ItemsSource="{Binding Locations}" SelectedItem="{Binding SelectedLocation}" HorizontalAlignment="Stretch"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel Spacing="6">
|
||||||
|
<TextBlock Text="Обновления" Classes="label"/>
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="10">
|
||||||
|
<Button Content="Проверить обновления" Click="OnCheckUpdate"/>
|
||||||
|
<TextBlock x:Name="UpdateStatus" VerticalAlignment="Center" TextWrapping="Wrap"
|
||||||
|
Foreground="{DynamicResource Muted}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Spacing="10" Margin="0,8,0,0">
|
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Spacing="10" Margin="0,8,0,0">
|
||||||
<Button Content="Отмена" Click="OnCancel" Padding="18,9"/>
|
<Button Content="Отмена" Click="OnCancel" Padding="18,9"/>
|
||||||
<Button Classes="primary" Content="Сохранить" Click="OnSave"/>
|
<Button Classes="primary" Content="Сохранить" Click="OnSave"/>
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
@ -12,6 +14,28 @@ public partial class SettingsWindow : Window
|
|||||||
{
|
{
|
||||||
public SettingsWindow() => AvaloniaXamlLoader.Load(this);
|
public SettingsWindow() => AvaloniaXamlLoader.Load(this);
|
||||||
|
|
||||||
|
private async void OnCheckUpdate(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
var status = this.FindControl<TextBlock>("UpdateStatus");
|
||||||
|
var current = Assembly.GetEntryAssembly()?.GetName().Version ?? new Version(0, 0, 0, 0);
|
||||||
|
if (status is not null) status.Text = "Проверяем…";
|
||||||
|
var info = await UpdateService.CheckAsync(current);
|
||||||
|
if (info is null)
|
||||||
|
{
|
||||||
|
if (status is not null) status.Text = "Не удалось проверить (нет сети).";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!info.Available)
|
||||||
|
{
|
||||||
|
if (status is not null) status.Text = $"У вас последняя версия ({info.CurrentVersion}).";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (status is not null) status.Text = $"Доступна {info.LatestVersion} — открываю…";
|
||||||
|
var win = new UpdateWindow();
|
||||||
|
win.DataContext = new UpdateViewModel(info, win.Close);
|
||||||
|
await win.ShowDialog(this);
|
||||||
|
}
|
||||||
|
|
||||||
private void OnSave(object? sender, RoutedEventArgs e)
|
private void OnSave(object? sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (DataContext is SettingsViewModel vm)
|
if (DataContext is SettingsViewModel vm)
|
||||||
|
|||||||
@ -20,6 +20,9 @@ public sealed class UpdateInfo
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static class UpdateService
|
public static class UpdateService
|
||||||
{
|
{
|
||||||
|
// Первичный источник — публичный CDN (тот же хост, откуда качается установщик;
|
||||||
|
// надёжнее приватных API и отдельных поддоменов). Fallback — Gitea Releases.
|
||||||
|
private const string LatestJsonUrl = "https://cdn.24pharmdata.ru/latest.json";
|
||||||
private const string ReleasesLatest =
|
private const string ReleasesLatest =
|
||||||
"https://git.24pharmdata.ru/api/v1/repos/pharmdata/elfisa-pharmacy/releases/latest";
|
"https://git.24pharmdata.ru/api/v1/repos/pharmdata/elfisa-pharmacy/releases/latest";
|
||||||
|
|
||||||
@ -28,6 +31,41 @@ public static class UpdateService
|
|||||||
|
|
||||||
/// <summary>Проверяет наличие новой версии. Возвращает null при офлайне/ошибке (не мешаем работе).</summary>
|
/// <summary>Проверяет наличие новой версии. Возвращает null при офлайне/ошибке (не мешаем работе).</summary>
|
||||||
public static async Task<UpdateInfo?> CheckAsync(Version current)
|
public static async Task<UpdateInfo?> CheckAsync(Version current)
|
||||||
|
{
|
||||||
|
var info = await TryCdnAsync(current).ConfigureAwait(false)
|
||||||
|
?? await TryGiteaAsync(current).ConfigureAwait(false);
|
||||||
|
Log(info is null
|
||||||
|
? $"current={current}: проверка не удалась (нет ответа CDN и Gitea)"
|
||||||
|
: $"current={current} latest={info.LatestVersion} available={info.Available}");
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CDN latest.json: {"version":"2.0.7","setup":"https://cdn.24pharmdata.ru/ElfisaPharmacy-Setup.exe"}
|
||||||
|
private static async Task<UpdateInfo?> TryCdnAsync(Version current)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(8) };
|
||||||
|
var json = await http.GetStringAsync(LatestJsonUrl).ConfigureAwait(false);
|
||||||
|
using var doc = JsonDocument.Parse(json);
|
||||||
|
var root = doc.RootElement;
|
||||||
|
var ver = root.TryGetProperty("version", out var v) ? v.GetString() : null;
|
||||||
|
var latest = ParseVersion(ver);
|
||||||
|
if (latest is null) return null;
|
||||||
|
var setup = root.TryGetProperty("setup", out var s) ? s.GetString() : null;
|
||||||
|
return new UpdateInfo
|
||||||
|
{
|
||||||
|
Available = latest > current,
|
||||||
|
CurrentVersion = current.ToString(),
|
||||||
|
LatestVersion = latest.ToString(),
|
||||||
|
ReleaseUrl = "",
|
||||||
|
SetupUrl = string.IsNullOrWhiteSpace(setup) ? SetupUrl : setup!,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception ex) { Log("CDN latest.json недоступен: " + ex.Message); return null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<UpdateInfo?> TryGiteaAsync(Version current)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -49,10 +87,18 @@ public static class UpdateService
|
|||||||
SetupUrl = SetupUrl,
|
SetupUrl = SetupUrl,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex) { Log("Gitea releases/latest недоступен: " + ex.Message); return null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Лог проверки в %TEMP%\elfisa-update.log — для диагностики на машине клиента.</summary>
|
||||||
|
private static void Log(string msg)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
return null;
|
var path = Path.Combine(Path.GetTempPath(), "elfisa-update.log");
|
||||||
|
File.AppendAllText(path, $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} {msg}{Environment.NewLine}");
|
||||||
}
|
}
|
||||||
|
catch { /* лог не критичен */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Скачивает установщик с CDN во временный файл. Возвращает путь.</summary>
|
/// <summary>Скачивает установщик с CDN во временный файл. Возвращает путь.</summary>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user