Compare commits

...

11 Commits

Author SHA1 Message Date
chenchun
6b47ae232d feat:完成hangfire接入 2024-11-15 18:17:53 +08:00
chenchun
536c3cc56b feat: 支持store 缓存和redis切换 2024-11-15 17:01:39 +08:00
chenchun
b75a8cb60d feat: 全量quarzt到hangfire任务 2024-11-15 16:45:01 +08:00
橙子
17bc4ade84 fix: 修复审计日志错误信息 2024-11-10 17:33:20 +08:00
橙子
aea0896356 fix: 修复GetUserAsync报错问题 2024-11-10 17:23:00 +08:00
chenchun
ae82a2d1cf style: 修改描述 2024-11-08 13:56:43 +08:00
chenchun
2412bc1da4 style: 修改开始描述 2024-11-08 13:41:03 +08:00
chenchun
42b00515eb Merge branch 'refs/heads/tool-dev' into abp 2024-11-08 12:36:26 +08:00
橙子
650c29e75a !77 修正Ruoyi查询时间条件为时间的错误问题
Merge pull request !77 from Po/N/A
2024-11-06 15:51:24 +00:00
chenchun
751cc3cadb feat: 支持不同类型的用户id、主键 2024-11-05 16:45:30 +08:00
Po
80fe1116a8 修正Ruoyi查询时间条件为时间的错误问题
Signed-off-by: Po <448443959@qq.com>
2024-11-05 00:26:59 +00:00
25 changed files with 483 additions and 540 deletions

View File

