diff --git a/Src/Dlhis.ScheduledTask/Abstractions/IJob.cs b/Src/Dlhis.ScheduledTask/Abstractions/IJob.cs new file mode 100644 index 00000000..bdde3dbe --- /dev/null +++ b/Src/Dlhis.ScheduledTask/Abstractions/IJob.cs @@ -0,0 +1,6 @@ +namespace Kurisu.Scheduled.Abstractions; + +public interface IJob +{ + Task TodoAsync(); +} diff --git a/Src/Dlhis.ScheduledTask/Attributes/RecurringJobAttribute.cs b/Src/Dlhis.ScheduledTask/Attributes/RecurringJobAttribute.cs new file mode 100644 index 00000000..78b00f60 --- /dev/null +++ b/Src/Dlhis.ScheduledTask/Attributes/RecurringJobAttribute.cs @@ -0,0 +1,18 @@ +namespace Kurisu.Scheduled.Attributes; + +[AttributeUsage(AttributeTargets.Class)] +public class RecurringJobAttribute : Attribute +{ + public RecurringJobAttribute(string uniqueJobKey, string cron) + { + UniqueJobKey = uniqueJobKey; + Cron = cron; + } + + public string Name { get; set; } + + public string UniqueJobKey { get; } + public string Cron { get; } + + public string Queue { get; set; } = "default"; +} diff --git a/Src/Dlhis.ScheduledTask/BaseJob.cs b/Src/Dlhis.ScheduledTask/BaseJob.cs new file mode 100644 index 00000000..c8dcaa44 --- /dev/null +++ b/Src/Dlhis.ScheduledTask/BaseJob.cs @@ -0,0 +1,53 @@ +using System.Reflection; +using Kurisu.Core.DataAccess.Entity; +using Kurisu.Scheduled.Abstractions; +using Kurisu.Scheduled.Attributes; +using Kurisu.SqlSugar.Services; + +namespace Kurisu.Scheduled; + +public abstract class BaseJob : IJob +{ + private readonly IServiceProvider _serviceProvider; + + public BaseJob(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + protected ILogger Logger { get; set; } + protected IDbContext DbContext { get; set; } + + public async Task TodoAsync() + { + using (var scope = _serviceProvider.CreateScope()) + { + Logger = scope.ServiceProvider.GetService>(); + DbContext = scope.ServiceProvider.GetService(); + var sqlSugarOptionsService = scope.ServiceProvider.GetService(); + + DbContext.Client.QueryFilter.ClearAndBackup(); + sqlSugarOptionsService.IgnoreTenant = true; + + var name = this.GetType().GetCustomAttribute()!.Name; + Logger.LogDebug("[{name}]开始执行...", name); + + try + { + await RunAsync(scope.ServiceProvider); + } + catch (Exception ex) + { + Logger.LogError(ex, "[{name}]执行失败:{message} {stacktrace}", name, ex.Message, ex.StackTrace); + } + finally + { + Logger.LogDebug("[{name}]执行结束...", name); + DbContext.Client.QueryFilter.Restore(); + sqlSugarOptionsService.IgnoreTenant = false; + } + } + } + + public abstract Task RunAsync(IServiceProvider serviceProvider); +} diff --git a/Src/Dlhis.ScheduledTask/CommonJobs/CancelDuplicationTaskJob.cs b/Src/Dlhis.ScheduledTask/CommonJobs/CancelDuplicationTaskJob.cs deleted file mode 100644 index b701c93e..00000000 --- a/Src/Dlhis.ScheduledTask/CommonJobs/CancelDuplicationTaskJob.cs +++ /dev/null @@ -1,165 +0,0 @@ -using Dlhis.Entity.Device.Entities; -using Dlhis.Entity.Device.Enums; -using Kurisu.AspNetCore.Utils.Extensions; -using Kurisu.Core.DataAccess.Entity; -using Kurisu.SqlSugar.Services; -using SqlSugar; -using System.Linq.Expressions; - -namespace Dlhis.ScheduledTask.CommonJobs; - -public class CancelDuplicationTaskJob -{ - private readonly IServiceProvider _serviceProvider; - private readonly ILogger _logger; - - public CancelDuplicationTaskJob(IServiceProvider serviceProvider, ILogger logger) - { - _serviceProvider = serviceProvider; - _logger = logger; - } - - public async Task RunAsync() - { - _logger.LogInformation("抵消任务开始处理"); - - using (var scope = _serviceProvider.CreateScope()) - { - var optionService = scope.ServiceProvider.GetService(); - var db = scope.ServiceProvider.GetService(); - - db.Client.QueryFilter.ClearAndBackup(); - optionService.IgnoreTenant = true; - try - { - //人员下发任务相关 - var taskTypes = new List() { DeviceTaskEnumType.Add, DeviceTaskEnumType.Delete, DeviceTaskEnumType.Update }; - - var deviceTasks = await db.Queryable() - .Where(x => x.Status == DeviceTaskStatusEnumType.Wait)//没有被获取 - .Where(x => taskTypes.Contains(x.Type)) - .OrderBy(x => x.CreateTime, OrderByType.Desc) - .ToListAsync(); - - var groupData = deviceTasks.GroupBy(x => new { x.TenantId, x.UserNo, x.DeviceUniqueNo }); - foreach (var deviceTaskPack in groupData) - { - var uniqueInfo = deviceTaskPack.Key; - var data = deviceTaskPack.ToList(); - - - foreach (var item in data) - { - try - { - Expression> where = LinqExpressionExtension.False(); - var ignoreData = new List(); - //最新一条更新人员信息 - if (item.Type == DeviceTaskEnumType.Update && item.Status == DeviceTaskStatusEnumType.Wait) - { - //获取过往的更新人员任务 - ignoreData = data.Where(x => x.Type == DeviceTaskEnumType.Update) - .Where(x => x.Status == DeviceTaskStatusEnumType.Wait) - .Where(x => x.Id != item.Id) - .Where(x => item.CreateTime > x.CreateTime) - .Select(x => new IdVersion { Id = x.Id, Version = x.Version }).ToList(); - } - //最新一条删除人员信息 - else if (item.Type == DeviceTaskEnumType.Delete && item.Status == DeviceTaskStatusEnumType.Wait) - { - //存在成功下发的任务,此处可以直接把其他任务取消 - if (await db.Queryable().Where(x => x.UserNo == item.UserNo) - .Where(x => x.DeviceUniqueNo == item.DeviceUniqueNo) - .Where(x => x.TenantId == item.TenantId).Where(x => x.Status == DeviceTaskStatusEnumType.Success).AnyAsync()) - { - ignoreData.AddRange(data.Where(x => x.Type == DeviceTaskEnumType.Add - || x.Type == DeviceTaskEnumType.Delete - || x.Type == DeviceTaskEnumType.Update) - .Where(x => x.Status == DeviceTaskStatusEnumType.Wait) - .Where(x => x.Id != item.Id) - .Where(x => item.CreateTime > x.CreateTime) - .Select(x => new IdVersion { Id = x.Id, Version = x.Version }) - ); - } - else - { - var currentIds = new List { item.Id }; - var beforeTask = data.Where(x => x.Type == DeviceTaskEnumType.Add || x.Type == DeviceTaskEnumType.Update) - .Where(x => !currentIds.Contains(x.Id)) - .Where(x => x.Status == DeviceTaskStatusEnumType.Wait) - .Where(x => item.CreateTime > x.CreateTime) - .FirstOrDefault(); - - //逻辑正确,最终beforeTask.type == DeviceTaskEnumType.Add - while (beforeTask != null && beforeTask.Type == DeviceTaskEnumType.Update) - { - ignoreData.Add(new IdVersion() { Id = beforeTask.Id, Version = beforeTask.Version }); - currentIds.Add(beforeTask.Id); - - beforeTask = data.Where(x => x.Type == DeviceTaskEnumType.Add || x.Type == DeviceTaskEnumType.Update) - .Where(x => !currentIds.Contains(x.Id)) - .Where(x => x.Status == DeviceTaskStatusEnumType.Wait) - .Where(x => item.CreateTime > x.CreateTime) - .FirstOrDefault(); - } - - if (beforeTask != null) - { - ignoreData.Add(new IdVersion() { Id = beforeTask.Id, Version = beforeTask.Version }); - ignoreData.Add(new IdVersion() { Id = item.Id, Version = item.Version }); - } - } - } - - if (ignoreData.Any()) - { - ignoreData.ForEach(p => - { - where = where.Or(x => x.Id == p.Id && x.Version == p.Version && x.Status == DeviceTaskStatusEnumType.Wait); - }); - - await db.Updateable() - .SetColumns(x => x.Version == x.Version + 1) - .SetColumns(x => x.Status == DeviceTaskStatusEnumType.Cancel) - .SetColumns(x => x.CancellationId == item.Id) - .SetColumns(x => x.ModifiedTime == DateTime.Now) - .Where(where) - .ExecuteCommandAsync(); - - data.ForEach(x => - { - if (ignoreData.Any(p => p.Id == x.Id)) - x.Status = DeviceTaskStatusEnumType.Cancel; - }); - } - } - catch (Exception ex) - { - _logger.LogError(ex, "抵消处理异常:{message}", ex.Message); - } - } - } - } - catch (Exception ex) - { - _logger.LogError(ex, "抵消处理异常:{message}", ex.Message); - } - finally - { - db.Client.QueryFilter.Restore(); - optionService.IgnoreTenant = false; - } - } - - - _logger.LogInformation("抵消任务处理完成"); - } - - class IdVersion - { - public long Id { get; set; } - public int Version { get; set; } - } - -} - diff --git a/Src/Dlhis.ScheduledTask/CommonJobs/DelApiLogTaskJob.cs b/Src/Dlhis.ScheduledTask/CommonJobs/DelApiLogTaskJob.cs deleted file mode 100644 index 9651ebbc..00000000 --- a/Src/Dlhis.ScheduledTask/CommonJobs/DelApiLogTaskJob.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Dlhis.Entity.Common; -using Kurisu.SqlSugar.Services; - -namespace Dlhis.ScheduledTask.CommonJobs; - -public class DelApiLogTaskJob -{ - private readonly IDbContext _dbContext; - private readonly ILogger _logger; - - public DelApiLogTaskJob(IDbContext dbContext, ILogger logger) - { - _dbContext = dbContext; - _logger = logger; - } - - public async Task RunAsync() - { - try - { - DateTime before = DateTime.Now.Date.AddDays(-7); - await _dbContext.ChangeDb("log").Client.Deleteable().Where(x => x._ts <= before).ExecuteCommandAsync(); - } - catch (Exception ex) - { - _logger.LogError(ex, "删除日志异常:{message}", ex.Message); - } - } -} - - diff --git a/Src/Dlhis.ScheduledTask/CommonJobs/HeartbeatJob.cs b/Src/Dlhis.ScheduledTask/CommonJobs/HeartbeatJob.cs deleted file mode 100644 index 59e4a97f..00000000 --- a/Src/Dlhis.ScheduledTask/CommonJobs/HeartbeatJob.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System.Net; -using System.Net.Sockets; -using Dlhis.Entity.Basic.Entity; -using Dlhis.Entity.Device.Entities; -using Kurisu.Core.DataAccess.Entity; -using Kurisu.SqlSugar.Services; -using Newtonsoft.Json; - -namespace Dlhis.ScheduledTask.CommonJobs; - -public class HeartbeatJob -{ - private readonly IDbContext _dbContext; - - public HeartbeatJob(IDbContext dbContext) - { - _dbContext = dbContext; - } - - public async Task RunAsync() - { - _dbContext.Client.QueryFilter.ClearAndBackup(); - try - { - var devices = await _dbContext.Queryable().Where(x => x.Enable).Where(x => x.HeartbeatInterval > 0).ToListAsync(); - foreach (var device in devices) - { - try - { - var ipInfo = JsonConvert.DeserializeObject(device.ConnectionInfo); - - //超时时间 - var CancellationTokenSource = new CancellationTokenSource(300); - await new TcpClient().ConnectAsync(IPAddress.Parse(ipInfo.IP), ipInfo.Port, CancellationTokenSource.Token); - - await _dbContext.Updateable().SetColumns(x => x.LastHeartbeatTime == DateTime.Now) - .Where(x => x.DeviceUniqueNo == device.UniqueNo).ExecuteCommandAsync(); - - // _logger.LogInformation("心跳设备成功:{no}", device.UniqueNo); - } - catch (Exception) - { - //_logger.LogError(ex, "心跳设备失败:{no}. {message}", device.UniqueNo, ex.Message); - } - } - } - finally - { - _dbContext.Client.QueryFilter.Restore(); - } - } -} diff --git a/Src/Dlhis.ScheduledTask/CommonJobs/MealSupplementHandlerJob.cs b/Src/Dlhis.ScheduledTask/CommonJobs/MealSupplementHandlerJob.cs deleted file mode 100644 index bc0e11c7..00000000 --- a/Src/Dlhis.ScheduledTask/CommonJobs/MealSupplementHandlerJob.cs +++ /dev/null @@ -1,162 +0,0 @@ -using Dlhis.Entity.Basic.Entity; -using Dlhis.Entity.Basic.Enums; -using Dlhis.Entity.Canteen.Entities; -using Dlhis.ScheduledTask.SyncSapInfo; -using Dlhis.ScheduledTask.SyncSapInfo.Services; -using Kurisu.AspNetCore.UnifyResultAndValidation; -using Kurisu.Core.DataAccess.Entity; -using Kurisu.SqlSugar.Services; -using SqlSugar; - -namespace Dlhis.ScheduledTask.CommonJobs; - -public class MealSupplementHandlerJob -{ - private readonly IDbContext _dbContext; - private readonly ILogger _logger; - private readonly IJinkoJIPService _jinkoJIPService; - - public MealSupplementHandlerJob(IDbContext dbContext, ILogger logger, IJinkoJIPService jinkoJIPService) - { - _dbContext = dbContext; - _logger = logger; - _jinkoJIPService = jinkoJIPService; - } - - public async Task RunAsync() - { - _dbContext.Client.QueryFilter.ClearAndBackup(); - try - { - //查询待处理餐补 - var mealSupplements = await _dbContext.Queryable() - .Where(x => (x.Status == MealSupplementStatusEnumtype.Wait || x.Status == MealSupplementStatusEnumtype.Error) && !x.Sync) - .ToListAsync(); - - foreach (var item in mealSupplements) - { - GainfoMealEntity mealUser = null; - var gainfo = await _dbContext.Queryable().Where(x => x.Code == item.Code).SingleAsync(); - //档案不存在 - if (gainfo == null) - { - //todo - //_logger.LogWarning("档案code:{code}不存在.flowno:{flowno}", item.Code, item.UniqueId); - //continue; - - gainfo = new GainfoEntity() { No = Guid.NewGuid().ToString() }; - } - else - { - - } - - mealUser = await _dbContext.Queryable().Where(x => x.UserNo == gainfo.No).SingleAsync(); - if (mealUser == null) - { - mealUser = new GainfoMealEntity - { - Balance = 0, - BalanceOfRecharge = 0, - BalanceOfSubsidies = 0, - UserNo = gainfo.No, - UserCode = gainfo.Code, - Version = 0, - TenantId = gainfo.Factory, - }; - - await _dbContext.InsertAsync(mealUser); - } - - await SetMealSupplementAsync(mealUser, item); - } - } - finally - { - _dbContext.Client.QueryFilter.Restore(); - } - } - - private async Task SetMealSupplementAsync(GainfoMealEntity mealUser, MealSupplementRecordEntity mealSupplement) - { - await _dbContext.Client.Ado.BeginTranAsync(); - try - { - await ContinueUpdateAsync(async () => - { - mealUser = await _dbContext.Queryable().Where(x => x.UserCode == mealUser.UserCode).FirstAsync(); - var b = mealUser.Balance += mealSupplement.Amount; - - var effect = await _dbContext.Updateable() - .SetColumns(x => x.Balance == b) - .SetColumns(x => x.ModifiedTime == DateTime.Now) - .Where(x => x.UserCode == mealUser.UserCode && x.Version == mealUser.Version) - .ExecuteCommandAsync(); - - if (effect <= 0) - { - throw new VersionExceptions("餐补写入错误"); - } - - }, 5); - - await _dbContext.Updateable() - .SetColumns(x => x.Status == MealSupplementStatusEnumtype.Sucess) - .SetColumns(x => x.Sync == true) - .SetColumns(x => x.ModifiedTime == DateTime.Now) - .Where(x => x.UniqueId == mealSupplement.UniqueId) - .ExecuteCommandAsync(); - - var r = await _jinkoJIPService.SyncMealSupplementRecordsAsync(new List - { - new() - { - UniqueId = mealSupplement.UniqueId, - Status = "SUCCESS", - Msg = "操作成功" - } - }); - - await _dbContext.Updateable() - .SetColumns(x => x.Result == r) - .SetColumns(x => x.ModifiedTime == DateTime.Now) - .Where(x => x.UniqueId == mealSupplement.UniqueId) - .ExecuteCommandAsync(); - - await _dbContext.Client.Ado.CommitTranAsync(); - } - catch (Exception ex) - { - await _dbContext.Client.Ado.RollbackTranAsync(); - - await _dbContext.Updateable() - .SetColumns(x => x.Status == MealSupplementStatusEnumtype.Error) - .SetColumns(x => x.Result == ex.Message) - .SetColumns(x => x.ModifiedTime == DateTime.Now) - .Where(x => x.UniqueId == mealSupplement.UniqueId) - .ExecuteCommandAsync(); - } - } - - private async Task ContinueUpdateAsync(Func func, int retry, string errorMessage = null) - { - for (int i = 0; i < retry; i++) - { - try - { - await func(); - return; - } - catch (Exception ex) when (ex is VersionExceptions) - { - _logger.LogWarning(ex, ex.Message); - } - catch (Exception) - { - throw; - } - } - - throw new UserFriendlyException(errorMessage ?? "操作失败,请重试"); - } -} diff --git a/Src/Dlhis.ScheduledTask/CommonJobs/UpdateUserPasswordJob.cs b/Src/Dlhis.ScheduledTask/CommonJobs/UpdateUserPasswordJob.cs deleted file mode 100644 index ac447fe4..00000000 --- a/Src/Dlhis.ScheduledTask/CommonJobs/UpdateUserPasswordJob.cs +++ /dev/null @@ -1,125 +0,0 @@ -using Dlhis.Entity.Basic.Entity; -using Dlhis.Entity.Sys.Entities; -using Kurisu.AspNetCore.Utils.Extensions; -using Kurisu.Core.DataAccess.Entity; -using Kurisu.SqlSugar.Services; -using Microsoft.AspNetCore.Identity; - -namespace Dlhis.ScheduledTask.CommonJobs; - -public class UpdateUserPasswordJob -{ - private readonly IDbContext _dbContext; - private readonly ILogger _logger; - - public UpdateUserPasswordJob( - IDbContext dbContext, - ILogger logger) - { - _dbContext = dbContext; - _logger = logger; - } - - public async Task RunAsync() - { - _dbContext.Client.QueryFilter.ClearAndBackup(); - try - { - - var identityDbContext = _dbContext.ChangeDb("identity"); - - var whitelist = new List() { "admin", "WB-0741", "WB-1091", "0123456" }; - - var users = await identityDbContext.Queryable() - .Where(x => !whitelist.Contains(x.UserName)) - .ToListAsync(); - - var gainfos = await _dbContext.Queryable().Where(x => !whitelist.Contains(x.Code)).ToListAsync(); - - var hasher = new PasswordHasher(); - foreach (var gainfo in gainfos) - { - if (gainfo.IdNo.IsPresent()) - { - try - { - var password = gainfo.IdNo.TakeLast(6).Join(""); - - var user = users.FirstOrDefault(x => x.UserName == gainfo.Code); - if (user == null) - { - user = new UserEntity - { - UserName = gainfo.Code, - NormalizedUserName = gainfo.Code.ToUpper(), - ConcurrencyStamp = Guid.NewGuid().ToString(), - SecurityStamp = Guid.NewGuid().ToString(), - }; - password = hasher.HashPassword(user, password); - user.PasswordHash = password; - - var id = (int)await identityDbContext.InsertReturnIdentityAsync(user); - await AddUserClaim(identityDbContext, id, "jinko-code", gainfo.Code); - await AddUserClaim(identityDbContext, id, "name", gainfo.Name); - if (!string.IsNullOrEmpty(gainfo.Factory)) - { - var userTenant = await identityDbContext.Queryable().Where(x => x.UserId == user.Id).FirstAsync(); - if (userTenant == null) - { - userTenant = new UserTenantEntity - { - UserId = user.Id, - TenantCode = gainfo.Factory - }; - await identityDbContext.InsertAsync(userTenant); - } - else - { - userTenant.TenantCode = gainfo.Factory; - await identityDbContext.UpdateAsync(userTenant); - } - } - } - else - { - password = hasher.HashPassword(user, password); - user.PasswordHash = password; - await identityDbContext.UpdateAsync(user); - } - } - catch (Exception) - { - } - } - } - } - catch (Exception ex) - { - _logger.LogError(ex, "密码修改失败:{message}", ex.Message); - } - finally - { - _dbContext.Client.QueryFilter.Restore(); - } - } - - private async Task AddUserClaim(IDbContext dbContext, int userId, string type, string value) - { - var claim = await dbContext.Queryable().Where(x => x.UserId == userId).FirstAsync(x => x.ClaimType == type); - if (claim == null) - { - claim = new UserClaimEntity() - { - UserId = userId, - ClaimType = type, - ClaimValue = value - }; - await dbContext.InsertAsync(claim); - } - else - { - claim.ClaimValue = value; - await dbContext.UpdateAsync(claim); - } - } -} diff --git a/Src/Dlhis.ScheduledTask/Dlhis.ScheduledTask.csproj b/Src/Dlhis.ScheduledTask/Dlhis.ScheduledTask.csproj index a199ba52..f600b79a 100644 --- a/Src/Dlhis.ScheduledTask/Dlhis.ScheduledTask.csproj +++ b/Src/Dlhis.ScheduledTask/Dlhis.ScheduledTask.csproj @@ -21,11 +21,11 @@ - + diff --git a/Src/Dlhis.ScheduledTask/Jobs/CancelDuplicationTaskJob.cs b/Src/Dlhis.ScheduledTask/Jobs/CancelDuplicationTaskJob.cs new file mode 100644 index 00000000..55ae7aa0 --- /dev/null +++ b/Src/Dlhis.ScheduledTask/Jobs/CancelDuplicationTaskJob.cs @@ -0,0 +1,138 @@ +using Dlhis.Entity.Device.Entities; +using Dlhis.Entity.Device.Enums; +using Kurisu.AspNetCore.Utils.Extensions; +using Kurisu.Scheduled; +using Kurisu.Scheduled.Attributes; +using SqlSugar; +using System.Linq.Expressions; + +namespace Dlhis.ScheduledTask.Jobs; + +/// +/// 处理重复下发任务 +/// +[RecurringJob(nameof(CancelDuplicationTaskJob), "0/15 * * * * ?", Name = "处理重复下发任务")] +public class CancelDuplicationTaskJob : BaseJob +{ + public CancelDuplicationTaskJob(IServiceProvider serviceProvider) : base(serviceProvider) + { + } + + public override async Task RunAsync(IServiceProvider serviceProvider) + { + //人员下发任务相关 + var taskTypes = new List() { DeviceTaskEnumType.Add, DeviceTaskEnumType.Delete, DeviceTaskEnumType.Update }; + + var deviceTasks = await DbContext.Queryable() + .Where(x => x.Status == DeviceTaskStatusEnumType.Wait)//没有被获取 + .Where(x => taskTypes.Contains(x.Type)) + .OrderBy(x => x.CreateTime, OrderByType.Desc) + .ToListAsync(); + + var groupData = deviceTasks.GroupBy(x => new { x.TenantId, x.UserNo, x.DeviceUniqueNo }); + foreach (var deviceTaskPack in groupData) + { + var uniqueInfo = deviceTaskPack.Key; + var data = deviceTaskPack.ToList(); + + + foreach (var item in data) + { + try + { + Expression> where = LinqExpressionExtension.False(); + var ignoreData = new List(); + //最新一条更新人员信息 + if (item.Type == DeviceTaskEnumType.Update && item.Status == DeviceTaskStatusEnumType.Wait) + { + //获取过往的更新人员任务 + ignoreData = data.Where(x => x.Type == DeviceTaskEnumType.Update) + .Where(x => x.Status == DeviceTaskStatusEnumType.Wait) + .Where(x => x.Id != item.Id) + .Where(x => item.CreateTime > x.CreateTime) + .Select(x => new IdVersion { Id = x.Id, Version = x.Version }).ToList(); + } + //最新一条删除人员信息 + else if (item.Type == DeviceTaskEnumType.Delete && item.Status == DeviceTaskStatusEnumType.Wait) + { + //存在成功下发的任务,此处可以直接把其他任务取消 + if (await DbContext.Queryable().Where(x => x.UserNo == item.UserNo) + .Where(x => x.DeviceUniqueNo == item.DeviceUniqueNo) + .Where(x => x.TenantId == item.TenantId).Where(x => x.Status == DeviceTaskStatusEnumType.Success).AnyAsync()) + { + ignoreData.AddRange(data.Where(x => x.Type == DeviceTaskEnumType.Add + || x.Type == DeviceTaskEnumType.Delete + || x.Type == DeviceTaskEnumType.Update) + .Where(x => x.Status == DeviceTaskStatusEnumType.Wait) + .Where(x => x.Id != item.Id) + .Where(x => item.CreateTime > x.CreateTime) + .Select(x => new IdVersion { Id = x.Id, Version = x.Version }) + ); + } + else + { + var currentIds = new List { item.Id }; + var beforeTask = data.Where(x => x.Type == DeviceTaskEnumType.Add || x.Type == DeviceTaskEnumType.Update) + .Where(x => !currentIds.Contains(x.Id)) + .Where(x => x.Status == DeviceTaskStatusEnumType.Wait) + .Where(x => item.CreateTime > x.CreateTime) + .FirstOrDefault(); + + //逻辑正确,最终beforeTask.type == DeviceTaskEnumType.Add + while (beforeTask != null && beforeTask.Type == DeviceTaskEnumType.Update) + { + ignoreData.Add(new IdVersion() { Id = beforeTask.Id, Version = beforeTask.Version }); + currentIds.Add(beforeTask.Id); + + beforeTask = data.Where(x => x.Type == DeviceTaskEnumType.Add || x.Type == DeviceTaskEnumType.Update) + .Where(x => !currentIds.Contains(x.Id)) + .Where(x => x.Status == DeviceTaskStatusEnumType.Wait) + .Where(x => item.CreateTime > x.CreateTime) + .FirstOrDefault(); + } + + if (beforeTask != null) + { + ignoreData.Add(new IdVersion() { Id = beforeTask.Id, Version = beforeTask.Version }); + ignoreData.Add(new IdVersion() { Id = item.Id, Version = item.Version }); + } + } + } + + if (ignoreData.Any()) + { + ignoreData.ForEach(p => + { + where = where.Or(x => x.Id == p.Id && x.Version == p.Version && x.Status == DeviceTaskStatusEnumType.Wait); + }); + + await DbContext.Updateable() + .SetColumns(x => x.Version == x.Version + 1) + .SetColumns(x => x.Status == DeviceTaskStatusEnumType.Cancel) + .SetColumns(x => x.CancellationId == item.Id) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .Where(where) + .ExecuteCommandAsync(); + + data.ForEach(x => + { + if (ignoreData.Any(p => p.Id == x.Id)) + x.Status = DeviceTaskStatusEnumType.Cancel; + }); + } + } + catch (Exception ex) + { + Logger.LogError(ex, "抵消处理异常:{message}", ex.Message); + } + } + } + } + + class IdVersion + { + public long Id { get; set; } + public int Version { get; set; } + } +} + diff --git a/Src/Dlhis.ScheduledTask/CommonJobs/CreateDefinitelyGroupJob.cs b/Src/Dlhis.ScheduledTask/Jobs/CreateDefinitelyGroupJob.cs similarity index 60% rename from Src/Dlhis.ScheduledTask/CommonJobs/CreateDefinitelyGroupJob.cs rename to Src/Dlhis.ScheduledTask/Jobs/CreateDefinitelyGroupJob.cs index 9daadce1..0257b863 100644 --- a/Src/Dlhis.ScheduledTask/CommonJobs/CreateDefinitelyGroupJob.cs +++ b/Src/Dlhis.ScheduledTask/Jobs/CreateDefinitelyGroupJob.cs @@ -5,74 +5,62 @@ using Dlhis.Sys.Api; using Dlhis.Sys.Api.Response; using Kurisu.AspNetCore.Utils.Extensions; using Kurisu.Core.DataAccess.Entity; +using Kurisu.Scheduled; +using Kurisu.Scheduled.Attributes; using Kurisu.SqlSugar.Services; using Newtonsoft.Json; using SqlSugar; -namespace Dlhis.ScheduledTask.CommonJobs; +namespace Dlhis.ScheduledTask.Jobs; -public class CreateDefinitelyGroupJob +/// +/// 创建系统默认分组 +/// +[RecurringJob(nameof(CreateDefinitelyGroupJob), "0 0 5 * * ?", Name = "创建系统默认分组")] +public class CreateDefinitelyGroupJob : BaseJob { - private readonly ILogger _logger; private readonly ITenantApi _tenantApi; - private readonly IDbContext _dbContext; - public CreateDefinitelyGroupJob(ILogger logger, + public CreateDefinitelyGroupJob( ITenantApi tenantApi, - IDbContext dbContext, - ISqlSugarOptionsService sqlSugarOptionsService) + IServiceProvider serviceProvider) : base(serviceProvider) { - _logger = logger; _tenantApi = tenantApi; - _dbContext = dbContext; - - sqlSugarOptionsService.IgnoreTenant = true; } private static readonly string _remark = "系统自动生成"; - public async Task RunAsync() + public override async Task RunAsync(IServiceProvider serviceProvider) { - _dbContext.Client.QueryFilter.ClearAndBackup(); - try - { - //获取所有基地信息 - var tenantResult = await _tenantApi.GetTenantsInternalAsync(); - var tenants = tenantResult.Data; + //获取所有基地信息 + var tenantResult = await _tenantApi.GetTenantsInternalAsync(); + var tenants = tenantResult.Data; - _logger.LogInformation("获取基地信息:{json}", JsonConvert.SerializeObject(tenants)); + Logger.LogInformation("获取基地信息:{json}", JsonConvert.SerializeObject(tenants)); - //****************************************************系统人员分组**********************************************************/ + //****************************************************系统人员分组**********************************************************/ - await CreateGainfoGroupsAsync(tenants); + await CreateGainfoGroupsAsync(tenants); - //*****************************************************考勤设备组*********************************************************/ + //*****************************************************考勤设备组*********************************************************/ - await CreateDeviceGroupAsync(DeviceTypeEnumType.Attendance, new List { "*通用考勤设备组", "*专用考勤设备组" }, tenants); + await CreateDeviceGroupAsync(DeviceTypeEnumType.Attendance, new List { "*通用考勤设备组", "*专用考勤设备组" }, tenants); - //*****************************************************门禁设备组********************************************************/ + //*****************************************************门禁设备组********************************************************/ + + await CreateDeviceGroupAsync(DeviceTypeEnumType.Door, new List { "*共用区域", "*非共用区域" }, tenants); - await CreateDeviceGroupAsync(DeviceTypeEnumType.Door, new List { "*共用区域", "*非共用区域" }, tenants); - } - catch (Exception ex) - { - _logger.LogError(ex, "自动创建系统分组失败:{message}", ex.Message); - } - finally - { - _dbContext.Client.QueryFilter.Restore(); - } } private async Task CreateGainfoGroupsAsync(List tenants) { var grps = new List { "*自定义人员分组", "*督查组", "*X3及以上领导组" }; - var searchGrps = await _dbContext.Queryable().Where(x => grps.Contains(x.Name)).ToListAsync(); + var searchGrps = await DbContext.Queryable().Where(x => grps.Contains(x.Name)).ToListAsync(); foreach (var grp in grps) { if (!searchGrps.Any(x => x.Name == grp)) { - await _dbContext.InsertAsync(new GainfoGroupEntity + await DbContext.InsertAsync(new GainfoGroupEntity { PCode = null, Code = Guid.NewGuid(), @@ -96,7 +84,7 @@ public class CreateDefinitelyGroupJob { foreach (var grp in topGroups) { - var topGrp = await _dbContext.Queryable().FirstAsync(x => x.Name == grp); + var topGrp = await DbContext.Queryable().FirstAsync(x => x.Name == grp); if (topGrp == null) { topGrp = new DeviceGroupEntity @@ -115,13 +103,13 @@ public class CreateDefinitelyGroupJob ModifiedTime = DateTime.Now, TenantId = null, }; - await _dbContext.InsertAsync(topGrp); + await DbContext.InsertAsync(topGrp); } foreach (var workplace in tenants.Where(x => x.PCode.IsEmpty())) { var workplaceName = $"*{type.GetDescription()}工作地系统组({workplace.Name})"; - var workplaceGrp = await _dbContext.Queryable().Where(x => x.PCode == topGrp.Code).FirstAsync(x => x.Name == workplaceName); + var workplaceGrp = await DbContext.Queryable().Where(x => x.PCode == topGrp.Code).FirstAsync(x => x.Name == workplaceName); if (workplaceGrp == null) { workplaceGrp = new DeviceGroupEntity @@ -140,15 +128,15 @@ public class CreateDefinitelyGroupJob ModifiedTime = DateTime.Now, TenantId = null, }; - await _dbContext.InsertAsync(workplaceGrp); + await DbContext.InsertAsync(workplaceGrp); } foreach (var factory in tenants.Where(x => x.PCode == workplace.Code)) { var factoryName = $"*{type.GetDescription()}厂区系统组({factory.Name})"; - if (!await _dbContext.Queryable().Where(x => x.PCode == workplaceGrp.Code).AnyAsync(x => x.Name == factoryName)) + if (!await DbContext.Queryable().Where(x => x.PCode == workplaceGrp.Code).AnyAsync(x => x.Name == factoryName)) { - await _dbContext.InsertAsync(new DeviceGroupEntity + await DbContext.InsertAsync(new DeviceGroupEntity { PCode = workplaceGrp.Code, Code = Guid.NewGuid(), diff --git a/Src/Dlhis.ScheduledTask/Jobs/CreateGetUploadRecordJob.cs b/Src/Dlhis.ScheduledTask/Jobs/CreateGetUploadRecordJob.cs new file mode 100644 index 00000000..944a2c53 --- /dev/null +++ b/Src/Dlhis.ScheduledTask/Jobs/CreateGetUploadRecordJob.cs @@ -0,0 +1,53 @@ +using Dlhis.Entity.Basic.Entity; +using Dlhis.Entity.Device.Entities; +using Dlhis.Entity.Device.Enums; +using Kurisu.Scheduled; +using Kurisu.Scheduled.Attributes; + +namespace Dlhis.ScheduledTask.Jobs; + +/// +/// 创建上传设备数据任务 +/// +[RecurringJob(nameof(CreateGetUploadRecordJob), "0 0/1 * * * ?", Name = "创建上传设备数据任务")] +public class CreateGetUploadRecordJob : BaseJob +{ + + public CreateGetUploadRecordJob(IServiceProvider serviceProvider) : base(serviceProvider) + { + } + + public override async Task RunAsync(IServiceProvider serviceProvider) + { + var devices = await DbContext.Queryable() + .Where(x => x.Enable) + .Where(x => x.Type == DeviceTypeEnumType.Attendance || x.Type == DeviceTypeEnumType.Door) + .ToListAsync(); + + //过滤处理中的任务 + var currentUniqueNos = await DbContext.Queryable() + .Where(x => x.Type == DeviceTaskEnumType.UploadRecord) + .Where(x => x.Status == DeviceTaskStatusEnumType.Process || x.Status == DeviceTaskStatusEnumType.Wait) + .Select(x => x.DeviceUniqueNo) + .ToListAsync(); + + var tasks = devices.Where(x => !currentUniqueNos.Contains(x.UniqueNo)).Select(x => new DeviceTaskEntity + { + DeviceUniqueNo = x.UniqueNo, + Status = DeviceTaskStatusEnumType.Wait, + + TenantId = x.TenantId, + Version = 0, + Type = DeviceTaskEnumType.UploadRecord, + + CreatedBy = 1, + CreateTime = DateTime.Now, + ModifiedBy = 1, + ModifiedTime = DateTime.Now, + + }) + .ToList(); + + await DbContext.InsertAsync(tasks); + } +} diff --git a/Src/Dlhis.ScheduledTask/Jobs/CreateSyncServerDateTimeJob.cs b/Src/Dlhis.ScheduledTask/Jobs/CreateSyncServerDateTimeJob.cs new file mode 100644 index 00000000..62f6614c --- /dev/null +++ b/Src/Dlhis.ScheduledTask/Jobs/CreateSyncServerDateTimeJob.cs @@ -0,0 +1,54 @@ +using Dlhis.Entity.Basic.Entity; +using Dlhis.Entity.Device.Entities; +using Dlhis.Entity.Device.Enums; +using Kurisu.Scheduled; +using Kurisu.Scheduled.Attributes; + +namespace Dlhis.ScheduledTask.Jobs; + +/// +/// 设备时间同步 +/// +[RecurringJob(nameof(CreateSyncServerDateTimeJob), "0 0 0/1 * * ?", Name = "设备时间同步")] +public class CreateSyncServerDateTimeJob : BaseJob +{ + + public CreateSyncServerDateTimeJob(IServiceProvider serviceProvider) : base(serviceProvider) + { + } + + public override async Task RunAsync(IServiceProvider serviceProvider) + { + var deviceUniqueNos = await DbContext.Queryable() + .Where(x => x.Status == DeviceTaskStatusEnumType.Wait || x.Status == DeviceTaskStatusEnumType.Process) + .Where(x => x.Type == DeviceTaskEnumType.SyncDateTime) + .Select(x => x.DeviceUniqueNo) + .Distinct() + .ToListAsync(); + + var devices = await DbContext.Queryable() + .Where(x => !deviceUniqueNos.Contains(x.UniqueNo)) + .Where(x => x.Enable) + .ToListAsync(); + + var tasks = devices.Select(x => new DeviceTaskEntity + { + DeviceUniqueNo = x.UniqueNo, + Status = DeviceTaskStatusEnumType.Wait, + + TenantId = x.TenantId, + Version = 0, + UserNo = string.Empty, + Type = DeviceTaskEnumType.SyncDateTime, + + CreatedBy = 1, + CreateTime = DateTime.Now, + ModifiedBy = 1, + ModifiedTime = DateTime.Now, + + }).ToList(); + + await DbContext.InsertAsync(tasks); + + } +} diff --git a/Src/Dlhis.ScheduledTask/Jobs/DeleteApiLogTaskJob.cs b/Src/Dlhis.ScheduledTask/Jobs/DeleteApiLogTaskJob.cs new file mode 100644 index 00000000..881b72a1 --- /dev/null +++ b/Src/Dlhis.ScheduledTask/Jobs/DeleteApiLogTaskJob.cs @@ -0,0 +1,25 @@ +using Dlhis.Entity.Common; +using Kurisu.Scheduled; +using Kurisu.Scheduled.Attributes; + +namespace Dlhis.ScheduledTask.Jobs; + +/// +/// 删除过期日志 +/// +[RecurringJob(nameof(DeleteApiLogTaskJob), "0 0 0 */6 * ?", Name = "删除过期日志")] +public class DeleteApiLogTaskJob : BaseJob +{ + + public DeleteApiLogTaskJob(IServiceProvider serviceProvider) : base(serviceProvider) + { + } + + public override async Task RunAsync(IServiceProvider serviceProvider) + { + var before = DateTime.Now.Date.AddDays(-7); + await DbContext.ChangeDb("log").Client.Deleteable().Where(x => x._ts <= before).ExecuteCommandAsync(); + } +} + + diff --git a/Src/Dlhis.ScheduledTask/Jobs/HeartbeatJob.cs b/Src/Dlhis.ScheduledTask/Jobs/HeartbeatJob.cs new file mode 100644 index 00000000..ba424a1f --- /dev/null +++ b/Src/Dlhis.ScheduledTask/Jobs/HeartbeatJob.cs @@ -0,0 +1,42 @@ +using System.Net; +using System.Net.Sockets; +using Dlhis.Entity.Basic.Entity; +using Dlhis.Entity.Device.Entities; +using Kurisu.Scheduled; +using Kurisu.Scheduled.Attributes; +using Newtonsoft.Json; + +namespace Dlhis.ScheduledTask.Jobs; + +/// +/// 设备心跳 +/// +[RecurringJob(nameof(HeartbeatJob), "0/10 * * * * ?", Name = "设备心跳")] +public class HeartbeatJob : BaseJob +{ + public HeartbeatJob(IServiceProvider serviceProvider) : base(serviceProvider) + { + } + + public override async Task RunAsync(IServiceProvider serviceProvider) + { + var devices = await DbContext.Queryable().Where(x => x.Enable).Where(x => x.HeartbeatInterval > 0).ToListAsync(); + foreach (var device in devices) + { + try + { + var ipInfo = JsonConvert.DeserializeObject(device.ConnectionInfo); + + //超时时间 + var CancellationTokenSource = new CancellationTokenSource(300); + await new TcpClient().ConnectAsync(IPAddress.Parse(ipInfo.IP), ipInfo.Port, CancellationTokenSource.Token); + + await DbContext.Updateable().SetColumns(x => x.LastHeartbeatTime == DateTime.Now) + .Where(x => x.DeviceUniqueNo == device.UniqueNo).ExecuteCommandAsync(); + } + catch (Exception) + { + } + } + } +} diff --git a/Src/Dlhis.ScheduledTask/Jobs/MealSupplementHandlerJob.cs b/Src/Dlhis.ScheduledTask/Jobs/MealSupplementHandlerJob.cs new file mode 100644 index 00000000..3b3f4885 --- /dev/null +++ b/Src/Dlhis.ScheduledTask/Jobs/MealSupplementHandlerJob.cs @@ -0,0 +1,224 @@ +using Dlhis.Canteen.Api; +using Dlhis.Canteen.Api.Request; +using Dlhis.Entity.Basic.Entity; +using Dlhis.Entity.Basic.Enums; +using Dlhis.Entity.Canteen.Entities; +using Dlhis.ScheduledTask.SyncSapInfo; +using Dlhis.ScheduledTask.SyncSapInfo.Services; +using Kurisu.AspNetCore.UnifyResultAndValidation; +using Kurisu.AspNetCore.Utils.Extensions; +using Kurisu.Scheduled; +using Kurisu.Scheduled.Attributes; +using SqlSugar; + +namespace Dlhis.ScheduledTask.Jobs; + +/// +/// 餐补核算 +/// +[RecurringJob(nameof(MealSupplementHandlerJob), "0 0/30 * * * ?", Name = "餐补核算")] +public class MealSupplementHandlerJob : BaseJob +{ + private readonly IHainingMealSupplementApi _hainingMealSupplementApi; + private readonly IJinkoJIPService _jinkoJIPService; + + public MealSupplementHandlerJob(IServiceProvider serviceProvider, IHainingMealSupplementApi hainingMealSupplementApi, IJinkoJIPService jinkoJIPService) : base(serviceProvider) + { + _hainingMealSupplementApi = hainingMealSupplementApi; + _jinkoJIPService = jinkoJIPService; + } + + public override async Task RunAsync(IServiceProvider serviceProvider) + { + //查询待处理餐补 + var mealSupplements = await DbContext.Queryable() + .Where(x => (x.Status == MealSupplementStatusEnumtype.Wait || x.Status == MealSupplementStatusEnumtype.Error) && !x.Sync) + .ToListAsync(); + + foreach (var item in mealSupplements) + { + GainfoMealEntity mealUser = null; + var gainfo = await DbContext.Queryable().Where(x => x.Code == item.Code).SingleAsync(); + //档案不存在 + if (gainfo == null) + { + await DbContext.Updateable() + .SetColumns(x => x.Status == MealSupplementStatusEnumtype.Error) + .SetColumns(x => x.Result == "人员档案不存在") + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .Where(x => x.UniqueId == item.UniqueId) + .ExecuteCommandAsync(); + continue; + } + else + { + //创建余额数据 + mealUser = await DbContext.Queryable().Where(x => x.UserCode == gainfo.Code).SingleAsync(); + if (mealUser == null) + { + mealUser = new GainfoMealEntity + { + Balance = 0, + BalanceOfRecharge = 0, + BalanceOfSubsidies = 0, + UserNo = gainfo.No, + UserCode = gainfo.Code, + Version = 0, + TenantId = gainfo.Factory, + }; + + await DbContext.InsertAsync(mealUser); + } + } + + if (item.Workplace == "5") + { + await SetHainingMealSupplementAsync(item); + } + else + { + await SetMealSupplementAsync(item); + } + } + } + + private async Task SetMealSupplementAsync(MealSupplementRecordEntity mealSupplement) + { + await DbContext.Client.Ado.BeginTranAsync(); + try + { + await ContinueUpdateAsync(async () => + { + var mealUser = await DbContext.Queryable().Where(x => x.UserCode == mealSupplement.Code).FirstAsync(); + var b = mealUser.Balance += mealSupplement.Amount; + + var effect = await DbContext.Updateable() + .SetColumns(x => x.Balance == b) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .Where(x => x.UserCode == mealUser.UserCode && x.Version == mealUser.Version) + .ExecuteCommandAsync(); + + if (effect <= 0) + { + throw new VersionExceptions("餐补写入错误"); + } + + }, 5); + + //更新餐补信息为成功(同步成功) + await DbContext.Updateable() + .SetColumns(x => x.Status == MealSupplementStatusEnumtype.Sucess) + .SetColumns(x => x.Sync == true) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .Where(x => x.UniqueId == mealSupplement.UniqueId) + .ExecuteCommandAsync(); + + var r = await _jinkoJIPService.SyncMealSupplementRecordsAsync(new List + { + new() + { + UniqueId = mealSupplement.UniqueId, + Status = "SUCCESS", + Msg = "操作成功" + } + }); + + await DbContext.Updateable() + .SetColumns(x => x.Result == r) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .Where(x => x.UniqueId == mealSupplement.UniqueId) + .ExecuteCommandAsync(); + + await DbContext.Client.Ado.CommitTranAsync(); + } + catch (Exception ex) + { + await DbContext.Client.Ado.RollbackTranAsync(); + + await DbContext.Updateable() + .SetColumns(x => x.Status == MealSupplementStatusEnumtype.Error) + .SetColumns(x => x.Result == ex.Message) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .Where(x => x.UniqueId == mealSupplement.UniqueId) + .ExecuteCommandAsync(); + } + } + + + private async Task SetHainingMealSupplementAsync(MealSupplementRecordEntity mealSupplement) + { + await DbContext.Client.Ado.BeginTranAsync(); + try + { + var hnResponse = await _hainingMealSupplementApi.AddMealSupplementAsync(new AddHainingMealSupplementRequest + { + Code = mealSupplement.Code, + Amount = mealSupplement.Amount, + Date = mealSupplement.Date, + Remark = mealSupplement.Remark, + UniqueId = mealSupplement.UniqueId, + }); + + (hnResponse == null || hnResponse.Code != 200).ThrowIfTrue("海宁餐补写入失败:" + hnResponse?.Message); + + //更新餐补信息为成功(同步成功) + await DbContext.Updateable() + .SetColumns(x => x.Status == MealSupplementStatusEnumtype.Sucess) + .SetColumns(x => x.Sync == true) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .Where(x => x.UniqueId == mealSupplement.UniqueId) + .ExecuteCommandAsync(); + + var r = await _jinkoJIPService.SyncMealSupplementRecordsAsync(new List + { + new() + { + UniqueId = mealSupplement.UniqueId, + Status = "SUCCESS", + Msg = "操作成功" + } + }); + + await DbContext.Updateable() + .SetColumns(x => x.Result == r) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .Where(x => x.UniqueId == mealSupplement.UniqueId) + .ExecuteCommandAsync(); + + await DbContext.Client.Ado.CommitTranAsync(); + } + catch (Exception ex) + { + await DbContext.Client.Ado.RollbackTranAsync(); + + await DbContext.Updateable() + .SetColumns(x => x.Status == MealSupplementStatusEnumtype.Error) + .SetColumns(x => x.Result == ex.Message) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .Where(x => x.UniqueId == mealSupplement.UniqueId) + .ExecuteCommandAsync(); + } + } + + private async Task ContinueUpdateAsync(Func func, int retry, string errorMessage = null) + { + for (int i = 0; i < retry; i++) + { + try + { + await func(); + return; + } + catch (Exception ex) when (ex is VersionExceptions) + { + Logger.LogWarning(ex, ex.Message); + } + catch (Exception) + { + throw; + } + } + + throw new UserFriendlyException(errorMessage ?? "操作失败,请重试"); + } +} diff --git a/Src/Dlhis.ScheduledTask/SyncSapInfo/Job/SyncOrganizationJob.cs b/Src/Dlhis.ScheduledTask/Jobs/SyncOrganizationJob.cs similarity index 57% rename from Src/Dlhis.ScheduledTask/SyncSapInfo/Job/SyncOrganizationJob.cs rename to Src/Dlhis.ScheduledTask/Jobs/SyncOrganizationJob.cs index 17e8567b..f39cc83f 100644 --- a/Src/Dlhis.ScheduledTask/SyncSapInfo/Job/SyncOrganizationJob.cs +++ b/Src/Dlhis.ScheduledTask/Jobs/SyncOrganizationJob.cs @@ -2,25 +2,25 @@ using Dlhis.ScheduledTask.SyncSapInfo.Dto; using Dlhis.ScheduledTask.SyncSapInfo.Services; using Hangfire; -using Kurisu.SqlSugar.Services; +using Kurisu.Scheduled; +using Kurisu.Scheduled.Attributes; -namespace Dlhis.ScheduledTask.SyncSapInfo.Job; +namespace Dlhis.ScheduledTask.Jobs; /// -/// 部门同步定时任务 +/// SAP组织架构数据同步 /// -public class SyncOrganizationJob +[RecurringJob(nameof(SyncOrganizationJob), "0 0 0 * * ?", Name = "SAP组织架构数据同步", Queue = "SAP")] +public class SyncOrganizationJob : BaseJob { - private readonly IDbContext _dbContext; private readonly IJinkoSapService _jinkoSapService; - public SyncOrganizationJob(IDbContext dbContext, IJinkoSapService jinkoSapService) + public SyncOrganizationJob(IServiceProvider serviceProvider, IJinkoSapService jinkoSapService) : base(serviceProvider) { - _dbContext = dbContext; _jinkoSapService = jinkoSapService; } - public async Task RunAsync() + public override async Task RunAsync(IServiceProvider serviceProvider) { var orgResult = await _jinkoSapService.GetSapOrganizationsAsync(); @@ -28,16 +28,13 @@ public class SyncOrganizationJob { await SaveOrg(orgResult.Org.Items); } - - var syncPositionJob = BackgroundJob.Enqueue(job => job.RunAsync()); - BackgroundJob.ContinueJobWith(syncPositionJob, job => job.RunAsync(), JobContinuationOptions.OnlyOnSucceededState); } private async Task SaveOrg(List modifiedOrgList) { foreach (SapOrganizationItem item in modifiedOrgList) { - var department = await _dbContext.Queryable().Where(x => x.No == item.OBJID).FirstAsync(); + var department = await DbContext.Queryable().Where(x => x.No == item.OBJID).FirstAsync(); if (department == null) { department = new DepartmentEntity @@ -47,14 +44,14 @@ public class SyncOrganizationJob PNo = item.SOBID, }; - await _dbContext.InsertAsync(department); + await DbContext.InsertAsync(department); } else { department.PNo = item.SOBID; department.Name = item.STEXT; - await _dbContext.UpdateAsync(department); + await DbContext.UpdateAsync(department); } } } diff --git a/Src/Dlhis.ScheduledTask/Jobs/SyncOriginCardInfoJob.cs b/Src/Dlhis.ScheduledTask/Jobs/SyncOriginCardInfoJob.cs new file mode 100644 index 00000000..e3c9b6d9 --- /dev/null +++ b/Src/Dlhis.ScheduledTask/Jobs/SyncOriginCardInfoJob.cs @@ -0,0 +1,74 @@ +using Dlhis.Entity.Basic.Entity; +using Dlhis.Entity.Device.Entities; +using Dlhis.Entity.Device.Enums; +using Dlhis.ScheduledTask.SyncSapInfo; +using Dlhis.ScheduledTask.SyncSapInfo.Services; +using Kurisu.AspNetCore.Utils.Extensions; +using Kurisu.Scheduled; +using Kurisu.Scheduled.Attributes; +using Kurisu.SqlSugar.Services; +using SqlSugar; + +namespace Dlhis.ScheduledTask.Jobs; + +/// +/// 上传考勤记录 +/// +[RecurringJob(nameof(SyncOriginCardInfoJob), "0/20 * * * * ?", Name = "上传考勤记录", Queue = "SAP")] +public class SyncOriginCardInfoJob : BaseJob +{ + private readonly IJinkoJIPService _jinkoJIPService; + private readonly ISqlSugarOptionsService _sqlSugarOptionsService; + + public SyncOriginCardInfoJob(IJinkoJIPService jinkoJIPService, IServiceProvider serviceProvider) : base(serviceProvider) + { + _jinkoJIPService = jinkoJIPService; + } + + public override async Task RunAsync(IServiceProvider serviceProvider) + { + //考勤设备(不需要Enable参数) + var devices = await DbContext.Queryable() + .Where(x => x.Type == DeviceTypeEnumType.Attendance || x.Type == DeviceTypeEnumType.Door && x.AsAttendance) + .ToListAsync(); + + //获取上传日志(有效的) + var deviceUniqueNos = devices.Select(x => x.UniqueNo).ToList(); + var logs = await DbContext.Queryable() + .Where(x => deviceUniqueNos.Contains(x.DeviceUniqueNo)) + .Where(x => !string.IsNullOrEmpty(x.UserUniqueNo)) + .Where(x => x.Sync == false) + .ToListAsync(); + + //获取人员信息 + var userCodes = logs.Select(x => x.UserUniqueNo).ToList(); + var gainfoCodes = await DbContext.Queryable().Where(x => userCodes.Contains(x.Code)).Select(x => x.Code).ToListAsync(); + + var requests = logs.Select(x => new UploadAttendanceRequest + { + Id = x.Id, + RaiseDateTime = x.RaiseDateTime, + ZNOTE = devices.First(item => item.UniqueNo == x.DeviceUniqueNo).DeployPlace, + ZWORKCODE = gainfoCodes.Contains(x.UserUniqueNo) ? x.UserUniqueNo?.TrimEnd('\0') : string.Empty, + + }).Where(x => x.ZWORKCODE.IsPresent()).ToList(); + + var ids = requests.Select(x => x.Id).ToList(); + if (ids.Any()) + { + var r = await _jinkoJIPService.UploadAttendancesAsync(requests); + if (r.OLX == "0") + { + await DbContext.Updateable() + .SetColumns(x => x.Sync == true) + .SetColumns(x => x.ModifiedTime == DateTime.Now) + .Where(x => ids.Contains(x.Id)) + .ExecuteCommandAsync(); + } + else + { + throw new Exception(r.OMS); + } + } + } +} diff --git a/Src/Dlhis.ScheduledTask/SyncSapInfo/Job/SyncPersonJob.cs b/Src/Dlhis.ScheduledTask/Jobs/SyncPersonJob.cs similarity index 68% rename from Src/Dlhis.ScheduledTask/SyncSapInfo/Job/SyncPersonJob.cs rename to Src/Dlhis.ScheduledTask/Jobs/SyncPersonJob.cs index 1d7e09af..981da2f5 100644 --- a/Src/Dlhis.ScheduledTask/SyncSapInfo/Job/SyncPersonJob.cs +++ b/Src/Dlhis.ScheduledTask/Jobs/SyncPersonJob.cs @@ -1,156 +1,147 @@ using System.Data; using System.Text; -using Kurisu.SqlSugar.Services; using Dlhis.Entity.Basic.Entity; using Dlhis.ScheduledTask.SyncSapInfo.Dto; using Dlhis.ScheduledTask.SyncSapInfo.Comparers; using Dlhis.ScheduledTask.SyncSapInfo.Services; -using Kurisu.AspNetCore.Scope; using Dlhis.Entity.Basic.Enums; using Dlhis.Sys.Api; using Dlhis.Sys.Api.Response; using SqlSugar; using Dlhis.Basic.Api; +using Kurisu.Scheduled; +using Kurisu.Scheduled.Attributes; -namespace Dlhis.ScheduledTask.SyncSapInfo.Job; +namespace Dlhis.ScheduledTask.Jobs; -public class SyncPersonJob +/// +/// SAP人员信息同步 +/// +[RecurringJob(nameof(SyncPersonJob), "0 0 1-4 * * ?", Name = "SAP人员信息同步", Queue = "SAP")] +public class SyncPersonJob : BaseJob { - private readonly ILogger _logger; private readonly IJinkoSapService _jinkoSapService; private readonly ITenantApi _tenantApi; private readonly IDevicePermissionApi _devicePermissionApi; - private List _positions; + private List _tenants; private List _departmentChanges; private List _jobChanges; - public SyncPersonJob(ILogger logger, IJinkoSapService jinkoSapService, - ITenantApi tenantApi, IDevicePermissionApi devicePermissionApi) + public SyncPersonJob( + IJinkoSapService jinkoSapService, + ITenantApi tenantApi, + IServiceProvider serviceProvider, + IDevicePermissionApi devicePermissionApi) : base(serviceProvider) { - _logger = logger; _jinkoSapService = jinkoSapService; _tenantApi = tenantApi; _devicePermissionApi = devicePermissionApi; } - public async Task RunAsync() + public override async Task RunAsync(IServiceProvider serviceProvider) { - _logger.LogInformation("开始获取SAP人员"); + Logger.LogWarning("开始获取SAP人员"); + DbContext.Client.QueryFilter.ClearAndBackup(); + var personResp = await _jinkoSapService.GetPersonsAsync(); var persons = personResp.Person.Items; _departmentChanges = personResp.DepartmentInfo.Items; _jobChanges = personResp.JobStatusInfo.Items; - _logger.LogInformation("获取SAP人员数量为:{count}", persons.Count); + Logger.LogWarning("获取SAP人员数量为:{count}", persons.Count); if (persons.Count > 0) { - Scoped.Temp.Value.Create(sp => + var modifiedPersons = GetModifiedPerson(persons.OrderByDescending(x => x.ZSTATUS).ThenBy(x => x.ZRZRQ).ToList()); + Logger.LogWarning("SAP人员差异数量为:{count}", modifiedPersons.Count); + if (modifiedPersons.Count > 0) { - var dbContext = sp.GetService(); - _positions = dbContext.Queryable().ToList(); - var modifiedPersons = GetModifiedPerson(dbContext, persons.OrderByDescending(x => x.ZSTATUS).ThenBy(x => x.ZRZRQ).ToList()); - _logger.LogInformation("SAP人员差异数量为:{count}", modifiedPersons.Count); - if (modifiedPersons.Count > 0) - { - var failedRecords = SavePerson(modifiedPersons); - } - }); + await SavePersonAsync(modifiedPersons); + } } - _logger.LogInformation("同步SAP人员数据结束"); + Logger.LogWarning("同步SAP人员数据结束"); } - private async Task SavePerson(List persons) + private async Task SavePersonAsync(List persons) { var tenantResult = await _tenantApi.GetTenantsInternalAsync(); _tenants = tenantResult.Data; - var failure = 0; var workCodes = persons.Select(x => x.ZWORKCODE).ToList(); var chunks = workCodes.Chunk(4000).ToList(); var dtoResult = await _devicePermissionApi.GetPermissionUsersInfoAsync(); var dto = dtoResult.Data; - Scoped.Temp.Value.Create(sp => + foreach (var searchCodes in chunks) { - var dbContext = sp.GetService(); + Logger.LogWarning("SAP分批处理Chunk数量:{count}", searchCodes.Length); + var existsWorkCodes = DbContext.Queryable() + .Where(x => searchCodes.Contains(x.ename)) + .Select(x => x.ename) + .ToList(); - foreach (var searchCodes in chunks) + var originUpdates = persons.Where(x => existsWorkCodes.Contains(x.ZWORKCODE)).ToList(); + var existsUpdateWorkCodes = originUpdates.Select(x => x.ZWORKCODE).ToList(); + var originInserts = persons.Where(x => searchCodes.Contains(x.ZWORKCODE)).Where(x => !existsUpdateWorkCodes.Contains(x.ZWORKCODE)).ToList(); + + int i = 0; + + var updates = ToGainfoSap(originUpdates); + Logger.LogWarning("SAP分批更新数:{count}", updates.Count); + var inserts = ToGainfoSap(originInserts); + Logger.LogWarning("SAP分批新增数:{count}", inserts.Count); + + foreach (var item in inserts) { - _logger.LogInformation("SAP分批处理Chunk数量:{count}", searchCodes.Length); - var existsWorkCodes = dbContext.Queryable() - .Where(x => searchCodes.Contains(x.ename)) - .Select(x => x.ename) - .ToList(); - - var originUpdates = persons.Where(x => existsWorkCodes.Contains(x.ZWORKCODE)).ToList(); - var existsUpdateWorkCodes = originUpdates.Select(x => x.ZWORKCODE).ToList(); - var originInserts = persons.Where(x => searchCodes.Contains(x.ZWORKCODE)).Where(x => !existsUpdateWorkCodes.Contains(x.ZWORKCODE)).ToList(); - - int i = 0; - var currentTotal = originUpdates.Count + originInserts.Count; - - var updates = ToGainfoSap(originUpdates); - _logger.LogInformation("SAP分批更新数:{count}", updates.Count); - var inserts = ToGainfoSap(originInserts); - _logger.LogInformation("SAP分批新增数:{count}", inserts.Count); - - foreach (var item in inserts) + i++; + try { - i++; - try - { - InsertPerson(dbContext, item); - _logger.LogInformation("执行新增成功 工号:{code},姓名:{name}", item.ename, item.gname); - } - catch (Exception ex) - { - failure++; - _logger.LogError(ex, "执行新增失败:{message}", ex.Message); - } - + InsertPerson(item); + Logger.LogWarning("执行新增成功 工号:{code},姓名:{name}", item.ename, item.gname); } - - foreach (var item in updates) + catch (Exception ex) { - i++; - try - { - UpdatePerson(dbContext, item); - _logger.LogInformation("执行更新成功 工号:{code},姓名:{name}", item.ename, item.gname); - } - catch (Exception ex) - { - failure++; - _logger.LogError(ex, "执行更新失败:{message}", ex.Message); - } + Logger.LogError(ex, "执行新增失败:{message}", ex.Message); } } - }); + + foreach (var item in updates) + { + i++; + try + { + UpdatePerson(item); + Logger.LogWarning("执行更新成功 工号:{code},姓名:{name}", item.ename, item.gname); + } + catch (Exception ex) + { + Logger.LogError(ex, "执行更新失败:{message}", ex.Message); + } + } + } var rResult = await _devicePermissionApi.RePermissionUsersInfoAsync(dto); var r = rResult.Data; - _logger.LogInformation("生成下发任务数量:{count}", r); - return 0; + Logger.LogWarning("生成下发任务数量:{count}", r); } - private void InsertPerson(IDbContext db, GainfoSapEntity item) + private void InsertPerson(GainfoSapEntity item) { - db.Client.Insertable(item).ExecuteCommand(); + DbContext.Client.Insertable(item).ExecuteCommand(); var info = GainfoSapToGainfo(item); if (item.isowner == "T") { - db.Client.Insertable(info).ExecuteCommand(); + DbContext.Client.Insertable(info).ExecuteCommand(); } else { - db.Client.Insertable(info).AS("GainfoLeave").ExecuteCommand(); + DbContext.Client.Insertable(info).AS("GainfoLeave").ExecuteCommand(); } } @@ -187,10 +178,10 @@ public class SyncPersonJob return info; } - private void UpdatePerson(IDbContext db, GainfoSapEntity item) + private void UpdatePerson(GainfoSapEntity item) { - var gainfoSap = db.Queryable().Where(x => x.ename == item.ename).First(); - db.Updateable().SetColumns(g => new GainfoSapEntity + var gainfoSap = DbContext.Queryable().Where(x => x.ename == item.ename).First(); + DbContext.Updateable().SetColumns(g => new GainfoSapEntity { PERNR = item.PERNR, gname = item.gname, @@ -211,14 +202,14 @@ public class SyncPersonJob .Where(x => x.ename == item.ename) .ExecuteCommand(); - var gainfo = db.Queryable().Where(x => x.Code == item.ename).First(); + var gainfo = DbContext.Queryable().Where(x => x.Code == item.ename).First(); if (item.isowner == "T") { if (gainfo != null) { var workplace = _tenants.FirstOrDefault(x => x.Name == item.ZZ_GZDJDNM)?.Code ?? item.ZZ_GZDJDNM; var factory = _tenants.FirstOrDefault(x => x.Name == item.ZZ_GZDCQNM)?.Code ?? item.ZZ_GZDCQNM; - db.Updateable().SetColumns(g => new GainfoEntity + DbContext.Updateable().SetColumns(g => new GainfoEntity { SapNo = item.PERNR, Name = item.gname, @@ -240,23 +231,23 @@ public class SyncPersonJob else { var info = GainfoSapToGainfo(item); - db.Client.Insertable(info).ExecuteCommand(); + DbContext.Client.Insertable(info).ExecuteCommand(); } } else { if (gainfo != null) { - db.Client.Deleteable(gainfo).ExecuteCommand(); + DbContext.Client.Deleteable(gainfo).ExecuteCommand(); gainfo.Id = 0; - db.Client.Insertable(gainfo).AS("GainfoLeave").ExecuteCommand(); + DbContext.Client.Insertable(gainfo).AS("GainfoLeave").ExecuteCommand(); } } } - private List GetModifiedPerson(IDbContext db, List sapList) + private List GetModifiedPerson(List sapList) { - var last = LoadData(db); + var last = LoadData(); if (last.Count <= 0) { return sapList; @@ -294,9 +285,9 @@ public class SyncPersonJob } - private static List LoadData(IDbContext db) + private List LoadData() { - var gainfo = db.Queryable().ToList(); + var gainfo = DbContext.Queryable().ToList(); return gainfo.Select(x => new SapPersonItem { @@ -335,7 +326,7 @@ public class SyncPersonJob GainfoSapEntity o = null; try { - var position = _positions.FirstOrDefault(x => x.No == person.PLANS); + //var position = _positions.FirstOrDefault(x => x.No == person.PLANS); var rzrq = SafeParseDate(person.ZRZRQ); var lzrq = SafeParseDate(person.ZLZRQ); @@ -378,7 +369,7 @@ public class SyncPersonJob remark = rmk, native = native, sex = sex, - web = SubString(position?.Name ?? "", 30), + //web = SubString(position?.Name ?? "", 30), logdate = DateTime.Now, isowner = int.Parse(person.ZSTATUS) < 5 ? "T" : "F", @class = "C", @@ -409,7 +400,7 @@ public class SyncPersonJob { if (string.IsNullOrWhiteSpace(idno) || idno.Length < 6) return null; idno = idno.TrimStart(); - return idno.Substring(0, 6); + return idno[..6]; } private static DateTime? SafeParseDate(string str) diff --git a/Src/Dlhis.ScheduledTask/SyncSapInfo/Job/SyncPositionJob.cs b/Src/Dlhis.ScheduledTask/Jobs/SyncPositionJob.cs similarity index 60% rename from Src/Dlhis.ScheduledTask/SyncSapInfo/Job/SyncPositionJob.cs rename to Src/Dlhis.ScheduledTask/Jobs/SyncPositionJob.cs index 346668a5..173b3743 100644 --- a/Src/Dlhis.ScheduledTask/SyncSapInfo/Job/SyncPositionJob.cs +++ b/Src/Dlhis.ScheduledTask/Jobs/SyncPositionJob.cs @@ -1,33 +1,31 @@ using Dlhis.Entity.Basic.Entity; using Dlhis.ScheduledTask.SyncSapInfo.Dto; using Dlhis.ScheduledTask.SyncSapInfo.Services; -using Kurisu.SqlSugar.Services; +using Kurisu.Scheduled; +using Kurisu.Scheduled.Attributes; -namespace Dlhis.ScheduledTask.SyncSapInfo.Job; +namespace Dlhis.ScheduledTask.Jobs; /// -/// 职位同步定时任务 +/// SAP岗位信息同步 /// -public class SyncPositionJob +[RecurringJob(nameof(SyncPositionJob), "0 0 0 * * ?", Name = "SAP岗位信息同步", Queue = "SAP")] +public class SyncPositionJob : BaseJob { - private readonly IDbContext _dbContext; private readonly IJinkoSapService _jinkoSapService; - private readonly ILogger _logger; - public SyncPositionJob(IDbContext dbContext, IJinkoSapService jinkoSapService, ILogger logger) + public SyncPositionJob(IServiceProvider serviceProvider, IJinkoSapService jinkoSapService) : base(serviceProvider) { - _dbContext = dbContext; _jinkoSapService = jinkoSapService; - _logger = logger; } - public async Task RunAsync() + public override async Task RunAsync(IServiceProvider serviceProvider) { var positionResult = await _jinkoSapService.GetPositionsAsync(); if (positionResult.Position != null && positionResult.Position.Items.Count > 0) { - _logger.LogWarning("SAP岗位数量:{count}", positionResult.Position.Items.Count); + Logger.LogWarning("SAP岗位数量:{count}", positionResult.Position.Items.Count); await SaveOrg(positionResult.Position.Items); } } @@ -36,7 +34,7 @@ public class SyncPositionJob { foreach (var item in modifiedPostList) { - var position = await _dbContext.Queryable().Where(x => x.No == item.ZJOBID).FirstAsync(); + var position = await DbContext.Queryable().Where(x => x.No == item.ZJOBID).FirstAsync(); if (position == null) { position = new PositionEntity @@ -47,7 +45,7 @@ public class SyncPositionJob Grade = item.ZZWID }; - await _dbContext.InsertAsync(position); + await DbContext.InsertAsync(position); } else { @@ -55,7 +53,7 @@ public class SyncPositionJob position.DepartmentNo = item.ZDEPID; position.Grade = item.ZZWID; - await _dbContext.UpdateAsync(position); + await DbContext.UpdateAsync(position); } } } diff --git a/Src/Dlhis.ScheduledTask/Jobs/UpdateUserPasswordJob.cs b/Src/Dlhis.ScheduledTask/Jobs/UpdateUserPasswordJob.cs new file mode 100644 index 00000000..9998991f --- /dev/null +++ b/Src/Dlhis.ScheduledTask/Jobs/UpdateUserPasswordJob.cs @@ -0,0 +1,111 @@ +using Dlhis.Entity.Basic.Entity; +using Dlhis.Entity.Sys.Entities; +using Kurisu.AspNetCore.Utils.Extensions; +using Kurisu.Scheduled; +using Kurisu.Scheduled.Attributes; +using Kurisu.SqlSugar.Services; +using Microsoft.AspNetCore.Identity; + +namespace Dlhis.ScheduledTask.Jobs; + +/// +/// 用户创建 +/// +[RecurringJob(nameof(UpdateUserPasswordJob), "0 0 6 * * ?", Name = "用户创建")] +public class UpdateUserPasswordJob : BaseJob +{ + public UpdateUserPasswordJob(IServiceProvider serviceProvider) : base(serviceProvider) + { + } + + public override async Task RunAsync(IServiceProvider serviceProvider) + { + + var identityDbContext = DbContext.ChangeDb("identity"); + + var whitelist = new List() { "admin", "WB-0741", "WB-1091", "0123456" }; + + var users = await identityDbContext.Queryable() + .Where(x => !whitelist.Contains(x.UserName)) + .ToListAsync(); + + var gainfos = await DbContext.Queryable().Where(x => !whitelist.Contains(x.Code)).ToListAsync(); + + var hasher = new PasswordHasher(); + foreach (var gainfo in gainfos) + { + if (gainfo.IdNo.IsPresent()) + { + try + { + var password = gainfo.IdNo.TakeLast(6).Join(""); + + var user = users.FirstOrDefault(x => x.UserName == gainfo.Code); + if (user == null) + { + user = new UserEntity + { + UserName = gainfo.Code, + NormalizedUserName = gainfo.Code.ToUpper(), + ConcurrencyStamp = Guid.NewGuid().ToString(), + SecurityStamp = Guid.NewGuid().ToString(), + }; + password = hasher.HashPassword(user, password); + user.PasswordHash = password; + + var id = (int)await identityDbContext.InsertReturnIdentityAsync(user); + await AddUserClaim(identityDbContext, id, "jinko-code", gainfo.Code); + await AddUserClaim(identityDbContext, id, "name", gainfo.Name); + if (!string.IsNullOrEmpty(gainfo.Factory)) + { + var userTenant = await identityDbContext.Queryable().Where(x => x.UserId == user.Id).FirstAsync(); + if (userTenant == null) + { + userTenant = new UserTenantEntity + { + UserId = user.Id, + TenantCode = gainfo.Factory + }; + await identityDbContext.InsertAsync(userTenant); + } + else + { + userTenant.TenantCode = gainfo.Factory; + await identityDbContext.UpdateAsync(userTenant); + } + } + } + else + { + password = hasher.HashPassword(user, password); + user.PasswordHash = password; + await identityDbContext.UpdateAsync(user); + } + } + catch (Exception) + { + } + } + } + } + + private async Task AddUserClaim(IDbContext dbContext, int userId, string type, string value) + { + var claim = await dbContext.Queryable().Where(x => x.UserId == userId).FirstAsync(x => x.ClaimType == type); + if (claim == null) + { + claim = new UserClaimEntity() + { + UserId = userId, + ClaimType = type, + ClaimValue = value + }; + await dbContext.InsertAsync(claim); + } + else + { + claim.ClaimValue = value; + await dbContext.UpdateAsync(claim); + } + } +} diff --git a/Src/Dlhis.ScheduledTask/Packs/HangfirePack.cs b/Src/Dlhis.ScheduledTask/Packs/HangfirePack.cs index 9e90db6e..5d7179ec 100644 --- a/Src/Dlhis.ScheduledTask/Packs/HangfirePack.cs +++ b/Src/Dlhis.ScheduledTask/Packs/HangfirePack.cs @@ -22,7 +22,8 @@ public class HangfirePack : BaseAppPack { Db = 5, Prefix = "hangfire" - }); + }) + .UseSerilogLogProvider(); }); diff --git a/Src/Dlhis.ScheduledTask/Packs/JobPack.cs b/Src/Dlhis.ScheduledTask/Packs/JobPack.cs index ba1cb6b0..40e77023 100644 --- a/Src/Dlhis.ScheduledTask/Packs/JobPack.cs +++ b/Src/Dlhis.ScheduledTask/Packs/JobPack.cs @@ -1,8 +1,12 @@ -using Dlhis.ScheduledTask.CommonJobs; -using Dlhis.ScheduledTask.SyncSapInfo.Job; -using Dlhis.ScheduledTask.TaskAssignment.Job; +using System.Linq.Expressions; +using System.Reflection; using Hangfire; +using Hangfire.Common; using Kurisu.AspNetCore.Startup; +using Kurisu.AspNetCore.Utils.Extensions; +using Kurisu.Scheduled; +using Kurisu.Scheduled.Attributes; +using SqlSugar; namespace Dlhis.ScheduledTask.Packs; @@ -13,68 +17,34 @@ public class JobPack : BaseAppPack public override void Invoke(IServiceProvider serviceProvider) { - RecurringJob.AddOrUpdate("SyncSap", s => s.RunAsync(), "0 0 2 * * ?", new RecurringJobOptions - { - TimeZone = TimeZoneInfo.Local - }); + var logger = serviceProvider.GetService>(); - RecurringJob.AddOrUpdate("SyncPerson", s => s.RunAsync(), "0 0 3 * * ?", new RecurringJobOptions - { - TimeZone = TimeZoneInfo.Local - }); + var jobs = Assembly.GetEntryAssembly().GetTypes() + .Where(x => x.IsAssignableTo(typeof(BaseJob)) && x != typeof(BaseJob)) + .Where(x => x.IsDefined(typeof(RecurringJobAttribute))) + .ToList(); - //创建设备同步时间任务 - RecurringJob.AddOrUpdate("SyncServerDateTime", s => s.RunAsync(), "0 0 0/1 * * ?", new RecurringJobOptions - { - TimeZone = TimeZoneInfo.Local - }); + var setJob = typeof(Job).GetMethod(nameof(Job.FromExpression), BindingFlags.NonPublic | BindingFlags.Static, new[] { typeof(LambdaExpression), typeof(Type), typeof(string) }); + var m = (Lazy)typeof(RecurringJob).GetField("Instance", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null); - //创建设备获取的任务 - RecurringJob.AddOrUpdate("CreateGetUploadRecord", s => s.RunAsync(), "0 0/1 * * * ?", new RecurringJobOptions - { - TimeZone = TimeZoneInfo.Local - }); + (jobs.Select(job => job.GetCustomAttribute().UniqueJobKey).Distinct().Count() != jobs.Count).ThrowIfTrue("任务key重复"); - //创建系统默认分组 - RecurringJob.AddOrUpdate("CreateDefinitelyGroup", s => s.RunAsync(), "0 0 5 * * ?", new RecurringJobOptions - { - TimeZone = TimeZoneInfo.Local - }); + logger.LogDebug("一共获取{count}个调度任务", jobs.Count); - //心跳 - RecurringJob.AddOrUpdate("Heartbeat", s => s.RunAsync(), "0/10 * * * * ?", new RecurringJobOptions + foreach (var job in jobs) { - TimeZone = TimeZoneInfo.Local - }); + var recurringSetting = job.GetCustomAttribute()!; + recurringSetting.Cron.IsEmpty().ThrowIfTrue(job.Name + "尚未定义Cron"); - //上传考勤记录 - RecurringJob.AddOrUpdate("SyncOriginCardInfo", s => s.RunAsync(), "0/20 * * * * ?", new RecurringJobOptions - { - TimeZone = TimeZoneInfo.Local - }); + var parameterExpression = Expression.Parameter(job); + var todo = job.GetMethod(nameof(BaseJob.TodoAsync)); + var todoExp = Expression.Call(parameterExpression, todo); - //处理重复下发任务 - RecurringJob.AddOrUpdate("CancelDuplicationTask", s => s.RunAsync(), "0/15 * * * * ?", new RecurringJobOptions - { - TimeZone = TimeZoneInfo.Local - }); - - //更新用户密码 - RecurringJob.AddOrUpdate("UpdateUserPassword", s => s.RunAsync(), "0 0 5 * * ?", new RecurringJobOptions - { - TimeZone = TimeZoneInfo.Local - }); - - //删除前三天前的日志 - RecurringJob.AddOrUpdate("DelApiLogTask", s => s.RunAsync(), "0 0 */7 * *", new RecurringJobOptions - { - TimeZone = TimeZoneInfo.Local - }); - - //处理餐补 - RecurringJob.AddOrUpdate("MealSupplementHandler", s => s.RunAsync(), "0 0 0/1 * * ?", new RecurringJobOptions - { - TimeZone = TimeZoneInfo.Local - }); + var nJob = (Job)setJob.Invoke(null, new object[] { Expression.Lambda(todoExp), job, "default" }); + m.Value.AddOrUpdate(recurringSetting.UniqueJobKey, nJob, recurringSetting.Cron, new RecurringJobOptions + { + TimeZone = TimeZoneInfo.Local + }); + } } } diff --git a/Src/Dlhis.ScheduledTask/SyncSapInfo/Job/SyncOriginCardInfoJob.cs b/Src/Dlhis.ScheduledTask/SyncSapInfo/Job/SyncOriginCardInfoJob.cs deleted file mode 100644 index 88f2c0f5..00000000 --- a/Src/Dlhis.ScheduledTask/SyncSapInfo/Job/SyncOriginCardInfoJob.cs +++ /dev/null @@ -1,95 +0,0 @@ -using Dlhis.Entity.Basic.Entity; -using Dlhis.Entity.Device.Entities; -using Dlhis.Entity.Device.Enums; -using Dlhis.ScheduledTask.SyncSapInfo.Services; -using Kurisu.AspNetCore.Utils.Extensions; -using Kurisu.Core.DataAccess.Entity; -using Kurisu.SqlSugar.Services; -using SqlSugar; - -namespace Dlhis.ScheduledTask.SyncSapInfo.Job; - -public class SyncOriginCardInfoJob -{ - private readonly IJinkoJIPService _jinkoJIPService; - private readonly IDbContext _dbContext; - private readonly ISqlSugarOptionsService _sqlSugarOptionsService; - private readonly ILogger _logger; - - public SyncOriginCardInfoJob(IJinkoJIPService jinkoJIPService, - IDbContext dbContext, - ISqlSugarOptionsService sqlSugarOptionsService, - ILogger logger - ) - { - _jinkoJIPService = jinkoJIPService; - _dbContext = dbContext; - _sqlSugarOptionsService = sqlSugarOptionsService; - _logger = logger; - } - - public async Task RunAsync() - { - _logger.LogInformation("调度任务:{job}.开始执行", nameof(SyncOriginCardInfoJob)); - - _dbContext.Client.QueryFilter.ClearAndBackup(); - _sqlSugarOptionsService.IgnoreTenant = true; - try - { - //考勤设备(不需要Enable参数) - var devices = await _dbContext.Queryable() - .Where(x => x.Type == DeviceTypeEnumType.Attendance || (x.Type == DeviceTypeEnumType.Door && x.AsAttendance)) - .ToListAsync(); - - //获取上传日志(有效的) - var deviceUniqueNos = devices.Select(x => x.UniqueNo).ToList(); - var logs = await _dbContext.Queryable() - .Where(x => deviceUniqueNos.Contains(x.DeviceUniqueNo)) - .Where(x => !string.IsNullOrEmpty(x.UserUniqueNo)) - .Where(x => x.Sync == false) - .ToListAsync(); - - //获取人员信息 - var userCodes = logs.Select(x => x.UserUniqueNo).ToList(); - var gainfoCodes = await _dbContext.Queryable().Where(x => userCodes.Contains(x.Code)).Select(x => x.Code).ToListAsync(); - - var requests = logs.Select(x => new UploadAttendanceRequest - { - Id = x.Id, - RaiseDateTime = x.RaiseDateTime, - ZNOTE = devices.First(item => item.UniqueNo == x.DeviceUniqueNo).DeployPlace, - ZWORKCODE = gainfoCodes.Contains(x.UserUniqueNo) ? x.UserUniqueNo?.TrimEnd('\0') : string.Empty, - - }).Where(x => x.ZWORKCODE.IsPresent()).ToList(); - - var ids = requests.Select(x => x.Id).ToList(); - if (ids.Any()) - { - var r = await _jinkoJIPService.UploadAttendancesAsync(requests); - if (r.OLX == "0") - { - await _dbContext.Updateable() - .SetColumns(x => x.Sync == true) - .SetColumns(x => x.ModifiedTime == DateTime.Now) - .Where(x => ids.Contains(x.Id)) - .ExecuteCommandAsync(); - } - else - { - throw new Exception(r.OMS); - } - } - } - catch (Exception ex) - { - _logger.LogError("上传考勤记录失败:{message}", ex.Message); - } - finally - { - _sqlSugarOptionsService.IgnoreTenant = false; - _dbContext.Client.QueryFilter.Restore(); - - _logger.LogInformation("调度任务:{job}.结束", nameof(SyncOriginCardInfoJob)); - } - } -} diff --git a/Src/Dlhis.ScheduledTask/SyncSapInfo/Services/Implements/JinkoJIPService.cs b/Src/Dlhis.ScheduledTask/SyncSapInfo/Services/Implements/JinkoJIPService.cs index 0b9d512f..d93f6753 100644 --- a/Src/Dlhis.ScheduledTask/SyncSapInfo/Services/Implements/JinkoJIPService.cs +++ b/Src/Dlhis.ScheduledTask/SyncSapInfo/Services/Implements/JinkoJIPService.cs @@ -60,7 +60,7 @@ public class JinkoJIPService : IJinkoJIPService { var requestUrl = "/JIP/DHR/DHR_DL_CALLBACK_UAT"; - var json = requests.ToJson(); + var json = requests.ToJson(Kurisu.AspNetCore.Utils.Extensions.JsonExtensions.DefaultSetting); var content = new StringContent(json, Encoding.UTF8, "application/json"); var response = await GetHttpClient().PostAsync(requestUrl, content); diff --git a/Src/Dlhis.ScheduledTask/SyncSapInfo/Services/Implements/JinkoSapService.cs b/Src/Dlhis.ScheduledTask/SyncSapInfo/Services/Implements/JinkoSapService.cs index 9d25a50b..af6afb0f 100644 --- a/Src/Dlhis.ScheduledTask/SyncSapInfo/Services/Implements/JinkoSapService.cs +++ b/Src/Dlhis.ScheduledTask/SyncSapInfo/Services/Implements/JinkoSapService.cs @@ -112,10 +112,12 @@ public class JinkoSapService : IJinkoSapService { departmentInfos.AddRange(personResp.DepartmentInfo.Items); } + + _logger.LogInformation("获取人事范围{werk}完成", item.Werk); } catch (Exception ex) { - _logger.LogError(ex, "获取人事范围{werk}失败:{message}", ex.Message, item.Werk); + _logger.LogError(ex, "获取人事范围{werk}失败:{message}", item.Werk, ex.Message); } } diff --git a/Src/Dlhis.ScheduledTask/TaskAssignment/Job/CreateGetUploadRecordJob.cs b/Src/Dlhis.ScheduledTask/TaskAssignment/Job/CreateGetUploadRecordJob.cs deleted file mode 100644 index d11caa4c..00000000 --- a/Src/Dlhis.ScheduledTask/TaskAssignment/Job/CreateGetUploadRecordJob.cs +++ /dev/null @@ -1,70 +0,0 @@ -using Dlhis.Entity.Basic.Entity; -using Dlhis.Entity.Device.Entities; -using Dlhis.Entity.Device.Enums; -using Kurisu.AspNetCore.Utils.Extensions; -using Kurisu.Core.DataAccess.Entity; -using Kurisu.SqlSugar.Services; - -namespace Dlhis.ScheduledTask.TaskAssignment.Job; - -public class CreateGetUploadRecordJob -{ - private readonly IDbContext _dbContext; - private readonly ILogger _logger; - private readonly ISqlSugarOptionsService _sqlSugarOptionsService; - - public CreateGetUploadRecordJob(IDbContext dbContext, ILogger logger, ISqlSugarOptionsService sqlSugarOptionsService) - { - _logger = logger; - _sqlSugarOptionsService = sqlSugarOptionsService; - _dbContext = dbContext; - } - - public async Task RunAsync() - { - _dbContext.Client.QueryFilter.ClearAndBackup(); - _sqlSugarOptionsService.IgnoreTenant = true; - try - { - var devices = await _dbContext.Queryable() - .Where(x => x.Enable) - .Where(x => x.Type == DeviceTypeEnumType.Attendance || x.Type == DeviceTypeEnumType.Door) - .ToListAsync(); - - //过滤处理中的任务 - var currentUniqueNos = await _dbContext.Queryable() - .Where(x => x.Type == DeviceTaskEnumType.UploadRecord) - .Where(x => x.Status == DeviceTaskStatusEnumType.Process || x.Status == DeviceTaskStatusEnumType.Wait) - .Select(x => x.DeviceUniqueNo) - .ToListAsync(); - - var tasks = devices.Where(x => !currentUniqueNos.Contains(x.UniqueNo)).Select(x => new DeviceTaskEntity - { - DeviceUniqueNo = x.UniqueNo, - Status = DeviceTaskStatusEnumType.Wait, - - TenantId = x.TenantId, - Version = 0, - Type = DeviceTaskEnumType.UploadRecord, - - CreatedBy = 1, - CreateTime = DateTime.Now, - ModifiedBy = 1, - ModifiedTime = DateTime.Now, - - }) - .ToList(); - - await _dbContext.InsertAsync(tasks); - } - catch (Exception ex) - { - _logger.LogError(ex, "生成{type}任务失败:{message}", DeviceTaskEnumType.UploadRecord.GetDescription(), ex.Message); - } - finally - { - _sqlSugarOptionsService.IgnoreTenant = false; - _dbContext.Client.QueryFilter.Restore(); - } - } -} diff --git a/Src/Dlhis.ScheduledTask/TaskAssignment/Job/CreateSyncServerDateTimeJob.cs b/Src/Dlhis.ScheduledTask/TaskAssignment/Job/CreateSyncServerDateTimeJob.cs deleted file mode 100644 index a8efb1c1..00000000 --- a/Src/Dlhis.ScheduledTask/TaskAssignment/Job/CreateSyncServerDateTimeJob.cs +++ /dev/null @@ -1,71 +0,0 @@ -using Dlhis.Entity.Basic.Entity; -using Dlhis.Entity.Device.Entities; -using Dlhis.Entity.Device.Enums; -using Kurisu.Core.DataAccess.Entity; -using Kurisu.SqlSugar.Services; - -namespace Dlhis.ScheduledTask.TaskAssignment.Job -{ - public class CreateSyncServerDateTimeJob - { - private readonly IDbContext _dbContext; - private readonly ILogger _logger; - private readonly ISqlSugarOptionsService _sqlSugarOptionsService; - - public CreateSyncServerDateTimeJob(IDbContext dbContext, ILogger logger, ISqlSugarOptionsService sqlSugarOptionsService) - { - _dbContext = dbContext; - _logger = logger; - _sqlSugarOptionsService = sqlSugarOptionsService; - } - - - public async Task RunAsync() - { - _dbContext.Client.QueryFilter.ClearAndBackup(); - _sqlSugarOptionsService.IgnoreTenant = true; - try - { - var deviceUniqueNos = await _dbContext.Queryable() - .Where(x => x.Status == DeviceTaskStatusEnumType.Wait || x.Status == DeviceTaskStatusEnumType.Process) - .Where(x => x.Type == DeviceTaskEnumType.SyncDateTime) - .Select(x => x.DeviceUniqueNo) - .Distinct() - .ToListAsync(); - - var devices = await _dbContext.Queryable() - .Where(x => !deviceUniqueNos.Contains(x.UniqueNo)) - .Where(x => x.Enable) - .ToListAsync(); - - var tasks = devices.Select(x => new DeviceTaskEntity - { - DeviceUniqueNo = x.UniqueNo, - Status = DeviceTaskStatusEnumType.Wait, - - TenantId = x.TenantId, - Version = 0, - UserNo = string.Empty, - Type = DeviceTaskEnumType.SyncDateTime, - - CreatedBy = 1, - CreateTime = DateTime.Now, - ModifiedBy = 1, - ModifiedTime = DateTime.Now, - - }).ToList(); - - await _dbContext.InsertAsync(tasks); - } - catch (Exception ex) - { - _logger.LogError(ex, "生成同步时间任务失败:{message}", ex.Message); - } - finally - { - _sqlSugarOptionsService.IgnoreTenant = false; - _dbContext.Client.QueryFilter.Restore(); - } - } - } -} diff --git a/Src/Dlhis.ScheduledTask/TaskAssignment/Services/Implements/DeviceTaskAssignmentService.cs b/Src/Dlhis.ScheduledTask/TaskAssignment/Services/Implements/DeviceTaskAssignmentService.cs index cec44059..e5dcbada 100644 --- a/Src/Dlhis.ScheduledTask/TaskAssignment/Services/Implements/DeviceTaskAssignmentService.cs +++ b/Src/Dlhis.ScheduledTask/TaskAssignment/Services/Implements/DeviceTaskAssignmentService.cs @@ -80,7 +80,6 @@ public class DeviceTaskAssignmentService : IDeviceTaskAssignmentService { var tasks = await _dbContext.Queryable() .Where(x => request.Ids.Contains(x.Id)) - .Where(x => x.Status == DeviceTaskStatusEnumType.Process || x.Status == DeviceTaskStatusEnumType.Error) .ToListAsync(); //判断process任务时间 diff --git a/Src/Dlhis.ScheduledTask/appsettings.json b/Src/Dlhis.ScheduledTask/appsettings.json index 92cb3b23..216d65e7 100644 --- a/Src/Dlhis.ScheduledTask/appsettings.json +++ b/Src/Dlhis.ScheduledTask/appsettings.json @@ -52,9 +52,9 @@ }, "JinkoOptions": { "Jip": { - "BaseUrl": "http://172.16.202.34:8000", - "Key": "FACE-7409WIBX", - "Secret": "be0a4b88-cd80-4509-b9b9-865205d0d3d8" + "BaseUrl": "http://jip.jinkosolar.com", + "Key": "FACE-CUOJG9N7", + "Secret": "130c2f2d-03a0-4720-8e25-538ffac7a7cb" } }, "RedisOptions": { @@ -63,12 +63,12 @@ "AllowedHosts": "*", "Serilog": { "MinimumLevel": { - "Default": "Information", + "Default": "Warning", "Override": { "System": "Warning", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information", - "Hangfire": "Information" + "Hangfire": "Warning" } }, "WriteTo": [