feat: 新增VIP充值接口并支持通过角色代码为用户分配角色

This commit is contained in:
ccnetcore
2025-08-10 11:53:28 +08:00
parent a9c3a1bcec
commit 7038d31c53
8 changed files with 181 additions and 58 deletions

View File

@@ -0,0 +1,43 @@
using System.ComponentModel.DataAnnotations;
namespace Yi.Framework.AiHub.Application.Contracts.Dtos.Recharge;
public class RechargeCreateInput
{
/// <summary>
/// 用户ID
/// </summary>
[Required]
public Guid UserId { get; set; }
/// <summary>
/// 充值金额
/// </summary>
[Required]
[Range(0.01, double.MaxValue, ErrorMessage = "充值金额必须大于0")]
public decimal RechargeAmount { get; set; }
/// <summary>
/// 充值内容
/// </summary>
[Required]
[StringLength(500, ErrorMessage = "充值内容不能超过500个字符")]
public string Content { get; set; } = string.Empty;
/// <summary>
/// 到期时间为空表示永久VIP
/// </summary>
public DateTime? ExpireDateTime { get; set; }
/// <summary>
/// 备注
/// </summary>
[StringLength(1000, ErrorMessage = "备注不能超过1000个字符")]
public string? Remark { get; set; }
/// <summary>
/// 联系方式
/// </summary>
[StringLength(200, ErrorMessage = "联系方式不能超过200个字符")]
public string? ContactInfo { get; set; }
}

View File

@@ -1,41 +1,73 @@
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Application.Services;
using Volo.Abp.Users;
using Yi.Framework.AiHub.Application.Contracts.Dtos.Recharge;
using Yi.Framework.AiHub.Domain.Entities;
using Yi.Framework.AiHub.Domain.Shared.Consts;
using Yi.Framework.Rbac.Application.Contracts.IServices;
using Yi.Framework.Rbac.Domain.Shared.Dtos;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.AiHub.Application.Services;
/// <summary>
/// ai 充值表
/// </summary>
public class RechargeService : ApplicationService
namespace Yi.Framework.AiHub.Application.Services
{
private readonly ISqlSugarRepository<AiRechargeAggregateRoot> _repository;
public RechargeService(ISqlSugarRepository<AiRechargeAggregateRoot> repository)
public class RechargeService : ApplicationService
{
_repository = repository;
}
private readonly ISqlSugarRepository<AiRechargeAggregateRoot> _repository;
private readonly ICurrentUser _currentUser;
private readonly IUserService _userService;
/// <summary>
/// 查询已登录的账户充值记录
/// </summary>
/// <returns></returns>
[Route("recharge/account")]
[Authorize]
public async Task<List<RechargeGetListOutput>> GetListByAccountAsync()
{
var userId = CurrentUser.Id;
var entities = await _repository._DbQueryable.Where(x => x.UserId == userId)
.OrderByDescending(x => x.CreationTime)
.ToListAsync();
var output = entities.Adapt<List<RechargeGetListOutput>>();
return output;
public RechargeService(
ISqlSugarRepository<AiRechargeAggregateRoot> repository,
ICurrentUser currentUser,
IUserService userService)
{
_repository = repository;
_currentUser = currentUser;
_userService = userService;
}
/// <summary>
/// 查询已登录的账户充值记录
/// </summary>
/// <returns></returns>
[Route("recharge/account")]
[Authorize]
public async Task<List<RechargeGetListOutput>> GetListByAccountAsync()
{
var userId = CurrentUser.Id;
var entities = await _repository._DbQueryable.Where(x => x.UserId == userId)
.OrderByDescending(x => x.CreationTime)
.ToListAsync();
var output = entities.Adapt<List<RechargeGetListOutput>>();
return output;
}
/// <summary>
/// 给用户充值VIP
/// </summary>
/// <param name="input">充值输入参数</param>
/// <returns></returns>
[HttpPost("recharge/vip")]
public async Task RechargeVipAsync(RechargeCreateInput input)
{
// 创建充值记录
var rechargeRecord = new AiRechargeAggregateRoot
{
UserId = input.UserId,
RechargeAmount = input.RechargeAmount,
Content = input.Content,
ExpireDateTime = input.ExpireDateTime,
Remark = input.Remark,
ContactInfo = input.ContactInfo
};
// 保存充值记录到数据库
await _repository.InsertAsync(rechargeRecord);
// 使用UserService给用户添加VIP角色
await _userService.AddUserRoleByRoleCodeAsync(input.UserId,
new List<string>() { AiHubConst.VipRole, "default" });
}
}
}

