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 + + + +