From 571db6fc55d0f8ac6ae4658924e116306255e10e Mon Sep 17 00:00:00 2001 From: fuenmao <980740792@qq.com> Date: Fri, 11 Sep 2026 10:38:20 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=91=98=E5=B7=A5=E7=BB=9F?= =?UTF-8?q?=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Employee/Dto/OnboardingEmployeeInput.cs | 52 ++++++++++ .../Employee/IOnboardingEmployeeService.cs | 4 +- .../Employee/OnboardingEmployeeService.cs | 97 ++++++++++++++++--- 3 files changed, 135 insertions(+), 18 deletions(-) diff --git a/SimpleAdmin.Application/Services/Onboarding/Employee/Dto/OnboardingEmployeeInput.cs b/SimpleAdmin.Application/Services/Onboarding/Employee/Dto/OnboardingEmployeeInput.cs index 7e51d96..6e14320 100644 --- a/SimpleAdmin.Application/Services/Onboarding/Employee/Dto/OnboardingEmployeeInput.cs +++ b/SimpleAdmin.Application/Services/Onboarding/Employee/Dto/OnboardingEmployeeInput.cs @@ -46,6 +46,58 @@ public class OnboardingEmployeePageInput : BasePageInput /// 社保状态。 /// public string SocialInsuranceStatus { get; set; } + + /// + /// 合同即将到期筛选(30天内到期或已到期)。 + /// + public bool? ContractExpiringSoon { get; set; } +} + +/// +/// 正式员工档案分页数据及当前查询条件下的维度统计。 +/// +public class OnboardingEmployeePageOutput : SqlSugarPagedList +{ + /// + /// 不受快捷维度筛选影响的员工维度统计。 + /// + public OnboardingEmployeeStatisticsOutput Statistics { get; set; } = new(); +} + +/// +/// 正式员工档案维度统计。 +/// +public class OnboardingEmployeeStatisticsOutput +{ + /// + /// 在册总数。 + /// + public int Total { get; set; } + + /// + /// 正式员工数量。 + /// + public int FullTime { get; set; } + + /// + /// 兼职员工数量。 + /// + public int PartTime { get; set; } + + /// + /// 试用期待转正数量。 + /// + public int Probation { get; set; } + + /// + /// 社保已缴纳数量。 + /// + public int SocialPurchased { get; set; } + + /// + /// 合同即将到期数量(30天内到期或已到期)。 + /// + public int ExpiringContract { get; set; } } /// diff --git a/SimpleAdmin.Application/Services/Onboarding/Employee/IOnboardingEmployeeService.cs b/SimpleAdmin.Application/Services/Onboarding/Employee/IOnboardingEmployeeService.cs index 52036b9..47eda1f 100644 --- a/SimpleAdmin.Application/Services/Onboarding/Employee/IOnboardingEmployeeService.cs +++ b/SimpleAdmin.Application/Services/Onboarding/Employee/IOnboardingEmployeeService.cs @@ -6,9 +6,9 @@ namespace SimpleAdmin.Application; public interface IOnboardingEmployeeService : ITransient { /// - /// 分页查询审核通过后生成的正式员工档案。 + /// 分页查询审核通过后生成的正式员工档案及维度统计。 /// - Task> Page(OnboardingEmployeePageInput input); + Task Page(OnboardingEmployeePageInput input); /// /// 按当前列表筛选条件导出员工明细。 /// diff --git a/SimpleAdmin.Application/Services/Onboarding/Employee/OnboardingEmployeeService.cs b/SimpleAdmin.Application/Services/Onboarding/Employee/OnboardingEmployeeService.cs index 3b63c07..5cd6d66 100644 --- a/SimpleAdmin.Application/Services/Onboarding/Employee/OnboardingEmployeeService.cs +++ b/SimpleAdmin.Application/Services/Onboarding/Employee/OnboardingEmployeeService.cs @@ -20,18 +20,30 @@ public class OnboardingEmployeeService : IOnboardingEmployeeService } /// - /// 分页查询审核通过后生成的员工档案。 + /// 分页查询审核通过后生成的员工档案及维度统计。 /// - public async Task> Page(OnboardingEmployeePageInput input) + public async Task 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 + }; } /// @@ -633,21 +645,31 @@ public class OnboardingEmployeeService : IOnboardingEmployeeService await FillMissingEntryDates(employeeList); } + /// + /// 构造基础员工查询(包含组织、岗位和姓名/手机号搜索),供列表、统计和导出复用。 + /// + private ISugarQueryable BuildBaseEmployeeQuery(OnboardingEmployeePageInput input) + { + return _db.Queryable() + .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); + } + /// /// 构造列表和导出共用的员工筛选,保证页面看到的范围与导出范围一致。 /// private ISugarQueryable BuildEmployeeQuery(OnboardingEmployeePageInput input) { input ??= new OnboardingEmployeePageInput(); - return _db.Queryable() - .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); + } + + /// + /// 计算员工档案的各项维度统计数量,受组织及关键字联动,但不受快捷状态筛选影响。 + /// + private async Task 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(