FieldWorkClient/ViewModel/Send/DownViewModel.cs

300 lines
8.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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<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; }
private ObservableCollection<DownItem> _downItems;
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}";
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);
}
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; }
/// <summary>
/// object key
/// </summary>
[SugarColumn(ColumnName = "object_key")]
public string ObjectKey { get; set; }
/// <summary>
/// 文件名称
/// </summary>
[SugarColumn(ColumnName = "file_name")]
public string FileName { get; set; }
/// <summary>
/// 文件类型
/// </summary>
[SugarColumn(ColumnName = "file_type")]
public string FileType { get; set; }
/// <summary>
/// 文件大小
/// </summary>
[SugarColumn(ColumnName = "file_size")]
public long FileSize { get; set; }
/// <summary>
/// 速度 100kb/s
/// </summary>
[SugarColumn(IsIgnore = true)]
public long Speed { get; set; }
/// <summary>
/// 本地保存路径
/// </summary>
[SugarColumn(ColumnName = "file_path")]
public string FilePath { get; set; }
/// <summary>
/// 文件的ETag
/// </summary>
[SugarColumn(ColumnName = "file_etag")]
public string FileETag { get; set; }
}
}