diff --git a/TransportPlugin.csproj b/TransportPlugin.csproj index a899d66..8244912 100644 --- a/TransportPlugin.csproj +++ b/TransportPlugin.csproj @@ -339,6 +339,7 @@ + diff --git a/src/Core/BatchQueueManager.cs b/src/Core/BatchQueueManager.cs index 7fa8935..002ec97 100644 --- a/src/Core/BatchQueueManager.cs +++ b/src/Core/BatchQueueManager.cs @@ -11,6 +11,7 @@ using NavisworksTransport.Core.Collision; using NavisworksTransport.Core.Config; using NavisworksTransport.Core.Models; using NavisworksTransport.Core.Services; +using NavisworksTransport.Utils; namespace NavisworksTransport.Core { @@ -204,6 +205,9 @@ namespace NavisworksTransport.Core /// public async Task ProcessQueueAsync() { + // 自动模式:批处理全程窗口自动选择默认动作并立即关闭(排除列表确认/完成汇总/错误提示等) + using (AutomationModeContext.EnterAutomaticMode()) + { Autodesk.Navisworks.Api.Progress progress = null; // 统计信息 @@ -406,6 +410,7 @@ namespace NavisworksTransport.Core TimeSpan duration = endTime - startTime; ShowBatchSummary(startTime, endTime, duration, totalCount, successCount, failedCount, skippedCount); } + } } /// @@ -463,7 +468,14 @@ namespace NavisworksTransport.Core } LogManager.Info($"[批处理队列] 执行汇总 - 总计:{totalCount}, 成功:{successCount}, 失败:{failedCount}, 跳过:{skippedCount}, 耗时:{durationText}"); - + + // 自动模式下跳过完成弹窗(汇总已写入日志) + if (AutomationModeContext.IsAutomaticMode) + { + LogManager.Info("[批处理队列] 自动模式下跳过完成汇总弹窗"); + return; + } + // 在UI线程显示消息框 System.Windows.Application.Current?.Dispatcher.Invoke(() => { @@ -1043,7 +1055,14 @@ namespace NavisworksTransport.Core // 排除列表为空,提示用户 LogManager.Warning("[批处理队列] 排除列表为空,需要用户确认"); - + + // 自动模式下跳过确认框,默认继续(不使用排除列表) + if (AutomationModeContext.IsAutomaticMode) + { + LogManager.Info("[批处理队列] 自动模式下跳过排除列表确认,默认继续"); + return new List(); + } + bool shouldContinue = false; System.Windows.Application.Current?.Dispatcher.Invoke(() => { diff --git a/src/Core/Collision/ClashDetectiveIntegration.cs b/src/Core/Collision/ClashDetectiveIntegration.cs index 1df4de3..9935ac0 100644 --- a/src/Core/Collision/ClashDetectiveIntegration.cs +++ b/src/Core/Collision/ClashDetectiveIntegration.cs @@ -1305,6 +1305,13 @@ namespace NavisworksTransport /// private void ShowCancellationMessage() { + // 自动模式下跳过取消提示(日志已记录,避免残留弹窗阻塞自动化) + if (AutomationModeContext.IsAutomaticMode) + { + LogManager.Info("[ClashDetective] 自动模式下跳过检测取消提示框"); + return; + } + try { // 获取 Navisworks 主窗口句柄作为父窗口 diff --git a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs index 1d7858c..402c448 100644 --- a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs +++ b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs @@ -3623,7 +3623,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels { try { - if (DialogHelper.IsTestAutomationModeEnabled) + if (AutomationModeContext.IsAutomaticMode) { LogManager.Info("[碰撞分析] 自动测试模式下跳过预计算碰撞分析"); SaveCollisionDetectionRecord(); @@ -3861,7 +3861,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels string routeId = CurrentPathRoute?.Id ?? ""; - if (!DialogHelper.IsTestAutomationModeEnabled) + if (!AutomationModeContext.IsAutomaticMode) { // 🔥 检查是否已有相同配置的检测记录 var existingRecordResult = CheckExistingDetectionRecord(); @@ -4154,7 +4154,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels /// private (int id, UserChoice userChoice)? ShowDuplicateConfigDialog(CollisionDetectionRecord record) { - if (TestAutomationHttpService.ShouldAutoChooseCreateNewDetectionRecord) + if (TestAutomationHttpService.ShouldAutoChooseCreateNewDetectionRecord || + AutomationModeContext.IsAutomaticMode) { _lastReusedRecordId = null; LogManager.Info($"[检测记录] 测试自动化已接管重复配置对话框,自动选择重新生成新记录 (ExistingId={record.Id})"); diff --git a/src/UI/WPF/Views/CollisionAnalysisDialog.xaml.cs b/src/UI/WPF/Views/CollisionAnalysisDialog.xaml.cs index 2096cba..54b6784 100644 --- a/src/UI/WPF/Views/CollisionAnalysisDialog.xaml.cs +++ b/src/UI/WPF/Views/CollisionAnalysisDialog.xaml.cs @@ -67,7 +67,8 @@ namespace NavisworksTransport.UI.WPF.Views private void CollisionAnalysisDialog_Loaded(object sender, RoutedEventArgs e) { - if (!TestAutomationHttpService.ShouldAutoConfirmCollisionAnalysisDialogs) + if (!TestAutomationHttpService.ShouldAutoConfirmCollisionAnalysisDialogs && + !AutomationModeContext.IsAutomaticMode) { return; } diff --git a/src/Utils/AutomationModeContext.cs b/src/Utils/AutomationModeContext.cs new file mode 100644 index 0000000..e71d81f --- /dev/null +++ b/src/Utils/AutomationModeContext.cs @@ -0,0 +1,59 @@ +using System; +using System.Threading; + +namespace NavisworksTransport.Utils +{ + /// + /// 自动模式上下文(自动测试 / 批处理执行期间)。 + /// + /// 自动模式下: + /// - 窗口(对话框/提示框)自动选择默认动作并立即关闭(或直接跳过弹窗) + /// - 保证自动测试与批处理流畅进行,无需人工干预 + /// + /// 进入方式: + /// - 批处理执行(BatchQueueManager.ProcessQueueAsync)全程 + /// - 测试 HTTP 端点(TestAutomationHttpService 计数器,兼容保留) + /// - 环境变量 TRANSPORTPLUGIN_TEST_AUTOMATION=1(副实例/测试进程) + /// + public static class AutomationModeContext + { + private static int _requestCount; + + /// + /// 当前是否处于自动模式(任一来源生效:运行时计数 / 环境变量)。 + /// + public static bool IsAutomaticMode => + Interlocked.CompareExchange(ref _requestCount, 0, 0) > 0 || + DialogHelper.IsTestAutomationModeEnabled; + + /// + /// 进入自动模式(可嵌套),Dispose 时退出。 + /// + public static IDisposable EnterAutomaticMode() + { + Interlocked.Increment(ref _requestCount); + return new ActionOnDispose(() => + { + if (Interlocked.Decrement(ref _requestCount) < 0) + { + Interlocked.Exchange(ref _requestCount, 0); + } + }); + } + + private sealed class ActionOnDispose : IDisposable + { + private readonly Action _action; + + public ActionOnDispose(Action action) + { + _action = action; + } + + public void Dispose() + { + _action?.Invoke(); + } + } + } +} diff --git a/src/Utils/DialogHelper.cs b/src/Utils/DialogHelper.cs index ae9044d..b779edc 100644 --- a/src/Utils/DialogHelper.cs +++ b/src/Utils/DialogHelper.cs @@ -180,7 +180,7 @@ namespace NavisworksTransport.Utils MessageBoxImage icon = MessageBoxImage.Information, int autoCloseMilliseconds = 4000) { - if (IsTestAutomationModeEnabled) + if (AutomationModeContext.IsAutomaticMode) { LogManager.Info($"[DialogHelper] 自动测试模式下跳过自动关闭提示框: {caption}"); return;