YD_Event.Admin/YD_Event.Core/Certificate/DocxTemplateProcessor.cs
2026-03-04 12:13:49 +08:00

235 lines
8.3 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 System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using DocumentFormat.OpenXml.Drawing.Wordprocessing;
using Furion.DependencyInjection;
namespace YD_Event.Core.Certificate
{
/// <summary>
/// DOCX模板处理器
/// </summary>
public class DocxTemplateProcessor : ITransient
{
private const string PlaceholderPattern = @"\{\{([^}]+)\}\}";
/// <summary>
/// 处理DOCX模板,替换占位符
/// </summary>
/// <param name="templateStream">模板文件流</param>
/// <param name="data">数据字典</param>
/// <param name="qrCodeData">二维码数据字典</param>
/// <returns>处理后的文件流</returns>
public Stream ProcessTemplate(Stream templateStream, Dictionary<string, string> data, Dictionary<string, string> qrCodeData = null)
{
var outputStream = new MemoryStream();
// 复制模板到输出流
templateStream.Position = 0;
templateStream.CopyTo(outputStream);
outputStream.Position = 0;
using (var document = WordprocessingDocument.Open(outputStream, true))
{
var body = document.MainDocumentPart?.Document?.Body;
if (body == null) return outputStream;
// 处理段落中的占位符
ProcessParagraphs(body, data, qrCodeData);
// 处理表格中的占位符
ProcessTables(body, data, qrCodeData);
// 处理页眉页脚中的占位符
ProcessHeaderFooter(document, data, qrCodeData);
document.Save();
}
outputStream.Position = 0;
return outputStream;
}
/// <summary>
/// 处理段落中的占位符
/// </summary>
private void ProcessParagraphs(Body body, Dictionary<string, string> data, Dictionary<string, string> qrCodeData)
{
foreach (var paragraph in body.Elements<Paragraph>())
{
ProcessParagraph(paragraph, data, qrCodeData);
}
}
/// <summary>
/// 处理单个段落
/// </summary>
private void ProcessParagraph(Paragraph paragraph, Dictionary<string, string> data, Dictionary<string, string> qrCodeData)
{
var runs = paragraph.Elements<Run>().ToList();
foreach (var run in runs)
{
var texts = run.Elements<Text>().ToList();
foreach (var text in texts)
{
var processedText = ReplacePlaceholders(text.Text, data, qrCodeData);
// 检查是否是二维码占位符
if (IsQRCodePlaceholder(text.Text))
{
var placeholder = ExtractPlaceholderKey(text.Text);
if (qrCodeData != null && qrCodeData.ContainsKey(placeholder))
{
// 替换为二维码图片
ReplaceTextWithQRCode(run, qrCodeData[placeholder]);
}
else
{
text.Text = processedText;
}
}
else
{
text.Text = processedText;
}
}
}
}
/// <summary>
/// 处理表格中的占位符
/// </summary>
private void ProcessTables(Body body, Dictionary<string, string> data, Dictionary<string, string> qrCodeData)
{
foreach (var table in body.Elements<Table>())
{
foreach (var row in table.Elements<TableRow>())
{
foreach (var cell in row.Elements<TableCell>())
{
foreach (var paragraph in cell.Elements<Paragraph>())
{
ProcessParagraph(paragraph, data, qrCodeData);
}
}
}
}
}
/// <summary>
/// 处理页眉页脚中的占位符
/// </summary>
private void ProcessHeaderFooter(WordprocessingDocument document,
Dictionary<string, string> data, Dictionary<string, string> qrCodeData)
{
// 暂时跳过页眉页脚处理,因为API兼容性问题
// 实际项目中需要根据具体的DocumentFormat.OpenXml版本调整
}
/// <summary>
/// 替换文本中的占位符
/// </summary>
private string ReplacePlaceholders(string text, Dictionary<string, string> data, Dictionary<string, string> qrCodeData)
{
if (string.IsNullOrWhiteSpace(text)) return text;
return Regex.Replace(text, PlaceholderPattern, match =>
{
var key = match.Groups[1].Value.Trim();
// 优先使用二维码数据
if (qrCodeData != null && qrCodeData.ContainsKey(key))
{
return qrCodeData[key];
}
// 使用普通数据
if (data != null && data.ContainsKey(key))
{
return data[key] ?? string.Empty;
}
// 返回原始占位符(未找到数据)
return match.Value;
});
}
/// <summary>
/// 检查是否是二维码占位符
/// </summary>
private bool IsQRCodePlaceholder(string text)
{
if (string.IsNullOrWhiteSpace(text)) return false;
var match = Regex.Match(text, PlaceholderPattern);
if (!match.Success) return false;
var key = match.Groups[1].Value.Trim().ToLowerInvariant();
return key.Contains("qr") || key.Contains("qrcode");
}
/// <summary>
/// 提取占位符键名
/// </summary>
private string ExtractPlaceholderKey(string text)
{
var match = Regex.Match(text, PlaceholderPattern);
return match.Success ? match.Groups[1].Value.Trim() : string.Empty;
}
/// <summary>
/// 将文本替换为二维码图片
/// </summary>
private void ReplaceTextWithQRCode(Run run, string qrCodeContent)
{
// 注意:这里需要实现二维码图片生成和插入逻辑
// 由于DocumentFormat.OpenXml处理图片比较复杂,这里先简化处理
// 实际实现需要使用QRCodeService生成图片,然后插入到文档中
// 临时实现:用文本替代
var texts = run.Elements<Text>().ToList();
foreach (var text in texts)
{
text.Text = $"[QR: {qrCodeContent}]";
}
}
/// <summary>
/// 验证数据完整性
/// </summary>
/// <param name="requiredPlaceholders">必填占位符列表</param>
/// <param name="data">数据字典</param>
/// <returns>验证结果</returns>
public TemplateValidationResult ValidateTemplateData(List<string> requiredPlaceholders, Dictionary<string, string> data)
{
var result = new TemplateValidationResult { IsValid = true };
foreach (var placeholder in requiredPlaceholders)
{
if (!data.ContainsKey(placeholder) || string.IsNullOrWhiteSpace(data[placeholder]))
{
result.IsValid = false;
result.MissingPlaceholders.Add(placeholder);
}
}
return result;
}
}
/// <summary>
/// 模板验证结果
/// </summary>
public class TemplateValidationResult
{
public bool IsValid { get; set; }
public List<string> MissingPlaceholders { get; set; } = new List<string>();
public List<string> Warnings { get; set; } = new List<string>();
}
}