@@ -156,6 +156,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Abp.Tool.HttpApi.Client"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.SettingManagement.Application", "module\setting-management\Yi.Framework.SettingManagement.Application\Yi.Framework.SettingManagement.Application.csproj", "{2A31D7CB-BDCC-4253-BA73-273B6B5E1956}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.SettingManagement.Application", "module\setting-management\Yi.Framework.SettingManagement.Application\Yi.Framework.SettingManagement.Application.csproj", "{2A31D7CB-BDCC-4253-BA73-273B6B5E1956}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.BackgroundWorkers.Hangfire", "framework\Yi.Framework.BackgroundWorkers.Hangfire\Yi.Framework.BackgroundWorkers.Hangfire.csproj", "{862CA181-BEE6-4870-82D2-B662E527ED8C}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -390,6 +392,10 @@ Global
{2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Debug|Any CPU.Build.0 = Debug|Any CPU {2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Release|Any CPU.ActiveCfg = Release|Any CPU {2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Release|Any CPU.Build.0 = Release|Any CPU {2A31D7CB-BDCC-4253-BA73-273B6B5E1956}.Release|Any CPU.Build.0 = Release|Any CPU
{862CA181-BEE6-4870-82D2-B662E527ED8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{862CA181-BEE6-4870-82D2-B662E527ED8C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{862CA181-BEE6-4870-82D2-B662E527ED8C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{862CA181-BEE6-4870-82D2-B662E527ED8C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@@ -459,6 +465,7 @@ Global
{4AE84CDE-2A47-4D68-8E93-86193F72E4E8} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4} {4AE84CDE-2A47-4D68-8E93-86193F72E4E8} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4}
{C8F97775-D903-4365-A4FF-3DA97E318CD2} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4} {C8F97775-D903-4365-A4FF-3DA97E318CD2} = {084CBEEC-5D37-4716-B9C7-D80D6960DFF4}
{2A31D7CB-BDCC-4253-BA73-273B6B5E1956} = {8C68059E-F3B1-4D28-A1C9-A5830F53E5D3} {2A31D7CB-BDCC-4253-BA73-273B6B5E1956} = {8C68059E-F3B1-4D28-A1C9-A5830F53E5D3}
{862CA181-BEE6-4870-82D2-B662E527ED8C} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {23D6FBC9-C970-4641-BC1E-2AEA59F51C18} SolutionGuid = {23D6FBC9-C970-4641-BC1E-2AEA59F51C18}

View File

@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.BackgroundWorkers.Hangfire" Version="$(AbpVersion)" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,27 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.BackgroundWorkers;
using Volo.Abp.BackgroundWorkers.Hangfire;
namespace Yi.Framework.BackgroundWorkers.Hangfire;
[DependsOn(typeof(AbpBackgroundWorkersHangfireModule))]
public class YiFrameworkBackgroundWorkersHangfireModule:AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddConventionalRegistrar(new YiHangfireConventionalRegistrar());
}
public override async Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
{
//定时任务自动注入Abp默认只有在Quartz才实现
var backgroundWorkerManager = context.ServiceProvider.GetRequiredService<IBackgroundWorkerManager>();
var works = context.ServiceProvider.GetServices<IHangfireBackgroundWorker>();
foreach (var work in works)
{
await backgroundWorkerManager.AddAsync(work);
}
}
}

View File

@@ -0,0 +1,20 @@
using Volo.Abp.BackgroundWorkers.Hangfire;
using Volo.Abp.DependencyInjection;
namespace Yi.Framework.BackgroundWorkers.Hangfire;
public class YiHangfireConventionalRegistrar : DefaultConventionalRegistrar
{
protected override bool IsConventionalRegistrationDisabled(Type type)
{
return !typeof(IHangfireBackgroundWorker).IsAssignableFrom(type) || base.IsConventionalRegistrationDisabled(type);
}
protected override List<Type> GetExposedServiceTypes(Type type)
{
return new List<Type>()
{
typeof(IHangfireBackgroundWorker)
};
}
}

View File

@@ -36,15 +36,18 @@ namespace Yi.Framework.SqlSugarCore
protected virtual bool IsSoftDeleteFilterEnabled => DataFilter?.IsEnabled<ISoftDelete>() ?? false; protected virtual bool IsSoftDeleteFilterEnabled => DataFilter?.IsEnabled<ISoftDelete>() ?? false;
private IEntityChangeEventHelper EntityChangeEventHelper => LazyServiceProvider.LazyGetService<IEntityChangeEventHelper>(NullEntityChangeEventHelper.Instance); private IEntityChangeEventHelper EntityChangeEventHelper =>
LazyServiceProvider.LazyGetService<IEntityChangeEventHelper>(NullEntityChangeEventHelper.Instance);
public DbConnOptions Options => LazyServiceProvider.LazyGetRequiredService<IOptions<DbConnOptions>>().Value; public DbConnOptions Options => LazyServiceProvider.LazyGetRequiredService<IOptions<DbConnOptions>>().Value;
private ISerializeService SerializeService=> LazyServiceProvider.LazyGetRequiredService<ISerializeService>(); private ISerializeService SerializeService => LazyServiceProvider.LazyGetRequiredService<ISerializeService>();
public void SetSqlSugarClient(ISqlSugarClient sqlSugarClient) public void SetSqlSugarClient(ISqlSugarClient sqlSugarClient)
{ {
SqlSugarClient = sqlSugarClient; SqlSugarClient = sqlSugarClient;
} }
public SqlSugarDbContext(IAbpLazyServiceProvider lazyServiceProvider) public SqlSugarDbContext(IAbpLazyServiceProvider lazyServiceProvider)
{ {
LazyServiceProvider = lazyServiceProvider; LazyServiceProvider = lazyServiceProvider;
@@ -73,12 +76,14 @@ namespace Yi.Framework.SqlSugarCore
protected virtual string GetCurrentConnectionString() protected virtual string GetCurrentConnectionString()
{ {
var connectionStringResolver = LazyServiceProvider.LazyGetRequiredService<IConnectionStringResolver>(); var connectionStringResolver = LazyServiceProvider.LazyGetRequiredService<IConnectionStringResolver>();
var connectionString = connectionStringResolver.ResolveAsync().ConfigureAwait(false).GetAwaiter().GetResult(); var connectionString =
connectionStringResolver.ResolveAsync().ConfigureAwait(false).GetAwaiter().GetResult();
if (string.IsNullOrWhiteSpace(connectionString)) if (string.IsNullOrWhiteSpace(connectionString))
{ {
Check.NotNull(Options.Url, "dbUrl未配置"); Check.NotNull(Options.Url, "dbUrl未配置");
} }
return connectionString!; return connectionString!;
} }
@@ -92,6 +97,7 @@ namespace Yi.Framework.SqlSugarCore
return dbTypeFromTenantName.Value; return dbTypeFromTenantName.Value;
} }
} }
Check.NotNull(Options.DbType, "默认DbType未配置"); Check.NotNull(Options.DbType, "默认DbType未配置");
return Options.DbType!.Value; return Options.DbType!.Value;
} }
@@ -126,7 +132,6 @@ namespace Yi.Framework.SqlSugarCore
} }
/// <summary> /// <summary>
/// 上下文对象扩展 /// 上下文对象扩展
/// </summary> /// </summary>
@@ -138,21 +143,23 @@ namespace Yi.Framework.SqlSugarCore
{ {
sqlSugarClient.QueryFilter.AddTableFilter<ISoftDelete>(u => u.IsDeleted == false); sqlSugarClient.QueryFilter.AddTableFilter<ISoftDelete>(u => u.IsDeleted == false);
} }
if (IsMultiTenantFilterEnabled) if (IsMultiTenantFilterEnabled)
{ {
//表达式里只能有具体值,不能运算 //表达式里只能有具体值,不能运算
var expressionCurrentTenant = CurrentTenant.Id ?? null; var expressionCurrentTenant = CurrentTenant.Id ?? null;
sqlSugarClient.QueryFilter.AddTableFilter<IMultiTenant>(u => u.TenantId == expressionCurrentTenant); sqlSugarClient.QueryFilter.AddTableFilter<IMultiTenant>(u => u.TenantId == expressionCurrentTenant);
} }
CustomDataFilter(sqlSugarClient); CustomDataFilter(sqlSugarClient);
} }
protected virtual void CustomDataFilter(ISqlSugarClient sqlSugarClient) protected virtual void CustomDataFilter(ISqlSugarClient sqlSugarClient)
{ {
} }
protected virtual void DataExecuted(object oldValue, DataAfterModel entityInfo) protected virtual void DataExecuted(object oldValue, DataAfterModel entityInfo)
{ {
} }
/// <summary> /// <summary>
@@ -174,25 +181,34 @@ namespace Yi.Framework.SqlSugarCore
entityInfo.SetValue(DateTime.Now); entityInfo.SetValue(DateTime.Now);
} }
} }
if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.LastModifierId))) else if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.LastModifierId)))
{ {
if (CurrentUser.Id != null) if (typeof(Guid?) == entityInfo.EntityColumnInfo.PropertyInfo.PropertyType)
{ {
entityInfo.SetValue(CurrentUser.Id); if (CurrentUser.Id != null)
} {
} entityInfo.SetValue(CurrentUser.Id);
break; }
case DataFilterType.InsertByObject:
if (entityInfo.PropertyName.Equals(nameof(IEntity<Guid>.Id)))
{
//主键为空或者为默认最小值
if (Guid.Empty.Equals(oldValue))
{
entityInfo.SetValue(GuidGenerator.Create());
} }
} }
if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreationTime))) break;
case DataFilterType.InsertByObject:
if (entityInfo.PropertyName.Equals(nameof(IEntity<Guid>.Id)))
{
//类型为guid
if (typeof(Guid) == entityInfo.EntityColumnInfo.PropertyInfo.PropertyType)
{
//主键为空或者为默认最小值
if (Guid.Empty.Equals(oldValue))
{
entityInfo.SetValue(GuidGenerator.Create());
}
}
}
else if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreationTime)))
{ {
//为空或者为默认最小值 //为空或者为默认最小值
if (DateTime.MinValue.Equals(oldValue)) if (DateTime.MinValue.Equals(oldValue))
@@ -200,21 +216,26 @@ namespace Yi.Framework.SqlSugarCore
entityInfo.SetValue(DateTime.Now); entityInfo.SetValue(DateTime.Now);
} }
} }
if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreatorId))) else if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreatorId)))
{ {
if (CurrentUser.Id is not null) //类型为guid
if (typeof(Guid?) == entityInfo.EntityColumnInfo.PropertyInfo.PropertyType)
{ {
entityInfo.SetValue(CurrentUser.Id); if (CurrentUser.Id is not null)
{
entityInfo.SetValue(CurrentUser.Id);
}
} }
} }
if (entityInfo.PropertyName.Equals(nameof(IMultiTenant.TenantId))) else if (entityInfo.PropertyName.Equals(nameof(IMultiTenant.TenantId)))
{ {
if (CurrentTenant.Id is not null) if (CurrentTenant.Id is not null)
{ {
entityInfo.SetValue(CurrentTenant.Id); entityInfo.SetValue(CurrentTenant.Id);
} }
} }
break; break;
} }
@@ -227,6 +248,7 @@ namespace Yi.Framework.SqlSugarCore
{ {
EntityChangeEventHelper.PublishEntityCreatedEvent(entityInfo.EntityValue); EntityChangeEventHelper.PublishEntityCreatedEvent(entityInfo.EntityValue);
} }
break; break;
case DataFilterType.UpdateByObject: case DataFilterType.UpdateByObject:
if (entityInfo.PropertyName == nameof(IEntity<object>.Id)) if (entityInfo.PropertyName == nameof(IEntity<object>.Id))
@@ -243,8 +265,8 @@ namespace Yi.Framework.SqlSugarCore
{ {
EntityChangeEventHelper.PublishEntityUpdatedEvent(entityInfo.EntityValue); EntityChangeEventHelper.PublishEntityUpdatedEvent(entityInfo.EntityValue);
} }
} }
break; break;
case DataFilterType.DeleteByObject: case DataFilterType.DeleteByObject:
if (entityInfo.PropertyName == nameof(IEntity<object>.Id)) if (entityInfo.PropertyName == nameof(IEntity<object>.Id))
@@ -254,14 +276,13 @@ namespace Yi.Framework.SqlSugarCore
{ {
foreach (var entityValue in entityValues) foreach (var entityValue in entityValues)
{ {
EntityChangeEventHelper.PublishEntityDeletedEvent(entityValue); EntityChangeEventHelper.PublishEntityDeletedEvent(entityValue);
} }
} }
} }
break; break;
} }
} }
/// <summary> /// <summary>
@@ -280,7 +301,6 @@ namespace Yi.Framework.SqlSugarCore
sb.AppendLine("==============================="); sb.AppendLine("===============================");
Logger.CreateLogger<SqlSugarDbContext>().LogDebug(sb.ToString()); Logger.CreateLogger<SqlSugarDbContext>().LogDebug(sb.ToString());
} }
} }
/// <summary> /// <summary>
@@ -306,14 +326,14 @@ namespace Yi.Framework.SqlSugarCore
{ {
if (property.Name == nameof(IHasConcurrencyStamp.ConcurrencyStamp)) //带版本号并发更新 if (property.Name == nameof(IHasConcurrencyStamp.ConcurrencyStamp)) //带版本号并发更新
{ {
// column.IsOnlyIgnoreInsert = true;
// column.IsOnlyIgnoreUpdate = true;
column.IsEnableUpdateVersionValidation = true; column.IsEnableUpdateVersionValidation = true;
} }
if (property.PropertyType == typeof(ExtraPropertyDictionary)) if (property.PropertyType == typeof(ExtraPropertyDictionary))
{ {
column.IsIgnore = true; column.IsIgnore = true;
} }
if (property.Name == nameof(Entity<object>.Id)) if (property.Name == nameof(Entity<object>.Id))
{ {
column.IsPrimarykey = true; column.IsPrimarykey = true;
@@ -328,11 +348,13 @@ namespace Yi.Framework.SqlSugarCore
{ {
Directory.CreateDirectory(directoryName); Directory.CreateDirectory(directoryName);
} }
switch (Options.DbType) switch (Options.DbType)
{ {
case DbType.MySql: case DbType.MySql:
//MySql //MySql
SqlSugarClient.DbMaintenance.BackupDataBase(SqlSugarClient.Ado.Connection.Database, $"{Path.Combine(directoryName, fileName)}.sql");//mysql 只支持.net core SqlSugarClient.DbMaintenance.BackupDataBase(SqlSugarClient.Ado.Connection.Database,
$"{Path.Combine(directoryName, fileName)}.sql"); //mysql 只支持.net core
break; break;
@@ -344,19 +366,14 @@ namespace Yi.Framework.SqlSugarCore
case DbType.SqlServer: case DbType.SqlServer:
//SqlServer //SqlServer
SqlSugarClient.DbMaintenance.BackupDataBase(SqlSugarClient.Ado.Connection.Database, $"{Path.Combine(directoryName, fileName)}.bak"/*服务器路径*/);//第一个参数库名 SqlSugarClient.DbMaintenance.BackupDataBase(SqlSugarClient.Ado.Connection.Database,
$"{Path.Combine(directoryName, fileName)}.bak" /*服务器路径*/); //第一个参数库名
break; break;
default: default:
throw new NotImplementedException("其他数据库备份未实现"); throw new NotImplementedException("其他数据库备份未实现");
} }
} }
} }
} }

View File

