using Microsoft.Extensions.Logging; using QYZH.InteractiveMagazine.IService; using QYZH.InteractiveMagazine.Models.Common; using QYZH.InteractiveMagazine.Models.Dto; using QYZH.InteractiveMagazine.Models.Dto.Pet; using QYZH.InteractiveMagazine.Models.Entity; using QYZH.InteractiveMagazine.Repository; using SqlSugar; namespace QYZH.InteractiveMagazine.Service; /// /// 宠物服务实现 /// public class PetService( BaseRepository petRepository, BaseRepository feedingRecordRepository, BaseRepository petEvolutionRepository, ILogger logger) : BaseRepository, IPetService { /// /// 获取用户宠物信息 /// public async Task GetPetByUserIdAsync(long userId) { logger.LogInformation("获取用户宠物信息,UserId: {UserId}", userId); var pet = await petRepository.Queryable() .Where(p => p.UserId == userId) .Select(p => new PetOutput { Id = p.Id, UserId = p.UserId, Name = p.Name, CurrentEvolutionId = p.CurrentEvolutionId, GrowthPoints = p.GrowthPoints, FeedingCount = p.FeedingCount, Type = p.Type, Status = p.Status, CreatedAt = p.CreatedAt }) .FirstAsync(); return pet; } /// /// 为用户创建默认宠物(最低形态、成长值为0、未激活状态) /// public async Task CreateDefaultPetAsync(long userId) { logger.LogInformation("为用户创建默认宠物,UserId: {UserId}", userId); // 检查用户是否已有宠物 var exists = petRepository.Context.Queryable() .Any(p => p.UserId == userId); if (exists) { logger.LogWarning("用户已存在宠物,跳过创建,UserId: {UserId}", userId); return; } var pet = new Pet { UserId = userId, Name = "小精灵", CurrentEvolutionId = 1, GrowthPoints = 0, FeedingCount = 0, Type = "Normal", Status = "Inactive", IsDeleted = false, CreatedBy = userId.ToString(), CreatedAt = DateTime.Now, UpdatedBy = userId.ToString(), UpdatedAt = DateTime.Now }; var result = await petRepository.InsertAsync(pet); if (!result) { logger.LogError("创建默认宠物失败,UserId: {UserId}", userId); throw new Exception("创建宠物失败"); } logger.LogInformation("用户默认宠物创建成功,UserId: {UserId}, PetId: {PetId}", userId, pet.Id); } /// /// 激活宠物(将状态从 Inactive 改为 Active) /// public async Task ActivatePetAsync(long userId) { logger.LogInformation("激活用户宠物,UserId: {UserId}", userId); var pet = await petRepository.Queryable() .Where(p => p.UserId == userId) .FirstAsync(); if (pet == null) { logger.LogWarning("用户宠物不存在,无法激活,UserId: {UserId}", userId); return; } if (pet.Status != "Inactive") { logger.LogInformation("用户宠物已非未激活状态,跳过激活,UserId: {UserId}, Status: {Status}", userId, pet.Status); return; } var result = await petRepository.UpdateAsync( p => new Pet { Status = "Active" }, p => p.UserId == userId); if (!result) { logger.LogError("激活宠物失败,UserId: {UserId}", userId); throw new Exception("激活宠物失败"); } logger.LogInformation("用户宠物激活成功,UserId: {UserId}", userId); } /// /// 喂养宠物(增加成长值 + 记录喂养记录 + 触发进化检查) /// public async Task FeedPetAsync(long userId, FeedPetInput input) { logger.LogInformation("喂养宠物,UserId: {UserId}, PetId: {PetId}, GrowthPoints: {GrowthPoints}", userId, input.PetId, input.GrowthPoints); if (input.PetId <= 0) { throw new BusinessException("宠物Id不能为空", 400); } if (input.GrowthPoints <= 0) { throw new BusinessException("成长值必须大于0", 400); } // 查询宠物 var pet = await petRepository.GetByIdAsync(input.PetId); if (pet == null || pet.IsDeleted) { logger.LogWarning("喂养失败,宠物不存在,PetId: {PetId}", input.PetId); throw new BusinessException("宠物不存在", 404); } // 校验宠物归属 if (pet.UserId != userId) { logger.LogWarning("喂养失败,无权操作该宠物,UserId: {UserId}, PetUserId: {PetUserId}", userId, pet.UserId); throw new BusinessException("无权操作该宠物", 403); } // 校验宠物状态 if (pet.Status != "Active") { logger.LogWarning("喂养失败,宠物未激活,PetId: {PetId}, Status: {Status}", input.PetId, pet.Status); throw new BusinessException("宠物未激活,无法喂养", 400); } var growthBefore = pet.GrowthPoints; var growthAfter = growthBefore + input.GrowthPoints; var hasEvolved = false; string? evolvedStageName = null; // 事务保证一致性 await UseTranAsync(async () => { // 累加成长值和喂养次数 var updateResult = await petRepository.Context.Updateable() .SetColumns(p => p.GrowthPoints == growthAfter) .SetColumns(p => p.FeedingCount == p.FeedingCount + 1) .SetColumns(p => p.UpdatedAt == DateTime.Now) .SetColumns(p => p.UpdatedBy == userId.ToString()) .Where(p => p.Id == input.PetId) .ExecuteCommandAsync(); if (updateResult <= 0) { throw new BusinessException("更新宠物成长值失败", 500); } // 进化检查:查找下一阶段进化形态 var nextEvolution = await petEvolutionRepository.Queryable() .Where(e => e.PreviousEvolutionId == pet.CurrentEvolutionId && e.RequiredGrowth <= growthAfter && e.Status == "Active") .OrderBy(e => e.RequiredGrowth, OrderByType.Desc) .FirstAsync(); if (nextEvolution != null) { // 触发进化 var evolveResult = await petRepository.Context.Updateable() .SetColumns(p => p.CurrentEvolutionId == nextEvolution.Id) .SetColumns(p => p.UpdatedAt == DateTime.Now) .SetColumns(p => p.UpdatedBy == userId.ToString()) .Where(p => p.Id == input.PetId) .ExecuteCommandAsync(); if (evolveResult > 0) { hasEvolved = true; evolvedStageName = nextEvolution.StageName; logger.LogInformation("宠物进化成功,PetId: {PetId}, 新形态: {StageName} (Level {StageLevel})", input.PetId, nextEvolution.StageName, nextEvolution.StageLevel); } } // 写入喂养记录 var record = new PetFeedingRecord { PetId = input.PetId, UserId = userId, PointsUsed = 0, // 预留:后期可扩展为消耗积分喂养 GrowthChange = input.GrowthPoints, GrowthBefore = growthBefore, GrowthAfter = growthAfter, Type = "Normal", Status = "Success", IsDeleted = false, CreatedBy = userId.ToString(), CreatedAt = DateTime.Now, UpdatedBy = userId.ToString(), UpdatedAt = DateTime.Now }; var insertResult = await feedingRecordRepository.InsertAsync(record); if (!insertResult) { throw new BusinessException("写入喂养记录失败", 500); } }); logger.LogInformation("喂养宠物成功,PetId: {PetId}, 成长值: {Before} -> {After}, 进化: {HasEvolved}", input.PetId, growthBefore, growthAfter, hasEvolved); return new FeedPetOutput { PetId = input.PetId, GrowthBefore = growthBefore, GrowthAfter = growthAfter, GrowthChange = input.GrowthPoints, HasEvolved = hasEvolved, EvolvedStageName = evolvedStageName }; } /// /// 获取宠物喂养记录列表 /// public async Task> GetFeedingRecordsAsync(long userId, long petId, PageQueryModel pageQuery) { logger.LogInformation("查询喂养记录,UserId: {UserId}, PetId: {PetId}, PageIndex: {PageIndex}, PageSize: {PageSize}", userId, petId, pageQuery.PageIndex, pageQuery.PageSize); RefAsync totalNumber = 0; var records = await feedingRecordRepository.Queryable() .Where(r => r.UserId == userId && r.PetId == petId) .OrderByDescending(r => r.CreatedAt) .Select(r => new FeedingRecordOutput { Id = r.Id, PetId = r.PetId, UserId = r.UserId, GrowthChange = r.GrowthChange, GrowthBefore = r.GrowthBefore, GrowthAfter = r.GrowthAfter, Type = r.Type, Status = r.Status, CreatedAt = r.CreatedAt }, true) .ToPageListAsync(pageQuery.PageIndex, pageQuery.PageSize, totalNumber); return new PageListModel(records, pageQuery.PageIndex, pageQuery.PageSize, totalNumber); } }