using Dlhis.Basic.Appointment.Services; using Dlhis.Basic.Device.Services; using Dlhis.Basic.Organization.Request; using Dlhis.Basic.Organization.Response; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Basic.Enums; using Dlhis.Entity.Device.Entities; using Dlhis.Entity.Device.Enums; using Dlhis.Entity.Sys.Entities; using Dlhis.Entity.Sys.Enums; using Dlhis.Entity.Visitor.Entity; using Dlhis.Entity.Visitor.Enums; using Dlhis.Sys.Api; using Kurisu.AspNetCore.Authentication.Abstractions; using Kurisu.AspNetCore.DataAccess.Dto; using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; using Kurisu.AspNetCore.Utils.Extensions; using Microsoft.AspNetCore.DataProtection; using SqlSugar; namespace Dlhis.Basic.Organization.Services.Implements; public class GainfoService : IGainfoService { private readonly IGainfoStore _gainfoStore; private readonly IDbContext _dbContext; private readonly IDataProtectionProvider _dataProtectionProvider; private readonly ICurrentUser _currentUser; private readonly ITenantApi _tenantApi; private readonly IJinkoSapService _jinkoSapService; private readonly IDevicePermissionService _devicePermissionService; private readonly IGainfoPermissionService _gainfoPermissionService; private readonly IAppointmentService _appointmentService; private readonly ILogger _logger; public GainfoService(IGainfoStore gainfoStore, IDbContext dbContext, IDataProtectionProvider dataProtectionProvider, ICurrentUser currentUser, ITenantApi tenantApi, IJinkoSapService jinkoSapService, IDevicePermissionService devicePermissionService, IGainfoPermissionService gainfoPermissionService, IAppointmentService appointmentService, ILogger logger) { _gainfoStore = gainfoStore; _dbContext = dbContext; _dataProtectionProvider = dataProtectionProvider; _currentUser = currentUser; _tenantApi = tenantApi; _jinkoSapService = jinkoSapService; _devicePermissionService = devicePermissionService; _gainfoPermissionService = gainfoPermissionService; _appointmentService = appointmentService; _logger = logger; } /// /// 档案分页 /// /// /// public async Task> GetPageAsync(GainfoPageRequest request) { var today = DateTime.Today; //根据组织架构搜索档案 var where = LinqExpressionExtensions.False(); var factories = _currentUser.GetUserClaim("tenants").Split(",").ToList(); if (request.DepartmentSelections.Any()) { foreach (var item in request.DepartmentSelections) { var searchDepartments = await GetRecursionDepartmentNosAsync(item.DepartmentNos); where = searchDepartments.Any() ? where.Or(gainfo => gainfo.Factory == item.Tenant && searchDepartments.Contains(gainfo.DepartmentNo)) : where.Or(gainfo => gainfo.Factory == item.Tenant); } factories = request.DepartmentSelections.Select(x => x.Tenant).Distinct().ToList(); } else { where = where.Or(gainfo => factories.Contains(gainfo.Factory)); } if (request.SearchType.HasValue) { GainfoUserTypeEnumType userTypeEnumType = request.SearchType switch { GainfoSearchEnumType.Internal => GainfoUserTypeEnumType.Normal, GainfoSearchEnumType.Outsource => GainfoUserTypeEnumType.Outsource, GainfoSearchEnumType.BusinessTrip => throw new ArgumentNullException(request.SearchType?.ToString()), GainfoSearchEnumType.External => GainfoUserTypeEnumType.External, null => throw new ArgumentOutOfRangeException(request.SearchType?.ToString()), _ => throw new ArgumentOutOfRangeException(request.SearchType?.ToString()) }; where = where.And(x => x.Type == userTypeEnumType); } if (request.IsSearchAll) { where = Expressionable.Create() .And(where) .Or(gainfo => SqlFunc.Subqueryable() .Where(p => p.Code == gainfo.Code && factories.Contains(p.Destination) && SqlFunc.DateIsSame(p.BeginDate, today)) .Any() ) .ToExpression(); } ISugarQueryable queryable = request.IsSearchAll ? _dbContext.Queryable().AS("GainfoEntity", "gainfo") .Where(where) .LeftJoin((gainfo, department) => gainfo.DepartmentNo == department.No) .LeftJoin((gainfo, department, type) => type.Code == SqlFunc.ToString(gainfo.CardType) && type.Type == "timeperiod") .WhereIF(request.Search.IsPresent(), gainfo => gainfo.Name == request.Search || gainfo.Code == request.Search || gainfo.IdNo == request.Search) .Select((gainfo, department, type) => new GainfoPageResponse { DepartmentName = department.Name, CardType = gainfo.CardType, CardTypeName = type.Display }, true) : _gainfoStore.Queryable(request.Status) .WhereIF(request.SearchType.HasValue, where) .LeftJoin((gainfo, department) => gainfo.DepartmentNo == department.No) .LeftJoin((gainfo, department, type) => type.Code == SqlFunc.ToString(gainfo.CardType) && type.Type == "timeperiod") .WhereIF(request.SearchType.HasValue == false, gainfo => SqlFunc.Subqueryable() .Where(p => p.Code == gainfo.Code && factories.Contains(p.Destination) && SqlFunc.DateIsSame(p.BeginDate, today)) .Any()) .WhereIF(request.Search.IsPresent(), gainfo => gainfo.Name.Contains(request.Search) || gainfo.Code == request.Search || gainfo.IdNo == request.Search) .OrderByIF(request.SearchType == GainfoSearchEnumType.Outsource, gainfo => gainfo.ResignationDate, OrderByType.Desc) //外包人员按离职日期倒排 .Select((gainfo, department, type) => new GainfoPageResponse { DepartmentName = department.Name, CardType = gainfo.CardType, CardTypeName = type.Display }, true); var page = await queryable.ToPageListAsync(request); //外包人员部门号处理 if (request.SearchType == GainfoSearchEnumType.Outsource) { var codes = page.Data.Select(x => x.Code).ToList(); var outsourceInfos = await _dbContext.Queryable() .Where(x => codes.Contains(x.Code)) .Select(x => new { x.Code, x.Supplier }) .ToListAsync(); page.Data.ForEach(item => { item.DepartmentName = outsourceInfos.FirstOrDefault(x => x.Code == item.Code)?.Supplier; }); } return page; } public async Task> GetPageByCodeAsync(string code) { var page = await _gainfoStore.Queryable() .Where(x => x.Code == code) .Select() .ToPageListAsync(new PageDto { PageIndex = 1, PageSize = 1 }); var tenants = await _tenantApi.GetTenantsInternalAsync(); page.Data.ForEach(x => { x.Workplace = tenants.FirstOrDefault(item => item.Code == x.Workplace)?.Name; x.Factory = tenants.FirstOrDefault(item => item.Code == x.Factory)?.Name; }); return page; } public async Task CurrentUserInfoAsync() { var code = _currentUser.GetUserClaim("jinko-code"); if (code.IsEmpty()) { _logger.LogWarning("工号为空尝试获取人员信息"); return null; } var gainfo = await _gainfoStore.Queryable().Where(x => x.Code == code).SingleAsync(); if (gainfo == null) { //开启同步处理 await _jinkoSapService.GetPersonsByCodeAsync(code); gainfo = await _gainfoStore.Queryable().Where(x => x.Code == code).SingleAsync(); if (gainfo == null) return null; } var info = await _gainfoStore.Queryable(GainfoStatusEnumType.Working) .LeftJoin((ga, department) => ga.DepartmentNo == department.No) .LeftJoin((ga, department, type) => type.Code == ga.CardType.ToString() && type.Type == "timeperiod") .Where((ga, department) => ga.Id == gainfo.Id) .Select((ga, department, type) => new GainfoCurrentResponse { UserNo = ga.No, Birthday = ga.Birthday, DepartmentNo = department.No, DepartmentName = department.Name, Gender = ga.Gender, UserCode = ga.Code, UserName = ga.Name, Factory = ga.Factory, CardType = ga.CardType, CardTypeName = type.Display }).SingleAsync(); if (info != null) { try { var tenant = await _tenantApi.GetTenantByCodeAsync(info.Factory); info.FactoryName = tenant?.Name; } catch (Exception) { // ignored } } return info; } public async Task CheckIdNoAndNameMatchAsync(GainfoCheckIdNoAndNameRequest request) { var gainfo = await _gainfoStore.Queryable(GainfoStatusEnumType.Working).SingleAsync(x => x.IdNo == request.IdNo && x.Name == request.Name); gainfo.ThrowIfNull("验证失败!"); var protector = _dataProtectionProvider.CreateProtector("gainfo:external:idno"); return new { loginPass = protector.Protect(request.IdNo), UserNo = gainfo.No }; } public async Task ResignAsync(GainfoResignRequest request) { var gainfo = await _dbContext.Queryable().SingleAsync(x => x.Id == request.Id); gainfo.ThrowIfNull("档案数据不存在"); if (gainfo.Type == GainfoUserTypeEnumType.External) { var visitorAppointmentDetails = await _dbContext.Queryable() .Where(x => x.UserNo == gainfo.No) .Where(x => x.DoorStatus == VisitorAppointmentDetailStatusEnumType.Wait || x.WorkplaceStatus == VisitorAppointmentDetailStatusEnumType.Wait) .ToListAsync(); foreach (var visitorAppointment in visitorAppointmentDetails) { await _appointmentService.FocusLeaveAsync(visitorAppointment.Id, request.Reason); } } else { await _gainfoPermissionService.ResetPermissionsAsync(gainfo.No, DeviceTaskEnumType.Delete, null, request.Reason); await _dbContext.Deleteable().Where(x => x.UserNo == gainfo.No).ExecuteCommandAsync(); await _dbContext.Deleteable().Where(x => x.AssignType == AssignTypeEnumType.User && x.AssignValue == gainfo.No).ExecuteCommandAsync(); } //先写入离职表 gainfo.IdentityUserId = (int)gainfo.Id; //记录原始id gainfo.ResignationDate = request.Date; gainfo.Remark = request.Reason; gainfo.Id = 0; if (!await _dbContext.Queryable().AS("GainfoLeave").AnyAsync(x => x.Code == gainfo.Code)) { await _dbContext.Client.Insertable(gainfo).AS("GainfoLeave").ExecuteCommandAsync(); } gainfo.Id = gainfo.IdentityUserId; await _dbContext.DeleteReallyAsync(gainfo); } public async Task SetSecurityWhiteAsync(string userCode) { var gainfo = await _gainfoStore.Queryable().Where(x => x.Code == userCode).SingleAsync(); gainfo.ThrowIfNull("档案信息不存在"); gainfo.Type = gainfo.Type switch { GainfoUserTypeEnumType.Normal => GainfoUserTypeEnumType.SecurityWhite, GainfoUserTypeEnumType.SecurityWhite => GainfoUserTypeEnumType.Normal, _ => gainfo.Type }; await _dbContext.UpdateAsync(gainfo); var deviceCodes = await _devicePermissionService.GetUserDeviceCodesByNoAsync(gainfo.No); var dhDevices = await _dbContext.Queryable().LeftJoin((x, xt) => x.TemplateCode == xt.Code) .Where((x, xt) => xt.Name == "大华人脸机") .Where(x => deviceCodes.Contains(x.Code)) .ToListAsync(); await _dbContext.InsertAsync(dhDevices.Select(x => new DeviceTaskEntity { Type = DeviceTaskEnumType.Update, DeviceType = x.Type, UserId = gainfo.Id, UserNo = gainfo.No, DeviceUniqueNo = x.UniqueNo, Status = DeviceTaskStatusEnumType.Wait, Version = 0, ResultMessage = null, Source = "安全级别提高", Priority = 60, TenantId = x.TenantId }).ToList()); } /// /// 档案列表 /// /// /// public async Task> GetGainfoListAsync(GainfoListRequest request) { var page = await _gainfoStore.Queryable(request.Status) .LeftJoin((ga, de) => ga.DepartmentNo == de.No) .WhereIF(!request.Name.IsEmpty(), ga => ga.Name == request.Name) .WhereIF(!request.IdNo.IsEmpty(), ga => ga.IdNo == request.IdNo) .WhereIF(!request.DepartmentNo.IsEmpty(), ga => ga.DepartmentNo == request.DepartmentNo) .WhereIF(!request.Code.IsEmpty(), ga => ga.Code == request.Code) .Select((ga, de) => new GainfoListResponse { No = ga.No, Name = ga.Name, Code = ga.Code, IdNo = ga.IdNo, Gender = ga.Gender, Phone = ga.Phone, DepartmentNo = de.No, DepartmentName = de.Name, Address = ga.Address, }).ToPageListAsync(request); return page; } /// /// 档案详情 /// /// /// public async Task GetGainfoDetailAsync(GainfoDetailRequest request) { var info = await _gainfoStore.Queryable(request.Status) .LeftJoin((ga, de) => ga.DepartmentNo == de.No) .LeftJoin((ga, de, pos) => ga.PositionNo == pos.No) .LeftJoin((ga, de, pos, type) => type.Code == ga.CardType.ToString() && type.Type == "timeperiod") .Where(ga => ga.No == request.No) .Select((ga, de, pos, type) => new GainfoDetailResponse { No = ga.No, InternalNo = ga.InternalNo, Name = ga.Name, Code = ga.Code, IdClass = ga.IdClass, IdNo = ga.IdNo, Gender = ga.Gender, Address = ga.Address, OriginalBirthday = ga.Birthday, Phone = ga.Phone, Grade = ga.Grade, Title = ga.Title, Degree = ga.Degree, Werks = ga.Werks, CostId = ga.CostId, NativeName = ga.Native, CountryName = ga.CountryNo, NationName = ga.Nation, ClassName = ga.IdClass, EntryDate = ga.EntryDate, Workplace = ga.Workplace, Factory = ga.Factory, DepartmentName = de.Name, Position = pos.Name, CardType = ga.CardType, CardTypeName = type.Display }) .SingleAsync(); if (info != null) { var searchTypes = new List { "native", "country", "nation", "cls" }; var types = await _dbContext.Queryable().Where(x => searchTypes.Contains(x.Type)).ToListAsync(); info.NativeName = types.Where(x => x.Type == "native").FirstOrDefault(x => x.Code == info.NativeName)?.Display; info.CountryName = types.Where(x => x.Type == "country").FirstOrDefault(x => x.Code == info.CountryName)?.Display ?? "中国"; info.NationName = types.Where(x => x.Type == "nation").FirstOrDefault(x => x.Code == info.NationName)?.Display; info.ClassName = types.Where(x => x.Type == "cls").FirstOrDefault(x => x.Code == info.ClassName)?.Display ?? "身份证"; if (request.WithFace) { info.Face = await _dbContext.ChangeDb("face").Queryable().Where(x => x.UserCode == info.Code).Select(x => x.Face).SingleAsync(); } try { var tenants = await _tenantApi.GetTenantsInternalAsync(); info.Workplace = tenants.FirstOrDefault(x => x.Code == info.Workplace)?.Name; info.Factory = tenants.FirstOrDefault(x => x.Code == info.Factory)?.Name; } catch (Exception) { //ignore } } return info; } public async Task MigrationAsync(MigrationRequest request) { //档案数据 var gainfo = await _gainfoStore.Queryable().Where(x => x.Code == request.Code).FirstAsync(); if (gainfo == null) { return; } //卡号为空则更新 if (gainfo.CardNo.IsEmpty()) { gainfo.CardNo = request.CardNo; await _gainfoStore.UpdateAsync(gainfo); } //外部传入人脸 if (request.Face.IsPresent()) { var faceDbContext = _dbContext.ChangeDb("face"); var exists = await faceDbContext.Queryable().AnyAsync(x => x.UserCode == gainfo.Code); //人脸不存在则写入 if (!exists) { await faceDbContext.InsertAsync(new GainfoFaceEntity { UserCode = gainfo.Code, Face = request.Face }); //海宁触发权限下发 if (gainfo.Workplace == "5") { await _devicePermissionService.GenerateDeviceTasksAsync(gainfo.No, DeviceTaskEnumType.Add, "人员迁移生成"); } } } } //-------------------------------------------help methods ------------------------------------------------ /// /// 递归获取部门No /// /// /// private async Task> GetRecursionDepartmentNosAsync(List departmentNos) { if (departmentNos.IsEmpty()) { return new List(); } var departments = await _dbContext.Queryable().ToListAsync(); var currentNos = departments.Where(x => departmentNos.Contains(x.No)).ToList(); foreach (var item in currentNos) { RecursionGetNext(item.No, departments, departmentNos); } return departmentNos.Distinct().ToList(); //local method void RecursionGetNext(string currentNo, List internalDepartments, List result) { var next = internalDepartments.Where(x => x.PNo == currentNo).ToList(); foreach (var item in next) { result.Add(item.No); RecursionGetNext(item.No, internalDepartments, result); } } } }