完善第三方签署

This commit is contained in:
fuenmao
2026-09-08 17:48:30 +08:00
parent da777327f5
commit c015bc356c
22 changed files with 961 additions and 62 deletions
@@ -17,25 +17,39 @@ public static class DocxTemplateProcessor
/// </summary>
public static List<string> ExtractVariableCodes(byte[] docx)
{
using var input = new MemoryStream(docx);
using var archive = new global::System.IO.Compression.ZipArchive(
input,
global::System.IO.Compression.ZipArchiveMode.Read);
var codes = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var entry in archive.Entries.Where(entry => IsWordTextXml(entry.FullName)))
ValidateDocxHeader(docx);
try
{
using var stream = entry.Open();
var document = global::System.Xml.Linq.XDocument.Load(stream);
foreach (var paragraph in document.Descendants(WordNamespace + "p"))
{
var text = string.Concat(paragraph.Descendants(WordNamespace + "t").Select(node => node.Value));
foreach (global::System.Text.RegularExpressions.Match match in PlaceholderRegex.Matches(text))
codes.Add(match.Groups["code"].Value.Trim());
}
}
using var input = new MemoryStream(docx);
using var archive = new global::System.IO.Compression.ZipArchive(
input,
global::System.IO.Compression.ZipArchiveMode.Read);
if (archive.GetEntry("word/document.xml") == null)
throw Oops.Bah("上传文件不是有效的 DOCX 文档,请使用 Word 或 WPS 另存为“Word 文档(*.docx)”后重新上传");
return codes.OrderBy(code => code).ToList();
var codes = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var entry in archive.Entries.Where(entry => IsWordTextXml(entry.FullName)))
{
using var stream = entry.Open();
var document = global::System.Xml.Linq.XDocument.Load(stream);
foreach (var paragraph in document.Descendants(WordNamespace + "p"))
{
var text = string.Concat(paragraph.Descendants(WordNamespace + "t").Select(node => node.Value));
foreach (global::System.Text.RegularExpressions.Match match in PlaceholderRegex.Matches(text))
codes.Add(match.Groups["code"].Value.Trim());
}
}
return codes.OrderBy(code => code).ToList();
}
catch (global::System.IO.InvalidDataException)
{
throw Oops.Bah("DOCX 文件结构已经损坏或上传不完整,请重新另存为 DOCX 后上传");
}
catch (global::System.Xml.XmlException)
{
throw Oops.Bah("DOCX 文件内部内容损坏,Word 可以尝试修复该文件;请修复并重新另存为 DOCX 后上传");
}
}
/// <summary>
@@ -43,6 +57,7 @@ public static class DocxTemplateProcessor
/// </summary>
public static byte[] Render(byte[] docx, IReadOnlyDictionary<string, string> values)
{
ValidateDocxHeader(docx);
using var input = new MemoryStream(docx);
using var archive = new global::System.IO.Compression.ZipArchive(
input,
@@ -157,4 +172,26 @@ public static class DocxTemplateProcessor
|| entryName.StartsWith("word/footer", StringComparison.OrdinalIgnoreCase))
&& entryName.EndsWith(".xml", StringComparison.OrdinalIgnoreCase));
}
}
/// <summary>
/// 根据文件头识别真实格式,避免只修改扩展名的旧版 DOC 在解压时变成系统异常。
/// </summary>
private static void ValidateDocxHeader(byte[] docx)
{
if (docx == null || docx.Length < 4)
throw Oops.Bah("上传的 DOCX 文件为空或上传不完整,请重新选择文件上传");
// 旧版 Word 97-2003 二进制 DOC 使用 OLE Compound File 文件头:D0 CF 11 E0。
if (docx[0] == 0xD0
&& docx[1] == 0xCF
&& docx[2] == 0x11
&& docx[3] == 0xE0)
{
throw Oops.Bah("上传文件实际是旧版 DOC 格式,不能直接修改后缀名;请使用 Word 或 WPS 另存为“Word 文档(*.docx)”后重新上传");
}
// DOCX 是 Open XML ZIP 包,正常文件以 PK 开头。
if (docx[0] != 0x50 || docx[1] != 0x4B)
throw Oops.Bah("上传文件的真实格式不是 DOCX,请使用 Word 或 WPS 另存为“Word 文档(*.docx)”后重新上传");
}
}
@@ -37,6 +37,7 @@ public class OnboardingContractTemplateService : DbRepository<ObContractTemplate
var page = await query
.OrderByIF(!string.IsNullOrWhiteSpace(input.SortField), $"{input.SortField} {input.SortOrder}")
.OrderByDescending(it => it.CreateTime)
.OrderBy(it => it.TemplateName)
.ToPagedListAsync(input.PageNum, input.PageSize);
await PopulateScopeDisplay(page.List.ToList());