代码优化

This commit is contained in:
fuenmao
2026-08-27 11:09:20 +08:00
parent 658869b3a7
commit ae8167a566
46 changed files with 2051 additions and 204 deletions
@@ -17,15 +17,30 @@ public class OnboardingContractTemplateService : DbRepository<ObContractTemplate
/// </summary>
public async Task<SqlSugarPagedList<ObContractTemplate>> Page(OnboardingContractTemplatePageInput input)
{
return await Context.Queryable<ObContractTemplate>()
var query = Context.Queryable<ObContractTemplate>()
.WhereIF(input.CompanyId.HasValue, item => item.CompanyId == input.CompanyId.Value)
.WhereIF(input.DepartmentId.HasValue, item => item.DepartmentId == input.DepartmentId.Value)
.WhereIF(
!string.IsNullOrWhiteSpace(input.TemplateName),
it => it.TemplateName.Contains(input.TemplateName) || it.TemplateCode.Contains(input.TemplateName))
.WhereIF(!string.IsNullOrWhiteSpace(input.ContractType), it => it.ContractType == input.ContractType)
.WhereIF(!string.IsNullOrWhiteSpace(input.Status), it => it.Status == input.Status)
.WhereIF(!string.IsNullOrWhiteSpace(input.Status), it => it.Status == input.Status);
if (input.PositionId.HasValue)
{
var templateIds = await Context.Queryable<ObContractTemplatePosition>()
.Where(item => item.PositionId == input.PositionId.Value)
.Select(item => item.ContractTemplateId)
.ToListAsync();
query = query.Where(item => templateIds.Contains(item.Id));
}
var page = await query
.OrderByIF(!string.IsNullOrWhiteSpace(input.SortField), $"{input.SortField} {input.SortOrder}")
.OrderBy(it => it.TemplateName)
.ToPagedListAsync(input.PageNum, input.PageSize);
await PopulateScopeDisplay(page.List.ToList());
return page;
}
/// <summary>
@@ -33,7 +48,47 @@ public class OnboardingContractTemplateService : DbRepository<ObContractTemplate
/// </summary>
public async Task<ObContractTemplate> Detail(BaseIdInput input)
{
return await GetByIdAsync(input.Id) ?? throw Oops.Bah("合同模板不存在");
var template = await GetByIdAsync(input.Id) ?? throw Oops.Bah("合同模板不存在");
await PopulateScopeDisplay(new List<ObContractTemplate> { template });
return template;
}
/// <summary>
/// 查询同时覆盖全部已选岗位的启用合同模板。
/// </summary>
public async Task<List<ObContractTemplate>> ListAvailable(
OnboardingContractTemplateAvailableInput input)
{
input.PositionIds = input.PositionIds?.Distinct().ToList() ?? new List<long>();
if (input.PositionIds.Count == 0)
return new List<ObContractTemplate>();
await ValidateBusinessScope(input.CompanyId, input.DepartmentId, input.PositionIds);
var candidates = await Context.Queryable<ObContractTemplate>()
.Where(item => item.CompanyId == input.CompanyId
&& item.DepartmentId == input.DepartmentId
&& item.Status == "enable")
.OrderBy(item => item.TemplateName)
.ToListAsync();
if (candidates.Count == 0)
return candidates;
var candidateIds = candidates.Select(item => item.Id).ToList();
var relations = await Context.Queryable<ObContractTemplatePosition>()
.Where(item => candidateIds.Contains(item.ContractTemplateId))
.ToListAsync();
var availableIds = relations
.GroupBy(item => item.ContractTemplateId)
.Where(group => input.PositionIds.All(positionId =>
group.Any(item => item.PositionId == positionId)))
.Select(group => group.Key)
.ToHashSet();
var availableTemplates = candidates
.Where(item => availableIds.Contains(item.Id))
.ToList();
await PopulateScopeDisplay(availableTemplates);
return availableTemplates;
}
/// <summary>
@@ -41,8 +96,24 @@ public class OnboardingContractTemplateService : DbRepository<ObContractTemplate
/// </summary>
public async Task Add(OnboardingContractTemplateAddInput input)
{
NormalizeInput(input);
await ValidateBusinessScope(input.CompanyId, input.DepartmentId, input.PositionIds);
await EnsureCodeUnique(input.TemplateCode, 0);
await InsertAsync(input.Adapt<ObContractTemplate>());
var templateId = global::SimpleAdmin.Core.Utils.CommonUtils.GetSingleId();
var entity = BuildEntity(templateId, input);
await Context.Ado.BeginTranAsync();
try
{
await Context.Insertable(entity).ExecuteCommandAsync();
await InsertPositionRelations(templateId, input.PositionIds);
await Context.Ado.CommitTranAsync();
}
catch
{
await Context.Ado.RollbackTranAsync();
throw;
}
}
/// <summary>
@@ -51,8 +122,29 @@ public class OnboardingContractTemplateService : DbRepository<ObContractTemplate
public async Task Edit(OnboardingContractTemplateEditInput input)
{
await Detail(new BaseIdInput { Id = input.Id });
NormalizeInput(input);
await ValidateBusinessScope(input.CompanyId, input.DepartmentId, input.PositionIds);
await ValidateReferencedOnboardingTemplates(input);
await EnsureCodeUnique(input.TemplateCode, input.Id);
await UpdateAsync(input.Adapt<ObContractTemplate>());
var entity = BuildEntity(input.Id, input);
await Context.Ado.BeginTranAsync();
try
{
await Context.Updateable(entity)
.IgnoreColumns(ignoreAllNullColumns: true)
.ExecuteCommandAsync();
await Context.Deleteable<ObContractTemplatePosition>()
.Where(item => item.ContractTemplateId == input.Id)
.ExecuteCommandAsync();
await InsertPositionRelations(input.Id, input.PositionIds);
await Context.Ado.CommitTranAsync();
}
catch
{
await Context.Ado.RollbackTranAsync();
throw;
}
}
/// <summary>
@@ -95,6 +187,10 @@ public class OnboardingContractTemplateService : DbRepository<ObContractTemplate
.Where(it => input.Ids.Contains(it.TemplateId))
.ExecuteCommandAsync();
await Context.Deleteable<ObContractTemplatePosition>()
.Where(item => input.Ids.Contains(item.ContractTemplateId))
.ExecuteCommandAsync();
await DeleteByIdsAsync(input.Ids.Cast<object>().ToArray());
await Context.Ado.CommitTranAsync();
}
@@ -182,6 +278,15 @@ public class OnboardingContractTemplateService : DbRepository<ObContractTemplate
// 严格比对变量字典库,防止手误和非法占位符
var dictList = await Context.Queryable<ObVariableDefinition>().ToListAsync();
var duplicateDefinition = dictList
.GroupBy(item => item.VariableCode, StringComparer.OrdinalIgnoreCase)
.FirstOrDefault(group => group.Count() > 1);
if (duplicateDefinition != null)
{
throw Oops.Bah(
$"变量字典编码“{duplicateDefinition.Key}”存在重复数据,请先清理后再导入合同版本");
}
var dictMap = dictList.ToDictionary(it => it.VariableCode, it => it, StringComparer.OrdinalIgnoreCase);
var undefinedCodes = variableCodes.Where(code => !dictMap.ContainsKey(code)).ToList();
if (undefinedCodes.Count > 0)
@@ -336,4 +441,189 @@ public class OnboardingContractTemplateService : DbRepository<ObContractTemplate
if (exists)
throw Oops.Bah("模板编码已存在");
}
/// <summary>
/// 标准化合同模板保存参数并执行基础业务校验。
/// </summary>
private static void NormalizeInput(OnboardingContractTemplateAddInput input)
{
input.TemplateCode = input.TemplateCode?.Trim();
input.TemplateName = input.TemplateName?.Trim();
input.ContractType = input.ContractType?.Trim();
input.PositionIds = input.PositionIds?.Distinct().ToList() ?? new List<long>();
if (string.IsNullOrWhiteSpace(input.TemplateCode)
|| string.IsNullOrWhiteSpace(input.TemplateName)
|| string.IsNullOrWhiteSpace(input.ContractType))
{
throw Oops.Bah("请填写模板编码、模板名称和合同类型");
}
if (input.PositionIds.Count == 0)
throw Oops.Bah("请至少选择一个适用岗位");
if (input.Status != "enable" && input.Status != "disable")
throw Oops.Bah("合同模板状态不正确");
}
/// <summary>
/// 校验公司、部门、岗位属于同一条启用的业务层级。
/// </summary>
private async Task ValidateBusinessScope(
long companyId,
long departmentId,
List<long> positionIds)
{
var companyEnabled = await Context.Queryable<ObCompany>()
.AnyAsync(item => item.Id == companyId && item.Status == "enable");
if (!companyEnabled)
throw Oops.Bah("所属公司不存在或未启用");
var departmentEnabled = await Context.Queryable<ObDepartment>()
.AnyAsync(item => item.Id == departmentId
&& item.CompanyId == companyId
&& item.Status == "enable");
if (!departmentEnabled)
throw Oops.Bah("所属部门不存在、未启用或不属于该公司");
var positionCount = await Context.Queryable<ObPosition>()
.CountAsync(item => positionIds.Contains(item.Id)
&& item.CompanyId == companyId
&& item.DepartmentId == departmentId
&& item.Status == "enable");
if (positionCount != positionIds.Count)
throw Oops.Bah("存在未启用或不属于该公司、部门的岗位");
}
/// <summary>
/// 防止修改合同模板归属后破坏已经保存的入职模板配置。
/// </summary>
private async Task ValidateReferencedOnboardingTemplates(
OnboardingContractTemplateEditInput input)
{
var relations = await Context.Queryable<ObOnboardingTemplateContract>()
.Where(item => item.ContractTemplateId == input.Id)
.ToListAsync();
if (relations.Count == 0)
return;
var onboardingTemplateIds = relations
.Select(item => item.OnboardingTemplateId)
.Distinct()
.ToList();
var onboardingTemplates = await Context.Queryable<ObOnboardingTemplate>()
.Where(item => onboardingTemplateIds.Contains(item.Id))
.ToListAsync();
var positionRelations = await Context.Queryable<ObOnboardingTemplatePosition>()
.Where(item => onboardingTemplateIds.Contains(item.OnboardingTemplateId))
.ToListAsync();
foreach (var template in onboardingTemplates)
{
var positionIds = positionRelations
.Where(item => item.OnboardingTemplateId == template.Id)
.Select(item => item.PositionId)
.Distinct()
.ToList();
var departmentMatches = !template.DepartmentId.HasValue
|| template.DepartmentId.Value == input.DepartmentId;
var scopeMatches = template.CompanyId == input.CompanyId
&& departmentMatches
&& positionIds.All(input.PositionIds.Contains);
if (!scopeMatches)
{
throw Oops.Bah(
$"合同模板仍被入职模板“{template.TemplateName}”引用,当前归属调整会使其失效,请先调整入职模板");
}
}
}
/// <summary>
/// 构建合同模板主档案实体。
/// </summary>
private static ObContractTemplate BuildEntity(
long templateId,
OnboardingContractTemplateAddInput input)
{
return new ObContractTemplate
{
Id = templateId,
CompanyId = input.CompanyId,
DepartmentId = input.DepartmentId,
TemplateCode = input.TemplateCode,
TemplateName = input.TemplateName,
ContractType = input.ContractType,
Description = input.Description,
Status = input.Status
};
}
/// <summary>
/// 保存合同模板适用岗位关系。
/// </summary>
private async Task InsertPositionRelations(long templateId, List<long> positionIds)
{
var relations = positionIds.Select(positionId => new ObContractTemplatePosition
{
Id = global::SimpleAdmin.Core.Utils.CommonUtils.GetSingleId(),
ContractTemplateId = templateId,
PositionId = positionId
}).ToList();
await Context.Insertable(relations).ExecuteCommandAsync();
}
/// <summary>
/// 回填合同模板的公司、部门和适用岗位展示信息。
/// </summary>
private async Task PopulateScopeDisplay(List<ObContractTemplate> templates)
{
if (templates.Count == 0)
return;
var templateIds = templates.Select(item => item.Id).ToList();
var companyIds = templates
.Where(item => item.CompanyId.HasValue)
.Select(item => item.CompanyId.Value)
.Distinct()
.ToList();
var departmentIds = templates
.Where(item => item.DepartmentId.HasValue)
.Select(item => item.DepartmentId.Value)
.Distinct()
.ToList();
var companies = companyIds.Count == 0
? new List<ObCompany>()
: await Context.Queryable<ObCompany>()
.Where(item => companyIds.Contains(item.Id))
.ToListAsync();
var departments = departmentIds.Count == 0
? new List<ObDepartment>()
: await Context.Queryable<ObDepartment>()
.Where(item => departmentIds.Contains(item.Id))
.ToListAsync();
var relations = await Context.Queryable<ObContractTemplatePosition>()
.Where(item => templateIds.Contains(item.ContractTemplateId))
.ToListAsync();
var positionIds = relations.Select(item => item.PositionId).Distinct().ToList();
var positions = positionIds.Count == 0
? new List<ObPosition>()
: await Context.Queryable<ObPosition>()
.Where(item => positionIds.Contains(item.Id))
.ToListAsync();
foreach (var template in templates)
{
template.CompanyName = companies
.FirstOrDefault(item => item.Id == template.CompanyId)?.CompanyName;
template.DepartmentName = departments
.FirstOrDefault(item => item.Id == template.DepartmentId)?.DepartmentName;
template.PositionIds = relations
.Where(item => item.ContractTemplateId == template.Id)
.Select(item => item.PositionId)
.ToList();
template.PositionNames = template.PositionIds
.Select(positionId => positions.FirstOrDefault(item => item.Id == positionId)?.PositionName)
.Where(name => !string.IsNullOrWhiteSpace(name))
.ToList();
}
}
}