@@ -1,8 +1,8 @@
using FreeRedis; using FreeRedis;
using Hangfire;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Quartz; using Volo.Abp.BackgroundWorkers.Hangfire;
using Volo.Abp.BackgroundWorkers.Quartz;
using Volo.Abp.Caching; using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
@@ -15,23 +15,27 @@ using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.Bbs.Application.Jobs; namespace Yi.Framework.Bbs.Application.Jobs;
public class AccessLogCacheJob : QuartzBackgroundWorkerBase public class AccessLogCacheJob : HangfireBackgroundWorkerBase
{ {
private readonly ILocalEventBus _localEventBus; private readonly ILocalEventBus _localEventBus;
public AccessLogCacheJob(ILocalEventBus localEventBus) public AccessLogCacheJob(ILocalEventBus localEventBus)
{ {
_localEventBus = localEventBus; _localEventBus = localEventBus;
JobDetail = JobBuilder.Create<AccessLogCacheJob>().WithIdentity(nameof(AccessLogCacheJob)) RecurringJobId = "访问日志写入缓存";
.Build(); //每10秒执行一次将本地缓存转入redis防止丢数据
CronExpression = "*/10 * * * * *";
//
// JobDetail = JobBuilder.Create<AccessLogCacheJob>().WithIdentity(nameof(AccessLogCacheJob))
// .Build();
//每10秒执行一次将本地缓存转入redis防止丢数据 //每10秒执行一次将本地缓存转入redis防止丢数据
Trigger = TriggerBuilder.Create().WithIdentity(nameof(AccessLogCacheJob)) // Trigger = TriggerBuilder.Create().WithIdentity(nameof(AccessLogCacheJob))
.WithSimpleSchedule((schedule) => { schedule.WithInterval(TimeSpan.FromSeconds(10)).RepeatForever();; }) // .WithSimpleSchedule((schedule) => { schedule.WithInterval(TimeSpan.FromSeconds(10)).RepeatForever();; })
.Build(); // .Build();
} }
public override async Task Execute(IJobExecutionContext context) public override async Task DoWorkAsync(CancellationToken cancellationToken = new CancellationToken())
{ {
await _localEventBus.PublishAsync(new AccessLogResetArgs()); await _localEventBus.PublishAsync(new AccessLogResetArgs());
} }

View File

@@ -1,11 +1,9 @@
using FreeRedis; using FreeRedis;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Quartz; using Volo.Abp.BackgroundWorkers.Hangfire;
using Volo.Abp.BackgroundWorkers.Quartz;
using Volo.Abp.Caching; using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities;
using Yi.Framework.Bbs.Domain.Entities; using Yi.Framework.Bbs.Domain.Entities;
using Yi.Framework.Bbs.Domain.Shared.Caches; using Yi.Framework.Bbs.Domain.Shared.Caches;
using Yi.Framework.Bbs.Domain.Shared.Enums; using Yi.Framework.Bbs.Domain.Shared.Enums;
@@ -13,7 +11,7 @@ using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.Bbs.Application.Jobs; namespace Yi.Framework.Bbs.Application.Jobs;
public class AccessLogStoreJob : QuartzBackgroundWorkerBase public class AccessLogStoreJob : HangfireBackgroundWorkerBase
{ {
private readonly ISqlSugarRepository<AccessLogAggregateRoot> _repository; private readonly ISqlSugarRepository<AccessLogAggregateRoot> _repository;
@@ -45,18 +43,23 @@ public class AccessLogStoreJob : QuartzBackgroundWorkerBase
public AccessLogStoreJob(ISqlSugarRepository<AccessLogAggregateRoot> repository) public AccessLogStoreJob(ISqlSugarRepository<AccessLogAggregateRoot> repository)
{ {
_repository = repository; _repository = repository;
JobDetail = JobBuilder.Create<AccessLogStoreJob>().WithIdentity(nameof(AccessLogStoreJob))
.Build();
RecurringJobId = "访问日志写入数据库";
//每分钟执行一次 //每分钟执行一次
Trigger = TriggerBuilder.Create().WithIdentity(nameof(AccessLogStoreJob)) CronExpression = "0 * * * * ?";
.WithCronSchedule("0 * * * * ?") // JobDetail = JobBuilder.Create<AccessLogStoreJob>().WithIdentity(nameof(AccessLogStoreJob))
.Build(); // .Build();
// //每分钟执行一次
// Trigger = TriggerBuilder.Create().WithIdentity(nameof(AccessLogStoreJob))
// .WithCronSchedule("0 * * * * ?")
// .Build();
} }
public override async Task Execute(IJobExecutionContext context) public override async Task DoWorkAsync(CancellationToken cancellationToken = new CancellationToken())
{ {
if (EnableRedisCache) if (EnableRedisCache)
{ {

View File

@@ -1,5 +1,4 @@
using Quartz; using Volo.Abp.BackgroundWorkers.Hangfire;
using Volo.Abp.BackgroundWorkers.Quartz;
using Yi.Framework.Bbs.Domain.Managers; using Yi.Framework.Bbs.Domain.Managers;
namespace Yi.Framework.Bbs.Application.Jobs; namespace Yi.Framework.Bbs.Application.Jobs;
@@ -7,20 +6,25 @@ namespace Yi.Framework.Bbs.Application.Jobs;
/// <summary> /// <summary>
/// 每日任务job /// 每日任务job
/// </summary> /// </summary>
public class AssignmentExpireTimeOutJob : QuartzBackgroundWorkerBase public class AssignmentExpireTimeOutJob : HangfireBackgroundWorkerBase
{ {
private readonly AssignmentManager _assignmentManager; private readonly AssignmentManager _assignmentManager;
public AssignmentExpireTimeOutJob(AssignmentManager assignmentManager) public AssignmentExpireTimeOutJob(AssignmentManager assignmentManager)
{ {
_assignmentManager = assignmentManager; _assignmentManager = assignmentManager;
JobDetail = JobBuilder.Create<AssignmentExpireTimeOutJob>().WithIdentity(nameof(AssignmentExpireTimeOutJob)).Build();
//每个小时整点执行一次 RecurringJobId = "每日任务系统超时检测";
Trigger = TriggerBuilder.Create().WithIdentity(nameof(AssignmentExpireTimeOutJob)).WithCronSchedule("0 0 * * * ?") //每分钟执行一次
.Build(); CronExpression = "0 * * * * ?";
//
// JobDetail = JobBuilder.Create<AssignmentExpireTimeOutJob>().WithIdentity(nameof(AssignmentExpireTimeOutJob)).Build();
// //每个小时整点执行一次
// Trigger = TriggerBuilder.Create().WithIdentity(nameof(AssignmentExpireTimeOutJob)).WithCronSchedule("0 0 * * * ?")
// .Build();
} }
public override async Task Execute(IJobExecutionContext context) public override async Task DoWorkAsync(CancellationToken cancellationToken = new CancellationToken())
{ {
await _assignmentManager.ExpireTimeoutAsync(); await _assignmentManager.ExpireTimeoutAsync();
} }

View File

@@ -1,20 +1,24 @@
using Quartz; using Volo.Abp.BackgroundWorkers.Hangfire;
using Volo.Abp.BackgroundWorkers.Quartz;
using Yi.Framework.Bbs.Domain.Managers; using Yi.Framework.Bbs.Domain.Managers;
namespace Yi.Framework.Bbs.Application.Jobs namespace Yi.Framework.Bbs.Application.Jobs
{ {
public class InterestRecordsJob : QuartzBackgroundWorkerBase public class InterestRecordsJob : HangfireBackgroundWorkerBase
{ {
private BankManager _bankManager; private BankManager _bankManager;
public InterestRecordsJob(BankManager bankManager) public InterestRecordsJob(BankManager bankManager)
{ {
_bankManager = bankManager; _bankManager = bankManager;
JobDetail = JobBuilder.Create<InterestRecordsJob>().WithIdentity(nameof(InterestRecordsJob)).Build();
RecurringJobId = "银行利息积分刷新";
//每个小时整点执行一次 //每个小时整点执行一次
CronExpression = "0 0 * * * ?";
Trigger = TriggerBuilder.Create().WithIdentity(nameof(InterestRecordsJob)).WithCronSchedule("0 0 * * * ?").Build();
// JobDetail = JobBuilder.Create<InterestRecordsJob>().WithIdentity(nameof(InterestRecordsJob)).Build();
//
// //每个小时整点执行一次
//
// Trigger = TriggerBuilder.Create().WithIdentity(nameof(InterestRecordsJob)).WithCronSchedule("0 0 * * * ?").Build();
//测试 //测试
// Trigger = TriggerBuilder.Create().WithIdentity(nameof(InterestRecordsJob)) // Trigger = TriggerBuilder.Create().WithIdentity(nameof(InterestRecordsJob))
@@ -23,7 +27,8 @@ namespace Yi.Framework.Bbs.Application.Jobs
// .RepeatForever()) // .RepeatForever())
//.Build(); //.Build();
} }
public override async Task Execute(IJobExecutionContext context)
public override async Task DoWorkAsync(CancellationToken cancellationToken = new CancellationToken())
{ {
//创建一个记录,莫得了 //创建一个记录,莫得了
await _bankManager.GetCurrentInterestRate(); await _bankManager.GetCurrentInterestRate();

View File

@@ -27,13 +27,19 @@ namespace Yi.Framework.Bbs.Application.Services
var userEntity = await _bbsUserManager._userRepository.GetFirstAsync(x => x.UserName == userNameOrUserId); var userEntity = await _bbsUserManager._userRepository.GetFirstAsync(x => x.UserName == userNameOrUserId);
if (userEntity == null) if (userEntity == null)
{ {
throw new Volo.Abp.UserFriendlyException("该用户不存在"); throw new UserFriendlyException("该用户不存在");
} }
userId= userEntity.Id; userId= userEntity.Id;
} }
var output =await _bbsUserManager.GetBbsUserInfoAsync(userId); var output =await _bbsUserManager.GetBbsUserInfoAsync(userId);
//不是自己
if (CurrentUser.Id != output.Id)
{
output.Phone = null;
output.Email=null;
}
return output!; return output!;
} }
} }

View File

@@ -136,6 +136,11 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
[Authorize] [Authorize]
public override async Task<CommentGetOutputDto> CreateAsync(CommentCreateInputVo input) public override async Task<CommentGetOutputDto> CreateAsync(CommentCreateInputVo input)
{ {
if (input.Content.Length<=6)
{
throw new UserFriendlyException("评论长度至少大于6");
}
var discuess = await _discussRepository.GetFirstAsync(x => x.Id == input.DiscussId); var discuess = await _discussRepository.GetFirstAsync(x => x.Id == input.DiscussId);
if (discuess is null) if (discuess is null)
{ {

View File

@@ -78,7 +78,12 @@ namespace Yi.Framework.ChatHub.Domain.Managers
public async Task<ChatOnlineUserCacheItem?> GetUserAsync(Guid userId) public async Task<ChatOnlineUserCacheItem?> GetUserAsync(Guid userId)
{ {
var key = new ChatOnlineUserCacheKey(CacheKeyPrefix); var key = new ChatOnlineUserCacheKey(CacheKeyPrefix);
var cacheUser = System.Text.Json.JsonSerializer.Deserialize<ChatOnlineUserCacheItem>(await RedisClient.HGetAsync(key.GetKey(), key.GetField(userId))); var cacheUserOrNull= await RedisClient.HGetAsync(key.GetKey(), key.GetField(userId));
if (cacheUserOrNull is null)
{
return null;
}
var cacheUser = System.Text.Json.JsonSerializer.Deserialize<ChatOnlineUserCacheItem>(cacheUserOrNull);
return cacheUser; return cacheUser;
} }
} }

View File

@@ -6,16 +6,14 @@ using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Quartz; using Volo.Abp.BackgroundWorkers.Hangfire;
using Quartz.Logging;
using Volo.Abp.BackgroundWorkers.Quartz;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
using Yi.Framework.Rbac.Domain.Shared.Options; using Yi.Framework.Rbac.Domain.Shared.Options;
using Yi.Framework.SqlSugarCore.Abstractions; using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.Rbac.Application.Jobs namespace Yi.Framework.Rbac.Application.Jobs
{ {
public class BackupDataBaseJob : QuartzBackgroundWorkerBase public class BackupDataBaseJob: HangfireBackgroundWorkerBase
{ {
private ISqlSugarDbContext _dbContext; private ISqlSugarDbContext _dbContext;
private IOptions<RbacOptions> _options; private IOptions<RbacOptions> _options;
@@ -24,13 +22,12 @@ namespace Yi.Framework.Rbac.Application.Jobs
_options = options; _options = options;
_dbContext = dbContext; _dbContext = dbContext;
JobDetail = JobBuilder.Create<BackupDataBaseJob>().WithIdentity(nameof(BackupDataBaseJob)).Build();
RecurringJobId = "数据库备份";
//每天00点与24点进行备份 //每天00点与24点进行备份
Trigger = TriggerBuilder.Create().WithIdentity(nameof(BackupDataBaseJob)).WithCronSchedule("0 0 0,12 * * ? ").Build(); CronExpression = "0 0 0,12 * * ? ";
//Trigger = TriggerBuilder.Create().WithIdentity(nameof(BackupDataBaseJob)).WithSimpleSchedule(x=>x.WithIntervalInSeconds(10)).Build();
} }
public override Task Execute(IJobExecutionContext context) public override Task DoWorkAsync(CancellationToken cancellationToken = new CancellationToken())
{ {
if (_options.Value.EnableDataBaseBackup) if (_options.Value.EnableDataBaseBackup)
{ {

View File

@@ -1,220 +0,0 @@
using System.Reflection;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Quartz;
using Quartz.Impl.Matchers;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Timing;
using Yi.Framework.Rbac.Application.Contracts.Dtos.Task;
using Yi.Framework.Rbac.Application.Contracts.IServices;
using Yi.Framework.Rbac.Domain.Shared.Enums;
namespace Yi.Framework.Rbac.Application.Services.Monitor
{
public class TaskService : ApplicationService, ITaskService
{
private readonly ISchedulerFactory _schedulerFactory;
private readonly IClock _clock;
public TaskService(ISchedulerFactory schedulerFactory, IClock clock)
{
_clock = clock;
_schedulerFactory = schedulerFactory;
}
/// <summary>
/// 单查job
/// </summary>
/// <param name="jobId"></param>
/// <returns></returns>
[HttpGet("task/{jobId}")]
public async Task<TaskGetOutput> GetAsync([FromRoute] string jobId)
{
var scheduler = await _schedulerFactory.GetScheduler();
var jobDetail = await scheduler.GetJobDetail(new JobKey(jobId));
var trigger = (await scheduler.GetTriggersOfJob(new JobKey(jobId))).First();
//状态
var state = await scheduler.GetTriggerState(trigger.Key);
var output = new TaskGetOutput
{
JobId = jobDetail.Key.Name,
GroupName = jobDetail.Key.Group,
JobType = jobDetail.JobType.Name,
Properties = Newtonsoft.Json.JsonConvert.SerializeObject(jobDetail.JobDataMap),
Concurrent = !jobDetail.ConcurrentExecutionDisallowed,
Description = jobDetail.Description,
LastRunTime = _clock.Normalize(trigger.GetPreviousFireTimeUtc()?.DateTime ?? DateTime.MinValue),
NextRunTime = _clock.Normalize(trigger.GetNextFireTimeUtc()?.DateTime ?? DateTime.MinValue),
AssemblyName = jobDetail.JobType.Assembly.GetName().Name,
Status = state.ToString()
};
if (trigger is ISimpleTrigger simple)
{
output.TriggerArgs = Math.Round(simple.RepeatInterval.TotalMinutes, 2).ToString() + "分钟";
output.Type = JobTypeEnum.Millisecond;
output.Millisecond = simple.RepeatInterval.TotalMilliseconds;
}
else if (trigger is ICronTrigger cron)
{
output.TriggerArgs = cron.CronExpressionString!;
output.Type = JobTypeEnum.Cron;
output.Cron = cron.CronExpressionString;
}
return output;
}
/// <summary>
/// 多查job
/// </summary>
/// <returns></returns>
public async Task<PagedResultDto<TaskGetListOutput>> GetListAsync([FromQuery] TaskGetListInput input)
{
var items = new List<TaskGetOutput>();
var scheduler = await _schedulerFactory.GetScheduler();
var groups = await scheduler.GetJobGroupNames();
foreach (var groupName in groups)
{
foreach (var jobKey in await scheduler.GetJobKeys(GroupMatcher<JobKey>.GroupEquals(groupName)))
{
string jobName = jobKey.Name;
string jobGroup = jobKey.Group;
var triggers = (await scheduler.GetTriggersOfJob(jobKey)).First();
items.Add(await GetAsync(jobName));
}
}
var output = items.Skip((input.SkipCount - 1) * input.MaxResultCount).Take(input.MaxResultCount)
.OrderByDescending(x => x.LastRunTime)
.ToList();
return new PagedResultDto<TaskGetListOutput>(items.Count(), output.Adapt<List<TaskGetListOutput>>());
}
/// <summary>
/// 创建job
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task CreateAsync(TaskCreateInput input)
{
var scheduler = await _schedulerFactory.GetScheduler();
//设置启动时执行一次,然后最大只执行一次
//jobBuilder
var jobClassType = Assembly.Load(input.AssemblyName).GetTypes().Where(x => x.Name == input.JobType).FirstOrDefault();
if (jobClassType is null)
{
throw new UserFriendlyException($"程序集:{input.AssemblyName}{input.JobType} 不存在");
}
var jobBuilder = JobBuilder.Create(jobClassType).WithIdentity(new JobKey(input.JobId, input.GroupName))
.WithDescription(input.Description);
if (!input.Concurrent)
{
jobBuilder.DisallowConcurrentExecution();
}
//triggerBuilder
TriggerBuilder triggerBuilder = null;
switch (input.Type)
{
case JobTypeEnum.Cron:
triggerBuilder =
TriggerBuilder.Create()
.WithCronSchedule(input.Cron);
break;
case JobTypeEnum.Millisecond:
triggerBuilder =
TriggerBuilder.Create().StartNow()
.WithSimpleSchedule(x => x
.WithInterval(TimeSpan.FromMilliseconds(input.Millisecond ?? 10000))
.RepeatForever()
);
break;
}
//作业计划,单个jobBuilder与多个triggerBuilder组合
await scheduler.ScheduleJob(jobBuilder.Build(), triggerBuilder.Build());
}
/// <summary>
/// 移除job
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public async Task DeleteAsync(IEnumerable<string> id)
{
var scheduler = await _schedulerFactory.GetScheduler();
await scheduler.DeleteJobs(id.Select(x => new JobKey(x)).ToList());
}
/// <summary>
/// 暂停job
/// </summary>
/// <param name="jobId"></param>
/// <returns></returns>
[HttpPut]
public async Task PauseAsync(string jobId)
{
var scheduler = await _schedulerFactory.GetScheduler();
await scheduler.PauseJob(new JobKey(jobId));
}
/// <summary>
/// 开始job
/// </summary>
/// <param name="jobId"></param>
/// <returns></returns>
[HttpPut]
public async Task StartAsync(string jobId)
{
var scheduler = await _schedulerFactory.GetScheduler();
await scheduler.ResumeJob(new JobKey(jobId));
}
/// <summary>
/// 更新job
/// </summary>
/// <param name="id"></param>
/// <param name="input"></param>
/// <returns></returns>
public async Task UpdateAsync(string id, TaskUpdateInput input)
{
await DeleteAsync(new List<string>() { id });
await CreateAsync(input.Adapt<TaskCreateInput>());
}
[HttpPost("task/run-once/{id}")]
public async Task RunOnceAsync([FromRoute] string id)
{
var scheduler = await _schedulerFactory.GetScheduler();
var jobDetail = await scheduler.GetJobDetail(new JobKey(id));
var jobBuilder = JobBuilder.Create(jobDetail.JobType).WithIdentity(new JobKey(Guid.NewGuid().ToString()));
//设置启动时执行一次,然后最大只执行一次
var trigger = TriggerBuilder.Create().WithIdentity(Guid.NewGuid().ToString()).StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInHours(1)
.WithRepeatCount(1))
.Build();
await scheduler.ScheduleJob(jobBuilder.Build(), trigger);
}
}
}

View File

@@ -10,13 +10,15 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Lazy.Captcha.Core" Version="2.0.7" /> <PackageReference Include="Lazy.Captcha.Core" Version="2.0.7" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.7" /> <PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.7" />
<PackageReference Include="Volo.Abp.BackgroundWorkers.Quartz" Version="$(AbpVersion)" /> <PackageReference Include="Volo.Abp.BackgroundJobs.Hangfire" Version="$(AbpVersion)" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\framework\Yi.Framework.Ddd.Application\Yi.Framework.Ddd.Application.csproj" /> <ProjectReference Include="..\..\..\framework\Yi.Framework.Ddd.Application\Yi.Framework.Ddd.Application.csproj" />
<ProjectReference Include="..\Yi.Framework.Rbac.Application.Contracts\Yi.Framework.Rbac.Application.Contracts.csproj" /> <ProjectReference Include="..\Yi.Framework.Rbac.Application.Contracts\Yi.Framework.Rbac.Application.Contracts.csproj" />
<ProjectReference Include="..\Yi.Framework.Rbac.Domain\Yi.Framework.Rbac.Domain.csproj" /> <ProjectReference Include="..\Yi.Framework.Rbac.Domain\Yi.Framework.Rbac.Domain.csproj" />
<ProjectReference Include="..\..\..\framework\Yi.Framework.BackgroundWorkers.Hangfire\Yi.Framework.BackgroundWorkers.Hangfire.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -2,7 +2,7 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.BackgroundWorkers; using Volo.Abp.BackgroundWorkers;
using Volo.Abp.BackgroundWorkers.Quartz; using Volo.Abp.BackgroundWorkers.Hangfire;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Yi.Framework.Ddd.Application; using Yi.Framework.Ddd.Application;
using Yi.Framework.Rbac.Application.Contracts; using Yi.Framework.Rbac.Application.Contracts;
@@ -16,8 +16,7 @@ namespace Yi.Framework.Rbac.Application
typeof(YiFrameworkRbacDomainModule), typeof(YiFrameworkRbacDomainModule),
typeof(YiFrameworkDddApplicationModule), typeof(YiFrameworkDddApplicationModule)
typeof(AbpBackgroundWorkersQuartzModule)
)] )]
public class YiFrameworkRbacApplicationModule : AbpModule public class YiFrameworkRbacApplicationModule : AbpModule
{ {
@@ -28,7 +27,6 @@ namespace Yi.Framework.Rbac.Application
service.AddCaptcha(options => service.AddCaptcha(options =>
{ {
options.CaptchaType = CaptchaType.ARITHMETIC; options.CaptchaType = CaptchaType.ARITHMETIC;
}); });
} }

View File

@@ -1,15 +1,13 @@
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Quartz; using Volo.Abp.BackgroundWorkers.Hangfire;
using Quartz.Logging;
using Volo.Abp.BackgroundWorkers.Quartz;
using Volo.Abp.Data; using Volo.Abp.Data;
using Yi.Framework.Rbac.Domain.Entities; using Yi.Framework.Rbac.Domain.Entities;
using Yi.Framework.SqlSugarCore.Abstractions; using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Abp.Application.Jobs namespace Yi.Abp.Application.Jobs
{ {
public class DemoResetJob : QuartzBackgroundWorkerBase public class DemoResetJob : HangfireBackgroundWorkerBase
{ {
private ISqlSugarDbContext _dbContext; private ISqlSugarDbContext _dbContext;
private ILogger<DemoResetJob> _logger => LoggerFactory.CreateLogger<DemoResetJob>(); private ILogger<DemoResetJob> _logger => LoggerFactory.CreateLogger<DemoResetJob>();
@@ -18,15 +16,15 @@ namespace Yi.Abp.Application.Jobs
public DemoResetJob(ISqlSugarDbContext dbContext, IDataSeeder dataSeeder, IConfiguration configuration) public DemoResetJob(ISqlSugarDbContext dbContext, IDataSeeder dataSeeder, IConfiguration configuration)
{ {
_dbContext = dbContext; _dbContext = dbContext;
JobDetail = JobBuilder.Create<DemoResetJob>().WithIdentity(nameof(DemoResetJob)).Build(); RecurringJobId = "重置demo环境";
//每天1点和13点进行重置demo环境
//每天01点与13点,演示环境进行重置 CronExpression = "0 0 1,13 * * ?";
Trigger = TriggerBuilder.Create().WithIdentity(nameof(DemoResetJob)).WithCronSchedule("0 0 1,13 * * ? ").Build();
// Trigger = TriggerBuilder.Create().WithIdentity(nameof(DemoResetJob)).WithSimpleSchedule(x=>x.WithIntervalInSeconds(10)).Build();
_dataSeeder = dataSeeder; _dataSeeder = dataSeeder;
_configuration = configuration; _configuration = configuration;
} }
public override async Task Execute(IJobExecutionContext context)
public override async Task DoWorkAsync(CancellationToken cancellationToken = new CancellationToken())
{ {
//开启演示环境重置功能 //开启演示环境重置功能
if (_configuration.GetSection("EnableDemoReset").Get<bool>()) if (_configuration.GetSection("EnableDemoReset").Get<bool>())
@@ -50,7 +48,6 @@ namespace Yi.Abp.Application.Jobs
} }
} }
} }
} }

View File

@@ -1,6 +1,6 @@
using Quartz; using Hangfire;
using SqlSugar; using SqlSugar;
using Volo.Abp.BackgroundWorkers.Quartz; using Volo.Abp.BackgroundWorkers.Hangfire;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
using Volo.Abp.Uow; using Volo.Abp.Uow;
using Yi.Framework.Rbac.Domain.Entities; using Yi.Framework.Rbac.Domain.Entities;
@@ -11,26 +11,21 @@ namespace Yi.Abp.Application.Jobs
/// <summary> /// <summary>
/// 定时任务 /// 定时任务
/// </summary> /// </summary>
public class TestJob : QuartzBackgroundWorkerBase public class TestJob : HangfireBackgroundWorkerBase
{ {
private ISqlSugarRepository<UserAggregateRoot> _repository; private ISqlSugarRepository<UserAggregateRoot> _repository;
public TestJob(ISqlSugarRepository<UserAggregateRoot> repository) public TestJob(ISqlSugarRepository<UserAggregateRoot> repository)
{ {
_repository = repository; _repository = repository;
JobDetail = JobBuilder.Create<TestJob>().WithIdentity(nameof(TestJob)).Build(); RecurringJobId = "测试";
Trigger = TriggerBuilder.Create().WithIdentity(nameof(TestJob)).StartNow() //每天一次
.WithSimpleSchedule(x => x CronExpression = Cron.Daily();
.WithIntervalInSeconds(1000 * 60)
.RepeatForever())
.Build();
} }
public override async Task Execute(IJobExecutionContext context) public override Task DoWorkAsync(CancellationToken cancellationToken = new CancellationToken())
{ {
//定时任务,非常简单 //定时任务,非常简单
Console.WriteLine("你好,世界"); Console.WriteLine("你好,世界");
// var eneities= await _repository.GetListAsync(); return Task.CompletedTask;
//var entities= await _sqlSugarClient.Queryable<UserEntity>().ToListAsync();
//await Console.Out.WriteLineAsync(entities.Count().ToString());
} }
} }
} }

View File

@@ -3,6 +3,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\framework\Yi.Framework.BackgroundWorkers.Hangfire\Yi.Framework.BackgroundWorkers.Hangfire.csproj" />
<ProjectReference Include="..\..\framework\Yi.Framework.Ddd.Application\Yi.Framework.Ddd.Application.csproj" /> <ProjectReference Include="..\..\framework\Yi.Framework.Ddd.Application\Yi.Framework.Ddd.Application.csproj" />
<ProjectReference Include="..\..\module\bbs\Yi.Framework.Bbs.Application\Yi.Framework.Bbs.Application.csproj" /> <ProjectReference Include="..\..\module\bbs\Yi.Framework.Bbs.Application\Yi.Framework.Bbs.Application.csproj" />
<ProjectReference Include="..\..\module\chat-hub\Yi.Framework.ChatHub.Application\Yi.Framework.ChatHub.Application.csproj" /> <ProjectReference Include="..\..\module\chat-hub\Yi.Framework.ChatHub.Application\Yi.Framework.ChatHub.Application.csproj" />

View File

@@ -1,6 +1,7 @@
using Volo.Abp.SettingManagement; using Volo.Abp.SettingManagement;
using Yi.Abp.Application.Contracts; using Yi.Abp.Application.Contracts;
using Yi.Abp.Domain; using Yi.Abp.Domain;
using Yi.Framework.BackgroundWorkers.Hangfire;
using Yi.Framework.Bbs.Application; using Yi.Framework.Bbs.Application;
using Yi.Framework.ChatHub.Application; using Yi.Framework.ChatHub.Application;
using Yi.Framework.CodeGen.Application; using Yi.Framework.CodeGen.Application;
@@ -23,7 +24,8 @@ namespace Yi.Abp.Application
typeof(YiFrameworkCodeGenApplicationModule), typeof(YiFrameworkCodeGenApplicationModule),
typeof (YiFrameworkSettingManagementApplicationModule), typeof (YiFrameworkSettingManagementApplicationModule),
typeof(YiFrameworkDddApplicationModule) typeof(YiFrameworkDddApplicationModule),
typeof(YiFrameworkBackgroundWorkersHangfireModule)
)] )]
public class YiAbpApplicationModule : AbpModule public class YiAbpApplicationModule : AbpModule
{ {

View File

@@ -8,6 +8,8 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Hangfire.MemoryStorage" Version="1.8.1.1" />
<PackageReference Include="Hangfire.Redis.StackExchange" Version="1.9.4" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.3" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.3" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.3" /> <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.3" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.6" /> <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.6" />

View File

@@ -3,27 +3,28 @@ using System.Text;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata; using System.Text.Json.Serialization.Metadata;
using System.Threading.RateLimiting; using System.Threading.RateLimiting;
using Hangfire;
using Hangfire.MemoryStorage;
using Hangfire.Redis.StackExchange;
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
using Newtonsoft.Json.Converters; using StackExchange.Redis;
using Volo.Abp.AspNetCore.Auditing;
using Volo.Abp.AspNetCore.Authentication.JwtBearer; using Volo.Abp.AspNetCore.Authentication.JwtBearer;
using Volo.Abp.AspNetCore.ExceptionHandling; using Volo.Abp.AspNetCore.ExceptionHandling;
using Volo.Abp.AspNetCore.MultiTenancy; using Volo.Abp.AspNetCore.MultiTenancy;
using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.AntiForgery; using Volo.Abp.AspNetCore.Mvc.AntiForgery;
using Volo.Abp.AspNetCore.Mvc.ExceptionHandling;
using Volo.Abp.AspNetCore.Serilog; using Volo.Abp.AspNetCore.Serilog;
using Volo.Abp.Auditing; using Volo.Abp.Auditing;
using Volo.Abp.Autofac; using Volo.Abp.Autofac;
using Volo.Abp.BackgroundJobs.Hangfire;
using Volo.Abp.BackgroundWorkers;
using Volo.Abp.BackgroundWorkers.Hangfire;
using Volo.Abp.Caching; using Volo.Abp.Caching;
using Volo.Abp.Json;
using Volo.Abp.Json.SystemTextJson;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.Swashbuckle; using Volo.Abp.Swashbuckle;
using Yi.Abp.Application; using Yi.Abp.Application;
@@ -34,7 +35,7 @@ using Yi.Framework.AspNetCore.Authentication.OAuth.Gitee;
using Yi.Framework.AspNetCore.Authentication.OAuth.QQ; using Yi.Framework.AspNetCore.Authentication.OAuth.QQ;
using Yi.Framework.AspNetCore.Microsoft.AspNetCore.Builder; using Yi.Framework.AspNetCore.Microsoft.AspNetCore.Builder;
using Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection; using Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection;
using Yi.Framework.AspNetCore.UnifyResult; using Yi.Framework.BackgroundWorkers.Hangfire;
using Yi.Framework.Bbs.Application; using Yi.Framework.Bbs.Application;
using Yi.Framework.Bbs.Application.Extensions; using Yi.Framework.Bbs.Application.Extensions;
using Yi.Framework.ChatHub.Application; using Yi.Framework.ChatHub.Application;
@@ -57,6 +58,8 @@ namespace Yi.Abp.Web
typeof(AbpSwashbuckleModule), typeof(AbpSwashbuckleModule),
typeof(AbpAspNetCoreSerilogModule), typeof(AbpAspNetCoreSerilogModule),
typeof(AbpAuditingModule), typeof(AbpAuditingModule),
typeof(YiFrameworkBackgroundWorkersHangfireModule),
typeof(AbpBackgroundJobsHangfireModule),
typeof(AbpAspNetCoreAuthenticationJwtBearerModule), typeof(AbpAspNetCoreAuthenticationJwtBearerModule),
typeof(YiFrameworkAspNetCoreModule), typeof(YiFrameworkAspNetCoreModule),
typeof(YiFrameworkAspNetCoreAuthenticationOAuthModule) typeof(YiFrameworkAspNetCoreAuthenticationOAuthModule)
@@ -70,217 +73,245 @@ namespace Yi.Abp.Web
var configuration = context.Services.GetConfiguration(); var configuration = context.Services.GetConfiguration();
var host = context.Services.GetHostingEnvironment(); var host = context.Services.GetHostingEnvironment();
var service = context.Services; var service = context.Services;
//请求日志 //请求日志
Configure<AbpAuditingOptions>(optios => Configure<AbpAuditingOptions>(optios =>
{ {
//默认关闭,开启会有大量的审计日志 //默认关闭,开启会有大量的审计日志
optios.IsEnabled = true; optios.IsEnabled = true;
//审计日志过滤器
optios.AlwaysLogSelectors.Add(x => Task.FromResult(!x.Url.StartsWith("/api/app/file/")));
}); });
//忽略审计日志路径
//采用furion格式的规范化api默认不开启使用abp优雅的方式 Configure<AbpAspNetCoreAuditingOptions>(options =>
//你没看错。。。
//service.AddFurionUnifyResultApi();
//配置错误处理显示详情
Configure<AbpExceptionHandlingOptions>(options => { options.SendExceptionsDetailsToClients = true; });
//动态Api
Configure<AbpAspNetCoreMvcOptions>(options =>
{ {
options.ConventionalControllers.Create(typeof(YiAbpApplicationModule).Assembly, options.IgnoredUrls.Add("/api/app/file/");
options => options.RemoteServiceName = "default"); options.IgnoredUrls.Add("/hangfire");
options.ConventionalControllers.Create(typeof(YiFrameworkRbacApplicationModule).Assembly,
options => options.RemoteServiceName = "rbac");
options.ConventionalControllers.Create(typeof(YiFrameworkBbsApplicationModule).Assembly,
options => options.RemoteServiceName = "bbs");
options.ConventionalControllers.Create(typeof(YiFrameworkChatHubApplicationModule).Assembly,
options => options.RemoteServiceName = "chat-hub");
options.ConventionalControllers.Create(typeof(YiFrameworkTenantManagementApplicationModule).Assembly,
options => options.RemoteServiceName = "tenant-management");
options.ConventionalControllers.Create(typeof(YiFrameworkCodeGenApplicationModule).Assembly,
options => options.RemoteServiceName = "code-gen");
//统一前缀
options.ConventionalControllers.ConventionalControllerSettings.ForEach(x => x.RootPath = "api/app");
}); });
//【NewtonsoftJson严重问题逆天】设置api格式留给后人铭记
// service.AddControllers().AddNewtonsoftJson(options =>
// {
// options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
// options.SerializerSettings.Converters.Add(new StringEnumConverter());
// });
//请使用微软的注意abp date又包了一层采用DefaultJsonTypeInfoResolver统一覆盖 //采用furion格式的规范化api默认不开启使用abp优雅的方式
Configure<JsonOptions>(options => //你没看错。。。
{ //service.AddFurionUnifyResultApi();
options.JsonSerializerOptions.TypeInfoResolver = new DefaultJsonTypeInfoResolver();
options.JsonSerializerOptions.Converters.Add(new DatetimeJsonConverter());
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
});
//设置缓存不要过期默认滑动20分钟 //配置错误处理显示详情
Configure<AbpDistributedCacheOptions>(cacheOptions => Configure<AbpExceptionHandlingOptions>(options => { options.SendExceptionsDetailsToClients = true; });
{
cacheOptions.GlobalCacheEntryOptions.SlidingExpiration = null;
//缓存key前缀
cacheOptions.KeyPrefix = "Yi:";
});
//动态Api
Configure<AbpAntiForgeryOptions>(options => { options.AutoValidate = false; }); Configure<AbpAspNetCoreMvcOptions>(options =>
//Swagger
context.Services.AddYiSwaggerGen<YiAbpWebModule>(options =>
{
options.SwaggerDoc("default",
new OpenApiInfo { Title = "Yi.Framework.Abp", Version = "v1", Description = "集大成者" });
});
//跨域
context.Services.AddCors(options =>
{
options.AddPolicy(DefaultCorsPolicyName, builder =>
{ {
builder options.ConventionalControllers.Create(typeof(YiAbpApplicationModule).Assembly,
.WithOrigins( options => options.RemoteServiceName = "default");
configuration["App:CorsOrigins"]! options.ConventionalControllers.Create(typeof(YiFrameworkRbacApplicationModule).Assembly,
.Split(";", StringSplitOptions.RemoveEmptyEntries) options => options.RemoteServiceName = "rbac");
.Select(o => o.RemovePostFix("/")) options.ConventionalControllers.Create(typeof(YiFrameworkBbsApplicationModule).Assembly,
.ToArray() options => options.RemoteServiceName = "bbs");
) options.ConventionalControllers.Create(typeof(YiFrameworkChatHubApplicationModule).Assembly,
.WithAbpExposedHeaders() options => options.RemoteServiceName = "chat-hub");
.SetIsOriginAllowedToAllowWildcardSubdomains() options.ConventionalControllers.Create(
.AllowAnyHeader() typeof(YiFrameworkTenantManagementApplicationModule).Assembly,
.AllowAnyMethod() options => options.RemoteServiceName = "tenant-management");
.AllowCredentials(); options.ConventionalControllers.Create(typeof(YiFrameworkCodeGenApplicationModule).Assembly,
options => options.RemoteServiceName = "code-gen");
//统一前缀
options.ConventionalControllers.ConventionalControllerSettings.ForEach(x => x.RootPath = "api/app");
}); });
});
//配置多租户 //【NewtonsoftJson严重问题逆天】设置api格式留给后人铭记
Configure<AbpTenantResolveOptions>(options => // service.AddControllers().AddNewtonsoftJson(options =>
{ // {
//基于cookie jwt不好用有坑 // options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
options.TenantResolvers.Clear(); // options.SerializerSettings.Converters.Add(new StringEnumConverter());
options.TenantResolvers.Add(new HeaderTenantResolveContributor()); // });
//options.TenantResolvers.Add(new HeaderTenantResolveContributor());
//options.TenantResolvers.Add(new CookieTenantResolveContributor());
//options.TenantResolvers.RemoveAll(x => x.Name == CookieTenantResolveContributor.ContributorName); //请使用微软的注意abp date又包了一层采用DefaultJsonTypeInfoResolver统一覆盖
}); Configure<JsonOptions>(options =>
//速率限制
//每60秒限制100个请求滑块添加分6段
service.AddRateLimiter(_ =>
{
_.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
_.OnRejected = (context, _) =>
{ {
if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter)) options.JsonSerializerOptions.TypeInfoResolver = new DefaultJsonTypeInfoResolver();
options.JsonSerializerOptions.Converters.Add(new DatetimeJsonConverter());
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
});
//设置缓存不要过期默认滑动20分钟
Configure<AbpDistributedCacheOptions>(cacheOptions =>
{
cacheOptions.GlobalCacheEntryOptions.SlidingExpiration = null;
//缓存key前缀
cacheOptions.KeyPrefix = "Yi:";
});
Configure<AbpAntiForgeryOptions>(options => { options.AutoValidate = false; });
//Swagger
context.Services.AddYiSwaggerGen<YiAbpWebModule>(options =>
{
options.SwaggerDoc("default",
new OpenApiInfo { Title = "Yi.Framework.Abp", Version = "v1", Description = "集大成者" });
});
//跨域
context.Services.AddCors(options =>
{
options.AddPolicy(DefaultCorsPolicyName, builder =>
{ {
context.HttpContext.Response.Headers.RetryAfter = builder
((int)retryAfter.TotalSeconds).ToString(NumberFormatInfo.InvariantInfo); .WithOrigins(
configuration["App:CorsOrigins"]!
.Split(";", StringSplitOptions.RemoveEmptyEntries)
.Select(o => o.RemovePostFix("/"))
.ToArray()
)
.WithAbpExposedHeaders()
.SetIsOriginAllowedToAllowWildcardSubdomains()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
//配置多租户
Configure<AbpTenantResolveOptions>(options =>
{
//基于cookie jwt不好用有坑
options.TenantResolvers.Clear();
options.TenantResolvers.Add(new HeaderTenantResolveContributor());
//options.TenantResolvers.Add(new HeaderTenantResolveContributor());
//options.TenantResolvers.Add(new CookieTenantResolveContributor());
//options.TenantResolvers.RemoveAll(x => x.Name == CookieTenantResolveContributor.ContributorName);
});
//配置Hangfire定时任务存储开启redis后优先使用redis
var redisConfiguration = configuration["Redis:Configuration"];
var redisEnabled = configuration["Redis:IsEnabled"];
context.Services.AddHangfire(config =>
{
if (redisEnabled.IsNullOrEmpty() || bool.Parse(redisEnabled))
{
config.UseRedisStorage(
ConnectionMultiplexer.Connect(redisConfiguration),
new RedisStorageOptions()
{
InvisibilityTimeout = TimeSpan.FromHours(1), //JOB允许执行1小时
Prefix = "Yi:HangfireJob:"
}).WithJobExpirationTimeout(TimeSpan.FromHours(1));
} }
else
context.HttpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests;
context.HttpContext.Response.WriteAsync("Too many requests. Please try again later.");
return new ValueTask();
};
//全局使用,链式表达式
_.GlobalLimiter = PartitionedRateLimiter.CreateChained(
PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
{ {
var userAgent = httpContext.Request.Headers.UserAgent.ToString(); config.UseMemoryStorage();
}
});
return RateLimitPartition.GetSlidingWindowLimiter //速率限制
(userAgent, _ => //每60秒限制100个请求滑块添加分6段
new SlidingWindowRateLimiterOptions service.AddRateLimiter(_ =>
{
PermitLimit = 1000,
Window = TimeSpan.FromSeconds(60),
SegmentsPerWindow = 6,
QueueProcessingOrder = QueueProcessingOrder.OldestFirst
});
}));
});
//jwt鉴权
var jwtOptions = configuration.GetSection(nameof(JwtOptions)).Get<JwtOptions>();
var refreshJwtOptions = configuration.GetSection(nameof(RefreshJwtOptions)).Get<RefreshJwtOptions>();
context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{ {
options.TokenValidationParameters = new TokenValidationParameters _.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
_.OnRejected = (context, _) =>
{ {
ClockSkew = TimeSpan.Zero, if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter))
ValidateIssuerSigningKey = true,
ValidIssuer = jwtOptions.Issuer,
ValidAudience = jwtOptions.Audience,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.SecurityKey))
};
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{ {
var accessToken = context.Request.Query["access_token"]; context.HttpContext.Response.Headers.RetryAfter =
if (!string.IsNullOrEmpty(accessToken)) ((int)retryAfter.TotalSeconds).ToString(NumberFormatInfo.InvariantInfo);
{
context.Token = accessToken;
}
return Task.CompletedTask;
} }
context.HttpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests;
context.HttpContext.Response.WriteAsync("Too many requests. Please try again later.");
return new ValueTask();
}; };
})
.AddJwtBearer(TokenTypeConst.Refresh, options => //全局使用,链式表达式
{ _.GlobalLimiter = PartitionedRateLimiter.CreateChained(
options.TokenValidationParameters = new TokenValidationParameters PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
{
ClockSkew = TimeSpan.Zero,
ValidateIssuerSigningKey = true,
ValidIssuer = refreshJwtOptions.Issuer,
ValidAudience = refreshJwtOptions.Audience,
IssuerSigningKey =
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(refreshJwtOptions.SecurityKey))
};
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{ {
var refresh_token = context.Request.Headers["refresh_token"]; var userAgent = httpContext.Request.Headers.UserAgent.ToString();
if (!string.IsNullOrEmpty(refresh_token))
return RateLimitPartition.GetSlidingWindowLimiter
(userAgent, _ =>
new SlidingWindowRateLimiterOptions
{
PermitLimit = 1000,
Window = TimeSpan.FromSeconds(60),
SegmentsPerWindow = 6,
QueueProcessingOrder = QueueProcessingOrder.OldestFirst
});
}));
});
//jwt鉴权
var jwtOptions = configuration.GetSection(nameof(JwtOptions)).Get<JwtOptions>();
var refreshJwtOptions = configuration.GetSection(nameof(RefreshJwtOptions)).Get<RefreshJwtOptions>();
context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ClockSkew = TimeSpan.Zero,
ValidateIssuerSigningKey = true,
ValidIssuer = jwtOptions.Issuer,
ValidAudience = jwtOptions.Audience,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.SecurityKey))
};
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{ {
context.Token = refresh_token; var accessToken = context.Request.Query["access_token"];
if (!string.IsNullOrEmpty(accessToken))
{
context.Token = accessToken;
}
return Task.CompletedTask; return Task.CompletedTask;
} }
};
var refreshToken = context.Request.Query["refresh_token"]; })
if (!string.IsNullOrEmpty(refreshToken)) .AddJwtBearer(TokenTypeConst.Refresh, options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ClockSkew = TimeSpan.Zero,
ValidateIssuerSigningKey = true,
ValidIssuer = refreshJwtOptions.Issuer,
ValidAudience = refreshJwtOptions.Audience,
IssuerSigningKey =
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(refreshJwtOptions.SecurityKey))
};
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{ {
context.Token = refreshToken; var refresh_token = context.Request.Headers["refresh_token"];
if (!string.IsNullOrEmpty(refresh_token))
{
context.Token = refresh_token;
return Task.CompletedTask;
}
var refreshToken = context.Request.Query["refresh_token"];
if (!string.IsNullOrEmpty(refreshToken))
{
context.Token = refreshToken;
}
return Task.CompletedTask;
} }
};
})
.AddQQ(options => { configuration.GetSection("OAuth:QQ").Bind(options); })
.AddGitee(options => { configuration.GetSection("OAuth:Gitee").Bind(options); });
return Task.CompletedTask; //授权
} context.Services.AddAuthorization();
};
})
.AddQQ(options => { configuration.GetSection("OAuth:QQ").Bind(options); })
.AddGitee(options => { configuration.GetSection("OAuth:Gitee").Bind(options); });
//授权
context.Services.AddAuthorization();
return Task.CompletedTask;
return Task.CompletedTask; }
}
public override Task OnApplicationInitializationAsync(ApplicationInitializationContext context) public override async Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
{ {
var service = context.ServiceProvider; var service = context.ServiceProvider;
var env = context.GetEnvironment(); var env = context.GetEnvironment();
@@ -334,11 +365,15 @@ namespace Yi.Abp.Web
//日志记录 //日志记录
app.UseAbpSerilogEnrichers(); app.UseAbpSerilogEnrichers();
//Hangfire定时任务面板可配置授权
app.UseAbpHangfireDashboard("/hangfire", options =>
{
// options.AsyncAuthorization = new[] { new AbpHangfireAuthorizationFilter() };
});
//终节点 //终节点
app.UseConfiguredEndpoints(); app.UseConfiguredEndpoints();
return Task.CompletedTask;
} }
} }
} }

