2025-11-29 18:28:42 +08:00
|
|
|
|
using Dm.util;
|
2025-11-27 19:01:16 +08:00
|
|
|
|
using Microsoft.AspNetCore.Authorization;
|
|
|
|
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
|
|
using SqlSugar;
|
2025-11-29 18:25:43 +08:00
|
|
|
|
using Volo.Abp.Application.Dtos;
|
2025-07-03 22:31:39 +08:00
|
|
|
|
using Volo.Abp.Application.Services;
|
|
|
|
|
|
using Volo.Abp.Users;
|
2025-07-03 22:44:52 +08:00
|
|
|
|
using Yi.Framework.AiHub.Application.Contracts.Dtos.Token;
|
2025-11-27 19:01:16 +08:00
|
|
|
|
using Yi.Framework.AiHub.Domain.Entities;
|
2026-01-01 00:44:02 +08:00
|
|
|
|
using Yi.Framework.AiHub.Domain.Entities.Model;
|
2025-07-03 22:31:39 +08:00
|
|
|
|
using Yi.Framework.AiHub.Domain.Entities.OpenApi;
|
2025-07-05 15:11:56 +08:00
|
|
|
|
using Yi.Framework.AiHub.Domain.Extensions;
|
2026-01-01 00:44:02 +08:00
|
|
|
|
using Yi.Framework.AiHub.Domain.Managers;
|
2025-11-27 19:01:16 +08:00
|
|
|
|
using Yi.Framework.AiHub.Domain.Shared.Consts;
|
2025-11-29 18:25:43 +08:00
|
|
|
|
using Yi.Framework.Ddd.Application.Contracts;
|
2025-07-03 22:31:39 +08:00
|
|
|
|
using Yi.Framework.SqlSugarCore.Abstractions;
|
|
|
|
|
|
|
|
|
|
|
|
namespace Yi.Framework.AiHub.Application.Services;
|
|
|
|
|
|
|
2025-11-27 19:01:16 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Token服务
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[Authorize]
|
2025-07-03 22:31:39 +08:00
|
|
|
|
public class TokenService : ApplicationService
|
|
|
|
|
|
{
|
|
|
|
|
|
private readonly ISqlSugarRepository<TokenAggregateRoot> _tokenRepository;
|
2025-11-27 19:01:16 +08:00
|
|
|
|
private readonly ISqlSugarRepository<UsageStatisticsAggregateRoot> _usageStatisticsRepository;
|
2026-01-01 00:44:02 +08:00
|
|
|
|
private readonly ModelManager _modelManager;
|
2026-01-03 14:39:17 +08:00
|
|
|
|
|
2025-11-27 19:01:16 +08:00
|
|
|
|
public TokenService(
|
|
|
|
|
|
ISqlSugarRepository<TokenAggregateRoot> tokenRepository,
|
2026-01-01 00:44:02 +08:00
|
|
|
|
ISqlSugarRepository<UsageStatisticsAggregateRoot> usageStatisticsRepository,
|
|
|
|
|
|
ModelManager modelManager)
|
2025-07-03 22:31:39 +08:00
|
|
|
|
{
|
|
|
|
|
|
_tokenRepository = tokenRepository;
|
2025-11-27 19:01:16 +08:00
|
|
|
|
_usageStatisticsRepository = usageStatisticsRepository;
|
2026-01-01 00:44:02 +08:00
|
|
|
|
_modelManager = modelManager;
|
2025-07-03 22:31:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-11-27 19:01:16 +08:00
|
|
|
|
/// 获取当前用户的Token列表
|
2025-07-03 22:31:39 +08:00
|
|
|
|
/// </summary>
|
2025-11-27 19:01:16 +08:00
|
|
|
|
[HttpGet("token/list")]
|
2025-11-29 18:25:43 +08:00
|
|
|
|
public async Task<PagedResultDto<TokenGetListOutputDto>> GetListAsync([FromQuery] PagedAllResultRequestDto input)
|
2025-07-03 22:31:39 +08:00
|
|
|
|
{
|
2025-11-29 18:25:43 +08:00
|
|
|
|
RefAsync<int> total = 0;
|
2025-11-27 19:01:16 +08:00
|
|
|
|
var userId = CurrentUser.GetId();
|
|
|
|
|
|
|
|
|
|
|
|
var tokens = await _tokenRepository._DbQueryable
|
|
|
|
|
|
.Where(x => x.UserId == userId)
|
|
|
|
|
|
.OrderByDescending(x => x.CreationTime)
|
2025-11-29 18:25:43 +08:00
|
|
|
|
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
|
2025-11-27 19:01:16 +08:00
|
|
|
|
|
|
|
|
|
|
if (!tokens.Any())
|
2025-07-03 22:44:52 +08:00
|
|
|
|
{
|
2025-11-29 18:25:43 +08:00
|
|
|
|
return new PagedResultDto<TokenGetListOutputDto>();
|
2025-11-27 19:01:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-01 00:44:02 +08:00
|
|
|
|
// 通过ModelManager获取尊享包模型ID列表
|
|
|
|
|
|
var premiumModelIds = await _modelManager.GetPremiumModelIdsAsync();
|
2025-11-27 19:01:16 +08:00
|
|
|
|
|
|
|
|
|
|
// 批量查询所有Token的尊享包已使用额度
|
|
|
|
|
|
var tokenIds = tokens.Select(t => t.Id).ToList();
|
|
|
|
|
|
var usageStats = await _usageStatisticsRepository._DbQueryable
|
|
|
|
|
|
.Where(x => x.UserId == userId && tokenIds.Contains(x.TokenId) && premiumModelIds.Contains(x.ModelId))
|
|
|
|
|
|
.GroupBy(x => x.TokenId)
|
|
|
|
|
|
.Select(g => new
|
|
|
|
|
|
{
|
|
|
|
|
|
TokenId = g.TokenId,
|
|
|
|
|
|
UsedQuota = SqlFunc.AggregateSum(g.TotalTokenCount)
|
|
|
|
|
|
})
|
|
|
|
|
|
.ToListAsync();
|
|
|
|
|
|
|
|
|
|
|
|
var result = tokens.Select(t =>
|
|
|
|
|
|
{
|
|
|
|
|
|
var usedQuota = usageStats.FirstOrDefault(u => u.TokenId == t.Id)?.UsedQuota ?? 0;
|
2025-11-29 18:25:43 +08:00
|
|
|
|
return new TokenGetListOutputDto
|
2025-11-27 19:01:16 +08:00
|
|
|
|
{
|
|
|
|
|
|
Id = t.Id,
|
|
|
|
|
|
Name = t.Name,
|
|
|
|
|
|
ApiKey = t.Token,
|
|
|
|
|
|
ExpireTime = t.ExpireTime,
|
|
|
|
|
|
PremiumQuotaLimit = t.PremiumQuotaLimit,
|
|
|
|
|
|
PremiumUsedQuota = usedQuota,
|
|
|
|
|
|
IsDisabled = t.IsDisabled,
|
|
|
|
|
|
CreationTime = t.CreationTime
|
|
|
|
|
|
};
|
|
|
|
|
|
}).ToList();
|
|
|
|
|
|
|
2025-11-29 18:25:43 +08:00
|
|
|
|
return new PagedResultDto<TokenGetListOutputDto>(total, result);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[HttpGet("token/select-list")]
|
2026-01-03 14:39:17 +08:00
|
|
|
|
public async Task<List<TokenSelectListOutputDto>> GetSelectListAsync([FromQuery] bool? includeDefault = true)
|
2025-11-29 18:25:43 +08:00
|
|
|
|
{
|
|
|
|
|
|
var userId = CurrentUser.GetId();
|
|
|
|
|
|
var tokens = await _tokenRepository._DbQueryable
|
|
|
|
|
|
.Where(x => x.UserId == userId)
|
|
|
|
|
|
.OrderBy(x => x.IsDisabled)
|
|
|
|
|
|
.OrderByDescending(x => x.CreationTime)
|
|
|
|
|
|
.Select(x => new TokenSelectListOutputDto
|
|
|
|
|
|
{
|
|
|
|
|
|
TokenId = x.Id,
|
|
|
|
|
|
Name = x.Name,
|
|
|
|
|
|
IsDisabled = x.IsDisabled
|
|
|
|
|
|
}).ToListAsync();
|
2026-01-03 14:39:17 +08:00
|
|
|
|
|
|
|
|
|
|
if (includeDefault == true)
|
2025-11-29 18:28:42 +08:00
|
|
|
|
{
|
2026-01-03 14:39:17 +08:00
|
|
|
|
tokens.Insert(0, new TokenSelectListOutputDto
|
|
|
|
|
|
{
|
|
|
|
|
|
TokenId = Guid.Empty,
|
|
|
|
|
|
Name = "默认",
|
|
|
|
|
|
IsDisabled = false
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-29 18:25:43 +08:00
|
|
|
|
return tokens;
|
2025-07-03 22:31:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-29 18:25:43 +08:00
|
|
|
|
|
2025-07-03 22:31:39 +08:00
|
|
|
|
/// <summary>
|
2025-11-27 19:01:16 +08:00
|
|
|
|
/// 创建Token
|
2025-07-03 22:31:39 +08:00
|
|
|
|
/// </summary>
|
2025-11-27 19:01:16 +08:00
|
|
|
|
[HttpPost("token")]
|
2025-11-29 18:25:43 +08:00
|
|
|
|
public async Task<TokenGetListOutputDto> CreateAsync([FromBody] TokenCreateInput input)
|
2025-07-03 22:31:39 +08:00
|
|
|
|
{
|
2025-11-27 19:01:16 +08:00
|
|
|
|
var userId = CurrentUser.GetId();
|
|
|
|
|
|
|
|
|
|
|
|
// 检查用户是否为VIP
|
2025-07-05 15:11:56 +08:00
|
|
|
|
if (!CurrentUser.IsAiVip())
|
2025-07-03 22:31:39 +08:00
|
|
|
|
{
|
2025-08-13 17:42:13 +08:00
|
|
|
|
throw new UserFriendlyException("充值成为Vip,畅享第三方token服务");
|
2025-07-03 22:31:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 19:01:16 +08:00
|
|
|
|
// 检查名称是否重复
|
|
|
|
|
|
var exists = await _tokenRepository._DbQueryable
|
|
|
|
|
|
.AnyAsync(x => x.UserId == userId && x.Name == input.Name);
|
|
|
|
|
|
if (exists)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new UserFriendlyException($"名称【{input.Name}】已存在,请使用其他名称");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var token = new TokenAggregateRoot(userId, input.Name)
|
|
|
|
|
|
{
|
|
|
|
|
|
ExpireTime = input.ExpireTime,
|
|
|
|
|
|
PremiumQuotaLimit = input.PremiumQuotaLimit
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
await _tokenRepository.InsertAsync(token);
|
|
|
|
|
|
|
2025-11-29 18:25:43 +08:00
|
|
|
|
return new TokenGetListOutputDto
|
2025-11-27 19:01:16 +08:00
|
|
|
|
{
|
|
|
|
|
|
Id = token.Id,
|
|
|
|
|
|
Name = token.Name,
|
|
|
|
|
|
ApiKey = token.Token,
|
|
|
|
|
|
ExpireTime = token.ExpireTime,
|
|
|
|
|
|
PremiumQuotaLimit = token.PremiumQuotaLimit,
|
|
|
|
|
|
PremiumUsedQuota = 0,
|
|
|
|
|
|
IsDisabled = token.IsDisabled,
|
|
|
|
|
|
CreationTime = token.CreationTime
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 编辑Token
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[HttpPut("token")]
|
|
|
|
|
|
public async Task UpdateAsync([FromBody] TokenUpdateInput input)
|
|
|
|
|
|
{
|
|
|
|
|
|
var userId = CurrentUser.GetId();
|
|
|
|
|
|
|
|
|
|
|
|
var token = await _tokenRepository._DbQueryable
|
|
|
|
|
|
.FirstAsync(x => x.Id == input.Id && x.UserId == userId);
|
|
|
|
|
|
|
|
|
|
|
|
if (token is null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new UserFriendlyException("Token不存在或无权限操作");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查名称是否重复(排除自己)
|
|
|
|
|
|
var exists = await _tokenRepository._DbQueryable
|
|
|
|
|
|
.AnyAsync(x => x.UserId == userId && x.Name == input.Name && x.Id != input.Id);
|
|
|
|
|
|
if (exists)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new UserFriendlyException($"名称【{input.Name}】已存在,请使用其他名称");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
token.Name = input.Name;
|
|
|
|
|
|
token.ExpireTime = input.ExpireTime;
|
|
|
|
|
|
token.PremiumQuotaLimit = input.PremiumQuotaLimit;
|
|
|
|
|
|
|
|
|
|
|
|
await _tokenRepository.UpdateAsync(token);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 删除Token
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[HttpDelete("token/{id}")]
|
|
|
|
|
|
public async Task DeleteAsync(Guid id)
|
|
|
|
|
|
{
|
|
|
|
|
|
var userId = CurrentUser.GetId();
|
|
|
|
|
|
|
|
|
|
|
|
var token = await _tokenRepository._DbQueryable
|
|
|
|
|
|
.FirstAsync(x => x.Id == id && x.UserId == userId);
|
|
|
|
|
|
|
|
|
|
|
|
if (token is null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new UserFriendlyException("Token不存在或无权限操作");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
await _tokenRepository.DeleteAsync(token);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 启用Token
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[HttpPost("token/{id}/enable")]
|
|
|
|
|
|
public async Task EnableAsync(Guid id)
|
|
|
|
|
|
{
|
|
|
|
|
|
var userId = CurrentUser.GetId();
|
|
|
|
|
|
|
|
|
|
|
|
var token = await _tokenRepository._DbQueryable
|
|
|
|
|
|
.FirstAsync(x => x.Id == id && x.UserId == userId);
|
|
|
|
|
|
|
|
|
|
|
|
if (token is null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new UserFriendlyException("Token不存在或无权限操作");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
token.Enable();
|
|
|
|
|
|
await _tokenRepository.UpdateAsync(token);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 禁用Token
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[HttpPost("token/{id}/disable")]
|
|
|
|
|
|
public async Task DisableAsync(Guid id)
|
|
|
|
|
|
{
|
|
|
|
|
|
var userId = CurrentUser.GetId();
|
|
|
|
|
|
|
|
|
|
|
|
var token = await _tokenRepository._DbQueryable
|
|
|
|
|
|
.FirstAsync(x => x.Id == id && x.UserId == userId);
|
|
|
|
|
|
|
|
|
|
|
|
if (token is null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new UserFriendlyException("Token不存在或无权限操作");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
token.Disable();
|
|
|
|
|
|
await _tokenRepository.UpdateAsync(token);
|
2025-07-03 22:31:39 +08:00
|
|
|
|
}
|
2025-11-29 18:25:43 +08:00
|
|
|
|
}
|