using Dlhis.Entity.Basic.Entity; using Dlhis.Entity.Device.Entities; using Dlhis.Entity.Device.Enums; using System.Linq.Expressions; using Dlhis.ScheduledTask.TaskAssignment.Request; using Dlhis.ScheduledTask.TaskAssignment.Response; using Kurisu.AspNetCore.Scope; using Kurisu.AspNetCore.UnifyResultAndValidation; using Kurisu.AspNetCore.Utils.Extensions; using Kurisu.SqlSugar.Services; using Microsoft.AspNetCore.DataProtection; using Microsoft.Extensions.Options; using SqlSugar; using Kurisu.SqlSugar.Extensions; using Kurisu.SqlSugar.Attributes; using System.Threading.Tasks; namespace Dlhis.ScheduledTask.TaskAssignment.Services.Implements; [IgnoreTenant] public class AssignmentService : IAssignmentService { private readonly IDbContext _dbContext; private readonly ILogger _logger; public AssignmentService(IDbContext dbContext, ILogger logger) { _dbContext = dbContext; _logger = logger; } public async Task> DeviceGetTasksAsync(DeviceTaskGetRequest request) { var data = await ContinueUpdateAsync(async () => { var page = await _dbContext.Queryable() .LeftJoin((deviceTask, deivce) => deviceTask.DeviceUniqueNo == deivce.UniqueNo) .LeftJoin((deviceTask, deivce, deivceTamplate) => deivceTamplate.Code == deivce.TemplateCode) .LeftJoin((deviceTask, deivce, deivceTamplate, ga) => deviceTask.UserNo == ga.No) .LeftJoin((deviceTask, deivce, deivceTamplate, ga, department) => department.No == ga.DepartmentNo) .WhereIF(request.Brand.IsPresent(), (deviceTask, deivce, deivceTamplate) => deivceTamplate.Brand == request.Brand) .WhereIF(request.DeviceUniqueNo.IsPresent(), (deviceTask, deivce) => deviceTask.DeviceUniqueNo == request.DeviceUniqueNo) .Where(deviceTask => deviceTask.Status == DeviceTaskStatusEnumType.Wait) .OrderBy(deviceTask => deviceTask.CreateTime) .Select((deviceTask, deivce, deivceTamplate, ga, department) => new { deviceTask.Id, deviceTask.Type, deviceTask.DeviceUniqueNo, DeviceConnectionInfo = deivce.ConnectionInfo, deivce.Brand, deviceTask.UserNo, deviceTask.UserCode, UserName = ga.Name, ga.DepartmentNo, DepartmentName = department.Name, ga.CardNo, deviceTask.Version }) .ToPageListAsync(request); if (!page.Data.Any()) { return page.Data; } var taskIdVs = page.Data.Select(x => new { x.Id, x.Version }).ToList(); Expression> where = LinqExpressionExtension.False(); taskIdVs.ForEach(p => { where = where.Or(x => x.Id == p.Id && x.Version == p.Version && x.Status != DeviceTaskStatusEnumType.Success); }); await _dbContext.Client.Ado.BeginTranAsync(); try { var effecet = await _dbContext.Updateable() .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 != effecet) { throw new VersionExceptions("更新错误"); } await _dbContext.Client.Ado.CommitTranAsync(); } catch { await _dbContext.Client.Ado.RollbackTranAsync(); throw; } return page.Data; }, 5); if (!data.Any()) { return new List(); } return Scoped.Request.Value.Create((sp) => { var faceUrlOptions = sp.GetService>().Value; var dataProtectionProvider = sp.GetService(); var timeLimitedDataProtector = dataProtectionProvider .CreateProtector("down:face") .ToTimeLimitedDataProtector(); return data.GroupBy(x => new { x.Brand, x.DeviceUniqueNo, x.DeviceConnectionInfo }) .Select(x => { var b = x.Key.Brand; var d = x.Key.DeviceUniqueNo; var dc = x.Key.DeviceConnectionInfo; return new DeviceTaskToDeviceByDeviceResponse { Brand = b, DeviceUniqueNo = d, DeviceConnectionInfo = dc, Tasks = x.AsEnumerable().Select(item => { var key = $"face:{item.UserCode}"; var token = item.Type == DeviceTaskEnumType.Add ? timeLimitedDataProtector.Protect(key, TimeSpan.FromSeconds(faceUrlOptions.Limit)) : string.Empty; return new TaskCombineUserDimensionDto { TaskId = item.Id, Type = item.Type, UserInfo = new UserToDeviceResponse { UserNo = item.UserNo, UserCode = item.UserCode, UserName = item.UserName, DepartmentNo = item.DepartmentNo, DepartmentName = item.DepartmentName, CardNo = item.Type == DeviceTaskEnumType.Add ? item.CardNo : string.Empty, Face = item.Type == DeviceTaskEnumType.Add ? faceUrlOptions.Url + token : string.Empty,//下发才附带照片信息 } }; }) .ToList() }; }).ToList(); }); } /// /// 获取新token /// /// /// /// public async Task RenewFaceUrlAsync(long taskId) { var task = await _dbContext.Queryable().Where(x => x.Id == taskId).FirstAsync(); task.ThrowIfNull("该任务不存在"); (task.Status != DeviceTaskStatusEnumType.Process).ThrowIfTrue($"设备任务下发状态需为{DeviceTaskStatusEnumType.Process.GetDescription()}"); return Scoped.Request.Value.Create((sp) => { var faceUrlOptions = sp.GetService>().Value; var dataProtectionProvider = sp.GetService(); var timeLimitedDataProtector = dataProtectionProvider .CreateProtector("down:face") .ToTimeLimitedDataProtector(); var userCode = task.UserCode; var key = $"face:{userCode}"; var token = timeLimitedDataProtector.Protect(key, TimeSpan.FromSeconds(faceUrlOptions.Limit)); return faceUrlOptions.Url + token; }); } public async Task UpdateDeviceTaskStatusAsync(UpdateDeviceTaskStatusRequest request) { for (int i = 0; i < 5; i++) { var deviceTask = await _dbContext.Queryable().Where(x => x.Id == request.TaskId).SingleAsync(); deviceTask.ThrowIfNull("设备任务不存在"); (deviceTask.Status != DeviceTaskStatusEnumType.Process) .ThrowIfTrue($"任务状态[{deviceTask.Status.GetDescription()}]有误"); var status = request.IsSuccess ? DeviceTaskStatusEnumType.Success : DeviceTaskStatusEnumType.Error; var effect = await _dbContext.Updateable() .SetColumns(x => x.Status == status) .SetColumns(x => x.ResultMessage == request.ResultMessage) .SetColumns(x => x.Version == x.Version + 1) .SetColumns(x => x.ModifiedTime == DateTime.Now) .Where(x => x.Id == request.TaskId && x.Version == deviceTask.Version) .ExecuteCommandAsync(); if (effect == 0) { continue; } return; } throw new UserFriendlyException("操作失败,请重试"); } //*********************************************************** help methods ********************************************************************* private async Task ContinueUpdateAsync(Func> func, int retry) { for (int i = 0; i < retry; i++) { try { return await func(); } catch (Exception ex) when (ex is VersionExceptions) { _logger.LogWarning(ex, ex.Message); } catch (Exception) { throw; } } throw new UserFriendlyException("操作失败,请重试"); } }