feat: 全站优化

This commit is contained in:
chenchun
2025-12-11 17:33:12 +08:00
parent 67ed1ac1e3
commit f90105ebb4
8 changed files with 8 additions and 945 deletions

View File

@@ -0,0 +1,275 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Logging;
using Volo.Abp.Application.Services;
using Volo.Abp.Users;
using Yi.Framework.AiHub.Application.Contracts.Dtos.CardFlip;
using Yi.Framework.AiHub.Application.Contracts.IServices;
using Yi.Framework.AiHub.Domain.Entities;
using Yi.Framework.AiHub.Domain.Extensions;
using Yi.Framework.AiHub.Domain.Managers;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.AiHub.Application.Services;
/// <summary>
/// 翻牌服务 - 应用层组合服务
/// </summary>
[Authorize]
public class CardFlipService : ApplicationService, ICardFlipService
{
private readonly CardFlipManager _cardFlipManager;
private readonly InviteCodeManager _inviteCodeManager;
private readonly ISqlSugarRepository<PremiumPackageAggregateRoot> _premiumPackageRepository;
private readonly ILogger<CardFlipService> _logger;
public CardFlipService(
CardFlipManager cardFlipManager,
InviteCodeManager inviteCodeManager,
ISqlSugarRepository<PremiumPackageAggregateRoot> premiumPackageRepository,
ILogger<CardFlipService> logger)
{
_cardFlipManager = cardFlipManager;
_inviteCodeManager = inviteCodeManager;
_premiumPackageRepository = premiumPackageRepository;
_logger = logger;
}
/// <summary>
/// 获取本周翻牌任务状态
/// </summary>
public async Task<CardFlipStatusOutput> GetWeeklyTaskStatusAsync()
{
var userId = CurrentUser.GetId();
var weekStart = CardFlipManager.GetWeekStartDate(DateTime.Now);
// 获取本周任务
var task = await _cardFlipManager.GetOrCreateWeeklyTaskAsync(userId, weekStart, createIfNotExists: false);
// 获取邀请码信息
var inviteCode = await _inviteCodeManager.GetUserInviteCodeAsync(userId);
// 统计本周邀请人数
var invitedCount = await _inviteCodeManager.GetWeeklyInvitationCountAsync(userId, weekStart);
//当前用户是否已填写过邀请码
var isFilledInviteCode = await _inviteCodeManager.IsFilledInviteCodeAsync(userId);
var output = new CardFlipStatusOutput
{
TotalFlips = task?.TotalFlips ?? 0,
RemainingFreeFlips = CardFlipManager.MAX_FREE_FLIPS - (task?.FreeFlipsUsed ?? 0),
RemainingBonusFlips = 0, // 已废弃
RemainingInviteFlips = CardFlipManager.MAX_INVITE_FLIPS - (task?.InviteFlipsUsed ?? 0),
CanFlip = _cardFlipManager.CanFlipCard(task),
MyInviteCode = inviteCode?.Code,
InvitedCount = invitedCount,
FlipRecords = BuildFlipRecords(task),
IsFilledInviteCode = isFilledInviteCode
};
// 生成提示信息
output.NextFlipTip = GenerateNextFlipTip(output);
return output;
}
/// <summary>
/// 翻牌
/// </summary>
public async Task<FlipCardOutput> FlipCardAsync(FlipCardInput input)
{
var userId = CurrentUser.GetId();
var weekStart = CardFlipManager.GetWeekStartDate(DateTime.Now);
// 执行翻牌逻辑(由Manager处理验证和翻牌)
var result = await _cardFlipManager.ExecuteFlipAsync(userId, input.FlipNumber, weekStart);
// 如果中奖,发放奖励
if (result.IsWin)
{
await GrantRewardAsync(userId, result.RewardAmount, $"翻牌活动-序号{input.FlipNumber}中奖");
}
// 构建输出
var output = new FlipCardOutput
{
FlipNumber = result.FlipNumber,
IsWin = result.IsWin,
RewardAmount = result.RewardAmount,
RewardDesc = result.RewardDesc,
RemainingFlips = CardFlipManager.TOTAL_MAX_FLIPS - input.FlipNumber
};
return output;
}
/// <summary>
/// 使用邀请码解锁翻牌次数
/// </summary>
public async Task UseInviteCodeAsync(UseInviteCodeInput input)
{
var userId = CurrentUser.GetId();
var weekStart = CardFlipManager.GetWeekStartDate(DateTime.Now);
// 获取本周任务
var task = await _cardFlipManager.GetOrCreateWeeklyTaskAsync(userId, weekStart, createIfNotExists: true);
// 验证是否已经使用了所有邀请解锁次数
if (task.InviteFlipsUsed >= CardFlipManager.MAX_INVITE_FLIPS)
{
throw new UserFriendlyException("本周邀请解锁次数已用完");
}
// 使用邀请码(由Manager处理验证和邀请逻辑)
await _inviteCodeManager.UseInviteCodeAsync(userId, input.InviteCode);
_logger.LogInformation($"用户 {userId} 使用邀请码 {input.InviteCode} 解锁翻牌次数成功");
}
/// <summary>
/// 获取我的邀请码信息
/// </summary>
public async Task<InviteCodeOutput> GetMyInviteCodeAsync()
{
var userId = CurrentUser.GetId();
var weekStart = CardFlipManager.GetWeekStartDate(DateTime.Now);
// 获取我的邀请码
var inviteCode = await _inviteCodeManager.GetUserInviteCodeAsync(userId);
// 统计本周邀请人数
var invitedCount = await _inviteCodeManager.GetWeeklyInvitationCountAsync(userId, weekStart);
// 获取邀请历史
var invitationHistory = await _inviteCodeManager.GetInvitationHistoryAsync(userId, 10);
return new InviteCodeOutput
{
MyInviteCode = inviteCode?.Code,
InvitedCount = invitedCount,
InvitationHistory = invitationHistory.Select(x => new InvitationHistoryItem
{
InvitedUserName = x.InvitedUserName,
InvitationTime = x.InvitationTime,
WeekDescription = GetWeekDescription(x.InvitationTime)
}).ToList()
};
}
/// <summary>
/// 生成我的邀请码
/// </summary>
public async Task<string> GenerateMyInviteCodeAsync()
{
var userId = CurrentUser.GetId();
// 生成邀请码(由Manager处理)
var code = await _inviteCodeManager.GenerateInviteCodeForUserAsync(userId);
return code;
}
#region
/// <summary>
/// 构建翻牌记录列表
/// </summary>
private List<CardFlipRecord> BuildFlipRecords(CardFlipTaskAggregateRoot? task)
{
var records = new List<CardFlipRecord>();
// 获取已翻牌的顺序
var flippedOrder = task != null ? _cardFlipManager.GetFlippedOrder(task) : new List<int>();
var flippedNumbers = new HashSet<int>(flippedOrder);
// 获取中奖记录
var winRecords = task?.WinRecords ?? new Dictionary<int, long>();
// 构建记录按照原始序号1-10排列
for (int i = 1; i <= CardFlipManager.TOTAL_MAX_FLIPS; i++)
{
var record = new CardFlipRecord
{
FlipNumber = i,
IsFlipped = flippedNumbers.Contains(i),
IsWin = false,
FlipTypeDesc = CardFlipManager.GetFlipTypeDesc(i),
// 设置在翻牌顺序中的位置0表示未翻>0表示第几个翻的
FlipOrderIndex = flippedOrder.IndexOf(i) >= 0 ? flippedOrder.IndexOf(i) + 1 : 0
};
// 设置中奖信息
// 判断这张卡是第几次翻的
if (task != null && flippedNumbers.Contains(i))
{
var flipOrderIndex = flippedOrder.IndexOf(i) + 1; // 第几次翻的1-based
// 检查这次翻牌是否中奖
if (winRecords.TryGetValue(flipOrderIndex, out var rewardAmount))
{
record.IsWin = true;
record.RewardAmount = rewardAmount;
}
}
records.Add(record);
}
return records;
}
/// <summary>
/// 生成下次翻牌提示
/// </summary>
private string GenerateNextFlipTip(CardFlipStatusOutput status)
{
if (status.TotalFlips >= CardFlipManager.TOTAL_MAX_FLIPS)
{
return "本周翻牌次数已用完,请下周再来!";
}
if (status.RemainingFreeFlips > 0)
{
return $"本周您还有{status.RemainingFreeFlips}次免费翻牌机会";
}
else if (status.RemainingInviteFlips > 0)
{
if (status.TotalFlips >= 7)
{
return $"本周使用他人邀请码或他人使用你的邀请码,可解锁{status.RemainingInviteFlips}次翻牌,且必中大奖!每次中奖最大额度将翻倍!";
}
return $"本周使用他人邀请码或他人使用你的邀请码,可解锁{status.RemainingInviteFlips}次翻牌,必中大奖!每次中奖最大额度将翻倍!";
}
return "继续加油!";
}
/// <summary>
/// 发放奖励
/// </summary>
private async Task GrantRewardAsync(Guid userId, long amount, string description)
{
var premiumPackage = new PremiumPackageAggregateRoot(userId, amount, description)
{
PurchaseAmount = 0, // 奖励不需要付费
Remark = $"翻牌活动奖励:{amount / 10000}w tokens"
};
await _premiumPackageRepository.InsertAsync(premiumPackage);
_logger.LogInformation($"用户 {userId} 获得翻牌奖励 {amount / 10000}w tokens");
}
/// <summary>
/// 获取周描述
/// </summary>
private string GetWeekDescription(DateTime date)
{
var weekStart = CardFlipManager.GetWeekStartDate(date);
var weekEnd = weekStart.AddDays(6);
return $"{weekStart:MM-dd} 至 {weekEnd:MM-dd}";
}
#endregion
}

