feat: 合并

This commit is contained in:
橙子
2024-02-26 22:16:16 +08:00
72 changed files with 1521 additions and 221 deletions

View File

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

View File

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

View File

@@ -26,6 +26,9 @@ namespace Yi.Framework.CodeGen.Domain.Shared.Enums
[Display(Name = "DateTime", Description = "DateTime")]
DateTime,
[Display(Name = "Guid", Description = "Guid")]
Guid
}
}

View File

@@ -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
/// </summary>
[Navigate(NavigateType.OneToMany, nameof(FieldEntity.TableId))]
public List<FieldEntity> Fields { get; set; }
[SugarColumn(IsIgnore =true)]
public override ExtraPropertyDictionary ExtraProperties { get; protected set; }
}
}

View File

@@ -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<TemplateEntity> _repository;
public TemplateDataSeed(ISqlSugarRepository<TemplateEntity> repository)
{
_repository = repository;
}
public async Task SeedAsync(DataSeedContext context)
{
if (!await _repository.IsAnyAsync(x => true))
{
await _repository.InsertManyAsync(GetSeedData());
}
}
public List<TemplateEntity> GetSeedData()
{
var entities = new List<TemplateEntity>();
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 /// <summary>\r\n /// 实体\r\n /// </summary>\r\n [SugarTable(\"@Model\")]\r\n public class @ModelEntity : Entity<Guid>\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 /// <summary>\r\n /// 查询参数\r\n /// </summary>\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<Guid>\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<Guid>\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 /// <summary>\r\n /// @Model输入创建对象\r\n /// </summary>\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 /// <summary>\r\n /// @Model服务抽象\r\n /// </summary>\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 /// <summary>\r\n /// @Model服务实现\r\n /// </summary>\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 /// <summary>\r\n /// 多查\r\n /// </summary>\r\n /// <param name=\"input\"></param>\r\n /// <returns></returns>\r\n public override async Task<PagedResultDto<@ModelGetListOutputDto>> GetListAsync(@ModelGetListInput input)\r\n {\r\n RefAsync<int> 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;
}
}
}

View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\framework\Yi.Framework.SqlSugarCore\Yi.Framework.SqlSugarCore.csproj" />
<ProjectReference Include="..\Yi.Framework.CodeGen.Domain\Yi.Framework.CodeGen.Domain.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,10 @@
using Yi.Framework.SqlSugarCore;
namespace Yi.Framework.CodeGen.SqlSugarCore
{
[DependsOn(typeof(YiFrameworkSqlSugarCoreModule))]
public class YiFrameworkCodeGenSqlSugarCoreModule:AbpModule
{
}
}

View File

@@ -0,0 +1,17 @@
using Yi.Framework.Rbac.Domain.Shared.Enums;
namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Notice
{
/// <summary>
/// Notice输入创建对象
/// </summary>
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; }
}
}

View File

@@ -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
{
/// <summary>
/// 查询参数
/// </summary>
public class NoticeGetListInput : PagedAllResultRequestDto
{
public string? Title { get; set; }
public NoticeTypeEnum? Type { get; set; }
}
}

View File

@@ -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<Guid>
{
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; }
}
}

View File

@@ -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<Guid>
{
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; }
}
}

View File

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

View File

@@ -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
{
/// <summary>
/// Notice服务抽象
/// </summary>
public interface INoticeService : IYiCrudAppService<NoticeGetOutputDto, NoticeGetListOutputDto, Guid, NoticeGetListInput, NoticeCreateInput, NoticeUpdateInput>
{
}
}

View File

@@ -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<UserInfoCacheItem, UserInfoCacheKey> _userCache;
public AccountService(IUserRepository userRepository,
ICurrentUser currentUser,
IAccountManager accountManager,
ISqlSugarRepository<MenuEntity> menuRepository,
IDistributedCache<CaptchaPhoneCacheItem, CaptchaPhoneCacheKey> phoneCache,
IDistributedCache<UserInfoCacheItem, UserInfoCacheKey> userCache,
ICaptcha captcha,
IGuidGenerator guidGenerator,
IOptions<RbacOptions> 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<object> 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 };
}
/// <summary>
@@ -249,7 +253,7 @@ namespace Yi.Framework.Rbac.Application.Services
/// <summary>
/// 查询已登录的账户信息
/// 查询已登录的账户信息,已缓存
/// </summary>
/// <returns></returns>
[Route("account")]
@@ -263,16 +267,33 @@ namespace Yi.Framework.Rbac.Application.Services
{
throw new UserFriendlyException("用户未登录");
}
//此处从缓存中获取也行
//var data = _cacheManager.Get<UserRoleMenuDto>($"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<IOptions<JwtOptions>>().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
/// 退出登录
/// </summary>
/// <returns></returns>
public Task<bool> PostLogout()
public async Task<bool> 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;
}
/// <summary>

