修复证书生成问题

This commit is contained in:
马梓彭 2026-05-19 11:12:41 +08:00
parent f823dfb7eb
commit 8c298544b4
2 changed files with 45 additions and 46 deletions

View File

@ -295,7 +295,15 @@ public class CertificateGenerateService : IDynamicApiController, ITransient
// 生成PDF // 生成PDF
var pdfStream = new MemoryStream(); var pdfStream = new MemoryStream();
await GeneratePdfWithQuestPDF(pdfStream, documentData); try
{
await GeneratePdfWithQuestPDF(pdfStream, documentData);
}
catch (Exception ex)
{
var a = 1;
throw;
}
pdfStream.Position = 0; pdfStream.Position = 0;
_logger.LogInformation("DOCX转PDF完成,PDF大小: {Size} bytes", pdfStream.Length); _logger.LogInformation("DOCX转PDF完成,PDF大小: {Size} bytes", pdfStream.Length);
@ -793,8 +801,8 @@ public class CertificateGenerateService : IDynamicApiController, ITransient
var outerXml = drawing.OuterXml; var outerXml = drawing.OuterXml;
_logger.LogDebug("Drawing 对象原始 XML (前800字符): {Xml}", outerXml.Substring(0, Math.Min(800, outerXml.Length))); _logger.LogDebug("Drawing 对象原始 XML (前800字符): {Xml}", outerXml.Substring(0, Math.Min(800, outerXml.Length)));
// 方法1: 查找 simplePos 属性(通常用于绝对定位) // 方法1: 先查找 simplePos 属性(通常用于绝对定位)
// ExtractSimplePosition(outerXml, paragraphData); ExtractSimplePosition(outerXml, paragraphData);
// 方法2: 如果 simplePos 没有值,查找 positionOffset 元素 // 方法2: 如果 simplePos 没有值,查找 positionOffset 元素
if (paragraphData.PositionX == null || paragraphData.PositionY == null) if (paragraphData.PositionX == null || paragraphData.PositionY == null)
@ -802,12 +810,6 @@ public class CertificateGenerateService : IDynamicApiController, ITransient
ExtractPositionOffset(outerXml, paragraphData); ExtractPositionOffset(outerXml, paragraphData);
} }
// 注意:不使用 distL, distT 等距离属性
// 这些属性不是文本框在页面上的坐标,而是:
// - 要么是文本框的内边距(文本到边框的距离)
// - 要么是文本框到页面边距的距离(而不是绝对坐标)
// 我们目前使用写死定位方式,不需要依赖这些值
_logger.LogDebug("最终提取的位置 - X: {X}, Y: {Y}", paragraphData.PositionX, paragraphData.PositionY); _logger.LogDebug("最终提取的位置 - X: {X}, Y: {Y}", paragraphData.PositionX, paragraphData.PositionY);
} }
catch (Exception ex) catch (Exception ex)
@ -1063,6 +1065,14 @@ public class CertificateGenerateService : IDynamicApiController, ITransient
var selectedFont = CertificateFontHelper.GetSelectedFont(); var selectedFont = CertificateFontHelper.GetSelectedFont();
_logger.LogInformation($"使用字体: {selectedFont ?? "默认字体"}"); _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 => var questDocument = QuestPDF.Fluent.Document.Create(container =>
{ {
container.Page(page => container.Page(page =>
@ -1084,62 +1094,52 @@ public class CertificateGenerateService : IDynamicApiController, ITransient
.Image(documentData.BackgroundImage) .Image(documentData.BackgroundImage)
.FitArea(); .FitArea();
} }
// 最简单且工作的方案:使用正常的 Column 布局
// 但通过跟踪和补偿累积高度来定位所有文本
float cumulativeHeight = 0;
// 使用 Column 来放置所有内容
page.Content().Column(column => page.Content().Column(column =>
{ {
column.Spacing(0); column.Spacing(0);
double? firstParagraphY = null; foreach (var paragraph in documentData.Paragraphs)
double? firstParagraphOriginalY = null;
// 根据文本框数量确定X轴偏移量
float xOffset = documentData.Paragraphs.Count == 1 ? 140 : 100;
// 根据段落信息进行定位
for (int i = 0; i < documentData.Paragraphs.Count; i++)
{ {
var paragraph = documentData.Paragraphs[i];
var fontSize = paragraph.FontSize ?? 14; var fontSize = paragraph.FontSize ?? 14;
var isBold = paragraph.IsBold; var isBold = paragraph.IsBold;
// 计算位置 // X偏移+80保持不变
float x = (float)(paragraph.PositionX ?? 50) + xOffset; // Y坐标减去之前所有文本占用的高度进行补偿
float y; float x = (float)(paragraph.PositionX ?? 50) + 90;
float y = (float)(paragraph.PositionY ?? 50) + 75 - cumulativeHeight;
if (i == 0)
{ _logger.LogInformation($"放置文本框: 文本={paragraph.Text}, X={x}, Y={y}, cumulativeHeight={cumulativeHeight}");
firstParagraphY = paragraph.PositionY ?? 50;
firstParagraphOriginalY = firstParagraphY.Value; // 正常添加文本,不限制高度
y = (float)firstParagraphY + 70; var element = column.Item()
}
else
{
y = (float)(firstParagraphOriginalY + 70) + (i * 45);
}
// 创建文本元素
var textElement = column.Item()
.TranslateX(x) .TranslateX(x)
.TranslateY(y) .TranslateY(y)
.Text(paragraph.Text) .Text(paragraph.Text)
.FontSize((float)fontSize) .FontSize((float)fontSize)
.FontColor(QuestPDF.Helpers.Colors.Black) .FontColor(Colors.Black)
.AlignLeft(); .AlignLeft();
// 应用字体
if (!string.IsNullOrEmpty(selectedFont)) if (!string.IsNullOrEmpty(selectedFont))
{ {
textElement = textElement.FontFamily(selectedFont); element = element.FontFamily(selectedFont);
} }
if (isBold) if (isBold)
{ {
textElement = textElement.Bold(); element = element.Bold();
} }
// 估算当前文本行的高度并累积
// 通常一行文本高度大约是 font-size * 1.5
cumulativeHeight += (float)(fontSize * 1.5f);
} }
}); });
// 添加二维码到右下角 // 添加二维码到右下角
if (documentData.QRCodeImage != null) if (documentData.QRCodeImage != null)
{ {

View File

@ -287,7 +287,6 @@ public class PointsRecordService : BaseService<PointsRecord>, ITransient
Action = e.EventName, Action = e.EventName,
Item = pr.Name, Item = pr.Name,
ProjectId = pr.Id, ProjectId = pr.Id,
ProjectType = pr.ProjectType,
Group = er.GroupName, Group = er.GroupName,
Points = p.Points, Points = p.Points,
Remark = p.Remark, Remark = p.Remark,