修复文件模版占位符错误问题
This commit is contained in:
@@ -35,6 +35,7 @@ public static class DocxTemplateProcessor
|
|||||||
foreach (var paragraph in document.Descendants(WordNamespace + "p"))
|
foreach (var paragraph in document.Descendants(WordNamespace + "p"))
|
||||||
{
|
{
|
||||||
var text = string.Concat(paragraph.Descendants(WordNamespace + "t").Select(node => node.Value));
|
var text = string.Concat(paragraph.Descendants(WordNamespace + "t").Select(node => node.Value));
|
||||||
|
ValidatePlaceholderSyntax(text);
|
||||||
foreach (global::System.Text.RegularExpressions.Match match in PlaceholderRegex.Matches(text))
|
foreach (global::System.Text.RegularExpressions.Match match in PlaceholderRegex.Matches(text))
|
||||||
codes.Add(match.Groups["code"].Value.Trim());
|
codes.Add(match.Groups["code"].Value.Trim());
|
||||||
}
|
}
|
||||||
@@ -52,6 +53,72 @@ public static class DocxTemplateProcessor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 占位符提取正则只会匹配正确格式,因此必须先主动检查错误格式,
|
||||||
|
/// 避免缺少花括号或变量编码写错时被静默忽略并继续创建版本。
|
||||||
|
/// </summary>
|
||||||
|
private static void ValidatePlaceholderSyntax(string text)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(text))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (text.Contains("{{", StringComparison.Ordinal)
|
||||||
|
|| text.Contains("}}", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
throw Oops.Bah(
|
||||||
|
"DOCX 占位符格式错误:检测到中文全角花括号。请使用英文半角双花括号,例如 {{employee.EmployeeName}}。");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text.Contains("{{{", StringComparison.Ordinal)
|
||||||
|
|| text.Contains("}}}", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
throw Oops.Bah(
|
||||||
|
"DOCX 占位符格式错误:检测到多余的花括号。占位符必须使用成对的英文半角双花括号,例如 {{employee.EmployeeName}}。");
|
||||||
|
}
|
||||||
|
|
||||||
|
var searchStart = 0;
|
||||||
|
while (searchStart < text.Length)
|
||||||
|
{
|
||||||
|
var openIndex = text.IndexOf("{{", searchStart, StringComparison.Ordinal);
|
||||||
|
var closeIndex = text.IndexOf("}}", searchStart, StringComparison.Ordinal);
|
||||||
|
|
||||||
|
if (closeIndex >= 0 && (openIndex < 0 || closeIndex < openIndex))
|
||||||
|
{
|
||||||
|
throw Oops.Bah(
|
||||||
|
$"DOCX 占位符格式错误:{BuildPlaceholderPreview(text, closeIndex)} 缺少对应的起始符“{{{{”。正确格式示例:{{{{employee.EmployeeName}}}}。");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (openIndex < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
closeIndex = text.IndexOf("}}", openIndex + 2, StringComparison.Ordinal);
|
||||||
|
if (closeIndex < 0)
|
||||||
|
{
|
||||||
|
throw Oops.Bah(
|
||||||
|
$"DOCX 占位符格式错误:{BuildPlaceholderPreview(text, openIndex)} 缺少结束符“}}}}”。正确格式示例:{{{{employee.EmployeeName}}}}。");
|
||||||
|
}
|
||||||
|
|
||||||
|
var placeholder = text.Substring(openIndex, closeIndex + 2 - openIndex);
|
||||||
|
var match = PlaceholderRegex.Match(placeholder);
|
||||||
|
if (!match.Success || match.Length != placeholder.Length)
|
||||||
|
{
|
||||||
|
throw Oops.Bah(
|
||||||
|
$"DOCX 占位符格式错误:“{placeholder}”。变量编码只能包含英文字母、数字、下划线、点和短横线,并且必须使用成对的英文半角双花括号。");
|
||||||
|
}
|
||||||
|
|
||||||
|
searchStart = closeIndex + 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string BuildPlaceholderPreview(string text, int markerIndex)
|
||||||
|
{
|
||||||
|
const int maxLength = 60;
|
||||||
|
var preview = text[markerIndex..].Trim();
|
||||||
|
if (preview.Length > maxLength)
|
||||||
|
preview = preview[..maxLength] + "…";
|
||||||
|
return $"“{preview}”";
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 使用任务变量快照替换 DOCX 中的占位符,支持占位符跨多个 Word 文本节点。
|
/// 使用任务变量快照替换 DOCX 中的占位符,支持占位符跨多个 Word 文本节点。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
+5
@@ -37,6 +37,11 @@ public class OnboardingContractTemplateController
|
|||||||
if (!string.Equals(suffix, ".docx", StringComparison.OrdinalIgnoreCase))
|
if (!string.Equals(suffix, ".docx", StringComparison.OrdinalIgnoreCase))
|
||||||
throw Oops.Bah("合同模板仅支持 DOCX 文件");
|
throw Oops.Bah("合同模板仅支持 DOCX 文件");
|
||||||
|
|
||||||
|
await using var input = file.OpenReadStream();
|
||||||
|
using var bytes = new MemoryStream();
|
||||||
|
await input.CopyToAsync(bytes);
|
||||||
|
DocxTemplateProcessor.ExtractVariableCodes(bytes.ToArray());
|
||||||
|
|
||||||
return await _fileService.UploadFile(SysDictConst.FILE_ENGINE_ALIYUN_OSS, file);
|
return await _fileService.UploadFile(SysDictConst.FILE_ENGINE_ALIYUN_OSS, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user