588 lines
25 KiB
C#
588 lines
25 KiB
C#
using Dlhis.Basic.Appointment.Request;
|
||
using Dlhis.Basic.Appointment.Response;
|
||
using Dlhis.Basic.Common.Message.Requests;
|
||
using Dlhis.Basic.Common.Message.Services;
|
||
using Dlhis.Basic.Organization.Request;
|
||
using Dlhis.Basic.Organization.Response;
|
||
using Dlhis.Basic.Organization.Services;
|
||
using Dlhis.Dh.Api;
|
||
using Dlhis.Dh.Api.Requests;
|
||
using Dlhis.Entity.Basic.Entity;
|
||
using Dlhis.Entity.Basic.Enums;
|
||
using Dlhis.Entity.Device.Entities;
|
||
using Dlhis.Entity.Device.Enums;
|
||
using Dlhis.Entity.Visitor.Entity;
|
||
using Dlhis.Entity.Visitor.Enums;
|
||
using Kurisu.AspNetCore.Authentication.Abstractions;
|
||
using Kurisu.AspNetCore.CustomClass;
|
||
using Kurisu.AspNetCore.DataAccess.Dto;
|
||
using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions;
|
||
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
|
||
using Kurisu.AspNetCore.Utils.Extensions;
|
||
using Mapster;
|
||
using Microsoft.AspNetCore.DataProtection;
|
||
using SqlSugar;
|
||
|
||
namespace Dlhis.Basic.Appointment.Services.Implements;
|
||
|
||
public class AppointmentService : IAppointmentService
|
||
{
|
||
private readonly IDbContext _dbContext;
|
||
private readonly IDataProtectionProvider _dataProtectionProvider;
|
||
private readonly ICurrentUser _currentUser;
|
||
private readonly IDhApi _dhApi;
|
||
private readonly IJinkoApiService _jinkoApiService;
|
||
private readonly IFactorySettingService _factorySettingService;
|
||
private readonly ILogger<AppointmentService> _logger;
|
||
private readonly IGainfoFaceService _gainfoFaceService;
|
||
private readonly IServiceProvider _serviceProvider;
|
||
|
||
public AppointmentService(IDbContext dbContext,
|
||
IDataProtectionProvider dataProtectionProvider,
|
||
ICurrentUser currentUser,
|
||
IDhApi dhApi,
|
||
IJinkoApiService jinkoApiService,
|
||
IFactorySettingService factorySettingService,
|
||
IGainfoFaceService gainfoFaceService,
|
||
IServiceProvider serviceProvider,
|
||
|
||
ILogger<AppointmentService> logger)
|
||
{
|
||
_dbContext = dbContext;
|
||
_dataProtectionProvider = dataProtectionProvider;
|
||
_currentUser = currentUser;
|
||
_dhApi = dhApi;
|
||
_jinkoApiService = jinkoApiService;
|
||
_factorySettingService = factorySettingService;
|
||
_logger = logger;
|
||
_gainfoFaceService = gainfoFaceService;
|
||
_serviceProvider = serviceProvider;
|
||
}
|
||
|
||
public async Task<Pagination<AppointmentPageResponse>> GetPageAsync(AppointmentPageRequest request)
|
||
{
|
||
var factory = _currentUser.GetStringTenantId();
|
||
|
||
return await _dbContext.Queryable<VisitorAppointmentEntity>()
|
||
.WhereIF(request.SearchDateTimePeriod.HasValue(),
|
||
x => x.Date >= request.SearchDateTimePeriod.Start && x.Date <= request.SearchDateTimePeriod.End)
|
||
.WhereIF(request.Search.IsPresent(), x => x.Code == request.Search ||
|
||
SqlFunc.Subqueryable<VisitorAppointmentDetailEntity>()
|
||
.Where(p => p.No == x.No)
|
||
.Where(p => p.IdNo == request.Search || p.Name == request.Search).Any()
|
||
)
|
||
.Where(x => x.Factory == factory)
|
||
.Select<AppointmentPageResponse>()
|
||
.ToPageListAsync(request);
|
||
}
|
||
|
||
public async Task<List<AppointmentDetailResponse>> GetAppointmentDetailsByIdAsync(string no)
|
||
{
|
||
return await _dbContext.Queryable<VisitorAppointmentDetailEntity>()
|
||
.Where(x => x.No == no)
|
||
.Select(x => new AppointmentDetailResponse
|
||
{
|
||
Id = x.Id,
|
||
No = x.No,
|
||
UserNo = x.UserNo,
|
||
IdType = x.IdType,
|
||
IdNo = x.IdNo,
|
||
Name = x.Name,
|
||
Phone = x.Phone,
|
||
LicensePlate = x.LicensePlate,
|
||
IsEnterDoorArea = x.IsEnterDoorArea,
|
||
ApplyDoorArea = SqlFunc.Subqueryable<AppointmentAreaEntity>().Where(p => p.CustomCode == x.ApplyDoorArea).Select(p => p.Name),
|
||
DoorStart = x.DoorStart,
|
||
DoorEnd = x.DoorEnd,
|
||
IsEnterWorkplace = x.IsEnterWorkplace,
|
||
ApplyWorkplaceAreas = SqlFunc.Subqueryable<AppointmentAreaEntity>().Where(p => x.ApplyWorkplaceAreas.ToString().Contains(p.CustomCode)).ToList(p => p.Name),
|
||
WorkplaceStart = x.WorkplaceStart,
|
||
WorkplaceEnd = x.WorkplaceEnd,
|
||
ImageUrl = x.ImageUrl,
|
||
Remark = x.Remark,
|
||
DoorStatus = x.DoorStatus,
|
||
WorkplaceStatus = x.WorkplaceStatus,
|
||
})
|
||
.ToListAsync();
|
||
}
|
||
|
||
public async Task ConfirmAsync(AppointmentConfirmRequest request)
|
||
{
|
||
var detail = await _dbContext.Queryable<VisitorAppointmentDetailEntity>().Where(x => x.Id == request.Id).SingleAsync();
|
||
detail.ThrowIfNull("预约信息不存在");
|
||
|
||
//提前传
|
||
await UploadFaceToDhAsync(detail.IdNo, request.Base64Image);
|
||
|
||
if (detail.DoorStatus == VisitorAppointmentDetailStatusEnumType.Wait)
|
||
{
|
||
detail.DoorStatus = VisitorAppointmentDetailStatusEnumType.Arrived;
|
||
}
|
||
else
|
||
{
|
||
true.ThrowIfTrue($"数据有误:{detail.DoorStatus.GetDescription()}");
|
||
}
|
||
|
||
detail.ArrivedTime = DateTime.Now;
|
||
await _dbContext.UpdateAsync(detail);
|
||
|
||
await _gainfoFaceService.UploadExternalFaceAsync(new GainfoUploadFaceRequest
|
||
{
|
||
UserNo = detail.IdNo,
|
||
Face = request.Base64Image
|
||
});
|
||
|
||
await GenerateDeviceTasksAsync(detail, false, DeviceTaskEnumType.Add, "访客门岗认证生成");
|
||
}
|
||
|
||
public async Task<AppointmentDetailResponse> GetTodayByIdNoAsync(string idNo, string factory)
|
||
{
|
||
var protector = _dataProtectionProvider.CreateProtector("gainfo:external:idno");
|
||
try
|
||
{
|
||
idNo = protector.Unprotect(idNo);
|
||
}
|
||
catch (Exception)
|
||
{
|
||
//ignore
|
||
}
|
||
|
||
var now = DateTime.Now;
|
||
return await _dbContext.Queryable<VisitorAppointmentDetailEntity>()
|
||
.LeftJoin<GainfoEntity>((x, ga) => ga.IdNo == x.IdNo)
|
||
.Where((x, ga) => ga.IdNo == idNo)
|
||
.Where(x => x.IsEnterDoorArea && now >= x.DoorStart && now <= x.DoorEnd && x.DoorStatus == VisitorAppointmentDetailStatusEnumType.Wait)
|
||
.Where(x => SqlFunc.Subqueryable<VisitorAppointmentEntity>().Where(p => p.No == x.No).Where(p => p.Factory == factory).Any())
|
||
.Select(x => new AppointmentDetailResponse
|
||
{
|
||
No = x.No,
|
||
Mst = SqlFunc.Subqueryable<VisitorAppointmentEntity>()
|
||
.LeftJoin<GainfoEntity>((p, ga) => p.Code == ga.Code)
|
||
.Where((p, ga) => p.No == x.No)
|
||
.First((p, ga) => new AppointmentPageResponse
|
||
{
|
||
No = p.No,
|
||
Title = p.Title,
|
||
Code = p.Code,
|
||
Name = ga.Name,
|
||
Source = p.Source,
|
||
Date = p.Date,
|
||
Remark = p.Remark,
|
||
Factory = p.Factory,
|
||
Reason = p.Reason
|
||
}, false)
|
||
}, true)
|
||
.FirstAsync();
|
||
}
|
||
|
||
public async Task FocusLeaveAsync(long id, string reason)
|
||
{
|
||
// 根据访客预约详情ID获取记录,若不存在则抛出异常
|
||
var detail = await _dbContext.Queryable<VisitorAppointmentDetailEntity>().Where(x => x.Id == id).SingleAsync();
|
||
detail.ThrowIfNull("数据不存在");
|
||
|
||
// 如果已进入门区且门区状态为“已到达”,则将门区状态更新为“强制离场”
|
||
if (detail.IsEnterDoorArea && detail.DoorStatus == VisitorAppointmentDetailStatusEnumType.Arrived)
|
||
detail.DoorStatus = VisitorAppointmentDetailStatusEnumType.FocusLeave;
|
||
|
||
// 如果已进入门区且门区状态为“待到达”,则将门区状态更新为“作废”
|
||
if (detail.IsEnterDoorArea && detail.DoorStatus == VisitorAppointmentDetailStatusEnumType.Wait)
|
||
detail.DoorStatus = VisitorAppointmentDetailStatusEnumType.Obsolete;
|
||
|
||
// 如果已进入工作区且工作区状态为“已到达”,则将工作区状态更新为“强制离场”
|
||
if (detail.IsEnterWorkplace && detail.WorkplaceStatus == VisitorAppointmentDetailStatusEnumType.Arrived)
|
||
detail.WorkplaceStatus = VisitorAppointmentDetailStatusEnumType.FocusLeave;
|
||
|
||
// 如果已进入工作区且工作区状态为“待到达”,则将工作区状态更新为“作废”
|
||
if (detail.IsEnterWorkplace && detail.WorkplaceStatus == VisitorAppointmentDetailStatusEnumType.Wait)
|
||
detail.WorkplaceStatus = VisitorAppointmentDetailStatusEnumType.Obsolete;
|
||
|
||
// 记录强制离场时间和原因
|
||
detail.FocusLeaveDateTime = DateTime.Now;
|
||
detail.Remark += "强制离场:" + reason;
|
||
|
||
// 生成设备任务并更新数据库
|
||
await GenerateDeviceTasksAsync(detail, true, DeviceTaskEnumType.Delete, $"强制离场:{reason}");
|
||
await _dbContext.UpdateAsync(detail);
|
||
|
||
try
|
||
{
|
||
var appointment = await _dbContext.Queryable<VisitorAppointmentEntity>().Where(x => x.No == detail.No).SingleAsync();
|
||
await _jinkoApiService.SendWorkMessageAsync(new DingTalkWorkMessageRequest
|
||
{
|
||
WorkCodes = new List<string> { appointment.Code },
|
||
Content = $"您的访客预约《{appointment.Title}》中的访客{detail.Name}已被强制离场,原因:{reason}。"
|
||
});
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "发送访客离场通知失败:{msg}", ex.Message);
|
||
}
|
||
}
|
||
|
||
public async Task<Pagination<AppointmentDetailResponse>> GetRecordPageByIdNoAsync(AppointmentIdNoPageRequest request)
|
||
{
|
||
var protector = _dataProtectionProvider.CreateProtector("gainfo:external:idno");
|
||
try
|
||
{
|
||
request.IdNo = protector.Unprotect(request.IdNo);
|
||
}
|
||
catch (Exception)
|
||
{
|
||
//ignore
|
||
}
|
||
|
||
var page = await _dbContext.Queryable<VisitorAppointmentDetailEntity>()
|
||
.LeftJoin<GainfoEntity>((x, ga) => x.UserNo == ga.No)
|
||
.Where((x, ga) => ga.IdNo == request.IdNo)
|
||
.OrderBy(x => x.CreateTime)
|
||
.Select<AppointmentDetailResponse>()
|
||
.ToPageListAsync(request);
|
||
|
||
return page;
|
||
}
|
||
|
||
|
||
public async Task<List<AppointmentDetailResponse>> GetRecordListAsync(string factory, string search, VisitorAppointmentDetailStatusEnumType? status, DateTime start, DateTime end)
|
||
{
|
||
var now = DateTime.Now;
|
||
var currentDateTime = start.Date.AddHours(now.Hour).AddMinutes(now.Minute);
|
||
|
||
return await _dbContext.Queryable<VisitorAppointmentDetailEntity>()
|
||
.LeftJoin<GainfoEntity>((x, ga) => ga.IdNo == x.IdNo)
|
||
.Where(x => SqlFunc.Subqueryable<VisitorAppointmentEntity>()
|
||
.Where(p => p.No == x.No)
|
||
.Where(p => p.Factory == factory).Any()
|
||
)
|
||
.Where(x => x.IsEnterDoorArea)
|
||
.WhereIF(status.HasValue, x => x.DoorStatus == status)
|
||
.WhereIF(status.HasValue && status == VisitorAppointmentDetailStatusEnumType.Wait, x => currentDateTime >= x.DoorStart && currentDateTime <= x.DoorEnd)
|
||
.WhereIF(status.HasValue && status == VisitorAppointmentDetailStatusEnumType.Arrived, x => currentDateTime >= x.DoorStart && currentDateTime <= x.DoorEnd)
|
||
.WhereIF(!status.HasValue, x => x.DoorStart >= start && x.DoorEnd <= end)
|
||
.WhereIF(search.IsPresent(), x => x.Name.Contains(search) || x.No == search || x.IdNo == search)
|
||
.Select(x => new AppointmentDetailResponse
|
||
{
|
||
No = x.No,
|
||
Mst = SqlFunc.Subqueryable<VisitorAppointmentEntity>()
|
||
.LeftJoin<GainfoEntity>((p, ga) => p.Code == ga.Code)
|
||
.Where((p, ga) => p.No == x.No)
|
||
.First((p, ga) => new AppointmentPageResponse
|
||
{
|
||
No = p.No,
|
||
Title = p.Title,
|
||
Code = p.Code,
|
||
Name = ga.Name,
|
||
Source = p.Source,
|
||
Date = p.Date,
|
||
Remark = p.Remark,
|
||
Factory = p.Factory,
|
||
Reason = p.Reason
|
||
}, false)
|
||
}, true)
|
||
.ToListAsync();
|
||
}
|
||
|
||
|
||
public async Task<AppointmentSummaryResponse> GetSummaryAsync(string factory, DateTime start, DateTime end)
|
||
{
|
||
start = start.Date;
|
||
|
||
var total = await _dbContext.Queryable<VisitorAppointmentDetailEntity>()
|
||
.Where(x => x.IsEnterDoorArea && x.DoorStart >= start && x.DoorStart <= end)
|
||
.Where(x => SqlFunc.Subqueryable<VisitorAppointmentEntity>().Where(p => p.No == x.No).Where(p => p.Factory == factory).Any())
|
||
.CountAsync();
|
||
|
||
var @in = await _dbContext.Queryable<VisitorAppointmentDetailEntity>()
|
||
.Where(x => x.IsEnterDoorArea && x.ArrivedTime >= start && x.ArrivedTime <= end && x.DoorStatus == VisitorAppointmentDetailStatusEnumType.Arrived)
|
||
.Where(x => SqlFunc.Subqueryable<VisitorAppointmentEntity>().Where(p => p.No == x.No).Where(p => p.Factory == factory).Any())
|
||
.CountAsync();
|
||
|
||
var notIn = await _dbContext.Queryable<VisitorAppointmentDetailEntity>()
|
||
.Where(x => x.IsEnterDoorArea && x.DoorStart >= start && x.DoorStart <= end)
|
||
.Where(x => x.IsEnterDoorArea && x.DoorStatus == VisitorAppointmentDetailStatusEnumType.Wait)
|
||
.Where(x => SqlFunc.Subqueryable<VisitorAppointmentEntity>().Where(p => p.No == x.No).Where(p => p.Factory == factory).Any())
|
||
.CountAsync();
|
||
|
||
var leave = await _dbContext.Queryable<VisitorAppointmentDetailEntity>()
|
||
.Where(x => x.IsEnterDoorArea && x.DoorEnd >= start && x.DoorEnd <= end)
|
||
.Where(x => x.IsEnterDoorArea && (x.DoorStatus == VisitorAppointmentDetailStatusEnumType.Leave || x.DoorStatus == VisitorAppointmentDetailStatusEnumType.FocusLeave))
|
||
.Where(x => SqlFunc.Subqueryable<VisitorAppointmentEntity>().Where(p => p.No == x.No).Where(p => p.Factory == factory).Any())
|
||
.CountAsync();
|
||
|
||
var notLeave = await _dbContext.Queryable<VisitorAppointmentDetailEntity>()
|
||
.Where(x => x.IsEnterDoorArea && x.DoorEnd >= start && x.DoorEnd <= end && x.DoorStatus == VisitorAppointmentDetailStatusEnumType.Arrived)
|
||
.Where(x => SqlFunc.Subqueryable<VisitorAppointmentEntity>().Where(p => p.No == x.No).Where(p => p.Factory == factory).Any())
|
||
.CountAsync();
|
||
|
||
return new AppointmentSummaryResponse
|
||
{
|
||
Total = total,
|
||
In = @in,
|
||
NotIn = notIn,
|
||
Leave = leave,
|
||
NotLeave = notLeave
|
||
};
|
||
}
|
||
|
||
|
||
public async Task UpdateFaceAsync(long detailId, string base64)
|
||
{
|
||
var detail = await _dbContext.Queryable<VisitorAppointmentDetailEntity>().Where(x => x.Id == detailId).SingleAsync();
|
||
detail.ThrowIfNull("数据不存在");
|
||
|
||
await UploadFaceToDhAsync(detail.IdNo, base64);
|
||
|
||
await _gainfoFaceService.UploadExternalFaceAsync(new GainfoUploadFaceRequest
|
||
{
|
||
UserNo = detail.IdNo,
|
||
Face = base64
|
||
});
|
||
|
||
await GenerateDeviceTasksAsync(detail, true, DeviceTaskEnumType.Update, "访客手动上传照片");
|
||
}
|
||
|
||
public async Task RecoverAsync()
|
||
{
|
||
var day = new DateTime(2025, 12, 19);
|
||
var gainfoLeaves = await _dbContext.Queryable<GainfoLeaveEntity>()
|
||
.Where(x => x.Type == GainfoUserTypeEnumType.External)
|
||
.Where(x => SqlFunc.DateIsSame(x.ResignationDate, day))
|
||
.ToListAsync();
|
||
|
||
foreach (var gainfoLeave in gainfoLeaves)
|
||
{
|
||
await _dbContext.Client.Ado.BeginTranAsync();
|
||
try
|
||
{
|
||
var gainfo = gainfoLeave.Adapt<GainfoEntity>();
|
||
gainfo.Id = gainfo.IdentityUserId;
|
||
await _dbContext.InsertAsync(gainfo);
|
||
await _dbContext.DeleteReallyAsync(gainfoLeave);
|
||
|
||
var detail = await _dbContext.Queryable<VisitorAppointmentDetailEntity>().Where(x => x.UserNo == gainfo.No).SingleAsync();
|
||
detail.ThrowIfNull("数据不存在");
|
||
|
||
await GenerateDeviceTasksAsync(detail, true, DeviceTaskEnumType.Update, "数据恢复");
|
||
|
||
await _dbContext.Client.Ado.CommitTranAsync();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "恢复外部人员失败:{userNo}", gainfoLeave.No);
|
||
await _dbContext.Client.Ado.RollbackTranAsync();
|
||
}
|
||
}
|
||
}
|
||
|
||
public async Task<List<string>> GetVisitorDevicesAsync(long detailId)
|
||
{
|
||
var detail = await _dbContext.Queryable<VisitorAppointmentDetailEntity>().Where(x => x.Id == detailId).SingleAsync();
|
||
detail.ThrowIfNull("数据不存在");
|
||
|
||
var areaCodes = GetValidAreaCodes(detail, true).ToList();
|
||
if (areaCodes.IsEmpty()) return new List<string>();
|
||
|
||
var existsAreaCodes = await _dbContext.Queryable<AppointmentAreaEntity>().Where(x => areaCodes.Contains(x.CustomCode)).Select(x => x.CustomCode).ToListAsync();
|
||
|
||
//当前分配的设备组code
|
||
var deviceGroupCodes = await _dbContext.Queryable<AppointmentAreaAssignmentEntity>()
|
||
.Where(x => existsAreaCodes.Contains(x.CustomCode))
|
||
.Select(x => x.DeviceGroupCode)
|
||
.ToListAsync();
|
||
|
||
var deviceCodes = await _dbContext.Queryable<DeviceGroupRelationshipEntity>().Where(x => deviceGroupCodes.Contains(x.GroupCode)).Select(x => x.DeviceCode).ToListAsync();
|
||
var deviceUniqueNos = await _dbContext.Queryable<DeviceEntity>().Where(x => deviceCodes.Contains(x.Code)).Select(x => x.UniqueNo).ToListAsync();
|
||
|
||
return deviceUniqueNos;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task AutoResignAsync()
|
||
{
|
||
//获取外部人员
|
||
var externals = await _dbContext.Queryable<GainfoEntity>()
|
||
.Where(x => x.Type == GainfoUserTypeEnumType.External)
|
||
.Where(x => x.Code == "EXT059373")
|
||
.Select(x => new { x.Id, x.Code, x.Factory, x.CreateTime })
|
||
.ToListAsync();
|
||
|
||
var settings = new List<FactorySettingResponse>() { new FactorySettingResponse
|
||
{
|
||
Factory= "502",
|
||
NoRecordAutoResignExternalDays = 3
|
||
} };//await _factorySettingService.GetListAsync(false);
|
||
|
||
//todo 临时处理循环依赖
|
||
var gainfoService = _serviceProvider.GetService<IGainfoService>();
|
||
|
||
var holidaies = await _dbContext
|
||
.Queryable<HolidayEntity>()
|
||
.Select(x => new
|
||
{
|
||
x.Type,
|
||
x.Start,
|
||
x.End
|
||
})
|
||
.ToListAsync();
|
||
|
||
|
||
var weekends = new List<DayOfWeek>() { DayOfWeek.Saturday, DayOfWeek.Sunday };
|
||
//人员分组,key为factory
|
||
foreach (var exts in externals.GroupBy(x => x.Factory))
|
||
{
|
||
//factory的设置
|
||
var setting = settings.First(x => x.Factory == exts.Key);
|
||
if (setting.NoRecordAutoResignExternalDays == 0)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
foreach (var ext in exts)
|
||
{
|
||
// 查询该外部人员最近一次通行记录的时间
|
||
DateTime? raiseDateTime = await _dbContext.Queryable<DeviceUploadLogEntity>()
|
||
.Where(x => x.UserUniqueNo == ext.Code)
|
||
.GroupBy(x => x.UserUniqueNo)
|
||
.Select(x => SqlFunc.IsNull(SqlFunc.AggregateMax(x.RaiseDateTime), default(DateTime?)))
|
||
.SingleAsync();
|
||
|
||
// 如果最近通行时间存在且超出未通行天数阈值,则自动归档该外部人员
|
||
if (raiseDateTime.HasValue)
|
||
{
|
||
var checkDates = GetDaysUntilToday(raiseDateTime.Value);
|
||
var days = checkDates.Count;
|
||
foreach (var date in checkDates)
|
||
{
|
||
//date.DayOfWeek
|
||
foreach (var holiday in holidaies)
|
||
{
|
||
var isPresent = date >= holiday.Start && date <= holiday.Start;
|
||
if (isPresent)
|
||
{
|
||
if (holiday.Type == HolidayEnumType.Rest)
|
||
{
|
||
days--;
|
||
}
|
||
}
|
||
}
|
||
if (weekends.Contains(date.DayOfWeek))
|
||
{
|
||
days--;
|
||
}
|
||
}
|
||
|
||
if (days >= setting.NoRecordAutoResignExternalDays)
|
||
{
|
||
try
|
||
{
|
||
await gainfoService.ResignAsync(new GainfoResignRequest
|
||
{
|
||
Id = ext.Id,
|
||
Reason = $"{setting.NoRecordAutoResignExternalDays}天无通行记录",
|
||
Date = DateTime.Now
|
||
});
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
// 记录自动归档异常日志
|
||
_logger.LogError(e, "自动归档外部人员异常:{msg}", e.Message);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
//*********************************************************************************************************************
|
||
|
||
private List<DateOnly> GetDaysUntilToday(DateTime begin)
|
||
{
|
||
var start = DateOnly.FromDateTime(begin.Date);
|
||
var today = DateOnly.FromDateTime(DateTime.Today);
|
||
if (start > today) return new List<DateOnly>();
|
||
|
||
var days = new List<DateOnly>();
|
||
for (var d = start; d < today; d = d.AddDays(1))
|
||
{
|
||
days.Add(d);
|
||
}
|
||
|
||
return days;
|
||
}
|
||
|
||
|
||
private async Task GenerateDeviceTasksAsync(VisitorAppointmentDetailEntity detail, bool withWorkplace, DeviceTaskEnumType deviceTaskType, string source)
|
||
{
|
||
var gainfo = await _dbContext.Queryable<GainfoEntity>().Where(x => x.IdNo == detail.IdNo || x.Code == detail.IdNo).SingleAsync();
|
||
gainfo.ThrowIfNull("人员信息不存在");
|
||
|
||
var areaCodes = GetValidAreaCodes(detail, withWorkplace).ToList();
|
||
if (areaCodes.IsEmpty()) return;
|
||
|
||
var existsAreaCodes = await _dbContext.Queryable<AppointmentAreaEntity>().Where(x => areaCodes.Contains(x.CustomCode)).Select(x => x.CustomCode).ToListAsync();
|
||
|
||
//当前分配的设备组code
|
||
var deviceGroupCodes = await _dbContext.Queryable<AppointmentAreaAssignmentEntity>()
|
||
.Where(x => existsAreaCodes.Contains(x.CustomCode))
|
||
.Select(x => x.DeviceGroupCode)
|
||
.ToListAsync();
|
||
|
||
var deviceCodes = await _dbContext.Queryable<DeviceGroupRelationshipEntity>().Where(x => deviceGroupCodes.Contains(x.GroupCode)).Select(x => x.DeviceCode).ToListAsync();
|
||
var deviceUniqueNos = await _dbContext.Queryable<DeviceEntity>().Where(x => deviceCodes.Contains(x.Code)).Select(x => new { x.UniqueNo, x.TenantId }).ToListAsync();
|
||
|
||
await _dbContext.InsertAsync(deviceUniqueNos.Select(x => new DeviceTaskEntity
|
||
{
|
||
DeviceType = DeviceTypeEnumType.Door,
|
||
DeviceUniqueNo = x.UniqueNo,
|
||
Status = DeviceTaskStatusEnumType.Wait,
|
||
UserNo = gainfo.No,
|
||
Type = deviceTaskType,
|
||
Priority = 100,
|
||
TenantId = x.TenantId,
|
||
Source = source,
|
||
Version = 0
|
||
}).ToList());
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取有效的区域编码
|
||
/// </summary>
|
||
/// <param name="detail"></param>
|
||
/// <param name="withWorkplace"></param>
|
||
/// <returns></returns>
|
||
private static IEnumerable<string> GetValidAreaCodes(VisitorAppointmentDetailEntity detail, bool withWorkplace)
|
||
{
|
||
if (detail.IsEnterDoorArea)
|
||
{
|
||
yield return detail.ApplyDoorArea;
|
||
}
|
||
|
||
if (withWorkplace && detail.IsEnterWorkplace)
|
||
{
|
||
foreach (var item in detail.ApplyWorkplaceAreas)
|
||
{
|
||
yield return item;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
private async Task UploadFaceToDhAsync(string idNo, string base64Image)
|
||
{
|
||
try
|
||
{
|
||
var r = await _dhApi.SendFaceAsync(new FaceRequest
|
||
{
|
||
IdNo = idNo,
|
||
Face = base64Image
|
||
});
|
||
|
||
_logger.LogInformation("上传face数据到大华成功: {idNo} . {json}", idNo, r.ToJson());
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
_logger.LogError(e, "上传face数据到大华失败:{msg}", e.Message);
|
||
}
|
||
}
|
||
} |