refactor 封装任务,调整人员获取

This commit is contained in:
2024-03-29 10:43:13 +08:00
parent 1d2572e617
commit e2c8dcf8d5
30 changed files with 976 additions and 1003 deletions

View File

@@ -0,0 +1,6 @@
namespace Kurisu.Scheduled.Abstractions;
public interface IJob
{
Task TodoAsync();
}

View File

@@ -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";
}

View File

@@ -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<ILogger<BaseJob>>();
DbContext = scope.ServiceProvider.GetService<IDbContext>();
var sqlSugarOptionsService = scope.ServiceProvider.GetService<ISqlSugarOptionsService>();
DbContext.Client.QueryFilter.ClearAndBackup<ITenantId>();
sqlSugarOptionsService.IgnoreTenant = true;
var name = this.GetType().GetCustomAttribute<RecurringJobAttribute>()!.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);
}

View File

@@ -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<CancelDuplicationTaskJob> _logger;
public CancelDuplicationTaskJob(IServiceProvider serviceProvider, ILogger<CancelDuplicationTaskJob> logger)
{
_serviceProvider = serviceProvider;
_logger = logger;
}
public async Task RunAsync()
{
_logger.LogInformation("抵消任务开始处理");
using (var scope = _serviceProvider.CreateScope())
{
var optionService = scope.ServiceProvider.GetService<ISqlSugarOptionsService>();
var db = scope.ServiceProvider.GetService<IDbContext>();
db.Client.QueryFilter.ClearAndBackup<ITenantId>();
optionService.IgnoreTenant = true;
try
{
//人员下发任务相关
var taskTypes = new List<DeviceTaskEnumType>() { DeviceTaskEnumType.Add, DeviceTaskEnumType.Delete, DeviceTaskEnumType.Update };
var deviceTasks = await db.Queryable<DeviceTaskEntity>()
.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<Func<DeviceTaskEntity, bool>> where = LinqExpressionExtension.False<DeviceTaskEntity>();
var ignoreData = new List<IdVersion>();
//最新一条更新人员信息
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<DeviceTaskEntity>().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<long> { 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<DeviceTaskEntity>()
.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; }
}
}

View File

@@ -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<DelApiLogTaskJob> _logger;
public DelApiLogTaskJob(IDbContext dbContext, ILogger<DelApiLogTaskJob> logger)
{
_dbContext = dbContext;
_logger = logger;
}
public async Task RunAsync()
{
try
{
DateTime before = DateTime.Now.Date.AddDays(-7);
await _dbContext.ChangeDb("log").Client.Deleteable<ApiLogEntity>().Where(x => x._ts <= before).ExecuteCommandAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, "删除日志异常:{message}", ex.Message);
}
}
}

View File

@@ -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<ITenantId>();
try
{
var devices = await _dbContext.Queryable<DeviceEntity>().Where(x => x.Enable).Where(x => x.HeartbeatInterval > 0).ToListAsync();
foreach (var device in devices)
{
try
{
var ipInfo = JsonConvert.DeserializeObject<IPPortDto>(device.ConnectionInfo);
//超时时间
var CancellationTokenSource = new CancellationTokenSource(300);
await new TcpClient().ConnectAsync(IPAddress.Parse(ipInfo.IP), ipInfo.Port, CancellationTokenSource.Token);
await _dbContext.Updateable<DeviceRegistryEntity>().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();
}
}
}

View File

