From d9da8e95cef8dab2c1001bcce8ee52124beb854d Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Sat, 7 Feb 2026 00:22:07 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=99=E7=A2=B0=E6=92=9E=E6=8A=A5=E5=91=8A?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=A4=9A=E6=88=AA=E5=9B=BE=E7=9A=84=E8=83=BD?= =?UTF-8?q?=E5=8A=9B=EF=BC=9B=E4=BF=AE=E5=A4=8D=E8=B7=AF=E5=BE=84=E5=AE=BD?= =?UTF-8?q?=E5=BA=A6=E5=9C=A8=E4=BF=AE=E6=94=B9=E8=B7=AF=E5=BE=84=E7=82=B9?= =?UTF-8?q?=E5=9D=90=E6=A0=87=E5=90=8E=E5=9B=9E=E5=88=B0=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E5=80=BC=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- NavisworksTransportPlugin.csproj | 1 + .../GenerateCollisionReportCommand.cs | 174 +++++- src/Core/PathDatabase.cs | 227 +++++++- .../Converters/CountToVisibilityConverter.cs | 21 + src/UI/WPF/Converters/PathToImageConverter.cs | 42 ++ .../ViewModels/CollisionReportViewModel.cs | 497 ++++++++++++++---- src/UI/WPF/ViewModels/PathEditingViewModel.cs | 9 + src/UI/WPF/Views/CollisionReportDialog.xaml | 181 ++++++- .../WPF/Views/CollisionReportDialog.xaml.cs | 95 +++- .../Views/GenerateNavigationMapDialog.xaml.cs | 85 ++- src/Utils/CollisionReportHtmlGenerator.cs | 64 ++- 11 files changed, 1192 insertions(+), 204 deletions(-) create mode 100644 src/UI/WPF/Converters/PathToImageConverter.cs diff --git a/NavisworksTransportPlugin.csproj b/NavisworksTransportPlugin.csproj index a207ce6..4c86306 100644 --- a/NavisworksTransportPlugin.csproj +++ b/NavisworksTransportPlugin.csproj @@ -282,6 +282,7 @@ + diff --git a/src/Commands/GenerateCollisionReportCommand.cs b/src/Commands/GenerateCollisionReportCommand.cs index 6480f94..4b41d78 100644 --- a/src/Commands/GenerateCollisionReportCommand.cs +++ b/src/Commands/GenerateCollisionReportCommand.cs @@ -78,6 +78,31 @@ namespace NavisworksTransport.Commands public string ScreenshotPath { get; set; } } + /// + /// 碰撞报告截图项 + /// + public class CollisionReportScreenshot + { + /// 截图唯一标识(UI用) + public string Id { get; set; } = Guid.NewGuid().ToString("N"); + /// 数据库记录Id(用于删除) + public int DatabaseId { get; set; } + /// 截图文件路径 + public string FilePath { get; set; } + /// 图片格式 (PNG/JPG) + public string Format { get; set; } + /// 图片宽度 + public int Width { get; set; } + /// 图片高度 + public int Height { get; set; } + /// 截图时间 + public DateTime CaptureTime { get; set; } = DateTime.Now; + /// 截图描述/备注 + public string Description { get; set; } + /// 排序顺序 + public int SortOrder { get; set; } + } + /// /// 碰撞报告结果类 /// @@ -96,16 +121,54 @@ namespace NavisworksTransport.Commands // 新增:动画参数 public string RouteId { get; set; } // 路径ID,用于数据库关联 + public int ResultId { get; set; } // 数据库记录Id,用于关联截图 public string PathName { get; set; } public int FrameRate { get; set; } public double Duration { get; set; } public double DetectionTolerance { get; set; } - // 新增:截图信息 - public string ScreenshotPath { get; set; } - public string ScreenshotFormat { get; set; } - public int ScreenshotWidth { get; set; } - public int ScreenshotHeight { get; set; } + // 截图列表 - 支持多张截图 + public List Screenshots { get; set; } = new List(); + + // 兼容旧代码:单张截图属性(现在指向第一张截图) + [Obsolete("请使用 Screenshots 列表")] + public string ScreenshotPath + { + get => Screenshots?.FirstOrDefault()?.FilePath; + set + { + if (!string.IsNullOrEmpty(value)) + { + if (Screenshots == null) Screenshots = new List(); + if (Screenshots.Count == 0) + { + Screenshots.Add(new CollisionReportScreenshot { FilePath = value }); + } + else + { + Screenshots[0].FilePath = value; + } + } + } + } + [Obsolete("请使用 Screenshots 列表")] + public string ScreenshotFormat + { + get => Screenshots?.FirstOrDefault()?.Format; + set { if (Screenshots?.FirstOrDefault() != null) Screenshots[0].Format = value; } + } + [Obsolete("请使用 Screenshots 列表")] + public int ScreenshotWidth + { + get => Screenshots?.FirstOrDefault()?.Width ?? 0; + set { if (Screenshots?.FirstOrDefault() != null) Screenshots[0].Width = value; } + } + [Obsolete("请使用 Screenshots 列表")] + public int ScreenshotHeight + { + get => Screenshots?.FirstOrDefault()?.Height ?? 0; + set { if (Screenshots?.FirstOrDefault() != null) Screenshots[0].Height = value; } + } } /// @@ -184,8 +247,13 @@ namespace NavisworksTransport.Commands var testInfo = GetTestInfoFromDatabase(targetTestName); result.PathName = testInfo?.PathName ?? "未知路径"; result.RouteId = testInfo?.RouteId; + result.ResultId = testInfo?.Id ?? 0; - LogManager.Info($"碰撞报告计数 - 检查点: {result.AnimationCollisions}, Clash Detective: {result.TotalCollisions}"); + LogManager.Info($"碰撞报告数据 - TestName={targetTestName}, ResultId={result.ResultId}, PathName={result.PathName}"); + if (testInfo == null) + { + LogManager.Warning($"未在数据库中找到测试记录: {targetTestName}"); + } UpdateProgress(70, "生成报告内容..."); @@ -247,25 +315,70 @@ namespace NavisworksTransport.Commands // 视角调整失败不影响截图生成 } - UpdateProgress(95, "生成碰撞场景截图..."); + UpdateProgress(95, "加载碰撞报告截图..."); - // 检查是否已有截图路径(从数据库) + // 加载多截图数据(从新的截图表) var pathDatabase = PathPlanningManager.Instance?.GetPathDatabase(); - var existingScreenshotPath = pathDatabase != null ? - pathDatabase.GetClashDetectiveResultByTestName(targetTestName)?.ScreenshotPath : null; - - if (!string.IsNullOrEmpty(existingScreenshotPath) && System.IO.File.Exists(existingScreenshotPath)) + if (pathDatabase != null) { - // 使用数据库中保存的截图路径 - result.ScreenshotPath = existingScreenshotPath; - result.ScreenshotFormat = "JPG"; - result.ScreenshotWidth = 1920; - result.ScreenshotHeight = 1080; - LogManager.Info($"使用数据库中保存的截图: {existingScreenshotPath}"); + try + { + // 先获取结果记录以获取 ResultId + var testRecord = pathDatabase.GetClashDetectiveResultByTestName(targetTestName); + if (testRecord != null) + { + LogManager.Debug($"加载截图 - 找到测试记录: TestName={targetTestName}, ResultId={testRecord.Id}"); + + // 从新的截图表加载所有截图 + var screenshotRecords = pathDatabase.GetCollisionReportScreenshots(testRecord.Id); + LogManager.Debug($"加载截图 - 查询到 {screenshotRecords?.Count ?? 0} 张截图 (ResultId={testRecord.Id})"); + + if (screenshotRecords != null && screenshotRecords.Count > 0) + { + result.Screenshots = screenshotRecords.Select(r => new CollisionReportScreenshot + { + DatabaseId = r.Id, // 数据库主键,用于删除 + FilePath = r.FilePath, + Format = r.Format, + Width = r.Width, + Height = r.Height, + CaptureTime = r.CaptureTime, + Description = r.Description, + SortOrder = r.SortOrder + }).ToList(); + LogManager.Info($"从数据库加载了 {result.Screenshots.Count} 张截图 (ResultId={testRecord.Id})"); + } + else + { + // 回退:检查旧表中的单截图 + var existingScreenshotPath = testRecord.ScreenshotPath; + if (!string.IsNullOrEmpty(existingScreenshotPath) && System.IO.File.Exists(existingScreenshotPath)) + { + result.Screenshots = new List + { + new CollisionReportScreenshot + { + FilePath = existingScreenshotPath, + Format = "JPG", + Width = 1920, + Height = 1080, + CaptureTime = testRecord.TestTime + } + }; + LogManager.Info($"从旧表加载单截图: {existingScreenshotPath}"); + } + } + } + } + catch (Exception ex) + { + LogManager.Error($"加载截图数据失败: {ex.Message}"); + } } - else + + // 如果没有加载到任何截图,生成一张默认截图 + if (result.Screenshots == null || result.Screenshots.Count == 0) { - // 生成新截图 try { string screenshotPath = PathHelper.GenerateSceneScreenshot( @@ -278,13 +391,20 @@ namespace NavisworksTransport.Commands if (screenshotPath != null) { - result.ScreenshotPath = screenshotPath; - result.ScreenshotFormat = "JPG"; - result.ScreenshotWidth = 1920; - result.ScreenshotHeight = 1080; - LogManager.Info($"碰撞场景截图已自动生成: {screenshotPath}"); + result.Screenshots = new List + { + new CollisionReportScreenshot + { + FilePath = screenshotPath, + Format = "JPG", + Width = 1920, + Height = 1080, + CaptureTime = DateTime.Now + } + }; + LogManager.Info($"自动生成默认截图: {screenshotPath}"); - // 保存截图路径到数据库 + // 保存截图路径到数据库(旧表兼容) if (pathDatabase != null) { try @@ -301,7 +421,6 @@ namespace NavisworksTransport.Commands catch (Exception dbEx) { LogManager.Error($"保存截图路径到数据库失败: {dbEx.Message}"); - // 数据库更新失败不影响报告生成 } } } @@ -309,7 +428,6 @@ namespace NavisworksTransport.Commands catch (Exception ex) { LogManager.Error($"自动生成碰撞场景截图失败: {ex.Message}"); - // 截图失败不影响报告生成 } } diff --git a/src/Core/PathDatabase.cs b/src/Core/PathDatabase.cs index 388b5b6..8cfc272 100644 --- a/src/Core/PathDatabase.cs +++ b/src/Core/PathDatabase.cs @@ -201,6 +201,22 @@ namespace NavisworksTransport ) "); + // 8. 碰撞报告截图表(支持多张截图) + ExecuteNonQuery(@" + CREATE TABLE IF NOT EXISTS CollisionReportScreenshots ( + Id INTEGER PRIMARY KEY AUTOINCREMENT, + ResultId INTEGER NOT NULL, + FilePath TEXT NOT NULL, + Format TEXT, + Width INTEGER, + Height INTEGER, + CaptureTime DATETIME DEFAULT CURRENT_TIMESTAMP, + Description TEXT, + SortOrder INTEGER DEFAULT 0, + FOREIGN KEY(ResultId) REFERENCES ClashDetectiveResults(Id) ON DELETE CASCADE + ) + "); + // 创建索引 ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_reports_route ON CollisionReports(RouteId)"); ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_pathpoints_route ON PathPoints(RouteId)"); @@ -209,8 +225,10 @@ namespace NavisworksTransport ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_clash_test_time ON ClashDetectiveResults(TestTime DESC)"); ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_clash_objects_result ON ClashDetectiveCollisionObjects(ResultId)"); ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_clash_objects_path ON ClashDetectiveCollisionObjects(PathId)"); + ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_screenshots_result ON CollisionReportScreenshots(ResultId)"); + ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_screenshots_sort ON CollisionReportScreenshots(ResultId, SortOrder)"); - // 8. 批处理队列表(简化版,只维护FIFO队列) + // 9. 批处理队列表(简化版,只维护FIFO队列) ExecuteNonQuery(@" CREATE TABLE IF NOT EXISTS BatchQueueItems ( Id INTEGER PRIMARY KEY AUTOINCREMENT, @@ -392,46 +410,193 @@ namespace NavisworksTransport } /// - /// 更新碰撞报告的截图信息(更新ClashDetectiveResults表) + /// 更新碰撞报告的截图信息(更新ClashDetectiveResults表,兼容旧版本) /// public void UpdateCollisionReportScreenshot(string routeId, string screenshotPath, string screenshotFormat, int screenshotWidth, int screenshotHeight) { try { - // 更新 ClashDetectiveResults 表(该表包含 ScreenshotPath 列) - // 更新该 RouteId 的最新记录 - var sql = @" + // 获取该 RouteId 的最新记录Id + var getIdSql = @" + SELECT Id FROM ClashDetectiveResults + WHERE RouteId = @routeId + ORDER BY TestTime DESC + LIMIT 1 + "; + + int? resultId = null; + using (var cmd = new SQLiteCommand(getIdSql, _connection)) + { + cmd.Parameters.AddWithValue("@routeId", routeId ?? ""); + var result = cmd.ExecuteScalar(); + if (result != null && result != DBNull.Value) + { + resultId = Convert.ToInt32(result); + } + } + + if (!resultId.HasValue) + { + LogManager.Warning($"未找到需要更新的碰撞记录: RouteId={routeId}"); + return; + } + + // 同时更新旧表的 ScreenshotPath 字段(兼容旧版本) + var updateSql = @" UPDATE ClashDetectiveResults SET ScreenshotPath = @screenshotPath - WHERE RouteId = @routeId - AND Id = ( - SELECT Id FROM ClashDetectiveResults - WHERE RouteId = @routeId - ORDER BY TestTime DESC - LIMIT 1 - ) + WHERE Id = @resultId + "; + using (var cmd = new SQLiteCommand(updateSql, _connection)) + { + cmd.Parameters.AddWithValue("@resultId", resultId.Value); + cmd.Parameters.AddWithValue("@screenshotPath", screenshotPath ?? (object)DBNull.Value); + cmd.ExecuteNonQuery(); + } + + // 添加/更新到新的截图表 + SaveCollisionReportScreenshot(resultId.Value, screenshotPath, screenshotFormat, screenshotWidth, screenshotHeight, 0); + + LogManager.Info($"碰撞报告截图已更新: RouteId={routeId}, 截图={screenshotPath}"); + } + catch (Exception ex) + { + LogManager.Error($"更新碰撞报告截图失败: {ex.Message}", ex); + throw; + } + } + + /// + /// 保存碰撞报告截图到截图表,返回新记录Id + /// + public int SaveCollisionReportScreenshot(int resultId, string filePath, string format, int width, int height, int sortOrder, string description = null) + { + try + { + var sql = @" + INSERT INTO CollisionReportScreenshots + (ResultId, FilePath, Format, Width, Height, CaptureTime, Description, SortOrder) + VALUES (@resultId, @filePath, @format, @width, @height, @captureTime, @description, @sortOrder) "; using (var cmd = new SQLiteCommand(sql, _connection)) { - cmd.Parameters.AddWithValue("@routeId", routeId ?? ""); - cmd.Parameters.AddWithValue("@screenshotPath", screenshotPath ?? (object)DBNull.Value); - var rowsAffected = cmd.ExecuteNonQuery(); - - if (rowsAffected > 0) + cmd.Parameters.AddWithValue("@resultId", resultId); + cmd.Parameters.AddWithValue("@filePath", filePath ?? (object)DBNull.Value); + cmd.Parameters.AddWithValue("@format", format ?? (object)DBNull.Value); + cmd.Parameters.AddWithValue("@width", width); + cmd.Parameters.AddWithValue("@height", height); + cmd.Parameters.AddWithValue("@captureTime", DateTime.Now); + cmd.Parameters.AddWithValue("@description", description ?? (object)DBNull.Value); + cmd.Parameters.AddWithValue("@sortOrder", sortOrder); + cmd.ExecuteNonQuery(); + } + + // 获取新插入记录的Id + int newId = (int)_connection.LastInsertRowId; + LogManager.Debug($"碰撞报告截图已保存: Id={newId}, ResultId={resultId}, FilePath={filePath}"); + return newId; + } + catch (Exception ex) + { + LogManager.Error($"保存碰撞报告截图失败: {ex.Message}", ex); + throw; + } + } + + /// + /// 获取碰撞报告的所有截图 + /// + public List GetCollisionReportScreenshots(int resultId) + { + var screenshots = new List(); + + try + { + var sql = @" + SELECT Id, ResultId, FilePath, Format, Width, Height, CaptureTime, Description, SortOrder + FROM CollisionReportScreenshots + WHERE ResultId = @resultId + ORDER BY SortOrder, CaptureTime + "; + + using (var cmd = new SQLiteCommand(sql, _connection)) + { + cmd.Parameters.AddWithValue("@resultId", resultId); + using (var reader = cmd.ExecuteReader()) { - LogManager.Info($"碰撞报告截图已更新: RouteId={routeId}, 截图={screenshotPath}"); - } - else - { - LogManager.Warning($"未找到需要更新的碰撞记录: RouteId={routeId}"); + while (reader.Read()) + { + screenshots.Add(new CollisionReportScreenshotRecord + { + Id = Convert.ToInt32(reader["Id"]), + ResultId = Convert.ToInt32(reader["ResultId"]), + FilePath = reader["FilePath"]?.ToString(), + Format = reader["Format"]?.ToString(), + Width = reader["Width"] != DBNull.Value ? Convert.ToInt32(reader["Width"]) : 0, + Height = reader["Height"] != DBNull.Value ? Convert.ToInt32(reader["Height"]) : 0, + CaptureTime = reader["CaptureTime"] != DBNull.Value ? Convert.ToDateTime(reader["CaptureTime"]) : DateTime.MinValue, + Description = reader["Description"]?.ToString(), + SortOrder = reader["SortOrder"] != DBNull.Value ? Convert.ToInt32(reader["SortOrder"]) : 0 + }); + } } } } catch (Exception ex) { - LogManager.Error($"更新碰撞报告截图失败: {ex.Message}", ex); + LogManager.Error($"获取碰撞报告截图失败: {ex.Message}", ex); + } + + return screenshots; + } + + /// + /// 删除碰撞报告截图 + /// + public void DeleteCollisionReportScreenshot(int screenshotId) + { + try + { + var sql = "DELETE FROM CollisionReportScreenshots WHERE Id = @id"; + using (var cmd = new SQLiteCommand(sql, _connection)) + { + cmd.Parameters.AddWithValue("@id", screenshotId); + cmd.ExecuteNonQuery(); + } + LogManager.Debug($"碰撞报告截图已删除: ScreenshotId={screenshotId}"); + } + catch (Exception ex) + { + LogManager.Error($"删除碰撞报告截图失败: {ex.Message}", ex); + throw; + } + } + + /// + /// 更新截图排序和描述 + /// + public void UpdateCollisionReportScreenshotMetadata(int screenshotId, int sortOrder, string description) + { + try + { + var sql = @" + UPDATE CollisionReportScreenshots + SET SortOrder = @sortOrder, Description = @description + WHERE Id = @id + "; + using (var cmd = new SQLiteCommand(sql, _connection)) + { + cmd.Parameters.AddWithValue("@id", screenshotId); + cmd.Parameters.AddWithValue("@sortOrder", sortOrder); + cmd.Parameters.AddWithValue("@description", description ?? (object)DBNull.Value); + cmd.ExecuteNonQuery(); + } + } + catch (Exception ex) + { + LogManager.Error($"更新截图元数据失败: {ex.Message}", ex); throw; } } @@ -1877,6 +2042,22 @@ namespace NavisworksTransport public string ObjectName { get; set; } } + /// + /// 碰撞报告截图记录 + /// + public class CollisionReportScreenshotRecord + { + public int Id { get; set; } + public int ResultId { get; set; } + public string FilePath { get; set; } + public string Format { get; set; } + public int Width { get; set; } + public int Height { get; set; } + public DateTime CaptureTime { get; set; } + public string Description { get; set; } + public int SortOrder { get; set; } + } + /// /// 路径分析结果数据模型 /// diff --git a/src/UI/WPF/Converters/CountToVisibilityConverter.cs b/src/UI/WPF/Converters/CountToVisibilityConverter.cs index 7980e91..8ca3a42 100644 --- a/src/UI/WPF/Converters/CountToVisibilityConverter.cs +++ b/src/UI/WPF/Converters/CountToVisibilityConverter.cs @@ -2,6 +2,7 @@ using System; using System.Globalization; using System.Windows; using System.Windows.Data; +using System.Linq; namespace NavisworksTransport.UI.WPF.Converters { @@ -122,4 +123,24 @@ namespace NavisworksTransport.UI.WPF.Converters return false; } } + + /// + /// 等值转换器 - 用于MultiBinding,比较两个值是否相等 + /// + public class EqualityToBooleanConverter : IMultiValueConverter + { + public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) + { + if (values == null || values.Length < 2) + return false; + + // 比较第一个值和第二个值是否相等 + return Equals(values[0], values[1]); + } + + public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) + { + throw new NotImplementedException("EqualityToBooleanConverter不支持反向转换"); + } + } } \ No newline at end of file diff --git a/src/UI/WPF/Converters/PathToImageConverter.cs b/src/UI/WPF/Converters/PathToImageConverter.cs new file mode 100644 index 0000000..8d1fc78 --- /dev/null +++ b/src/UI/WPF/Converters/PathToImageConverter.cs @@ -0,0 +1,42 @@ +using System; +using System.Globalization; +using System.IO; +using System.Windows.Data; +using System.Windows.Media.Imaging; + +namespace NavisworksTransport.UI.WPF.Converters +{ + /// + /// 文件路径转换为BitmapImage的转换器 + /// + public class PathToImageConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is string path && !string.IsNullOrEmpty(path) && File.Exists(path)) + { + try + { + var bitmap = new BitmapImage(); + bitmap.BeginInit(); + bitmap.CacheOption = BitmapCacheOption.OnLoad; + bitmap.UriSource = new Uri(path); + bitmap.EndInit(); + bitmap.Freeze(); + return bitmap; + } + catch (Exception ex) + { + LogManager.Warning($"加载图片失败: {path}, 错误: {ex.Message}"); + return null; + } + } + return null; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/UI/WPF/ViewModels/CollisionReportViewModel.cs b/src/UI/WPF/ViewModels/CollisionReportViewModel.cs index 040a6e2..cb3652c 100644 --- a/src/UI/WPF/ViewModels/CollisionReportViewModel.cs +++ b/src/UI/WPF/ViewModels/CollisionReportViewModel.cs @@ -11,6 +11,7 @@ using Microsoft.Win32; using System.Threading.Tasks; using System.Windows.Media.Imaging; using NavisworksTransport.UI.WPF.Views; +using ImageFormat = System.Drawing.Imaging.ImageFormat; namespace NavisworksTransport.UI.WPF.ViewModels { @@ -252,36 +253,80 @@ namespace NavisworksTransport.UI.WPF.ViewModels } /// - /// 截图预览图像源 + /// 截图预览图像源(兼容旧版本,返回当前选中的截图) /// - public BitmapImage ScreenshotPreviewSource + public BitmapImage ScreenshotPreviewSource => GetScreenshotBitmap(SelectedScreenshot); + + /// + /// 截图列表 + /// + private ObservableCollection _screenshots = new ObservableCollection(); + public ObservableCollection Screenshots { - get + get => _screenshots; + set { - if (string.IsNullOrEmpty(CurrentReport?.ScreenshotPath) || - !File.Exists(CurrentReport.ScreenshotPath)) + if (SetProperty(ref _screenshots, value)) { - return null; + OnPropertyChanged(nameof(HasScreenshots)); + OnPropertyChanged(nameof(ScreenshotPreviewSource)); } - - try + } + } + + /// + /// 当前选中的截图 + /// + private CollisionReportScreenshot _selectedScreenshot; + public CollisionReportScreenshot SelectedScreenshot + { + get => _selectedScreenshot; + set + { + if (SetProperty(ref _selectedScreenshot, value)) { - var bitmap = new BitmapImage(); - bitmap.BeginInit(); - bitmap.CacheOption = BitmapCacheOption.OnLoad; - bitmap.UriSource = new Uri(CurrentReport.ScreenshotPath); - bitmap.EndInit(); - bitmap.Freeze(); // 防止跨线程访问问题 - return bitmap; - } - catch (Exception ex) - { - LogManager.Error($"加载截图预览失败: {ex.Message}"); - return null; + OnPropertyChanged(nameof(ScreenshotPreviewSource)); } } } + /// + /// 是否有截图 + /// + public bool HasScreenshots => Screenshots?.Count > 0; + + /// + /// 截图数量 + /// + public int ScreenshotCount => Screenshots?.Count ?? 0; + + /// + /// 获取截图的BitmapImage + /// + private BitmapImage GetScreenshotBitmap(CollisionReportScreenshot screenshot) + { + if (screenshot == null || string.IsNullOrEmpty(screenshot.FilePath) || !File.Exists(screenshot.FilePath)) + { + return null; + } + + try + { + var bitmap = new BitmapImage(); + bitmap.BeginInit(); + bitmap.CacheOption = BitmapCacheOption.OnLoad; + bitmap.UriSource = new Uri(screenshot.FilePath); + bitmap.EndInit(); + bitmap.Freeze(); + return bitmap; + } + catch (Exception ex) + { + LogManager.Error($"加载截图预览失败: {ex.Message}"); + return null; + } + } + #endregion #region 命令属性 @@ -297,9 +342,24 @@ namespace NavisworksTransport.UI.WPF.ViewModels public ICommand CloseCommand { get; } /// - /// 重新截图命令 + /// 添加截图命令 /// - public ICommand RetakeScreenshotCommand { get; } + public ICommand AddScreenshotCommand { get; } + + /// + /// 删除截图命令 + /// + public ICommand DeleteScreenshotCommand { get; } + + /// + /// 选择截图命令 + /// + public ICommand SelectScreenshotCommand { get; } + + /// + /// 截图设置命令 + /// + public ICommand ScreenshotSettingsCommand { get; } /// /// 高亮碰撞对象命令 @@ -308,6 +368,42 @@ namespace NavisworksTransport.UI.WPF.ViewModels #endregion + #region 截图设置属性 + + // 默认截图设置 + private int _screenshotWidth = 1920; + private int _screenshotHeight = 1080; + private ImageFormat _screenshotFormat = ImageFormat.Png; + + /// + /// 截图宽度 + /// + public int ScreenshotWidthSetting + { + get => _screenshotWidth; + set => SetProperty(ref _screenshotWidth, value); + } + + /// + /// 截图高度 + /// + public int ScreenshotHeightSetting + { + get => _screenshotHeight; + set => SetProperty(ref _screenshotHeight, value); + } + + /// + /// 截图格式 + /// + public ImageFormat ScreenshotFormatSetting + { + get => _screenshotFormat; + set => SetProperty(ref _screenshotFormat, value); + } + + #endregion + #region 构造函数 public CollisionReportViewModel() @@ -322,7 +418,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels ExportReportCommand = new RelayCommand(async () => await ExportReportAsync(), () => !IsGenerating && HasCollisions); CloseCommand = new RelayCommand(CloseWindow); HighlightCollisionCommand = new RelayCommand(HighlightCollision, item => item?.CollisionData != null); - RetakeScreenshotCommand = new RelayCommand(ExecuteRetakeScreenshot, CanExecuteRetakeScreenshot); + AddScreenshotCommand = new RelayCommand(ExecuteAddScreenshot, CanExecuteAddScreenshot); + DeleteScreenshotCommand = new RelayCommand(ExecuteDeleteScreenshot, s => s != null); + SelectScreenshotCommand = new RelayCommand(ExecuteSelectScreenshot); + ScreenshotSettingsCommand = new RelayCommand(ExecuteScreenshotSettings); // 初始化状态 ReportStatus = CollisionReportStatus.Generating; @@ -360,6 +459,34 @@ namespace NavisworksTransport.UI.WPF.ViewModels // 清空现有数据 AnimationCollisions.Clear(); CollidedObjectsList.Clear(); + Screenshots.Clear(); + + // 加载截图列表 + if (reportResult.Screenshots?.Count > 0) + { + foreach (var screenshot in reportResult.Screenshots.OrderBy(s => s.SortOrder)) + { + Screenshots.Add(screenshot); + } + // 默认选中第一张 + SelectedScreenshot = Screenshots.FirstOrDefault(); + LogManager.Info($"碰撞报告加载了 {Screenshots.Count} 张截图"); + } + else if (!string.IsNullOrEmpty(reportResult.ScreenshotPath)) + { + // 兼容旧版本:如果只有单张截图路径,也添加到列表 + var oldScreenshot = new CollisionReportScreenshot + { + FilePath = reportResult.ScreenshotPath, + Format = reportResult.ScreenshotFormat, + Width = reportResult.ScreenshotWidth, + Height = reportResult.ScreenshotHeight, + SortOrder = 0 + }; + Screenshots.Add(oldScreenshot); + SelectedScreenshot = oldScreenshot; + LogManager.Info("碰撞报告加载了1张旧版截图"); + } // 设置运动构件信息 MovingObjectInfo = reportResult.MovingObjectInfo; @@ -638,6 +765,35 @@ namespace NavisworksTransport.UI.WPF.ViewModels } } + /// + /// 自动导出报告到默认目录(关闭窗口时调用) + /// + public async Task AutoExportReportAsync() + { + try + { + if (CurrentReport == null || !HasCollisions) return; + + // 生成默认文件名和路径 + var sanitizedName = PathHelper.SanitizeFileName(CurrentReport.PathName ?? "未知路径"); + var fileName = $"NavisworksTransport_CollisionReport_{sanitizedName}_{DateTime.Now:yyyyMMdd_HHmmss}.html"; + var reportDir = PathHelper.GetReportDirectory(); + var filePath = Path.Combine(reportDir, fileName); + + await Task.Run(() => + { + var content = GenerateHtmlReport(filePath); + File.WriteAllText(filePath, content, Encoding.UTF8); + }); + + LogManager.Info($"报告已自动导出到: {filePath}"); + } + catch (Exception ex) + { + LogManager.Error($"自动导出报告失败: {ex.Message}"); + } + } + /// /// 生成导出内容 /// @@ -831,23 +987,56 @@ namespace NavisworksTransport.UI.WPF.ViewModels html.AppendLine(""); html.AppendLine(""); - // 碰撞场景截图 - if (!string.IsNullOrEmpty(CurrentReport?.ScreenshotPath) && File.Exists(CurrentReport.ScreenshotPath)) + // 碰撞场景截图(支持多张) + var validScreenshots = Screenshots?.Where(s => !string.IsNullOrEmpty(s.FilePath) && File.Exists(s.FilePath)).ToList(); + if (validScreenshots?.Count > 0) { html.AppendLine("

