NavisworksTransport/src/Commands/DeletePathCommand.cs

655 lines
25 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using NavisworksTransport.Core;
using NavisworksTransport.PathPlanning;
using NavisworksTransport.Utils;
namespace NavisworksTransport.Commands
{
/// <summary>
/// 删除路径参数类
/// </summary>
public class DeletePathParameters
{
/// <summary>
/// 要删除的路径集合
/// </summary>
public List<PathRoute> PathsToDelete { get; set; }
/// <summary>
/// 路径ID集合作为PathsToDelete的替代
/// </summary>
public List<string> PathIds { get; set; }
/// <summary>
/// 是否删除所有路径
/// </summary>
public bool DeleteAll { get; set; } = false;
/// <summary>
/// 是否创建删除前的备份
/// </summary>
public bool CreateBackup { get; set; } = true;
/// <summary>
/// 删除确认回调函数
/// </summary>
public Func<PathRoute, bool> ConfirmDeleteCallback { get; set; }
/// <summary>
/// 是否强制删除(跳过确认)
/// </summary>
public bool ForceDelete { get; set; } = false;
/// <summary>
/// 操作描述
/// </summary>
public string Description { get; set; }
public DeletePathParameters()
{
PathsToDelete = new List<PathRoute>();
PathIds = new List<string>();
}
/// <summary>
/// 验证参数有效性
/// </summary>
public PathPlanningResult ValidateParameters()
{
var errors = new List<string>();
if (!DeleteAll)
{
if ((PathsToDelete == null || PathsToDelete.Count == 0) &&
(PathIds == null || PathIds.Count == 0))
{
errors.Add("必须指定要删除的路径或路径ID或设置DeleteAll为true");
}
// 检查路径有效性
if (PathsToDelete != null)
{
foreach (var path in PathsToDelete)
{
if (path == null)
{
errors.Add("路径集合包含空引用");
break;
}
}
}
// 检查路径ID有效性
if (PathIds != null)
{
foreach (var id in PathIds)
{
if (string.IsNullOrWhiteSpace(id))
{
errors.Add("路径ID集合包含空或无效的ID");
break;
}
}
}
}
if (errors.Count > 0)
{
return PathPlanningResult.ValidationFailure($"参数验证失败: {string.Join("; ", errors)}");
}
return PathPlanningResult.Success("参数验证通过");
}
}
/// <summary>
/// 删除路径结果类
/// </summary>
public class DeletePathResult
{
/// <summary>
/// 成功删除的路径数量
/// </summary>
public int DeletedCount { get; set; }
/// <summary>
/// 失败的路径数量
/// </summary>
public int FailedCount { get; set; }
/// <summary>
/// 跳过的路径数量(用户取消确认)
/// </summary>
public int SkippedCount { get; set; }
/// <summary>
/// 总路径数量
/// </summary>
public int TotalCount { get; set; }
/// <summary>
/// 已删除的路径信息
/// </summary>
public List<string> DeletedPaths { get; set; }
/// <summary>
/// 删除失败的路径信息
/// </summary>
public List<string> FailedPaths { get; set; }
/// <summary>
/// 备份文件路径(如果创建了备份)
/// </summary>
public string BackupFilePath { get; set; }
/// <summary>
/// 操作执行时间(毫秒)
/// </summary>
public long ExecutionTimeMs { get; set; }
public DeletePathResult()
{
DeletedPaths = new List<string>();
FailedPaths = new List<string>();
}
/// <summary>
/// 删除成功率
/// </summary>
public double DeleteSuccessRate => TotalCount > 0 ? (double)DeletedCount / TotalCount : 0.0;
}
/// <summary>
/// 删除路径Command
/// </summary>
public class DeletePathCommand : CommandBase
{
#region
private readonly DeletePathParameters _parameters;
private readonly PathPlanningManager _pathPlanningManager;
private readonly UIStateManager _uiStateManager;
/// <summary>
/// 命令参数
/// </summary>
public DeletePathParameters Parameters => _parameters;
#endregion
#region
/// <summary>
/// 初始化删除路径命令
/// </summary>
/// <param name="parameters">删除参数</param>
/// <param name="pathPlanningManager">路径规划管理器</param>
public DeletePathCommand(DeletePathParameters parameters, PathPlanningManager pathPlanningManager = null)
: base("DeletePath", "删除路径", "删除指定的路径规划数据")
{
_parameters = parameters ?? throw new ArgumentNullException(nameof(parameters));
_pathPlanningManager = pathPlanningManager ?? throw new ArgumentNullException(nameof(pathPlanningManager));
_uiStateManager = UIStateManager.Instance;
LogInfo("删除路径命令初始化完成");
}
#endregion
#region CommandBase实现
/// <summary>
/// 验证命令参数
/// </summary>
protected override PathPlanningResult ValidateParameters()
{
LogInfo("开始验证删除路径参数");
try
{
// 验证基础参数
var basicValidation = _parameters.ValidateParameters();
if (!basicValidation.IsSuccess)
{
LogWarning($"基础参数验证失败: {basicValidation.ErrorMessage}");
return basicValidation;
}
// 验证PathPlanningManager状态
if (_pathPlanningManager == null)
{
return PathPlanningResult.ValidationFailure("路径规划管理器未初始化");
}
// 检查是否有路径可删除
if (!_parameters.DeleteAll && _pathPlanningManager.Routes.Count == 0)
{
return PathPlanningResult.ValidationFailure("当前没有可删除的路径");
}
// 如果指定了路径ID验证ID是否存在
if (_parameters.PathIds.Count > 0)
{
var availableIds = _pathPlanningManager.Routes.Select(r => r.Id).ToHashSet();
var invalidIds = _parameters.PathIds.Where(id => !availableIds.Contains(id)).ToList();
if (invalidIds.Count > 0)
{
LogWarning($"发现无效的路径ID: {string.Join(", ", invalidIds)}");
// 不阻止执行,只是警告
}
}
LogInfo("参数验证通过");
return PathPlanningResult.Success("所有参数验证通过");
}
catch (Exception ex)
{
LogError("参数验证过程中发生异常", ex);
return PathPlanningResult.ValidationFailure($"验证过程异常: {ex.Message}");
}
}
/// <summary>
/// 执行删除路径的核心逻辑
/// </summary>
protected override async Task<PathPlanningResult> ExecuteInternalAsync(CancellationToken cancellationToken)
{
LogInfo("开始执行删除路径");
var startTime = DateTime.UtcNow;
try
{
// 第一阶段初始化10%
UpdateProgress(10, "正在初始化删除操作...");
ThrowIfCancellationRequested(cancellationToken);
// 更新UI状态
await _uiStateManager.ExecuteUIUpdateAsync(() =>
{
LogInfo("UI状态更新路径删除进行中");
});
// 第二阶段收集要删除的路径20%
UpdateProgress(20, "正在收集要删除的路径...");
ThrowIfCancellationRequested(cancellationToken);
var pathsToDelete = await Task.Run(() => CollectPathsToDelete(), cancellationToken);
if (pathsToDelete.Count == 0)
{
LogWarning("没有找到需要删除的路径");
return PathPlanningResult.Success("没有找到需要删除的路径");
}
LogInfo($"收集到 {pathsToDelete.Count} 个路径待删除");
var result = new DeletePathResult
{
TotalCount = pathsToDelete.Count
};
// 第三阶段创建备份30%
if (_parameters.CreateBackup && pathsToDelete.Count > 0)
{
UpdateProgress(30, "正在创建删除前备份...");
ThrowIfCancellationRequested(cancellationToken);
try
{
result.BackupFilePath = await CreateBackupAsync(pathsToDelete, cancellationToken);
LogInfo($"备份已创建: {result.BackupFilePath}");
}
catch (Exception backupEx)
{
LogWarning($"创建备份失败: {backupEx.Message}");
// 备份失败不阻止删除操作,但记录警告
}
}
// 第四阶段执行删除操作40% - 80%
UpdateProgress(40, "正在删除路径...");
ThrowIfCancellationRequested(cancellationToken);
await Task.Run(() =>
{
try
{
LogInfo("开始批量删除路径");
int processedCount = 0;
foreach (var path in pathsToDelete)
{
try
{
// 检查取消请求
ThrowIfCancellationRequested(cancellationToken);
// 检查是否需要确认删除
bool shouldDelete = _parameters.ForceDelete;
if (!shouldDelete && _parameters.ConfirmDeleteCallback != null)
{
shouldDelete = _parameters.ConfirmDeleteCallback(path);
if (!shouldDelete)
{
result.SkippedCount++;
LogInfo($"用户取消删除路径: {path.Name}");
processedCount++;
continue;
}
}
else if (!_parameters.ForceDelete)
{
// 默认删除
shouldDelete = true;
}
if (shouldDelete)
{
// 执行删除
bool deleteSuccess = _pathPlanningManager.DeleteRoute(path);
if (deleteSuccess)
{
result.DeletedCount++;
result.DeletedPaths.Add($"{path.Name} (ID: {path.Id})");
LogInfo($"成功删除路径: {path.Name}");
}
else
{
result.FailedCount++;
result.FailedPaths.Add($"{path.Name} (ID: {path.Id}) - 删除操作失败");
LogWarning($"删除路径失败: {path.Name}");
}
}
processedCount++;
// 更新进度40% - 80%
var progressPercent = 40 + (int)((double)processedCount / pathsToDelete.Count * 40);
UpdateProgress(progressPercent, $"正在删除路径... ({processedCount}/{pathsToDelete.Count})");
}
catch (OperationCanceledException)
{
throw; // 重新抛出取消异常
}
catch (Exception pathEx)
{
result.FailedCount++;
result.FailedPaths.Add($"{path.Name} (ID: {path.Id}) - 异常: {pathEx.Message}");
LogError($"删除路径时发生异常: {path.Name}", pathEx);
}
}
LogInfo($"路径删除完成 - 删除: {result.DeletedCount}, 失败: {result.FailedCount}, 跳过: {result.SkippedCount}");
}
catch (OperationCanceledException)
{
LogInfo("路径删除被用户取消");
throw; // 重新抛出取消异常
}
catch (Exception ex)
{
LogError("批量删除路径时发生异常", ex);
throw;
}
}, cancellationToken);
UpdateProgress(85, "正在完成删除操作...");
ThrowIfCancellationRequested(cancellationToken);
// 第五阶段刷新UI状态90%
UpdateProgress(90, "正在刷新界面状态...");
try
{
await _uiStateManager.ExecuteUIUpdateAsync(() =>
{
// 如果删除了当前路径,需要选择新的当前路径
if (_pathPlanningManager.Routes.Count > 0 && _pathPlanningManager.CurrentRoute == null)
{
_pathPlanningManager.SetCurrentRoute(_pathPlanningManager.Routes.First());
}
LogInfo("UI状态已刷新");
});
}
catch (Exception refreshEx)
{
LogWarning($"刷新UI状态失败: {refreshEx.Message}");
}
// 完成100%
UpdateProgress(100, "路径删除完成");
var elapsedMs = (DateTime.UtcNow - startTime).TotalMilliseconds;
result.ExecutionTimeMs = (long)elapsedMs;
LogInfo($"删除路径执行完成,总耗时: {elapsedMs:F0}ms");
LogInfo($"删除结果 - 总数: {result.TotalCount}, 删除: {result.DeletedCount}, 失败: {result.FailedCount}, 跳过: {result.SkippedCount}");
// 创建结果对象
string resultMessage;
if (result.TotalCount == 0)
{
resultMessage = "没有找到需要删除的路径";
}
else
{
resultMessage = $"路径删除完成:删除 {result.DeletedCount}/{result.TotalCount} 项";
if (result.FailedCount > 0)
{
resultMessage += $",失败 {result.FailedCount} 项";
}
if (result.SkippedCount > 0)
{
resultMessage += $",跳过 {result.SkippedCount} 项";
}
}
var commandResult = PathPlanningResult<DeletePathResult>.Success(result, resultMessage);
commandResult.ElapsedMilliseconds = (long)elapsedMs;
return commandResult;
}
catch (OperationCanceledException)
{
LogInfo("删除路径被用户取消");
throw; // 让基类处理取消异常
}
catch (Exception ex)
{
var elapsedMs = (DateTime.UtcNow - startTime).TotalMilliseconds;
LogError($"删除路径执行失败,已耗时: {elapsedMs:F0}ms", ex);
// 尝试恢复UI状态
try
{
await _uiStateManager.ExecuteUIUpdateAsync(() =>
{
LogInfo("尝试恢复UI状态");
});
}
catch (Exception uiEx)
{
LogError("UI状态恢复失败", uiEx);
}
return PathPlanningResult.Failure($"删除路径失败: {ex.Message}", ex);
}
}
#endregion
#region
/// <summary>
/// 收集要删除的路径
/// </summary>
private List<PathRoute> CollectPathsToDelete()
{
var pathsToDelete = new List<PathRoute>();
if (_parameters.DeleteAll)
{
// 删除所有路径
pathsToDelete.AddRange(_pathPlanningManager.Routes);
LogInfo($"收集所有路径进行删除:{pathsToDelete.Count} 个");
}
else
{
// 从直接指定的路径收集
if (_parameters.PathsToDelete != null)
{
pathsToDelete.AddRange(_parameters.PathsToDelete.Where(p => p != null));
}
// 从路径ID收集
if (_parameters.PathIds != null && _parameters.PathIds.Count > 0)
{
var availableRoutes = _pathPlanningManager.Routes.ToLookup(r => r.Id);
foreach (var pathId in _parameters.PathIds.Where(id => !string.IsNullOrWhiteSpace(id)))
{
var routes = availableRoutes[pathId];
pathsToDelete.AddRange(routes);
}
}
// 去重
pathsToDelete = pathsToDelete.Distinct().ToList();
LogInfo($"收集指定路径进行删除:{pathsToDelete.Count} 个");
}
return pathsToDelete;
}
/// <summary>
/// 创建删除前备份
/// </summary>
private async Task<string> CreateBackupAsync(List<PathRoute> pathsToDelete, CancellationToken cancellationToken)
{
try
{
var backupFileName = $"路径删除备份_{DateTime.Now:yyyyMMdd_HHmmss}.xml";
var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var backupPath = System.IO.Path.Combine(documentsPath, "NavisworksTransport", "Backups");
if (!System.IO.Directory.Exists(backupPath))
{
System.IO.Directory.CreateDirectory(backupPath);
}
var backupFilePath = System.IO.Path.Combine(backupPath, backupFileName);
// 使用PathDataManager创建备份
var pathDataManager = new PathDataManager();
var exportSettings = new ExportSettings
{
ProjectName = "删除前备份",
Description = $"删除 {pathsToDelete.Count} 个路径前的备份",
Units = "meters"
};
await Task.Run(() =>
{
bool success = pathDataManager.ExportToXml(pathsToDelete, backupFilePath, exportSettings);
if (!success)
{
throw new InvalidOperationException("备份文件创建失败");
}
}, cancellationToken);
return backupFilePath;
}
catch (Exception ex)
{
LogError("创建备份文件失败", ex);
throw;
}
}
#endregion
#region
/// <summary>
/// 创建删除单个路径的快捷命令
/// </summary>
/// <param name="pathToDelete">要删除的路径</param>
/// <param name="createBackup">是否创建备份</param>
/// <param name="forceDelete">是否强制删除</param>
/// <returns>删除路径命令实例</returns>
public static DeletePathCommand CreateSingle(PathRoute pathToDelete, bool createBackup = true, bool forceDelete = false)
{
var parameters = new DeletePathParameters
{
PathsToDelete = new List<PathRoute> { pathToDelete },
CreateBackup = createBackup,
ForceDelete = forceDelete,
Description = $"删除路径: {pathToDelete?.Name}"
};
return new DeletePathCommand(parameters);
}
/// <summary>
/// 创建删除多个路径的快捷命令
/// </summary>
/// <param name="pathsToDelete">要删除的路径集合</param>
/// <param name="createBackup">是否创建备份</param>
/// <param name="confirmCallback">删除确认回调</param>
/// <returns>删除路径命令实例</returns>
public static DeletePathCommand CreateMultiple(List<PathRoute> pathsToDelete, bool createBackup = true, Func<PathRoute, bool> confirmCallback = null)
{
var parameters = new DeletePathParameters
{
PathsToDelete = pathsToDelete ?? new List<PathRoute>(),
CreateBackup = createBackup,
ConfirmDeleteCallback = confirmCallback,
ForceDelete = confirmCallback == null, // 如果没有确认回调,则强制删除
Description = $"删除 {pathsToDelete?.Count ?? 0} 个路径"
};
return new DeletePathCommand(parameters);
}
/// <summary>
/// 创建删除所有路径的快捷命令
/// </summary>
/// <param name="createBackup">是否创建备份</param>
/// <param name="confirmCallback">删除确认回调</param>
/// <returns>删除路径命令实例</returns>
public static DeletePathCommand CreateDeleteAll(bool createBackup = true, Func<PathRoute, bool> confirmCallback = null)
{
var parameters = new DeletePathParameters
{
DeleteAll = true,
CreateBackup = createBackup,
ConfirmDeleteCallback = confirmCallback,
ForceDelete = confirmCallback == null, // 如果没有确认回调,则强制删除
Description = "删除所有路径"
};
return new DeletePathCommand(parameters);
}
/// <summary>
/// 获取命令执行摘要信息
/// </summary>
/// <returns>命令信息摘要</returns>
public string GetExecutionSummary()
{
var targetDescription = _parameters.DeleteAll ? "所有路径" :
$"{_parameters.PathsToDelete?.Count ?? 0} + {_parameters.PathIds?.Count ?? 0} 个路径";
return $"删除路径命令 - 目标:{targetDescription}, " +
$"备份:{_parameters.CreateBackup}, " +
$"强制:{_parameters.ForceDelete}, " +
$"状态:{Status}";
}
#endregion
}
}