using AIK.Common.Interface; using AIK.Models.BannerModels; using AIK.Service.IService; using AIK.Service.Service; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Microsoft.Win32; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Media.Imaging; using System.Windows.Threading; namespace AIK.ViewModels.HomePage { public partial class HomePageViewModel : ObservableObject { private readonly DispatcherTimer _timer; [ObservableProperty] [NotifyPropertyChangedFor(nameof(IsFirst))] [NotifyPropertyChangedFor(nameof(IsLast))] private int _currentIndexPublic = -1; public bool IsFirst => CurrentIndexPublic == 0; [ObservableProperty] private string _currentImagePath; [ObservableProperty] private BitmapImage _currentBitmapImage; public bool IsLast => Banners.Count > 0 && CurrentIndexPublic == Banners.Count - 1; public ObservableCollection Banners { get; } = new ObservableCollection(); private readonly IConfigurationService _configurationService; private readonly IQRCodeService _qRCodeService; //国内版 private string defaultLogoPath = "AIK.Assets.Images.AIKChina.png"; //国外版 //private const string defaultLogoPath = "AIK.Assets.Images.AIKInternationl.png"; [ObservableProperty] private byte[]? _qrCodeBytes; // 👈 只暴露字节数组 private readonly IAikDataService _aikDataService; private readonly IImageCacheService _imageCacheService; public HomePageViewModel(IConfigurationService configurationService, IQRCodeService qRCodeService, IAikDataService aikDataService, IImageCacheService imageCacheService) { #if CN defaultLogoPath = "AIK.Assets.Images.AIKChina.png"; #elif TEST defaultLogoPath = "AIK.Assets.Images.AIKChina.png"; #else defaultLogoPath = "AIK.Assets.Images.AIKInternationl.png"; #endif _configurationService = configurationService; _qRCodeService = qRCodeService; _aikDataService = aikDataService; _imageCacheService = imageCacheService; //LoadLocalBanners(); _ = LoadRemoteBanners(); LoadQrCodeImage(); if (Banners.Count > 0) { CurrentIndexPublic = 0; } _timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(5) }; _timer.Tick += OnTimerTick; _timer.Start(); } partial void OnCurrentIndexPublicChanged(int value) { if (Banners.Count == 0) return; // 边界保护 if (value < 0 || value >= Banners.Count) return; for (int i = 0; i < Banners.Count; i++) { Banners[i].IsSelected = (i == value); if (Banners[i].IsSelected) { CurrentImagePath = Banners[i].ImagePath!; CurrentBitmapImage = Banners[i].BitmapImage!; } } //_timer.Stop(); //_timer.Start(); // 重置自动轮播 } private void LoadQrCodeImage() { QrCodeBytes = _qRCodeService.GenerateQRCodeWithLogo(_configurationService.ApiSettings.QRCodeUrl, defaultLogoPath, 12); } private void LoadLocalBanners() { // 修改为你的实际图片文件夹路径(相对路径) string imageFolder = @"C:\Users\23231\Desktop\Images"; if (!Directory.Exists(imageFolder)) return; var validExtensions = new[] { ".jpg", ".jpeg", ".png", ".bmp", ".gif" }; var imageFiles = Directory.GetFiles(imageFolder) .Where(f => validExtensions.Contains(Path.GetExtension(f).ToLowerInvariant())) .OrderBy(f => f) // 可按需排序 .ToList(); for (int i = 0; i < imageFiles.Count; i++) { try { Banners.Add(new BannerItem { ImagePath = imageFiles[i], Index = i }); } catch (Exception ex) { // 可记录日志或跳过损坏图片 System.Diagnostics.Debug.WriteLine($"Failed to load image {imageFiles[i]}: {ex.Message}"); } } } private async Task LoadRemoteBanners() { try { var bannerlist = await _aikDataService.GetBannerCache(); //var bannerlist = await _aikDataService.GetBanner(); int i = 0; foreach (var item in bannerlist) { if (!string.IsNullOrEmpty(item.ImgUrl)) { var start = DateTime.Now; var localbitmapImage = await _imageCacheService.GetImageByLocalPathAsync(item.ImgUrl); Banners.Add(new BannerItem { BitmapImage = localbitmapImage, ImagePath = item.ImgUrl, Index = i++ }); var loaded = DateTime.Now; Debug.WriteLine($"Loaded: {(loaded - start).TotalMilliseconds}ms"); } } } catch (Exception ex) { // fire-and-forget 任务(_ = LoadRemoteBanners())必须捕获异常, // 否则异常会成为"未观察任务异常"(终结器线程重新抛出,App 记录 Task未观察异常)。 // Banner 加载失败(如网络/TLS 问题)不应影响主流程。 Debug.WriteLine($"加载远程Banner失败: {ex.Message}"); } } private void OnTimerTick(object? sender, EventArgs e) { if (Banners.Count == 0) return; CurrentIndexPublic = (CurrentIndexPublic + 1) % Banners.Count; } [RelayCommand] private void Previous() => CurrentIndexPublic = (CurrentIndexPublic - 1 + Banners.Count) % Banners.Count; [RelayCommand] private void Next() => CurrentIndexPublic = (CurrentIndexPublic + 1) % Banners.Count; [RelayCommand] private void SelectBanner(int index) => CurrentIndexPublic = index; } }