@@ -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<MealSupplementHandlerJob> _logger;
private readonly IJinkoJIPService _jinkoJIPService;
public MealSupplementHandlerJob(IDbContext dbContext, ILogger<MealSupplementHandlerJob> logger, IJinkoJIPService jinkoJIPService)
{
_dbContext = dbContext;
_logger = logger;
_jinkoJIPService = jinkoJIPService;
}
public async Task RunAsync()
{
_dbContext.Client.QueryFilter.ClearAndBackup<ITenantId>();
try
{
//查询待处理餐补
var mealSupplements = await _dbContext.Queryable<MealSupplementRecordEntity>()
.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<GainfoEntity>().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<GainfoMealEntity>().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<GainfoMealEntity>().Where(x => x.UserCode == mealUser.UserCode).FirstAsync();
var b = mealUser.Balance += mealSupplement.Amount;
var effect = await _dbContext.Updateable<GainfoMealEntity>()
.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<MealSupplementRecordEntity>()
.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<SyncMealSupplementRecordRequest>
{
new()
{
UniqueId = mealSupplement.UniqueId,
Status = "SUCCESS",
Msg = "操作成功"
}
});
await _dbContext.Updateable<MealSupplementRecordEntity>()
.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<MealSupplementRecordEntity>()
.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<Task> 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 ?? "操作失败,请重试");
}
}

View File

@@ -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<UpdateUserPasswordJob> _logger;
public UpdateUserPasswordJob(
IDbContext dbContext,
ILogger<UpdateUserPasswordJob> logger)
{
_dbContext = dbContext;
_logger = logger;
}
public async Task RunAsync()
{
_dbContext.Client.QueryFilter.ClearAndBackup<ITenantId>();
try
{
var identityDbContext = _dbContext.ChangeDb("identity");
var whitelist = new List<string>() { "admin", "WB-0741", "WB-1091", "0123456" };
var users = await identityDbContext.Queryable<UserEntity>()
.Where(x => !whitelist.Contains(x.UserName))
.ToListAsync();
var gainfos = await _dbContext.Queryable<GainfoEntity>().Where(x => !whitelist.Contains(x.Code)).ToListAsync();
var hasher = new PasswordHasher<UserEntity>();
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<UserTenantEntity>().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<UserClaimEntity>().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);
}
}
}

View File

@@ -21,11 +21,11 @@
<PackageReference Include="Hangfire.Dashboard.BasicAuthorization" Version="1.0.2" />
<PackageReference Include="Hangfire.Redis.StackExchange" Version="1.9.3" />
<PackageReference Include="Kurisu.AspNetCore" Version="0.7.0" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Dlhis.Basic.Api\Dlhis.Basic.Api.csproj" />
<ProjectReference Include="..\Dlhis.Canteen.Api\Dlhis.Canteen.Api.csproj" />
<ProjectReference Include="..\Dlhis.Entity\Dlhis.Entity.csproj" />
<ProjectReference Include="..\Dlhis.Sys.Api\Dlhis.Sys.Api.csproj" />
</ItemGroup>

View File

@@ -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;
/// <summary>
/// 处理重复下发任务
/// </summary>
[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>() { DeviceTaskEnumType.Add, DeviceTaskEnumType.Delete, DeviceTaskEnumType.Update };
var deviceTasks = await DbContext.Queryable<DeviceTaskEntity>()
.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<Func<DeviceTaskEntity, bool>> where = LinqExpressionExtension.False<DeviceTaskEntity>();
var ignoreData = new List<IdVersion>();
//最新一条更新人员信息
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<DeviceTaskEntity>().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<long> { 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<DeviceTaskEntity>()
.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; }
}
}

View File