View File

@@ -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; }
/// <summary>
/// 缓存前缀
/// </summary>
private string CacheKeyPrefix => LazyServiceProvider.LazyGetRequiredService<IOptions<AbpDistributedCacheOptions>>().Value.KeyPrefix;
private bool EnableRedisCache
{
get
{
var redisEnabled = LazyServiceProvider.LazyGetRequiredService<IConfiguration>()["Redis:IsEnabled"];
return redisEnabled.IsNullOrEmpty() || bool.Parse(redisEnabled);
}
}
/// <summary>
/// 使用懒加载防止报错
/// </summary>
private IRedisClient RedisClient => LazyServiceProvider.LazyGetRequiredService<IRedisClient>();
/// <summary>
/// 获取所有key并分组
/// </summary>
/// <returns></returns>
[HttpGet("monitor-cache/name")]
public List<MonitorCacheNameGetListOutputDto> 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<string> GroupedKeys(List<string> keys)
{
HashSet<string> resultSet = new HashSet<string>();
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<string> 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;
}
}
}

View File

@@ -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
{

View File

@@ -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<OnlineService> _logger;
private IHubContext<OnlineUserHub> _hub;
public OnlineService(ILogger<OnlineService> logger, IHubContext<OnlineUserHub> hub)
private IHubContext<OnlineHub> _hub;
public OnlineService(ILogger<OnlineService> logger, IHubContext<OnlineHub> hub)
{
_logger = logger;
_hub = hub;
@@ -26,7 +26,7 @@ namespace Yi.Framework.Rbac.Application.Services
/// <returns></returns>
public Task<PagedResultDto<OnlineUserModel>> GetListAsync([FromQuery] OnlineUserModel online)
{
var data = OnlineUserHub.clientUsers;
var data = OnlineHub.clientUsers;
IEnumerable<OnlineUserModel> 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<OnlineUserModel>() { TotalCount = data.Count, Items = dataWhere.ToList() }) ;
return Task.FromResult(new PagedResultDto<OnlineUserModel>() { TotalCount = data.Count, Items = dataWhere.ToList() });
}
@@ -50,7 +50,7 @@ namespace Yi.Framework.Rbac.Application.Services
[Route("online/{connnectionId}")]
public async Task<bool> 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", "你已被强制退出!");

View File

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

View File

@@ -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<MonitorCacheNameGetListOutputDto> monitorCacheNames => new List<MonitorCacheNameGetListOutputDto>()
{
new MonitorCacheNameGetListOutputDto{ CacheName="Yi:Login",Remark="登录验证码"},
new MonitorCacheNameGetListOutputDto{ CacheName="Yi:User",Remark="用户信息"}
};
private Dictionary<string, string> monitorCacheNamesDic => monitorCacheNames.ToDictionary(x => x.CacheName, x => x.Remark);
//private CSRedisClient _cacheClient;
public MonitorCacheService()
{
//_cacheClient = redisCacheClient.Client;
}
//cacheKey value为空只要name和备注
public List<MonitorCacheNameGetListOutputDto> GetName()
{
//固定的
return monitorCacheNames;
}
[HttpGet("key/{cacaheName}")]
public List<string> GetKey(string cacaheName)
{
//var output = _cacheClient.Keys($"{cacaheName}:*");
return new List<string>() { "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] };
}
}
}

View File

@@ -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
{
/// <summary>
/// Notice服务实现
/// </summary>
public class NoticeService : YiCrudAppService<NoticeEntity, NoticeGetOutputDto, NoticeGetListOutputDto, Guid, NoticeGetListInput, NoticeCreateInput, NoticeUpdateInput>,
INoticeService
{
private ISqlSugarRepository<NoticeEntity, Guid> _repository;
private IHubContext<NoticeHub> _hubContext;
public NoticeService(ISqlSugarRepository<NoticeEntity, Guid> repository, IHubContext<NoticeHub> hubContext) : base(repository)
{
_hubContext = hubContext;
_repository = repository;
}
/// <summary>
/// 多查
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public override async Task<PagedResultDto<NoticeGetListOutputDto>> GetListAsync(NoticeGetListInput input)
{
RefAsync<int> 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<NoticeGetListOutputDto>(total, await MapToGetListOutputDtosAsync(entities));
}
/// <summary>
/// 发送在线消息
/// </summary>
/// <returns></returns>
[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);
}
/// <summary>
/// 发送离线消息
/// </summary>
/// <returns></returns>
[HttpPost("notice/offline/{id}")]
public async Task SendOfflineAsync([FromRoute] Guid id)
{
//先发送一个在线
await SendOnlineAsync(id);
//然后将所有用户和通知id进行保留记录判断是否已读还是未读
//在首次请求返回全部未读的通知给前端即可
}
}
}

