This commit is contained in:
fuenmao
2026-08-26 18:17:58 +08:00
parent db3d58bc99
commit 9741481a62
8 changed files with 117 additions and 14 deletions
+2 -1
View File
@@ -8,6 +8,7 @@
</PropertyGroup>
<PropertyGroup>
<DocumentationFile>$(MSBuildProjectName).xml</DocumentationFile>
<!-- 由 SDK 按目标框架输出 XML,避免 net6/net7/net8 并行编译时共同写入项目根目录的同名文件。 -->
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
</Project>
@@ -61,14 +61,16 @@ public class OnboardingContractDocumentService : IOnboardingContractDocumentServ
item => item.VariableCode,
item => item.VariableValue ?? string.Empty,
StringComparer.OrdinalIgnoreCase));
var name = $"{task.TaskNo}_{contract.ContractName}.docx";
var generatedAt = DateTime.Now;
// 在文件名中加入生成批次,避免手机系统把同名的新合同误认为历史下载文件。
var name = $"{task.TaskNo}_{contract.ContractName}_{generatedAt:yyyyMMddHHmmssfff}.docx";
var fileId = await _fileService.StoreGeneratedFile(
SysDictConst.FILE_ENGINE_ALIYUN_OSS,
name,
rendered);
contract.GeneratedDocxFileId = fileId;
contract.GeneratedAt = DateTime.Now;
contract.GeneratedAt = generatedAt;
contract.ContractStatus = task.TaskStatus == OnboardingTaskStatus.Approved
? TaskContractStatus.OfflinePendingSign
: TaskContractStatus.PendingConfirm;
@@ -14,7 +14,13 @@ public interface IOnboardingPublicTaskService : ITransient
/// </summary>
Task SaveEmployeeInfo(OnboardingTaskPublicSaveInput input);
/// <summary>
/// 校验任务归属后返回合同模板源文件 Id。
/// 校验合同变量并提前生成候选人的合同 DOCX。
/// </summary>
Task<OnboardingPublicContractPrepareOutput> PrepareContract(
OnboardingPublicContractSourceInput input);
/// <summary>
/// 校验任务归属后返回已经准备完成的合同文件 Id。
/// </summary>
Task<long> GetContractSourceFileId(OnboardingPublicContractSourceInput input);
@@ -162,25 +162,71 @@ public class OnboardingPublicTaskService : IOnboardingPublicTaskService
}
/// <summary>
/// 根据员工当前已填写信息生成合同预览,并返回已替换变量的 DOCX 文件 Id。
/// 根据员工当前已填写信息校验变量并提前生成合同 DOCX。
/// </summary>
public async Task<long> GetContractSourceFileId(OnboardingPublicContractSourceInput input)
public async Task<OnboardingPublicContractPrepareOutput> PrepareContract(
OnboardingPublicContractSourceInput input)
{
var link = await GetActiveLink(input.Token);
var contract = await _db.Queryable<ObTaskContract>()
.FirstAsync(item => item.Id == input.TaskContractId && item.TaskId == link.TaskId)
?? throw Oops.Bah("合同不存在");
// 员工资料保存时会清除旧文件 Id;仍有文件 Id 时还需确认文件记录没有被异常删除。
if (contract.GeneratedDocxFileId.HasValue)
{
var generatedFileExists = await _db.Queryable<SysFile>()
.AnyAsync(item => item.Id == contract.GeneratedDocxFileId.Value);
if (!generatedFileExists)
throw Oops.Bah("已生成的合同文件不存在,请联系管理员重新生成");
return new OnboardingPublicContractPrepareOutput
{
FileId = contract.GeneratedDocxFileId.Value,
GeneratedAt = contract.GeneratedAt
};
}
await _snapshotService.Build(link.TaskId);
var fileId = await _contractDocumentService.Generate(new OnboardingGenerateContractInput
{
TaskContractId = contract.Id
});
var generatedAt = await _db.Queryable<ObTaskContract>()
.Where(item => item.Id == contract.Id)
.Select(item => item.GeneratedAt)
.SingleAsync();
return new OnboardingPublicContractPrepareOutput
{
FileId = fileId,
GeneratedAt = generatedAt
};
}
/// <summary>
/// 返回已经准备完成的合同文件,下载阶段不再执行变量校验和文档生成。
/// </summary>
public async Task<long> GetContractSourceFileId(OnboardingPublicContractSourceInput input)
{
var link = await GetActiveLink(input.Token);
var contract = await _db.Queryable<ObTaskContract>()
.FirstAsync(item => item.Id == input.TaskContractId && item.TaskId == link.TaskId)
?? throw Oops.Bah("合同不存在");
var fileId = contract.GeneratedDocxFileId
?? throw Oops.Bah("合同尚未准备完成,请刷新页面后重试");
var fileExists = await _db.Queryable<SysFile>()
.AnyAsync(item => item.Id == fileId);
if (!fileExists)
throw Oops.Bah("合同文件不存在,请重新准备合同");
contract.ReadAt ??= DateTime.Now;
if (contract.ContractStatus == TaskContractStatus.PendingGenerate)
contract.ContractStatus = TaskContractStatus.PendingConfirm;
await _db.Updateable(contract).ExecuteCommandAsync();
await _db.Updateable(contract)
.UpdateColumns(item => new { item.ReadAt, item.ContractStatus })
.ExecuteCommandAsync();
return fileId;
}
@@ -28,6 +28,27 @@ public class OnboardingPublicContractSourceInput
/// </summary>
[IdNotNull(ErrorMessage = "任务合同Id不能为空")]
public long TaskContractId { get; set; }
/// <summary>
/// 当前生成文件的版本标识,仅用于区分手机下载缓存,不参与文件权限判断。
/// </summary>
public long? Version { get; set; }
}
/// <summary>
/// 员工端合同准备结果。
/// </summary>
public class OnboardingPublicContractPrepareOutput
{
/// <summary>
/// 当前已经生成并可下载的系统文件 Id,同时作为客户端下载版本号。
/// </summary>
public long FileId { get; set; }
/// <summary>
/// 合同文件生成时间;复用现有文件时返回原生成时间。
/// </summary>
public DateTime? GeneratedAt { get; set; }
}
/// <summary>
@@ -3182,9 +3182,14 @@
保存候选人固定基础信息并刷新合同变量快照。
</summary>
</member>
<member name="M:SimpleAdmin.Application.IOnboardingPublicTaskService.PrepareContract(SimpleAdmin.Application.OnboardingPublicContractSourceInput)">
<summary>
校验合同变量并提前生成候选人的合同 DOCX。
</summary>
</member>
<member name="M:SimpleAdmin.Application.IOnboardingPublicTaskService.GetContractSourceFileId(SimpleAdmin.Application.OnboardingPublicContractSourceInput)">
<summary>
校验任务归属后返回合同模板源文件 Id。
校验任务归属后返回已经准备完成的合同文件 Id。
</summary>
</member>
<member name="M:SimpleAdmin.Application.IOnboardingPublicTaskService.GetMaterialSource(SimpleAdmin.Application.OnboardingPublicMaterialSourceInput)">
@@ -3207,9 +3212,14 @@
保存候选人的固定基础信息并刷新尚未确认的合同变量快照。
</summary>
</member>
<member name="M:SimpleAdmin.Application.OnboardingPublicTaskService.PrepareContract(SimpleAdmin.Application.OnboardingPublicContractSourceInput)">
<summary>
根据员工当前已填写信息校验变量并提前生成合同 DOCX。
</summary>
</member>
<member name="M:SimpleAdmin.Application.OnboardingPublicTaskService.GetContractSourceFileId(SimpleAdmin.Application.OnboardingPublicContractSourceInput)">
<summary>
根据员工当前已填写信息生成合同预览,并返回已替换变量的 DOCX 文件 Id。
返回已经准备完成的合同文件,下载阶段不再执行变量校验和文档生成。
</summary>
</member>
<member name="M:SimpleAdmin.Application.OnboardingPublicTaskService.GetMaterialSource(SimpleAdmin.Application.OnboardingPublicMaterialSourceInput)">
@@ -36,13 +36,25 @@ public class OnboardingPublicTaskController
}
/// <summary>
/// 下载根据当前任务资料动态生成并已替换变量的合同文件。
/// 校验合同变量并提前生成候选人的合同文件。
/// </summary>
[HttpPost("prepare-contract")]
public async Task<OnboardingPublicContractPrepareOutput> PrepareContract(
[FromBody] OnboardingPublicContractSourceInput input)
{
return await _service.PrepareContract(input);
}
/// <summary>
/// 下载已经准备完成并替换变量的合同文件。
/// </summary>
[HttpGet("contract-source")]
[ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
public async Task<FileStreamResult> ContractSource([FromQuery] OnboardingPublicContractSourceInput input)
{
var fileId = await _service.GetContractSourceFileId(input);
return await _fileService.Download(new BaseIdInput { Id = fileId });
return await _fileService.Download(new BaseIdInput { Id = fileId })
?? throw Oops.Bah("合同文件不存在,请重新准备合同");
}
/// <summary>
@@ -296,9 +296,14 @@
保存候选人固定基础信息。
</summary>
</member>
<member name="M:SimpleAdmin.Web.Core.OnboardingPublicTaskController.PrepareContract(SimpleAdmin.Application.OnboardingPublicContractSourceInput)">
<summary>
校验合同变量并提前生成候选人的合同文件。
</summary>
</member>
<member name="M:SimpleAdmin.Web.Core.OnboardingPublicTaskController.ContractSource(SimpleAdmin.Application.OnboardingPublicContractSourceInput)">
<summary>
下载根据当前任务资料动态生成并已替换变量的合同文件。
下载已经准备完成并替换变量的合同文件。
</summary>
</member>
<member name="M:SimpleAdmin.Web.Core.OnboardingPublicTaskController.MaterialSource(SimpleAdmin.Application.OnboardingPublicMaterialSourceInput)">