WorkCamera/client/WorkCameraExport/Services/ExcelService.cs
2026-01-05 21:20:55 +08:00

277 lines
9.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using OfficeOpenXml;
using OfficeOpenXml.Style;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Formats.Jpeg;
using WorkCameraExport.Models;
namespace WorkCameraExport.Services
{
/// <summary>
/// Excel 服务类 - 生成带图片的 Excel 文件
/// </summary>
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;
}
/// <summary>
/// 生成 Excel 文件
/// </summary>
/// <param name="filePath">输出文件路径</param>
/// <param name="records">工作记录列表</param>
/// <param name="images">图片数据字典URL -> 图片字节数组)</param>
/// <param name="progressCallback">进度回调(当前行, 总行数)</param>
public void GenerateExcel(
string filePath,
List<WorkRecordExportDto> records,
Dictionary<string, byte[]> images,
Action<int, int>? 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));
}
/// <summary>
/// 设置表头
/// </summary>
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;
}
/// <summary>
/// 填充单行数据
/// </summary>
private void FillRecordRow(
ExcelWorksheet worksheet,
int rowIndex,
WorkRecordExportDto record,
Dictionary<string, byte[]> 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;
}
}
/// <summary>
/// 设置单元格值
/// </summary>
private void SetCellValue(ExcelWorksheet worksheet, int row, int col, object value)
{
worksheet.Cells[row, col].Value = value;
}
/// <summary>
/// 嵌入图片到单元格
/// </summary>
private void EmbedImages(
ExcelWorksheet worksheet,
int rowIndex,
int colIndex,
List<string> imageUrls,
Dictionary<string, byte[]> 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}张图片(加载失败)");
}
}
/// <summary>
/// 处理图片(调整大小和压缩)
/// </summary>
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;
}
}
/// <summary>
/// 设置列宽
/// </summary>
private void SetColumnWidths(ExcelWorksheet worksheet)
{
for (int i = 0; i < ColumnWidths.Length; i++)
{
worksheet.Column(i + 1).Width = ColumnWidths[i];
}
}
}
}