View File

@@ -32,19 +32,40 @@ public class AiRechargeManager : DomainService
// 获取当前时间
var currentTime = DateTime.Now;
// 查找过期的充值记录
var expiredRecharges = await _rechargeRepository._DbQueryable
.Where(x => x.ExpireDateTime.HasValue && x.ExpireDateTime.Value < currentTime)
// 查找所有充值记录,按用户分组
var allRecharges = await _rechargeRepository._DbQueryable
.ToListAsync();
if (!expiredRecharges.Any())
if (!allRecharges.Any())
{
_logger.LogInformation("没有找到任何充值记录");
return;
}
// 按用户分组,找出真正过期的用户
var expiredUserIds = allRecharges
.GroupBy(x => x.UserId)
.Where(group =>
{
// 如果用户有任何一个过期时间为空的记录说明是永久VIP不过期
if (group.Any(x => !x.ExpireDateTime.HasValue))
return false;
// 找到用户最大的过期时间
var maxExpireTime = group.Max(x => x.ExpireDateTime);
// 如果最大过期时间小于当前时间,说明用户已过期
return maxExpireTime.HasValue && maxExpireTime.Value < currentTime;
})
.Select(group => group.Key)
.ToList();
if (!expiredUserIds.Any())
{
_logger.LogInformation("没有找到过期的VIP用户");
return;
}
// 获取过期用户的ID列表
var expiredUserIds = expiredRecharges.Select(x => x.UserId).Distinct().ToList();
_logger.LogInformation($"找到 {expiredUserIds.Count} 个过期的VIP用户");
// 获取YiXinAi-Vip角色ID

View File

@@ -8,5 +8,12 @@ namespace Yi.Framework.Rbac.Application.Contracts.IServices
/// </summary>
public interface IUserService : IYiCrudAppService<UserGetOutputDto, UserGetListOutputDto, Guid, UserGetListInputVo, UserCreateInputVo, UserUpdateInputVo>
{
/// <summary>
/// 通过角色代码给用户添加角色
/// </summary>
/// <param name="userId">用户ID</param>
/// <param name="roleCodes">角色代码</param>
/// <returns></returns>
Task AddUserRoleByRoleCodeAsync(Guid userId, List<string> roleCodes);
}
}

View File

@@ -241,5 +241,29 @@ namespace Yi.Framework.Rbac.Application.Services.System
{
return base.PostImportExcelAsync(input);
}
/// <summary>
/// 通过角色代码给用户添加角色
/// </summary>
/// <param name="userId">用户ID</param>
/// <param name="roleCodes"></param>
/// <returns></returns>
public async Task AddUserRoleByRoleCodeAsync(Guid userId, List<string> roleCodes)
{
// 根据角色代码查找角色ID
var roleRepository = LazyServiceProvider.LazyGetRequiredService<ISqlSugarRepository<RoleAggregateRoot>>();
var roleIds = await roleRepository._DbQueryable
.Where(r => roleCodes.Contains(r.RoleCode) && r.State == true)
.Select(r=>r.Id)
.ToListAsync();
if (!roleIds.Any())
{
return;
}
// 使用UserManager给用户设置角色
await _userManager.GiveUserSetRoleAsync(new List<Guid> { userId }, roleIds);
}
}
}

View File