@@ -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
/// <summary>
/// 创建系统默认分组
/// </summary>
[RecurringJob(nameof(CreateDefinitelyGroupJob), "0 0 5 * * ?", Name = "创建系统默认分组")]
public class CreateDefinitelyGroupJob : BaseJob
{
private readonly ILogger<CreateDefinitelyGroupJob> _logger;
private readonly ITenantApi _tenantApi;
private readonly IDbContext _dbContext;
public CreateDefinitelyGroupJob(ILogger<CreateDefinitelyGroupJob> 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<ITenantId>();
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<string> { "*通用考勤设备组", "*专用考勤设备组" }, tenants);
await CreateDeviceGroupAsync(DeviceTypeEnumType.Attendance, new List<string> { "*通用考勤设备组", "*专用考勤设备组" }, tenants);
//*****************************************************门禁设备组********************************************************/
//*****************************************************门禁设备组********************************************************/
await CreateDeviceGroupAsync(DeviceTypeEnumType.Door, new List<string> { "*共用区域", "*非共用区域" }, tenants);
await CreateDeviceGroupAsync(DeviceTypeEnumType.Door, new List<string> { "*共用区域", "*非共用区域" }, tenants);
}
catch (Exception ex)
{
_logger.LogError(ex, "自动创建系统分组失败:{message}", ex.Message);
}
finally
{
_dbContext.Client.QueryFilter.Restore();
}
}
private async Task CreateGainfoGroupsAsync(List<TenantResponse> tenants)
{
var grps = new List<string> { "*自定义人员分组", "*督查组", "*X3及以上领导组" };
var searchGrps = await _dbContext.Queryable<GainfoGroupEntity>().Where(x => grps.Contains(x.Name)).ToListAsync();
var searchGrps = await DbContext.Queryable<GainfoGroupEntity>().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<DeviceGroupEntity>().FirstAsync(x => x.Name == grp);
var topGrp = await DbContext.Queryable<DeviceGroupEntity>().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<DeviceGroupEntity>().Where(x => x.PCode == topGrp.Code).FirstAsync(x => x.Name == workplaceName);
var workplaceGrp = await DbContext.Queryable<DeviceGroupEntity>().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<DeviceGroupEntity>().Where(x => x.PCode == workplaceGrp.Code).AnyAsync(x => x.Name == factoryName))
if (!await DbContext.Queryable<DeviceGroupEntity>().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(),

View File

@@ -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;
/// <summary>
/// 创建上传设备数据任务
/// </summary>
[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<DeviceEntity>()
.Where(x => x.Enable)
.Where(x => x.Type == DeviceTypeEnumType.Attendance || x.Type == DeviceTypeEnumType.Door)
.ToListAsync();
//过滤处理中的任务
var currentUniqueNos = await DbContext.Queryable<DeviceTaskEntity>()
.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);
}
}

View File

@@ -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;
/// <summary>
/// 设备时间同步
/// </summary>
[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<DeviceTaskEntity>()
.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<DeviceEntity>()
.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);
}
}

View File

@@ -0,0 +1,25 @@
using Dlhis.Entity.Common;
using Kurisu.Scheduled;
using Kurisu.Scheduled.Attributes;
namespace Dlhis.ScheduledTask.Jobs;
/// <summary>
/// 删除过期日志
/// </summary>
[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<ApiLogEntity>().Where(x => x._ts <= before).ExecuteCommandAsync();
}
}

View File

@@ -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;
/// <summary>
/// 设备心跳
/// </summary>
[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<DeviceEntity>().Where(x => x.Enable).Where(x => x.HeartbeatInterval > 0).ToListAsync();
foreach (var device in devices)
{
try
{
var ipInfo = JsonConvert.DeserializeObject<IPPortDto>(device.ConnectionInfo);
//超时时间
var CancellationTokenSource = new CancellationTokenSource(300);
await new TcpClient().ConnectAsync(IPAddress.Parse(ipInfo.IP), ipInfo.Port, CancellationTokenSource.Token);
await DbContext.Updateable<DeviceRegistryEntity>().SetColumns(x => x.LastHeartbeatTime == DateTime.Now)
.Where(x => x.DeviceUniqueNo == device.UniqueNo).ExecuteCommandAsync();
}
catch (Exception)
{
}
}
}
}

View File

