From 41c55fafe0269806610f40a704dd63d08621afa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E6=A2=93=E5=BD=AD?= Date: Thu, 16 Apr 2026 12:51:29 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E8=AF=81=E4=B9=A6=E5=8F=91?= =?UTF-8?q?=E6=94=BE=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Certificate/CertificateGenerateService.cs | 51 ++++++++++++++++--- 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/YD_Event.Application/Certificate/CertificateGenerateService.cs b/YD_Event.Application/Certificate/CertificateGenerateService.cs index 4050776..c703b12 100644 --- a/YD_Event.Application/Certificate/CertificateGenerateService.cs +++ b/YD_Event.Application/Certificate/CertificateGenerateService.cs @@ -475,6 +475,16 @@ public class CertificateGenerateService : IDynamicApiController, ITransient } } + // 按照Y轴坐标进行升序排序,确保文本框显示顺序与Word文档视觉顺序一致 + documentData.Paragraphs = documentData.Paragraphs + .OrderBy(p => p.PositionY ?? double.MaxValue) // 使用PositionY排序,没有位置的放在最后 + .ThenBy(p => p.PositionX ?? double.MaxValue) // Y轴相同的情况下按X轴排序 + .ToList(); + + // 记录排序后的顺序,便于调试 + _logger.LogDebug("文本框排序完成,顺序: {Order}", + string.Join(" -> ", documentData.Paragraphs.Select((p, i) => $"[{i}]{p.Text}(Y={p.PositionY})"))); + return documentData; } @@ -782,7 +792,7 @@ public class CertificateGenerateService : IDynamicApiController, ITransient _logger.LogDebug("Drawing 对象原始 XML (前800字符): {Xml}", outerXml.Substring(0, Math.Min(800, outerXml.Length))); // 方法1: 查找 simplePos 属性(通常用于绝对定位) - ExtractSimplePosition(outerXml, paragraphData); + // ExtractSimplePosition(outerXml, paragraphData); // 方法2: 如果 simplePos 没有值,查找 positionOffset 元素 if (paragraphData.PositionX == null || paragraphData.PositionY == null) @@ -1061,12 +1071,22 @@ public class CertificateGenerateService : IDynamicApiController, ITransient .FitArea(); } - // 使用 Column 来放置所有内容,但使用 Translate 而非 Padding 定位 + // 使用 Column 来放置所有内容,但禁用默认间距 page.Content().Column(column => { - // 根据段落信息进行定位(使用从Word文档提取的位置信息) - foreach (var paragraph in documentData.Paragraphs) + column.Spacing(0); + + double? firstParagraphY = null; + double? firstParagraphOriginalY = null; + + // 根据文本框数量确定X轴偏移量 + float xOffset = documentData.Paragraphs.Count == 1 ? 140 : 100; + _logger.LogDebug("文本框数量: {Count}, X轴偏移量: {Offset}", documentData.Paragraphs.Count, xOffset); + + // 根据段落信息进行定位(基于第一个元素重新计算,保持50单位统一间隔) + for (int i = 0; i < documentData.Paragraphs.Count; i++) { + var paragraph = documentData.Paragraphs[i]; var fontSize = paragraph.FontSize ?? 14; var isBold = paragraph.IsBold; @@ -1074,13 +1094,28 @@ public class CertificateGenerateService : IDynamicApiController, ITransient _logger.LogDebug("处理段落: Text={Text}, X={X}, Y={Y}, FontSize={FontSize}, Bold={IsBold}", paragraph.Text, paragraph.PositionX, paragraph.PositionY, fontSize, isBold); - // 直接使用从Word文档提取的位置信息,并增加110个单位进行调整 - float x = (float)(paragraph.PositionX ?? 50) + 90; - float y = (float)(paragraph.PositionY ?? 50) + 50; + // 直接使用从Word文档提取的X坐标,并增加条件性调整值 + float x = (float)(paragraph.PositionX ?? 50) + xOffset; + float y; + + if (i == 0) + { + // 第一个段落,保持原始位置+70偏移 + firstParagraphY = paragraph.PositionY ?? 50; + firstParagraphOriginalY = firstParagraphY.Value; + y = (float)firstParagraphY + 70; + _logger.LogDebug("第一个段落,使用原始Y + 70偏移"); + } + else + { + // 后续段落,相对于前一个段落,固定增加50单位 + y = (float)(firstParagraphOriginalY + 70) + (i * 45); + _logger.LogDebug("第{Index}个段落,基于第一个段落 + {Offset}单位", i + 1, i * 50); + } _logger.LogDebug("最终位置 - X={X}, Y={Y}", x, y); - // 使用 Translate 而非 Padding 来定位,避免流式布局累加导致分页 + // 使用 Translate 来定位,配合 Spacing(0) 确保没有额外间隔 var textElement = column.Item().TranslateX(x).TranslateY(y).Text(paragraph.Text) .FontSize((float)fontSize) .FontColor(QuestPDF.Helpers.Colors.Black)