Files
jinko.yikatong/Src/Dlhis.ScheduledTask/Jobs/AutoConfirmAppointmentJob.cs
2025-06-30 14:11:34 +08:00

151 lines
6.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
/// <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 == 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;
}
// 生成设备任务
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();
}
}