@@ -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;
/// <summary>
/// 餐补核算
/// </summary>
[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<MealSupplementRecordEntity>()
.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<GainfoEntity>().Where(x => x.Code == item.Code).SingleAsync();
//档案不存在
if (gainfo == null)
{
await DbContext.Updateable<MealSupplementRecordEntity>()
.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<GainfoMealEntity>().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<GainfoMealEntity>().Where(x => x.UserCode == mealSupplement.Code).FirstAsync();
var b = mealUser.Balance += mealSupplement.Amount;
var effect = await DbContext.Updateable<GainfoMealEntity>()
.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<MealSupplementRecordEntity>()
.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<SyncMealSupplementRecordRequest>
{
new()
{
UniqueId = mealSupplement.UniqueId,
Status = "SUCCESS",
Msg = "操作成功"
}
});
await DbContext.Updateable<MealSupplementRecordEntity>()
.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<MealSupplementRecordEntity>()
.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<MealSupplementRecordEntity>()
.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<SyncMealSupplementRecordRequest>
{
new()
{
UniqueId = mealSupplement.UniqueId,
Status = "SUCCESS",
Msg = "操作成功"
}
});
await DbContext.Updateable<MealSupplementRecordEntity>()
.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<MealSupplementRecordEntity>()
.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<Task> 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 ?? "操作失败,请重试");
}
}

View File

@@ -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;
/// <summary>
/// 部门同步定时任务
/// SAP组织架构数据同步
/// </summary>
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<SyncPositionJob>(job => job.RunAsync());
BackgroundJob.ContinueJobWith<SyncPersonJob>(syncPositionJob, job => job.RunAsync(), JobContinuationOptions.OnlyOnSucceededState);
}
private async Task SaveOrg(List<SapOrganizationItem> modifiedOrgList)
{
foreach (SapOrganizationItem item in modifiedOrgList)
{
var department = await _dbContext.Queryable<DepartmentEntity>().Where(x => x.No == item.OBJID).FirstAsync();
var department = await DbContext.Queryable<DepartmentEntity>().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);
}
}
}

View File

@@ -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;
/// <summary>
/// 上传考勤记录
/// </summary>
[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<DeviceEntity>()
.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<DeviceUploadLogEntity>()
.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<GainfoEntity>().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<DeviceUploadLogEntity>()
.SetColumns(x => x.Sync == true)
.SetColumns(x => x.ModifiedTime == DateTime.Now)
.Where(x => ids.Contains(x.Id))
.ExecuteCommandAsync();
}
else
{
throw new Exception(r.OMS);
}
}
}
}

View File

@@ -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
/// <summary>
/// SAP人员信息同步
/// </summary>
[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<PositionEntity> _positions;
private List<TenantResponse> _tenants;
private List<SapPersonDepartmentStatus> _departmentChanges;
private List<SapPersonJobStatus> _jobChanges;
public SyncPersonJob(ILogger<SyncPersonJob> 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<IDbContext>();
_positions = dbContext.Queryable<PositionEntity>().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<int> SavePerson(List<SapPersonItem> persons)
private async Task SavePersonAsync(List<SapPersonItem> 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<IDbContext>();
Logger.LogWarning("SAP分批处理Chunk数量:{count}", searchCodes.Length);
var existsWorkCodes = DbContext.Queryable<GainfoSapEntity>()
.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<GainfoSapEntity>()
.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<GainfoSapEntity>().Where(x => x.ename == item.ename).First();
db.Updateable<GainfoSapEntity>().SetColumns(g => new GainfoSapEntity
var gainfoSap = DbContext.Queryable<GainfoSapEntity>().Where(x => x.ename == item.ename).First();
DbContext.Updateable<GainfoSapEntity>().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<GainfoEntity>().Where(x => x.Code == item.ename).First();
var gainfo = DbContext.Queryable<GainfoEntity>().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<GainfoEntity>().SetColumns(g => new GainfoEntity
DbContext.Updateable<GainfoEntity>().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<SapPersonItem> GetModifiedPerson(IDbContext db, List<SapPersonItem> sapList)
private List<SapPersonItem> GetModifiedPerson(List<SapPersonItem> sapList)
{
var last = LoadData(db);
var last = LoadData();
if (last.Count <= 0)
{
return sapList;
@@ -294,9 +285,9 @@ public class SyncPersonJob
}
private static List<SapPersonItem> LoadData(IDbContext db)
private List<SapPersonItem> LoadData()
{
var gainfo = db.Queryable<GainfoSapEntity>().ToList();
var gainfo = DbContext.Queryable<GainfoSapEntity>().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)

View File

@@ -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;
/// <summary>
/// 职位同步定时任务
/// SAP岗位信息同步
/// </summary>
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<SyncPositionJob> _logger;
public SyncPositionJob(IDbContext dbContext, IJinkoSapService jinkoSapService, ILogger<SyncPositionJob> 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<PositionEntity>().Where(x => x.No == item.ZJOBID).FirstAsync();
var position = await DbContext.Queryable<PositionEntity>().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);
}
}
}

View File

@@ -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;
/// <summary>
/// 用户创建
/// </summary>
[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<string>() { "admin", "WB-0741", "WB-1091", "0123456" };
var users = await identityDbContext.Queryable<UserEntity>()
.Where(x => !whitelist.Contains(x.UserName))
.ToListAsync();
var gainfos = await DbContext.Queryable<GainfoEntity>().Where(x => !whitelist.Contains(x.Code)).ToListAsync();
var hasher = new PasswordHasher<UserEntity>();
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<UserTenantEntity>().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<UserClaimEntity>().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);
}
}
}

