Files
2026-11-06 19:25:36 +08:00

277 lines
8.5 KiB
C#

using Asp.Versioning;
using MAX.Framework.Commons;
using MAX.Framework.Dtos;
using MAX.Framework.Security;
using Microsoft.AspNetCore.Mvc;
using Store.Framework.Base;
using Store.Modules.CloudProduct.Dtos;
using Store.Modules.CloudProduct.Services;
namespace Store.Modules.CloudProduct.Controllers
{
/// <summary>
/// 用户收藏商品:收藏/取消收藏(数据库 + 收藏索引同步)、收藏分组、收藏状态查询、收藏检索与索引重建。
/// 请求中的 userName 允许为空,为空时取当前登录用户。
/// </summary>
[ApiVersionNeutral]
[Route("api/CloudGoods/[action]")]
public class UserFavoritesController : AppControllerBase
{
private readonly IUserFavoritesService _favoritesService;
private readonly ICurrentUser _currentUser;
public UserFavoritesController(IUserFavoritesService favoritesService, ICurrentUser currentUser)
{
_favoritesService = favoritesService;
_currentUser = currentUser;
}
/// <summary>
/// 批量收藏商品:写入 user_goods_favorites 并同步写入收藏索引,返回本次成功收藏的商品数量。
/// 商品已收藏时视为修改收藏分组;商品不存在/已删除的编号会被跳过。
/// </summary>
[HttpPost]
public async Task<int> AddFavorite(AddUserFavoriteRequest request)
{
if (request == null)
{
throw new AppException("请求参数不能为空", ResultCode.ValidationError);
}
request.UserName = ResolveUserName(request.UserName);
if (string.IsNullOrWhiteSpace(request.UserName))
{
throw new AppException("用户名不能为空", ResultCode.ValidationError);
}
if (request.GoodsIds == null || request.GoodsIds.Count == 0)
{
throw new AppException("请提供要收藏的商品编号", ResultCode.ValidationError);
}
if (request.GroupId < 0)
{
throw new AppException("收藏分组无效", ResultCode.ValidationError);
}
return await _favoritesService.AddFavoritesAsync(request);
}
/// <summary>更新用户已收藏商品的安全结论。</summary>
[HttpPost]
public async Task<ApiResult> SaveProductSafety(SaveProductSafetyRequest request)
{
await _favoritesService.SaveProductSafetyAsync(request);
return ApiResult.Ok();
}
/// <summary>
/// 批量取消收藏:删除 user_goods_favorites 记录并同步删除收藏索引文档,返回实际取消的条数。
/// </summary>
[HttpPost]
public async Task<int> RemoveFavorites(RemoveUserFavoritesRequest request)
{
if (request == null)
{
throw new AppException("请求参数不能为空", ResultCode.ValidationError);
}
request.UserName = ResolveUserName(request.UserName);
if (string.IsNullOrWhiteSpace(request.UserName))
{
throw new AppException("用户名不能为空", ResultCode.ValidationError);
}
if (request.GoodsIds == null || request.GoodsIds.Count == 0)
{
throw new AppException("请提供要取消收藏的商品编号", ResultCode.ValidationError);
}
return await _favoritesService.RemoveFavoritesAsync(request);
}
/// <summary>
/// 创建收藏分组:创建成功返回 true,同名分组已存在返回 false。
/// </summary>
[HttpPost]
public async Task<bool> CreateGroup(CreateUserFavoriteGroupRequest request)
{
if (request == null)
{
throw new AppException("请求参数不能为空", ResultCode.ValidationError);
}
request.UserName = ResolveUserName(request.UserName);
if (string.IsNullOrWhiteSpace(request.UserName))
{
throw new AppException("用户名不能为空", ResultCode.ValidationError);
}
if (string.IsNullOrWhiteSpace(request.GroupName))
{
throw new AppException("分组名不能为空", ResultCode.ValidationError);
}
return await _favoritesService.CreateGroupAsync(request);
}
/// <summary>
/// 查询用户的收藏分组(含默认分组)及分组下收藏数量。
/// </summary>
[HttpGet]
public async Task<List<UserFavoriteGroupDto>> GetGroups(string? userName = null)
{
var resolved = ResolveUserName(userName);
if (string.IsNullOrWhiteSpace(resolved))
{
throw new AppException("用户名不能为空", ResultCode.ValidationError);
}
return await _favoritesService.GetGroupsAsync(resolved);
}
/// <summary>
/// 按 GoodsIds 顺序返回每个商品是否已被收藏(如 [true,false,...]),前台可按顺序直接渲染。
/// </summary>
[HttpPost]
public async Task<List<bool>> GetFavoriteStatus(UserFavoriteStatusRequest request)
{
if (request == null)
{
throw new AppException("请求参数不能为空", ResultCode.ValidationError);
}
request.UserName = ResolveUserName(request.UserName);
if (string.IsNullOrWhiteSpace(request.UserName))
{
throw new AppException("用户名不能为空", ResultCode.ValidationError);
}
return await _favoritesService.GetFavoriteStatusAsync(request);
}
/// <summary>
/// 检索用户收藏的商品(标题、销量、价格、类目、分组)。
/// </summary>
[HttpPost]
public async Task<PageData<UserFavoriteItem>> SearchFavorites(UserFavoritesSearchRequest request)
{
// 1. 参数基础校验
if (request == null)
{
throw new AppException("请求参数不能为空", ResultCode.ValidationError);
}
request.UserName = ResolveUserName(request.UserName);
if (string.IsNullOrWhiteSpace(request.UserName))
{
throw new AppException("用户名不能为空", ResultCode.ValidationError);
}
// 2. 分页参数校验
if (request.PageIndex < 1)
{
throw new AppException("页码必须大于0", ResultCode.ValidationError);
}
if (request.PageSize < 1 || request.PageSize > 2000)
{
throw new AppException("每页数量必须在1-2000之间", ResultCode.ValidationError);
}
// 3. 价格区间校验
if (request.MinPrice.HasValue && request.MinPrice < 0)
{
throw new AppException("最低价格不能小于0", ResultCode.ValidationError);
}
if (request.MaxPrice.HasValue && request.MaxPrice < 0)
{
throw new AppException("最高价格不能小于0", ResultCode.ValidationError);
}
if (request.MinPrice.HasValue && request.MaxPrice.HasValue && request.MinPrice > request.MaxPrice)
{
throw new AppException("最低价格不能大于最高价格", ResultCode.ValidationError);
}
// 4. 销量区间校验
if (request.MinSoldQuantity.HasValue && request.MinSoldQuantity < 0)
{
throw new AppException("最低销量不能小于0", ResultCode.ValidationError);
}
if (request.MaxSoldQuantity.HasValue && request.MaxSoldQuantity < 0)
{
throw new AppException("最高销量不能小于0", ResultCode.ValidationError);
}
if (request.MinSoldQuantity.HasValue && request.MaxSoldQuantity.HasValue &&
request.MinSoldQuantity > request.MaxSoldQuantity)
{
throw new AppException("最低销量不能大于最高销量", ResultCode.ValidationError);
}
// 5. 类目层级校验
if (request.CatId2.HasValue && !request.CatId1.HasValue)
{
throw new AppException("选择二级类目时必须先选择一级类目", ResultCode.ValidationError);
}
if (request.CatId3.HasValue && !request.CatId2.HasValue)
{
throw new AppException("选择三级类目时必须先选择二级类目", ResultCode.ValidationError);
}
if (request.CatId4.HasValue && !request.CatId3.HasValue)
{
throw new AppException("选择四级类目时必须先选择三级类目", ResultCode.ValidationError);
}
// 6. 分组校验
if (request.GroupId.HasValue && request.GroupId < 0)
{
throw new AppException("收藏分组无效", ResultCode.ValidationError);
}
// 7. 平台校验
if (request.Platform.HasValue && request.Platform < 0)
{
throw new AppException("平台类型无效", ResultCode.ValidationError);
}
var result = await _favoritesService.SearchFavoritesAsync(request);
return new PageData<UserFavoriteItem>
{
List = result.List,
Total = result.Total,
PageSize = request.PageSize,
PageIndex = request.PageIndex,
};
}
/// <summary>
/// 移除所有用户收藏索引并重新创建,随后按 user_goods_favorites 关联 goods 全量回填。
/// </summary>
[HttpPost]
public async Task<long> RebuildSearchIndex()
{
return await _favoritesService.RebuildSearchIndexAsync();
}
/// <summary>
/// 取用户名:显式传入优先,否则取当前登录用户。
/// </summary>
private string ResolveUserName(string? userName)
{
return string.IsNullOrWhiteSpace(userName)
? (_currentUser.UserName ?? string.Empty)
: userName.Trim();
}
}
}