using HoneyBox.Core.Interfaces; using HoneyBox.Model.Data; using HoneyBox.Model.Entities; using HoneyBox.Model.Models; using HoneyBox.Model.Models.Goods; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; namespace HoneyBox.Core.Services; /// /// 收藏服务实现 /// public class CollectionService : ICollectionService { private readonly HoneyBoxDbContext _dbContext; private readonly ILogger _logger; private readonly IRedisService _redisService; // 奖品统计ID范围 (与PHP保持一致) private static readonly int[] ShangPrizeIdRange = { 10, 33 }; public CollectionService( HoneyBoxDbContext dbContext, ILogger logger, IRedisService redisService) { _dbContext = dbContext; _logger = logger; _redisService = redisService; } /// public async Task ToggleCollectionAsync(int userId, int goodsId, int goodsNum) { // 1. 验证商品是否存在 var goods = await _dbContext.Goods .Where(g => g.Id == goodsId) .Select(g => new { g.Id, g.Stock, g.Status, g.Type }) .FirstOrDefaultAsync(); if (goods == null) { throw new InvalidOperationException("盒子不存在"); } if (goods.Status != 1 && goods.Status != 3) { throw new InvalidOperationException("盒子已下架"); } // 2. 检查是否已收藏 var existingCollection = await _dbContext.GoodsCollections .Where(c => c.UserId == userId && c.GoodsId == goodsId && c.Num == goodsNum) .FirstOrDefaultAsync(); bool result; if (existingCollection != null) { // 已收藏,则取消收藏 _dbContext.GoodsCollections.Remove(existingCollection); result = await _dbContext.SaveChangesAsync() > 0; } else { // 未收藏,则添加收藏 var collection = new GoodsCollection { UserId = userId, GoodsId = goodsId, Num = goodsNum, Type = goods.Type, CreatedAt = DateTime.Now }; _dbContext.GoodsCollections.Add(collection); result = await _dbContext.SaveChangesAsync() > 0; } // 3. 清除相关缓存 if (result) { try { await _redisService.DeleteAsync($"goods_detail_{goodsId}_{userId}"); await _redisService.DeleteAsync($"infinite_goodsdetail_{goodsId}_{userId}"); } catch (Exception ex) { _logger.LogWarning(ex, "清除收藏相关缓存失败"); } } return result; } /// public async Task GetCollectionListAsync(int userId, int type, int page, int pageSize) { // 1. 构建查询 var query = _dbContext.GoodsCollections .Where(c => c.UserId == userId); // 按类型过滤 if (type > 0) { query = query.Where(c => c.Type == type); } // 2. 获取总数和分页数据 var totalCount = await query.CountAsync(); var lastPage = pageSize > 0 ? (int)Math.Ceiling((double)totalCount / pageSize) : 1; var collections = await query .OrderByDescending(c => c.Id) .Skip((page - 1) * pageSize) .Take(pageSize) .ToListAsync(); if (!collections.Any()) { return new CollectionListResponse { Data = new List(), LastPage = lastPage }; } // 3. 获取商品信息 var goodsIds = collections.Select(c => c.GoodsId).Distinct().ToList(); var goodsDict = await _dbContext.Goods .Where(g => goodsIds.Contains(g.Id)) .Select(g => new { g.Id, g.Title, g.Price, g.ImgUrl }) .ToDictionaryAsync(g => g.Id); // 4. 获取库存信息 (仅对特定类型的商品) // 类型 1, 3, 5, 6, 10, 11 需要查询库存 var stockTypes = new byte[] { 1, 3, 5, 6, 10, 11 }; var stockCollections = collections .Where(c => stockTypes.Contains(c.Type)) .Select(c => new { c.GoodsId, c.Num }) .Distinct() .ToList(); var stockDict = new Dictionary(); if (stockCollections.Any()) { foreach (var sc in stockCollections) { var stockInfo = await _dbContext.GoodsItems .Where(gi => gi.GoodsId == sc.GoodsId && gi.Num == sc.Num && gi.ShangId >= ShangPrizeIdRange[0] && gi.ShangId <= ShangPrizeIdRange[1]) .GroupBy(gi => 1) .Select(g => new { Stock = g.Sum(x => x.Stock), SurplusStock = g.Sum(x => x.SurplusStock) }) .FirstOrDefaultAsync(); var key = $"{sc.GoodsId}_{sc.Num}"; stockDict[key] = stockInfo != null ? (stockInfo.Stock, stockInfo.SurplusStock) : (0, 0); } } // 5. 构建响应 var result = new List(); foreach (var collection in collections) { var dto = new CollectionDto { Id = collection.Id, GoodsId = collection.GoodsId, Type = collection.Type, Num = collection.Num }; // 填充商品信息 if (goodsDict.TryGetValue(collection.GoodsId, out var goodsInfo)) { dto.GoodsTitle = goodsInfo.Title; dto.GoodsPrice = goodsInfo.Price.ToString("0.##"); dto.ImgUrl = FormatImageUrl(goodsInfo.ImgUrl); } // 填充库存信息 if (stockTypes.Contains(collection.Type)) { var stockKey = $"{collection.GoodsId}_{collection.Num}"; if (stockDict.TryGetValue(stockKey, out var stock)) { dto.Stock = stock.Stock; dto.SurplusStock = stock.SurplusStock; } } result.Add(dto); } return new CollectionListResponse { Data = result, LastPage = lastPage }; } /// public async Task DeleteCollectionAsync(int userId, int collectionId) { var collection = await _dbContext.GoodsCollections .Where(c => c.UserId == userId && c.Id == collectionId) .FirstOrDefaultAsync(); if (collection == null) { throw new InvalidOperationException("请求重复操作"); } _dbContext.GoodsCollections.Remove(collection); return await _dbContext.SaveChangesAsync() > 0; } /// public async Task IsCollectedAsync(int userId, int goodsId, int goodsNum) { if (userId <= 0) { return false; } return await _dbContext.GoodsCollections .AnyAsync(c => c.UserId == userId && c.GoodsId == goodsId && c.Num == goodsNum); } /// public async Task CancelCollectionByGoodsIdAsync(int userId, int goodsId) { // 查找该用户对该商品的所有收藏记录 var collections = await _dbContext.GoodsCollections .Where(c => c.UserId == userId && c.GoodsId == goodsId) .ToListAsync(); if (!collections.Any()) { throw new InvalidOperationException("未找到收藏记录"); } _dbContext.GoodsCollections.RemoveRange(collections); var result = await _dbContext.SaveChangesAsync() > 0; // 清除相关缓存 if (result) { try { await _redisService.DeleteAsync($"goods_detail_{goodsId}_{userId}"); await _redisService.DeleteAsync($"infinite_goodsdetail_{goodsId}_{userId}"); } catch (Exception ex) { _logger.LogWarning(ex, "清除收藏相关缓存失败"); } } return result; } /// /// 格式化图片URL /// private static string FormatImageUrl(string? imgUrl) { if (string.IsNullOrEmpty(imgUrl)) { return string.Empty; } // 如果已经是完整URL,直接返回 if (imgUrl.StartsWith("http://") || imgUrl.StartsWith("https://")) { return imgUrl; } // 否则直接返回 (可以从配置读取基础URL) return imgUrl; } }