@@ -32,14 +32,15 @@ public class FileManager : DomainService, IFileManager
/// <exception cref="ArgumentException"></exception>
public async Task<List<FileAggregateRoot>> CreateAsync(IEnumerable<IFormFile> files)
{
if (files.Count() == 0)
var formFiles = files as IFormFile[] ?? files.ToArray();
if (!formFiles.Any())
{
throw new ArgumentException("文件上传为空!");
}
//批量插入
List<FileAggregateRoot> entities = new();
foreach (var file in files)
foreach (var file in formFiles)
{
FileAggregateRoot data = new(_guidGenerator.Create(), file.FileName, (decimal)file.Length / 1024);
data.CheckDirectoryOrCreate();

View File

@@ -26,19 +26,20 @@ namespace Yi.Framework.Rbac.Domain.Managers
{
//这个是需要事务的在service中进行工作单元
await _roleMenuRepository.DeleteAsync(u => roleIds.Contains(u.RoleId));
//添加新的关系
List<RoleMenuEntity> roleMenuEntity = new();
//遍历用户
foreach (var roleId in roleIds)
{
//添加新的关系
List<RoleMenuEntity> roleMenuEntity = new();
foreach (var menu in menuIds)
{
roleMenuEntity.Add(new RoleMenuEntity() { RoleId = roleId, MenuId = menu });
}
//一次性批量添加
await _roleMenuRepository.InsertRangeAsync(roleMenuEntity);
}
}
//一次性批量添加
await _roleMenuRepository.InsertRangeAsync(roleMenuEntity);
}
/// <summary>

View File

@@ -46,27 +46,25 @@ namespace Yi.Framework.Rbac.Domain.Managers
/// <param name="userIds"></param>
/// <param name="roleIds"></param>
/// <returns></returns>
public async Task GiveUserSetRoleAsync(List<Guid> userIds, List<Guid> roleIds)
public async Task GiveUserSetRoleAsync(List<Guid> userIds, List<Guid>? roleIds)
{
//删除用户之前所有的用户角色关系(物理删除,没有恢复的必要)
//删除用户之前所有的用户角色关系
await _repositoryUserRole.DeleteAsync(u => userIds.Contains(u.UserId));
if (roleIds is not null)
{
//添加新的关系
List<UserRoleEntity> userRoleEntities = new();
//遍历用户
foreach (var userId in userIds)
{
//添加新的关系
List<UserRoleEntity> userRoleEntities = new();
foreach (var roleId in roleIds)
{
userRoleEntities.Add(new UserRoleEntity() { UserId = userId, RoleId = roleId });
}
//一次性批量添加
await _repositoryUserRole.InsertRangeAsync(userRoleEntities);
}
//一次性批量添加
await _repositoryUserRole.InsertRangeAsync(userRoleEntities);
}
}
@@ -77,25 +75,24 @@ namespace Yi.Framework.Rbac.Domain.Managers
/// <param name="userIds"></param>
/// <param name="postIds"></param>
/// <returns></returns>
public async Task GiveUserSetPostAsync(List<Guid> userIds, List<Guid> postIds)
public async Task GiveUserSetPostAsync(List<Guid> userIds, List<Guid>? postIds)
{
//删除用户之前所有的用户角色关系(物理删除,没有恢复的必要)
await _repositoryUserPost.DeleteAsync(u => userIds.Contains(u.UserId));
if (postIds is not null)
{
//添加新的关系
List<UserPostEntity> userPostEntities = new();
//遍历用户
foreach (var userId in userIds)
{
//添加新的关系
List<UserPostEntity> userPostEntities = new();
foreach (var post in postIds)
{
userPostEntities.Add(new UserPostEntity() { UserId = userId, PostId = post });
}
//一次性批量添加
await _repositoryUserPost.InsertRangeAsync(userPostEntities);
}
//一次性批量添加
await _repositoryUserPost.InsertRangeAsync(userPostEntities);
}
}
@@ -137,10 +134,7 @@ namespace Yi.Framework.Rbac.Domain.Managers
public async Task SetDefautRoleAsync(Guid userId)
{
var role = await _roleRepository.GetFirstAsync(x => x.RoleCode == UserConst.DefaultRoleCode);
if (role is not null)
{
await GiveUserSetRoleAsync(new List<Guid> { userId }, new List<Guid> { role.Id });
}
await GiveUserSetRoleAsync(new List<Guid> { userId }, new List<Guid> { role.Id });
}
private void ValidateUserName(UserAggregateRoot input)