View File

@@ -22,7 +22,8 @@ public class HangfirePack : BaseAppPack
{
Db = 5,
Prefix = "hangfire"
});
})
.UseSerilogLogProvider();
});

View File

@@ -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<SyncOrganizationJob>("SyncSap", s => s.RunAsync(), "0 0 2 * * ?", new RecurringJobOptions
{
TimeZone = TimeZoneInfo.Local
});
var logger = serviceProvider.GetService<ILogger<JobPack>>();
RecurringJob.AddOrUpdate<SyncPersonJob>("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<CreateSyncServerDateTimeJob>("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<RecurringJobManager>)typeof(RecurringJob).GetField("Instance", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
//创建设备获取的任务
RecurringJob.AddOrUpdate<CreateGetUploadRecordJob>("CreateGetUploadRecord", s => s.RunAsync(), "0 0/1 * * * ?", new RecurringJobOptions
{
TimeZone = TimeZoneInfo.Local
});
(jobs.Select(job => job.GetCustomAttribute<RecurringJobAttribute>().UniqueJobKey).Distinct().Count() != jobs.Count).ThrowIfTrue("任务key重复");
//创建系统默认分组
RecurringJob.AddOrUpdate<CreateDefinitelyGroupJob>("CreateDefinitelyGroup", s => s.RunAsync(), "0 0 5 * * ?", new RecurringJobOptions
{
TimeZone = TimeZoneInfo.Local
});
logger.LogDebug("一共获取{count}个调度任务", jobs.Count);
//心跳
RecurringJob.AddOrUpdate<HeartbeatJob>("Heartbeat", s => s.RunAsync(), "0/10 * * * * ?", new RecurringJobOptions
foreach (var job in jobs)
{
TimeZone = TimeZoneInfo.Local
});
var recurringSetting = job.GetCustomAttribute<RecurringJobAttribute>()!;
recurringSetting.Cron.IsEmpty().ThrowIfTrue(job.Name + "尚未定义Cron");
//上传考勤记录
RecurringJob.AddOrUpdate<SyncOriginCardInfoJob>("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<CancelDuplicationTaskJob>("CancelDuplicationTask", s => s.RunAsync(), "0/15 * * * * ?", new RecurringJobOptions
{
TimeZone = TimeZoneInfo.Local
});
//更新用户密码
RecurringJob.AddOrUpdate<UpdateUserPasswordJob>("UpdateUserPassword", s => s.RunAsync(), "0 0 5 * * ?", new RecurringJobOptions
{
TimeZone = TimeZoneInfo.Local
});
//删除前三天前的日志
RecurringJob.AddOrUpdate<DelApiLogTaskJob>("DelApiLogTask", s => s.RunAsync(), "0 0 */7 * *", new RecurringJobOptions
{
TimeZone = TimeZoneInfo.Local
});
//处理餐补
RecurringJob.AddOrUpdate<MealSupplementHandlerJob>("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
});
}
}
}

