797 lines
29 KiB
C#
797 lines
29 KiB
C#
using System.Collections.ObjectModel;
|
||
using System.IO;
|
||
using System.Text;
|
||
using System.Windows;
|
||
using System.Windows.Input;
|
||
using System.Windows.Threading;
|
||
using HarmonyLib;
|
||
using HeBianGu.Base.WpfBase;
|
||
using HeBianGu.Control.Explorer;
|
||
using HeBianGu.Control.Message;
|
||
using HeBianGu.Service.Mvc;
|
||
using Hopetry.Models;
|
||
using Hopetry.Provider;
|
||
using Hopetry.Provider.Behaviors;
|
||
using Hopetry.Services;
|
||
using Hopetry.ViewModel.Send;
|
||
using Microsoft.Extensions.Configuration;
|
||
using Microsoft.Win32;
|
||
using Microsoft.WindowsAPICodePack.Dialogs;
|
||
using Minio;
|
||
using Minio.DataModel.Args;
|
||
|
||
namespace HeBianGu.App.Disk
|
||
{
|
||
[ViewModel("Loyout")]
|
||
internal class LoyoutViewModel : MvcViewModelBase
|
||
{
|
||
#region 参数定义及初始化
|
||
|
||
private readonly FileUploadService _uploadService;
|
||
private string _path;
|
||
|
||
/// <summary> 说明 </summary>
|
||
public string Path
|
||
{
|
||
get { return _path; }
|
||
set
|
||
{
|
||
_path = value;
|
||
RaisePropertyChanged("Path");
|
||
}
|
||
}
|
||
|
||
private string _nearPath;
|
||
|
||
/// <summary> 说明 </summary>
|
||
public string NearPath
|
||
{
|
||
get { return _nearPath; }
|
||
set
|
||
{
|
||
_nearPath = value;
|
||
RaisePropertyChanged("NearPath");
|
||
}
|
||
}
|
||
|
||
private string _sharePath;
|
||
|
||
/// <summary> 说明 </summary>
|
||
public string SharePath
|
||
{
|
||
get { return _sharePath; }
|
||
set
|
||
{
|
||
_sharePath = value;
|
||
RaisePropertyChanged("SharePath");
|
||
}
|
||
}
|
||
|
||
protected override void Init()
|
||
{
|
||
//Path = Environment.GetFolderPath(Environment.SpecialFolder.MyComputer);
|
||
//NearPath = Environment.GetFolderPath(Environment.SpecialFolder.Recent);
|
||
//SharePath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
|
||
|
||
// LinkActions.Add(new LinkAction() { Action = "Near", Controller = "Loyout", DisplayName = "最近使用", Logo = "\xe6f3" });
|
||
LinkActions.Add(new LinkAction()
|
||
{ Action = "Explorer", Controller = "Loyout", DisplayName = "全部文件", Logo = "\xe8d6" });
|
||
// LinkActions.Add(new LinkAction() { Action = "Image", Controller = "Loyout", DisplayName = " 图片", Logo = "" });
|
||
// LinkActions.Add(new LinkAction() { Action = "Video", Controller = "Loyout", DisplayName = " 视频", Logo = "" });
|
||
// LinkActions.Add(new LinkAction() { Action = "Document", Controller = "Loyout", DisplayName = " 文档", Logo = "" });
|
||
// LinkActions.Add(new LinkAction() { Action = "Music", Controller = "Loyout", DisplayName = " 音乐", Logo = "" });
|
||
// LinkActions.Add(new LinkAction() { Action = "Explorer", Controller = "Loyout", DisplayName = " 种子", Logo = "" });
|
||
//LinkActions.Add(new LinkAction() { Action = "Recent", Controller = "Loyout", DisplayName = " 其他", Logo = "" });
|
||
// LinkActions.Add(new LinkAction() { Action = "Space", Controller = "Loyout", DisplayName = "隐藏空间", Logo = "\xe613" });
|
||
//LinkActions.Add(new LinkAction() { Action = "Share", Controller = "Loyout", DisplayName = "我的分享", Logo = "\xe764" });
|
||
// LinkActions.Add(new LinkAction() { Action = "Near", Controller = "Loyout", DisplayName = "回收站", Logo = "\xe618" });
|
||
|
||
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Loaded,
|
||
new Action(() => { SelectLink = LinkActions[0]; }));
|
||
}
|
||
|
||
protected override void Loaded(string args)
|
||
{
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 文件上传
|
||
|
||
#region 网盘空间文件数量更新
|
||
|
||
private string _statusMessage;
|
||
|
||
public string StatusMessage
|
||
{
|
||
get { return _statusMessage; }
|
||
set
|
||
{
|
||
_statusMessage = value;
|
||
RaisePropertyChanged("StatusMessage");
|
||
}
|
||
}
|
||
|
||
|
||
// 添加状态更新方法
|
||
public void UpdateStatus(string message)
|
||
{
|
||
StatusMessage = message;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 参数定义
|
||
|
||
private SendViewModel _sendViewModel;
|
||
|
||
private IConfiguration config;
|
||
|
||
//private Task _currentUploadTask = null; // 新增:当前上传任务
|
||
//private CancellationTokenSource _uploadCancellation = new CancellationTokenSource();
|
||
//private int _uploadCount = 0;
|
||
//private int _completeCount = 0;
|
||
private ExplorerMinIOBehavior _explorerBehavior;
|
||
private MinIOSearchBehavior _minioBehavior;
|
||
|
||
|
||
public ICommand UploadCommand { get; }
|
||
public ICommand UploadCommand1 { get; }
|
||
public ICommand CreateFolderCommand { get; }
|
||
public ICommand DownloadCommand { get; set; }
|
||
|
||
public ICommand DeleteFolderCommand { get; }
|
||
|
||
//public ICommand SelectItemsCommand { get; }
|
||
public LoyoutViewModel(SendViewModel sendViewModel)
|
||
{
|
||
_sendViewModel = sendViewModel;
|
||
_uploadService = new FileUploadService();
|
||
// 文件上传
|
||
UploadCommand = new AsyncRelayCommand(async () => await UploadFile());
|
||
// 文件夹上传
|
||
UploadCommand1 = new AsyncRelayCommand(async () => await UploadFile1());
|
||
|
||
CreateFolderCommand = new AsyncRelayCommand(async () => await CreateNewFolderAsync());
|
||
DeleteFolderCommand = new AsyncRelayCommand(async () => await DeleteSelectedItemsAsync());
|
||
DownloadCommand = new AsyncRelayCommand(async () => await DoDownloadCommand());
|
||
SelectDirCommand = new CustomCommand(async () => await DoSelectDirCommand());
|
||
|
||
// 订阅上传完成事件,以便在上传完成后刷新显示
|
||
_sendViewModel.FileUploadCompleted += OnFileUploadCompleted;
|
||
|
||
// 初始化CurrentMinIOPath为空字符串,表示显示根目录(所有存储桶)
|
||
CurrentMinIOPath = string.Empty;
|
||
|
||
//systemInfo = SystemInfoCollector.Collect();
|
||
}
|
||
|
||
private async Task DoSelectDirCommand()
|
||
{
|
||
CommonOpenFileDialog dialog = new CommonOpenFileDialog
|
||
{
|
||
IsFolderPicker = true
|
||
};
|
||
|
||
if (dialog.ShowDialog() == CommonFileDialogResult.Ok)
|
||
{
|
||
var folderPath = dialog.FileName; // 获取选中的文件夹路径
|
||
// todo 设置文件夹
|
||
Application.Current.Dispatcher.Invoke(() =>
|
||
{
|
||
DownFolderSelect.DownFolder = folderPath;
|
||
Console.WriteLine($"选择文件夹:{folderPath}");
|
||
});
|
||
|
||
// 处理选中的文件夹路径
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 行为方法
|
||
|
||
// 添加设置Behavior的方法
|
||
public void SetExplorerBehavior(ExplorerMinIOBehavior behavior)
|
||
{
|
||
_explorerBehavior = behavior;
|
||
}
|
||
|
||
public void SetExplorerBehavior(MinIOSearchBehavior behavior)
|
||
{
|
||
_minioBehavior = behavior;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 上传执行
|
||
|
||
//多文件上传
|
||
private async Task UploadFile()
|
||
{
|
||
var openFileDialog = new OpenFileDialog
|
||
{
|
||
Multiselect = true,
|
||
Filter = "All Files (*.*)|*.*"
|
||
};
|
||
|
||
if (openFileDialog.ShowDialog() == true)
|
||
{
|
||
MessageProxy.Snacker.Show("正在上传列表中可查看进度");
|
||
// 如果没有上传任务在运行,则启动上传
|
||
/*if (!_sendViewModel._isUploading)
|
||
{
|
||
await _sendViewModel.ProcessUploadTasks();
|
||
}*/
|
||
Console
|
||
.WriteLine($"弹窗返回文件数:{openFileDialog.FileNames.Length}");
|
||
// 过滤掉已经存在的文件
|
||
var newFiles = openFileDialog.FileNames
|
||
.Where(filePath => !_sendViewModel.UpLoadItems.Any(item =>
|
||
item.Value5.Equals(filePath, StringComparison.OrdinalIgnoreCase)))
|
||
.ToList();
|
||
Console.WriteLine($"过滤后的文件数:{newFiles.Count}");
|
||
if (newFiles.Count == 0)
|
||
{
|
||
MessageBox.Show("没有新文件需要上传或文件已在上传队列中");
|
||
return;
|
||
}
|
||
|
||
//判断是否存在上传路径
|
||
var bucketName = GetCurrentBucket();
|
||
if (string.IsNullOrEmpty(bucketName))
|
||
{
|
||
MessageBox.Show("请选择上传路径");
|
||
return;
|
||
}
|
||
|
||
var fix = GetCurrentPrefix(); //获取当前所在的文件夹路径,除桶之外的
|
||
Task.Run(() =>
|
||
{
|
||
foreach (string filePath in newFiles)
|
||
{
|
||
string str = System.IO.Path.GetFileName(filePath);
|
||
if (!string.IsNullOrEmpty(fix))
|
||
{
|
||
str = fix + System.IO.Path.GetFileName(filePath);
|
||
}
|
||
|
||
var ut = CreateUploadItem(filePath, str, bucketName);
|
||
_sendViewModel.AddUploadTask(ut);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
//文件夹上传
|
||
private async Task UploadFile1()
|
||
{
|
||
var dialog = new CommonOpenFileDialog
|
||
{
|
||
IsFolderPicker = true,
|
||
Title = "请选择上传文件"
|
||
};
|
||
|
||
if (dialog.ShowDialog() == CommonFileDialogResult.Ok)
|
||
{
|
||
string folderPath = dialog.FileName;
|
||
string folderName = new DirectoryInfo(folderPath).Name; // 获取选中的文件夹名称
|
||
var beforeFiles = Directory.GetFiles(folderPath, "*.*", SearchOption.AllDirectories);
|
||
Console.WriteLine($"文件夹上传选中文件数:{beforeFiles.Length}");
|
||
var files = beforeFiles
|
||
.Where(filePath => !_sendViewModel.UpLoadItems
|
||
.Any(item =>
|
||
item.Value5.Equals(filePath, StringComparison.OrdinalIgnoreCase)))
|
||
.ToList();
|
||
Console.WriteLine($"过滤后的文件数:{files.Count}");
|
||
if (files.Count == 0)
|
||
{
|
||
MessageBox.Show("没有新文件需要上传或文件已在上传队列中");
|
||
return;
|
||
}
|
||
|
||
//判断是否存在上传路径
|
||
string bucketName = GetCurrentBucket();
|
||
if (string.IsNullOrEmpty(bucketName))
|
||
{
|
||
MessageBox.Show("请选择上传路径");
|
||
return;
|
||
}
|
||
|
||
MessageProxy.Snacker.Show("正在上传列表中可查看进度");
|
||
MessageProxy.Snacker.Show($"添加上传{files.Count}个文件");
|
||
Task.Run(() =>
|
||
{
|
||
foreach (string filePath in files)
|
||
{
|
||
var fix = GetCurrentPrefix(); //获取当前所在的文件夹路径,除桶之外的
|
||
string relativePath =
|
||
folderName + '/' + filePath.Substring(folderPath.Length + 1).Replace('\\', '/');
|
||
if (!string.IsNullOrEmpty(fix))
|
||
{
|
||
relativePath = fix + folderName + '/' +
|
||
filePath.Substring(folderPath.Length + 1).Replace('\\', '/');
|
||
}
|
||
|
||
var ut = CreateUploadItem(filePath, relativePath, bucketName);
|
||
_sendViewModel.AddUploadTask(ut);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
//创建上传列表
|
||
private UpLoadItems CreateUploadItem(string filePath, string objectName, string bucketname)
|
||
{
|
||
FileInfo fileInfo = new FileInfo(filePath);
|
||
string sizeText = fileInfo.Length < 1024 * 1024
|
||
? $"{Math.Ceiling((decimal)fileInfo.Length / 1024)}KB"
|
||
: $"{Math.Ceiling((decimal)fileInfo.Length / (1024 * 1024))}MB";
|
||
|
||
//写入数据库
|
||
FUpload fp = new FUpload();
|
||
fp.Id = Guid.NewGuid().ToString();
|
||
fp.FileName = objectName;
|
||
fp.FileSize = fileInfo.Length;
|
||
fp.FilePath = filePath;
|
||
fp.FileType = fileInfo.Extension;
|
||
fp.CreateTime = DateTime.Now;
|
||
fp.IsComplete = false;
|
||
fp.FileSizeText = sizeText;
|
||
fp.BucketName = bucketname;
|
||
if (_uploadService.AddFile(fp)) //添加到数据库,成功后,添加到下载队列
|
||
{
|
||
return new UpLoadItems
|
||
{
|
||
Value = System.IO.Path.GetFileName(filePath),
|
||
Value3 = "等待上传",
|
||
Value4 = fp.Id, //唯一标识,与数据库一致
|
||
Value5 = filePath, //文件名称
|
||
Value6 = objectName, //文件地址
|
||
Value9 = bucketname,
|
||
Double1 = fileInfo.Length,
|
||
Double2 = 0.0,
|
||
Bool1 = false,
|
||
Value1 = $"0{(fileInfo.Length < 1024 * 1024 ? "KB" : "MB")}/{sizeText}"
|
||
};
|
||
}
|
||
|
||
throw new Exception("文件载入失败");
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 其他
|
||
|
||
//更新上传进行中及上传完成列表
|
||
private void UpdateFileCounts()
|
||
{
|
||
_sendViewModel.UploadingCount = _sendViewModel.UploadingItems.Count;
|
||
_sendViewModel.CompleteCount = _sendViewModel.CompleteItems.Count;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#endregion
|
||
|
||
#region 文件下载
|
||
|
||
private DownFolderSelect _downFolderSelect = new DownFolderSelect();
|
||
|
||
public DownFolderSelect DownFolderSelect
|
||
{
|
||
get => _downFolderSelect;
|
||
set
|
||
{
|
||
_downFolderSelect = value;
|
||
RaisePropertyChanged();
|
||
}
|
||
}
|
||
|
||
private async Task DoDownloadCommand()
|
||
{
|
||
// 当为文件时,处理
|
||
var tempSelectedItems = new ObservableCollection<SystemInfoModel>(SelectedItems);
|
||
if (tempSelectedItems.Count > 0)
|
||
{
|
||
if (string.IsNullOrEmpty(DownFolderSelect.DownFolder))
|
||
{
|
||
// 如果是空,则把同步目录拿过来使用
|
||
DownFolderSelect.DownFolder = ViewModelLocator.SyncViewModel.SyncDir;
|
||
}
|
||
|
||
//下载目录
|
||
bool r = await MessageProxy.Presenter.Show(DownFolderSelect, x => true, "下载目录选择", x =>
|
||
{
|
||
x.Width = 600;
|
||
x.Height = 450;
|
||
//x.Padding = new System.Windows.Thickness(10);
|
||
//x.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
|
||
//x.VerticalAlignment = System.Windows.VerticalAlignment.Center;
|
||
}, ObjectContentDialog.ClearKey);
|
||
if (r)
|
||
{
|
||
var downDir = DownFolderSelect.DownFolder;
|
||
if (DownFolderSelect.IsSelect)
|
||
{
|
||
// todo 持久化配置
|
||
}
|
||
|
||
SelectedItems.Clear();
|
||
// 刷新界面(网盘空间)
|
||
_explorerBehavior.RefreshMinIOPath(CurrentMinIOPath);
|
||
Task.Run(() => AddTaskToDownLoad(tempSelectedItems, downDir));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
await MessageProxy.Messager.ShowResult("至少选择一项");
|
||
}
|
||
}
|
||
|
||
private void AddTaskToDownLoad(ObservableCollection<SystemInfoModel> tempSelectedItems, string downDir)
|
||
{
|
||
foreach (var item in tempSelectedItems)
|
||
{
|
||
if (item is MinIOFileModel file)
|
||
{
|
||
var temp = (MinIOFileInfo)file.Model;
|
||
var objectKey = temp.FullName.Replace(temp.BucketName + "/", "");
|
||
ViewModelLocator.DownViewModel.AddTask(temp.BucketName, objectKey, temp.Size, downDir);
|
||
}
|
||
else if (item is MinIODirectoryModel dir)
|
||
{
|
||
var temp = (MinIODirectoryInfo)dir.Model;
|
||
//Console.WriteLine($"bucket: {temp.BucketName} objectKey {temp.FullName}");
|
||
var objectKey = temp.FullName.Replace(temp.BucketName + "/", "");
|
||
ViewModelLocator.DownViewModel.AddDirTask(temp.BucketName, objectKey, temp.Name, downDir);
|
||
}
|
||
|
||
MessageProxy.Snacker.Show("已加入下载队列");
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 文件列表
|
||
|
||
private string _currentMinIOPath;
|
||
|
||
/// <summary> 说明CurrentMinIOPath </summary>
|
||
public string CurrentMinIOPath
|
||
{
|
||
get { return _currentMinIOPath; }
|
||
set
|
||
{
|
||
// 确保路径格式正确
|
||
var newPath = value;
|
||
if (!string.IsNullOrEmpty(newPath) && !newPath.EndsWith("/") &&
|
||
newPath.Contains("/") && !newPath.EndsWith("/"))
|
||
{
|
||
newPath += "/";
|
||
}
|
||
|
||
if (_currentMinIOPath != newPath)
|
||
{
|
||
_currentMinIOPath = newPath;
|
||
_sendViewModel.CurrentMinIOPath = newPath;
|
||
RaisePropertyChanged("CurrentMinIOPath");
|
||
|
||
//// 强制刷新导航栏
|
||
//if (_explorerBehavior != null)
|
||
//{
|
||
// _explorerBehavior.RefreshMinIOPath(newPath);
|
||
//}
|
||
}
|
||
}
|
||
}
|
||
|
||
public ObservableCollection<SystemInfoModel> Items { get; } = new ObservableCollection<SystemInfoModel>();
|
||
|
||
//Explorer创建新建文件夹并可编辑
|
||
private async Task CreateNewFolderAsync()
|
||
{
|
||
try
|
||
{
|
||
// 创建新的文件夹模型
|
||
var newFolder = new MinIODirectoryModel(
|
||
new MinIODirectoryInfo(GetCurrentBucket(), "新建文件夹/", false, DateTime.Now))
|
||
{
|
||
IsRenaming = false // 设置为可编辑状态
|
||
};
|
||
|
||
// 通知行为类开始编辑
|
||
_explorerBehavior?.BeginEditNewFolder(newFolder);
|
||
await Task.Delay(100); // 等待UI更新
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
MessageBox.Show($"创建文件夹失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
//minio创建新建文件
|
||
public async Task CreateMinIOFolder(string folderName)
|
||
{
|
||
var builder = new ConfigurationBuilder()
|
||
.SetBasePath(Directory.GetCurrentDirectory())
|
||
.AddJsonFile("global.json", optional: false, reloadOnChange: true);
|
||
// 构建配置
|
||
var config = builder.Build();
|
||
// 从配置获取MinIO设置更安全
|
||
IMinioClient client = new MinioClient()
|
||
.WithEndpoint(config["Minio:Endpoint"])
|
||
.WithCredentials(config["Minio:AccessKey"], config["Minio:SecretKey"])
|
||
.Build();
|
||
string bucket = folderName;
|
||
if (string.IsNullOrWhiteSpace(folderName))
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (!folderName.EndsWith("/"))
|
||
folderName += "/";
|
||
|
||
try
|
||
{
|
||
var bucketName = GetCurrentBucket();
|
||
var prefix = GetCurrentPrefix();
|
||
if (!string.IsNullOrEmpty(bucketName))
|
||
{
|
||
var beArgs = new BucketExistsArgs().WithBucket(bucketName);
|
||
bool found = await client.BucketExistsAsync(beArgs);
|
||
if (!found)
|
||
{
|
||
var mbArgs = new MakeBucketArgs().WithBucket(bucketName);
|
||
await client.MakeBucketAsync(mbArgs);
|
||
}
|
||
|
||
using (var emptyStream = new MemoryStream(Encoding.UTF8.GetBytes(" ")))
|
||
{
|
||
await client.PutObjectAsync(
|
||
new PutObjectArgs()
|
||
.WithBucket(bucketName)
|
||
.WithObject(prefix + folderName)
|
||
.WithStreamData(emptyStream)
|
||
.WithObjectSize(1) // 必须设置为0
|
||
.WithContentType("application/x-directory"));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
var mbArgs = new MakeBucketArgs().WithBucket(bucket);
|
||
await client.MakeBucketAsync(mbArgs);
|
||
}
|
||
|
||
// 刷新当前目录
|
||
_explorerBehavior?.RefreshMinIOPath(CurrentMinIOPath);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
MessageBox.Show($"在MinIO中创建文件夹失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
//获取当前路径下的桶
|
||
private string GetCurrentBucket()
|
||
{
|
||
if (string.IsNullOrEmpty(CurrentMinIOPath))
|
||
return string.Empty;
|
||
|
||
return CurrentMinIOPath.Split('/')[0];
|
||
}
|
||
|
||
//获取桶下的文件路径
|
||
private string GetCurrentPrefix()
|
||
{
|
||
if (string.IsNullOrEmpty(CurrentMinIOPath) || CurrentMinIOPath.IndexOf('/') < 0)
|
||
return string.Empty;
|
||
|
||
return CurrentMinIOPath.Substring(CurrentMinIOPath.IndexOf('/') + 1);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 删除文件夹
|
||
|
||
private ObservableCollection<SystemInfoModel> _selectedItems = new ObservableCollection<SystemInfoModel>();
|
||
|
||
public ObservableCollection<SystemInfoModel> SelectedItems
|
||
{
|
||
get { return _selectedItems; }
|
||
set
|
||
{
|
||
_selectedItems = value;
|
||
RaisePropertyChanged();
|
||
}
|
||
}
|
||
|
||
private ICommand _selectItemsCommand;
|
||
|
||
public ICommand SelectItemsCommand => _selectItemsCommand ??
|
||
(_selectItemsCommand = new RelayCommand<SystemInfoModel>(SelectItem));
|
||
|
||
public ICommand SelectDirCommand { get; set; }
|
||
|
||
// 处理上传完成事件
|
||
private void OnFileUploadCompleted(string currentPath)
|
||
{
|
||
// 检查当前路径是否匹配,如果是则更新显示
|
||
if (CurrentMinIOPath == currentPath || string.IsNullOrEmpty(currentPath))
|
||
{
|
||
Application.Current.Dispatcher.BeginInvoke(() =>
|
||
{
|
||
// 延迟一小段时间以确保服务器端数据同步完成
|
||
Task.Delay(1000).ContinueWith(_ =>
|
||
{
|
||
Application.Current.Dispatcher.Invoke(() =>
|
||
{
|
||
// 只触发Explorer控件的更新而不完全刷新整个页面
|
||
_explorerBehavior?.RefreshMinIOPath(CurrentMinIOPath);
|
||
|
||
// 更新状态信息
|
||
UpdateStatus("文件上传完成,已更新列表");
|
||
});
|
||
});
|
||
});
|
||
}
|
||
}
|
||
|
||
private void SelectItem(SystemInfoModel item)
|
||
{
|
||
if (item == null) return;
|
||
|
||
if (SelectedItems.Contains(item))
|
||
{
|
||
SelectedItems.Remove(item);
|
||
}
|
||
else
|
||
{
|
||
SelectedItems.Add(item);
|
||
}
|
||
|
||
UpdateStatus($"已选中{SelectedItems.Count} 个文件/文件夹");
|
||
}
|
||
|
||
private async Task DeleteSelectedItemsAsync()
|
||
{
|
||
try
|
||
{
|
||
var selectedItems = _selectedItems;
|
||
if (selectedItems == null || !selectedItems.Any())
|
||
{
|
||
await MessageProxy.Messager.ShowResult("请先选择要删除的项目");
|
||
return;
|
||
}
|
||
|
||
var message = $"确定要删除选中的 {selectedItems.Count} 个项目吗?";
|
||
var result = MessageBox.Show(message, "确认删除", MessageBoxButton.YesNo);
|
||
|
||
if (result == MessageBoxResult.Yes)
|
||
{
|
||
await DeleteMinIOItems(selectedItems);
|
||
|
||
MessageBox.Show($"已成功删除 {selectedItems.Count} 个项目");
|
||
_explorerBehavior.RefreshMinIOPath(CurrentMinIOPath);
|
||
SelectedItems.Clear();
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
MessageBox.Show($"删除失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
private async Task DeleteMinIOItems(IEnumerable<SystemInfoModel> items)
|
||
{
|
||
var builder = new ConfigurationBuilder()
|
||
.SetBasePath(Directory.GetCurrentDirectory())
|
||
.AddJsonFile("global.json", optional: false, reloadOnChange: true);
|
||
var config = builder.Build();
|
||
|
||
using var client = new MinioClient()
|
||
.WithEndpoint(config["Minio:Endpoint"])
|
||
.WithCredentials(config["Minio:AccessKey"], config["Minio:SecretKey"])
|
||
.Build();
|
||
|
||
// 按桶分组
|
||
var itemsByBucket = items.GroupBy(item =>
|
||
{
|
||
if (item is MinIOFileModel file)
|
||
return ((MinIOFileInfo)file.Model).BucketName;
|
||
if (item is MinIODirectoryModel dir)
|
||
return ((MinIODirectoryInfo)dir.Model).BucketName;
|
||
return null;
|
||
});
|
||
|
||
foreach (var bucketGroup in itemsByBucket.Where(g => g.Key != null))
|
||
{
|
||
var bucketName = bucketGroup.Key;
|
||
var objectsToDelete = new List<string>();
|
||
|
||
foreach (var item in bucketGroup)
|
||
{
|
||
if (item is MinIOFileModel fileModel)
|
||
{
|
||
var fileInfo = (MinIOFileInfo)fileModel.Model;
|
||
objectsToDelete.Add(fileInfo.FullName.Substring(fileInfo.BucketName.Length + 1));
|
||
}
|
||
else if (item is MinIODirectoryModel dirModel)
|
||
{
|
||
var dirInfo = (MinIODirectoryInfo)dirModel.Model;
|
||
if (dirInfo.BucketName == dirInfo.FullName)
|
||
{
|
||
// 获取文件夹下所有对象
|
||
var listArgs = new ListObjectsArgs()
|
||
.WithBucket(bucketName);
|
||
List<string> list = new List<string>();
|
||
await foreach (var obj in client.ListObjectsEnumAsync(listArgs))
|
||
{
|
||
list.Add(obj.Key);
|
||
}
|
||
|
||
if (list.Count > 0)
|
||
{
|
||
SelectedItems.Clear();
|
||
throw new Exception($"仅能删除空桶!");
|
||
}
|
||
else
|
||
{
|
||
await client.RemoveBucketAsync(new RemoveBucketArgs().WithBucket(dirInfo.BucketName));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
var folderPath = dirInfo.FullName.Substring(dirInfo.BucketName.Length + 1);
|
||
|
||
// 确保文件夹路径以斜杠结尾
|
||
if (!folderPath.EndsWith("/")) folderPath += "/";
|
||
|
||
// 获取文件夹下所有对象
|
||
var listArgs = new ListObjectsArgs()
|
||
.WithBucket(bucketName)
|
||
.WithPrefix(folderPath)
|
||
.WithRecursive(true);
|
||
|
||
await foreach (var obj in client.ListObjectsEnumAsync(listArgs))
|
||
{
|
||
objectsToDelete.Add(obj.Key);
|
||
}
|
||
|
||
// 添加文件夹标记本身
|
||
objectsToDelete.Add(folderPath);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 批量删除
|
||
if (objectsToDelete.Any())
|
||
{
|
||
await client.RemoveObjectsAsync(
|
||
new RemoveObjectsArgs()
|
||
.WithBucket(bucketName)
|
||
.WithObjects(objectsToDelete));
|
||
}
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
// 清理资源
|
||
public void Cleanup()
|
||
{
|
||
if (_sendViewModel != null)
|
||
{
|
||
_sendViewModel.FileUploadCompleted -= OnFileUploadCompleted;
|
||
}
|
||
}
|
||
}
|
||
|
||
internal class DataFileViewModel : ObservableSourceViewModel<TestViewModel>
|
||
{
|
||
protected override void Init()
|
||
{
|
||
base.Init();
|
||
}
|
||
}
|
||
} |