From eaf4a9c489282ba85a1c47ff9a484e67703b2190 Mon Sep 17 00:00:00 2001 From: zpc Date: Thu, 5 Feb 2026 23:44:19 +0800 Subject: [PATCH] 321 --- honey_box/common/env.js | 4 +- .../pages/infinite/bonus_house_details.vue | 8 +- honey_box/pages/infinite/reward_records.vue | 20 +- .../Controllers/GoodsTypesController.cs | 24 +- .../Models/Goods/GoodsModels.cs | 41 +- .../Models/Goods/GoodsTypeModels.cs | 4 +- .../Models/Goods/PrizeModels.cs | 13 + .../Services/GoodsService.cs | 455 ++++++++++++++---- 8 files changed, 449 insertions(+), 120 deletions(-) diff --git a/honey_box/common/env.js b/honey_box/common/env.js index 927fcad7..6ee2ac79 100644 --- a/honey_box/common/env.js +++ b/honey_box/common/env.js @@ -11,9 +11,9 @@ // 测试环境配置 - .NET 10 后端 const testing = { - // baseUrl: 'https://app.zpc-xy.com/honey/api', + baseUrl: 'https://app.zpc-xy.com/honey/api', // baseUrl: 'http://192.168.1.24:5238', - baseUrl: 'http://192.168.195.15:2822', + // baseUrl: 'http://192.168.195.15:2822', imageUrl: 'https://youdas-1308826010.cos.ap-shanghai.myqcloud.com', loginPage: '', wxAppId: '' diff --git a/honey_box/pages/infinite/bonus_house_details.vue b/honey_box/pages/infinite/bonus_house_details.vue index 8e2b6452..2c2f32bd 100644 --- a/honey_box/pages/infinite/bonus_house_details.vue +++ b/honey_box/pages/infinite/bonus_house_details.vue @@ -495,7 +495,7 @@ export default { this.participantList = res.data.list.map(item => ({ avatar: item.avatar || "", name: item.nickname || "用户", - time: item.create_time || "" + time: item.createTime || "" })); } } catch (error) { @@ -519,9 +519,9 @@ export default { this.awardRecordList = res.data.list.map(item => ({ avatar: item.avatar || "", name: item.nickname || "用户", - time: item.create_time || "", - award: item.goodslist_title || "钻石*0", - shang_id: item.shang_id + time: item.createTime || "", + award: item.goodslistTitle || "钻石*0", + shang_id: item.shangId })); } } catch (error) { diff --git a/honey_box/pages/infinite/reward_records.vue b/honey_box/pages/infinite/reward_records.vue index e07b7f6e..205b54d6 100644 --- a/honey_box/pages/infinite/reward_records.vue +++ b/honey_box/pages/infinite/reward_records.vue @@ -86,30 +86,29 @@ export default { // 格式化API返回的数据为显示格式 formatListData(list, isWinningRecord = false) { return list.map(item => ({ - Title: item.goods_title || "参与时间", - Time: item.create_time || "", - Content: isWinningRecord ? item.goodslist_title : (item.description) + Title: item.goodsTitle || "参与时间", + Time: item.createTime || "", + Content: isWinningRecord ? item.goodslistTitle : item.description })); }, // 格式化API返回的数据为显示格式 formatListData1(list, isWinningRecord = false) { return list.map(item => ({ Title: "参与时间", - Time: item.create_time || "", - Content: item.goods_title + Time: item.createTime || "", + Content: item.goodsTitle })); }, // 参与记录 async load_records() { - // API: fuliwu_user_records const res = await getUserWelfareRecords(); if (res.status !== 1) { this.$c.toast(res.msg); return; } - if (res.data && res.data.list && res.data.list.length > 0) { - this.recordsList = this.formatListData1(res.data.list, false); + if (res.data && res.data.length > 0) { + this.recordsList = this.formatListData1(res.data, false); } else { this.recordsList = []; } @@ -117,15 +116,14 @@ export default { // 赏品记录 async load_winning_records() { - // API: fuliwu_user_winning_records const res = await getUserWinningRecords(); if (res.status !== 1) { this.$c.toast(res.msg); return; } - if (res.data && res.data.list && res.data.list.length > 0) { - this.winningList = this.formatListData(res.data.list, true); + if (res.data && res.data.length > 0) { + this.winningList = this.formatListData(res.data, true); } else { this.winningList = []; } diff --git a/server/HoneyBox/src/HoneyBox.Admin.Business/Controllers/GoodsTypesController.cs b/server/HoneyBox/src/HoneyBox.Admin.Business/Controllers/GoodsTypesController.cs index 631da03f..4ebe231f 100644 --- a/server/HoneyBox/src/HoneyBox.Admin.Business/Controllers/GoodsTypesController.cs +++ b/server/HoneyBox/src/HoneyBox.Admin.Business/Controllers/GoodsTypesController.cs @@ -1,5 +1,6 @@ using HoneyBox.Admin.Business.Attributes; using HoneyBox.Admin.Business.Models; +using HoneyBox.Admin.Business.Models.Config; using HoneyBox.Admin.Business.Models.Goods; using HoneyBox.Admin.Business.Services.Interfaces; using Microsoft.AspNetCore.Mvc; @@ -13,23 +14,40 @@ namespace HoneyBox.Admin.Business.Controllers; public class GoodsTypesController : BusinessControllerBase { private readonly IGoodsService _goodsService; + private readonly IAdminConfigService _configService; - public GoodsTypesController(IGoodsService goodsService) + public GoodsTypesController(IGoodsService goodsService, IAdminConfigService configService) { _goodsService = goodsService; + _configService = configService; } /// /// 获取盒子类型列表 /// - /// 盒子类型列表 + /// 盒子类型列表及货币名称配置 [HttpGet] [BusinessPermission("goods:view")] public async Task GetGoodsTypes() { try { - var result = await _goodsService.GetGoodsTypesAsync(); + var types = await _goodsService.GetGoodsTypesAsync(); + + // 获取货币名称配置 + var appSetting = await _configService.GetConfigAsync(ConfigKeys.AppSetting); + + var result = new GoodsTypesResponse + { + List = types, + CurrencyNames = new CurrencyNamesDto + { + BalanceName = appSetting?.BalanceName ?? "余额", + Currency1Name = appSetting?.Currency1Name ?? "吧唧币", + Currency2Name = appSetting?.Currency2Name ?? "哈尼券" + } + }; + return Ok(result); } catch (BusinessException ex) diff --git a/server/HoneyBox/src/HoneyBox.Admin.Business/Models/Goods/GoodsModels.cs b/server/HoneyBox/src/HoneyBox.Admin.Business/Models/Goods/GoodsModels.cs index 54c2618f..38567257 100644 --- a/server/HoneyBox/src/HoneyBox.Admin.Business/Models/Goods/GoodsModels.cs +++ b/server/HoneyBox/src/HoneyBox.Admin.Business/Models/Goods/GoodsModels.cs @@ -461,12 +461,12 @@ public class GoodsTypeDto public int PayBalance { get; set; } /// - /// 是否支持积分支付 0-否 1-是 + /// 是否支持货币1支付(HH币/吧唧币)0-否 1-是 /// public int PayCurrency { get; set; } /// - /// 是否支持积分2支付 0-否 1-是 + /// 是否支持货币2支付(哈尼券)0-否 1-是 /// public int PayCurrency2 { get; set; } @@ -486,4 +486,41 @@ public class GoodsTypeDto public string? Remark { get; set; } } +/// +/// 盒子类型列表响应(包含货币名称配置) +/// +public class GoodsTypesResponse +{ + /// + /// 盒子类型列表 + /// + public List List { get; set; } = new(); + + /// + /// 货币名称配置 + /// + public CurrencyNamesDto CurrencyNames { get; set; } = new(); +} + +/// +/// 货币名称配置 +/// +public class CurrencyNamesDto +{ + /// + /// 余额名称(如:钻石) + /// + public string BalanceName { get; set; } = "余额"; + + /// + /// 货币1名称(如:HH币、吧唧币) + /// + public string Currency1Name { get; set; } = "吧唧币"; + + /// + /// 货币2名称(如:哈尼券) + /// + public string Currency2Name { get; set; } = "哈尼券"; +} + #endregion diff --git a/server/HoneyBox/src/HoneyBox.Admin.Business/Models/Goods/GoodsTypeModels.cs b/server/HoneyBox/src/HoneyBox.Admin.Business/Models/Goods/GoodsTypeModels.cs index a1adcdc1..680151cb 100644 --- a/server/HoneyBox/src/HoneyBox.Admin.Business/Models/Goods/GoodsTypeModels.cs +++ b/server/HoneyBox/src/HoneyBox.Admin.Business/Models/Goods/GoodsTypeModels.cs @@ -53,12 +53,12 @@ public class GoodsTypeCreateRequest public int PayBalance { get; set; } /// - /// 是否支持积分支付 0-否 1-是 + /// 是否支持货币1支付(HH币/吧唧币)0-否 1-是 /// public int PayCurrency { get; set; } /// - /// 是否支持积分2支付 0-否 1-是 + /// 是否支持货币2支付(哈尼券)0-否 1-是 /// public int PayCurrency2 { get; set; } diff --git a/server/HoneyBox/src/HoneyBox.Admin.Business/Models/Goods/PrizeModels.cs b/server/HoneyBox/src/HoneyBox.Admin.Business/Models/Goods/PrizeModels.cs index 5879ed5c..db1673c1 100644 --- a/server/HoneyBox/src/HoneyBox.Admin.Business/Models/Goods/PrizeModels.cs +++ b/server/HoneyBox/src/HoneyBox.Admin.Business/Models/Goods/PrizeModels.cs @@ -106,6 +106,13 @@ public class PrizeCreateRequest /// 是否灵珠奖品 0-否 1-是 /// public int IsLingzhu { get; set; } + + /// + /// 父奖品ID(宝箱子奖品时使用) + /// 当添加宝箱的子奖品时,需要传入父奖品ID + /// 系统会自动为所有箱号中的同一父奖品创建对应的子奖品 + /// + public int GoodsListId { get; set; } } /// @@ -259,6 +266,12 @@ public class PrizeDto /// public int IsLingzhu { get; set; } + /// + /// 父奖品ID(宝箱子奖品时使用) + /// 0 表示是父奖品或普通奖品,大于0表示是子奖品 + /// + public int GoodsListId { get; set; } + /// /// 创建时间 /// diff --git a/server/HoneyBox/src/HoneyBox.Admin.Business/Services/GoodsService.cs b/server/HoneyBox/src/HoneyBox.Admin.Business/Services/GoodsService.cs index f15df34d..8e22f23e 100644 --- a/server/HoneyBox/src/HoneyBox.Admin.Business/Services/GoodsService.cs +++ b/server/HoneyBox/src/HoneyBox.Admin.Business/Services/GoodsService.cs @@ -326,56 +326,207 @@ public class GoodsService : IGoodsService throw new BusinessException(BusinessErrorCodes.NotFound, "商品不存在"); } - // 获取当前最大编号 - var maxNum = await _dbContext.GoodsItems - .Where(gi => gi.GoodsId == goodsId) - .MaxAsync(gi => (int?)gi.Num) ?? 0; - var now = DateTime.Now; - var prize = new GoodsItem + var prizeCode = GeneratePrizeCode(); + + // 根据商品类型决定添加逻辑 + // 无限赏(2)、盲盒(8)、扭蛋(9)、福利屋(15)、连抽赏(16)、大乱斗(17):num = 0(模板奖品,只添加一条) + // 一番赏(1)、擂台赏(3)、福袋(5)、幸运赏(6)、积分商城(10)、转转赏(11):为每个箱子都添加一条奖品 + var templateTypes = new[] { 2, 8, 9, 15, 16, 17 }; // 使用模板奖品的类型 + + // 处理宝箱子奖品的情况 + if (request.GoodsListId > 0) { - GoodsId = goodsId, - Num = maxNum + 1, - Title = request.Title, - ImgUrl = request.ImgUrl, - ImgUrlDetail = request.ImgUrlDetail, - Stock = request.Stock, - SurplusStock = request.Stock, - Price = request.Price, - Money = request.Money, - ScMoney = request.ScMoney, - RealPro = request.RealPro, - GoodsType = (byte)request.GoodsType, - Sort = request.Sort, - ShangId = request.ShangId, - RewardNum = request.RewardNum, - Rank = request.Rank, - GiveMoney = request.GiveMoney, - CardNo = request.CardNo, - PrizeCode = GeneratePrizeCode(), - Type = (byte)request.Type, - LianJiType = (byte)request.LianJiType, - RewardId = request.RewardId, - Doubling = request.Doubling, - IsLingzhu = (byte)request.IsLingzhu, - PrizeNum = 1, - GoodsListId = 0, - CreatedAt = now, - UpdatedAt = now - }; + return await AddChildPrizeAsync(goodsId, request, now); + } + + if (templateTypes.Contains(goods.Type)) + { + // 模板类型:只添加一条 num=0 的记录 + var prize = new GoodsItem + { + GoodsId = goodsId, + Num = 0, + Title = request.Title, + ImgUrl = request.ImgUrl, + ImgUrlDetail = request.ImgUrlDetail, + Stock = request.Stock, + SurplusStock = request.Stock, + Price = request.Price, + Money = request.Money, + ScMoney = request.ScMoney, + RealPro = request.RealPro, + GoodsType = (byte)request.GoodsType, + Sort = request.Sort, + ShangId = request.ShangId, + RewardNum = request.RewardNum, + Rank = request.Rank, + GiveMoney = request.GiveMoney, + CardNo = request.CardNo, + PrizeCode = prizeCode, + Type = (byte)request.Type, + LianJiType = (byte)request.LianJiType, + RewardId = request.RewardId, + Doubling = request.Doubling, + IsLingzhu = (byte)request.IsLingzhu, + PrizeNum = 1, + GoodsListId = 0, + CreatedAt = now, + UpdatedAt = now + }; - _dbContext.GoodsItems.Add(prize); + _dbContext.GoodsItems.Add(prize); + await _dbContext.SaveChangesAsync(); - // 更新商品奖品数量 - goods.PrizeNum = await _dbContext.GoodsItems.CountAsync(gi => gi.GoodsId == goodsId) + 1; - goods.UpdatedAt = now; + // 更新商品奖品数量 + goods.PrizeNum = await _dbContext.GoodsItems.CountAsync(gi => gi.GoodsId == goodsId && gi.Num == 0); + goods.UpdatedAt = now; + await _dbContext.SaveChangesAsync(); + _logger.LogInformation("添加模板奖品成功: GoodsId={GoodsId}, PrizeId={PrizeId}, Title={Title}", + goodsId, prize.Id, prize.Title); + + return prize.Id; + } + else + { + // 箱号类型(一番赏等):为每个箱子都添加一条奖品 + var boxCount = goods.Stock; // 箱数 + if (boxCount <= 0) + { + throw new BusinessException(BusinessErrorCodes.ValidationFailed, "商品箱数必须大于0才能添加奖品"); + } + + var prizes = new List(); + for (int i = 1; i <= boxCount; i++) + { + var prize = new GoodsItem + { + GoodsId = goodsId, + Num = i, // 箱号 + Title = request.Title, + ImgUrl = request.ImgUrl, + ImgUrlDetail = request.ImgUrlDetail, + Stock = request.Stock, + SurplusStock = request.Stock, + Price = request.Price, + Money = request.Money, + ScMoney = request.ScMoney, + RealPro = request.RealPro, + GoodsType = (byte)request.GoodsType, + Sort = request.Sort, + ShangId = request.ShangId, + RewardNum = request.RewardNum, + Rank = request.Rank, + GiveMoney = request.GiveMoney, + CardNo = request.CardNo, + PrizeCode = prizeCode, // 同一个 prize_code,表示是同一个奖品配置 + Type = (byte)request.Type, + LianJiType = (byte)request.LianJiType, + RewardId = request.RewardId, + Doubling = request.Doubling, + IsLingzhu = (byte)request.IsLingzhu, + PrizeNum = 1, + GoodsListId = 0, + CreatedAt = now, + UpdatedAt = now + }; + prizes.Add(prize); + } + + _dbContext.GoodsItems.AddRange(prizes); + await _dbContext.SaveChangesAsync(); + + // 更新商品奖品数量(按第一箱的奖品数计算) + goods.PrizeNum = await _dbContext.GoodsItems.CountAsync(gi => gi.GoodsId == goodsId && gi.Num == 1); + goods.UpdatedAt = now; + await _dbContext.SaveChangesAsync(); + + _logger.LogInformation("添加箱号奖品成功: GoodsId={GoodsId}, BoxCount={BoxCount}, Title={Title}, PrizeCode={PrizeCode}", + goodsId, boxCount, request.Title, prizeCode); + + return prizes.First().Id; + } + } + + /// + /// 添加宝箱子奖品 + /// 当父奖品存在于多个箱号中时,会为每个箱号的父奖品都创建对应的子奖品 + /// + private async Task AddChildPrizeAsync(int goodsId, PrizeCreateRequest request, DateTime now) + { + // 获取父奖品信息 + var parentPrize = await _dbContext.GoodsItems + .AsNoTracking() + .FirstOrDefaultAsync(gi => gi.Id == request.GoodsListId && gi.GoodsId == goodsId); + + if (parentPrize == null) + { + throw new BusinessException(BusinessErrorCodes.NotFound, "宝箱父奖品不存在"); + } + + // 验证父奖品是宝箱类型 (goods_type = 4) + if (parentPrize.GoodsType != 4) + { + throw new BusinessException(BusinessErrorCodes.ValidationFailed, "只有宝箱类型的奖品才能添加子奖品"); + } + + // 子奖品生成自己的 prize_code + var childPrizeCode = GeneratePrizeCode(); + + // 查找所有箱号中具有相同 prize_code 的父奖品(同一个宝箱配置在不同箱号中的记录) + var sameParentPrizes = await _dbContext.GoodsItems + .AsNoTracking() + .Where(gi => gi.GoodsId == goodsId + && gi.PrizeCode == parentPrize.PrizeCode + && gi.GoodsListId == 0) // 确保只查询父奖品 + .ToListAsync(); + + var childPrizes = new List(); + + foreach (var parent in sameParentPrizes) + { + var childPrize = new GoodsItem + { + GoodsId = goodsId, + Num = parent.Num, // 继承父奖品的箱号 + Title = request.Title, + ImgUrl = request.ImgUrl, + ImgUrlDetail = request.ImgUrlDetail, + Stock = request.Stock, + SurplusStock = request.Stock, + Price = request.Price, + Money = request.Money, + ScMoney = request.ScMoney, + RealPro = request.RealPro, + GoodsType = (byte)request.GoodsType, + Sort = request.Sort, + ShangId = request.ShangId, + RewardNum = request.RewardNum, + Rank = request.Rank, + GiveMoney = request.GiveMoney, + CardNo = request.CardNo, + PrizeCode = childPrizeCode, // 子奖品使用自己的 prize_code + Type = (byte)request.Type, + LianJiType = (byte)request.LianJiType, + RewardId = request.RewardId, + Doubling = request.Doubling, + IsLingzhu = (byte)request.IsLingzhu, + PrizeNum = 1, + GoodsListId = parent.Id, // 关联到对应箱号的父奖品 + CreatedAt = now, + UpdatedAt = now + }; + childPrizes.Add(childPrize); + } + + _dbContext.GoodsItems.AddRange(childPrizes); await _dbContext.SaveChangesAsync(); - _logger.LogInformation("添加奖品成功: GoodsId={GoodsId}, PrizeId={PrizeId}, Title={Title}", - goodsId, prize.Id, prize.Title); + _logger.LogInformation("添加宝箱子奖品成功: GoodsId={GoodsId}, ParentPrizeCode={ParentPrizeCode}, ChildCount={ChildCount}, Title={Title}", + goodsId, parentPrize.PrizeCode, childPrizes.Count, request.Title); - return prize.Id; + return childPrizes.First().Id; } @@ -773,6 +924,7 @@ public class GoodsService : IGoodsService RewardId = prize.RewardId, Doubling = prize.Doubling, IsLingzhu = prize.IsLingzhu, + GoodsListId = prize.GoodsListId, CreatedAt = prize.CreatedAt, UpdatedAt = prize.UpdatedAt }; @@ -787,15 +939,14 @@ public class GoodsService : IGoodsService } /// - /// 库存增加时复制奖品配置 + /// 库存增加时复制奖品配置(正确处理宝箱子奖品的父子关系) /// private async Task CopyPrizeConfigurationsAsync(int goodsId, int stockIncrease) { - // 获取第一套奖品配置(作为模板) + // 获取第一箱的奖品配置(作为模板) var templatePrizes = await _dbContext.GoodsItems .AsNoTracking() - .Where(gi => gi.GoodsId == goodsId) - .OrderBy(gi => gi.Num) + .Where(gi => gi.GoodsId == goodsId && gi.Num == 1) // 只取第一箱作为模板 .ToListAsync(); if (!templatePrizes.Any()) @@ -804,20 +955,29 @@ public class GoodsService : IGoodsService } var now = DateTime.Now; - var newPrizes = new List(); - // 获取当前最大编号 - var maxNum = templatePrizes.Max(p => p.Num); + // 获取当前最大箱号 + var maxNum = await _dbContext.GoodsItems + .Where(gi => gi.GoodsId == goodsId) + .MaxAsync(gi => gi.Num); - // 为每个新增的库存复制奖品配置 + // 分离父奖品和子奖品模板 + var parentTemplates = templatePrizes.Where(p => p.GoodsListId == 0).ToList(); + var childTemplates = templatePrizes.Where(p => p.GoodsListId > 0).ToList(); + + // 为每个新增的箱号复制奖品配置 for (int i = 0; i < stockIncrease; i++) { - foreach (var template in templatePrizes) + var newNum = maxNum + 1 + i; + var oldToNewIdMap = new Dictionary(); // 旧模板ID -> 新ID 映射 + + // 第一步:复制父奖品 + foreach (var template in parentTemplates) { var newPrize = new GoodsItem { GoodsId = goodsId, - Num = maxNum + 1 + (i * templatePrizes.Count) + templatePrizes.IndexOf(template), + Num = newNum, Title = template.Title, ImgUrl = template.ImgUrl, ImgUrlDetail = template.ImgUrlDetail, @@ -834,28 +994,73 @@ public class GoodsService : IGoodsService Rank = template.Rank, GiveMoney = template.GiveMoney, CardNo = template.CardNo, - PrizeCode = GeneratePrizeCode(), + PrizeCode = template.PrizeCode, // 保持相同的 prize_code,表示是同一个奖品配置 Type = template.Type, LianJiType = template.LianJiType, RewardId = template.RewardId, Doubling = template.Doubling, IsLingzhu = template.IsLingzhu, PrizeNum = template.PrizeNum, - GoodsListId = template.GoodsListId, + GoodsListId = 0, SpecialStock = template.SpecialStock, CreatedAt = now, UpdatedAt = now }; - newPrizes.Add(newPrize); + _dbContext.GoodsItems.Add(newPrize); + await _dbContext.SaveChangesAsync(); // 保存以获取新ID + oldToNewIdMap[template.Id] = newPrize.Id; + } + + // 第二步:复制子奖品,并更新 goods_list_id 为新的父奖品ID + foreach (var template in childTemplates) + { + var newParentId = oldToNewIdMap.GetValueOrDefault(template.GoodsListId, 0); + if (newParentId == 0) + { + _logger.LogWarning("复制奖品配置时找不到子奖品的父奖品映射: GoodsId={GoodsId}, TemplateChildId={TemplateChildId}, TemplateParentId={TemplateParentId}", + goodsId, template.Id, template.GoodsListId); + continue; + } + + var newPrize = new GoodsItem + { + GoodsId = goodsId, + Num = newNum, + Title = template.Title, + ImgUrl = template.ImgUrl, + ImgUrlDetail = template.ImgUrlDetail, + Stock = template.Stock, + SurplusStock = template.Stock, + Price = template.Price, + Money = template.Money, + ScMoney = template.ScMoney, + RealPro = template.RealPro, + GoodsType = template.GoodsType, + Sort = template.Sort, + ShangId = template.ShangId, + RewardNum = template.RewardNum, + Rank = template.Rank, + GiveMoney = template.GiveMoney, + CardNo = template.CardNo, + PrizeCode = template.PrizeCode, // 保持相同的 prize_code + Type = template.Type, + LianJiType = template.LianJiType, + RewardId = template.RewardId, + Doubling = template.Doubling, + IsLingzhu = template.IsLingzhu, + PrizeNum = template.PrizeNum, + GoodsListId = newParentId, // 使用新的父奖品ID + SpecialStock = template.SpecialStock, + CreatedAt = now, + UpdatedAt = now + }; + _dbContext.GoodsItems.Add(newPrize); } } - if (newPrizes.Any()) - { - _dbContext.GoodsItems.AddRange(newPrizes); - _logger.LogInformation("复制奖品配置: GoodsId={GoodsId}, StockIncrease={StockIncrease}, NewPrizes={NewPrizes}", - goodsId, stockIncrease, newPrizes.Count); - } + await _dbContext.SaveChangesAsync(); + _logger.LogInformation("复制奖品配置: GoodsId={GoodsId}, StockIncrease={StockIncrease}, NewBoxes={NewBoxes}", + goodsId, stockIncrease, stockIncrease); } /// @@ -1100,7 +1305,7 @@ public class GoodsService : IGoodsService _dbContext.Goods.Add(newGoods); await _dbContext.SaveChangesAsync(); - // 复制奖品 + // 复制奖品(需要正确处理宝箱子奖品的父子关系) var sourcePrizes = await _dbContext.GoodsItems .AsNoTracking() .Where(gi => gi.GoodsId == goodsId) @@ -1108,43 +1313,101 @@ public class GoodsService : IGoodsService if (sourcePrizes.Any()) { - var newPrizes = sourcePrizes.Select(p => new GoodsItem + // 第一步:先复制所有父奖品(goods_list_id = 0) + var parentPrizes = sourcePrizes.Where(p => p.GoodsListId == 0).ToList(); + var oldToNewIdMap = new Dictionary(); // 旧ID -> 新ID 映射 + + foreach (var p in parentPrizes) { - GoodsId = newGoods.Id, - Num = p.Num, - Title = p.Title, - ImgUrl = p.ImgUrl, - ImgUrlDetail = p.ImgUrlDetail, - Stock = p.Stock, - SurplusStock = p.Stock, // 重置剩余库存 - Price = p.Price, - Money = p.Money, - ScMoney = p.ScMoney, - RealPro = p.RealPro, - GoodsType = p.GoodsType, - Sort = p.Sort, - ShangId = p.ShangId, - RewardNum = p.RewardNum, - Rank = p.Rank, - GiveMoney = p.GiveMoney, - CardNo = p.CardNo, - PrizeCode = GeneratePrizeCode(), - Type = p.Type, - LianJiType = p.LianJiType, - RewardId = p.RewardId, - Doubling = p.Doubling, - IsLingzhu = p.IsLingzhu, - PrizeNum = p.PrizeNum, - GoodsListId = 0, - SpecialStock = p.SpecialStock, - CreatedAt = now, - UpdatedAt = now - }).ToList(); + var newPrize = new GoodsItem + { + GoodsId = newGoods.Id, + Num = p.Num, + Title = p.Title, + ImgUrl = p.ImgUrl, + ImgUrlDetail = p.ImgUrlDetail, + Stock = p.Stock, + SurplusStock = p.Stock, // 重置剩余库存 + Price = p.Price, + Money = p.Money, + ScMoney = p.ScMoney, + RealPro = p.RealPro, + GoodsType = p.GoodsType, + Sort = p.Sort, + ShangId = p.ShangId, + RewardNum = p.RewardNum, + Rank = p.Rank, + GiveMoney = p.GiveMoney, + CardNo = p.CardNo, + PrizeCode = GeneratePrizeCode(), + Type = p.Type, + LianJiType = p.LianJiType, + RewardId = p.RewardId, + Doubling = p.Doubling, + IsLingzhu = p.IsLingzhu, + PrizeNum = p.PrizeNum, + GoodsListId = 0, + SpecialStock = p.SpecialStock, + CreatedAt = now, + UpdatedAt = now + }; + _dbContext.GoodsItems.Add(newPrize); + await _dbContext.SaveChangesAsync(); // 保存以获取新ID + oldToNewIdMap[p.Id] = newPrize.Id; + } - _dbContext.GoodsItems.AddRange(newPrizes); + // 第二步:复制所有子奖品(goods_list_id > 0),并更新 goods_list_id 为新的父奖品ID + var childPrizes = sourcePrizes.Where(p => p.GoodsListId > 0).ToList(); + foreach (var p in childPrizes) + { + // 查找新的父奖品ID + var newParentId = oldToNewIdMap.GetValueOrDefault(p.GoodsListId, 0); + if (newParentId == 0) + { + _logger.LogWarning("复制盒子时找不到子奖品的父奖品映射: SourceChildId={SourceChildId}, SourceParentId={SourceParentId}", + p.Id, p.GoodsListId); + continue; // 跳过找不到父奖品的子奖品 + } - // 更新新盒子的奖品数量 - newGoods.PrizeNum = newPrizes.Count; + var newPrize = new GoodsItem + { + GoodsId = newGoods.Id, + Num = p.Num, + Title = p.Title, + ImgUrl = p.ImgUrl, + ImgUrlDetail = p.ImgUrlDetail, + Stock = p.Stock, + SurplusStock = p.Stock, // 重置剩余库存 + Price = p.Price, + Money = p.Money, + ScMoney = p.ScMoney, + RealPro = p.RealPro, + GoodsType = p.GoodsType, + Sort = p.Sort, + ShangId = p.ShangId, + RewardNum = p.RewardNum, + Rank = p.Rank, + GiveMoney = p.GiveMoney, + CardNo = p.CardNo, + PrizeCode = GeneratePrizeCode(), + Type = p.Type, + LianJiType = p.LianJiType, + RewardId = p.RewardId, + Doubling = p.Doubling, + IsLingzhu = p.IsLingzhu, + PrizeNum = p.PrizeNum, + GoodsListId = newParentId, // 使用新的父奖品ID + SpecialStock = p.SpecialStock, + CreatedAt = now, + UpdatedAt = now + }; + _dbContext.GoodsItems.Add(newPrize); + } + + await _dbContext.SaveChangesAsync(); + + // 更新新盒子的奖品数量(只统计父奖品) + newGoods.PrizeNum = parentPrizes.Count; } // 复制扩展设置(如果有)