From b18aad1f85efcc85d46b1193221ecba9da1fd7de Mon Sep 17 00:00:00 2001 From: chfei Date: Tue, 10 Nov 2026 15:10:20 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BA=91=E5=95=86=E5=93=81=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=88=86=E7=BB=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/UserFavoritesController.cs | 41 ++++- .../Dtos/CreateUserFavoriteGroupRequest.cs | 2 +- .../Dtos/SetUserFavoriteGroupRequest.cs | 15 ++ .../CloudProduct/Dtos/UserFavoriteGroupDto.cs | 2 +- .../Services/UserFavoritesService.cs | 164 ++++++++++++++++-- 5 files changed, 200 insertions(+), 24 deletions(-) create mode 100644 Plugins/CloudProduct/Dtos/SetUserFavoriteGroupRequest.cs diff --git a/Plugins/CloudProduct/Controllers/UserFavoritesController.cs b/Plugins/CloudProduct/Controllers/UserFavoritesController.cs index 248ce32..8c24ace 100644 --- a/Plugins/CloudProduct/Controllers/UserFavoritesController.cs +++ b/Plugins/CloudProduct/Controllers/UserFavoritesController.cs @@ -96,7 +96,7 @@ namespace Store.Modules.CloudProduct.Controllers /// 创建收藏分组:创建成功返回 true,同名分组已存在返回 false。 /// [HttpPost] - public async Task CreateGroup(CreateUserFavoriteGroupRequest request) + public async Task CreateGroup(UserFavoriteGroupRequest request) { if (request == null) { @@ -121,7 +121,7 @@ namespace Store.Modules.CloudProduct.Controllers /// /// 查询用户的收藏分组(含默认分组)及分组下收藏数量。 /// - [HttpGet] + [HttpPost] public async Task> GetGroups(string? userName = null) { var resolved = ResolveUserName(userName); @@ -153,6 +153,41 @@ namespace Store.Modules.CloudProduct.Controllers return await _favoritesService.GetFavoriteStatusAsync(request); } + /// + /// 删除分组 + /// + /// + /// + [HttpPost] + public async Task DelGroup(UserFavoriteGroupRequest 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.DelGroupAsync(request); + } + + /// 将已收藏商品移动到指定分组。 + [HttpPost] + public async Task SetFavoriteGroup(SetUserFavoriteGroupRequest request) + { + if (request == null) + { + throw new AppException("请求参数不能为空", ResultCode.ValidationError); + } + + request.UserName = ResolveUserName(request.UserName); + return await _favoritesService.SetFavoriteGroupAsync(request); + } /// /// 检索用户收藏的商品(标题、销量、价格、类目、分组)。 @@ -274,4 +309,4 @@ namespace Store.Modules.CloudProduct.Controllers : userName.Trim(); } } -} \ No newline at end of file +} diff --git a/Plugins/CloudProduct/Dtos/CreateUserFavoriteGroupRequest.cs b/Plugins/CloudProduct/Dtos/CreateUserFavoriteGroupRequest.cs index c0dc188..7b17617 100644 --- a/Plugins/CloudProduct/Dtos/CreateUserFavoriteGroupRequest.cs +++ b/Plugins/CloudProduct/Dtos/CreateUserFavoriteGroupRequest.cs @@ -3,7 +3,7 @@ namespace Store.Modules.CloudProduct.Dtos /// /// 创建收藏分组请求 /// - public class CreateUserFavoriteGroupRequest + public class UserFavoriteGroupRequest { /// /// 用户名(为空时取当前登录用户) diff --git a/Plugins/CloudProduct/Dtos/SetUserFavoriteGroupRequest.cs b/Plugins/CloudProduct/Dtos/SetUserFavoriteGroupRequest.cs new file mode 100644 index 0000000..87f1929 --- /dev/null +++ b/Plugins/CloudProduct/Dtos/SetUserFavoriteGroupRequest.cs @@ -0,0 +1,15 @@ +namespace Store.Modules.CloudProduct.Dtos +{ + /// 将用户已收藏的商品移动到指定分组。 + public class SetUserFavoriteGroupRequest + { + /// 用户名称,为空时由 API 使用当前登录用户。 + public string UserName { get; set; } = string.Empty; + + /// 商品编号集合。 + public List GoodsIds { get; set; } = new(); + + /// 目标分组 ID。 + public int GroupId { get; set; } + } +} diff --git a/Plugins/CloudProduct/Dtos/UserFavoriteGroupDto.cs b/Plugins/CloudProduct/Dtos/UserFavoriteGroupDto.cs index b45ee6b..ba3c131 100644 --- a/Plugins/CloudProduct/Dtos/UserFavoriteGroupDto.cs +++ b/Plugins/CloudProduct/Dtos/UserFavoriteGroupDto.cs @@ -15,6 +15,6 @@ namespace Store.Modules.CloudProduct.Dtos public string GroupName { get; set; } = string.Empty; /// 该分组下的收藏数量 - public long FavoriteCount { get; set; } + //public long FavoriteCount { get; set; } } } \ No newline at end of file diff --git a/Plugins/CloudProduct/Services/UserFavoritesService.cs b/Plugins/CloudProduct/Services/UserFavoritesService.cs index b65628c..f549d74 100644 --- a/Plugins/CloudProduct/Services/UserFavoritesService.cs +++ b/Plugins/CloudProduct/Services/UserFavoritesService.cs @@ -27,7 +27,7 @@ namespace Store.Modules.CloudProduct.Services Task RemoveFavoritesAsync(RemoveUserFavoritesRequest request); /// 创建收藏分组:创建成功返回 true,同名分组已存在返回 false - Task CreateGroupAsync(CreateUserFavoriteGroupRequest request); + Task CreateGroupAsync(UserFavoriteGroupRequest request); /// 查询用户的收藏分组(含默认分组)及分组下收藏数量 Task> GetGroupsAsync(string userName); @@ -40,6 +40,8 @@ namespace Store.Modules.CloudProduct.Services /// 移除所有用户收藏索引并按数据库数据全量重建,返回重建的文档数 Task RebuildSearchIndexAsync(); + Task DelGroupAsync(UserFavoriteGroupRequest request); + Task SetFavoriteGroupAsync(SetUserFavoriteGroupRequest request); } internal class UserFavoritesService : IUserFavoritesService @@ -298,7 +300,7 @@ namespace Store.Modules.CloudProduct.Services /// /// 创建收藏分组:创建成功返回 true,同一用户同名分组已存在返回 false。 /// - public async Task CreateGroupAsync(CreateUserFavoriteGroupRequest request) + public async Task CreateGroupAsync(UserFavoriteGroupRequest request) { if (request == null) { @@ -356,36 +358,160 @@ namespace Store.Modules.CloudProduct.Services .OrderBy(x => x.Id) .ToListAsync(); - var countList = await _favoriteRepository.Select - .Where(x => x.UserName == userName) - .GroupBy(x => x.GroupId) - .ToListAsync(x => new { GroupId = x.Key, Count = x.Count() }); + //var countList = await _favoriteRepository.Select + // .Where(x => x.UserName == userName) + // .GroupBy(x => x.GroupId) + // .ToListAsync(x => new { GroupId = x.Key, Count = x.Count() }); - var countMap = countList.ToDictionary(x => x.GroupId, x => (long)x.Count); + //var countMap = countList.ToDictionary(x => x.GroupId, x => (long)x.Count); var result = new List(); - if (countMap.TryGetValue(0, out var defaultCount) && defaultCount > 0) - { - result.Add(new UserFavoriteGroupDto - { - Id = 0, - UserName = userName, - GroupName = DefaultGroupName, - FavoriteCount = defaultCount, - }); - } + //if (countMap.TryGetValue(0, out var defaultCount) && defaultCount > 0) + //{ + // result.Add(new UserFavoriteGroupDto + // { + // Id = 0, + // UserName = userName, + // GroupName = DefaultGroupName, + // FavoriteCount = defaultCount, + // }); + //} result.AddRange(groups.Select(x => new UserFavoriteGroupDto { Id = x.Id, UserName = x.UserName, GroupName = x.GroupName, - FavoriteCount = countMap.TryGetValue((int)x.Id, out var count) ? count : 0, + //FavoriteCount = countMap.TryGetValue((int)x.Id, out var count) ? count : 0, })); return result; } + /// + /// 删除用户分组 + /// + /// + /// + /// + public async Task DelGroupAsync(UserFavoriteGroupRequest request) + { + if (request == null) + { + throw new AppException("请求参数不能为空", ResultCode.ValidationError); + } + + var userName = request.UserName?.Trim() ?? string.Empty; + if (string.IsNullOrWhiteSpace(userName)) + { + throw new AppException("用户名不能为空", ResultCode.ValidationError); + } + + var groupName = request.GroupName?.Trim() ?? string.Empty; + if (string.IsNullOrWhiteSpace(groupName)) + { + throw new AppException("分组名不能为空", ResultCode.ValidationError); + } + + if (groupName.Length > 255) + { + throw new AppException("分组名长度不能超过255个字符", ResultCode.ValidationError); + } + //_favoriteRepository.Select.Where(a=>a.Id) + + var existing = await _groupRepository.Select + .Where(x => x.UserName == userName && x.GroupName == groupName) + .FirstAsync(); + + if (existing != null) + { + var favorites = await _favoriteRepository.Select + .Where(x => x.UserName == userName && x.GroupId == existing.Id) + .ToListAsync(); + var goodsIds = favorites.Select(x => x.GoodsId).ToList(); + var goodsMap = goodsIds.Count == 0 + ? new Dictionary() + : (await _goodsRepository.Select.Where(x => goodsIds.Contains(x.GoodsId)).ToListAsync()) + .ToDictionary(x => x.GoodsId); + + await _favoriteRepository.Orm.Update() + .Set(a => a.GroupId, 0) + .Where(a => a.UserName == userName && a.GroupId == existing.Id) + .ExecuteAffrowsAsync(); + + foreach (var favorite in favorites) + { + favorite.GroupId = 0; + } + await _indexService.IndexDocumentsAsync(favorites + .Where(x => goodsMap.ContainsKey(x.GoodsId)) + .Select(x => BuildDocument(x, goodsMap[x.GoodsId], DefaultGroupName))); + } + + var rows = await _groupRepository.DeleteAsync(a => a.UserName == userName && a.GroupName == groupName); + if (rows != 1) + { + return false; + } + return true; + } + + /// 将用户已收藏的商品移动到其指定分组,并同步收藏索引。 + public async Task SetFavoriteGroupAsync(SetUserFavoriteGroupRequest request) + { + if (request == null) + { + throw new AppException("请求参数不能为空", ResultCode.ValidationError); + } + + var userName = request.UserName?.Trim() ?? string.Empty; + var goodsIds = request.GoodsIds?.Where(x => x > 0).Distinct().ToList() ?? new List(); + if (string.IsNullOrWhiteSpace(userName) || goodsIds.Count == 0 || request.GroupId < 0) + { + throw new AppException("用户、商品或分组参数无效", ResultCode.ValidationError); + } + + var mainUser = await _queryService.GetMainUser(userName); + userName = mainUser.UserName; + await using var lease = await _indexLock.AcquireFavoritesAsync(); + + var favorites = await _favoriteRepository.Select + .Where(x => x.UserName == userName && goodsIds.Contains(x.GoodsId)) + .ToListAsync(); + + + if (request.GroupId > 0 && await _groupRepository.Select + .Where(x => x.Id == request.GroupId && x.UserName == userName) + .FirstAsync() == null) + { + throw new AppException("收藏分组不存在或不属于该用户", ResultCode.ValidationError); + } + + var goodsList = await _goodsRepository.Select.Where(x => goodsIds.Contains(x.GoodsId)).ToListAsync(); + if (goodsList.Count != goodsIds.Count) + { + throw new AppException("部分商品不存在", ResultCode.ValidationError); + } + + var changedFavorites = favorites.Where(x => x.GroupId != request.GroupId).ToList(); + if (changedFavorites.Count == 0) + { + return true; + } + + await _favoriteRepository.Orm.Update() + .Set(x => x.GroupId, request.GroupId) + .Where(x => x.UserName == userName && goodsIds.Contains(x.GoodsId)) + .ExecuteAffrowsAsync(); + foreach (var favorite in changedFavorites) + { + favorite.GroupId = request.GroupId; + } + var goodsMap = goodsList.ToDictionary(x => x.GoodsId); + var groupName = await ResolveGroupNameAsync(userName, request.GroupId); + await _indexService.IndexDocumentsAsync(changedFavorites.Select(x => BuildDocument(x, goodsMap[x.GoodsId], groupName))); + return true; + } /// /// 按 GoodsIds 顺序返回每个商品是否已被该用户收藏(商品编号无效的返回 false)。 @@ -640,4 +766,4 @@ namespace Store.Modules.CloudProduct.Services : UserFavoritesSortBy.CreatedTimeDesc; } } -} \ No newline at end of file +}