FieldWorkClient/ViewModel/Send/DownViewModel.cs

336 lines
8.8 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;
public RelayCommand<MinioDownloadTask> OpenDownItemFolder { get; set; }
private readonly ConcurrentQueue<MinioDownloadTask> _taskQueue = new();
private SemaphoreSlim _concurrencySemaphore;
private CancellationTokenSource _processingCts = new();
/// <summary>
/// 全部任务动态标题
/// </summary>
private string _allTaskHeader;
public string AllTaskHeader
{
get => _allTaskHeader;
set
{
_allTaskHeader = value;
RaisePropertyChanged();
}
}
private string _runningTaskHeader;
public string RunningTaskHeader
{
get => _runningTaskHeader;
set
{
_runningTaskHeader = value;
RaisePropertyChanged();
}
}
private string _finishedTaskHeader;
public string FinishedTaskHeader
{
get => _finishedTaskHeader;
set
{
_finishedTaskHeader = value;
RaisePropertyChanged();
}
}
// 绑定属性
public ObservableCollection<MinioDownloadTask> AllTasks { get;set; } = new();
public ICollectionView RunningTasksView { get; set; }
public ICollectionView FinishedTasksView { 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();
}
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="minioService"></param>
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<MinioDownloadTask>(DoOpenDownItemFolder);
// 命令初始化
// AddTaskCommand = new RelayCommand(AddTask, CanAddTask);
// 修正:使用 CollectionViewSource 确保通知
var cvsRunning = new CollectionViewSource { Source = AllTasks };
cvsRunning.Filter += (s, e) =>
{
var b = ((MinioDownloadTask)e.Item).Status is "下载中" or "等待中" or "已暂停";
e.Accepted = b;
};
RunningTasksView = cvsRunning.View;
var cvsFinished = new CollectionViewSource { Source = AllTasks };
cvsFinished.Filter += (s, e) =>
{
var b = ((MinioDownloadTask)e.Item).Status == "已完成";
e.Accepted = b;
};
FinishedTasksView = cvsFinished.View;
if (FinishedTasksView is ListCollectionView finishListView)
{
FinishedTaskHeader = $"已完成({finishListView.Count}";
}
if (RunningTasksView is ListCollectionView runningListView)
{
RunningTaskHeader = $"下载中({runningListView.Count}";
}
// 关键:订阅数据源变更事件,强制视图刷新
AllTasks.CollectionChanged += (s, e) =>
{
RunningTasksView.Refresh();
FinishedTasksView.Refresh();
};
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);
AllTasks.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(MinioDownloadTask 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; }
}
}