From a655e8092ce5965b5423e382e90f0e5cdc61c798 Mon Sep 17 00:00:00 2001
From: tian <11429339@qq.com>
Date: Sat, 7 Feb 2026 01:56:24 +0800
Subject: [PATCH] =?UTF-8?q?=E5=BB=BA=E7=AB=8B=E7=AE=80=E5=8D=95=E7=9A=84?=
=?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93=E5=A4=87=E4=BB=BD=E5=92=8C=E6=81=A2?=
=?UTF-8?q?=E5=A4=8D=E6=9C=BA=E5=88=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
NavisworksTransportPlugin.csproj | 4 +
doc/requirement/todo_features.md | 6 +
packages.config | 1 +
src/Core/Database/BackupManager.cs | 276 +++++++++++++
src/Core/PathDatabase.cs | 113 ++++++
.../ViewModels/SystemManagementViewModel.cs | 379 ++++++++++++++++++
src/UI/WPF/Views/SystemManagementView.xaml | 74 ++++
7 files changed, 853 insertions(+)
create mode 100644 src/Core/Database/BackupManager.cs
diff --git a/NavisworksTransportPlugin.csproj b/NavisworksTransportPlugin.csproj
index 4c86306..4c2f019 100644
--- a/NavisworksTransportPlugin.csproj
+++ b/NavisworksTransportPlugin.csproj
@@ -64,6 +64,9 @@
+
+ packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll
+
@@ -131,6 +134,7 @@
+
diff --git a/doc/requirement/todo_features.md b/doc/requirement/todo_features.md
index 9d5cb04..5725724 100644
--- a/doc/requirement/todo_features.md
+++ b/doc/requirement/todo_features.md
@@ -2,6 +2,12 @@
## 功能点
+### [2026/2/6]
+
+1. [x] (功能)在碰撞报告中支持多张截图
+2. [x] (功能)增加提取元素的包围盒信息,并一键拷贝到坐标编辑窗口
+3. [x] (功能)在状态栏增加路径可视化快捷按钮
+
### [2026/2/3]
1. [x] (优化)预计算高亮正确,结果高亮错误,高亮了很多不相干的同名物体
diff --git a/packages.config b/packages.config
index 6698170..5c4ba8d 100644
--- a/packages.config
+++ b/packages.config
@@ -6,4 +6,5 @@
+
\ No newline at end of file
diff --git a/src/Core/Database/BackupManager.cs b/src/Core/Database/BackupManager.cs
new file mode 100644
index 0000000..ad110a9
--- /dev/null
+++ b/src/Core/Database/BackupManager.cs
@@ -0,0 +1,276 @@
+using System;
+using System.Data.SQLite;
+using System.IO;
+
+namespace NavisworksTransport.Core.Database
+{
+ ///
+ /// 简单数据库备份管理器
+ /// 直接备份整个 SQLite 数据库文件,100% 保留所有数据
+ ///
+ public class BackupManager
+ {
+ private readonly PathDatabase _database;
+ private readonly string _dbPath;
+
+ public BackupManager(PathDatabase database)
+ {
+ _database = database ?? throw new ArgumentNullException(nameof(database));
+ _dbPath = GetDatabaseFilePath(database);
+ }
+
+ ///
+ /// 获取数据库文件路径
+ ///
+ private string GetDatabaseFilePath(PathDatabase database)
+ {
+ // 通过反射获取私有字段 _dbPath
+ var field = typeof(PathDatabase).GetField("_dbPath", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
+ return field?.GetValue(database) as string ?? "";
+ }
+
+ ///
+ /// 获取数据库版本号
+ ///
+ public int GetDatabaseVersion()
+ {
+ try
+ {
+ using (var cmd = new SQLiteCommand("PRAGMA user_version", _database.Connection))
+ {
+ return Convert.ToInt32(cmd.ExecuteScalar());
+ }
+ }
+ catch
+ {
+ return 0;
+ }
+ }
+
+ ///
+ /// 格式化版本号显示
+ ///
+ public static string FormatVersion(int version)
+ {
+ if (version == 0) return "未知版本";
+ int major = version / 10000;
+ int minor = (version % 10000) / 100;
+ int patch = version % 100;
+ return $"v{major}.{minor}.{patch}";
+ }
+
+ ///
+ /// 检查两个版本是否兼容(主版本必须相同)
+ ///
+ public static bool IsVersionCompatible(int sourceVersion, int targetVersion)
+ {
+ if (sourceVersion == 0 || targetVersion == 0) return false;
+ int sourceMajor = sourceVersion / 10000;
+ int targetMajor = targetVersion / 10000;
+ return sourceMajor == targetMajor;
+ }
+
+ ///
+ /// 备份数据库(直接复制文件)
+ ///
+ public string BackupDatabase(string exportDirectory = null)
+ {
+ try
+ {
+ if (string.IsNullOrEmpty(_dbPath) || !File.Exists(_dbPath))
+ {
+ throw new InvalidOperationException("数据库文件不存在");
+ }
+
+ // 确保目录存在
+ if (string.IsNullOrEmpty(exportDirectory))
+ {
+ exportDirectory = Path.Combine(
+ Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
+ "NavisworksTransport", "Backups");
+ }
+
+ if (!Directory.Exists(exportDirectory))
+ Directory.CreateDirectory(exportDirectory);
+
+ // 获取当前版本号
+ int version = GetDatabaseVersion();
+ string versionStr = FormatVersion(version).Replace(".", "_");
+
+ // 生成备份文件名(包含版本号)
+ string fileName = $"NavisworksTransport_{versionStr}_{DateTime.Now:yyyyMMdd_HHmmss}.db";
+ string backupPath = Path.Combine(exportDirectory, fileName);
+
+ // 关闭数据库连接以释放文件锁
+ _database.Connection.Close();
+
+ try
+ {
+ // 复制数据库文件
+ File.Copy(_dbPath, backupPath, true);
+ }
+ finally
+ {
+ // 重新打开连接
+ _database.Connection.Open();
+ }
+
+ LogManager.Info($"数据库备份完成: {backupPath}");
+ return backupPath;
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"数据库备份失败: {ex.Message}");
+ throw;
+ }
+ }
+
+ ///
+ /// 获取指定数据库文件的版本号
+ ///
+ private int GetBackupFileVersion(string backupFilePath)
+ {
+ try
+ {
+ using (var connection = new SQLiteConnection($"Data Source={backupFilePath};Version=3;"))
+ {
+ connection.Open();
+ using (var cmd = new SQLiteCommand("PRAGMA user_version", connection))
+ {
+ return Convert.ToInt32(cmd.ExecuteScalar());
+ }
+ }
+ }
+ catch
+ {
+ return 0;
+ }
+ }
+
+ ///
+ /// 恢复数据库(直接替换文件)
+ ///
+ public void RestoreDatabase(string backupFilePath)
+ {
+ try
+ {
+ if (!File.Exists(backupFilePath))
+ {
+ throw new FileNotFoundException("备份文件不存在", backupFilePath);
+ }
+
+ if (string.IsNullOrEmpty(_dbPath))
+ {
+ throw new InvalidOperationException("数据库路径未知");
+ }
+
+ // 获取版本信息
+ int currentVersion = GetDatabaseVersion();
+ int backupVersion = GetBackupFileVersion(backupFilePath);
+
+ LogManager.Info($"数据库版本检查: 当前={FormatVersion(currentVersion)}, 备份={FormatVersion(backupVersion)}");
+
+ // 版本兼容性检查
+ if (!IsVersionCompatible(backupVersion, currentVersion))
+ {
+ throw new InvalidOperationException(
+ $"版本不兼容!\n\n" +
+ $"备份版本: {FormatVersion(backupVersion)}\n" +
+ $"当前版本: {FormatVersion(currentVersion)}\n\n" +
+ $"主版本号必须相同才能恢复。\n" +
+ $"请使用相同版本的插件进行恢复,或联系管理员进行数据库升级。");
+ }
+
+ // 关闭数据库连接
+ _database.Connection.Close();
+
+ try
+ {
+ // 备份当前数据库(以防万一)
+ if (File.Exists(_dbPath))
+ {
+ string safetyBackup = _dbPath + $".backup_{DateTime.Now:yyyyMMdd_HHmmss}";
+ File.Copy(_dbPath, safetyBackup, true);
+ LogManager.Info($"已创建安全备份: {safetyBackup}");
+ }
+
+ // 替换数据库文件
+ File.Copy(backupFilePath, _dbPath, true);
+ }
+ finally
+ {
+ // 重新打开连接
+ try { _database.Connection.Open(); } catch { }
+ }
+
+ LogManager.Info($"数据库恢复完成: {backupFilePath}");
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"数据库恢复失败: {ex.Message}");
+ throw;
+ }
+ }
+
+ ///
+ /// 获取数据库信息
+ ///
+ public DatabaseInfo GetDatabaseInfo()
+ {
+ try
+ {
+ var info = new DatabaseInfo
+ {
+ FilePath = _dbPath,
+ FileSize = File.Exists(_dbPath) ? new FileInfo(_dbPath).Length : 0,
+ Version = GetDatabaseVersion()
+ };
+
+ // 获取表行数
+ info.PathRoutesCount = GetTableCount("PathRoutes");
+ info.PathPointsCount = GetTableCount("PathPoints");
+ info.PathEdgesCount = GetTableCount("PathEdges");
+ info.ClashResultsCount = GetTableCount("ClashDetectiveResults");
+ info.ScreenshotsCount = GetTableCount("CollisionReportScreenshots");
+
+ return info;
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"获取数据库信息失败: {ex.Message}");
+ return new DatabaseInfo();
+ }
+ }
+
+ private int GetTableCount(string tableName)
+ {
+ try
+ {
+ var sql = $"SELECT COUNT(*) FROM {tableName}";
+ using (var cmd = new SQLiteCommand(sql, _database.Connection))
+ {
+ return Convert.ToInt32(cmd.ExecuteScalar());
+ }
+ }
+ catch
+ {
+ return 0;
+ }
+ }
+ }
+
+ public class DatabaseInfo
+ {
+ public string FilePath { get; set; }
+ public long FileSize { get; set; }
+ public int Version { get; set; }
+ public int PathRoutesCount { get; set; }
+ public int PathPointsCount { get; set; }
+ public int PathEdgesCount { get; set; }
+ public int ClashResultsCount { get; set; }
+ public int ScreenshotsCount { get; set; }
+
+ public string FileSizeFormatted => $"{FileSize / 1024} KB";
+ public string VersionFormatted => BackupManager.FormatVersion(Version);
+ }
+}
diff --git a/src/Core/PathDatabase.cs b/src/Core/PathDatabase.cs
index 8cfc272..193fdcc 100644
--- a/src/Core/PathDatabase.cs
+++ b/src/Core/PathDatabase.cs
@@ -7,6 +7,7 @@ using System.Threading.Tasks;
using Autodesk.Navisworks.Api;
using NavisworksTransport.Core.Config;
using NavisworksTransport.Core.Models;
+using NavisworksTransport.Core.Database;
namespace NavisworksTransport
{
@@ -18,12 +19,18 @@ namespace NavisworksTransport
{
internal SQLiteConnection _connection;
private readonly string _dbPath;
+ private BackupManager _backupManager;
///
/// 数据库连接(供内部使用)
///
internal SQLiteConnection Connection => _connection;
+ ///
+ /// 简单数据库备份管理器(直接备份文件,最可靠)
+ ///
+ public BackupManager Backup => _backupManager ?? (_backupManager = new BackupManager(this));
+
///
/// 初始化路径数据库
///
@@ -217,6 +224,11 @@ namespace NavisworksTransport
)
");
+ // 9. 设置数据库版本(SQLite内置user_version)
+ // 版本号格式:主版本*10000 + 次版本*100 + 修订号
+ // 例如:2.1.3 = 20103
+ ExecuteNonQuery("PRAGMA user_version = 20100"); // v2.1.0
+
// 创建索引
ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_reports_route ON CollisionReports(RouteId)");
ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_pathpoints_route ON PathPoints(RouteId)");
@@ -868,6 +880,107 @@ namespace NavisworksTransport
}
}
+ ///
+ /// 获取所有碰撞检测结果
+ ///
+ public List GetAllClashDetectiveResults()
+ {
+ var results = new List();
+
+ try
+ {
+ var sql = @"
+ SELECT cdr.Id, cdr.TestName, cdr.RouteId, pr.Name AS PathName, cdr.TestTime,
+ cdr.CollisionCount, cdr.AnimationCollisionCount,
+ cdr.FrameRate, cdr.Duration, cdr.DetectionGap, cdr.AnimatedObjectName,
+ cdr.CreatedAt, cdr.ScreenshotPath
+ FROM ClashDetectiveResults cdr
+ INNER JOIN PathRoutes pr ON cdr.RouteId = pr.Id
+ ORDER BY cdr.TestTime DESC
+ ";
+
+ using (var cmd = new SQLiteCommand(sql, _connection))
+ using (var reader = cmd.ExecuteReader())
+ {
+ while (reader.Read())
+ {
+ results.Add(new ClashDetectiveResultRecord
+ {
+ Id = Convert.ToInt32(reader["Id"]),
+ TestName = reader["TestName"].ToString(),
+ RouteId = reader["RouteId"].ToString(),
+ PathName = reader["PathName"].ToString(),
+ TestTime = Convert.ToDateTime(reader["TestTime"]),
+ CollisionCount = Convert.ToInt32(reader["CollisionCount"]),
+ AnimationCollisionCount = Convert.ToInt32(reader["AnimationCollisionCount"]),
+ FrameRate = Convert.ToInt32(reader["FrameRate"]),
+ Duration = Convert.ToDouble(reader["Duration"]),
+ DetectionGap = Convert.ToDouble(reader["DetectionGap"]),
+ AnimatedObjectName = reader["AnimatedObjectName"].ToString(),
+ CreatedAt = Convert.ToDateTime(reader["CreatedAt"]),
+ ScreenshotPath = reader["ScreenshotPath"]?.ToString()
+ });
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"获取所有碰撞检测结果失败: {ex.Message}", ex);
+ }
+
+ return results;
+ }
+
+ ///
+ /// 清空所有数据
+ ///
+ public void ClearAllData()
+ {
+ try
+ {
+ // 按依赖关系顺序删除(先删除子表,再删除主表)
+ var tables = new[]
+ {
+ "CollisionReportScreenshots",
+ "ClashDetectiveCollisionObjects",
+ "ClashDetectiveResults",
+ "PathEdges",
+ "PathPoints",
+ "AnalysisResults",
+ "CollisionReports",
+ "PathRoutes",
+ "BatchQueueItems"
+ };
+
+ foreach (var table in tables)
+ {
+ try
+ {
+ ExecuteNonQuery($"DELETE FROM {table}");
+ LogManager.Debug($"已清空表: {table}");
+ }
+ catch (Exception ex)
+ {
+ LogManager.Warning($"清空表 {table} 失败(可能表不存在): {ex.Message}");
+ }
+ }
+
+ // 重置自增ID
+ try
+ {
+ ExecuteNonQuery("DELETE FROM sqlite_sequence");
+ }
+ catch { }
+
+ LogManager.Info("已清空所有数据表");
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"清空数据失败: {ex.Message}", ex);
+ throw;
+ }
+ }
+
///
/// 根据测试名称获取ClashDetective结果记录
///
diff --git a/src/UI/WPF/ViewModels/SystemManagementViewModel.cs b/src/UI/WPF/ViewModels/SystemManagementViewModel.cs
index 8d30bda..b16fb64 100644
--- a/src/UI/WPF/ViewModels/SystemManagementViewModel.cs
+++ b/src/UI/WPF/ViewModels/SystemManagementViewModel.cs
@@ -30,6 +30,14 @@ namespace NavisworksTransport.UI.WPF.ViewModels
private string _memoryUsage = "0 MB";
private string _runningTime = "00:00:00";
+ // 数据管理字段
+ private string _databaseVersion = "--";
+ private string _pathCount = "--";
+ private string _collisionRecordCount = "--";
+ private bool _autoBackupEnabled = true;
+ private int _selectedBackupKeepCount = 10;
+ private string _lastBackupInfo = "暂无备份记录";
+
// 🔧 修复:添加释放状态标志
private bool _disposed = false;
@@ -103,6 +111,44 @@ namespace NavisworksTransport.UI.WPF.ViewModels
set => SetProperty(ref _runningTime, value);
}
+ // 数据管理属性
+ public string DatabaseVersion
+ {
+ get => _databaseVersion;
+ set => SetProperty(ref _databaseVersion, value);
+ }
+
+ public string PathCount
+ {
+ get => _pathCount;
+ set => SetProperty(ref _pathCount, value);
+ }
+
+ public string CollisionRecordCount
+ {
+ get => _collisionRecordCount;
+ set => SetProperty(ref _collisionRecordCount, value);
+ }
+
+ public bool AutoBackupEnabled
+ {
+ get => _autoBackupEnabled;
+ set => SetProperty(ref _autoBackupEnabled, value);
+ }
+
+ public ObservableCollection BackupKeepCountOptions { get; } = new ObservableCollection { 5, 10, 20, 50 };
+
+ public int SelectedBackupKeepCount
+ {
+ get => _selectedBackupKeepCount;
+ set => SetProperty(ref _selectedBackupKeepCount, value);
+ }
+
+ public string LastBackupInfo
+ {
+ get => _lastBackupInfo;
+ set => SetProperty(ref _lastBackupInfo, value);
+ }
#endregion
@@ -114,6 +160,12 @@ namespace NavisworksTransport.UI.WPF.ViewModels
public ICommand GeneratePerformanceReportCommand { get; private set; }
public ICommand DiagnosticCommand { get; private set; }
+ // 数据管理命令
+ public ICommand BackupDataCommand { get; private set; }
+ public ICommand RestoreDataCommand { get; private set; }
+ public ICommand RepairDatabaseCommand { get; private set; }
+ public ICommand ClearAllDataCommand { get; private set; }
+
// 功能测试命令
public ICommand TestVoxelGridSDFCommand { get; private set; }
public ICommand TestVoxelPathFindingCommand { get; private set; }
@@ -245,6 +297,12 @@ namespace NavisworksTransport.UI.WPF.ViewModels
GeneratePerformanceReportCommand = new RelayCommand(() => ExecuteGeneratePerformanceReport());
DiagnosticCommand = new RelayCommand(() => ExecuteDiagnostic());
+ // 数据管理命令
+ BackupDataCommand = new RelayCommand(() => ExecuteBackupData());
+ RestoreDataCommand = new RelayCommand(() => ExecuteRestoreData());
+ RepairDatabaseCommand = new RelayCommand(() => ExecuteRepairDatabase());
+ ClearAllDataCommand = new RelayCommand(() => ExecuteClearAllData());
+
// 功能测试命令
TestVoxelGridSDFCommand = new RelayCommand(() => ExecuteTestVoxelGridSDF());
TestVoxelPathFindingCommand = new RelayCommand(() => ExecuteTestVoxelPathFinding());
@@ -531,6 +589,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels
// 初始化系统信息
PluginVersion = "v1.0";
NavisworksVersion = "2026";
+
+ // 初始化数据库状态(如果数据库已连接)
+ RefreshDatabaseStatus();
+
UpdateMainStatus("系统管理初始化完成");
});
@@ -852,6 +914,323 @@ namespace NavisworksTransport.UI.WPF.ViewModels
}
}
+ #region 数据管理方法
+
+ ///
+ /// 刷新数据库状态信息
+ ///
+ private void RefreshDatabaseStatus()
+ {
+ try
+ {
+ var pathDatabase = PathPlanningManager.Instance?.GetPathDatabase();
+ if (pathDatabase != null)
+ {
+ // 获取数据库信息
+ var dbInfo = pathDatabase.Backup.GetDatabaseInfo();
+ DatabaseVersion = dbInfo.VersionFormatted;
+ PathCount = dbInfo.PathRoutesCount.ToString();
+ CollisionRecordCount = dbInfo.ClashResultsCount.ToString();
+ LogManager.Debug($"数据库状态: 版本{dbInfo.VersionFormatted}, 路径{dbInfo.PathRoutesCount}, 点{dbInfo.PathPointsCount}, 边{dbInfo.PathEdgesCount}, 碰撞{dbInfo.ClashResultsCount}");
+ }
+ else
+ {
+ DatabaseVersion = "未连接";
+ PathCount = "--";
+ CollisionRecordCount = "--";
+ }
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"刷新数据库状态失败: {ex.Message}");
+ DatabaseVersion = "错误";
+ }
+ }
+
+ ///
+ /// 执行数据备份
+ ///
+ private void ExecuteBackupData()
+ {
+ SafeExecute(() =>
+ {
+ try
+ {
+ var pathDatabase = PathPlanningManager.Instance?.GetPathDatabase();
+ if (pathDatabase == null)
+ {
+ System.Windows.MessageBox.Show(
+ "未找到数据库连接,请确保已加载模型",
+ "备份数据",
+ System.Windows.MessageBoxButton.OK,
+ System.Windows.MessageBoxImage.Warning);
+ return;
+ }
+
+ UpdateMainStatus("正在备份数据库...");
+ LogManager.Info("开始数据库文件备份");
+
+ string backupPath = pathDatabase.Backup.BackupDatabase();
+
+ if (!string.IsNullOrEmpty(backupPath))
+ {
+ var info = pathDatabase.Backup.GetDatabaseInfo();
+ LastBackupInfo = $"上次备份: {DateTime.Now:yyyy-MM-dd HH:mm:ss}, 版本{info.VersionFormatted}, {info.FileSizeFormatted}";
+ System.Windows.MessageBox.Show(
+ $"数据库备份完成!\n\n" +
+ $"版本: {info.VersionFormatted}\n" +
+ $"文件: {backupPath}\n\n" +
+ $"包含数据:\n" +
+ $"- 路径: {info.PathRoutesCount} 条\n" +
+ $"- 路径点: {info.PathPointsCount} 个\n" +
+ $"- 碰撞记录: {info.ClashResultsCount} 条\n" +
+ $"- 截图: {info.ScreenshotsCount} 张",
+ "备份成功",
+ System.Windows.MessageBoxButton.OK,
+ System.Windows.MessageBoxImage.Information);
+ UpdateMainStatus("数据库备份完成");
+ LogManager.Info($"数据库备份完成: {backupPath}, 版本{info.VersionFormatted}");
+ }
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"数据备份失败: {ex.Message}");
+ System.Windows.MessageBox.Show(
+ $"数据备份失败: {ex.Message}",
+ "备份失败",
+ System.Windows.MessageBoxButton.OK,
+ System.Windows.MessageBoxImage.Error);
+ UpdateMainStatus("数据备份失败");
+ }
+ }, "数据备份");
+ }
+
+ ///
+ /// 执行数据恢复
+ ///
+ private void ExecuteRestoreData()
+ {
+ SafeExecute(() =>
+ {
+ try
+ {
+ var pathDatabase = PathPlanningManager.Instance?.GetPathDatabase();
+ if (pathDatabase == null)
+ {
+ System.Windows.MessageBox.Show(
+ "未找到数据库连接,请确保已加载模型",
+ "恢复数据",
+ System.Windows.MessageBoxButton.OK,
+ System.Windows.MessageBoxImage.Warning);
+ return;
+ }
+
+ // 选择备份文件
+ var openFileDialog = new Microsoft.Win32.OpenFileDialog
+ {
+ Title = "选择数据库备份文件",
+ Filter = "数据库备份文件 (*.db)|*.db",
+ InitialDirectory = System.IO.Path.Combine(
+ Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
+ "NavisworksTransport", "Backups")
+ };
+
+ if (openFileDialog.ShowDialog() != true)
+ {
+ return;
+ }
+
+ // 确认恢复
+ var result = System.Windows.MessageBox.Show(
+ "恢复数据将覆盖现有数据,建议先备份当前数据。\n\n是否继续?",
+ "确认恢复",
+ System.Windows.MessageBoxButton.YesNo,
+ System.Windows.MessageBoxImage.Warning);
+
+ if (result != System.Windows.MessageBoxResult.Yes)
+ {
+ return;
+ }
+
+ UpdateMainStatus("正在恢复数据库...");
+ LogManager.Info($"开始数据库恢复: {openFileDialog.FileName}");
+
+ pathDatabase.Backup.RestoreDatabase(openFileDialog.FileName);
+
+ // 恢复成功
+ bool restoreSuccess = true;
+
+ if (restoreSuccess)
+ {
+ // 刷新数据库状态
+ RefreshDatabaseStatus();
+
+ var info = pathDatabase.Backup.GetDatabaseInfo();
+ System.Windows.MessageBox.Show(
+ $"数据库恢复完成!\n\n" +
+ $"当前数据:\n" +
+ $"- 路径: {info.PathRoutesCount} 条\n" +
+ $"- 路径点: {info.PathPointsCount} 个\n" +
+ $"- 碰撞记录: {info.ClashResultsCount} 条\n" +
+ $"- 截图: {info.ScreenshotsCount} 张\n\n" +
+ $"请重新启动 Navisworks 以加载恢复的数据。",
+ "恢复成功",
+ System.Windows.MessageBoxButton.OK,
+ System.Windows.MessageBoxImage.Information);
+ UpdateMainStatus("数据恢复完成");
+ LogManager.Info("数据恢复完成");
+
+ // 刷新显示
+ RefreshDatabaseStatus();
+ }
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"数据恢复失败: {ex.Message}");
+ System.Windows.MessageBox.Show(
+ $"数据恢复失败: {ex.Message}",
+ "恢复失败",
+ System.Windows.MessageBoxButton.OK,
+ System.Windows.MessageBoxImage.Error);
+ UpdateMainStatus("数据恢复失败");
+ }
+ }, "数据恢复");
+ }
+
+ ///
+ /// 执行数据库修复
+ ///
+ private void ExecuteRepairDatabase()
+ {
+ SafeExecute(() =>
+ {
+ try
+ {
+ var pathDatabase = PathPlanningManager.Instance?.GetPathDatabase();
+ if (pathDatabase == null)
+ {
+ System.Windows.MessageBox.Show(
+ "未找到数据库连接",
+ "修复数据库",
+ System.Windows.MessageBoxButton.OK,
+ System.Windows.MessageBoxImage.Warning);
+ return;
+ }
+
+ UpdateMainStatus("正在检查数据库...");
+ LogManager.Info("开始数据库修复检查");
+
+ // 获取数据库信息
+ var info = pathDatabase.Backup.GetDatabaseInfo();
+
+ System.Windows.MessageBox.Show(
+ $"数据库检查结果:\n\n" +
+ $"版本: {info.VersionFormatted}\n" +
+ $"文件大小: {info.FileSizeFormatted}\n" +
+ $"路径数量: {info.PathRoutesCount} 条\n" +
+ $"路径点: {info.PathPointsCount} 个\n" +
+ $"路径边: {info.PathEdgesCount} 条\n" +
+ $"碰撞记录: {info.ClashResultsCount} 条\n" +
+ $"截图: {info.ScreenshotsCount} 张",
+ "检查结果",
+ System.Windows.MessageBoxButton.OK,
+ System.Windows.MessageBoxImage.Information);
+
+ // 刷新状态
+ RefreshDatabaseStatus();
+ UpdateMainStatus("数据库检查完成");
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"数据库修复失败: {ex.Message}");
+ System.Windows.MessageBox.Show(
+ $"数据库修复失败: {ex.Message}",
+ "修复失败",
+ System.Windows.MessageBoxButton.OK,
+ System.Windows.MessageBoxImage.Error);
+ UpdateMainStatus("数据库修复失败");
+ }
+ }, "数据库修复");
+ }
+
+ ///
+ /// 执行清空所有数据
+ ///
+ private void ExecuteClearAllData()
+ {
+ SafeExecute(() =>
+ {
+ try
+ {
+ var pathDatabase = PathPlanningManager.Instance?.GetPathDatabase();
+ if (pathDatabase == null)
+ {
+ System.Windows.MessageBox.Show(
+ "未找到数据库连接",
+ "清空数据",
+ System.Windows.MessageBoxButton.OK,
+ System.Windows.MessageBoxImage.Warning);
+ return;
+ }
+
+ // 双重确认
+ var result1 = System.Windows.MessageBox.Show(
+ "⚠️ 警告:此操作将永久删除所有路径和碰撞记录!\n\n" +
+ "建议先备份数据。\n\n" +
+ "是否继续?",
+ "确认清空数据",
+ System.Windows.MessageBoxButton.YesNo,
+ System.Windows.MessageBoxImage.Warning);
+
+ if (result1 != System.Windows.MessageBoxResult.Yes)
+ {
+ return;
+ }
+
+ var result2 = System.Windows.MessageBox.Show(
+ "请再次确认:是否永久删除所有数据?\n\n" +
+ "此操作不可恢复!",
+ "最终确认",
+ System.Windows.MessageBoxButton.YesNo,
+ System.Windows.MessageBoxImage.Warning);
+
+ if (result2 != System.Windows.MessageBoxResult.Yes)
+ {
+ return;
+ }
+
+ UpdateMainStatus("正在清空数据...");
+ LogManager.Info("开始清空所有数据");
+
+ // 清空所有表
+ pathDatabase.ClearAllData();
+
+ System.Windows.MessageBox.Show(
+ "所有数据已清空!",
+ "清空完成",
+ System.Windows.MessageBoxButton.OK,
+ System.Windows.MessageBoxImage.Information);
+ UpdateMainStatus("数据已清空");
+ LogManager.Info("所有数据已清空");
+
+ // 刷新状态
+ RefreshDatabaseStatus();
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"清空数据失败: {ex.Message}");
+ System.Windows.MessageBox.Show(
+ $"清空数据失败: {ex.Message}",
+ "操作失败",
+ System.Windows.MessageBoxButton.OK,
+ System.Windows.MessageBoxImage.Error);
+ UpdateMainStatus("清空数据失败");
+ }
+ }, "清空数据");
+ }
+
+ #endregion
+
///
/// 执行体素网格 SDF 测试(使用 MeshSignedDistanceGrid)
///
diff --git a/src/UI/WPF/Views/SystemManagementView.xaml b/src/UI/WPF/Views/SystemManagementView.xaml
index f1782ed..4492eca 100644
--- a/src/UI/WPF/Views/SystemManagementView.xaml
+++ b/src/UI/WPF/Views/SystemManagementView.xaml
@@ -42,6 +42,80 @@ NavisworksTransport 系统管理页签视图 - 采用与其他页签一致的Nav
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+