Files
OnboardXAdmin/SimpleAdmin.Application/Services/Onboarding/Task/OnboardingTaskService.cs
T
2026-08-24 15:04:15 +08:00

129 lines
4.9 KiB
C#

namespace SimpleAdmin.Application;
public class OnboardingTaskService : IOnboardingTaskService
{
private readonly SqlSugarScope _db;
private readonly IConfigService _configService;
private readonly IOnboardingContractSnapshotService _snapshotService;
public OnboardingTaskService(
IConfigService configService,
IOnboardingContractSnapshotService snapshotService)
{
_db = DbContext.DB;
_configService = configService;
_snapshotService = snapshotService;
}
public async Task<OnboardingTaskCreatedOutput> Create(OnboardingTaskCreateInput input)
{
var companyEnabled = await _db.Queryable<ObCompany>()
.AnyAsync(item => item.Id == input.CompanyId && item.Status == "enable");
if (!companyEnabled)
{
throw Oops.Bah("公司不存在或未启用");
}
var positionEnabled = await _db.Queryable<ObPosition>()
.AnyAsync(item => item.Id == input.PositionId
&& item.CompanyId == input.CompanyId
&& item.Status == "enable");
if (!positionEnabled)
{
throw Oops.Bah("岗位不存在、未启用或不属于该公司");
}
var scopes = await _db.Queryable<ObContractScope>()
.Where(item => item.CompanyId == input.CompanyId
&& (item.PositionId == null || item.PositionId == input.PositionId))
.ToListAsync();
// 同一版本同时存在“全公司”和“指定岗位”范围时,岗位专属配置优先,避免同一合同生成两次。
scopes = scopes
.GroupBy(item => item.TemplateVersionId)
.Select(group => group.FirstOrDefault(item => item.PositionId == input.PositionId) ?? group.First())
.ToList();
if (scopes.Count == 0)
{
throw Oops.Bah("该公司和岗位尚未配置合同适用范围");
}
var taskId = global::SimpleAdmin.Core.Utils.CommonUtils.GetSingleId();
var expiryConfig = await _configService.GetByConfigKey(
CateGoryConst.CONFIG_BIZ_DEFINE,
"onboard.link.expireHours");
if (expiryConfig == null
|| !int.TryParse(expiryConfig.ConfigValue, out var expiryHours)
|| expiryHours <= 0)
{
throw Oops.Bah("请在系统配置中设置 onboard.link.expireHours(正整数小时)");
}
var expiresAt = DateTime.Now.AddHours(expiryHours);
var token = Guid.NewGuid().ToString("N");
var task = new ObOnboardingTask
{
Id = taskId,
TaskNo = $"OB{DateTime.Now:yyyyMMddHHmmss}{taskId.ToString()[^4..]}",
CompanyId = input.CompanyId,
PositionId = input.PositionId,
AssignedReviewerUserId = input.AssignedReviewerUserId,
LinkExpireAt = expiresAt,
TaskStatus = OnboardingTaskStatus.PendingFill,
Remark = input.Remark
};
await _db.Ado.BeginTranAsync();
try
{
await _db.Insertable(task).ExecuteCommandAsync();
await _db.Insertable(new ObTaskLink
{
Id = global::SimpleAdmin.Core.Utils.CommonUtils.GetSingleId(),
TaskId = taskId,
TokenHash = Convert.ToHexString(global::System.Security.Cryptography.SHA256.HashData(
global::System.Text.Encoding.UTF8.GetBytes(token))),
ExpiresAt = expiresAt
}).ExecuteCommandAsync();
var templateIds = scopes.Select(item => item.TemplateId).Distinct().ToList();
var templates = await _db.Queryable<ObContractTemplate>()
.Where(item => templateIds.Contains(item.Id))
.ToListAsync();
var contracts = scopes.Select(scope =>
{
var template = templates.First(item => item.Id == scope.TemplateId);
return new ObTaskContract
{
Id = global::SimpleAdmin.Core.Utils.CommonUtils.GetSingleId(),
TaskId = taskId,
TemplateId = scope.TemplateId,
TemplateVersionId = scope.TemplateVersionId,
ContractName = template.TemplateName,
ContractType = template.ContractType,
Required = scope.Required
};
}).ToList();
await _db.Insertable(contracts).ExecuteCommandAsync();
await _snapshotService.Build(taskId);
await _db.Ado.CommitTranAsync();
}
catch
{
await _db.Ado.RollbackTranAsync();
throw;
}
return new OnboardingTaskCreatedOutput
{
TaskId = taskId,
TaskNo = task.TaskNo,
LinkToken = token,
ExpiresAt = expiresAt
};
}
}