FieldWorkClient/ViewModel/Send/DownViewModel.cs

300 lines
8.2 KiB
C#
Raw Normal View History

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;
2025-04-08 16:22:25 +08:00
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<DownItem> OpenDownItemFolder { get; set; }
public RelayCommand<string> LoadData { get; set; }
private readonly ConcurrentQueue<MinioDownloadTask> _taskQueue = new();
private SemaphoreSlim _concurrencySemaphore;
private CancellationTokenSource _processingCts = new();
public string _AllTaskHeader;
public string AllTaskHeader
{
get => _AllTaskHeader;
set
{
_AllTaskHeader = value;
RaisePropertyChanged();
}
}
// 绑定属性
public ObservableCollection<MinioDownloadTask> Tasks { get; } = new();
// 所有任务
public ObservableCollection<MinioDownloadTask> 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; }
2025-04-08 16:22:25 +08:00
private ObservableCollection<DownItem> _downItems;
2025-04-08 16:22:25 +08:00
public ObservableCollection<DownItem> 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<MinioDownloadTask>($"select * from download_task");
//DownItems = new ObservableCollection<DownItem>(data);
AllTasks = new ObservableCollection<MinioDownloadTask>(data);
AllTaskHeader = $"全部({AllTasks.Count}";
2025-04-08 16:22:25 +08:00
Console.WriteLine(JsonConvert.SerializeObject(data));
OpenDownItemFolder = new RelayCommand<DownItem>(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);
2025-04-08 16:22:25 +08:00
}
protected override void Init()
{
}
protected override void Loaded(string args)
{
}
2025-04-08 16:22:25 +08:00
[SugarTable("f_down_item")]
public class DownItem
{
public DownItem()
{
}
[SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnName = "id")]
2025-04-08 16:22:25 +08:00
public long Id { get; set; }
2025-04-08 16:22:25 +08:00
// 进度 已下载 多久下载完成 下载速度
[SugarColumn(IsIgnore = true)] public int ProgressInt { get; set; }
2025-04-08 16:22:25 +08:00
/// <summary>
/// object key
/// </summary>
[SugarColumn(ColumnName = "object_key")]
public string ObjectKey { get; set; }
2025-04-08 16:22:25 +08:00
/// <summary>
/// 文件名称
/// </summary>
[SugarColumn(ColumnName = "file_name")]
public string FileName { get; set; }
2025-04-08 16:22:25 +08:00
/// <summary>
/// 文件类型
/// </summary>
[SugarColumn(ColumnName = "file_type")]
public string FileType { get; set; }
2025-04-08 16:22:25 +08:00
/// <summary>
/// 文件大小
/// </summary>
[SugarColumn(ColumnName = "file_size")]
public long FileSize { get; set; }
2025-04-08 16:22:25 +08:00
/// <summary>
/// 速度 100kb/s
/// </summary>
[SugarColumn(IsIgnore = true)]
public long Speed { get; set; }
/// <summary>
/// 本地保存路径
/// </summary>
[SugarColumn(ColumnName = "file_path")]
public string FilePath { get; set; }
2025-04-08 16:22:25 +08:00
/// <summary>
/// 文件的ETag
/// </summary>
[SugarColumn(ColumnName = "file_etag")]
public string FileETag { get; set; }
}
}