using OfficeOpenXml; using OfficeOpenXml.Style; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Formats.Jpeg; using WorkCameraExport.Models; namespace WorkCameraExport.Services { /// /// Excel 服务类 - 生成带图片的 Excel 文件 /// public class ExcelService { // 图片尺寸配置 private const int ImageWidth = 100; private const int ImageHeight = 60; private const int JpegQuality = 50; // Excel 列配置 private static readonly string[] Headers = new[] { "序号", "部门名称", "拍照时间", "经度", "纬度", "位置", "工作内容", "施工人员", "状态", "施工图片", "创建时间", "更新时间" }; private static readonly int[] ColumnWidths = new[] { 8, 20, 18, 12, 12, 30, 40, 20, 10, 15, 18, 18 }; static ExcelService() { // 设置 EPPlus 许可证(非商业用途) ExcelPackage.LicenseContext = LicenseContext.NonCommercial; } /// /// 生成 Excel 文件 /// /// 输出文件路径 /// 工作记录列表 /// 图片数据字典(URL -> 图片字节数组) /// 进度回调(当前行, 总行数) public void GenerateExcel( string filePath, List records, Dictionary images, Action? progressCallback = null) { using var package = new ExcelPackage(); var worksheet = package.Workbook.Worksheets.Add("工作记录"); // 设置表头 SetupHeaders(worksheet); // 填充数据 int rowIndex = 2; int totalRows = records.Count; foreach (var record in records) { FillRecordRow(worksheet, rowIndex, record, images); progressCallback?.Invoke(rowIndex - 1, totalRows); rowIndex++; } // 设置列宽 SetColumnWidths(worksheet); // 冻结首行 worksheet.View.FreezePanes(2, 1); // 保存文件 package.SaveAs(new FileInfo(filePath)); } /// /// 设置表头 /// private void SetupHeaders(ExcelWorksheet worksheet) { for (int i = 0; i < Headers.Length; i++) { var cell = worksheet.Cells[1, i + 1]; cell.Value = Headers[i]; cell.Style.Font.Bold = true; cell.Style.Fill.PatternType = ExcelFillStyle.Solid; cell.Style.Fill.BackgroundColor.SetColor(System.Drawing.Color.FromArgb(0, 122, 204)); cell.Style.Font.Color.SetColor(System.Drawing.Color.White); cell.Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; cell.Style.VerticalAlignment = ExcelVerticalAlignment.Center; cell.Style.Border.BorderAround(ExcelBorderStyle.Thin); } // 设置表头行高 worksheet.Row(1).Height = 25; } /// /// 填充单行数据 /// private void FillRecordRow( ExcelWorksheet worksheet, int rowIndex, WorkRecordExportDto record, Dictionary images) { // 序号 SetCellValue(worksheet, rowIndex, 1, rowIndex - 1); // 部门名称 SetCellValue(worksheet, rowIndex, 2, record.DeptName); // 拍照时间 SetCellValue(worksheet, rowIndex, 3, record.RecordTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? ""); // 经度 SetCellValue(worksheet, rowIndex, 4, record.Longitude); // 纬度 SetCellValue(worksheet, rowIndex, 5, record.Latitude); // 位置 SetCellValue(worksheet, rowIndex, 6, record.Address); // 工作内容 SetCellValue(worksheet, rowIndex, 7, record.Content); worksheet.Cells[rowIndex, 7].Style.WrapText = true; // 施工人员 SetCellValue(worksheet, rowIndex, 8, string.Join(", ", record.Workers)); // 状态 SetCellValue(worksheet, rowIndex, 9, record.StatusName); // 施工图片 - 嵌入图片 EmbedImages(worksheet, rowIndex, 10, record.Images, images); // 创建时间 SetCellValue(worksheet, rowIndex, 11, record.CreateTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? ""); // 更新时间 SetCellValue(worksheet, rowIndex, 12, record.UpdateTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? ""); // 设置行高(根据图片数量调整) int imageCount = record.Images.Count; if (imageCount > 0) { // 每张图片高度 + 间距 double rowHeight = Math.Max(20, imageCount * (ImageHeight + 5)); worksheet.Row(rowIndex).Height = rowHeight; } else { worksheet.Row(rowIndex).Height = 20; } // 设置边框 for (int col = 1; col <= Headers.Length; col++) { worksheet.Cells[rowIndex, col].Style.Border.BorderAround(ExcelBorderStyle.Thin); worksheet.Cells[rowIndex, col].Style.VerticalAlignment = ExcelVerticalAlignment.Center; } } /// /// 设置单元格值 /// private void SetCellValue(ExcelWorksheet worksheet, int row, int col, object value) { worksheet.Cells[row, col].Value = value; } /// /// 嵌入图片到单元格 /// private void EmbedImages( ExcelWorksheet worksheet, int rowIndex, int colIndex, List imageUrls, Dictionary images) { if (imageUrls.Count == 0) { SetCellValue(worksheet, rowIndex, colIndex, "无图片"); return; } int imageOffset = 0; int successCount = 0; foreach (var url in imageUrls) { if (!images.TryGetValue(url, out var imageData) || imageData == null) { continue; } try { // 压缩和调整图片大小 var processedImage = ProcessImage(imageData); if (processedImage == null) continue; // 添加图片到 Excel using var stream = new MemoryStream(processedImage); var picture = worksheet.Drawings.AddPicture( $"img_{rowIndex}_{colIndex}_{successCount}", stream); // 设置图片位置 picture.SetPosition(rowIndex - 1, imageOffset, colIndex - 1, 2); picture.SetSize(ImageWidth, ImageHeight); imageOffset += ImageHeight + 5; successCount++; } catch { // 忽略单张图片处理失败 } } // 如果没有成功嵌入任何图片,显示文本 if (successCount == 0) { SetCellValue(worksheet, rowIndex, colIndex, $"共{imageUrls.Count}张图片(加载失败)"); } } /// /// 处理图片(调整大小和压缩) /// private byte[]? ProcessImage(byte[] imageData) { try { using var image = SixLabors.ImageSharp.Image.Load(imageData); // 调整大小 image.Mutate(x => x.Resize(new ResizeOptions { Size = new SixLabors.ImageSharp.Size(ImageWidth, ImageHeight), Mode = ResizeMode.Max })); // 压缩为 JPEG using var outputStream = new MemoryStream(); var encoder = new JpegEncoder { Quality = JpegQuality }; image.Save(outputStream, encoder); return outputStream.ToArray(); } catch { return null; } } /// /// 设置列宽 /// private void SetColumnWidths(ExcelWorksheet worksheet) { for (int i = 0; i < ColumnWidths.Length; i++) { worksheet.Column(i + 1).Width = ColumnWidths[i]; } } } }