新增员工统计

This commit is contained in:
fuenmao
2026-09-11 10:38:20 +08:00
parent f858b04701
commit 571db6fc55
3 changed files with 135 additions and 18 deletions
@@ -46,6 +46,58 @@ public class OnboardingEmployeePageInput : BasePageInput
/// 社保状态。
/// </summary>
public string SocialInsuranceStatus { get; set; }
/// <summary>
/// 合同即将到期筛选(30天内到期或已到期)。
/// </summary>
public bool? ContractExpiringSoon { get; set; }
}
/// <summary>
/// 正式员工档案分页数据及当前查询条件下的维度统计。
/// </summary>
public class OnboardingEmployeePageOutput : SqlSugarPagedList<ObEmployee>
{
/// <summary>
/// 不受快捷维度筛选影响的员工维度统计。
/// </summary>
public OnboardingEmployeeStatisticsOutput Statistics { get; set; } = new();
}
/// <summary>
/// 正式员工档案维度统计。
/// </summary>
public class OnboardingEmployeeStatisticsOutput
{
/// <summary>
/// 在册总数。
/// </summary>
public int Total { get; set; }
/// <summary>
/// 正式员工数量。
/// </summary>
public int FullTime { get; set; }
/// <summary>
/// 兼职员工数量。
/// </summary>
public int PartTime { get; set; }
/// <summary>
/// 试用期待转正数量。
/// </summary>
public int Probation { get; set; }
/// <summary>
/// 社保已缴纳数量。
/// </summary>
public int SocialPurchased { get; set; }
/// <summary>
/// 合同即将到期数量(30天内到期或已到期)。
/// </summary>
public int ExpiringContract { get; set; }
}
/// <summary>
@@ -6,9 +6,9 @@ namespace SimpleAdmin.Application;
public interface IOnboardingEmployeeService : ITransient
{
/// <summary>
/// 分页查询审核通过后生成的正式员工档案。
/// 分页查询审核通过后生成的正式员工档案及维度统计。
/// </summary>
Task<SqlSugarPagedList<ObEmployee>> Page(OnboardingEmployeePageInput input);
Task<OnboardingEmployeePageOutput> Page(OnboardingEmployeePageInput input);
/// <summary>
/// 按当前列表筛选条件导出员工明细。
/// </summary>
@@ -20,18 +20,30 @@ public class OnboardingEmployeeService : IOnboardingEmployeeService
}
/// <summary>
/// 分页查询审核通过后生成的员工档案。
/// 分页查询审核通过后生成的员工档案及维度统计。
/// </summary>
public async Task<SqlSugarPagedList<ObEmployee>> Page(OnboardingEmployeePageInput input)
public async Task<OnboardingEmployeePageOutput> Page(OnboardingEmployeePageInput input)
{
var result = await BuildEmployeeQuery(input)
var list = await BuildEmployeeQuery(input)
.OrderByDescending(item => item.CreateTime)
.ToPagedListAsync(input.PageNum, input.PageSize);
if (result.List != null && result.List.Any())
await FillEmployeeMetadata(result.List);
if (list.List != null && list.List.Any())
await FillEmployeeMetadata(list.List);
return result;
var stats = await CalculateStatistics(input);
return new OnboardingEmployeePageOutput
{
PageNum = list.PageNum,
PageSize = list.PageSize,
Total = list.Total,
Pages = list.Pages,
List = list.List,
HasPrevPages = list.HasPrevPages,
HasNextPages = list.HasNextPages,
Statistics = stats
};
}
/// <inheritdoc />
@@ -633,21 +645,31 @@ public class OnboardingEmployeeService : IOnboardingEmployeeService
await FillMissingEntryDates(employeeList);
}
/// <summary>
/// 构造基础员工查询(包含组织、岗位和姓名/手机号搜索),供列表、统计和导出复用。
/// </summary>
private ISugarQueryable<ObEmployee> BuildBaseEmployeeQuery(OnboardingEmployeePageInput input)
{
return _db.Queryable<ObEmployee>()
.WhereIF(
!string.IsNullOrWhiteSpace(input?.EmployeeName),
item => item.EmployeeName.Contains(input.EmployeeName)
|| item.IdCardNumber.Contains(input.EmployeeName))
.WhereIF(!string.IsNullOrWhiteSpace(input?.Phone), item => item.Phone.Contains(input.Phone))
.WhereIF(input?.CompanyId.HasValue == true, item => item.CompanyId == input.CompanyId.Value)
.WhereIF(input?.DepartmentId.HasValue == true, item => item.DepartmentId == input.DepartmentId.Value)
.WhereIF(input?.PositionId.HasValue == true, item => item.PositionId == input.PositionId.Value);
}
/// <summary>
/// 构造列表和导出共用的员工筛选,保证页面看到的范围与导出范围一致。
/// </summary>
private ISugarQueryable<ObEmployee> BuildEmployeeQuery(OnboardingEmployeePageInput input)
{
input ??= new OnboardingEmployeePageInput();
return _db.Queryable<ObEmployee>()
.WhereIF(
!string.IsNullOrWhiteSpace(input.EmployeeName),
item => item.EmployeeName.Contains(input.EmployeeName)
|| item.IdCardNumber.Contains(input.EmployeeName))
.WhereIF(!string.IsNullOrWhiteSpace(input.Phone), item => item.Phone.Contains(input.Phone))
.WhereIF(input.CompanyId.HasValue, item => item.CompanyId == input.CompanyId.Value)
.WhereIF(input.DepartmentId.HasValue, item => item.DepartmentId == input.DepartmentId.Value)
.WhereIF(input.PositionId.HasValue, item => item.PositionId == input.PositionId.Value)
var expiringThreshold = DateTime.Today.AddDays(30).Date.AddDays(1).AddSeconds(-1);
return BuildBaseEmployeeQuery(input)
.WhereIF(
!string.IsNullOrWhiteSpace(input.EmploymentType),
item => item.EmploymentType == input.EmploymentType)
@@ -656,7 +678,50 @@ public class OnboardingEmployeeService : IOnboardingEmployeeService
item => item.RegularizationStatus == input.RegularizationStatus)
.WhereIF(
!string.IsNullOrWhiteSpace(input.SocialInsuranceStatus),
item => item.SocialInsuranceStatus == input.SocialInsuranceStatus);
item => item.SocialInsuranceStatus == input.SocialInsuranceStatus)
.WhereIF(
input.ContractExpiringSoon == true,
item => item.ContractEndDate != null && item.ContractEndDate <= expiringThreshold);
}
/// <summary>
/// 计算员工档案的各项维度统计数量,受组织及关键字联动,但不受快捷状态筛选影响。
/// </summary>
private async Task<OnboardingEmployeeStatisticsOutput> CalculateStatistics(OnboardingEmployeePageInput input)
{
var expiringThreshold = DateTime.Today.AddDays(30).Date.AddDays(1).AddSeconds(-1);
var total = await BuildBaseEmployeeQuery(input).CountAsync();
if (total == 0)
{
return new OnboardingEmployeeStatisticsOutput();
}
var fullTime = await BuildBaseEmployeeQuery(input)
.Where(item => item.EmploymentType == EmployeeEmploymentType.FullTime)
.CountAsync();
var partTime = await BuildBaseEmployeeQuery(input)
.Where(item => item.EmploymentType == EmployeeEmploymentType.PartTime)
.CountAsync();
var probation = await BuildBaseEmployeeQuery(input)
.Where(item => item.RegularizationStatus == EmployeeRegularizationStatus.Probation)
.CountAsync();
var socialPurchased = await BuildBaseEmployeeQuery(input)
.Where(item => item.SocialInsuranceStatus == EmployeeSocialInsuranceStatus.Purchased)
.CountAsync();
var expiringContract = await BuildBaseEmployeeQuery(input)
.Where(item => item.ContractEndDate != null && item.ContractEndDate <= expiringThreshold)
.CountAsync();
return new OnboardingEmployeeStatisticsOutput
{
Total = total,
FullTime = fullTime,
PartTime = partTime,
Probation = probation,
SocialPurchased = socialPurchased,
ExpiringContract = expiringContract
};
}
private static void WriteEmployeeSheet(