diff --git a/Yi.Abp.Net8/Yi.Abp.sln b/Yi.Abp.Net8/Yi.Abp.sln index 03343e50..7a75e175 100644 --- a/Yi.Abp.Net8/Yi.Abp.sln +++ b/Yi.Abp.Net8/Yi.Abp.sln @@ -107,13 +107,17 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.TenantManageme EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "code-gen", "code-gen", "{4FFE7212-21F2-476D-B628-3C65E6C5075E}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.CodeGen.Application", "module\code-gen\Yi.Framework.Codegen.Application\Yi.Framework.CodeGen.Application.csproj", "{97EC40D7-DBFA-467A-98CB-221AF27B14F2}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.CodeGen.Application", "module\code-gen\Yi.Framework.CodeGen.Application\Yi.Framework.CodeGen.Application.csproj", "{97EC40D7-DBFA-467A-98CB-221AF27B14F2}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.CodeGen.Application.Contracts", "module\code-gen\Yi.Framework.Codegen.Application.Contracts\Yi.Framework.CodeGen.Application.Contracts.csproj", "{882BC563-2F75-4B95-AC96-F4BF23F5E69D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.CodeGen.Application.Contracts", "module\code-gen\Yi.Framework.CodeGen.Application.Contracts\Yi.Framework.CodeGen.Application.Contracts.csproj", "{882BC563-2F75-4B95-AC96-F4BF23F5E69D}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.CodeGen.Domain", "module\code-gen\Yi.Framework.Codegen.Domain\Yi.Framework.CodeGen.Domain.csproj", "{85CB8517-2B80-42D8-B954-081079AC9BA0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.CodeGen.Domain", "module\code-gen\Yi.Framework.CodeGen.Domain\Yi.Framework.CodeGen.Domain.csproj", "{85CB8517-2B80-42D8-B954-081079AC9BA0}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.CodeGen.Domain.Shared", "module\code-gen\Yi.Framework.Codegen.Domain.Shared\Yi.Framework.CodeGen.Domain.Shared.csproj", "{EEFF0F05-2709-4151-A8CE-667935CEAE0B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.CodeGen.Domain.Shared", "module\code-gen\Yi.Framework.CodeGen.Domain.Shared\Yi.Framework.CodeGen.Domain.Shared.csproj", "{EEFF0F05-2709-4151-A8CE-667935CEAE0B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yi.Framework.Caching.FreeRedis", "framework\Yi.Framework.Caching.FreeRedis\Yi.Framework.Caching.FreeRedis.csproj", "{862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.CodeGen.SqlSugarCore", "module\code-gen\Yi.Framework.CodeGen.SqlSugarCore\Yi.Framework.CodeGen.SqlSugarCore.csproj", "{FB09ACC2-A27D-4D87-8D85-1435FDED4D04}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -289,6 +293,14 @@ Global {EEFF0F05-2709-4151-A8CE-667935CEAE0B}.Debug|Any CPU.Build.0 = Debug|Any CPU {EEFF0F05-2709-4151-A8CE-667935CEAE0B}.Release|Any CPU.ActiveCfg = Release|Any CPU {EEFF0F05-2709-4151-A8CE-667935CEAE0B}.Release|Any CPU.Build.0 = Release|Any CPU + {862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {862BB0EF-3D4E-44FF-AB15-0EB74CE553D3}.Release|Any CPU.Build.0 = Release|Any CPU + {FB09ACC2-A27D-4D87-8D85-1435FDED4D04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FB09ACC2-A27D-4D87-8D85-1435FDED4D04}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FB09ACC2-A27D-4D87-8D85-1435FDED4D04}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FB09ACC2-A27D-4D87-8D85-1435FDED4D04}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -341,6 +353,8 @@ Global {882BC563-2F75-4B95-AC96-F4BF23F5E69D} = {4FFE7212-21F2-476D-B628-3C65E6C5075E} {85CB8517-2B80-42D8-B954-081079AC9BA0} = {4FFE7212-21F2-476D-B628-3C65E6C5075E} {EEFF0F05-2709-4151-A8CE-667935CEAE0B} = {4FFE7212-21F2-476D-B628-3C65E6C5075E} + {862BB0EF-3D4E-44FF-AB15-0EB74CE553D3} = {77B949E9-530E-45A5-9657-20F7D5C6875C} + {FB09ACC2-A27D-4D87-8D85-1435FDED4D04} = {4FFE7212-21F2-476D-B628-3C65E6C5075E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {23D6FBC9-C970-4641-BC1E-2AEA59F51C18} diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/FreeSqlOptions.cs b/Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/FreeSqlOptions.cs new file mode 100644 index 00000000..f87d54ec --- /dev/null +++ b/Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/FreeSqlOptions.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using FreeRedis; + +namespace Yi.Framework.Caching.FreeRedis +{ + /// + /// 便于转到定义 + /// + public class FreeSqlOptions: ConnectionStringBuilder + { + + } +} diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/Yi.Framework.Caching.FreeRedis.csproj b/Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/Yi.Framework.Caching.FreeRedis.csproj new file mode 100644 index 00000000..fe61ba31 --- /dev/null +++ b/Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/Yi.Framework.Caching.FreeRedis.csproj @@ -0,0 +1,16 @@ + + + + + net8.0 + enable + enable + + + + + + + + + diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/YiDistributedCacheKeyNormalizer.cs b/Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/YiDistributedCacheKeyNormalizer.cs new file mode 100644 index 00000000..e3e0e22e --- /dev/null +++ b/Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/YiDistributedCacheKeyNormalizer.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; +using Volo.Abp.MultiTenancy; + +namespace Yi.Framework.Caching.FreeRedis +{ + [Dependency(ReplaceServices =true)] + public class YiDistributedCacheKeyNormalizer : IDistributedCacheKeyNormalizer, ITransientDependency + { + protected ICurrentTenant CurrentTenant { get; } + + protected AbpDistributedCacheOptions DistributedCacheOptions { get; } + + public YiDistributedCacheKeyNormalizer( + ICurrentTenant currentTenant, + IOptions distributedCacheOptions) + { + CurrentTenant = currentTenant; + DistributedCacheOptions = distributedCacheOptions.Value; + } + + public virtual string NormalizeKey(DistributedCacheKeyNormalizeArgs args) + { + var normalizedKey = $"{DistributedCacheOptions.KeyPrefix}{args.Key}"; + + //if (!args.IgnoreMultiTenancy && CurrentTenant.Id.HasValue) + //{ + // normalizedKey = $"t:{CurrentTenant.Id.Value},{normalizedKey}"; + //} + + return normalizedKey; + } + } +} diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/YiFrameworkCachingFreeRedisModule.cs b/Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/YiFrameworkCachingFreeRedisModule.cs new file mode 100644 index 00000000..85b65e44 --- /dev/null +++ b/Yi.Abp.Net8/framework/Yi.Framework.Caching.FreeRedis/YiFrameworkCachingFreeRedisModule.cs @@ -0,0 +1,32 @@ +using FreeRedis; +using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Volo.Abp.Caching; + +namespace Yi.Framework.Caching.FreeRedis +{ + /// + /// 此模块得益于FreeRedis作者支持IDistributedCache,使用湿滑 + /// + [DependsOn(typeof(AbpCachingModule))] + public class YiFrameworkCachingFreeRedisModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + + var configuration = context.Services.GetConfiguration(); + + var redisEnabled = configuration["Redis:IsEnabled"]; + if (redisEnabled.IsNullOrEmpty() || bool.Parse(redisEnabled)) + { + var redisConfiguration = configuration["Redis:Configuration"]; + RedisClient redisClient = new RedisClient(redisConfiguration); + + context.Services.AddSingleton(redisClient); + context.Services.Replace(ServiceDescriptor.Singleton(new + DistributedCache(redisClient))); + } + } + } +} diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarDbContext.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarDbContext.cs index a2b5016c..edfcf258 100644 --- a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarDbContext.cs +++ b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarDbContext.cs @@ -60,6 +60,7 @@ namespace Yi.Framework.SqlSugarCore { options.ConnectionString = currentConnection; })); + connectionCreator.SetDbAop(SqlSugarClient); } /// @@ -242,6 +243,11 @@ namespace Yi.Framework.SqlSugarCore /// protected virtual void OnLogExecuted(string sql, SugarParameter[] pars) { + if (Options.EnabledSqlLog) + { + var sqllog = $"=========Yi-SQL耗时{SqlSugarClient.Ado.SqlExecutionTime.TotalMilliseconds}毫秒====="; + Logger.CreateLogger().LogDebug(sqllog.ToString()); + } } /// @@ -251,7 +257,14 @@ namespace Yi.Framework.SqlSugarCore /// protected virtual void EntityService(PropertyInfo property, EntityColumnInfo column) { - + if (property.PropertyType == typeof(ExtraPropertyDictionary)) + { + column.IsIgnore = true; + } + if (property.Name == nameof(Entity.Id)) + { + column.IsPrimarykey = true; + } } public void BackupDataBase() diff --git a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Services/Integral/IntegralService.cs b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Services/Integral/IntegralService.cs index 11bc594f..10855742 100644 --- a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Services/Integral/IntegralService.cs +++ b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Services/Integral/IntegralService.cs @@ -6,9 +6,11 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Volo.Abp.Application.Services; +using Volo.Abp.EventBus.Local; using Volo.Abp.Users; using Yi.Framework.Bbs.Application.Contracts.Dtos.Integral; using Yi.Framework.Bbs.Domain.Managers; +using Yi.Framework.Bbs.Domain.Shared.Etos; using Yi.Framework.Rbac.Domain.Authorization; namespace Yi.Framework.Bbs.Application.Services.Integral @@ -17,10 +19,12 @@ namespace Yi.Framework.Bbs.Application.Services.Integral { private IntegralManager _integralManager; private ICurrentUser _currentUser; - public IntegralService(IntegralManager integralManager, ICurrentUser currentUser) + private ILocalEventBus _localEventBus; + public IntegralService(IntegralManager integralManager, ICurrentUser currentUser, ILocalEventBus localEventBus) { _integralManager = integralManager; _currentUser = currentUser; + _localEventBus = localEventBus; } diff --git a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Domain.Shared/Consts/LevelConst.cs b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Domain.Shared/Consts/LevelConst.cs index e62d9afc..b5bb0b81 100644 --- a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Domain.Shared/Consts/LevelConst.cs +++ b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Domain.Shared/Consts/LevelConst.cs @@ -8,7 +8,7 @@ namespace Yi.Framework.Bbs.Domain.Shared.Consts { public class LevelConst { - public const string LevelCacheKey=nameof(LevelCacheKey); + public const string LevelCacheKey="Level:All"; public const string Level_Low_Zero = "经验提升等级低于或等于0"; } diff --git a/Yi.Abp.Net8/module/code-gen/Yi.Framework.CodeGen.Domain.Shared/Enums/FieldTypeEnum.cs b/Yi.Abp.Net8/module/code-gen/Yi.Framework.CodeGen.Domain.Shared/Enums/FieldTypeEnum.cs index 4713f2a9..8a08cca9 100644 --- a/Yi.Abp.Net8/module/code-gen/Yi.Framework.CodeGen.Domain.Shared/Enums/FieldTypeEnum.cs +++ b/Yi.Abp.Net8/module/code-gen/Yi.Framework.CodeGen.Domain.Shared/Enums/FieldTypeEnum.cs @@ -26,6 +26,9 @@ namespace Yi.Framework.CodeGen.Domain.Shared.Enums [Display(Name = "DateTime", Description = "DateTime")] DateTime, + + [Display(Name = "Guid", Description = "Guid")] + Guid } } diff --git a/Yi.Abp.Net8/module/code-gen/Yi.Framework.CodeGen.Domain/Entities/TableAggregateRoot.cs b/Yi.Abp.Net8/module/code-gen/Yi.Framework.CodeGen.Domain/Entities/TableAggregateRoot.cs index bee9af39..48ba4165 100644 --- a/Yi.Abp.Net8/module/code-gen/Yi.Framework.CodeGen.Domain/Entities/TableAggregateRoot.cs +++ b/Yi.Abp.Net8/module/code-gen/Yi.Framework.CodeGen.Domain/Entities/TableAggregateRoot.cs @@ -1,4 +1,5 @@ using SqlSugar; +using Volo.Abp.Data; using Volo.Abp.Domain.Entities; namespace Yi.Framework.CodeGen.Domain.Entities @@ -24,5 +25,8 @@ namespace Yi.Framework.CodeGen.Domain.Entities /// [Navigate(NavigateType.OneToMany, nameof(FieldEntity.TableId))] public List Fields { get; set; } + + [SugarColumn(IsIgnore =true)] + public override ExtraPropertyDictionary ExtraProperties { get; protected set; } } } diff --git a/Yi.Abp.Net8/module/code-gen/Yi.Framework.CodeGen.SqlSugarCore/TemplateDataSeed.cs b/Yi.Abp.Net8/module/code-gen/Yi.Framework.CodeGen.SqlSugarCore/TemplateDataSeed.cs new file mode 100644 index 00000000..06b01136 --- /dev/null +++ b/Yi.Abp.Net8/module/code-gen/Yi.Framework.CodeGen.SqlSugarCore/TemplateDataSeed.cs @@ -0,0 +1,116 @@ +using Volo.Abp.Data; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Guids; +using Yi.Framework.CodeGen.Domain.Entities; +using Yi.Framework.SqlSugarCore.Abstractions; + +namespace Yi.Framework.CodeGen.SqlSugarCore +{ + public class TemplateDataSeed : IDataSeedContributor, ITransientDependency + { + private ISqlSugarRepository _repository; + public TemplateDataSeed(ISqlSugarRepository repository) + { + _repository = repository; + } + public async Task SeedAsync(DataSeedContext context) + { + if (!await _repository.IsAnyAsync(x => true)) + { + await _repository.InsertManyAsync(GetSeedData()); + } + } + public List GetSeedData() + { + var entities = new List(); + TemplateEntity entityTemplate = new TemplateEntity() + { + Name = "Entity", + BuildPath = "D:\\code\\Entities\\@ModelEntity.cs", + Remarks = "实体", + TemplateStr = "using SqlSugar;\r\nusing lo.Abp;\r\nusing lo.Abp.Auditing;\r\nusing lo.Abp.Domain.Entities;\r\nusing Yi.Framework.Core.Data;\r\n\r\nnamespace Yi.Framework.Rbac.Domain.Entities\r\n{\r\n /// \r\n /// 实体\r\n /// \r\n [SugarTable(\"@Model\")]\r\n public class @ModelEntity : Entity\r\n {\r\n@field\r\n }\r\n}\r\n" + }; + entities.Add(entityTemplate); + + + TemplateEntity getListInputTemplate = new TemplateEntity() + { + Name = "GetListInput", + BuildPath = "D:\\code\\Dtos\\@Model\\@ModelGetListInput.cs", + Remarks = "列表查询参数", + TemplateStr = "using Yi.Framework.Ddd;\r\nusing Yi.Framework.Ddd.Application.Contracts;\r\n\r\nnamespace Yi.Framework.Rbac.Application.Contracts.Dtos.@Model\r\n{\r\n /// \r\n /// 查询参数\r\n /// \r\n public class @ModelGetListInput : PagedAllResultRequestDto\r\n {\r\n@field\r\n }\r\n}\r\n" + }; + entities.Add(getListInputTemplate); + + + TemplateEntity getListOutputDtoTemplate = new TemplateEntity() + { + Name = "GetListOutputDto", + BuildPath = "D:\\code\\Dtos\\@Model\\@ModelGetListOutputDto.cs", + Remarks = "列表返回dto", + TemplateStr = "using lo.Abp.Application.Dtos;\r\n\r\nnamespace Yi.Framework.Rbac.Application.Contracts.Dtos.@Model\r\n{\r\n public class @ModelGetListOutputDto : EntityDto\r\n {\r\n@field\r\n }\r\n}\r\n" + }; + entities.Add(getListOutputDtoTemplate); + + + TemplateEntity getOutputDtoTemplate = new TemplateEntity() + { + Name = "GetOutputDto", + BuildPath = "D:\\code\\Dtos\\@Model\\@ModelGetOutputDto.cs", + Remarks = "单返回dto", + TemplateStr = "using lo.Abp.Application.Dtos;\r\n\r\nnamespace Yi.Framework.Rbac.Application.Contracts.Dtos.@Model\r\n{\r\n public class @ModelGetOutputDto : EntityDto\r\n {\r\n@field\r\n }\r\n}\r\n" + }; + entities.Add(getOutputDtoTemplate); + + TemplateEntity updateInputTemplate = new TemplateEntity() + { + Name = "UpdateInput", + BuildPath = "D:\\code\\Dtos\\@Model\\@ModelUpdateInput.cs", + Remarks = "更新输入", + TemplateStr = "namespace Yi.Framework.Rbac.Application.Contracts.Dtos.@Model\r\n{\r\n public class @ModelUpdateInput\r\n {\r\n@field\r\n }\r\n}\r\n" + }; + entities.Add(updateInputTemplate); + + TemplateEntity createInputTemplate = new TemplateEntity() + { + Name = "CreateInput", + BuildPath = "D:\\code\\Dtos\\@Model\\@ModelCreateInput.cs", + Remarks = "创建dto", + TemplateStr = "namespace Yi.Framework.Rbac.Application.Contracts.Dtos.@Model\r\n{\r\n /// \r\n /// @Model输入创建对象\r\n /// \r\n public class @ModelCreateInput\r\n {\r\n@field\r\n }\r\n}\r\n" + }; + entities.Add(createInputTemplate); + + + TemplateEntity iServicesTemplate = new TemplateEntity() + { + Name = "IServices", + BuildPath = "D:\\code\\IServices\\I@ModelService.cs", + Remarks = "应用服务抽象", + TemplateStr = "using lo.Abp.Application.Services;\r\nusing Yi.Framework.Ddd.Application.Contracts;\r\nusing Yi.Framework.Rbac.Application.Contracts.Dtos.@Model;\r\n\r\nnamespace Yi.Framework.Rbac.Application.Contracts.IServices\r\n{\r\n /// \r\n /// @Model服务抽象\r\n /// \r\n public interface I@ModelService : IYiCrudAppService<@ModelGetOutputDto, @ModelGetListOutputDto, Guid, @ModelGetListInput, @ModelCreateInput, @ModelUpdateInput>\r\n {\r\n\r\n }\r\n}\r\n" + }; + entities.Add(iServicesTemplate); + + + + TemplateEntity servicesTemplate = new TemplateEntity() + { + Name = "Service", + BuildPath = "D:\\code\\Services\\@ModelService.cs", + Remarks = "应用服务", + TemplateStr = "using SqlSugar;\r\nusing lo.Abp.Application.Dtos;\r\nusing lo.Abp.Application.Services;\r\nusing Yi.Framework.Ddd.Application;\r\nusing Yi.Framework.Rbac.Application.Contracts.Dtos.@Model;\r\nusing Yi.Framework.Rbac.Application.Contracts.IServices;\r\nusing Yi.Framework.Rbac.Domain.Entities;\r\nusing Yi.Framework.SqlSugarCore.Abstractions;\r\n\r\nnamespace Yi.Framework.Rbac.Application.Services\r\n{\r\n /// \r\n /// @Model服务实现\r\n /// \r\n public class @ModelService : YiCrudAppService<@ModelEntity, @ModelGetOutputDto, @ModelGetListOutputDto, Guid, @ModelGetListInput, @ModelCreateInput, @ModelUpdateInput>,\r\n I@ModelService\r\n {\r\n private ISqlSugarRepository<@ModelEntity, Guid> _repository;\r\n public @ModelService(ISqlSugarRepository<@ModelEntity, Guid> repository) : base(repository)\r\n {\r\n _repository = repository;\r\n }\r\n\r\n /// \r\n /// 多查\r\n /// \r\n /// \r\n /// \r\n public override async Task> GetListAsync(@ModelGetListInput input)\r\n {\r\n RefAsync total = 0;\r\n\r\n var entities = await _repository._DbQueryable.WhereIF(!string.IsNullOrEmpty(input.@ModelKey), x => x.@ModelKey.Contains(input.@ModelKey!))\r\n .WhereIF(!string.IsNullOrEmpty(input.@ModelName), x => x.@ModelName!.Contains(input.@ModelName!))\r\n .WhereIF(input.StartTime is not null && input.EndTime is not null, x => x.CreationTime >= input.StartTime && x.CreationTime <= input.EndTime)\r\n .ToPageListAsync(input.SkipCount, input.MaxResultCount, total);\r\n return new PagedResultDto<@ModelGetListOutputDto>(total, await MapToGetListOutputDtosAsync(entities));\r\n }\r\n }\r\n}\r\n" + }; + entities.Add(servicesTemplate); + + TemplateEntity apiTemplate = new TemplateEntity() + { + TemplateStr = "import request from '@/utils/request'\r\n\r\n// 分页查询\r\nexport function listData(query) {\r\n return request({\r\n url: '/@model',\r\n method: 'get',\r\n params: query\r\n })\r\n}\r\n\r\n// id查询\r\nexport function getData(id) {\r\n return request({\r\n url: `/@model/${id}`,\r\n method: 'get'\r\n })\r\n}\r\n\r\n// 新增\r\nexport function addData(data) {\r\n return request({\r\n url: '/@model',\r\n method: 'post',\r\n data: data\r\n })\r\n}\r\n\r\n// 修改\r\nexport function updateData(id,data) {\r\n return request({\r\n url: `/@model/${id}`,\r\n method: 'put',\r\n data: data\r\n })\r\n}\r\n\r\n// 删除\r\nexport function delData(ids) {\r\n return request({\r\n url: `/@model`,\r\n method: 'delete',\r\n params:{id:ids}\r\n })\r\n}\r\n", + Name = "api", + BuildPath = "D:\\code\\Api\\@ModelApi.vue", + Remarks = "前端api" + }; + entities.Add(apiTemplate); + + return entities; + } + } +} diff --git a/Yi.Abp.Net8/module/code-gen/Yi.Framework.CodeGen.SqlSugarCore/Yi.Framework.CodeGen.SqlSugarCore.csproj b/Yi.Abp.Net8/module/code-gen/Yi.Framework.CodeGen.SqlSugarCore/Yi.Framework.CodeGen.SqlSugarCore.csproj new file mode 100644 index 00000000..00c88c1d --- /dev/null +++ b/Yi.Abp.Net8/module/code-gen/Yi.Framework.CodeGen.SqlSugarCore/Yi.Framework.CodeGen.SqlSugarCore.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/Yi.Abp.Net8/module/code-gen/Yi.Framework.CodeGen.SqlSugarCore/YiFrameworkCodeGenSqlSugarCoreModule.cs b/Yi.Abp.Net8/module/code-gen/Yi.Framework.CodeGen.SqlSugarCore/YiFrameworkCodeGenSqlSugarCoreModule.cs new file mode 100644 index 00000000..7e47a1d6 --- /dev/null +++ b/Yi.Abp.Net8/module/code-gen/Yi.Framework.CodeGen.SqlSugarCore/YiFrameworkCodeGenSqlSugarCoreModule.cs @@ -0,0 +1,10 @@ +using Yi.Framework.SqlSugarCore; + +namespace Yi.Framework.CodeGen.SqlSugarCore +{ + [DependsOn(typeof(YiFrameworkSqlSugarCoreModule))] + public class YiFrameworkCodeGenSqlSugarCoreModule:AbpModule + { + + } +} diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Notice/NoticeCreateInput.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Notice/NoticeCreateInput.cs new file mode 100644 index 00000000..cb420612 --- /dev/null +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Notice/NoticeCreateInput.cs @@ -0,0 +1,17 @@ +using Yi.Framework.Rbac.Domain.Shared.Enums; + +namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Notice +{ + /// + /// Notice输入创建对象 + /// + public class NoticeCreateInput + { + public string Title { get; set; } + public NoticeTypeEnum Type { get; set; } + public string Content { get; set; } + public int OrderNum { get; set; } + public bool State { get; set; } + + } +} diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Notice/NoticeGetListInput.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Notice/NoticeGetListInput.cs new file mode 100644 index 00000000..7884d073 --- /dev/null +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Notice/NoticeGetListInput.cs @@ -0,0 +1,14 @@ +using Yi.Framework.Ddd.Application.Contracts; +using Yi.Framework.Rbac.Domain.Shared.Enums; + +namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Notice +{ + /// + /// 查询参数 + /// + public class NoticeGetListInput : PagedAllResultRequestDto + { + public string? Title { get; set; } + public NoticeTypeEnum? Type { get; set; } + } +} diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Notice/NoticeGetListOutputDto.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Notice/NoticeGetListOutputDto.cs new file mode 100644 index 00000000..20521adf --- /dev/null +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Notice/NoticeGetListOutputDto.cs @@ -0,0 +1,20 @@ +using Volo.Abp.Application.Dtos; +using Yi.Framework.Rbac.Domain.Shared.Enums; + +namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Notice +{ + public class NoticeGetListOutputDto : EntityDto + { + public string Title { get; set; } + public NoticeTypeEnum Type { get; set; } + public string Content { get; set; } + public bool IsDeleted { get; set; } + public DateTime CreationTime { get; set; } + public Guid? CreatorId { get; set; } + public Guid? LastModifierId { get; set; } + public DateTime? LastModificationTime { get; set; } + public int OrderNum { get; set; } + public bool State { get; set; } + + } +} diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Notice/NoticeGetOutputDto.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Notice/NoticeGetOutputDto.cs new file mode 100644 index 00000000..423e07b9 --- /dev/null +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Notice/NoticeGetOutputDto.cs @@ -0,0 +1,20 @@ +using Volo.Abp.Application.Dtos; +using Yi.Framework.Rbac.Domain.Shared.Enums; + +namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Notice +{ + public class NoticeGetOutputDto : EntityDto + { + public string Title { get; set; } + public NoticeTypeEnum Type { get; set; } + public string Content { get; set; } + public bool IsDeleted { get; set; } + public DateTime CreationTime { get; set; } + public Guid? CreatorId { get; set; } + public Guid? LastModifierId { get; set; } + public DateTime? LastModificationTime { get; set; } + public int OrderNum { get; set; } + public bool State { get; set; } + + } +} diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Notice/NoticeUpdateInput.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Notice/NoticeUpdateInput.cs new file mode 100644 index 00000000..8bf8f4db --- /dev/null +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Notice/NoticeUpdateInput.cs @@ -0,0 +1,13 @@ +using Yi.Framework.Rbac.Domain.Shared.Enums; + +namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Notice +{ + public class NoticeUpdateInput + { + public string? Title { get; set; } + public NoticeTypeEnum? Type { get; set; } + public string? Content { get; set; } + public int? OrderNum { get; set; } + public bool? State { get; set; } + } +} diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/IServices/INoticeService.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/IServices/INoticeService.cs new file mode 100644 index 00000000..c42e1b75 --- /dev/null +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/IServices/INoticeService.cs @@ -0,0 +1,13 @@ +using Yi.Framework.Ddd.Application.Contracts; +using Yi.Framework.Rbac.Application.Contracts.Dtos.Notice; + +namespace Yi.Framework.Rbac.Application.Contracts.IServices +{ + /// + /// Notice服务抽象 + /// + public interface INoticeService : IYiCrudAppService + { + + } +} diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/AccountService.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/AccountService.cs index 3d7c79e2..116d27c5 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/AccountService.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/AccountService.cs @@ -3,6 +3,7 @@ using Lazy.Captcha.Core; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using SqlSugar; using Volo.Abp; @@ -33,15 +34,17 @@ namespace Yi.Framework.Rbac.Application.Services private readonly IGuidGenerator _guidGenerator; private readonly RbacOptions _rbacOptions; private readonly IAliyunManger _aliyunManger; + private IDistributedCache _userCache; public AccountService(IUserRepository userRepository, ICurrentUser currentUser, IAccountManager accountManager, ISqlSugarRepository menuRepository, IDistributedCache phoneCache, + IDistributedCache userCache, ICaptcha captcha, IGuidGenerator guidGenerator, IOptions options, - IAliyunManger aliyunManger ) + IAliyunManger aliyunManger) { _userRepository = userRepository; _currentUser = currentUser; @@ -52,6 +55,7 @@ namespace Yi.Framework.Rbac.Application.Services _guidGenerator = guidGenerator; _rbacOptions = options.Value; _aliyunManger = aliyunManger; + _userCache = userCache; } @@ -113,10 +117,10 @@ namespace Yi.Framework.Rbac.Application.Services [Authorize(AuthenticationSchemes = TokenTypeConst.Refresh)] public async Task PostRefreshAsync([FromQuery] string refresh_token) { - var userId = CurrentUser.Id.Value; - var accessToken = await _accountManager.GetTokenByUserIdAsync(userId); - var refreshToken = _accountManager.CreateRefreshToken(userId); - return new { Token = accessToken, RefreshToken = refreshToken }; + var userId = CurrentUser.Id.Value; + var accessToken = await _accountManager.GetTokenByUserIdAsync(userId); + var refreshToken = _accountManager.CreateRefreshToken(userId); + return new { Token = accessToken, RefreshToken = refreshToken }; } /// @@ -249,7 +253,7 @@ namespace Yi.Framework.Rbac.Application.Services /// - /// 查询已登录的账户信息 + /// 查询已登录的账户信息,已缓存 /// /// [Route("account")] @@ -263,16 +267,33 @@ namespace Yi.Framework.Rbac.Application.Services { throw new UserFriendlyException("用户未登录"); } - //此处从缓存中获取也行 - //var data = _cacheManager.Get($"Yi:UserInfo:{userId}"); - var data = await _userRepository.GetUserAllInfoAsync(userId ?? Guid.Empty); - //系统用户数据被重置,老前端访问重新授权 - if (data is null) + //此处优先从缓存中获取 + UserRoleMenuDto output = null; + var cacheData = await _userCache.GetAsync(new UserInfoCacheKey(userId.Value)); + if (cacheData is not null) { - throw new AbpAuthorizationException(); + output = cacheData.Info; } - data.Menus.Clear(); - return data; + else + { + var data = await _userRepository.GetUserAllInfoAsync(userId.Value); + //系统用户数据被重置,老前端访问重新授权 + if (data is null) + { + throw new AbpAuthorizationException(); + } + data.Menus.Clear(); + + output = data; + + var tokenExpiresMinuteTime = LazyServiceProvider.GetRequiredService>().Value.ExpiresMinuteTime; + //将用户信息放入缓存,下次获取直接从缓存中获取即可,过期时间为token过期时间 + await _userCache.SetAsync(new UserInfoCacheKey(userId.Value), new UserInfoCacheItem(data), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(tokenExpiresMinuteTime) }); + } + + + + return output; } @@ -307,10 +328,18 @@ namespace Yi.Framework.Rbac.Application.Services /// 退出登录 /// /// - public Task PostLogout() + public async Task PostLogout() { + //通过鉴权jwt获取到用户的id + var userId = _currentUser.Id; + if (userId is null) + { + return false; + // throw new UserFriendlyException("用户已退出"); + } + await _userCache.RemoveAsync(new UserInfoCacheKey(userId.Value)); //Jwt去中心化登出,只需用记录日志即可 - return Task.FromResult(true); + return true; } /// diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/Monitor/MonitorCacheService.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/Monitor/MonitorCacheService.cs new file mode 100644 index 00000000..a8173d93 --- /dev/null +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/Monitor/MonitorCacheService.cs @@ -0,0 +1,127 @@ +using FreeRedis; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Options; +using Microsoft.VisualBasic; +using TencentCloud.Mna.V20210119.Models; +using Volo.Abp.Application.Services; +using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; +using Yi.Framework.Rbac.Application.Contracts.Dtos.MonitorCache; +using Yi.Framework.Rbac.Application.Contracts.IServices; + +namespace Yi.Framework.Rbac.Application.Services.Monitor +{ + public class MonitorCacheService : ApplicationService, IMonitorCacheService + { + public IAbpLazyServiceProvider LazyServiceProvider { get; set; } + + /// + /// 缓存前缀 + /// + private string CacheKeyPrefix => LazyServiceProvider.LazyGetRequiredService>().Value.KeyPrefix; + + private bool EnableRedisCache + { + get + { + var redisEnabled = LazyServiceProvider.LazyGetRequiredService()["Redis:IsEnabled"]; + return redisEnabled.IsNullOrEmpty() || bool.Parse(redisEnabled); + } + } + /// + /// 使用懒加载防止报错 + /// + private IRedisClient RedisClient => LazyServiceProvider.LazyGetRequiredService(); + + /// + /// 获取所有key并分组 + /// + /// + [HttpGet("monitor-cache/name")] + public List GetName() + { + VerifyRedisCacheEnable(); + var keys = RedisClient.Keys(CacheKeyPrefix + "*"); + var result = GroupedKeys(keys.ToList()); + var output = result.Select(x => new MonitorCacheNameGetListOutputDto { CacheName = x }).ToList(); + return output; + } + + private List GroupedKeys(List keys) + { + HashSet resultSet = new HashSet(); + foreach (string str in keys) + { + string[] parts = str.Split(':'); + + // 如果字符串中包含冒号,则将第一部分和第二部分进行分组 + if (parts.Length >= 2) + { + string group = $"{parts[0]}:{parts[1]}"; + resultSet.Add(group); + } + // 如果字符串中不包含冒号,则直接进行分组 + else + { + resultSet.Add(str); + } + } + return resultSet.ToList(); + + } + + + + private void VerifyRedisCacheEnable() + { + if (!EnableRedisCache) + { + throw new UserFriendlyException("后端程序未使用Redis缓存,无法对Redis进行监控,可切换使用Redis"); + } + + } + + [HttpGet("monitor-cache/key/{cacaheName}")] + public List GetKey(string cacaheName) + { + VerifyRedisCacheEnable(); + var output = RedisClient.Keys($"{cacaheName}:*").Select(x => x.RemovePreFix(cacaheName + ":")); + return output.ToList(); + } + + //全部不为空 + [HttpGet("monitor-cache/value/{cacaheName}/{cacaheKey}")] + public MonitorCacheGetListOutputDto GetValue(string cacaheName, string cacaheKey) + { + var value = RedisClient.HGet($"{cacaheName}:{cacaheKey}", "data"); + return new MonitorCacheGetListOutputDto() { CacheKey = cacaheKey, CacheName = cacaheName, CacheValue = value }; + } + + + + [HttpDelete("monitor-cache/key/{cacaheName}")] + public bool DeleteKey(string cacaheName) + { + VerifyRedisCacheEnable(); + RedisClient.Del($"{cacaheName}:*"); + return true; + } + + [HttpDelete("monitor-cache/value/{cacaheName}/{cacaheKey}")] + public bool DeleteValue(string cacaheName, string cacaheKey) + { + RedisClient.Del($"{cacaheName}:{cacaheKey}"); + return true; + } + + [HttpDelete("monitor-cache/clear")] + public bool DeleteClear() + { + RedisClient.FlushDb(); + return true; + } + } + + +} diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/MonitorServerService.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/Monitor/MonitorServerService.cs similarity index 97% rename from Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/MonitorServerService.cs rename to Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/Monitor/MonitorServerService.cs index 7ab64101..55af86d3 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/MonitorServerService.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/Monitor/MonitorServerService.cs @@ -7,7 +7,7 @@ using Volo.Abp.Application.Services; using Yi.Framework.Core.Helper; using Yi.Framework.Rbac.Application.Contracts.IServices; -namespace Yi.Framework.Rbac.Application.Services +namespace Yi.Framework.Rbac.Application.Services.Monitor { public class MonitorServerService : ApplicationService, IMonitorServerService { diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/OnlineService.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/Monitor/OnlineService.cs similarity index 88% rename from Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/OnlineService.cs rename to Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/Monitor/OnlineService.cs index 257d3e54..5691a705 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/OnlineService.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/Monitor/OnlineService.cs @@ -7,13 +7,13 @@ using Yi.Framework.Rbac.Application.Contracts.IServices; using Yi.Framework.Rbac.Application.SignalRHubs; using Yi.Framework.Rbac.Domain.Shared.Model; -namespace Yi.Framework.Rbac.Application.Services +namespace Yi.Framework.Rbac.Application.Services.Monitor { public class OnlineService : ApplicationService, IOnlineService { private ILogger _logger; - private IHubContext _hub; - public OnlineService(ILogger logger, IHubContext hub) + private IHubContext _hub; + public OnlineService(ILogger logger, IHubContext hub) { _logger = logger; _hub = hub; @@ -26,7 +26,7 @@ namespace Yi.Framework.Rbac.Application.Services /// public Task> GetListAsync([FromQuery] OnlineUserModel online) { - var data = OnlineUserHub.clientUsers; + var data = OnlineHub.clientUsers; IEnumerable dataWhere = data.AsEnumerable(); if (!string.IsNullOrEmpty(online.Ipaddr)) @@ -37,7 +37,7 @@ namespace Yi.Framework.Rbac.Application.Services { dataWhere = dataWhere.Where((u) => u.UserName!.Contains(online.UserName)); } - return Task.FromResult(new PagedResultDto() { TotalCount = data.Count, Items = dataWhere.ToList() }) ; + return Task.FromResult(new PagedResultDto() { TotalCount = data.Count, Items = dataWhere.ToList() }); } @@ -50,7 +50,7 @@ namespace Yi.Framework.Rbac.Application.Services [Route("online/{connnectionId}")] public async Task ForceOut(string connnectionId) { - if (OnlineUserHub.clientUsers.Exists(u => u.ConnnectionId == connnectionId)) + if (OnlineHub.clientUsers.Exists(u => u.ConnnectionId == connnectionId)) { //前端接受到这个事件后,触发前端自动退出 await _hub.Clients.Client(connnectionId).SendAsync("forceOut", "你已被强制退出!"); diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/TaskService.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/Monitor/TaskService.cs similarity index 95% rename from Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/TaskService.cs rename to Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/Monitor/TaskService.cs index b8f79698..ab857fb6 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/TaskService.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/Monitor/TaskService.cs @@ -11,7 +11,7 @@ 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 +namespace Yi.Framework.Rbac.Application.Services.Monitor { public class TaskService : ApplicationService, ITaskService { @@ -19,7 +19,7 @@ namespace Yi.Framework.Rbac.Application.Services private readonly IClock _clock; public TaskService(ISchedulerFactory schedulerFactory, IClock clock) { - _clock=clock; + _clock = clock; _schedulerFactory = schedulerFactory; } @@ -39,7 +39,7 @@ namespace Yi.Framework.Rbac.Application.Services //状态 var state = await scheduler.GetTriggerState(trigger.Key); - + var output = new TaskGetOutput { JobId = jobDetail.Key.Name, @@ -48,7 +48,7 @@ namespace Yi.Framework.Rbac.Application.Services Properties = Newtonsoft.Json.JsonConvert.SerializeObject(jobDetail.JobDataMap), Concurrent = !jobDetail.ConcurrentExecutionDisallowed, Description = jobDetail.Description, - LastRunTime = _clock.Normalize( trigger.GetPreviousFireTimeUtc()?.DateTime??DateTime.MinValue), + 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() @@ -56,7 +56,7 @@ namespace Yi.Framework.Rbac.Application.Services if (trigger is ISimpleTrigger simple) { - output.TriggerArgs =Math.Round(simple.RepeatInterval.TotalMinutes,2) .ToString() + "分钟"; + output.TriggerArgs = Math.Round(simple.RepeatInterval.TotalMinutes, 2).ToString() + "分钟"; output.Type = JobTypeEnum.Millisecond; output.Millisecond = simple.RepeatInterval.TotalMilliseconds; } @@ -64,7 +64,7 @@ namespace Yi.Framework.Rbac.Application.Services { output.TriggerArgs = cron.CronExpressionString!; output.Type = JobTypeEnum.Cron; - output.Cron=cron.CronExpressionString; + output.Cron = cron.CronExpressionString; } return output; } @@ -159,7 +159,7 @@ namespace Yi.Framework.Rbac.Application.Services /// /// public async Task DeleteAsync(IEnumerable id) - { + { var scheduler = await _schedulerFactory.GetScheduler(); await scheduler.DeleteJobs(id.Select(x => new JobKey(x)).ToList()); } diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/MonitorCacheService.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/MonitorCacheService.cs deleted file mode 100644 index 0d02cee6..00000000 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/MonitorCacheService.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using Volo.Abp.Application.Services; -using Yi.Framework.Rbac.Application.Contracts.Dtos.MonitorCache; -using Yi.Framework.Rbac.Application.Contracts.IServices; - -namespace Yi.Framework.Rbac.Application.Services -{ - public class MonitorCacheService : ApplicationService, IMonitorCacheService - { - private static List monitorCacheNames => new List() - { - new MonitorCacheNameGetListOutputDto{ CacheName="Yi:Login",Remark="登录验证码"}, - new MonitorCacheNameGetListOutputDto{ CacheName="Yi:User",Remark="用户信息"} - }; - private Dictionary monitorCacheNamesDic => monitorCacheNames.ToDictionary(x => x.CacheName, x => x.Remark); - //private CSRedisClient _cacheClient; - public MonitorCacheService() - { - //_cacheClient = redisCacheClient.Client; - } - //cacheKey value为空,只要name和备注 - - public List GetName() - { - //固定的 - return monitorCacheNames; - } - [HttpGet("key/{cacaheName}")] - public List GetKey(string cacaheName) - { - //var output = _cacheClient.Keys($"{cacaheName}:*"); - return new List() { "1233124", "3124", "1231251", "12312412" }; - } - - //全部不为空 - [HttpGet("value/{cacaheName}/{cacaheKey}")] - public MonitorCacheGetListOutputDto GetValue(string cacaheName, string cacaheKey) - { - //var value = _cacheClient.Get($"{cacaheName}:{cacaheKey}"); - return new MonitorCacheGetListOutputDto() { CacheKey = cacaheKey, CacheName = cacaheName, CacheValue = "ttt", Remark = monitorCacheNamesDic[cacaheName] }; - } - } - - -} diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/NoticeService.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/NoticeService.cs new file mode 100644 index 00000000..dc77fbac --- /dev/null +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/NoticeService.cs @@ -0,0 +1,70 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.SignalR; +using SqlSugar; +using Volo.Abp.Application.Dtos; +using Yi.Framework.Ddd.Application; +using Yi.Framework.Rbac.Application.Contracts.Dtos.Notice; +using Yi.Framework.Rbac.Application.Contracts.IServices; +using Yi.Framework.Rbac.Application.SignalRHubs; +using Yi.Framework.Rbac.Domain.Entities; +using Yi.Framework.SqlSugarCore.Abstractions; + +namespace Yi.Framework.Rbac.Application.Services +{ + /// + /// Notice服务实现 + /// + public class NoticeService : YiCrudAppService, + INoticeService + { + private ISqlSugarRepository _repository; + private IHubContext _hubContext; + public NoticeService(ISqlSugarRepository repository, IHubContext hubContext) : base(repository) + { + _hubContext = hubContext; + _repository = repository; + } + + /// + /// 多查 + /// + /// + /// + public override async Task> GetListAsync(NoticeGetListInput input) + { + RefAsync total = 0; + + var entities = await _repository._DbQueryable.WhereIF(input.Type is not null, x => x.Type == input.Type) + .WhereIF(!string.IsNullOrEmpty(input.Title), x => x.Title!.Contains(input.Title!)) + .WhereIF(input.StartTime is not null && input.EndTime is not null, x => x.CreationTime >= input.StartTime && x.CreationTime <= input.EndTime) + .ToPageListAsync(input.SkipCount, input.MaxResultCount, total); + return new PagedResultDto(total, await MapToGetListOutputDtosAsync(entities)); + } + + + + /// + /// 发送在线消息 + /// + /// + [HttpPost("notice/online/{id}")] + public async Task SendOnlineAsync([FromRoute] Guid id) + { + var entity = await _repository._DbQueryable.FirstAsync(x => x.Id == id); + await _hubContext.Clients.All.SendAsync("ReceiveNotice", entity.Type.ToString(), entity.Title, entity.Content); + } + /// + /// 发送离线消息 + /// + /// + [HttpPost("notice/offline/{id}")] + public async Task SendOfflineAsync([FromRoute] Guid id) + { + //先发送一个在线 + await SendOnlineAsync(id); + + //然后将所有用户和通知id进行保留记录,判断是否已读还是未读 + //在首次请求返回全部未读的通知给前端即可 + } + } +} diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/LoginLogService.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/RecordLog/LoginLogService.cs similarity index 96% rename from Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/LoginLogService.cs rename to Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/RecordLog/LoginLogService.cs index 9ff45657..95c09dc6 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/LoginLogService.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/RecordLog/LoginLogService.cs @@ -7,7 +7,7 @@ using Yi.Framework.Rbac.Application.Contracts.Dtos.LoginLog; using Yi.Framework.Rbac.Domain.Entities; using Yi.Framework.SqlSugarCore.Abstractions; -namespace Yi.Framework.Rbac.Application.Services +namespace Yi.Framework.Rbac.Application.Services.RecordLog { public class LoginLogService : YiCrudAppService { diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/OperationLogService.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/RecordLog/OperationLogService.cs similarity index 94% rename from Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/OperationLogService.cs rename to Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/RecordLog/OperationLogService.cs index c12af05d..3bcd6d37 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/OperationLogService.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/RecordLog/OperationLogService.cs @@ -7,7 +7,7 @@ using Yi.Framework.Rbac.Application.Contracts.IServices; using Yi.Framework.Rbac.Domain.Operlog; using Yi.Framework.SqlSugarCore.Abstractions; -namespace Yi.Framework.Rbac.Application.Services +namespace Yi.Framework.Rbac.Application.Services.RecordLog { /// /// OperationLog服务实现 @@ -18,7 +18,7 @@ namespace Yi.Framework.Rbac.Application.Services private ISqlSugarRepository _repository; public OperationLogService(ISqlSugarRepository repository) : base(repository) { - _repository=repository; + _repository = repository; } public override async Task> GetListAsync(OperationLogGetListInputVo input) diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/SignalRHubs/NoticeHub.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/SignalRHubs/NoticeHub.cs new file mode 100644 index 00000000..262f09ac --- /dev/null +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/SignalRHubs/NoticeHub.cs @@ -0,0 +1,15 @@ +using Volo.Abp.AspNetCore.SignalR; + +namespace Yi.Framework.Rbac.Application.SignalRHubs +{ + [HubRoute("/hub/notice")] + public class NoticeHub : AbpHub + { + /// + /// 由于发布功能,主要是服务端项客户端主动推送 + /// + public NoticeHub() + { + } + } +} diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/SignalRHubs/OnlineUserHub.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/SignalRHubs/OnlineHub.cs similarity index 94% rename from Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/SignalRHubs/OnlineUserHub.cs rename to Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/SignalRHubs/OnlineHub.cs index 1d4afac5..8a269c6e 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/SignalRHubs/OnlineUserHub.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/SignalRHubs/OnlineHub.cs @@ -10,14 +10,14 @@ namespace Yi.Framework.Rbac.Application.SignalRHubs { [HubRoute("/hub/main")] [Authorize] - public class OnlineUserHub : AbpHub + public class OnlineHub : AbpHub { public static readonly List clientUsers = new(); private readonly static object objLock = new object(); private HttpContext? _httpContext; - private ILogger _logger => LoggerFactory.CreateLogger(); - public OnlineUserHub(IHttpContextAccessor httpContextAccessor) + private ILogger _logger => LoggerFactory.CreateLogger(); + public OnlineHub(IHttpContextAccessor httpContextAccessor) { _httpContext = httpContextAccessor?.HttpContext; } diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain.Shared/Caches/CaptchaPhoneCacheItem.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain.Shared/Caches/CaptchaPhoneCacheItem.cs index c18432fa..5ec63192 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain.Shared/Caches/CaptchaPhoneCacheItem.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain.Shared/Caches/CaptchaPhoneCacheItem.cs @@ -20,7 +20,7 @@ namespace Yi.Framework.Rbac.Domain.Shared.Caches public override string ToString() { - return $"Yi:Phone:{Phone}"; + return $"Phone:{Phone}"; } } } diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain.Shared/Caches/UserInfoCacheItem.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain.Shared/Caches/UserInfoCacheItem.cs new file mode 100644 index 00000000..6bbc113e --- /dev/null +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain.Shared/Caches/UserInfoCacheItem.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Rbac.Domain.Shared.Dtos; + +namespace Yi.Framework.Rbac.Domain.Shared.Caches +{ + public class UserInfoCacheItem + { + public UserInfoCacheItem(UserRoleMenuDto info) { Info = info; } + /// + /// 存储的用户信息 + /// + public UserRoleMenuDto Info { get; set; } + } + public class UserInfoCacheKey + { + public UserInfoCacheKey(Guid userId) { UserId = userId; } + + public Guid UserId { get; set; } + + public override string ToString() + { + return $"User:{UserId}"; + } + } +} diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain.Shared/Enums/NoticeTypeEnum.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain.Shared/Enums/NoticeTypeEnum.cs new file mode 100644 index 00000000..ae5fbff3 --- /dev/null +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain.Shared/Enums/NoticeTypeEnum.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Yi.Framework.Rbac.Domain.Shared.Enums +{ + public enum NoticeTypeEnum + { + [Description("走马灯")] + MerryGoRound = 0, + [Description("提示弹窗")] + Popup = 1 + } +} diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Entities/NoticeEntity.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Entities/NoticeEntity.cs new file mode 100644 index 00000000..f25aa89f --- /dev/null +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Entities/NoticeEntity.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SqlSugar; +using Volo.Abp.Auditing; +using Volo.Abp.Domain.Entities; +using Yi.Framework.Core.Data; +using Yi.Framework.Rbac.Domain.Shared.Enums; + +namespace Yi.Framework.Rbac.Domain.Entities +{ + [SugarTable("Notice")] + public class NoticeEntity : Entity, ISoftDelete, IAuditedObject, IOrderNum, IState + { + + [SugarColumn(IsPrimaryKey = true)] + public override Guid Id { get; protected set; } + + /// + /// 公告标题 + /// + public string Title { get; set; } + + /// + /// 类型 + /// + public NoticeTypeEnum Type { get; set; } + + /// + /// 内容 + /// + [SugarColumn(ColumnDataType = StaticConfig.CodeFirst_BigString)] + public string Content { get; set; } + + public bool IsDeleted { get; set; } + + public DateTime CreationTime { get; set; } + + public Guid? CreatorId { get; set; } + + public Guid? LastModifierId { get; set; } + + public DateTime? LastModificationTime { get; set; } + + public int OrderNum { get; set; } + public bool State { get; set; } + } +} diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Entities/PostEntity.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Entities/PostEntity.cs index 1cdd3bd1..a88457e7 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Entities/PostEntity.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Entities/PostEntity.cs @@ -10,7 +10,7 @@ namespace Yi.Framework.Rbac.Domain.Entities /// 岗位表 /// [SugarTable("Post")] - public partial class PostEntity : Entity, ISoftDelete, IAuditedObject, IOrderNum, IState + public class PostEntity : Entity, ISoftDelete, IAuditedObject, IOrderNum, IState { /// diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Entities/RoleDeptEntity.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Entities/RoleDeptEntity.cs index 52720653..9cfbe84b 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Entities/RoleDeptEntity.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Entities/RoleDeptEntity.cs @@ -7,7 +7,7 @@ namespace Yi.Framework.Rbac.Domain.Entities; /// 角色部门关系表 /// [SugarTable("RoleDept")] -public partial class RoleDeptEntity : Entity +public class RoleDeptEntity : Entity { /// /// 主键 diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Managers/AccountManager.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Managers/AccountManager.cs index db6d809f..dfe4ba03 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Managers/AccountManager.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Managers/AccountManager.cs @@ -6,15 +6,15 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using Newtonsoft.Json; -using Volo.Abp; +using Volo.Abp.Caching; using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Services; using Volo.Abp.EventBus.Local; using Volo.Abp.Security.Claims; -using Volo.Abp.Users; using Yi.Framework.Core.Helper; using Yi.Framework.Rbac.Domain.Entities; using Yi.Framework.Rbac.Domain.Repositories; +using Yi.Framework.Rbac.Domain.Shared.Caches; using Yi.Framework.Rbac.Domain.Shared.Consts; using Yi.Framework.Rbac.Domain.Shared.Dtos; using Yi.Framework.Rbac.Domain.Shared.Etos; @@ -38,6 +38,7 @@ namespace Yi.Framework.Rbac.Domain.Managers private UserManager _userManager; private ISqlSugarRepository _roleRepository; private RefreshJwtOptions _refreshJwtOptions; + public AccountManager(IUserRepository repository , IHttpContextAccessor httpContextAccessor , IOptions jwtOptions @@ -87,9 +88,9 @@ namespace Yi.Framework.Rbac.Domain.Managers loginEto.UserId = userInfo.User.Id; await _localEventBus.PublishAsync(loginEto); } + var accessToken = CreateToken(this.UserInfoToClaim(userInfo)); //将用户信息添加到缓存中,需要考虑的是更改了用户、角色、菜单等整个体系都需要将缓存进行刷新,看具体业务进行选择 - var accessToken = CreateToken(this.UserInfoToClaim(userInfo)); return accessToken; } @@ -175,11 +176,12 @@ namespace Yi.Framework.Rbac.Domain.Managers { userAction.Invoke(user); } - if (user == null) + //这里为了兼容解决数据库开启了大小写不敏感问题,还要将用户名进行二次效验 + if (user != null&&user.UserName==userName) { - return false; + return true; } - return true; + return false; } /// diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Yi.Framework.Rbac.Domain.csproj b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Yi.Framework.Rbac.Domain.csproj index 124133c1..3617a7e8 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Yi.Framework.Rbac.Domain.csproj +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Yi.Framework.Rbac.Domain.csproj @@ -21,6 +21,7 @@ + diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/YiFrameworkRbacDomainModule.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/YiFrameworkRbacDomainModule.cs index 7d185398..a5568c1e 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/YiFrameworkRbacDomainModule.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/YiFrameworkRbacDomainModule.cs @@ -3,6 +3,7 @@ using Volo.Abp.AspNetCore.SignalR; using Volo.Abp.Caching; using Volo.Abp.Domain; using Volo.Abp.Modularity; +using Yi.Framework.Caching.FreeRedis; using Yi.Framework.Mapster; using Yi.Framework.Rbac.Domain.Authorization; using Yi.Framework.Rbac.Domain.Operlog; @@ -13,6 +14,7 @@ namespace Yi.Framework.Rbac.Domain { [DependsOn( typeof(YiFrameworkRbacDomainSharedModule), + typeof(YiFrameworkCachingFreeRedisModule), typeof(AbpAspNetCoreSignalRModule), typeof(AbpDddDomainModule), diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.SqlSugarCore/DataSeeds/MenuDataSeed.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.SqlSugarCore/DataSeeds/MenuDataSeed.cs index 8c19cbcf..002db1be 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.SqlSugarCore/DataSeeds/MenuDataSeed.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.SqlSugarCore/DataSeeds/MenuDataSeed.cs @@ -1125,6 +1125,75 @@ namespace Yi.Framework.Rbac.SqlSugarCore.DataSeeds + //通知公告 + MenuEntity notice = new MenuEntity(_guidGenerator.Create()) + { + + MenuName = "通知公告", + PermissionCode = "system:notice:list", + MenuType = MenuTypeEnum.Menu, + Router = "notice", + IsShow = true, + IsLink = false, + IsCache = true, + Component = "system/notice/index", + MenuIcon = "message", + OrderNum = 93, + ParentId = system.Id, + IsDeleted = false + }; + entities.Add(notice); + + MenuEntity noticeQuery = new MenuEntity(_guidGenerator.Create()) + { + + MenuName = "通知查询", + PermissionCode = "system:notice:query", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = notice.Id, + IsDeleted = false + }; + entities.Add(noticeQuery); + + MenuEntity noticeAdd = new MenuEntity(_guidGenerator.Create()) + { + + MenuName = "通知新增", + PermissionCode = "system:notice:add", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = notice.Id, + IsDeleted = false + }; + entities.Add(noticeAdd); + + MenuEntity noticeEdit = new MenuEntity(_guidGenerator.Create()) + { + + MenuName = "通知修改", + PermissionCode = "system:notice:edit", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = notice.Id, + IsDeleted = false + }; + entities.Add(noticeEdit); + + MenuEntity noticeRemove = new MenuEntity(_guidGenerator.Create()) + { + + MenuName = "通知删除", + PermissionCode = "system:notice:remove", + MenuType = MenuTypeEnum.Component, + OrderNum = 100, + ParentId = notice.Id, + IsDeleted = false + }; + entities.Add(noticeRemove); + + + //日志管理 MenuEntity log = new MenuEntity(_guidGenerator.Create()) { @@ -1135,7 +1204,7 @@ namespace Yi.Framework.Rbac.SqlSugarCore.DataSeeds IsShow = true, IsLink = false, MenuIcon = "log", - OrderNum = 93, + OrderNum = 92, ParentId = system.Id, IsDeleted = false }; diff --git a/Yi.Abp.Net8/src/Yi.Abp.Application/Services/TestService.cs b/Yi.Abp.Net8/src/Yi.Abp.Application/Services/TestService.cs index 7d1dc92e..124b19bb 100644 --- a/Yi.Abp.Net8/src/Yi.Abp.Application/Services/TestService.cs +++ b/Yi.Abp.Net8/src/Yi.Abp.Application/Services/TestService.cs @@ -1,5 +1,6 @@ using Mapster; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.RateLimiting; using Volo.Abp.Application.Services; using Volo.Abp.Uow; using Yi.Framework.Bbs.Application.Contracts.Dtos.Banner; @@ -117,5 +118,19 @@ namespace Yi.Abp.Application.Services var entity = new BannerEntity(); var dto = entity.Adapt(); } + + + /// + /// 速率限制 + /// + /// + // [DisableRateLimiting] + //[EnableRateLimiting("sliding")] + public int GetRateLimiting() + { + RequestNumber++; + return RequestNumber; + } + private static int RequestNumber { get; set; } = 0; } } diff --git a/Yi.Abp.Net8/src/Yi.Abp.SqlSugarCore/Yi.Abp.SqlSugarCore.csproj b/Yi.Abp.Net8/src/Yi.Abp.SqlSugarCore/Yi.Abp.SqlSugarCore.csproj index c948284e..81fe397a 100644 --- a/Yi.Abp.Net8/src/Yi.Abp.SqlSugarCore/Yi.Abp.SqlSugarCore.csproj +++ b/Yi.Abp.Net8/src/Yi.Abp.SqlSugarCore/Yi.Abp.SqlSugarCore.csproj @@ -6,6 +6,7 @@ + diff --git a/Yi.Abp.Net8/src/Yi.Abp.SqlSugarCore/YiAbpSqlSugarCoreModule.cs b/Yi.Abp.Net8/src/Yi.Abp.SqlSugarCore/YiAbpSqlSugarCoreModule.cs index 004f7512..6cfd4b59 100644 --- a/Yi.Abp.Net8/src/Yi.Abp.SqlSugarCore/YiAbpSqlSugarCoreModule.cs +++ b/Yi.Abp.Net8/src/Yi.Abp.SqlSugarCore/YiAbpSqlSugarCoreModule.cs @@ -4,6 +4,7 @@ using Yi.Abp.Domain; using Yi.Abp.SqlSugarCore; using Yi.Framework.AuditLogging.SqlSugarCore; using Yi.Framework.Bbs.SqlSugarCore; +using Yi.Framework.CodeGen.SqlSugarCore; using Yi.Framework.Mapster; using Yi.Framework.Rbac.SqlSugarCore; using Yi.Framework.SqlSugarCore; @@ -17,6 +18,7 @@ namespace Yi.Abp.SqlsugarCore typeof(YiFrameworkRbacSqlSugarCoreModule), typeof(YiFrameworkBbsSqlSugarCoreModule), + typeof(YiFrameworkCodeGenSqlSugarCoreModule), typeof(YiFrameworkAuditLoggingSqlSugarCoreModule), typeof(YiFrameworkTenantManagementSqlSugarCoreModule), diff --git a/Yi.Abp.Net8/src/Yi.Abp.SqlSugarCore/YiDbContext.cs b/Yi.Abp.Net8/src/Yi.Abp.SqlSugarCore/YiDbContext.cs index 0e8404b5..28fd4436 100644 --- a/Yi.Abp.Net8/src/Yi.Abp.SqlSugarCore/YiDbContext.cs +++ b/Yi.Abp.Net8/src/Yi.Abp.SqlSugarCore/YiDbContext.cs @@ -1,6 +1,8 @@ -using SqlSugar; +using Microsoft.Extensions.Logging; +using SqlSugar; using Volo.Abp.DependencyInjection; using Yi.Framework.Rbac.SqlSugarCore; +using Yi.Framework.SqlSugarCore; namespace Yi.Abp.SqlSugarCore { diff --git a/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs b/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs index 65b0d18c..5c01c453 100644 --- a/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs +++ b/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs @@ -1,6 +1,9 @@ -using System.Text; +using System.Globalization; +using System.Text; +using System.Threading.RateLimiting; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Cors; +using Microsoft.AspNetCore.RateLimiting; using Microsoft.IdentityModel.Tokens; using Microsoft.OpenApi.Models; using Newtonsoft.Json.Converters; @@ -84,10 +87,12 @@ namespace Yi.Abp.Web }); //设置缓存不要过期,默认滑动20分钟 - Configure(cacheOptions => - { - cacheOptions.GlobalCacheEntryOptions.SlidingExpiration =null; - }); + Configure(cacheOptions => + { + cacheOptions.GlobalCacheEntryOptions.SlidingExpiration = null; + //缓存key前缀 + cacheOptions.KeyPrefix = "Yi:"; + }); Configure(options => @@ -133,24 +138,62 @@ namespace Yi.Abp.Web //options.TenantResolvers.RemoveAll(x => x.Name == CookieTenantResolveContributor.ContributorName); }); + + //速率限制 + //每60秒限制100个请求,滑块添加,分6段 + service.AddRateLimiter(_ => + { + _.RejectionStatusCode = StatusCodes.Status429TooManyRequests; + _.OnRejected = (context, _) => + { + if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter)) + { + context.HttpContext.Response.Headers.RetryAfter = + ((int)retryAfter.TotalSeconds).ToString(NumberFormatInfo.InvariantInfo); + } + 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 => + { + var userAgent = httpContext.Request.Headers.UserAgent.ToString(); + + return RateLimitPartition.GetSlidingWindowLimiter + (userAgent, _ => + new SlidingWindowRateLimiterOptions + { + PermitLimit = 100, + Window = TimeSpan.FromSeconds(60), + SegmentsPerWindow = 6, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst + }); + })); + }); + + //jwt鉴权 var jwtOptions = configuration.GetSection(nameof(JwtOptions)).Get(); var refreshJwtOptions = configuration.GetSection(nameof(RefreshJwtOptions)).Get(); context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) - .AddJwtBearer(options => - { - options.TokenValidationParameters = new TokenValidationParameters + .AddJwtBearer(options => { - 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 => + 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 => { var accessToken = context.Request.Query["access_token"]; if (!string.IsNullOrEmpty(accessToken)) @@ -159,21 +202,21 @@ namespace Yi.Abp.Web } return Task.CompletedTask; } - }; - }) - .AddJwtBearer(TokenTypeConst.Refresh, options => - { - options.TokenValidationParameters = new TokenValidationParameters + }; + }) + .AddJwtBearer(TokenTypeConst.Refresh, options => { - 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 => + 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 => { var refresh_token = context.Request.Headers["refresh_token"]; if (!string.IsNullOrEmpty(refresh_token)) @@ -189,17 +232,17 @@ namespace Yi.Abp.Web return Task.CompletedTask; } - }; + }; - }) - .AddQQ(options => - { - configuration.GetSection("OAuth:QQ").Bind(options); - }) - .AddGitee(options => - { - configuration.GetSection("OAuth:Gitee").Bind(options); - }); + }) + .AddQQ(options => + { + configuration.GetSection("OAuth:QQ").Bind(options); + }) + .AddGitee(options => + { + configuration.GetSection("OAuth:Gitee").Bind(options); + }); //授权 context.Services.AddAuthorization(); @@ -219,6 +262,9 @@ namespace Yi.Abp.Web //跨域 app.UseCors(DefaultCorsPolicyName); + //速率限制 + app.UseRateLimiter(); + //无感token,先刷新再鉴权 app.UseRefreshToken(); diff --git a/Yi.Abp.Net8/src/Yi.Abp.Web/appsettings.json b/Yi.Abp.Net8/src/Yi.Abp.Web/appsettings.json index b841aa14..05bb666b 100644 --- a/Yi.Abp.Net8/src/Yi.Abp.Web/appsettings.json +++ b/Yi.Abp.Net8/src/Yi.Abp.Web/appsettings.json @@ -23,7 +23,7 @@ "EnabledSqlLog": true, "EnabledDbSeed": true, //SAAS多租户 - "EnabledSaasMultiTenancy":false + "EnabledSaasMultiTenancy": false //读写分离地址 //"ReadUrl": [ // "DataSource=[xxxx]", //Sqlite @@ -32,6 +32,12 @@ //] }, + //redis使用freeesql参数在“FreeSqlOptions的ConnectionStringBuilder中” + "Redis": { + "IsEnabled": false, + "Configuration": "127.0.0.1:6379,password=123,defaultDatabase=13" + }, + //鉴权 "JwtOptions": { "Issuer": "https://ccnetcore.com", @@ -47,6 +53,7 @@ "ExpiresMinuteTime": 172800 }, + //第三方登录 "OAuth": { //QQ diff --git a/Yi.Abp.Net8/src/Yi.Abp.Web/yi-abp-dev.db b/Yi.Abp.Net8/src/Yi.Abp.Web/yi-abp-dev.db deleted file mode 100644 index bb954120..00000000 Binary files a/Yi.Abp.Net8/src/Yi.Abp.Web/yi-abp-dev.db and /dev/null differ diff --git a/Yi.Bbs.Vue3/package-lock.json b/Yi.Bbs.Vue3/package-lock.json index 9c1f9d94..27b62785 100644 --- a/Yi.Bbs.Vue3/package-lock.json +++ b/Yi.Bbs.Vue3/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.0", "dependencies": { "@element-plus/icons-vue": "^2.1.0", + "@lucky-canvas/vue": "^0.1.11", "@microsoft/signalr": "^8.0.0", "axios": "^1.3.4", "dayjs": "^1.11.10", @@ -855,6 +856,51 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, + "node_modules/@lucky-canvas/vue": { + "version": "0.1.11", + "resolved": "https://registry.npmmirror.com/@lucky-canvas/vue/-/vue-0.1.11.tgz", + "integrity": "sha512-5vm0txSKRBtMgrE/HZEvw1joSTx9NTdAkc8tBp/aX0LxyhQtiTVBLsRgdYUK/OiURCL8bo+046BTGnV+Q4JFlg==", + "dependencies": { + "@vue/composition-api": "^1.0.0", + "lucky-canvas": "^1.7.23", + "vue-demi": "^0.7.4" + }, + "peerDependencies": { + "vue": "^2.0.0 || >=3.0.0-rc.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/@lucky-canvas/vue/node_modules/@vue/composition-api": { + "version": "1.7.2", + "resolved": "https://registry.npmmirror.com/@vue/composition-api/-/composition-api-1.7.2.tgz", + "integrity": "sha512-M8jm9J/laYrYT02665HkZ5l2fWTK4dcVg3BsDHm/pfz+MjDYwX+9FUaZyGwEyXEDonQYRCo0H7aLgdklcIELjw==", + "peerDependencies": { + "vue": ">= 2.5 < 2.7" + } + }, + "node_modules/@lucky-canvas/vue/node_modules/vue-demi": { + "version": "0.7.5", + "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.7.5.tgz", + "integrity": "sha512-eFSQSvbQdY7C9ujOzvM6tn7XxwLjn0VQDXQsiYBLBwf28Na+2nTQR4BBBcomhmdP6mmHlBKAwarq6a0BPG87hQ==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-beta.1", + "vue": "^2.6.0 || >=3.0.0-rc.1" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, "node_modules/@microsoft/signalr": { "version": "8.0.0", "resolved": "https://registry.npmmirror.com/@microsoft/signalr/-/signalr-8.0.0.tgz", @@ -2673,6 +2719,11 @@ "node": ">=10" } }, + "node_modules/lucky-canvas": { + "version": "1.7.27", + "resolved": "https://registry.npmmirror.com/lucky-canvas/-/lucky-canvas-1.7.27.tgz", + "integrity": "sha512-Ftz6qD+863bI7xijBmZg3dw3cNEc7odPr70EZQcGA14y3TgTAzH65HPosOCd6kKUlMwhntBaHMx3onoj9MtJRQ==" + }, "node_modules/magic-string": { "version": "0.25.9", "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.25.9.tgz", @@ -4617,6 +4668,30 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, + "@lucky-canvas/vue": { + "version": "0.1.11", + "resolved": "https://registry.npmmirror.com/@lucky-canvas/vue/-/vue-0.1.11.tgz", + "integrity": "sha512-5vm0txSKRBtMgrE/HZEvw1joSTx9NTdAkc8tBp/aX0LxyhQtiTVBLsRgdYUK/OiURCL8bo+046BTGnV+Q4JFlg==", + "requires": { + "@vue/composition-api": "^1.0.0", + "lucky-canvas": "^1.7.23", + "vue-demi": "^0.7.4" + }, + "dependencies": { + "@vue/composition-api": { + "version": "1.7.2", + "resolved": "https://registry.npmmirror.com/@vue/composition-api/-/composition-api-1.7.2.tgz", + "integrity": "sha512-M8jm9J/laYrYT02665HkZ5l2fWTK4dcVg3BsDHm/pfz+MjDYwX+9FUaZyGwEyXEDonQYRCo0H7aLgdklcIELjw==", + "requires": {} + }, + "vue-demi": { + "version": "0.7.5", + "resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.7.5.tgz", + "integrity": "sha512-eFSQSvbQdY7C9ujOzvM6tn7XxwLjn0VQDXQsiYBLBwf28Na+2nTQR4BBBcomhmdP6mmHlBKAwarq6a0BPG87hQ==", + "requires": {} + } + } + }, "@microsoft/signalr": { "version": "8.0.0", "resolved": "https://registry.npmmirror.com/@microsoft/signalr/-/signalr-8.0.0.tgz", @@ -6128,6 +6203,11 @@ "yallist": "^4.0.0" } }, + "lucky-canvas": { + "version": "1.7.27", + "resolved": "https://registry.npmmirror.com/lucky-canvas/-/lucky-canvas-1.7.27.tgz", + "integrity": "sha512-Ftz6qD+863bI7xijBmZg3dw3cNEc7odPr70EZQcGA14y3TgTAzH65HPosOCd6kKUlMwhntBaHMx3onoj9MtJRQ==" + }, "magic-string": { "version": "0.25.9", "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.25.9.tgz", diff --git a/Yi.Bbs.Vue3/package.json b/Yi.Bbs.Vue3/package.json index 9eacef1b..26724971 100644 --- a/Yi.Bbs.Vue3/package.json +++ b/Yi.Bbs.Vue3/package.json @@ -10,6 +10,7 @@ }, "dependencies": { "@element-plus/icons-vue": "^2.1.0", + "@lucky-canvas/vue": "^0.1.11", "@microsoft/signalr": "^8.0.0", "axios": "^1.3.4", "dayjs": "^1.11.10", diff --git a/Yi.Bbs.Vue3/src/App.vue b/Yi.Bbs.Vue3/src/App.vue index 85ca157a..76c23713 100644 --- a/Yi.Bbs.Vue3/src/App.vue +++ b/Yi.Bbs.Vue3/src/App.vue @@ -7,6 +7,7 @@ + \ No newline at end of file diff --git a/Yi.Bbs.Vue3/src/views/signIn/Index.vue b/Yi.Bbs.Vue3/src/views/signIn/Index.vue index 6f7b51bf..80d65a0e 100644 --- a/Yi.Bbs.Vue3/src/views/signIn/Index.vue +++ b/Yi.Bbs.Vue3/src/views/signIn/Index.vue @@ -34,6 +34,7 @@ import { onMounted, ref, reactive, computed, nextTick, watch } from "vue"; import { signIn, signInRecord } from "@/apis/integralApi.js"; import useAuths from "@/hooks/useAuths"; + const { isLogin } = useAuths(); const number=ref(0); const signInData=ref([]); diff --git a/Yi.Bbs.Vue3/yarn.lock b/Yi.Bbs.Vue3/yarn.lock index 0559ec71..02a08f2f 100644 --- a/Yi.Bbs.Vue3/yarn.lock +++ b/Yi.Bbs.Vue3/yarn.lock @@ -286,6 +286,15 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" +"@lucky-canvas/vue@^0.1.11": + "integrity" "sha512-5vm0txSKRBtMgrE/HZEvw1joSTx9NTdAkc8tBp/aX0LxyhQtiTVBLsRgdYUK/OiURCL8bo+046BTGnV+Q4JFlg==" + "resolved" "https://registry.npmmirror.com/@lucky-canvas/vue/-/vue-0.1.11.tgz" + "version" "0.1.11" + dependencies: + "@vue/composition-api" "^1.0.0" + "lucky-canvas" "^1.7.23" + "vue-demi" "^0.7.4" + "@microsoft/signalr@^8.0.0": "integrity" "sha512-K/wS/VmzRWePCGqGh8MU8OWbS1Zvu7DG7LSJS62fBB8rJUXwwj4axQtqrAAwKGUZHQF6CuteuQR9xMsVpM2JNA==" "resolved" "https://registry.npmmirror.com/@microsoft/signalr/-/signalr-8.0.0.tgz" @@ -475,6 +484,11 @@ "@vue/compiler-dom" "3.2.47" "@vue/shared" "3.2.47" +"@vue/composition-api@^1.0.0", "@vue/composition-api@^1.0.0-beta.1": + "integrity" "sha512-M8jm9J/laYrYT02665HkZ5l2fWTK4dcVg3BsDHm/pfz+MjDYwX+9FUaZyGwEyXEDonQYRCo0H7aLgdklcIELjw==" + "resolved" "https://registry.npmmirror.com/@vue/composition-api/-/composition-api-1.7.2.tgz" + "version" "1.7.2" + "@vue/devtools-api@^6.4.5", "@vue/devtools-api@^6.5.0": "integrity" "sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==" "resolved" "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.5.0.tgz" @@ -1499,6 +1513,11 @@ dependencies: "yallist" "^4.0.0" +"lucky-canvas@^1.7.23": + "integrity" "sha512-Ftz6qD+863bI7xijBmZg3dw3cNEc7odPr70EZQcGA14y3TgTAzH65HPosOCd6kKUlMwhntBaHMx3onoj9MtJRQ==" + "resolved" "https://registry.npmmirror.com/lucky-canvas/-/lucky-canvas-1.7.27.tgz" + "version" "1.7.27" + "magic-string@^0.25.7": "integrity" "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==" "resolved" "https://registry.npmmirror.com/magic-string/-/magic-string-0.25.9.tgz" @@ -2239,6 +2258,11 @@ "resolved" "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.11.tgz" "version" "0.13.11" +"vue-demi@^0.7.4": + "integrity" "sha512-eFSQSvbQdY7C9ujOzvM6tn7XxwLjn0VQDXQsiYBLBwf28Na+2nTQR4BBBcomhmdP6mmHlBKAwarq6a0BPG87hQ==" + "resolved" "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.7.5.tgz" + "version" "0.7.5" + "vue-router@^4.1.6": "integrity" "sha512-DYWYwsG6xNPmLq/FmZn8Ip+qrhFEzA14EI12MsMgVxvHFDYvlr4NXpVF5hrRH1wVcDP8fGi5F4rxuJSl8/r+EQ==" "resolved" "https://registry.npmmirror.com/vue-router/-/vue-router-4.1.6.tgz" @@ -2246,7 +2270,7 @@ dependencies: "@vue/devtools-api" "^6.4.5" -"vue@^2.6.14 || ^3.2.0", "vue@^3.0.0-0 || ^2.6.0", "vue@^3.2.0", "vue@^3.2.23", "vue@^3.2.25", "vue@^3.2.47", "vue@2 || 3", "vue@3.2.47": +"vue@^2.0.0 || >=3.0.0-rc.0", "vue@^2.6.0 || >=3.0.0-rc.1", "vue@^2.6.14 || ^3.2.0", "vue@^3.0.0-0 || ^2.6.0", "vue@^3.2.0", "vue@^3.2.23", "vue@^3.2.25", "vue@^3.2.47", "vue@>= 2.5 < 2.7", "vue@2 || 3", "vue@3.2.47": "integrity" "sha512-60188y/9Dc9WVrAZeUVSDxRQOZ+z+y5nO2ts9jWXSTkMvayiWxCWOWtBQoYjLeccfXkiiPZWAHcV+WTPhkqJHQ==" "resolved" "https://registry.npmmirror.com/vue/-/vue-3.2.47.tgz" "version" "3.2.47" diff --git a/Yi.Doc.Md/01.框架快速开始教程/00.快速上手/00.模块与项目.md b/Yi.Doc.Md/01.框架快速开始教程/00.快速上手/00.模块与项目.md new file mode 100644 index 00000000..7d16b8fa --- /dev/null +++ b/Yi.Doc.Md/01.框架快速开始教程/00.快速上手/00.模块与项目.md @@ -0,0 +1,41 @@ +## 模块与项目 +意框架是一个基于Abp.VNext的框架,完美使用模块化理念进行开发。既然是模块化开发,就有`项目`与`项目`的概念。 + +很多人问到了我,我的代码应该放到哪里,其实是没有分清楚模块与项目,弄清楚这个,再下手撸码,才更有方向。 + +其实不必一堆概念,只需要心中思考一下 + +> 我接下来要开发的业务是否有必要被其他项目依赖使用? + +例如:内置的Rbac模块、Bbs模块,单独具备权限管理和社区论坛的功能,公开给大家复用引用,这就可以当成一个模块 + +`但是`,有时候如果我不认为他有必要复用,就是公司的一个内部系统,想要快速开发并交付,要同时具备权限管理、商城、审批等各种功能,那就直接当一个项目开发即可,不一定需要将各个模块拆的太散 + +> 这个划分的界限,是由项目来决定 + +注意:模块的代码与项目的代码结构几乎没有区别 + +这意味,有一个最好的方式,先将业务全部写在项目中,等稳定之后,在复制抽象到模块中,完全没有问题。 + +### 模块的优缺点 +- 优点:高度抽象复用 +- 缺点:肉眼可见的程序集增加、维护成本更高 + +### 模块 +![Alt text](image.png) + +代码位置放在`module`目录下,单独建立一个自己的模块名称,可使用`脚手架使用`将默认代码生成在这里。 + +### 项目 +![Alt text](image-1.png) + +框架内置一个host项目,代码位置存放在`src`中,直接使用即可,如果想更换命名,可以使用上一节的`脚手架使用`。 + +## 总结 +> 由于很多人询问我这个问题,所以单独写一篇,方便大家理解。 + +先区分模块还是项目,然后代码写到对应的位置即可 + +理论上,按这套规则意味着,只有在自己的`module`、`src`下才需要写代码,其他地方都是内置好了的,通过继承、实现等方式扩展即可 + +当然,你可以不按这套规则出发,目录结构按自己的舒服的方式去设计,当然也是可以的,不过这得花费一些时间了。 diff --git a/Yi.Doc.Md/01.框架快速开始教程/00.快速上手/01.依赖关系.md b/Yi.Doc.Md/01.框架快速开始教程/00.快速上手/01.依赖关系.md new file mode 100644 index 00000000..e69de29b diff --git a/Yi.Doc.Md/01.框架快速开始教程/00.快速上手/image-1.png b/Yi.Doc.Md/01.框架快速开始教程/00.快速上手/image-1.png new file mode 100644 index 00000000..e2d30f8e Binary files /dev/null and b/Yi.Doc.Md/01.框架快速开始教程/00.快速上手/image-1.png differ diff --git a/Yi.Doc.Md/01.框架快速开始教程/00.快速上手/image.png b/Yi.Doc.Md/01.框架快速开始教程/00.快速上手/image.png new file mode 100644 index 00000000..2cc8d284 Binary files /dev/null and b/Yi.Doc.Md/01.框架快速开始教程/00.快速上手/image.png differ diff --git a/Yi.Doc.Md/01.框架快速开始教程/05.脚手架使用.md b/Yi.Doc.Md/01.框架快速开始教程/05.脚手架使用.md new file mode 100644 index 00000000..b99ab511 --- /dev/null +++ b/Yi.Doc.Md/01.框架快速开始教程/05.脚手架使用.md @@ -0,0 +1,34 @@ +## 简介 +上节说到,真正关注的代码其实只用在src中 +![image.png](/prod-api/file/7f52e9a7-6b6d-cc80-64f6-3a10031e9214/true) +当我们要新建一个项目或者模块的时候,并不想取这个`Yi.Abp`的名字,我们可以使用dotnet的脚手架进行模板的生成 + +**环境**:只需要dotnet sdk即可 + +## 步骤 +![image.png](/prod-api/file/2a8d18c4-4899-433d-3553-3a10032e9645/true) +在模板文件目录上,有一个`.template.config`文件夹,就是通过这个进行控制模板的生成及替换 + +进入该目录,使用cmd执行以以下命令: +``` shell +dotnet new install . --force +``` + +![image.png](/prod-api/file/0a92e464-13af-ef93-77b9-3a10032fe20c/true) + +出现 `已安装以下模板` 及代表安装完成 + +>我们只需要安装一次即可,如果模板文件发生变化,我们生成出来的文件也是一样会变化的 + +当模板安装完成,接下来我们可以选择一个自己想要的空白文件夹,输入命令: + +``` shell +dotnet new yi --name=Acme.BookStore +#Acme.BookStore可以替换成你想要生成的名称即可 +``` + +![image.png](/prod-api/file/55536e5a-ef47-1593-3701-3a100333df31/true) + +最后查看目录: +![image.png](/prod-api/file/20286d62-a9d1-6ab0-7fc0-3a1003348554/true) +这个便是我们想要的结果了 \ No newline at end of file diff --git a/Yi.RuoYi.Vue3/src/api/monitor/cache.js b/Yi.RuoYi.Vue3/src/api/monitor/cache.js index cf495d4c..c2c034b5 100644 --- a/Yi.RuoYi.Vue3/src/api/monitor/cache.js +++ b/Yi.RuoYi.Vue3/src/api/monitor/cache.js @@ -35,15 +35,15 @@ export function getCacheValue(cacheName, cacheKey) { // 清理指定名称缓存 export function clearCacheName(cacheName) { return request({ - url: '/monitor/cache/clearCacheName/' + cacheName, + url: '/monitor-cache/key/' + cacheName, method: 'delete' }) } // 清理指定键名缓存 -export function clearCacheKey(cacheKey) { +export function clearCacheKey(cacheName,cacheKey) { return request({ - url: '/monitor/cache/clearCacheKey/' + cacheKey, + url: '/monitor-cache/value/'+cacheName+'/' + cacheKey, method: 'delete' }) } @@ -51,7 +51,7 @@ export function clearCacheKey(cacheKey) { // 清理全部缓存 export function clearCacheAll() { return request({ - url: '/monitor/cache/clearCacheAll', + url: '/monitor-cache/clear', method: 'delete' }) } diff --git a/Yi.RuoYi.Vue3/src/api/system/notice.js b/Yi.RuoYi.Vue3/src/api/system/notice.js index cf4335ae..61e00fd8 100644 --- a/Yi.RuoYi.Vue3/src/api/system/notice.js +++ b/Yi.RuoYi.Vue3/src/api/system/notice.js @@ -3,16 +3,16 @@ import request from '@/utils/request' // 查询公告列表 export function listNotice(query) { return request({ - url: '/system/notice/list', + url: '/notice', method: 'get', params: query }) } // 查询公告详细 -export function getNotice(noticeId) { +export function getNotice(id) { return request({ - url: '/system/notice/' + noticeId, + url: `/notice/${id}`, method: 'get' }) } @@ -20,26 +20,41 @@ export function getNotice(noticeId) { // 新增公告 export function addNotice(data) { return request({ - url: '/system/notice', + url: '/notice', method: 'post', data: data }) } // 修改公告 -export function updateNotice(data) { +export function updateNotice(id,data) { return request({ - url: '/system/notice', + url: `/notice/${id}`, method: 'put', data: data }) } // 删除公告 -export function delNotice(noticeId) { +export function delNotice(ids) { return request({ - url: '/system/notice', + url: `/notice`, method: 'delete', - params:{id:noticeId} + params:{id:ids} + }) +} + +// 发送在线公告 +export function sendOnlineNotice(id) { + return request({ + url: '/notice/online/'+id, + method: 'post', + }) +} +// 发送离线公告 +export function sendOfflineNotice(id) { + return request({ + url: '/notice/offline/'+id, + method: 'post', }) } \ No newline at end of file diff --git a/Yi.RuoYi.Vue3/src/layout/components/AppMain.vue b/Yi.RuoYi.Vue3/src/layout/components/AppMain.vue index 5b51fcf3..492b5a54 100644 --- a/Yi.RuoYi.Vue3/src/layout/components/AppMain.vue +++ b/Yi.RuoYi.Vue3/src/layout/components/AppMain.vue @@ -1,7 +1,7 @@