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];
}
}
}
}