View File

@@ -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<LoginLogEntity, LoginLogGetListOutputDto, Guid, LoginLogGetListInputVo>
{

View File

@@ -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
{
/// <summary>
/// OperationLog服务实现
@@ -18,7 +18,7 @@ namespace Yi.Framework.Rbac.Application.Services
private ISqlSugarRepository<OperationLogEntity, Guid> _repository;
public OperationLogService(ISqlSugarRepository<OperationLogEntity, Guid> repository) : base(repository)
{
_repository=repository;
_repository = repository;
}
public override async Task<PagedResultDto<OperationLogGetListOutputDto>> GetListAsync(OperationLogGetListInputVo input)

View File

@@ -0,0 +1,15 @@
using Volo.Abp.AspNetCore.SignalR;
namespace Yi.Framework.Rbac.Application.SignalRHubs
{
[HubRoute("/hub/notice")]
public class NoticeHub : AbpHub
{
/// <summary>
/// 由于发布功能,主要是服务端项客户端主动推送
/// </summary>
public NoticeHub()
{
}
}
}

View File

@@ -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<OnlineUserModel> clientUsers = new();
private readonly static object objLock = new object();
private HttpContext? _httpContext;
private ILogger<OnlineUserHub> _logger => LoggerFactory.CreateLogger<OnlineUserHub>();
public OnlineUserHub(IHttpContextAccessor httpContextAccessor)
private ILogger<OnlineHub> _logger => LoggerFactory.CreateLogger<OnlineHub>();
public OnlineHub(IHttpContextAccessor httpContextAccessor)
{
_httpContext = httpContextAccessor?.HttpContext;
}

View File

@@ -20,7 +20,7 @@ namespace Yi.Framework.Rbac.Domain.Shared.Caches
public override string ToString()
{
return $"Yi:Phone:{Phone}";
return $"Phone:{Phone}";
}
}
}

View File

@@ -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; }
/// <summary>
/// 存储的用户信息
/// </summary>
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}";
}
}
}

View File

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

View File

@@ -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<Guid>, ISoftDelete, IAuditedObject, IOrderNum, IState
{
[SugarColumn(IsPrimaryKey = true)]
public override Guid Id { get; protected set; }
/// <summary>
/// 公告标题
/// </summary>
public string Title { get; set; }
/// <summary>
/// 类型
/// </summary>
public NoticeTypeEnum Type { get; set; }
/// <summary>
/// 内容
/// </summary>
[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; }
}
}

View File

@@ -10,7 +10,7 @@ namespace Yi.Framework.Rbac.Domain.Entities
/// 岗位表
///</summary>
[SugarTable("Post")]
public partial class PostEntity : Entity<Guid>, ISoftDelete, IAuditedObject, IOrderNum, IState
public class PostEntity : Entity<Guid>, ISoftDelete, IAuditedObject, IOrderNum, IState
{
/// <summary>

View File

@@ -7,7 +7,7 @@ namespace Yi.Framework.Rbac.Domain.Entities;
/// 角色部门关系表
///</summary>
[SugarTable("RoleDept")]
public partial class RoleDeptEntity : Entity<Guid>
public class RoleDeptEntity : Entity<Guid>
{
/// <summary>
/// 主键

View File

@@ -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<RoleEntity> _roleRepository;
private RefreshJwtOptions _refreshJwtOptions;
public AccountManager(IUserRepository repository
, IHttpContextAccessor httpContextAccessor
, IOptions<JwtOptions> 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;
}
/// <summary>

View File

@@ -21,6 +21,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\framework\Yi.Framework.Caching.FreeRedis\Yi.Framework.Caching.FreeRedis.csproj" />
<ProjectReference Include="..\..\..\framework\Yi.Framework.SqlSugarCore.Abstractions\Yi.Framework.SqlSugarCore.Abstractions.csproj" />
<ProjectReference Include="..\Yi.Framework.Rbac.Domain.Shared\Yi.Framework.Rbac.Domain.Shared.csproj" />
</ItemGroup>

View File

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

View File

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