using System.Collections.Concurrent; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Windows.Data; using System.Windows.Input; using HeBianGu.Base.WpfBase; using HeBianGu.Service.Mvc; using Hopetry.Models; using Hopetry.Provider; using Hopetry.Services; using Newtonsoft.Json; using SqlSugar; namespace Hopetry.ViewModel.Send; [ViewModel("Down")] public class DownViewModel : MvcViewModelBase { private readonly MinioService _minioService; // todo 完成取消下载及暂停下载逻辑 public RelayCommand OpenDownItemFolder { get; set; } public RelayCommand LoadData { get; set; } private readonly ConcurrentQueue _taskQueue = new(); private SemaphoreSlim _concurrencySemaphore; private CancellationTokenSource _processingCts = new(); public string _AllTaskHeader; public string AllTaskHeader { get => _AllTaskHeader; set { _AllTaskHeader = value; RaisePropertyChanged(); } } // 绑定属性 public ObservableCollection Tasks { get; } = new(); // 所有任务 public ObservableCollection AllTasks { get; set; } public ICollectionView RunningTasksView { get; set; } public ICollectionView PausedTasksView { get; set; } private int _maxConcurrent = 3; public int MaxConcurrent { get => _maxConcurrent; set { if (value < 1) value = 1; if (_maxConcurrent == value) return; _maxConcurrent = value; AdjustConcurrency(); RaisePropertyChanged(); } } private int _runningTasks; public int RunningTasks { get => _runningTasks; private set { _runningTasks = value; RaisePropertyChanged(); } } // 命令 public ICommand AddTaskCommand { get; } public ICommand ClearFinishedCommand { get; } private ObservableCollection _downItems; public ObservableCollection DownItems { get => _downItems; set { _downItems = value; RaisePropertyChanged(); } } public DownViewModel(MinioService minioService) { _minioService = minioService; Console.WriteLine("初始化DownViewModel"); var client = SqlSugarConfig.GetSqlSugarScope(); var data = client.Ado.SqlQuery($"select * from download_task"); //DownItems = new ObservableCollection(data); AllTasks = new ObservableCollection(data); AllTaskHeader = $"全部({AllTasks.Count})"; Console.WriteLine(JsonConvert.SerializeObject(data)); OpenDownItemFolder = new RelayCommand(DoOpenDownItemFolder); // 命令初始化 // AddTaskCommand = new RelayCommand(AddTask, CanAddTask); // 修正:使用 CollectionViewSource 确保通知 var cvsRunning = new CollectionViewSource { Source = AllTasks }; cvsRunning.Filter += (s, e) => { var b = ((MinioDownloadTask)e.Item).Status == "下载中"; e.Accepted = b; }; RunningTasksView = cvsRunning.View; var cvsPaused = new CollectionViewSource { Source = AllTasks }; cvsPaused.Filter += (s, e) => { var b = ((MinioDownloadTask)e.Item).Status == "已完成"; e.Accepted = b; }; PausedTasksView = cvsPaused.View; // 关键:订阅数据源变更事件,强制视图刷新 AllTasks.CollectionChanged += (s, e) => { RunningTasksView.Refresh(); PausedTasksView.Refresh(); }; Console.WriteLine($"运行中任务:{JsonConvert.SerializeObject(RunningTasksView)}"); Console.WriteLine($"已完成任务:{JsonConvert.SerializeObject(PausedTasksView)}"); ClearFinishedCommand = new CustomCommand(() => { // todo 删除已完成的下载记录 }); // 启动任务处理线程 _concurrencySemaphore = new SemaphoreSlim(_maxConcurrent); new Thread(ProcessTasksLoop) { IsBackground = true }.Start(); } private void ProcessTasksLoop() { while (!_processingCts.IsCancellationRequested) { // 按当前并发数启动任务 for (int i = 0; i < _maxConcurrent; i++) { if (_taskQueue.TryDequeue(out var task)) { _ = ExecuteTaskAsync(task); } } Thread.Sleep(100); } } private void AddTask() { var task = new MinioDownloadTask(_minioService, NewBucket, NewObjectName); Tasks.Add(task); _taskQueue.Enqueue(task); RaisePropertyChanged(nameof(NewBucket)); RaisePropertyChanged(nameof(NewObjectName)); } private bool CanAddTask() => !string.IsNullOrEmpty(NewBucket) && !string.IsNullOrEmpty(NewObjectName); private async Task ExecuteTaskAsync(MinioDownloadTask task) { RunningTasks++; try { // todo 配置下载路径 var savePath = Path.Combine(task.FileName); await task.StartDownload(savePath); } finally { RunningTasks--; // 任务完成后自动处理下一个 if (!_processingCts.IsCancellationRequested) ProcessTasksLoop(); } } private void AdjustConcurrency() { lock (_concurrencySemaphore) { // 调整信号量容量 var delta = _maxConcurrent - _concurrencySemaphore.CurrentCount; if (delta > 0) { for (int i = 0; i < delta; i++) { _concurrencySemaphore.Release(); } } } } // 绑定属性 private string _newBucket; public string NewBucket { get => _newBucket; set { _newBucket = value; RaisePropertyChanged(); } } private string _newObjectName; public string NewObjectName { get => _newObjectName; set { _newObjectName = value; RaisePropertyChanged(); } } public void DoOpenDownItemFolder(DownItem para) { Console.WriteLine($"点击了什么值:{JsonConvert.SerializeObject(para)}"); Process.Start("explorer.exe", para.FilePath); } protected override void Init() { } protected override void Loaded(string args) { } [SugarTable("f_down_item")] public class DownItem { public DownItem() { } [SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnName = "id")] public long Id { get; set; } // 进度 已下载 多久下载完成 下载速度 [SugarColumn(IsIgnore = true)] public int ProgressInt { get; set; } /// /// object key /// [SugarColumn(ColumnName = "object_key")] public string ObjectKey { get; set; } /// /// 文件名称 /// [SugarColumn(ColumnName = "file_name")] public string FileName { get; set; } /// /// 文件类型 /// [SugarColumn(ColumnName = "file_type")] public string FileType { get; set; } /// /// 文件大小 /// [SugarColumn(ColumnName = "file_size")] public long FileSize { get; set; } /// /// 速度 100kb/s /// [SugarColumn(IsIgnore = true)] public long Speed { get; set; } /// /// 本地保存路径 /// [SugarColumn(ColumnName = "file_path")] public string FilePath { get; set; } /// /// 文件的ETag /// [SugarColumn(ColumnName = "file_etag")] public string FileETag { get; set; } } }