View File

@@ -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<SyncOriginCardInfoJob> _logger;
public SyncOriginCardInfoJob(IJinkoJIPService jinkoJIPService,
IDbContext dbContext,
ISqlSugarOptionsService sqlSugarOptionsService,
ILogger<SyncOriginCardInfoJob> logger
)
{
_jinkoJIPService = jinkoJIPService;
_dbContext = dbContext;
_sqlSugarOptionsService = sqlSugarOptionsService;
_logger = logger;
}
public async Task RunAsync()
{
_logger.LogInformation("调度任务:{job}.开始执行", nameof(SyncOriginCardInfoJob));
_dbContext.Client.QueryFilter.ClearAndBackup<ITenantId>();
_sqlSugarOptionsService.IgnoreTenant = true;
try
{
//考勤设备(不需要Enable参数)
var devices = await _dbContext.Queryable<DeviceEntity>()
.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<DeviceUploadLogEntity>()
.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<GainfoEntity>().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<DeviceUploadLogEntity>()
.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));
}
}
}

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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<CreateGetUploadRecordJob> _logger;
private readonly ISqlSugarOptionsService _sqlSugarOptionsService;
public CreateGetUploadRecordJob(IDbContext dbContext, ILogger<CreateGetUploadRecordJob> logger, ISqlSugarOptionsService sqlSugarOptionsService)
{
_logger = logger;
_sqlSugarOptionsService = sqlSugarOptionsService;
_dbContext = dbContext;
}
public async Task RunAsync()
{
_dbContext.Client.QueryFilter.ClearAndBackup<ITenantId>();
_sqlSugarOptionsService.IgnoreTenant = true;
try
{
var devices = await _dbContext.Queryable<DeviceEntity>()
.Where(x => x.Enable)
.Where(x => x.Type == DeviceTypeEnumType.Attendance || x.Type == DeviceTypeEnumType.Door)
.ToListAsync();
//过滤处理中的任务
var currentUniqueNos = await _dbContext.Queryable<DeviceTaskEntity>()
.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();
}
}
}

View File

@@ -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<CreateSyncServerDateTimeJob> _logger;
private readonly ISqlSugarOptionsService _sqlSugarOptionsService;
public CreateSyncServerDateTimeJob(IDbContext dbContext, ILogger<CreateSyncServerDateTimeJob> logger, ISqlSugarOptionsService sqlSugarOptionsService)
{
_dbContext = dbContext;
_logger = logger;
_sqlSugarOptionsService = sqlSugarOptionsService;
}
public async Task RunAsync()
{
_dbContext.Client.QueryFilter.ClearAndBackup<ITenantId>();
_sqlSugarOptionsService.IgnoreTenant = true;
try
{
var deviceUniqueNos = await _dbContext.Queryable<DeviceTaskEntity>()
.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<DeviceEntity>()
.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();
}
}
}
}

View File

@@ -80,7 +80,6 @@ public class DeviceTaskAssignmentService : IDeviceTaskAssignmentService
{
var tasks = await _dbContext.Queryable<DeviceTaskEntity>()
.Where(x => request.Ids.Contains(x.Id))
.Where(x => x.Status == DeviceTaskStatusEnumType.Process || x.Status == DeviceTaskStatusEnumType.Error)
.ToListAsync();
//判断process任务时间

View File

@@ -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": [