@@ -1,5 +1,4 @@
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 ;
@@ -8,51 +7,70 @@ using Dlhis.ScheduledTask.Attributes;
namespace Dlhis.ScheduledTask.Jobs ;
/// <summary>
/// 访客预约移除
/// 定时任务: 每5分钟执行一次, 自动处理访客预约车间相关逻辑。
/// </summary>
[RecurringJob(nameof(AutoConfirmAppointmentJob), "0 0/5 * * * ?", Name = "访客预约自动处理车间")]
public class AutoConfirmAppointmentJob : BaseJob
{
/ // <inheritdoc />
// 构造函数,注入服务提供者
public AutoConfirmAppointmentJob ( IServiceProvider serviceProvider ) : base ( serviceProvider )
{
}
/ // <inheritdoc />
// 定时任务主逻辑
protected override async Task RunAsync ( IServiceProvider serviceProvider )
{
// 查询所有需要自动处理的访客预约明细
var details = await DbContext . Queryable < VisitorAppointmentDetailEntity > ( )
. Where ( x = > x . IsEnterDoorArea = = false | | ( x . IsEnterDoorArea & & x . DoorStatus = = VisitorAppointmentDetailStatusEnumType . Arrived ) )
. Where ( x = > x . IsEnterWorkplace & & x . WorkplaceStatus = = VisitorAppointmentDetailStatusEnumType . Wait & & DateTime . Now > = x . WorkplaceStart )
. ToListAsync ( ) ;
// 获取所有相关证件号
var idNos = details . Select ( x = > x . IdNo ) . Distinct ( ) . ToList ( ) ;
// 查询访客信息
var gainfos = await DbContext . Queryable < GainfoEntity > ( )
. Where ( x = > idNos . Contains ( x . IdNo ) | | idNos . Contains ( x . Code ) )
. ToListAsync ( ) ;
// 批量获取所有有效区域编码,避免循环中多次查库
var allValidAreaCodes = details . SelectMany ( GetValidAreaCodes ) . Distinct ( ) . ToList ( ) ;
// 查询所有有效区域编码
var allAreaCodes = await DbContext . Queryable < AppointmentAreaEntity > ( )
. Where ( x = > allValidAreaCodes . Contains ( x . CustomCode ) )
. Select ( x = > x . CustomCode )
. ToListAsync ( ) ;
// 预先缓存每个detail的有效区域编码, 减少循环内重复计算
var detailsWithValidAreaCodesDict = details . ToDictionary (
x = > x . Id ,
x = > GetValidAreaCodes ( x ) . Intersect ( allAreaCodes ) . ToList ( )
) ;
var deviceTaskList = new List < DeviceTaskEntity > ( ) ; // 设备任务列表
var updateDetails = new List < VisitorAppointmentDetailEntity > ( ) ; // 需要更新的预约明细
foreach ( var detail in details )
{
var gainfo = await DbContext . Queryable < GainfoEntity > ( ) . Where ( x = > x . IdNo = = detail . IdNo | | x . Code = = detail . IdNo ) . SingleAsync ( ) ;
if ( gainfo = = null )
// 查找对应访客信息
var gainfo = gainfos . FirstOrDefault ( x = > x . IdNo = = detail . IdNo | | x . Code = = detail . IdNo ) ;
if ( gainfo = = null ) continue ;
// 获取当前明细的有效区域编码
var existsAreaCodes = detailsWithValidAreaCodesDict [ detail . Id ] ;
if ( ! existsAreaCodes . Any ( ) ) continue ;
// 查询区域下的设备信息
var deviceInfos = await GetDeviceUniqueNoAndTenantIdAsync ( existsAreaCodes ) ;
if ( deviceInfos ? . Any ( ) ! = true )
{
continue ;
}
var areaCodes = GetValidAreaCodes ( detail ) . ToList ( ) ;
if ( ! areaCodes . Any ( ) )
{
continue ;
}
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
// 生成设备任务
deviceTaskList . AddRange ( deviceInfos . Select ( x = > new DeviceTaskEntity
{
DeviceType = DeviceTypeEnumType . Door ,
DeviceUniqueNo = x . UniqueNo ,
@@ -63,20 +81,70 @@ public class AutoConfirmAppointmentJob : BaseJob
TenantId = x . TenantId ,
Source = "定时任务判断触发车间下发任务" ,
Version = 0
} ) . ToList ( ) );
} ) ) ;
if ( detail . WorkplaceStatus = = VisitorAppointmentDetailStatusEnumType . Wait )
{
detail . WorkplaceStatus = VisitorAppointmentDetailStatusEnumType . Arrived ;
}
// 更新预约明细状态
if ( detail . WorkplaceStatus ! = VisitorAppointmentDetailStatusEnumType . Wait ) continue ;
await DbContext . UpdateAsync ( detail ) ;
detail . WorkplaceStatus = VisitorAppointmentDetailStatusEnumType . Arrived ;
updateDetails . Add ( detail ) ;
}
// 事务提交设备任务和明细状态更新
var r = await DbContext . Client . Ado . UseTranAsync ( async ( ) = >
{
if ( deviceTaskList . Any ( ) )
await DbContext . InsertAsync ( deviceTaskList ) ;
if ( updateDetails . Any ( ) )
await DbContext . UpdateAsync ( updateDetails ) ;
} ) ;
// 记录失败日志
if ( ! r . IsSuccess )
{
Logger . LogError ( r . ErrorException , "执行访客预约自动处理车间任务失败:{error}" , r . ErrorMessage ) ;
}
}
private static IEnumerable < string > GetValidAreaCodes ( VisitorAppointmentDetailEntity detail )
/// <summary>
/// 获取预约明细的有效区域编码
/// </summary>
/// <param name="detail"></param>
/// <returns></returns>
private static List < string > GetValidAreaCodes ( VisitorAppointmentDetailEntity detail )
{
return detail . ApplyWorkplaceAreas ;
return detail . ApplyWorkplaceAreas ? ? new List < string > ( ) ;
}
}
/// <summary>
/// 根据区域编码获取设备唯一编号和租户ID
/// </summary>
/// <param name="existsAreaCodes"></param>
/// <returns></returns>
private async Task < List < ( string UniqueNo , string TenantId ) > > GetDeviceUniqueNoAndTenantIdAsync ( List < string > existsAreaCodes )
{
// 当前分配的设备组code
var deviceGroupCodes = await DbContext . Queryable < AppointmentAreaAssignmentEntity > ( )
. Where ( x = > existsAreaCodes . Contains ( x . CustomCode ) )
. Select ( x = > x . DeviceGroupCode )
. ToListAsync ( ) ;
if ( ! deviceGroupCodes . Any ( ) ) return null ;
// 查询设备组下的设备编码
var deviceCodes = await DbContext . Queryable < DeviceGroupRelationshipEntity > ( )
. Where ( x = > deviceGroupCodes . Contains ( x . GroupCode ) )
. Select ( x = > x . DeviceCode )
. ToListAsync ( ) ;
if ( ! deviceCodes . Any ( ) ) return null ;
// 查询设备唯一编号和租户ID
var deviceUniqueNos = await DbContext . Queryable < DeviceEntity > ( )
. Where ( x = > deviceCodes . Contains ( x . Code ) )
. Select ( x = > new { x . UniqueNo , x . TenantId } )
. ToListAsync ( ) ;
return ! deviceUniqueNos . Any ( )
? null
: deviceUniqueNos . Select ( x = > ( x . UniqueNo , x . TenantId ) ) . ToList ( ) ;
}
}