View File

@@ -0,0 +1,185 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Logging;
using SqlSugar;
using Volo.Abp.Application.Services;
using Volo.Abp.Users;
using Yi.Framework.AiHub.Application.Contracts.Dtos.DailyTask;
using Yi.Framework.AiHub.Domain.Entities;
using Yi.Framework.AiHub.Domain.Entities.Chat;
using Yi.Framework.AiHub.Domain.Extensions;
using Yi.Framework.AiHub.Domain.Managers;
using Yi.Framework.AiHub.Domain.Shared.Consts;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.AiHub.Application.Services;
/// <summary>
/// 每日任务服务
/// </summary>
[Authorize]
public class DailyTaskService : ApplicationService
{
private readonly ISqlSugarRepository<DailyTaskRewardRecordAggregateRoot> _dailyTaskRepository;
private readonly ISqlSugarRepository<MessageAggregateRoot> _messageRepository;
private readonly ISqlSugarRepository<PremiumPackageAggregateRoot> _premiumPackageRepository;
private readonly ILogger<DailyTaskService> _logger;
// 任务配置
private readonly Dictionary<int, (long RequiredTokens, long RewardTokens, string Name, string Description)>
_taskConfigs = new()
{
{ 1, (10000000, 1000000, "尊享包1000w token任务", "累积使用尊享包 1000w token") }, // 1000w消耗 -> 100w奖励
{ 2, (30000000, 2000000, "尊享包3000w token任务", "累积使用尊享包 3000w token") } // 3000w消耗 -> 200w奖励
};
public DailyTaskService(
ISqlSugarRepository<DailyTaskRewardRecordAggregateRoot> dailyTaskRepository,
ISqlSugarRepository<MessageAggregateRoot> messageRepository,
ISqlSugarRepository<PremiumPackageAggregateRoot> premiumPackageRepository,
ILogger<DailyTaskService> logger)
{
_dailyTaskRepository = dailyTaskRepository;
_messageRepository = messageRepository;
_premiumPackageRepository = premiumPackageRepository;
_logger = logger;
}
/// <summary>
/// 获取今日任务状态
/// </summary>
/// <returns></returns>
public async Task<DailyTaskStatusOutput> GetTodayTaskStatusAsync()
{
var userId = CurrentUser.GetId();
var today = DateTime.Today;
// 1. 统计今日尊享包Token消耗量
var todayConsumed = await GetTodayPremiumTokenConsumptionAsync(userId, today);
// 2. 查询今日已领取的任务
var claimedTasks = await _dailyTaskRepository._DbQueryable
.Where(x => x.UserId == userId && x.TaskDate == today)
.Select(x => new { x.TaskLevel, x.IsRewarded })
.ToListAsync();
// 3. 构建任务列表
var tasks = new List<DailyTaskItem>();
foreach (var (level, config) in _taskConfigs)
{
var claimed = claimedTasks.FirstOrDefault(x => x.TaskLevel == level);
int status;
if (claimed != null && claimed.IsRewarded)
{
status = 2; // 已领取
}
else if (todayConsumed >= config.RequiredTokens)
{
status = 1; // 可领取
}
else
{
status = 0; // 未完成
}
var progress = todayConsumed >= config.RequiredTokens
? 100
: Math.Round((decimal)todayConsumed / config.RequiredTokens * 100, 2);
tasks.Add(new DailyTaskItem
{
Level = level,
Name = config.Name,
Description = config.Description,
RequiredTokens = config.RequiredTokens,
RewardTokens = config.RewardTokens,
Status = status,
Progress = progress
});
}
return new DailyTaskStatusOutput
{
TodayConsumedTokens = todayConsumed,
Tasks = tasks
};
}
/// <summary>
/// 领取任务奖励
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task ClaimTaskRewardAsync(ClaimTaskRewardInput input)
{
var userId = CurrentUser.GetId();
var today = DateTime.Today;
// 1. 验证任务等级
if (!_taskConfigs.TryGetValue(input.TaskLevel, out var taskConfig))
{
throw new UserFriendlyException($"无效的任务等级: {input.TaskLevel}");
}
// 2. 检查是否已领取
var existingRecord = await _dailyTaskRepository._DbQueryable
.Where(x => x.UserId == userId && x.TaskDate == today && x.TaskLevel == input.TaskLevel)
.FirstAsync();
if (existingRecord != null)
{
throw new UserFriendlyException("今日该任务奖励已领取,请明天再来!");
}
// 3. 验证今日Token消耗是否达标
var todayConsumed = await GetTodayPremiumTokenConsumptionAsync(userId, today);
if (todayConsumed < taskConfig.RequiredTokens)
{
throw new UserFriendlyException(
$"Token消耗未达标需要 {taskConfig.RequiredTokens / 10000}w当前 {todayConsumed / 10000}w");
}
// 4. 创建奖励包(使用 PremiumPackageManager
var premiumPackage =
new PremiumPackageAggregateRoot(userId, taskConfig.RewardTokens, $"每日任务:{taskConfig.Name}")
{
PurchaseAmount = 0, // 奖励不需要付费
Remark = $"{today:yyyy-MM-dd} 每日任务奖励"
};
await _premiumPackageRepository.InsertAsync(premiumPackage);
// 5. 记录领取记录
var record = new DailyTaskRewardRecordAggregateRoot(userId, input.TaskLevel, today, taskConfig.RewardTokens)
{
Remark = $"完成任务{input.TaskLevel},名称:{taskConfig.Name},消耗 {todayConsumed / 10000}w token"
};
await _dailyTaskRepository.InsertAsync(record);
_logger.LogInformation(
$"用户 {userId} 领取每日任务 {input.TaskLevel} 奖励成功,获得 {taskConfig.RewardTokens / 10000}w tokens");
}
/// <summary>
/// 获取今日尊享包Token消耗量
/// </summary>
/// <param name="userId">用户ID</param>
/// <param name="today">今日日期</param>
/// <returns>消耗的Token总数</returns>
private async Task<long> GetTodayPremiumTokenConsumptionAsync(Guid userId, DateTime today)
{
var tomorrow = today.AddDays(1);
// 查询今日所有使用尊享包模型的消息role=system 表示消耗)
var totalTokens = await _messageRepository._DbQueryable
.Where(x => x.UserId == userId)
.Where(x => x.Role == "system") // system角色表示实际消耗
.Where(x => PremiumPackageConst.ModeIds.Contains(x.ModelId)) // 尊享包模型
.Where(x => x.CreationTime >= today && x.CreationTime < tomorrow)
.SumAsync(x => x.TokenUsage.TotalTokenCount);
return totalTokens;
}
}