From 8c298544b4b8fd6c5dfa6363426abc95354f62f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E6=A2=93=E5=BD=AD?= Date: Tue, 19 May 2026 11:12:41 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=AF=81=E4=B9=A6=E7=94=9F?= =?UTF-8?q?=E6=88=90=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Certificate/CertificateGenerateService.cs | 90 +++++++++---------- .../Points/PointsRecordService.cs | 1 - 2 files changed, 45 insertions(+), 46 deletions(-) diff --git a/YD_Event.Application/Certificate/CertificateGenerateService.cs b/YD_Event.Application/Certificate/CertificateGenerateService.cs index 11126c5..c96250d 100644 --- a/YD_Event.Application/Certificate/CertificateGenerateService.cs +++ b/YD_Event.Application/Certificate/CertificateGenerateService.cs @@ -295,7 +295,15 @@ public class CertificateGenerateService : IDynamicApiController, ITransient // 生成PDF var pdfStream = new MemoryStream(); - await GeneratePdfWithQuestPDF(pdfStream, documentData); + try + { + await GeneratePdfWithQuestPDF(pdfStream, documentData); + } + catch (Exception ex) + { + var a = 1; + throw; + } pdfStream.Position = 0; _logger.LogInformation("DOCX转PDF完成,PDF大小: {Size} bytes", pdfStream.Length); @@ -793,8 +801,8 @@ public class CertificateGenerateService : IDynamicApiController, ITransient var outerXml = drawing.OuterXml; _logger.LogDebug("Drawing 对象原始 XML (前800字符): {Xml}", outerXml.Substring(0, Math.Min(800, outerXml.Length))); - // 方法1: 查找 simplePos 属性(通常用于绝对定位) - // ExtractSimplePosition(outerXml, paragraphData); + // 方法1: 先查找 simplePos 属性(通常用于绝对定位) + ExtractSimplePosition(outerXml, paragraphData); // 方法2: 如果 simplePos 没有值,查找 positionOffset 元素 if (paragraphData.PositionX == null || paragraphData.PositionY == null) @@ -802,12 +810,6 @@ public class CertificateGenerateService : IDynamicApiController, ITransient ExtractPositionOffset(outerXml, paragraphData); } - // 注意:不使用 distL, distT 等距离属性 - // 这些属性不是文本框在页面上的坐标,而是: - // - 要么是文本框的内边距(文本到边框的距离) - // - 要么是文本框到页面边距的距离(而不是绝对坐标) - // 我们目前使用写死定位方式,不需要依赖这些值 - _logger.LogDebug("最终提取的位置 - X: {X}, Y: {Y}", paragraphData.PositionX, paragraphData.PositionY); } catch (Exception ex) @@ -1063,6 +1065,14 @@ public class CertificateGenerateService : IDynamicApiController, ITransient var selectedFont = CertificateFontHelper.GetSelectedFont(); _logger.LogInformation($"使用字体: {selectedFont ?? "默认字体"}"); + // 记录提取到的位置信息,便于调试 + _logger.LogInformation($"提取到 {documentData.Paragraphs.Count} 个文本框:"); + for (int i = 0; i < documentData.Paragraphs.Count; i++) + { + var p = documentData.Paragraphs[i]; + _logger.LogInformation($" [{i}] 文本: {p.Text}, X: {p.PositionX}, Y: {p.PositionY}, 字号: {p.FontSize}"); + } + var questDocument = QuestPDF.Fluent.Document.Create(container => { container.Page(page => @@ -1084,62 +1094,52 @@ public class CertificateGenerateService : IDynamicApiController, ITransient .Image(documentData.BackgroundImage) .FitArea(); } + + // 最简单且工作的方案:使用正常的 Column 布局 + // 但通过跟踪和补偿累积高度来定位所有文本 + float cumulativeHeight = 0; - // 使用 Column 来放置所有内容 page.Content().Column(column => { column.Spacing(0); - - double? firstParagraphY = null; - double? firstParagraphOriginalY = null; - - // 根据文本框数量确定X轴偏移量 - float xOffset = documentData.Paragraphs.Count == 1 ? 140 : 100; - - // 根据段落信息进行定位 - for (int i = 0; i < documentData.Paragraphs.Count; i++) + + foreach (var paragraph in documentData.Paragraphs) { - var paragraph = documentData.Paragraphs[i]; var fontSize = paragraph.FontSize ?? 14; var isBold = paragraph.IsBold; - - // 计算位置 - float x = (float)(paragraph.PositionX ?? 50) + xOffset; - float y; - - if (i == 0) - { - firstParagraphY = paragraph.PositionY ?? 50; - firstParagraphOriginalY = firstParagraphY.Value; - y = (float)firstParagraphY + 70; - } - else - { - y = (float)(firstParagraphOriginalY + 70) + (i * 45); - } - - // 创建文本元素 - var textElement = column.Item() + + // X偏移+80保持不变 + // Y坐标减去之前所有文本占用的高度进行补偿 + float x = (float)(paragraph.PositionX ?? 50) + 90; + float y = (float)(paragraph.PositionY ?? 50) + 75 - cumulativeHeight; + + _logger.LogInformation($"放置文本框: 文本={paragraph.Text}, X={x}, Y={y}, cumulativeHeight={cumulativeHeight}"); + + // 正常添加文本,不限制高度 + var element = column.Item() .TranslateX(x) .TranslateY(y) .Text(paragraph.Text) .FontSize((float)fontSize) - .FontColor(QuestPDF.Helpers.Colors.Black) + .FontColor(Colors.Black) .AlignLeft(); - - // 应用字体 + if (!string.IsNullOrEmpty(selectedFont)) { - textElement = textElement.FontFamily(selectedFont); + element = element.FontFamily(selectedFont); } - + if (isBold) { - textElement = textElement.Bold(); + element = element.Bold(); } + + // 估算当前文本行的高度并累积 + // 通常一行文本高度大约是 font-size * 1.5 + cumulativeHeight += (float)(fontSize * 1.5f); } }); - + // 添加二维码到右下角 if (documentData.QRCodeImage != null) { diff --git a/YD_Event.Application/Points/PointsRecordService.cs b/YD_Event.Application/Points/PointsRecordService.cs index 9d88036..d9fa833 100644 --- a/YD_Event.Application/Points/PointsRecordService.cs +++ b/YD_Event.Application/Points/PointsRecordService.cs @@ -287,7 +287,6 @@ public class PointsRecordService : BaseService, ITransient Action = e.EventName, Item = pr.Name, ProjectId = pr.Id, - ProjectType = pr.ProjectType, Group = er.GroupName, Points = p.Points, Remark = p.Remark,