using System.Text; using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Basic.Enums; using Dlhis.Entity.Visitor.Entity; using Dlhis.Entity.Visitor.Enums; using Dlhis.External.Appointment.Request; using Kurisu.AspNetCore.Cache; using Kurisu.AspNetCore.CustomClass; using Kurisu.AspNetCore.DataAccess.SqlSugar.Services; using Kurisu.AspNetCore.Utils.Extensions; namespace Dlhis.External.Appointment.Services.Implements; public class AppointmentService : IAppointmentService { private readonly IDbContext _dbContext; private readonly RedisCache _redisCache; private readonly IHttpClientFactory _httpClientFactory; private readonly ILogger _logger; public AppointmentService(IDbContext dbContext, RedisCache redisCache, IHttpClientFactory httpClientFactory, ILogger logger) { _dbContext = dbContext; _redisCache = redisCache; _httpClientFactory = httpClientFactory; _logger = logger; } public async Task ReceiveAsync(VisitorAppointmentReceiveRequest request) { var invalids = new[] { GainfoUserTypeEnumType.Normal, GainfoUserTypeEnumType.SecurityWhite }; var exists = await _dbContext.Queryable().Where(x => x.No == request.No).AnyAsync(); exists.ThrowIfTrue("已经存在申请,请勿重复提交"); var areas = await _dbContext.Queryable().Where(x => x.TenantId == request.Factory).ToListAsync(); if (request.OnlyCheck) { var enterDoorAreaIdNos = request.Items.Where(x => x.IsEnterDoorArea).Select(x => x.IdNo).Distinct().ToList(); var errors = await _dbContext.Queryable() .Where(x => enterDoorAreaIdNos.Contains(x.IdNo) || enterDoorAreaIdNos.Contains(x.Code)) .Where(x => invalids.Contains(x.Type)) .Select(x => x.IdNo + x.Name) .ToListAsync(); errors.ThrowIfExists($"内部人员无法发起门岗预约({errors.Join(",")})"); foreach (var item in request.Items) { item.IdNo = item.IdNo.Trim(); if (item.IsEnterDoorArea && areas.Where(x => x.Type == AppointmentAreaEnumType.Door) .Select(x => x.CustomCode) .Contains(item.ApplyDoorArea) == false) { throw new UserFriendlyException($"门岗区域{item.ApplyDoorArea}无效"); } if (item.IsEnterWorkplace && item.ApplyWorkplaceAreas.All(p => areas.Where(x => x.Type == AppointmentAreaEnumType.Workplace) .Select(x => x.CustomCode) .Contains(p)) == false) { var workplaceAreas = areas.Where(x => x.Type == AppointmentAreaEnumType.Workplace).Select(x => x.CustomCode); var notExistsAreas = item.ApplyWorkplaceAreas.Where(x => !workplaceAreas.Contains(x)); throw new UserFriendlyException($"车间区域{notExistsAreas.Join(",")}无效"); } var gainfo = await _dbContext.Queryable().Where(x => x.IdNo == item.IdNo || x.Code == item.IdNo).SingleAsync(); //外部人员 if (gainfo == null) { } else { (invalids.Contains(gainfo.Type) && item.IsEnterDoorArea).ThrowIfTrue("内部人员无法发起门岗预约"); } } } else { if (request.Factory == "501") { await ReSendTo501Async(request); return; } var mst = new VisitorAppointmentEntity { No = request.No, Title = request.Title, Code = request.Code, Source = request.Source, Date = request.Date, Factory = request.Factory, Reason = request.Reason, Remark = request.Remark, }; var enterDoorAreaIdNos = request.Items.Where(x => x.IsEnterDoorArea).Select(x => x.IdNo).Distinct().ToList(); var errors = await _dbContext.Queryable() .Where(x => enterDoorAreaIdNos.Contains(x.IdNo) || enterDoorAreaIdNos.Contains(x.Code)) .Where(x => invalids.Contains(x.Type)) .Select(x => x.IdNo + x.Name) .ToListAsync(); errors.ThrowIfExists($"内部人员无法发起门岗预约({errors.Join(",")})"); await _dbContext.InsertAsync(mst); //var idNos = request.Items.Select(x => x.IdNo).Distinct().ToList(); //var outsources = await _dbContext.Queryable() // .Where(x => idNos.Contains(x.IdNo) || idNos.Contains(x.Code)) // .Where(x => x.Type == GainfoUserTypeEnumType.Outsource) // .Select(x => x.IdNo + x.Name) // .ToListAsync(); //outsources.ThrowIfExists($"存在外包人员申请,请检查一下人员:{outsources.Join(",")}"); foreach (var item in request.Items) { item.IdNo = item.IdNo.Trim(); if (item.IsEnterDoorArea && areas.Where(x => x.Type == AppointmentAreaEnumType.Door) .Select(x => x.CustomCode) .Contains(item.ApplyDoorArea) == false) { throw new UserFriendlyException($"门岗区域{item.ApplyDoorArea}无效"); } if (item.IsEnterWorkplace && item.ApplyWorkplaceAreas.All(p => areas.Where(x => x.Type == AppointmentAreaEnumType.Workplace) .Select(x => x.CustomCode) .Contains(p)) == false) { var workplaceAreas = areas.Where(x => x.Type == AppointmentAreaEnumType.Workplace).Select(x => x.CustomCode); var notExistsAreas = item.ApplyWorkplaceAreas.Where(x => !workplaceAreas.Contains(x)); throw new UserFriendlyException($"车间区域{notExistsAreas.Join(",")}无效"); } var gainfo = await _dbContext.Queryable().Where(x => x.IdNo == item.IdNo || x.Code == item.IdNo).SingleAsync(); //外部人员 if (gainfo == null) { gainfo = new GainfoEntity { No = Guid.NewGuid().ToString(), Code = await GetNextExternalCodeAsync(), Gender = GetGender(item.IdNo), Type = GainfoUserTypeEnumType.External, IdNo = item.IdNo, Name = item.Name, Source = request.Source, Phone = item.Phone, Factory = request.Factory, EntryDate = DateTime.Now }; await _dbContext.InsertAsync(gainfo); } else { (invalids.Contains(gainfo.Type) && item.IsEnterDoorArea).ThrowIfTrue("内部人员无法发起门岗预约"); if (gainfo.Type == GainfoUserTypeEnumType.External) { gainfo.Source = request.Source; gainfo.Phone = item.Phone; gainfo.Factory = request.Factory; await _dbContext.UpdateAsync(gainfo); } //else if (gainfo.Type == GainfoUserTypeEnumType.Outsource) //{ // throw new UserFriendlyException($"访客类型有误!,请检查{gainfo.Name},{gainfo.IdNo}"); //} } var detail = new VisitorAppointmentDetailEntity { UserNo = gainfo.No, No = request.No, IdType = item.IdType, IdNo = item.IdNo, Name = item.Name, Phone = item.Phone, Remark = item.Remark, DoorStatus = item.IsEnterDoorArea && areas.Where(x => x.Type == AppointmentAreaEnumType.Door) .Select(x => x.CustomCode) .Contains(item.ApplyDoorArea) ? VisitorAppointmentDetailStatusEnumType.Wait : VisitorAppointmentDetailStatusEnumType.Obsolete, LicensePlate = item.LicensePlate, IsEnterDoorArea = item.IsEnterDoorArea, ApplyDoorArea = item.ApplyDoorArea, DoorStart = item.DoorStart, DoorEnd = item.DoorEnd, IsEnterWorkplace = item.IsEnterWorkplace, WorkplaceStatus = item.IsEnterWorkplace && item.ApplyWorkplaceAreas.All(p => areas.Where(x => x.Type == AppointmentAreaEnumType.Workplace) .Select(x => x.CustomCode) .Contains(p)) ? VisitorAppointmentDetailStatusEnumType.Wait : VisitorAppointmentDetailStatusEnumType.Obsolete, ApplyWorkplaceAreas = item.ApplyWorkplaceAreas, WorkplaceStart = item.WorkplaceStart, WorkplaceEnd = item.WorkplaceEnd, ImageUrl = item.ImageUrl }; await _dbContext.InsertAsync(detail); } } } private static GenderEnumType GetGender(string idNo) { try { if (idNo.Length == 18) { return int.Parse(idNo.ToCharArray()[16].ToString()) % 2 == 0 ? GenderEnumType.Female : GenderEnumType.Male; } } catch (Exception) { //ignore } return GenderEnumType.Unknown; } public async Task GetNextExternalCodeAsync() { await using var handler = await _redisCache.LockAsync("gainfo:external:code-generate", expiry: TimeSpan.FromSeconds(3), retryInterval: TimeSpan.FromSeconds(1), retryCount: 3); handler.Acquired.ThrowIfFalse("生成虚拟工号失败"); int code; var entity = await _dbContext.Queryable().Where(x => x.Type == "gainfoExternalMaxNum").SingleAsync(); if (entity == null) { code = 1; await _dbContext.InsertAsync(new BasicTypeEntity { Type = "gainfoExternalMaxNum", Code = "1", Display = "外部人员序号", DisplayEn = "外部人员序号", Remark = string.Empty, Sequence = 1 }); } else { code = int.Parse(entity.Code) + 1; entity.Code = code.ToString(); await _dbContext.UpdateAsync(entity); } return "EXT" + code.ToString().PadLeft(6, '0'); } private async Task ReSendTo501Async(VisitorAppointmentReceiveRequest request) { var gainfo = await _dbContext.Queryable() .LeftJoin((ga, dept) => ga.DepartmentNo == dept.No) .Where((ga, dept) => ga.Code == request.Code) .Select((ga, dept) => new { ga.No, ga.Name, ga.Phone, DeptName = dept.Name }) .SingleAsync(); gainfo.ThrowIfNull("501被访人工号不存在"); //501厂区发送访客预约 var httpClient = _httpClientFactory.CreateClient(); var list = request.Items.Where(x => x.IsEnterDoorArea).ToList(); var areas = await _dbContext.Queryable().Where(x => x.TenantId == request.Factory).ToListAsync(); foreach (var dto in list) { var json = new { arr = dto.DoorStart!.Value.ToString("yyyy-MM-dd HH:mm:ss"), // [必填] 到达时间 dep = dto.DoorEnd!.Value.ToString("yyyy-MM-dd HH:mm:ss"), // 离开时间 company = request.Source, // 公司 deptdes = gainfo.DeptName, // 被访人部门 askName = request.Code, // 被访人姓名 askPhone = gainfo.Phone, //被访人手机号 gname = dto.Name, // 访客姓名 idNo = dto.IdNo, // 访客身份证号 phone = dto.Phone, // 访客电话 reason = request.Reason, // 访问原因 carNo = dto.LicensePlate, // 车牌号 carDes = "", // 物品描述 remark = dto.Remark, // 备注 //logId = null, // 操作员ID,null或空时后台保存为"face" //logShift = null, // 操作员班别 null或空时后台保存为"1" //sta = null, //状态 null或空时后台保存为"R" newFunc = dto.IsEnterWorkplace ? 1 : 0, // 是否进入车间 yqgw = dto.IsEnterDoorArea ? areas.Where(x => x.Type == AppointmentAreaEnumType.Door) .Where(x => dto.ApplyDoorArea.Contains(x.CustomCode)) .Select(x => x.Name) .Distinct().Join(",") : string.Empty // 门岗名称 }.ToJson(); var response = await httpClient.PostAsync("https://pay.aizhuhotel.com/jschuneng/api/guest/GainfoReserveAdd", new StringContent(json, Encoding.UTF8, "application/json")); var responseJson = await response.Content.ReadAsStringAsync(); _logger.LogInformation("发送到501访客预约{idNo}--{name},发送:{json} ,返回:{responseJson}", dto.IdNo, dto.Name, json, responseJson); } } }