From e680ac4cac04c61c5912544ec779ab9be7687589 Mon Sep 17 00:00:00 2001 From: ccnetcore Date: Tue, 6 Jan 2026 22:13:18 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=BC=95=E5=85=A5=E5=9F=BA=E4=BA=8E=20?= =?UTF-8?q?Redis=20=E7=9A=84=E6=AF=8F=E6=97=A5=E4=BB=BB=E5=8A=A1=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将每日任务配置从硬编码字典改为通过 IDistributedCache 从 Redis 获取 新增默认任务配置作为兜底,在缓存不存在时自动写入 统一任务配置读取逻辑,支持后续动态调整任务等级与奖励 不影响现有任务流程与业务规则,仅增强配置灵活性 --- .../Dtos/DailyTask/DailyTaskConfigCacheDto.cs | 43 ++++++++++ .../Services/Activities/DailyTaskService.cs | 78 +++++++++++++------ 2 files changed, 97 insertions(+), 24 deletions(-) create mode 100644 Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/DailyTask/DailyTaskConfigCacheDto.cs diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/DailyTask/DailyTaskConfigCacheDto.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/DailyTask/DailyTaskConfigCacheDto.cs new file mode 100644 index 00000000..a1998211 --- /dev/null +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/DailyTask/DailyTaskConfigCacheDto.cs @@ -0,0 +1,43 @@ +namespace Yi.Framework.AiHub.Application.Contracts.Dtos.DailyTask; + +/// +/// 每日任务配置缓存DTO +/// +public class DailyTaskConfigCacheDto +{ + /// + /// 任务配置列表 + /// + public List Tasks { get; set; } = new(); +} + +/// +/// 每日任务配置项 +/// +public class DailyTaskConfigItem +{ + /// + /// 任务等级 + /// + public int Level { get; set; } + + /// + /// 需要消耗的Token数量 + /// + public long RequiredTokens { get; set; } + + /// + /// 奖励的Token数量 + /// + public long RewardTokens { get; set; } + + /// + /// 任务名称 + /// + public string Name { get; set; } = string.Empty; + + /// + /// 任务描述 + /// + public string Description { get; set; } = string.Empty; +} diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/Activities/DailyTaskService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/Activities/DailyTaskService.cs index 33394c9a..4a66601a 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/Activities/DailyTaskService.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/Activities/DailyTaskService.cs @@ -1,8 +1,10 @@ using Medallion.Threading; using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Logging; using SqlSugar; using Volo.Abp.Application.Services; +using Volo.Abp.Caching; using Volo.Abp.Users; using Yi.Framework.AiHub.Application.Contracts.Dtos.DailyTask; using Yi.Framework.AiHub.Domain.Entities; @@ -25,27 +27,33 @@ public class DailyTaskService : ApplicationService private readonly ISqlSugarRepository _messageRepository; private readonly ISqlSugarRepository _premiumPackageRepository; private readonly ILogger _logger; + private readonly IDistributedCache _taskConfigCache; private IDistributedLockProvider DistributedLock => LazyServiceProvider.LazyGetRequiredService(); private readonly ISqlSugarRepository _aiModelRepository; - // 任务配置 - private readonly Dictionary - _taskConfigs = new() - { - { 1, (10000000, 1000000, "尊享包1000w token任务", "累积使用尊享包 1000w token") }, // 1000w消耗 -> 100w奖励 - { 2, (30000000, 2000000, "尊享包3000w token任务", "累积使用尊享包 3000w token") } // 3000w消耗 -> 200w奖励 - }; + + private const string TaskConfigCacheKey = "AiHub:DailyTaskConfig"; + + // 默认任务配置(当Redis中没有配置时使用) + private static readonly List DefaultTaskConfigs = new() + { + new DailyTaskConfigItem { Level = 1, RequiredTokens = 10000000, RewardTokens = 1000000, Name = "尊享包1000w token任务", Description = "累积使用尊享包 1000w token" }, + new DailyTaskConfigItem { Level = 2, RequiredTokens = 30000000, RewardTokens = 2000000, Name = "尊享包3000w token任务", Description = "累积使用尊享包 3000w token" } + }; public DailyTaskService( ISqlSugarRepository dailyTaskRepository, ISqlSugarRepository messageRepository, ISqlSugarRepository premiumPackageRepository, - ILogger logger, ISqlSugarRepository aiModelRepository) + ILogger logger, + ISqlSugarRepository aiModelRepository, + IDistributedCache taskConfigCache) { _dailyTaskRepository = dailyTaskRepository; _messageRepository = messageRepository; _premiumPackageRepository = premiumPackageRepository; _logger = logger; _aiModelRepository = aiModelRepository; + _taskConfigCache = taskConfigCache; } /// @@ -57,20 +65,23 @@ public class DailyTaskService : ApplicationService var userId = CurrentUser.GetId(); var today = DateTime.Today; - // 1. 统计今日尊享包Token消耗量 + // 1. 获取任务配置 + var taskConfigs = await GetTaskConfigsAsync(); + + // 2. 统计今日尊享包Token消耗量 var todayConsumed = await GetTodayPremiumTokenConsumptionAsync(userId, today); - // 2. 查询今日已领取的任务 + // 3. 查询今日已领取的任务 var claimedTasks = await _dailyTaskRepository._DbQueryable .Where(x => x.UserId == userId && x.TaskDate == today) .Select(x => new { x.TaskLevel, x.IsRewarded }) .ToListAsync(); - // 3. 构建任务列表 + // 4. 构建任务列表 var tasks = new List(); - foreach (var (level, config) in _taskConfigs) + foreach (var config in taskConfigs) { - var claimed = claimedTasks.FirstOrDefault(x => x.TaskLevel == level); + var claimed = claimedTasks.FirstOrDefault(x => x.TaskLevel == config.Level); int status; if (claimed != null && claimed.IsRewarded) @@ -92,7 +103,7 @@ public class DailyTaskService : ApplicationService tasks.Add(new DailyTaskItem { - Level = level, + Level = config.Level, Name = config.Name, Description = config.Description, RequiredTokens = config.RequiredTokens, @@ -120,17 +131,20 @@ public class DailyTaskService : ApplicationService //自旋等待,防抖 await using var handle = await DistributedLock.AcquireLockAsync($"Yi:AiHub:ClaimTaskRewardLock:{userId}"); - - + var today = DateTime.Today; - // 1. 验证任务等级 - if (!_taskConfigs.TryGetValue(input.TaskLevel, out var taskConfig)) + // 1. 获取任务配置 + var taskConfigs = await GetTaskConfigsAsync(); + var taskConfig = taskConfigs.FirstOrDefault(x => x.Level == input.TaskLevel); + + // 2. 验证任务等级 + if (taskConfig == null) { throw new UserFriendlyException($"无效的任务等级: {input.TaskLevel}"); } - // 2. 检查是否已领取 + // 3. 检查是否已领取 var existingRecord = await _dailyTaskRepository._DbQueryable .Where(x => x.UserId == userId && x.TaskDate == today && x.TaskLevel == input.TaskLevel) .FirstAsync(); @@ -140,7 +154,7 @@ public class DailyTaskService : ApplicationService throw new UserFriendlyException("今日该任务奖励已领取,请明天再来!"); } - // 3. 验证今日Token消耗是否达标 + // 4. 验证今日Token消耗是否达标 var todayConsumed = await GetTodayPremiumTokenConsumptionAsync(userId, today); if (todayConsumed < taskConfig.RequiredTokens) { @@ -148,18 +162,17 @@ public class DailyTaskService : ApplicationService $"Token消耗未达标!需要 {taskConfig.RequiredTokens / 10000}w,当前 {todayConsumed / 10000}w"); } - // 4. 创建奖励包(使用 PremiumPackageManager) - + // 5. 创建奖励包 var premiumPackage = new PremiumPackageAggregateRoot(userId, taskConfig.RewardTokens, $"每日任务:{taskConfig.Name}") { - PurchaseAmount = 0, // 奖励不需要付费 + PurchaseAmount = 0, Remark = $"{today:yyyy-MM-dd} 每日任务奖励" }; await _premiumPackageRepository.InsertAsync(premiumPackage); - // 5. 记录领取记录 + // 6. 记录领取记录 var record = new DailyTaskRewardRecordAggregateRoot(userId, input.TaskLevel, today, taskConfig.RewardTokens) { Remark = $"完成任务{input.TaskLevel},名称:{taskConfig.Name},消耗 {todayConsumed / 10000}w token" @@ -197,4 +210,21 @@ public class DailyTaskService : ApplicationService return totalTokens; } + + /// + /// 从Redis获取任务配置,如果不存在则写入默认配置 + /// + private async Task> GetTaskConfigsAsync() + { + var cacheData = await _taskConfigCache.GetOrAddAsync( + TaskConfigCacheKey, + () => Task.FromResult(new DailyTaskConfigCacheDto { Tasks = DefaultTaskConfigs }), + () => new DistributedCacheEntryOptions + { + // 不设置过期时间,永久缓存,需要手动更新 + } + ); + + return cacheData?.Tasks ?? DefaultTaskConfigs; + } } \ No newline at end of file