碰撞场景截图

"); - html.AppendLine("
"); - // 使用 PathHelper 计算相对路径 - string relativePath = PathHelper.GetRelativePath(htmlFilePath, CurrentReport.ScreenshotPath); - - html.AppendLine("
"); - html.AppendLine($"\"碰撞场景截图\""); - html.AppendLine("
"); - html.AppendLine($"

分辨率: {CurrentReport.ScreenshotWidth} x {CurrentReport.ScreenshotHeight}

"); - html.AppendLine($"

格式: {CurrentReport.ScreenshotFormat}

"); - html.AppendLine("
"); - html.AppendLine("
"); - html.AppendLine("
"); + if (validScreenshots.Count > 1) + { + // 多张截图 - 画廊样式 + html.AppendLine(""); + + html.AppendLine(""); + } + else + { + // 单张截图 + var screenshot = validScreenshots.First(); + html.AppendLine("
"); + string relativePath = PathHelper.GetRelativePath(htmlFilePath, screenshot.FilePath); + html.AppendLine("
"); + html.AppendLine($"\"碰撞场景截图\""); + html.AppendLine("
"); + html.AppendLine($"

分辨率: {screenshot.Width} x {screenshot.Height}

"); + html.AppendLine($"

格式: {screenshot.Format}

"); + html.AppendLine("
"); + html.AppendLine("
"); + html.AppendLine("
"); + } } // 运动构件信息 @@ -978,17 +1167,105 @@ namespace NavisworksTransport.UI.WPF.ViewModels } /// - /// 执行重新截图 + /// 执行添加新截图(使用默认设置,不弹出对话框) /// - private void ExecuteRetakeScreenshot() + private void ExecuteAddScreenshot() { try { - // 复用现有的截图配置对话框 - var dialog = new GenerateNavigationMapDialog(); - dialog.Title = "碰撞场景截图配置"; + // 使用默认设置直接生成截图,不弹出对话框 + string screenshotPath = PathHelper.GenerateSceneScreenshot( + CurrentReport.PathName ?? "collision", + ScreenshotWidthSetting, + ScreenshotHeightSetting, + ScreenshotFormatSetting, + "collision" + ); + + if (screenshotPath != null) + { + // 创建截图对象 + var screenshot = new CollisionReportScreenshot + { + FilePath = screenshotPath, + Format = PathHelper.ImageFormatToExtension(ScreenshotFormatSetting).ToUpper(), + Width = ScreenshotWidthSetting, + Height = ScreenshotHeightSetting, + SortOrder = Screenshots.Count + }; + + // 添加到列表 + Screenshots.Add(screenshot); + SelectedScreenshot = screenshot; + + // 同步到报告数据 + if (CurrentReport.Screenshots == null) + CurrentReport.Screenshots = new List(); + CurrentReport.Screenshots.Add(screenshot); + + // 保存到数据库 + try + { + var pathDatabase = PathPlanningManager.Instance?.GetPathDatabase(); + // 使用 ResultId 精确关联到当前报告记录 + if (pathDatabase != null && CurrentReport.ResultId > 0) + { + int dbId = pathDatabase.SaveCollisionReportScreenshot( + CurrentReport.ResultId, + screenshotPath, + screenshot.Format, + screenshot.Width, + screenshot.Height, + screenshot.SortOrder + ); + screenshot.DatabaseId = dbId; // 保存数据库Id用于后续删除 + LogManager.Info($"新截图已保存到数据库: DatabaseId={dbId}, ResultId={CurrentReport.ResultId}, Path={screenshotPath}"); + } + else + { + LogManager.Warning($"无法保存截图到数据库: ResultId={CurrentReport.ResultId}, RouteId={CurrentReport.RouteId}"); + } + } + catch (Exception dbEx) + { + LogManager.Error($"保存新截图到数据库失败: {dbEx.Message}"); + } + + OnPropertyChanged(nameof(HasScreenshots)); + OnPropertyChanged(nameof(ScreenshotCount)); + + LogManager.Info($"已添加新截图,当前共 {Screenshots.Count} 张"); + } + } + catch (Exception ex) + { + LogManager.Error($"添加截图失败: {ex.Message}"); + System.Windows.MessageBox.Show($"添加截图失败: {ex.Message}", "错误", + System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error); + } + } + + /// + /// 检查是否可以添加截图 + /// + private bool CanExecuteAddScreenshot() + { + return CurrentReport != null; + } + + /// + /// 执行截图设置 - 打开对话框修改截图参数 + /// + private void ExecuteScreenshotSettings() + { + try + { + var dialog = new GenerateNavigationMapDialog(); + dialog.Title = "截图设置"; + + // 设置当前值,保留当前报告窗口的设置 + dialog.SetInitialValues(ScreenshotWidthSetting, ScreenshotHeightSetting, ScreenshotFormatSetting); - // 尝试设置 Owner(如果主窗口已显示) var mainWindow = System.Windows.Application.Current.MainWindow; if (mainWindow != null && mainWindow.IsLoaded) { @@ -997,77 +1274,91 @@ namespace NavisworksTransport.UI.WPF.ViewModels if (dialog.ShowDialog() == true) { - // 调用 PathHelper 生成截图 - string screenshotPath = PathHelper.GenerateSceneScreenshot( - CurrentReport.PathName ?? "collision", - dialog.ImageWidth, - dialog.ImageHeight, - dialog.ImageFormat, - "collision" - ); + // 更新设置 + ScreenshotWidthSetting = dialog.ImageWidth; + ScreenshotHeightSetting = dialog.ImageHeight; + ScreenshotFormatSetting = dialog.ImageFormat; - if (screenshotPath != null) - { - // 更新报告数据 - CurrentReport.ScreenshotPath = screenshotPath; - CurrentReport.ScreenshotFormat = PathHelper.ImageFormatToExtension(dialog.ImageFormat).ToUpper(); - CurrentReport.ScreenshotWidth = dialog.ImageWidth; - CurrentReport.ScreenshotHeight = dialog.ImageHeight; - - // 保存到数据库 - try - { - var pathDatabase = PathPlanningManager.Instance?.GetPathDatabase(); - if (pathDatabase != null && !string.IsNullOrEmpty(CurrentReport.RouteId)) - { - pathDatabase.UpdateCollisionReportScreenshot( - CurrentReport.RouteId, - screenshotPath, - CurrentReport.ScreenshotFormat, - dialog.ImageWidth, - dialog.ImageHeight - ); - LogManager.Info($"碰撞报告截图已保存到数据库: RouteId={CurrentReport.RouteId}"); - } - else - { - LogManager.Warning("无法保存截图到数据库:PathDatabase不可用或RouteId为空"); - } - } - catch (Exception dbEx) - { - LogManager.Error($"保存截图到数据库失败: {dbEx.Message}"); - // 继续执行,不影响截图生成 - } - - // 通知UI更新 - OnPropertyChanged(nameof(CurrentReport)); - OnPropertyChanged(nameof(ScreenshotPreviewSource)); - - // 提示用户 - System.Windows.MessageBox.Show( - "截图已更新并保存到数据库。", - "截图更新成功", - System.Windows.MessageBoxButton.OK, - System.Windows.MessageBoxImage.Information); - - LogManager.Info("碰撞场景截图已更新"); - } + LogManager.Info($"截图设置已更新: {ScreenshotWidthSetting}x{ScreenshotHeightSetting}, {ScreenshotFormatSetting}"); } } catch (Exception ex) { - LogManager.Error($"重新截图失败: {ex.Message}"); - System.Windows.MessageBox.Show($"重新截图失败: {ex.Message}", "错误", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error); + LogManager.Error($"打开截图设置失败: {ex.Message}"); } } /// - /// 检查是否可以执行重新截图 + /// 执行删除截图 /// - private bool CanExecuteRetakeScreenshot() + private void ExecuteDeleteScreenshot(CollisionReportScreenshot screenshot) { - return CurrentReport != null; + if (screenshot == null) return; + + try + { + var result = System.Windows.MessageBox.Show( + "确定要删除这张截图吗?", + "确认删除", + System.Windows.MessageBoxButton.YesNo, + System.Windows.MessageBoxImage.Question); + + if (result != System.Windows.MessageBoxResult.Yes) return; + + // 从数据库删除(如果知道DatabaseId) + if (screenshot.DatabaseId > 0) + { + try + { + var pathDatabase = PathPlanningManager.Instance?.GetPathDatabase(); + pathDatabase?.DeleteCollisionReportScreenshot(screenshot.DatabaseId); + LogManager.Debug($"从数据库删除截图: DatabaseId={screenshot.DatabaseId}"); + } + catch (Exception dbEx) + { + LogManager.Error($"从数据库删除截图失败: {dbEx.Message}"); + } + } + + // 从列表移除 + Screenshots.Remove(screenshot); + + // 从报告数据移除 + CurrentReport.Screenshots?.Remove(screenshot); + + // 更新选中项 + if (SelectedScreenshot == screenshot) + { + SelectedScreenshot = Screenshots.FirstOrDefault(); + } + + // 重新排序并更新数据库 + for (int i = 0; i < Screenshots.Count; i++) + { + Screenshots[i].SortOrder = i; + } + + OnPropertyChanged(nameof(HasScreenshots)); + OnPropertyChanged(nameof(ScreenshotCount)); + + LogManager.Info($"已删除截图,剩余 {Screenshots.Count} 张"); + } + catch (Exception ex) + { + LogManager.Error($"删除截图失败: {ex.Message}"); + } + } + + /// + /// 执行选择截图 + /// + private void ExecuteSelectScreenshot(CollisionReportScreenshot screenshot) + { + if (screenshot != null) + { + SelectedScreenshot = screenshot; + LogManager.Debug($"选中截图: {screenshot.FilePath}"); + } } #endregion diff --git a/src/UI/WPF/ViewModels/PathEditingViewModel.cs b/src/UI/WPF/ViewModels/PathEditingViewModel.cs index ba03f63..798e4c5 100644 --- a/src/UI/WPF/ViewModels/PathEditingViewModel.cs +++ b/src/UI/WPF/ViewModels/PathEditingViewModel.cs @@ -2784,6 +2784,15 @@ namespace NavisworksTransport.UI.WPF.ViewModels { if (PathPointRenderPlugin.Instance != null) { + // 检查检测动画页签是否选择了物体或使用了虚拟车辆,如果有,保持使用对应的尺寸而不是重置为默认车辆参数 + var animationVm = AnimationControlViewModel.Instance; + if (animationVm != null && animationVm.HasSelectedAnimatedObject) + { + // 检测动画页签已选择物体(实际物体或虚拟车辆),跳过同步,保留已设置的通行空间 + LogManager.Debug("[车辆参数同步] 检测动画页签已选择动画对象,跳过同步以保留当前通行空间尺寸"); + return; + } + // 根据路径类型计算通行空间尺寸 double passageAcrossPath, passageNormalToPath, passageAlongPath; PathType pathType = SelectedPathRoute?.PathType ?? PathType.Ground; diff --git a/src/UI/WPF/Views/CollisionReportDialog.xaml b/src/UI/WPF/Views/CollisionReportDialog.xaml index d2aa542..be44862 100644 --- a/src/UI/WPF/Views/CollisionReportDialog.xaml +++ b/src/UI/WPF/Views/CollisionReportDialog.xaml @@ -21,8 +21,8 @@ NavisworksTransport 碰撞检测报告对话框 - 采用与主界面一致的Nav Width="900" ResizeMode="CanResize" WindowStartupLocation="CenterOwner" - MinHeight="900" - MinWidth="700"> + MinHeight="800" + MinWidth="600"> @@ -36,6 +36,8 @@ NavisworksTransport 碰撞检测报告对话框 - 采用与主界面一致的Nav + + - - + MinHeight="300" + Margin="0,0,0,10"> + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -400,17 +531,17 @@ NavisworksTransport 碰撞检测报告对话框 - 采用与主界面一致的Nav +
/// 事件发送者 /// 事件参数 - private void CloseButton_Click(object sender, RoutedEventArgs e) + private async void CloseButton_Click(object sender, RoutedEventArgs e) { try { - LogManager.Info("用户关闭碰撞报告对话框"); + LogManager.Info("用户关闭碰撞报告对话框,正在自动导出报告..."); + + // 关闭前自动导出报告 + await AutoExportReportAsync(); + this.Close(); } catch (Exception ex) @@ -99,6 +106,24 @@ namespace NavisworksTransport.UI.WPF.Views } } + /// + /// 自动导出报告 + /// + private async System.Threading.Tasks.Task AutoExportReportAsync() + { + try + { + if (_viewModel != null) + { + await _viewModel.AutoExportReportAsync(); + } + } + catch (Exception ex) + { + LogManager.Error($"自动导出报告失败: {ex.Message}"); + } + } + /// /// 窗口关闭事件 /// @@ -251,6 +276,72 @@ namespace NavisworksTransport.UI.WPF.Views #endregion + #region 截图相关事件处理 + + /// + /// 缩略图点击事件 - 切换主图显示 + /// + private void OnThumbnailClick(object sender, System.Windows.Input.MouseButtonEventArgs e) + { + try + { + if (sender is Border border && border.DataContext is CollisionReportScreenshot screenshot) + { + _viewModel?.SelectScreenshotCommand?.Execute(screenshot); + LogManager.Debug($"切换截图: {screenshot.FilePath}"); + } + } + catch (Exception ex) + { + LogManager.Error($"切换截图失败: {ex.Message}"); + } + } + + /// + /// 添加截图按钮点击事件 + /// + private void OnAddScreenshotClick(object sender, System.Windows.Input.MouseButtonEventArgs e) + { + try + { + _viewModel?.AddScreenshotCommand?.Execute(null); + } + catch (Exception ex) + { + LogManager.Error($"添加截图失败: {ex.Message}"); + } + } + + /// + /// 删除截图按钮点击事件 - 删除当前选中的截图 + /// + private void OnDeleteScreenshotClick(object sender, System.Windows.Input.MouseButtonEventArgs e) + { + try + { + // 删除当前选中的截图 + if (_viewModel?.SelectedScreenshot != null) + { + _viewModel?.DeleteScreenshotCommand?.Execute(_viewModel.SelectedScreenshot); + } + else if (_viewModel?.Screenshots?.Count > 0) + { + // 如果没有选中,删除最后一张 + var lastScreenshot = _viewModel.Screenshots.LastOrDefault(); + if (lastScreenshot != null) + { + _viewModel?.DeleteScreenshotCommand?.Execute(lastScreenshot); + } + } + } + catch (Exception ex) + { + LogManager.Error($"删除截图失败: {ex.Message}"); + } + } + + #endregion + #region 静态工厂方法 /// diff --git a/src/UI/WPF/Views/GenerateNavigationMapDialog.xaml.cs b/src/UI/WPF/Views/GenerateNavigationMapDialog.xaml.cs index bc84b21..6c69249 100644 --- a/src/UI/WPF/Views/GenerateNavigationMapDialog.xaml.cs +++ b/src/UI/WPF/Views/GenerateNavigationMapDialog.xaml.cs @@ -44,6 +44,68 @@ namespace NavisworksTransport.UI.WPF.Views Loaded += (sender, e) => InitializeDefaults(); } + /// + /// 设置初始值(用于保留当前报告窗口的截图设置) + /// + public void SetInitialValues(int width, int height, ImageFormat format) + { + try + { + ImageWidth = width; + ImageHeight = height; + ImageFormat = format; + + // 更新UI控件 + if (WidthTextBox != null) + WidthTextBox.Text = width.ToString(); + if (HeightTextBox != null) + HeightTextBox.Text = height.ToString(); + + // 设置格式下拉框 + if (FormatComboBox != null) + { + string formatName = format.ToString().ToUpper(); + for (int i = 0; i < FormatComboBox.Items.Count; i++) + { + var item = FormatComboBox.Items[i] as ComboBoxItem; + if (item?.Tag?.ToString()?.ToUpper() == formatName) + { + FormatComboBox.SelectedIndex = i; + break; + } + } + } + + // 设置预设尺寸下拉框 + if (PresetSizeComboBox != null) + { + string sizeTag = $"{width}x{height}"; + bool found = false; + for (int i = 0; i < PresetSizeComboBox.Items.Count; i++) + { + var item = PresetSizeComboBox.Items[i] as ComboBoxItem; + if (item?.Tag?.ToString() == sizeTag) + { + PresetSizeComboBox.SelectedIndex = i; + found = true; + break; + } + } + // 如果没有匹配预设,选择自定义 + if (!found && PresetSizeComboBox.Items.Count > 0) + { + PresetSizeComboBox.SelectedIndex = PresetSizeComboBox.Items.Count - 1; // 假设最后是自定义 + } + } + + LogManager.Debug($"截图对话框初始值已设置: {width}x{height}, {format}"); + } + catch (Exception ex) + { + LogManager.Error($"设置截图对话框初始值失败: {ex.Message}", ex); + } + } + /// /// 初始化默认值 /// @@ -51,19 +113,24 @@ namespace NavisworksTransport.UI.WPF.Views { try { - // 设置默认值 - ImageWidth = 1920; - ImageHeight = 1080; - ImageFormat = ImageFormat.Png; + // 设置默认值(仅在未通过 SetInitialValues 设置时) + if (ImageWidth == 0) ImageWidth = 1920; + if (ImageHeight == 0) ImageHeight = 1080; + if (ImageFormat == null) ImageFormat = ImageFormat.Png; RenderStyle = ImageGenerationStyle.ScenePlusOverlay; IsConfirmed = false; - // 设置默认选择 - FormatComboBox.SelectedIndex = 1; // PNG - PresetSizeComboBox.SelectedIndex = 2; // 1920x1080 (因为添加了4K选项,索引变为2) + // 设置UI控件值 + if (WidthTextBox != null && string.IsNullOrEmpty(WidthTextBox.Text)) + WidthTextBox.Text = ImageWidth.ToString(); + if (HeightTextBox != null && string.IsNullOrEmpty(HeightTextBox.Text)) + HeightTextBox.Text = ImageHeight.ToString(); - WidthTextBox.Text = ImageWidth.ToString(); - HeightTextBox.Text = ImageHeight.ToString(); + // 设置默认选择(仅在未设置时) + if (FormatComboBox != null && FormatComboBox.SelectedIndex < 0) + FormatComboBox.SelectedIndex = 1; // PNG + if (PresetSizeComboBox != null && PresetSizeComboBox.SelectedIndex < 0) + PresetSizeComboBox.SelectedIndex = 2; // 1920x1080 } catch (Exception ex) { diff --git a/src/Utils/CollisionReportHtmlGenerator.cs b/src/Utils/CollisionReportHtmlGenerator.cs index f2a310c..fea1727 100644 --- a/src/Utils/CollisionReportHtmlGenerator.cs +++ b/src/Utils/CollisionReportHtmlGenerator.cs @@ -99,23 +99,59 @@ namespace NavisworksTransport.Utils html.AppendLine(""); html.AppendLine(""); - // 碰撞场景截图 - if (!string.IsNullOrEmpty(report.ScreenshotPath) && File.Exists(report.ScreenshotPath)) + // 碰撞场景截图(支持多张) + var validScreenshots = report.Screenshots?.Where(s => !string.IsNullOrEmpty(s.FilePath) && File.Exists(s.FilePath)).ToList(); + if (validScreenshots?.Count > 0 || (!string.IsNullOrEmpty(report.ScreenshotPath) && File.Exists(report.ScreenshotPath))) { html.AppendLine("

碰撞场景截图

"); - html.AppendLine("
"); - // 使用 PathHelper 计算相对路径 - string relativePath = PathHelper.GetRelativePath(htmlFilePath, report.ScreenshotPath); - - html.AppendLine("
"); - html.AppendLine($"\"碰撞场景截图\""); - html.AppendLine("
"); - html.AppendLine($"

分辨率: {report.ScreenshotWidth} x {report.ScreenshotHeight}

"); - html.AppendLine($"

格式: {report.ScreenshotFormat}

"); - html.AppendLine("
"); - html.AppendLine("
"); - html.AppendLine("
"); + // 多张截图样式 + if (validScreenshots?.Count > 1) + { + html.AppendLine(""); + + html.AppendLine(""); + } + else + { + // 单张截图样式(兼容旧版本) + string screenshotPath = validScreenshots?.FirstOrDefault()?.FilePath ?? report.ScreenshotPath; + var screenshot = validScreenshots?.FirstOrDefault(); + + html.AppendLine("
"); + string relativePath = PathHelper.GetRelativePath(htmlFilePath, screenshotPath); + html.AppendLine("
"); + html.AppendLine($"\"碰撞场景截图\""); + html.AppendLine("
"); + html.AppendLine($"

分辨率: {screenshot?.Width ?? report.ScreenshotWidth} x {screenshot?.Height ?? report.ScreenshotHeight}

"); + html.AppendLine($"

格式: {screenshot?.Format ?? report.ScreenshotFormat}

"); + html.AppendLine("
"); + html.AppendLine("
"); + html.AppendLine("
"); + } } // 运动构件信息