NavisworksTransport/src/Commands/SetLogisticsAttributeCommand.cs
2025-10-21 18:48:27 +08:00

490 lines
19 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 Autodesk.Navisworks.Api;
using NavisworksTransport.Core;
namespace NavisworksTransport.Commands
{
/// <summary>
/// 设置物流属性参数类
/// </summary>
public class SetLogisticsAttributeParameters
{
/// <summary>
/// 目标模型项集合
/// </summary>
public ModelItemCollection TargetItems { get; set; }
/// <summary>
/// 物流元素类型
/// </summary>
public CategoryAttributeManager.LogisticsElementType ElementType { get; set; }
/// <summary>
/// 是否可通行(仅对通道类型有效)
/// </summary>
public bool? IsTraversable { get; set; }
/// <summary>
/// 自定义属性字典
/// </summary>
public Dictionary<string, object> CustomAttributes { get; set; }
/// <summary>
/// 是否覆盖现有属性
/// </summary>
public bool OverwriteExisting { get; set; } = true;
/// <summary>
/// 操作描述(用于日志记录)
/// </summary>
public string Description { get; set; }
public SetLogisticsAttributeParameters()
{
TargetItems = new ModelItemCollection();
CustomAttributes = new Dictionary<string, object>();
}
/// <summary>
/// 验证参数有效性
/// </summary>
public PathPlanningResult ValidateParameters()
{
var errors = new List<string>();
if (TargetItems == null || TargetItems.Count == 0)
errors.Add("目标模型项集合不能为空");
if (!Enum.IsDefined(typeof(CategoryAttributeManager.LogisticsElementType), ElementType))
errors.Add("无效的物流元素类型");
// 检查通道类型的特殊要求
if (ElementType == CategoryAttributeManager.LogisticsElementType. && !IsTraversable.HasValue)
{
errors.Add("通道类型必须指定是否可通行");
}
if (errors.Count > 0)
{
return PathPlanningResult.ValidationFailure($"参数验证失败: {string.Join("; ", errors)}");
}
return PathPlanningResult.Success("参数验证通过");
}
}
/// <summary>
/// 设置物流属性结果类
/// </summary>
public class SetLogisticsAttributeResult
{
/// <summary>
/// 成功设置属性的模型项数量
/// </summary>
public int SuccessCount { get; set; }
/// <summary>
/// 失败的模型项数量
/// </summary>
public int FailureCount { get; set; }
/// <summary>
/// 总模型项数量
/// </summary>
public int TotalCount { get; set; }
/// <summary>
/// 详细结果信息
/// </summary>
public List<string> DetailedResults { get; set; }
/// <summary>
/// 已设置的物流元素类型
/// </summary>
public CategoryAttributeManager.LogisticsElementType ElementType { get; set; }
/// <summary>
/// 操作执行时间(毫秒)
/// </summary>
public long ExecutionTimeMs { get; set; }
public SetLogisticsAttributeResult()
{
DetailedResults = new List<string>();
}
/// <summary>
/// 成功率
/// </summary>
public double SuccessRate => TotalCount > 0 ? (double)SuccessCount / TotalCount : 0.0;
}
/// <summary>
/// 设置物流属性Command
/// </summary>
public class SetLogisticsAttributeCommand : CommandBase
{
#region
private readonly SetLogisticsAttributeParameters _parameters;
private readonly CategoryAttributeManager _categoryAttributeManager;
private readonly UIStateManager _uiStateManager;
/// <summary>
/// 命令参数
/// </summary>
public SetLogisticsAttributeParameters Parameters => _parameters;
#endregion
#region
/// <summary>
/// 初始化设置物流属性命令
/// </summary>
/// <param name="parameters">设置参数</param>
/// <param name="categoryAttributeManager">类别属性管理器</param>
public SetLogisticsAttributeCommand(SetLogisticsAttributeParameters parameters, CategoryAttributeManager categoryAttributeManager = null)
: base("SetLogisticsAttribute", "设置物流属性", "为指定模型项设置物流相关的属性信息")
{
_parameters = parameters ?? throw new ArgumentNullException(nameof(parameters));
_categoryAttributeManager = categoryAttributeManager ?? new CategoryAttributeManager();
_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;
}
// 验证CategoryAttributeManager状态
if (_categoryAttributeManager == null)
{
return PathPlanningResult.ValidationFailure("类别属性管理器未初始化");
}
// 验证Navisworks文档状态
var document = Application.ActiveDocument;
if (document?.Models == null || !document.Models.Any())
{
return PathPlanningResult.ValidationFailure("当前没有加载的Navisworks模型");
}
// 验证目标模型项是否在当前文档中
foreach (ModelItem item in _parameters.TargetItems)
{
if (item == null)
{
return PathPlanningResult.ValidationFailure("目标模型项集合包含空引用");
}
}
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 totalItems = _parameters.TargetItems.Count;
LogInfo($"目标模型项数量: {totalItems}");
LogInfo($"物流元素类型: {_parameters.ElementType}");
LogInfo($"是否覆盖现有属性: {_parameters.OverwriteExisting}");
if (_parameters.IsTraversable.HasValue)
{
LogInfo($"可通行性设置: {_parameters.IsTraversable.Value}");
}
// 第三阶段执行属性设置30% - 80%
UpdateProgress(30, "正在设置物流属性...");
ThrowIfCancellationRequested(cancellationToken);
var result = new SetLogisticsAttributeResult
{
TotalCount = totalItems,
ElementType = _parameters.ElementType
};
// 在后台线程中执行属性设置操作
await Task.Run(() =>
{
try
{
LogInfo("开始批量设置物流属性");
int processedCount = 0;
foreach (ModelItem item in _parameters.TargetItems)
{
try
{
// 检查取消请求
ThrowIfCancellationRequested(cancellationToken);
// 设置基本物流属性
// 创建单个项目的ModelItemCollection
var itemCollection = new ModelItemCollection
{
item
};
// 使用配置的默认值添加物流属性
int affectedCount = CategoryAttributeManager.AddLogisticsAttributes(
itemCollection,
_parameters.ElementType);
bool success = affectedCount > 0;
if (success)
{
// 如果是通道类型,设置可通行性
if (_parameters.ElementType == CategoryAttributeManager.LogisticsElementType. &&
_parameters.IsTraversable.HasValue)
{
success = _categoryAttributeManager.SetTraversable(item, _parameters.IsTraversable.Value);
}
// 设置自定义属性
if (success && _parameters.CustomAttributes.Count > 0)
{
foreach (var kvp in _parameters.CustomAttributes)
{
try
{
_categoryAttributeManager.SetCustomAttribute(item, kvp.Key, kvp.Value?.ToString() ?? string.Empty, _parameters.OverwriteExisting);
}
catch (Exception attrEx)
{
LogWarning($"设置自定义属性失败 - 项: {item.DisplayName}, 属性: {kvp.Key}, 错误: {attrEx.Message}");
}
}
}
}
if (success)
{
result.SuccessCount++;
result.DetailedResults.Add($"成功: {item.DisplayName}");
LogInfo($"成功设置物流属性: {item.DisplayName} -> {_parameters.ElementType}");
}
else
{
result.FailureCount++;
result.DetailedResults.Add($"失败: {item.DisplayName}");
LogWarning($"设置物流属性失败: {item.DisplayName}");
}
processedCount++;
// 更新进度30% - 80%
var progressPercent = 30 + (int)((double)processedCount / totalItems * 50);
UpdateProgress(progressPercent, $"正在设置物流属性... ({processedCount}/{totalItems})");
}
catch (OperationCanceledException)
{
throw; // 重新抛出取消异常
}
catch (Exception itemEx)
{
result.FailureCount++;
result.DetailedResults.Add($"异常: {item.DisplayName} - {itemEx.Message}");
LogError($"设置模型项属性时发生异常: {item.DisplayName}", itemEx);
}
}
LogInfo($"物流属性设置完成 - 成功: {result.SuccessCount}, 失败: {result.FailureCount}");
}
catch (OperationCanceledException)
{
LogInfo("物流属性设置被用户取消");
throw; // 重新抛出取消异常
}
catch (Exception ex)
{
LogError("批量设置物流属性时发生异常", ex);
throw;
}
}, cancellationToken);
UpdateProgress(85, "正在完成属性设置...");
ThrowIfCancellationRequested(cancellationToken);
// 第四阶段保存更改和后处理90%
UpdateProgress(90, "正在保存更改...");
// 刷新文档以确保属性更改生效
try
{
await _uiStateManager.ExecuteUIUpdateAsync(() =>
{
// 触发文档刷新
Application.ActiveDocument.CurrentSelection.Clear();
LogInfo("文档状态已刷新");
});
}
catch (Exception refreshEx)
{
LogWarning($"刷新文档状态失败: {refreshEx.Message}");
}
// 完成100%
UpdateProgress(100, "物流属性设置完成");
var elapsedMs = (DateTime.UtcNow - startTime).TotalMilliseconds;
result.ExecutionTimeMs = (long)elapsedMs;
LogInfo($"设置物流属性执行完成,总耗时: {elapsedMs:F0}ms");
LogInfo($"设置结果 - 总数: {result.TotalCount}, 成功: {result.SuccessCount}, 失败: {result.FailureCount}, 成功率: {result.SuccessRate:P2}");
// 创建结果对象
var commandResult = PathPlanningResult<SetLogisticsAttributeResult>.Success(
result,
$"物流属性设置完成:成功 {result.SuccessCount}/{result.TotalCount} 项,成功率 {result.SuccessRate:P2}"
);
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>
/// <param name="targetItems">目标模型项</param>
/// <param name="elementType">物流元素类型</param>
/// <param name="isTraversable">是否可通行(通道类型)</param>
/// <param name="description">操作描述</param>
/// <returns>设置物流属性命令实例</returns>
public static SetLogisticsAttributeCommand CreateQuick(ModelItemCollection targetItems,
CategoryAttributeManager.LogisticsElementType elementType,
bool? isTraversable = null,
string description = null)
{
var parameters = new SetLogisticsAttributeParameters
{
TargetItems = targetItems ?? new ModelItemCollection(),
ElementType = elementType,
IsTraversable = isTraversable,
Description = description,
OverwriteExisting = true
};
return new SetLogisticsAttributeCommand(parameters);
}
/// <summary>
/// 创建带自定义属性的设置命令
/// </summary>
/// <param name="targetItems">目标模型项</param>
/// <param name="elementType">物流元素类型</param>
/// <param name="customAttributes">自定义属性</param>
/// <param name="overwriteExisting">是否覆盖现有属性</param>
/// <returns>设置物流属性命令实例</returns>
public static SetLogisticsAttributeCommand CreateWithCustomAttributes(ModelItemCollection targetItems,
CategoryAttributeManager.LogisticsElementType elementType,
Dictionary<string, object> customAttributes,
bool overwriteExisting = true)
{
var parameters = new SetLogisticsAttributeParameters
{
TargetItems = targetItems ?? new ModelItemCollection(),
ElementType = elementType,
CustomAttributes = customAttributes ?? new Dictionary<string, object>(),
OverwriteExisting = overwriteExisting
};
return new SetLogisticsAttributeCommand(parameters);
}
/// <summary>
/// 获取命令执行摘要信息
/// </summary>
/// <returns>命令信息摘要</returns>
public string GetExecutionSummary()
{
return $"设置物流属性命令 - 目标数量:{_parameters.TargetItems?.Count ?? 0}, " +
$"元素类型:{_parameters.ElementType}, " +
$"可通行:{_parameters.IsTraversable?.ToString() ?? ""}, " +
$"状态:{Status}";
}
#endregion
}
}