151 lines
6.1 KiB
C#
151 lines
6.1 KiB
C#
using Dlhis.Entity.Basic.Entity;
|
||
using Dlhis.Entity.Device.Entities;
|
||
using Dlhis.Entity.Device.Enums;
|
||
using Dlhis.Entity.Visitor.Entity;
|
||
using Dlhis.Entity.Visitor.Enums;
|
||
using Dlhis.ScheduledTask.Attributes;
|
||
|
||
namespace Dlhis.ScheduledTask.Jobs.Visitor;
|
||
|
||
|
||
/// <summary>
|
||
/// 定时任务:每5分钟执行一次,自动处理访客预约车间相关逻辑。
|
||
/// </summary>
|
||
[RecurringJob(nameof(AutoConfirmAppointmentJob), "0 0/5 * * * ?", Name = "访客预约自动处理车间")]
|
||
public class AutoConfirmAppointmentJob : BaseJob
|
||
{
|
||
// 构造函数,注入服务提供者
|
||
public AutoConfirmAppointmentJob(IServiceProvider serviceProvider) : base(serviceProvider)
|
||
{
|
||
}
|
||
|
||
// 定时任务主逻辑
|
||
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 = gainfos.FirstOrDefault(x => x.IdNo.Equals(detail.IdNo, StringComparison.OrdinalIgnoreCase) || x.Code.Equals(detail.IdNo, StringComparison.OrdinalIgnoreCase));
|
||
if (gainfo == null) continue;
|
||
|
||
// 获取当前明细的有效区域编码
|
||
var existsAreaCodes = detailsWithValidAreaCodesDict[detail.Id];
|
||
if (!existsAreaCodes.Any()) continue;
|
||
|
||
// 查询区域下的设备信息
|
||
var deviceInfos = await GetDeviceUniqueNoAndTenantIdAsync(existsAreaCodes);
|
||
if (deviceInfos?.Any() != true)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
// 生成设备任务
|
||
deviceTaskList.AddRange(deviceInfos.Select(x => new DeviceTaskEntity
|
||
{
|
||
DeviceType = DeviceTypeEnumType.Door,
|
||
DeviceUniqueNo = x.UniqueNo,
|
||
Status = DeviceTaskStatusEnumType.Wait,
|
||
UserNo = gainfo.No,
|
||
Type = DeviceTaskEnumType.Add,
|
||
Priority = 100,
|
||
TenantId = x.TenantId,
|
||
Source = "定时任务判断触发车间下发任务",
|
||
Version = 0
|
||
}));
|
||
|
||
// 更新预约明细状态
|
||
if (detail.WorkplaceStatus != VisitorAppointmentDetailStatusEnumType.Wait) continue;
|
||
|
||
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);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取预约明细的有效区域编码
|
||
/// </summary>
|
||
/// <param name="detail"></param>
|
||
/// <returns></returns>
|
||
private static List<string> GetValidAreaCodes(VisitorAppointmentDetailEntity detail)
|
||
{
|
||
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();
|
||
}
|
||
}
|