463 lines
21 KiB
C#
463 lines
21 KiB
C#
using Dlhis.Entity.Basic.Entity;
|
|
using Dlhis.Entity.Device.Entities;
|
|
using Dlhis.Entity.Device.Enums;
|
|
using Dlhis.Entity.Device.Models;
|
|
using Dlhis.ScheduledTask.TaskAssignment.Request;
|
|
using Dlhis.ScheduledTask.TaskAssignment.Response;
|
|
using Kurisu.AspNetCore.Utils.Extensions;
|
|
using Microsoft.AspNetCore.DataProtection;
|
|
using Microsoft.Extensions.Options;
|
|
using SqlSugar;
|
|
using Newtonsoft.Json.Linq;
|
|
using Kurisu.AspNetCore.Utils;
|
|
using Dlhis.ScheduledTask.TaskAssignment.Dto;
|
|
using Kurisu.AspNetCore.CustomClass;
|
|
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
|
|
|
|
namespace Dlhis.ScheduledTask.TaskAssignment.Services.Implements;
|
|
|
|
public class AssignmentService : IAssignmentService
|
|
{
|
|
private readonly IDbContext _dbContext;
|
|
private readonly IDataProtectionProvider _dataProtectionProvider;
|
|
private readonly ILogger<AssignmentService> _logger;
|
|
private readonly FaceUrlOptions _faceUrlOptions;
|
|
|
|
public AssignmentService(IDbContext dbContext,
|
|
IDataProtectionProvider dataProtectionProvider,
|
|
IOptions<FaceUrlOptions> options,
|
|
ILogger<AssignmentService> logger)
|
|
{
|
|
_dbContext = dbContext;
|
|
_dataProtectionProvider = dataProtectionProvider;
|
|
_logger = logger;
|
|
_faceUrlOptions = options.Value;
|
|
}
|
|
|
|
public async Task<List<DeviceTaskToDeviceByDeviceResponse>> DeviceGetTasksAsync(DeviceTaskGetRequest request)
|
|
{
|
|
var data = await GetDataAsync(request);
|
|
if (data.IsEmpty()) return new List<DeviceTaskToDeviceByDeviceResponse>();
|
|
|
|
await HandlerOldDeviceGainfoAsync(data);
|
|
await HandlerTimePeriodAsync(data);
|
|
var deviceUploadInfos = await GetDeviceUploadRecordInfosAsync(data);
|
|
|
|
var timeLimitedDataProtector = _dataProtectionProvider
|
|
.CreateProtector("down:face")
|
|
.ToTimeLimitedDataProtector();
|
|
|
|
return data.GroupBy(x => new { x.DeviceUniqueNo, x.DeviceConnectionInfo, x.FuncStr })
|
|
.Select(x =>
|
|
{
|
|
var d = x.Key.DeviceUniqueNo;
|
|
var dc = x.Key.DeviceConnectionInfo ?? "{}";
|
|
var func = x.Key.FuncStr ?? "[]";
|
|
|
|
var jObj = new JObject
|
|
{
|
|
{ "connectionInfo", JToken.Parse(dc) },
|
|
{ "function", JArray.Parse(func) }
|
|
};
|
|
|
|
return new DeviceTaskToDeviceByDeviceResponse
|
|
{
|
|
DeviceUniqueNo = d,
|
|
DeviceInfo = jObj,
|
|
Tasks = x.Select(item =>
|
|
{
|
|
var key = $"face:{item.UserCode}";
|
|
var token = item.Type == DeviceTaskEnumType.Delete
|
|
? string.Empty
|
|
: timeLimitedDataProtector.Protect(key, TimeSpan.FromSeconds(_faceUrlOptions.Limit));
|
|
|
|
var dto = new TaskCombineDto
|
|
{
|
|
TaskId = item.TaskId,
|
|
Type = item.Type,
|
|
};
|
|
|
|
switch (dto.Type)
|
|
{
|
|
case DeviceTaskEnumType.Add:
|
|
case DeviceTaskEnumType.Delete:
|
|
case DeviceTaskEnumType.Update:
|
|
{
|
|
dto.Info = new UserToDeviceResponse
|
|
{
|
|
UserId = item.UserId ?? 0,
|
|
UserNo = item.UserNo,
|
|
OldUserNo = item.OldUserNo,
|
|
UserCode = item.UserCode,
|
|
UserType = item.UserType,
|
|
UserName = item.UserName,
|
|
DepartmentNo = item.DepartmentNo,
|
|
DepartmentName = item.DepartmentName,
|
|
CardNo = item.CardNo,
|
|
Face = item.Type == DeviceTaskEnumType.Delete ? string.Empty : _faceUrlOptions.Url + token, //下发才附带照片信息
|
|
ValidDatePeriod = new DatePeriod
|
|
{
|
|
Start = DateOnly.FromDateTime(DateTime.Now.AddDays(-1)),
|
|
End = DateOnly.FromDateTime(DateTime.Now.AddYears(20)),
|
|
},
|
|
TimePeriods = new List<int> { item.CardType },
|
|
Doors = new List<int> { 1 },
|
|
Schedule = 1
|
|
};
|
|
}
|
|
break;
|
|
case DeviceTaskEnumType.TimePeriodAdd:
|
|
case DeviceTaskEnumType.TimePeriodDelete:
|
|
{
|
|
dto.Info = item.TimePeriods.Select(t => new TimePeriodToDeviceResponse
|
|
{
|
|
Id = t.CardType,
|
|
Name = t.CardName,
|
|
Enable = item.EnableTimePeriod,
|
|
Sections = t.Sections.Select(s => new TimePeriodWeekDaySection
|
|
{
|
|
DayOfWeek = s.DayOfWeek,
|
|
TimePeriods = s.TimePeriods.Select(p => new DeviceTimePeriod
|
|
{
|
|
Enable = p.Enable,
|
|
Start = p.Enable ? p.Start : new TimeOnly(00, 00, 00),
|
|
End = p.Enable ? p.End : new TimeOnly(00, 00, 00)
|
|
}).ToList()
|
|
}).ToList()
|
|
});
|
|
}
|
|
break;
|
|
case DeviceTaskEnumType.ScheduleAdd:
|
|
case DeviceTaskEnumType.ScheduleDelete:
|
|
{
|
|
dto.Info = new ScheduleToDeviceResponse
|
|
{
|
|
Id = 1,
|
|
Enable = true,
|
|
Name = "计划的一部分",
|
|
Schedules = new List<ScheduleDto>
|
|
{
|
|
new()
|
|
{
|
|
Name = "国庆节",
|
|
DateTimePeriod = new DateTimePeriod
|
|
{
|
|
Start = new DateTime(2024, 10, 1),
|
|
End = new DateTime(2024, 10, 7)
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
break;
|
|
|
|
case DeviceTaskEnumType.UploadRecord:
|
|
{
|
|
var timeInfo = deviceUploadInfos[d];
|
|
dto.Info = new UploadRecordToDeviceResponse
|
|
{
|
|
DateTimePeriod = new DateTimePeriod
|
|
{
|
|
Start = timeInfo.Item1,
|
|
End = timeInfo.Item2
|
|
}
|
|
};
|
|
}
|
|
break;
|
|
}
|
|
|
|
return dto;
|
|
}).ToList()
|
|
};
|
|
}).ToList();
|
|
}
|
|
|
|
|
|
public async Task UpdateDeviceTaskStatusAsync(List<UpdateDeviceTaskStatusRequest> requests)
|
|
{
|
|
var taskIds = requests.Select(x => x.TaskId).ToList();
|
|
var deviceTasks = await _dbContext.Queryable<DeviceTaskEntity>()
|
|
.Where(x => taskIds.Contains(x.Id))
|
|
.Where(x => x.Status == DeviceTaskStatusEnumType.Process)
|
|
.ToListAsync();
|
|
|
|
var now = DateTime.Now;
|
|
|
|
deviceTasks.ForEach(task =>
|
|
{
|
|
var callbackMessage = requests.First(x => x.TaskId == task.Id);
|
|
|
|
task.Status = callbackMessage.IsSuccess ? DeviceTaskStatusEnumType.Success : DeviceTaskStatusEnumType.Error;
|
|
task.ResultMessage = callbackMessage.ResultMessage;
|
|
task.ModifiedTime = now;
|
|
});
|
|
|
|
if (await _dbContext.Queryable<OldDeviceGainfoEntity>().Where(x => x.Status != OldDeviceGainfoEnumType.Deleted).AnyAsync())
|
|
{
|
|
var dCodes = await _dbContext.Queryable<DeviceTaskEntity>()
|
|
.LeftJoin<GainfoEntity>((x, ga) => x.UserNo == ga.No)
|
|
.Where(x => taskIds.Contains(x.Id))
|
|
.Where(x => x.Status == DeviceTaskStatusEnumType.Process)
|
|
.Select((x, ga) => new
|
|
{
|
|
x.DeviceUniqueNo,
|
|
ga.Code,
|
|
ga.No
|
|
})
|
|
.ToListAsync();
|
|
|
|
var oldDeviceGainfoWhere = LinqExpressionExtensions.False<OldDeviceGainfoEntity>();
|
|
dCodes.ForEach(item => { oldDeviceGainfoWhere = oldDeviceGainfoWhere.Or(x => x.Code == item.Code && x.DeviceUniqueNo == item.DeviceUniqueNo); });
|
|
var oldData = await _dbContext.Queryable<OldDeviceGainfoEntity>().Where(x => x.Status == OldDeviceGainfoEnumType.Wait)
|
|
.Where(oldDeviceGainfoWhere)
|
|
.ToListAsync();
|
|
|
|
oldData.ForEach(d =>
|
|
{
|
|
var current = dCodes.FirstOrDefault(x => x.Code == d.Code);
|
|
if (current != null)
|
|
{
|
|
var task = deviceTasks.FirstOrDefault(x => x.UserNo == current.No && x.DeviceUniqueNo == current.DeviceUniqueNo);
|
|
if (task != null)
|
|
{
|
|
d.Status = task.Status == DeviceTaskStatusEnumType.Success
|
|
? OldDeviceGainfoEnumType.Deleted
|
|
: OldDeviceGainfoEnumType.Error;
|
|
|
|
d.Remark = task.ResultMessage;
|
|
}
|
|
}
|
|
});
|
|
|
|
await _dbContext.UpdateAsync(oldData);
|
|
}
|
|
|
|
|
|
await _dbContext.UpdateAsync(deviceTasks);
|
|
}
|
|
|
|
|
|
//**************************************************** help method **************************************************
|
|
|
|
private async Task<List<TaskDto>> GetDataAsync(DeviceTaskGetRequest request)
|
|
{
|
|
var data = await CommonHelper.RetryAsync(async () =>
|
|
{
|
|
var rows = await _dbContext.Queryable<DeviceTaskEntity>()
|
|
.LeftJoin<DeviceEntity>((deviceTask, device) => deviceTask.DeviceUniqueNo == device.UniqueNo)
|
|
.LeftJoin<GainfoEntity>((deviceTask, device, ga) => deviceTask.UserNo == ga.No)
|
|
.LeftJoin<GainfoLeaveEntity>((deviceTask, device, ga, gaLeave) => deviceTask.UserNo == gaLeave.No)
|
|
.LeftJoin<DepartmentEntity>((deviceTask, device, ga, gaLeave, department) => department.No == ga.DepartmentNo)
|
|
.LeftJoin<DeviceRegistryEntity>((deviceTask, device, ga, gaLeave, department, deviceRegistry) => deviceRegistry.DeviceUniqueNo == deviceTask.DeviceUniqueNo)
|
|
.Where((deviceTask, device) => device.Enable)
|
|
.WhereIF(!request.IsProcess, deviceTask => deviceTask.Status == DeviceTaskStatusEnumType.Wait)
|
|
.WhereIF(request.IsProcess, deviceTask => deviceTask.Status == DeviceTaskStatusEnumType.Process
|
|
&& SqlFunc.DateDiff(DateType.Minute, deviceTask.ModifiedTime, DateTime.Now) > 10)
|
|
.WhereIF(request.DeviceUniqueNo.IsPresent(), (deviceTask, device) => deviceTask.DeviceUniqueNo == request.DeviceUniqueNo)
|
|
.WhereIF(request.Types.IsPresent(), deviceTask => request.Types.Contains(deviceTask.Type))
|
|
.Where((deviceTask, device) => deviceTask.Version < 10)
|
|
#if !DEBUG
|
|
.Where((deviceTask, device, ga, gaLeave, department, deviceRegistry) =>
|
|
device.HeartbeatInterval == 0 || SqlFunc.DateAdd(deviceRegistry.LastHeartbeatTime, device.HeartbeatInterval, DateType.Second) > DateTime.Now)
|
|
#endif
|
|
.OrderBy(deviceTask => new { deviceTask.CreateTime, Priority = SqlFunc.Desc(deviceTask.Priority) })
|
|
.Select((deviceTask, device, ga, gaLeave, department) => new TaskDto
|
|
{
|
|
UserId = deviceTask.UserId == 0 || deviceTask.UserId == null
|
|
? ga.Id == 0
|
|
? gaLeave.IdentityUserId
|
|
: ga.Id
|
|
: deviceTask.UserId,
|
|
TaskId = deviceTask.Id,
|
|
Type = deviceTask.Type,
|
|
UserType = ga.Type,
|
|
DeviceUniqueNo = deviceTask.DeviceUniqueNo,
|
|
DeviceConnectionInfo = device.ConnectionInfo,
|
|
FuncStr = device.Funcs.ToString(),
|
|
UserNo = deviceTask.UserNo,
|
|
UserCode = SqlFunc.IsNull(SqlFunc.IsNull(ga.Code, gaLeave.Code), deviceTask.UserNo),
|
|
UserName = SqlFunc.IsNull(ga.Name, gaLeave.Name),
|
|
DepartmentNo = ga.DepartmentNo,
|
|
DepartmentName = department.Name,
|
|
CardNo = ga.CardNo,
|
|
Version = deviceTask.Version,
|
|
Status = deviceTask.Status,
|
|
EnableTimePeriod = device.EnableTimePeriod,
|
|
CardType = device.EnableTimePeriod
|
|
? SqlFunc.IsNullOrEmpty(ga.CardType)
|
|
? 1
|
|
: SqlFunc.ToInt32(ga.CardType)
|
|
: 1
|
|
})
|
|
.ToPageListAsync(request.PageIndex, request.PageSize);
|
|
|
|
if (!rows.Any())
|
|
{
|
|
return rows;
|
|
}
|
|
|
|
var taskIdVs = rows.Select(x => new { x.TaskId, x.Version, x.Status }).ToList();
|
|
var where = LinqExpressionExtensions.False<DeviceTaskEntity>();
|
|
taskIdVs.ForEach(p => { where = where.Or(x => x.Id == p.TaskId && x.Version == p.Version && x.Status == p.Status); });
|
|
|
|
var effect = await _dbContext.Updateable<DeviceTaskEntity>()
|
|
.SetColumns(x => x.Version == x.Version + 1)
|
|
.SetColumns(x => x.Status == DeviceTaskStatusEnumType.Process)
|
|
.SetColumns(x => x.ModifiedTime == DateTime.Now)
|
|
.Where(where)
|
|
.ExecuteCommandAsync();
|
|
|
|
if (taskIdVs.Count != effect)
|
|
{
|
|
throw new VersionExceptions("version exceptions");
|
|
}
|
|
|
|
return rows;
|
|
}, 5);
|
|
|
|
return data;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 处理获取上传记录的任务
|
|
/// </summary>
|
|
/// <param name="data"></param>
|
|
/// <returns></returns>
|
|
private async Task<Dictionary<string, (DateTime, DateTime)>> GetDeviceUploadRecordInfosAsync(List<TaskDto> data)
|
|
{
|
|
if (data.All(x => x.Type != DeviceTaskEnumType.UploadRecord))
|
|
{
|
|
return new Dictionary<string, (DateTime, DateTime)>();
|
|
}
|
|
|
|
var deviceNos = data.Select(x => x.DeviceUniqueNo).Distinct().ToList();
|
|
var result = new Dictionary<string, (DateTime, DateTime)>(deviceNos.Count);
|
|
|
|
var manualSettings = await _dbContext.Queryable<DeviceUploadLogManuallyEntity>().Where(x => deviceNos.Contains(x.DeviceNo))
|
|
.Where(x => x.IsFinished == false)
|
|
.OrderBy(x => x.CreateTime)
|
|
.Select(x => new { x.Id, x.DeviceNo, x.Start, x.End })
|
|
.ToListAsync();
|
|
|
|
var logInfos = await _dbContext.Queryable<DeviceUploadLogEntity>()
|
|
.GroupBy(x => x.DeviceUniqueNo)
|
|
.Select(x => new
|
|
{
|
|
x.DeviceUniqueNo,
|
|
RaiseDateTime = SqlFunc.AggregateMax(x.RaiseDateTime)
|
|
})
|
|
.ToListAsync();
|
|
|
|
var commonEnd = DateTime.Now.AddDays(1);
|
|
foreach (var item in deviceNos)
|
|
{
|
|
var setting = manualSettings.FirstOrDefault(x => x.DeviceNo == item);
|
|
if (setting != null)
|
|
{
|
|
result.Add(item, (setting.Start, setting.End));
|
|
}
|
|
else
|
|
{
|
|
var logInfo = logInfos.FirstOrDefault(x => x.DeviceUniqueNo == item);
|
|
result.Add(item, logInfo == null ? (DateTime.Now.AddMinutes(-10), commonEnd) : (logInfo.RaiseDateTime, commonEnd));
|
|
}
|
|
}
|
|
|
|
//更新为已处理
|
|
await _dbContext.Updateable<DeviceUploadLogManuallyEntity>()
|
|
.SetColumns(x => x.IsFinished == true)
|
|
.Where(x => manualSettings.Select(p => p.Id).Contains(x.Id))
|
|
.ExecuteCommandAsync();
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 处理老档案数据
|
|
/// </summary>
|
|
/// <param name="data"></param>
|
|
private async Task HandlerOldDeviceGainfoAsync(List<TaskDto> data)
|
|
{
|
|
if (await _dbContext.Queryable<OldDeviceGainfoEntity>().Where(x => x.Status != OldDeviceGainfoEnumType.Deleted).AnyAsync())
|
|
{
|
|
var oldDeviceGainfoWhere = LinqExpressionExtensions.False<OldDeviceGainfoEntity>();
|
|
data.ForEach(item => { oldDeviceGainfoWhere = oldDeviceGainfoWhere.Or(x => x.Code == item.UserCode && x.DeviceUniqueNo == item.DeviceUniqueNo); });
|
|
var oldData = await _dbContext.Queryable<OldDeviceGainfoEntity>()
|
|
.Where(x => x.Status == OldDeviceGainfoEnumType.Wait || x.Status == OldDeviceGainfoEnumType.Error)
|
|
.Where(oldDeviceGainfoWhere)
|
|
.ToListAsync();
|
|
|
|
data.ForEach(item =>
|
|
{
|
|
var o = oldData.FirstOrDefault(x => x.Code == item.UserCode && x.DeviceUniqueNo == item.DeviceUniqueNo);
|
|
if (o != null)
|
|
item.OldUserNo = o.No;
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
private async Task HandlerTimePeriodAsync(List<TaskDto> data)
|
|
{
|
|
try
|
|
{
|
|
var tasks = data.Where(x => x.Type is DeviceTaskEnumType.TimePeriodAdd or DeviceTaskEnumType.TimePeriodDelete).ToList();
|
|
if (tasks.IsEmpty()) return;
|
|
var deviceUniqueNos = tasks.Select(x => x.DeviceUniqueNo).ToList();
|
|
|
|
var devices = await _dbContext.Queryable<DeviceEntity>().Where(x => deviceUniqueNos.Contains(x.UniqueNo)).ToListAsync();
|
|
var templateCodes = devices.Select(x => new { x.TenantId, x.TemplateCode }).DistinctBy(x => new { x.TenantId, x.TemplateCode }).ToList();
|
|
var deviceCodes = devices.Select(x => x.Code).Distinct().ToList();
|
|
|
|
var where = LinqExpressionExtensions.False<DeviceTimePeriodEntity>();
|
|
where = where.Or(x => x.AssignType == DeviceTimePeriodAssignEnumType.Device && deviceCodes.Contains(x.Value));
|
|
foreach (var template in templateCodes)
|
|
{
|
|
where = where.Or(x => x.AssignType == DeviceTimePeriodAssignEnumType.Template && x.Value == template.TemplateCode && x.TenantId == template.TenantId);
|
|
}
|
|
|
|
var settings = await _dbContext.Queryable<DeviceTimePeriodEntity>()
|
|
.Where(where)
|
|
.Select<DeviceTimePeriodDto>()
|
|
.ToListAsync();
|
|
|
|
var basicTypes = await _dbContext.Queryable<BasicTypeEntity>().Where(x => x.Type == "timeperiod").ToListAsync();
|
|
settings.ForEach(x => x.CardName = basicTypes.FirstOrDefault(p => p.Code == x.CardType.ToString())?.Display);
|
|
|
|
foreach (var item in data)
|
|
{
|
|
var device = devices.FirstOrDefault(x => x.UniqueNo == item.DeviceUniqueNo);
|
|
if (device == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var templateCode = device.TemplateCode;
|
|
var code = device.Code;
|
|
|
|
var tSettings = settings.Where(x => x.AssignType == DeviceTimePeriodAssignEnumType.Template && x.TenantId == device.TenantId)
|
|
.Where(x => x.Value == templateCode)
|
|
.ToList();
|
|
var dSettings = settings.Where(x => x.AssignType == DeviceTimePeriodAssignEnumType.Device).Where(x => x.Value == code).ToList();
|
|
|
|
foreach (var setting in dSettings)
|
|
{
|
|
var s = tSettings.FirstOrDefault(x => x.CardType == setting.CardType);
|
|
if (s != null)
|
|
{
|
|
tSettings.Remove(s);
|
|
}
|
|
|
|
tSettings.Add(setting);
|
|
}
|
|
|
|
item.TimePeriods = tSettings;
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_logger.LogError(e, "处理时段码失败:{msg}", e.Message);
|
|
}
|
|
}
|
|
} |