HaniBlindBox/server/HoneyBox/src/HoneyBox.Core/Services/CollectionService.cs
2026-01-04 01:47:02 +08:00

291 lines
9.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
/// <summary>
/// 收藏服务实现
/// </summary>
public class CollectionService : ICollectionService
{
private readonly HoneyBoxDbContext _dbContext;
private readonly ILogger<CollectionService> _logger;
private readonly IRedisService _redisService;
// 奖品统计ID范围 (与PHP保持一致)
private static readonly int[] ShangPrizeIdRange = { 10, 33 };
public CollectionService(
HoneyBoxDbContext dbContext,
ILogger<CollectionService> logger,
IRedisService redisService)
{
_dbContext = dbContext;
_logger = logger;
_redisService = redisService;
}
/// <inheritdoc />
public async Task<bool> 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;
}
/// <inheritdoc />
public async Task<CollectionListResponse> 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<CollectionDto>(),
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<string, (int Stock, int SurplusStock)>();
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<CollectionDto>();
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
};
}
/// <inheritdoc />
public async Task<bool> 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;
}
/// <inheritdoc />
public async Task<bool> 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);
}
/// <inheritdoc />
public async Task<bool> 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;
}
/// <summary>
/// 格式化图片URL
/// </summary>
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;
}
}