98 lines
4.1 KiB
C#
98 lines
4.1 KiB
C#
namespace SimpleAdmin.Application;
|
|
|
|
public class OnboardingContractDocumentService : IOnboardingContractDocumentService
|
|
{
|
|
private readonly ISqlSugarClient _db;
|
|
private readonly IFileService _fileService;
|
|
|
|
public OnboardingContractDocumentService(ISqlSugarClient db, IFileService fileService)
|
|
{
|
|
_db = db;
|
|
_fileService = fileService;
|
|
}
|
|
|
|
public async Task<long> Generate(OnboardingGenerateContractInput input)
|
|
{
|
|
var contract = await _db.Queryable<ObTaskContract>().InSingleAsync(input.TaskContractId)
|
|
?? throw Oops.Bah("任务合同不存在");
|
|
var task = await _db.Queryable<ObOnboardingTask>().InSingleAsync(contract.TaskId)
|
|
?? throw Oops.Bah("入职任务不存在");
|
|
|
|
if (task.TaskStatus != OnboardingTaskStatus.Approved)
|
|
throw Oops.Bah("仅审核通过的任务可生成归档合同");
|
|
|
|
if (contract.GeneratedDocxFileId.HasValue)
|
|
return contract.GeneratedDocxFileId.Value;
|
|
|
|
var version = await _db.Queryable<ObContractTemplateVersion>().InSingleAsync(contract.TemplateVersionId)
|
|
?? throw Oops.Bah("合同版本不存在");
|
|
var source = await _db.Queryable<SysFile>().InSingleAsync(version.SourceDocxFileId)
|
|
?? throw Oops.Bah("合同源文件不存在");
|
|
var variables = await _db.Queryable<ObTaskContractVariable>()
|
|
.Where(x => x.TaskContractId == contract.Id)
|
|
.ToListAsync();
|
|
var sourceResult = await _fileService.Download(new BaseIdInput { Id = source.Id })
|
|
?? throw Oops.Bah("无法读取合同源文件");
|
|
|
|
await using var sourceStream = sourceResult.FileStream;
|
|
using var sourceBytes = new MemoryStream();
|
|
await sourceStream.CopyToAsync(sourceBytes);
|
|
|
|
var rendered = ReplaceDocxText(
|
|
sourceBytes.ToArray(),
|
|
variables.ToDictionary(x => x.VariableCode, x => x.VariableValue ?? string.Empty));
|
|
var name = $"{task.TaskNo}_{contract.ContractName}.docx";
|
|
var fileId = await _fileService.StoreGeneratedFile(source.Engine, name, rendered);
|
|
|
|
contract.GeneratedDocxFileId = fileId;
|
|
contract.GeneratedAt = DateTime.Now;
|
|
await _db.Updateable(contract).ExecuteCommandAsync();
|
|
|
|
return fileId;
|
|
}
|
|
|
|
private static byte[] ReplaceDocxText(byte[] docx, Dictionary<string, string> values)
|
|
{
|
|
using var input = new MemoryStream(docx);
|
|
using var archive = new global::System.IO.Compression.ZipArchive(
|
|
input,
|
|
global::System.IO.Compression.ZipArchiveMode.Read);
|
|
using var output = new MemoryStream();
|
|
using var target = new global::System.IO.Compression.ZipArchive(
|
|
output,
|
|
global::System.IO.Compression.ZipArchiveMode.Create,
|
|
true);
|
|
|
|
foreach (var entry in archive.Entries)
|
|
{
|
|
var next = target.CreateEntry(entry.FullName, global::System.IO.Compression.CompressionLevel.Optimal);
|
|
using var reader = entry.Open();
|
|
using var writer = next.Open();
|
|
|
|
var isWordTextXml = entry.FullName == "word/document.xml"
|
|
|| ((entry.FullName.StartsWith("word/header") || entry.FullName.StartsWith("word/footer"))
|
|
&& entry.FullName.EndsWith(".xml"));
|
|
if (!isWordTextXml)
|
|
{
|
|
reader.CopyTo(writer);
|
|
continue;
|
|
}
|
|
|
|
using var textReader = new StreamReader(reader);
|
|
var document = global::System.Xml.Linq.XDocument.Parse(textReader.ReadToEnd());
|
|
var word = global::System.Xml.Linq.XNamespace.Get("http://schemas.openxmlformats.org/wordprocessingml/2006/main");
|
|
|
|
foreach (var node in document.Descendants(word + "t"))
|
|
{
|
|
foreach (var item in values)
|
|
node.Value = node.Value.Replace("{{" + item.Key + "}}", item.Value ?? string.Empty);
|
|
}
|
|
|
|
using var textWriter = new StreamWriter(writer);
|
|
textWriter.Write(document.ToString(global::System.Xml.Linq.SaveOptions.DisableFormatting));
|
|
}
|
|
|
|
return output.ToArray();
|
|
}
|
|
}
|