using AIK.Common.Language; using AIK.Models; using AIK.Models.ApiModels.Record; using AIK.Service.IService; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using HidSharp.Utility; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; namespace AIK.ViewModels.UserKeyRecord { public partial class UserKeyRecordViewModel : ObservableObject { private readonly IAikDataService _aikDataService; private readonly IDataCacheService _dataCacheService; private readonly IImageCacheService _imageCacheService; private readonly ILogger _logger; [ObservableProperty] private ObservableCollection _records = new(); [ObservableProperty] private int currentIndex = 1; [ObservableProperty] private int size = 20; [ObservableProperty] private bool isShowLoadMore = true; [ObservableProperty] private string notMoreTip = "没有更多记录了~"; public UserKeyRecordViewModel(IAikDataService aikDataService, IDataCacheService dataCacheService, IImageCacheService imageCacheService, ILogger logger) { _aikDataService = aikDataService; _dataCacheService = dataCacheService; _imageCacheService = imageCacheService; _logger = logger; _ = LoadUserKeyRecordsAsync(); } private async Task LoadUserKeyRecordsAsync() { var token = await _dataCacheService.GetLatestUserTokenAsync(); if (!string.IsNullOrEmpty(token)) { var result = await _aikDataService.GetKeyLogList(token); if (result != null) { Records = new ObservableCollection(result.Records); if (result.Total == result.Records.Count) { IsShowLoadMore = false; NotMoreTip = AiKLanguage.LanguageKey.GetValueOrDefault("NotMoreTips"); } if (Records != null) { _ = LoadImagesPathAsync(result.Records); } } } } private async Task LoadImagesPathAsync(List items, CancellationToken cancellationToken = default) { try { var itemsWithImages = items.Where(keym => !string.IsNullOrEmpty(keym.Img)).ToList(); // 使用信号量限制并发数量 var semaphore = new SemaphoreSlim(initialCount: 5, maxCount: 5); var imageTasks = itemsWithImages.Select(async keym => { await semaphore.WaitAsync(cancellationToken); try { cancellationToken.ThrowIfCancellationRequested(); var imageUrl = keym.Img; var localiamgepath = await _imageCacheService.GetImagePathAsync(imageUrl, null, cancellationToken); if (!string.IsNullOrEmpty(localiamgepath)) { await Application.Current.Dispatcher.InvokeAsync(() => { keym.LocalImagePath = localiamgepath; }, System.Windows.Threading.DispatcherPriority.Background); } } catch (OperationCanceledException) { // 单个图片加载被取消,静默处理 _logger.LogDebug("图片加载被取消: {ImageUrl}", keym.Img); } catch (Exception ex) { _logger.LogWarning(ex, "加载图片失败: {ImageUrl}", keym.Img); } finally { semaphore.Release(); } }); await Task.WhenAll(imageTasks); } catch (OperationCanceledException) { _logger.LogInformation("图片加载操作被取消"); // 不需要重新抛出,这是正常的取消操作 } catch (Exception ex) { _logger.LogError(ex, "加载图片时发生错误"); throw; } } #region 页面方法 [RelayCommand] private async Task LoadMore() { CurrentIndex++; var token = await _dataCacheService.GetLatestUserTokenAsync(); if (!string.IsNullOrEmpty(token)) { var result = await _aikDataService.GetKeyLogList(token, CurrentIndex, Size); if (result != null) { if (result.Records != null) { if (result.Records.Count > 0) { foreach (var item in result.Records) { Records.Add(item); } _ = LoadImagesPathAsync(result.Records); } else { IsShowLoadMore = false; NotMoreTip = AiKLanguage.LanguageKey.GetValueOrDefault("NotMoreTips"); } } } } } #endregion } }