diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Consts/AiHubConst.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Consts/AiHubConst.cs
new file mode 100644
index 00000000..c1f3c416
--- /dev/null
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Consts/AiHubConst.cs
@@ -0,0 +1,6 @@
+namespace Yi.Framework.AiHub.Domain.Shared.Consts;
+
+public class AiHubConst
+{
+ public const string VipRole = "YiXinAi-Vip";
+}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Yi.Framework.AiHub.Domain.Shared.csproj b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Yi.Framework.AiHub.Domain.Shared.csproj
index dac23eef..b9a8850e 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Yi.Framework.AiHub.Domain.Shared.csproj
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Yi.Framework.AiHub.Domain.Shared.csproj
@@ -6,7 +6,6 @@
-
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Extensions/CurrentExtensions.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Extensions/CurrentExtensions.cs
index acab6162..54e152a4 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Extensions/CurrentExtensions.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Extensions/CurrentExtensions.cs
@@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Http;
using Volo.Abp.Users;
+using Yi.Framework.AiHub.Domain.Shared.Consts;
namespace Yi.Framework.AiHub.Domain.Extensions;
@@ -7,6 +8,6 @@ public static class CurrentExtensions
{
public static bool IsAiVip(this ICurrentUser currentUser)
{
- return currentUser.Roles.Contains("YiXinAi-Vip") || currentUser.UserName == "cc";
+ return currentUser.Roles.Contains(AiHubConst.VipRole) || currentUser.UserName == "cc";
}
}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/AiRechargeManager.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/AiRechargeManager.cs
new file mode 100644
index 00000000..ee9413fc
--- /dev/null
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/AiRechargeManager.cs
@@ -0,0 +1,59 @@
+using Microsoft.Extensions.Logging;
+using Volo.Abp.Domain.Services;
+using Yi.Framework.AiHub.Domain.Entities;
+using Yi.Framework.AiHub.Domain.Entities.OpenApi;
+using Yi.Framework.AiHub.Domain.Shared.Consts;
+using Yi.Framework.Rbac.Application.Contracts.IServices;
+using Yi.Framework.SqlSugarCore.Abstractions;
+
+namespace Yi.Framework.AiHub.Domain.Managers;
+
+public class AiRechargeManager : DomainService
+{
+ private readonly ISqlSugarRepository _rechargeRepository;
+ private readonly IRoleService _roleService;
+ private readonly ISqlSugarRepository _tokenRepository;
+ private readonly ILogger _logger;
+
+ public AiRechargeManager(ISqlSugarRepository rechargeRepository,
+ ISqlSugarRepository tokenRepository, ILogger logger,
+ IRoleService roleService)
+ {
+ _rechargeRepository = rechargeRepository;
+ _tokenRepository = tokenRepository;
+ _logger = logger;
+ _roleService = roleService;
+ }
+
+ public async Task RemoveVipRoleByExpireAsync()
+ {
+ _logger.LogInformation("开始执行VIP过期自动卸载任务");
+
+ // 获取当前时间
+ var currentTime = DateTime.Now;
+
+ // 查找过期的充值记录
+ var expiredRecharges = await _rechargeRepository._DbQueryable
+ .Where(x => x.ExpireDateTime.HasValue && x.ExpireDateTime.Value < currentTime)
+ .ToListAsync();
+
+ if (!expiredRecharges.Any())
+ {
+ _logger.LogInformation("没有找到过期的VIP用户");
+ return;
+ }
+
+ // 获取过期用户的ID列表
+ var expiredUserIds = expiredRecharges.Select(x => x.UserId).Distinct().ToList();
+ _logger.LogInformation($"找到 {expiredUserIds.Count} 个过期的VIP用户");
+
+ // 获取YiXinAi-Vip角色ID
+ await _roleService.RemoveUserRoleByRoleCodeAsync(expiredUserIds, AiHubConst.VipRole);
+
+ // 删除过期用户的Token密钥
+ var removedTokenCount = await _tokenRepository.DeleteAsync(x => expiredUserIds.Contains(x.UserId));
+
+ _logger.LogInformation($"成功删除 {removedTokenCount} 个用户的Token密钥");
+ _logger.LogInformation($"VIP过期自动卸载任务执行完成,共处理 {expiredUserIds.Count} 个过期用户");
+ }
+}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/IServices/IRoleService.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/IServices/IRoleService.cs
index ac94d752..c3daa732 100644
--- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/IServices/IRoleService.cs
+++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/IServices/IRoleService.cs
@@ -9,6 +9,12 @@ namespace Yi.Framework.Rbac.Application.Contracts.IServices
///
public interface IRoleService : IYiCrudAppService
{
-
+ ///
+ /// 根据角色名称移除指定用户的角色
+ ///
+ ///
+ ///
+ ///
+ Task RemoveUserRoleByRoleCodeAsync(List userIds, string roleName);
}
}
diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/System/RoleService.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/System/RoleService.cs
index 6188f0ce..643bb786 100644
--- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/System/RoleService.cs
+++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/System/RoleService.cs
@@ -2,9 +2,7 @@ using Mapster;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using Volo.Abp.Application.Dtos;
-using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Entities;
-using Volo.Abp.Uow;
using Yi.Framework.Ddd.Application;
using Yi.Framework.Rbac.Application.Contracts.Dtos.Role;
using Yi.Framework.Rbac.Application.Contracts.Dtos.User;
@@ -98,7 +96,8 @@ namespace Yi.Framework.Rbac.Application.Services.System
{
var entity = await _repository.GetByIdAsync(id);
- var isExist = await _repository._DbQueryable.Where(x => x.Id != entity.Id).AnyAsync(x => x.RoleCode == input.RoleCode || x.RoleName == input.RoleName);
+ var isExist = await _repository._DbQueryable.Where(x => x.Id != entity.Id)
+ .AnyAsync(x => x.RoleCode == input.RoleCode || x.RoleName == input.RoleName);
if (isExist)
{
throw new UserFriendlyException(RoleConst.Exist);
@@ -213,7 +212,18 @@ namespace Yi.Framework.Rbac.Application.Services.System
await _userRoleRepository._Db.Deleteable().Where(x => x.RoleId == input.RoleId)
.Where(x => input.UserIds.Contains(x.UserId))
.ExecuteCommandAsync();
- ;
+ }
+
+ ///
+ /// 根据角色名称移除指定用户的角色
+ ///
+ ///
+ ///
+ ///
+ [RemoteService(isEnabled: false)]
+ public Task RemoveUserRoleByRoleCodeAsync(List userIds, string roleCode)
+ {
+ return _roleManager.RemoveUserRoleByRoleCodeAsync(userIds, roleCode);
}
}
}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Managers/RoleManager.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Managers/RoleManager.cs
index cd5c2c32..3726eb00 100644
--- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Managers/RoleManager.cs
+++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Managers/RoleManager.cs
@@ -8,10 +8,12 @@ namespace Yi.Framework.Rbac.Domain.Managers
{
private ISqlSugarRepository _repository;
private ISqlSugarRepository _roleMenuRepository;
- public RoleManager(ISqlSugarRepository repository, ISqlSugarRepository roleMenuRepository)
+ private ISqlSugarRepository _userRoleRepository;
+ public RoleManager(ISqlSugarRepository repository, ISqlSugarRepository roleMenuRepository, ISqlSugarRepository userRoleRepository)
{
_repository = repository;
_roleMenuRepository = roleMenuRepository;
+ _userRoleRepository = userRoleRepository;
}
///
@@ -38,5 +40,30 @@ namespace Yi.Framework.Rbac.Domain.Managers
}
}
+
+ ///
+ /// 根据角色名称移除指定用户的角色
+ ///
+ /// 用户ID列表
+ /// 角色名称
+ /// 移除的角色关系数量
+ public async Task RemoveUserRoleByRoleCodeAsync(List userIds, string roleName)
+ {
+ // 获取角色ID
+ var role = await _repository._DbQueryable
+ .Where(x => x.RoleCode == roleName)
+ .FirstAsync();
+
+ if (role == null)
+ {
+ return 0;
+ }
+
+ // 移除用户角色关系
+ var removedCount = await _userRoleRepository._Db.Deleteable()
+ .Where(x => userIds.Contains(x.UserId) && x.RoleId == role.Id)
+ .ExecuteCommandAsync();
+ return removedCount;
+ }
}
}
diff --git a/Yi.Abp.Net8/src/Yi.Abp.Web/Jobs/ai-hub/VipExpireJob.cs b/Yi.Abp.Net8/src/Yi.Abp.Web/Jobs/ai-hub/VipExpireJob.cs
new file mode 100644
index 00000000..5576a0d5
--- /dev/null
+++ b/Yi.Abp.Net8/src/Yi.Abp.Web/Jobs/ai-hub/VipExpireJob.cs
@@ -0,0 +1,31 @@
+using Microsoft.Extensions.Logging;
+using SqlSugar;
+using Volo.Abp.BackgroundWorkers.Hangfire;
+using Yi.Framework.AiHub.Domain.Entities;
+using Yi.Framework.AiHub.Domain.Entities.OpenApi;
+using Yi.Framework.AiHub.Domain.Managers;
+using Yi.Framework.Rbac.Domain.Entities;
+using Yi.Framework.SqlSugarCore.Abstractions;
+
+namespace Yi.Abp.Web.Jobs.ai_hub;
+
+///
+/// VIP过期自动卸载任务
+///
+public class VipExpireJob : HangfireBackgroundWorkerBase
+{
+ private readonly AiRechargeManager _aiRechargeManager;
+
+ public VipExpireJob(AiRechargeManager aiRechargeManager)
+ {
+ _aiRechargeManager = aiRechargeManager;
+ RecurringJobId = "VIP过期自动卸载";
+ // 每天凌晨0点执行一次
+ CronExpression = "0 0 0 * * ?";
+ }
+
+ public override async Task DoWorkAsync(CancellationToken cancellationToken = new CancellationToken())
+ {
+ await _aiRechargeManager.RemoveVipRoleByExpireAsync();
+ }
+}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs b/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs
index d87d54db..26c53a67 100644
--- a/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs
+++ b/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs
@@ -77,23 +77,23 @@ namespace Yi.Abp.Web
PreConfigure(options =>
{
options.ConventionalControllers.Create(typeof(YiAbpApplicationModule).Assembly,
- options => options.RemoteServiceName = "default");
+ option => option.RemoteServiceName = "default");
options.ConventionalControllers.Create(typeof(YiFrameworkRbacApplicationModule).Assembly,
- options => options.RemoteServiceName = "rbac");
+ option => option.RemoteServiceName = "rbac");
options.ConventionalControllers.Create(typeof(YiFrameworkBbsApplicationModule).Assembly,
- options => options.RemoteServiceName = "bbs");
+ option => option.RemoteServiceName = "bbs");
options.ConventionalControllers.Create(typeof(YiFrameworkChatHubApplicationModule).Assembly,
- options => options.RemoteServiceName = "chat-hub");
+ option => option.RemoteServiceName = "chat-hub");
options.ConventionalControllers.Create(typeof(YiFrameworkTenantManagementApplicationModule).Assembly,
- options => options.RemoteServiceName = "tenant-management");
+ option => option.RemoteServiceName = "tenant-management");
options.ConventionalControllers.Create(typeof(YiFrameworkCodeGenApplicationModule).Assembly,
- options => options.RemoteServiceName = "code-gen");
+ option => option.RemoteServiceName = "code-gen");
options.ConventionalControllers.Create(typeof(YiFrameworkDigitalCollectiblesApplicationModule).Assembly,
- options => options.RemoteServiceName = "digital-collectibles");
+ option => option.RemoteServiceName = "digital-collectibles");
options.ConventionalControllers.Create(typeof(YiFrameworkStockApplicationModule).Assembly,
- options => options.RemoteServiceName = "ai-stock");
+ option => option.RemoteServiceName = "ai-stock");
options.ConventionalControllers.Create(typeof(YiFrameworkAiHubApplicationModule).Assembly,
- options => options.RemoteServiceName = "ai-hub");
+ option => option.RemoteServiceName = "ai-hub");
//统一前缀
options.ConventionalControllers.ConventionalControllerSettings.ForEach(x => x.RootPath = "api/app");
});
@@ -105,12 +105,12 @@ namespace Yi.Abp.Web
var host = context.Services.GetHostingEnvironment();
var service = context.Services;
- //本地开发环境,禁用作业执行
+ //本地开发环境,可以禁用作业执行
if (host.IsDevelopment())
{
Configure (options =>
{
- options.IsEnabled = false;
+ options.IsEnabled = true;
});
}