View File

@@ -2,8 +2,6 @@
using Volo.Abp.Auditing; using Volo.Abp.Auditing;
using Volo.Abp.Autofac; using Volo.Abp.Autofac;
using Volo.Abp.BackgroundWorkers; using Volo.Abp.BackgroundWorkers;
using Volo.Abp.BackgroundWorkers.Quartz;
using Volo.Abp.Domain.Repositories;
using Yi.Framework.Rbac.Application; using Yi.Framework.Rbac.Application;
using Yi.Framework.Rbac.Domain.Entities; using Yi.Framework.Rbac.Domain.Entities;
using Yi.Framework.Rbac.Domain.Managers; using Yi.Framework.Rbac.Domain.Managers;
@@ -24,10 +22,11 @@ namespace Yi.Framework.Rbac.Test
{ {
public override void ConfigureServices(ServiceConfigurationContext context) public override void ConfigureServices(ServiceConfigurationContext context)
{ {
Configure<AbpBackgroundWorkerQuartzOptions>(options =>
{ // Configure<AbpBackgroundWorkerQuartzOptions>(options =>
options.IsAutoRegisterEnabled = false; // {
}); // options.IsAutoRegisterEnabled = false;
// });
Configure<AbpBackgroundWorkerOptions> (options => Configure<AbpBackgroundWorkerOptions> (options =>
{ {
options.IsEnabled = false; //禁用作业执行 options.IsEnabled = false; //禁用作业执行
@@ -35,7 +34,6 @@ namespace Yi.Framework.Rbac.Test
Configure<DbConnOptions>(options => Configure<DbConnOptions>(options =>
{ {
options.Url = $"DataSource=yi-rbac-test-{DateTime.Now.ToString("yyyyMMdd_HHmmss")}.db"; options.Url = $"DataSource=yi-rbac-test-{DateTime.Now.ToString("yyyyMMdd_HHmmss")}.db";
}); });
} }

View File

@@ -16,7 +16,8 @@ const form = reactive({
}); });
const installText = "> dotnet tool install -g Yi.Abp.Tool"; const installText = "> dotnet tool install -g Yi.Abp.Tool";
const cloneText = "> yi-abp clone "; const cloneText = "> yi-abp clone ";
const listText="> yi-abp new list ";
const helpText="> yi-abp -h ";
const nugetData=reactive({ const nugetData=reactive({
versions:"0.0.0", versions:"0.0.0",
downloadNumber:0 downloadNumber:0
@@ -40,7 +41,9 @@ const dbData = [
const typeData = [{ name: '模块', key: 'module', value: 'module' }, const typeData = [{ name: '模块', key: 'module', value: 'module' },
{ name: '模块', key: 'project', value: 'project' }] { name: '模块', key: 'module', value: 'module' },
{ name: '模块', key: 'module', value: 'module' },
{ name: '模块', key: 'module', value: 'module' }]
const addModuleComputed=computed(()=>{ const addModuleComputed=computed(()=>{
return `> yi-abp add-module ${form.name}`; return `> yi-abp add-module ${form.name}`;
@@ -139,6 +142,19 @@ onUnmounted(() => {
<LableCheck v-model="form.isCsf" title="创建解决方案文件夹" text="指定项目是放在输出文件夹中的新文件夹中,还是直接放在输出文件夹中。" /> <LableCheck v-model="form.isCsf" title="创建解决方案文件夹" text="指定项目是放在输出文件夹中的新文件夹中,还是直接放在输出文件夹中。" />
<p>默认勾选</p>
<h4>模板库</h4>
<p>现在已经支持公开模板库地址https://gitee.com/ccnetcore/yi-template</p>
<p>每个分支代表一个模板你可以通过提交pr或联系管理员上传你自定义的模板</p>
<CodeBox v-model="listText" />
<p>通过以上命令可查询当前可用模板</p>
<h4>帮助</h4>
<p>更详细的实时帮助可执行帮助命令</p>
<CodeBox v-model="helpText" />
<p>如还有疑惑或错误可在社区对应板块发布问题</p>
</div> </div>
<div class="content-body-right"> <div class="content-body-right">
@@ -191,7 +207,7 @@ onUnmounted(() => {
} }
&-body { &-body {
height: 1400px; height: 1800px;
padding: 48px; padding: 48px;
background-color: #fff; background-color: #fff;
border-radius: 12px; border-radius: 12px;

View File

@@ -61,11 +61,11 @@ export function addDateRange(params, dateRange, propName) {
if (typeof (propName) === 'undefined') { if (typeof (propName) === 'undefined') {
// search.params['beginTime'] = dateRange[0]; // search.params['beginTime'] = dateRange[0];
// search.params['endTime'] = dateRange[1]; // search.params['endTime'] = dateRange[1];
search.startTime=dateRange[0]; search.startTime=parseTime(dateRange[0]);
search.endTime=dateRange[1]; search.endTime=parseTime(dateRange[1]);
} else { } else {
search.params['start' + propName] = dateRange[0]; search.params['start' + propName] = parseTime(dateRange[0]);
search.params['end' + propName] = dateRange[1]; search.params['end' + propName] = parseTime(dateRange[1]);
} }
return search; return search;
} }