using HoneyBox.Core.Interfaces; using HoneyBox.Model.Data; using HoneyBox.Model.Entities; using HoneyBox.Model.Models.Welfare; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; namespace HoneyBox.Core.Services; /// /// 福利屋服务实现 /// public class WelfareService : IWelfareService { private readonly HoneyBoxDbContext _dbContext; private readonly ILogger _logger; private const int WelfareType = 15; // 福利屋商品类型 public WelfareService(HoneyBoxDbContext dbContext, ILogger logger) { _dbContext = dbContext; _logger = logger; } /// public async Task GetWelfareListAsync(int userId, int type, int page, int limit = 15) { // 验证type参数 if (type != 1 && type != 3) { throw new ArgumentException("参数错误"); } // 计算用户消费总额(用于解锁金额判断) decimal userTotalConsumption = 0; if (userId > 0) { var userInfo = await _dbContext.Users .Where(u => u.Id == userId) .Select(u => new { u.IsTest }) .FirstOrDefaultAsync(); if (userInfo != null && userInfo.IsTest > 0) { // 推广账号,门槛计算是全部的order_zhe_total userTotalConsumption = await _dbContext.Orders .Where(o => o.Status == 1 && o.UserId == userId) .SumAsync(o => o.OrderZheTotal); } else { // 普通用户,计算price + use_money var orderPrice = await _dbContext.Orders .Where(o => o.Status == 1 && o.UserId == userId) .SumAsync(o => o.Price); var orderMoney = await _dbContext.Orders .Where(o => o.Status == 1 && o.UserId == userId) .SumAsync(o => o.UseMoney); userTotalConsumption = orderPrice + orderMoney; } } // 构建查询 var now = DateTime.Now; IQueryable query; if (type == 1) { // type=1 进行中:Status=1, IsOpen=0, 且开奖时间未到 query = _dbContext.Goods .Where(g => g.Status == 1 && g.Type == WelfareType && g.IsOpen == 0 && g.UnlockAmount <= userTotalConsumption && (g.OpenTime == null || g.OpenTime > now)) .OrderByDescending(g => g.Sort) .ThenByDescending(g => g.Id); } else { // type=3 已结束:已开奖的 或 开奖时间已过但未开奖的 query = _dbContext.Goods .Where(g => g.Type == WelfareType && g.UnlockAmount <= userTotalConsumption && (g.IsOpen == 1 || (g.OpenTime != null && g.OpenTime <= now))) .OrderByDescending(g => g.OpenTime); } // 获取总数 var total = await query.CountAsync(); var lastPage = (int)Math.Ceiling((double)total / limit); // 分页查询 var goods = await query .Skip((page - 1) * limit) .Take(limit) .Select(g => new { g.Id, g.Title, g.ImgUrl, g.Price, g.Type, g.NewIs, g.QuanjuXiangou, g.ChoujiangXianzhi, g.FlwStartTime, g.FlwEndTime, g.OpenTime, g.GoodsDescribe, g.IsOpen }) .ToListAsync(); // 获取商品ID列表 var goodsIds = goods.Select(g => g.Id).ToList(); // 获取每个商品的奖品列表 var goodsListItems = await _dbContext.GoodsItems .Where(gi => goodsIds.Contains(gi.GoodsId) && gi.Num == 0) .Select(gi => new { gi.GoodsId, gi.Title, gi.ImgUrl, gi.Stock, gi.Price, gi.ScMoney }) .ToListAsync(); // 获取参与次数 var joinCounts = await _dbContext.OrderItems .Where(oi => goodsIds.Contains(oi.GoodsId ?? 0)) .GroupBy(oi => oi.GoodsId) .Select(g => new { GoodsId = g.Key, Count = g.Count() }) .ToDictionaryAsync(x => x.GoodsId ?? 0, x => x.Count); // 构建返回数据 var list = goods.Select(g => new WelfareItemDto { Id = g.Id, Title = g.Title, Imgurl = g.ImgUrl, Price = g.Price, Type = g.Type, NewIs = g.NewIs, QuanjuXiangou = g.QuanjuXiangou, ChoujiangXianzhi = g.ChoujiangXianzhi, FlwStartTime = g.FlwStartTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? "", FlwEndTime = g.FlwEndTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? "", OpenTime = g.OpenTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? "", GoodsDescribe = g.GoodsDescribe ?? "", IsOpen = g.IsOpen, JoinCount = joinCounts.GetValueOrDefault(g.Id, 0), Goodslist = goodsListItems .Where(gi => gi.GoodsId == g.Id) .Select(gi => new WelfareGoodsListItemDto { Title = gi.Title, Imgurl = gi.ImgUrl, Stock = gi.Stock, Price = gi.Price, ScMoney = gi.ScMoney }) .ToList() }).ToList(); return new WelfareListResponse { List = list, LastPage = lastPage, Total = total }; } /// public async Task GetWelfareDetailAsync(int userId, int goodsId) { // 获取商品信息 var goods = await _dbContext.Goods .Where(g => g.Id == goodsId) .FirstOrDefaultAsync(); if (goods == null) { throw new InvalidOperationException("盒子不存在"); } if (goods.Status != 1 && goods.Status != 3) { throw new InvalidOperationException("盒子已下架"); } if (goods.Type != WelfareType) { throw new InvalidOperationException("该盒子不是福利屋类型"); } // 检查用户是否可以查看该福利屋(解锁金额限制) decimal userTotalConsumption = 0; if (userId > 0) { var userInfo = await _dbContext.Users .Where(u => u.Id == userId) .Select(u => new { u.IsTest }) .FirstOrDefaultAsync(); if (userInfo != null && userInfo.IsTest > 0) { // 推广账号 userTotalConsumption = await _dbContext.Orders .Where(o => o.Status == 1 && o.UserId == userId) .SumAsync(o => o.OrderZheTotal); } else { var orderPrice = await _dbContext.Orders .Where(o => o.Status == 1 && o.UserId == userId) .SumAsync(o => o.Price); var orderMoney = await _dbContext.Orders .Where(o => o.Status == 1 && o.UserId == userId) .SumAsync(o => o.UseMoney); userTotalConsumption = orderPrice + orderMoney; } if (goods.UnlockAmount > userTotalConsumption) { throw new InvalidOperationException($"您需要消费满{goods.UnlockAmount}元才能查看此福利屋"); } } else if (goods.UnlockAmount > 0) { throw new InvalidOperationException($"您需要登录并充值满{goods.UnlockAmount}元才能查看此福利屋"); } // 获取奖品列表 var goodsListItems = await _dbContext.GoodsItems .Where(gi => gi.GoodsId == goodsId && gi.Num == 0) .OrderByDescending(gi => gi.ShangId) .ThenBy(gi => gi.Sort) .Select(gi => new { gi.Id, gi.Title, gi.ImgUrl, gi.ImgUrlDetail, gi.Stock, gi.Price, gi.ScMoney, gi.ShangId, gi.SurplusStock, gi.Sort }) .ToListAsync(); // 获取奖品等级信息 var shangIds = goodsListItems.Where(gi => gi.ShangId.HasValue).Select(gi => gi.ShangId!.Value).Distinct().ToList(); var shangInfos = await _dbContext.PrizeLevels .Where(p => shangIds.Contains(p.Id)) .Select(p => new { p.Id, p.Title, p.Color }) .ToDictionaryAsync(p => p.Id); // 统计参与人数 var joinCount = await _dbContext.OrderItems .Where(oi => oi.GoodsId == goodsId && oi.OrderType == WelfareType) .CountAsync(); // 统计用户参与次数 var userCount = userId > 0 ? await _dbContext.OrderItems .Where(oi => oi.GoodsId == goodsId && oi.UserId == userId && oi.OrderType == WelfareType) .CountAsync() : 0; // 获取用户在活动期间的消费数据 var userConsumption = new UserConsumptionDto(); if (userId > 0 && goods.FlwStartTime.HasValue && goods.FlwEndTime.HasValue) { var startTimestamp = ToUnixTimestamp(goods.FlwStartTime.Value); var endTimestamp = ToUnixTimestamp(goods.FlwEndTime.Value); var consumptionData = await _dbContext.Orders .Where(o => o.UserId == userId && o.Status == 1 && o.Addtime >= startTimestamp && o.Addtime <= endTimestamp) .GroupBy(o => 1) .Select(g => new { TotalAmount = g.Sum(o => o.OrderTotal), OrderCount = g.Count() }) .FirstOrDefaultAsync(); if (consumptionData != null) { userConsumption.TotalAmount = consumptionData.TotalAmount; userConsumption.OrderCount = consumptionData.OrderCount; } } // 构建商品DTO var goodsDto = new WelfareGoodsDto { Id = goods.Id, Title = goods.Title, Imgurl = goods.ImgUrl, ImgurlDetail = !string.IsNullOrEmpty(goods.ImgUrlDetail) ? goods.ImgUrlDetail : goods.ImgUrl, Price = goods.Price, Type = goods.Type, NewIs = goods.NewIs, QuanjuXiangou = goods.QuanjuXiangou, ChoujiangXianzhi = goods.ChoujiangXianzhi, GoodsDescribe = goods.GoodsDescribe ?? "", IsOpen = goods.IsOpen, UnlockAmount = goods.UnlockAmount, Sort = goods.Sort, FlwStartTime = goods.FlwStartTime?.ToString("yyyy-MM-dd HH:mm") ?? "", FlwEndTime = goods.FlwEndTime?.ToString("yyyy-MM-dd HH:mm") ?? "", OpenTime = goods.OpenTime?.ToString("yyyy-MM-dd HH:mm") ?? "" }; // 构建奖品列表 var prizeList = goodsListItems.Select(gi => { var shangInfo = gi.ShangId.HasValue ? shangInfos.GetValueOrDefault(gi.ShangId.Value) : null; return new WelfarePrizeDto { Id = gi.Id, Title = gi.Title, Imgurl = gi.ImgUrl, ImgurlDetail = !string.IsNullOrEmpty(gi.ImgUrlDetail) ? gi.ImgUrlDetail : gi.ImgUrl, Stock = gi.Stock, Price = gi.Price, ScMoney = gi.ScMoney, ShangId = gi.ShangId ?? 0, SurplusStock = gi.SurplusStock, Sort = gi.Sort, ShangTitle = shangInfo?.Title ?? "", ShangColor = shangInfo?.Color ?? "" }; }).ToList(); // 判断福利屋状态 var now = DateTime.Now; var startTime = goods.FlwStartTime ?? DateTime.MinValue; var endTime = goods.FlwEndTime ?? DateTime.MinValue; var openTime = goods.OpenTime ?? DateTime.MinValue; string status; string statusText; if (now < startTime) { status = "waiting"; statusText = "即将开始"; } else if (now >= startTime && now < endTime) { status = "ongoing"; statusText = "进行中"; } else if (now >= endTime && now < openTime) { status = "ended"; statusText = "已结束,等待开奖"; } else if (now >= openTime) { if (goods.IsOpen == 1) { status = "opened"; statusText = "已开奖"; } else { status = "to_open"; statusText = "待开奖"; } } else { status = "unknown"; statusText = "未知状态"; } return new WelfareDetailResponse { Goods = goodsDto, Goodslist = prizeList, JoinCount = joinCount, CurrentTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), UserCount = userCount, UserConsumption = userConsumption, Status = status, StatusText = statusText }; } /// public async Task> GetParticipantsAsync(int goodsId, int page = 1, int limit = 15) { var participants = await _dbContext.OrderItems .Where(oi => oi.GoodsId == goodsId && oi.OrderType == WelfareType) .OrderByDescending(oi => oi.Addtime) .Take(1000) .Select(oi => new { oi.UserId, oi.Addtime }) .ToListAsync(); // 获取用户信息 var userIds = participants.Select(p => p.UserId).Distinct().ToList(); var users = await _dbContext.Users .Where(u => userIds.Contains(u.Id)) .Select(u => new { u.Id, u.Nickname, u.HeadImg }) .ToDictionaryAsync(u => u.Id); return participants.Select(p => { var user = users.GetValueOrDefault(p.UserId); return new ParticipantDto { Nickname = user?.Nickname ?? "", Avatar = user?.HeadImg ?? "", CreateTime = DateTimeOffset.FromUnixTimeSeconds(p.Addtime).LocalDateTime.ToString("yyyy-MM-dd HH:mm") }; }).ToList(); } /// public async Task> GetWinningRecordsAsync(int goodsId, int page = 1, int limit = 15) { var records = await _dbContext.OrderItems .Where(oi => oi.GoodsId == goodsId && oi.OrderType == WelfareType && oi.ShangId > 0) .OrderByDescending(oi => oi.ShangId) .ThenByDescending(oi => oi.Addtime) .Take(1000) .Select(oi => new { oi.UserId, oi.Addtime, oi.GoodslistTitle, oi.ShangId }) .ToListAsync(); // 获取用户信息 var userIds = records.Select(r => r.UserId).Distinct().ToList(); var users = await _dbContext.Users .Where(u => userIds.Contains(u.Id)) .Select(u => new { u.Id, u.Nickname, u.HeadImg }) .ToDictionaryAsync(u => u.Id); return records.Select(r => { var user = users.GetValueOrDefault(r.UserId); return new WinningRecordDto { Nickname = user?.Nickname ?? "", Avatar = user?.HeadImg ?? "", GoodslistTitle = r.GoodslistTitle ?? "", ShangId = r.ShangId, CreateTime = DateTimeOffset.FromUnixTimeSeconds(r.Addtime).LocalDateTime.ToString("yyyy-MM-dd HH:mm") }; }).ToList(); } /// public async Task> GetUserParticipationRecordsAsync(int userId, int page = 1, int limit = 15) { var records = await _dbContext.OrderItems .Where(oi => oi.UserId == userId && oi.OrderType == WelfareType) .OrderByDescending(oi => oi.Addtime) .Take(1000) .Select(oi => new { oi.GoodsId, oi.Addtime, oi.GoodslistTitle, oi.ShangId }) .ToListAsync(); // 获取商品信息 var goodsIds = records.Where(r => r.GoodsId.HasValue).Select(r => r.GoodsId!.Value).Distinct().ToList(); var goodsInfos = await _dbContext.Goods .Where(g => goodsIds.Contains(g.Id)) .Select(g => new { g.Id, g.Title }) .ToDictionaryAsync(g => g.Id); return records.Select(r => { var goodsInfo = r.GoodsId.HasValue ? goodsInfos.GetValueOrDefault(r.GoodsId.Value) : null; return new UserParticipationDto { GoodsId = r.GoodsId ?? 0, GoodsTitle = goodsInfo?.Title ?? "", GoodslistTitle = r.GoodslistTitle ?? "", ShangId = r.ShangId, CreateTime = DateTimeOffset.FromUnixTimeSeconds(r.Addtime).LocalDateTime.ToString("yyyy-MM-dd HH:mm") }; }).ToList(); } /// public async Task> GetUserWinningRecordsAsync(int userId, int page = 1, int limit = 15) { var records = await _dbContext.OrderItems .Where(oi => oi.UserId == userId && oi.OrderType == WelfareType && oi.ShangId > 0) .OrderByDescending(oi => oi.Addtime) .Take(1000) .Select(oi => new { oi.GoodsId, oi.Addtime, oi.GoodslistTitle, oi.ShangId }) .ToListAsync(); // 获取商品信息(包括开奖时间) var goodsIds = records.Where(r => r.GoodsId.HasValue).Select(r => r.GoodsId!.Value).Distinct().ToList(); var goodsInfos = await _dbContext.Goods .Where(g => goodsIds.Contains(g.Id)) .Select(g => new { g.Id, g.Title, g.OpenTime }) .ToDictionaryAsync(g => g.Id); return records.Select(r => { var goodsInfo = r.GoodsId.HasValue ? goodsInfos.GetValueOrDefault(r.GoodsId.Value) : null; return new UserWinningDto { GoodsId = r.GoodsId ?? 0, GoodsTitle = goodsInfo?.Title ?? "", GoodslistTitle = r.GoodslistTitle ?? "", ShangId = r.ShangId, CreateTime = goodsInfo?.OpenTime?.ToString("yyyy-MM-dd HH:mm") ?? "" }; }).ToList(); } /// /// 将DateTime转换为Unix时间戳 /// private static int ToUnixTimestamp(DateTime dateTime) { return (int)(dateTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds; } /// public async Task GetFuliwuListAsync(int userId, int type, int page) { // 验证type参数 if (type != 1 && type != 3) { throw new ArgumentException("参数错误"); } const int paginate = 15; // 计算用户消费总额(用于解锁金额判断) decimal userTotalConsumption = 0; if (userId > 0) { var userInfo = await _dbContext.Users .Where(u => u.Id == userId) .Select(u => new { u.IsTest }) .FirstOrDefaultAsync(); if (userInfo != null && userInfo.IsTest > 0) { // 推广账号,门槛计算是全部的order_zhe_total userTotalConsumption = await _dbContext.Orders .Where(o => o.Status == 1 && o.UserId == userId) .SumAsync(o => o.OrderZheTotal); } else { // 普通用户,计算price + use_money var orderPrice = await _dbContext.Orders .Where(o => o.Status == 1 && o.UserId == userId) .SumAsync(o => o.Price); var orderMoney = await _dbContext.Orders .Where(o => o.Status == 1 && o.UserId == userId) .SumAsync(o => o.UseMoney); userTotalConsumption = orderPrice + orderMoney; } } // 构建查询 var now = DateTime.Now; IQueryable query; _logger.LogInformation("GetFuliwuListAsync: userId={UserId}, type={Type}, page={Page}, userTotalConsumption={Consumption}, now={Now}", userId, type, page, userTotalConsumption, now); if (type == 1) { // type=1 进行中:Status=1, IsOpen=0, 且开奖时间未到 query = _dbContext.Goods .Where(g => g.Status == 1 && g.Type == WelfareType && g.IsOpen == 0 && g.UnlockAmount <= userTotalConsumption && (g.OpenTime == null || g.OpenTime > now)) .OrderByDescending(g => g.Sort) .ThenByDescending(g => g.Id); } else { // type=3 已结束:已开奖的 或 开奖时间已过但未开奖的 query = _dbContext.Goods .Where(g => g.Type == WelfareType && g.UnlockAmount <= userTotalConsumption && (g.IsOpen == 1 || (g.OpenTime != null && g.OpenTime <= now))) .OrderByDescending(g => g.OpenTime); } // 获取总数计算最后一页 var total = await query.CountAsync(); var lastPage = (int)Math.Ceiling((double)total / paginate); _logger.LogInformation("GetFuliwuListAsync: total={Total}, lastPage={LastPage}", total, lastPage); // 分页查询 var goods = await query .Skip((page - 1) * paginate) .Take(paginate) .Select(g => new { g.Id, g.Title, g.ImgUrl, g.Price, g.Type, g.NewIs, g.QuanjuXiangou, g.ChoujiangXianzhi, g.FlwStartTime, g.FlwEndTime, g.OpenTime, g.GoodsDescribe, g.IsOpen }) .ToListAsync(); // 获取商品ID列表 var goodsIds = goods.Select(g => g.Id).ToList(); // 获取每个商品的奖品列表 var goodsListItems = await _dbContext.GoodsItems .Where(gi => goodsIds.Contains(gi.GoodsId) && gi.Num == 0) .Select(gi => new { gi.GoodsId, gi.Title, gi.ImgUrl, gi.Stock, gi.Price, gi.ScMoney }) .ToListAsync(); // 获取参与次数 var joinCounts = await _dbContext.OrderItems .Where(oi => goodsIds.Contains(oi.GoodsId ?? 0)) .GroupBy(oi => oi.GoodsId) .Select(g => new { GoodsId = g.Key, Count = g.Count() }) .ToDictionaryAsync(x => x.GoodsId ?? 0, x => x.Count); // 构建返回数据 var list = goods.Select(g => new WelfareItemDto { Id = g.Id, Title = g.Title, Imgurl = g.ImgUrl, Price = g.Price, Type = g.Type, NewIs = g.NewIs, QuanjuXiangou = g.QuanjuXiangou, ChoujiangXianzhi = g.ChoujiangXianzhi, FlwStartTime = g.FlwStartTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? "", FlwEndTime = g.FlwEndTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? "", OpenTime = g.OpenTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? "", GoodsDescribe = g.GoodsDescribe ?? "", IsOpen = g.IsOpen, JoinCount = joinCounts.GetValueOrDefault(g.Id, 0), Goodslist = goodsListItems .Where(gi => gi.GoodsId == g.Id) .Select(gi => new WelfareGoodsListItemDto { Title = gi.Title, Imgurl = gi.ImgUrl, Stock = gi.Stock, Price = gi.Price, ScMoney = gi.ScMoney }) .ToList() }).ToList(); return new FuliwuListResponse { Data = list, LastPage = lastPage }; } /// public async Task BuyWelfareAsync(int userId, WelfareBuyRequest request) { // 1. 获取用户信息 var user = await _dbContext.Users .Where(u => u.Id == userId) .Select(u => new { u.Id, u.Mobile, u.Money, u.Integral, u.Money2, u.IsTest }) .FirstOrDefaultAsync(); if (user == null) { throw new InvalidOperationException("用户不存在"); } // 2. 验证手机号绑定 if (string.IsNullOrEmpty(user.Mobile)) { throw new InvalidOperationException("请先绑定手机号"); } // 3. 获取商品信息 var goods = await _dbContext.Goods .Where(g => g.Id == request.GoodsId) .FirstOrDefaultAsync(); if (goods == null) { throw new InvalidOperationException("盒子不存在"); } if (goods.Status != 1) { throw new InvalidOperationException("盒子已下架"); } // 4. 验证是否为福利屋类型 if (goods.Type != WelfareType) { throw new InvalidOperationException("该盒子不是福利屋类型"); } // 5. 验证福利屋活动时间 var now = DateTime.Now; if (goods.FlwStartTime.HasValue && now < goods.FlwStartTime.Value) { throw new InvalidOperationException("福利屋活动尚未开始"); } if (goods.FlwEndTime.HasValue && now > goods.FlwEndTime.Value) { throw new InvalidOperationException("福利屋活动已结束"); } // 6. 验证解锁金额 decimal userTotalConsumption = 0; if (user.IsTest > 0) { userTotalConsumption = await _dbContext.Orders .Where(o => o.Status == 1 && o.UserId == userId) .SumAsync(o => o.OrderZheTotal); } else { var orderPrice = await _dbContext.Orders .Where(o => o.Status == 1 && o.UserId == userId) .SumAsync(o => o.Price); var orderMoney = await _dbContext.Orders .Where(o => o.Status == 1 && o.UserId == userId) .SumAsync(o => o.UseMoney); userTotalConsumption = orderPrice + orderMoney; } if (goods.UnlockAmount > userTotalConsumption) { throw new InvalidOperationException($"您需要消费满{goods.UnlockAmount}元才能参与此福利屋"); } // 7. 验证抽奖门槛 (福利屋活动期间消费) if (goods.ChoujiangXianzhi > 0 && goods.FlwStartTime.HasValue && goods.FlwEndTime.HasValue) { var startTimestamp = ToUnixTimestamp(goods.FlwStartTime.Value); var endTimestamp = ToUnixTimestamp(goods.FlwEndTime.Value); var consumptionInPeriod = await _dbContext.Orders .Where(o => o.Status == 1 && o.UserId == userId && o.Addtime >= startTimestamp && o.Addtime <= endTimestamp) .SumAsync(o => o.UseMoney); if (consumptionInPeriod < goods.ChoujiangXianzhi) { var remaining = Math.Round(goods.ChoujiangXianzhi - consumptionInPeriod, 2); throw new InvalidOperationException( $"需在活动期间消耗达到{goods.ChoujiangXianzhi}钻石,还需{remaining}钻石"); } } // 8. 验证全局限购 if (goods.QuanjuXiangou > 0) { var userQuanjuCount = await _dbContext.OrderItems .Where(oi => oi.GoodsId == request.GoodsId && oi.UserId == userId && oi.ParentGoodsListId == 0) .CountAsync(); if (userQuanjuCount >= goods.QuanjuXiangou) { throw new InvalidOperationException($"当前限购{goods.QuanjuXiangou}次"); } var nowPrizeNum = request.PrizeNum + userQuanjuCount; if (nowPrizeNum > goods.QuanjuXiangou) { throw new InvalidOperationException($"购买超出限制,还允许购买{goods.QuanjuXiangou - userQuanjuCount}次"); } } // 9. 计算订单金额 var prizeNum = request.PrizeNum > 0 ? request.PrizeNum : 1; var orderTotal = goods.Price * prizeNum; var price = orderTotal; // 余额抵扣 decimal useMoney = 0; if (request.UseMoneyIs == 1) { if (user.Money >= price) { useMoney = price; price = 0; } else { useMoney = user.Money; price -= user.Money; } } // 积分抵扣 (1:100比例) decimal useIntegral = 0; if (request.UseIntegralIs == 1 && price > 0) { var priceInIntegral = price * 100; if (user.Integral >= priceInIntegral) { useIntegral = priceInIntegral; price = 0; } else { useIntegral = user.Integral; price -= user.Integral / 100; } } // 货币2抵扣 (1:100比例) decimal useMoney2 = 0; var userMoney2 = user.Money2 ?? 0; if (request.UseMoney2Is == 1 && price > 0) { var priceInMoney2 = price * 100; if (userMoney2 >= priceInMoney2) { useMoney2 = priceInMoney2; price = 0; } else { useMoney2 = userMoney2; price -= userMoney2 / 100; } } price = Math.Round(price, 2); // 10. 生成订单号 var orderNum = $"FLW_{DateTime.Now:yyyyMMddHHmmss}_{userId}_{new Random().Next(1000, 9999)}"; // 11. 使用事务创建订单 using var transaction = await _dbContext.Database.BeginTransactionAsync(); try { // 扣除用户余额/积分 if (useMoney > 0 || useIntegral > 0 || useMoney2 > 0) { var userEntity = await _dbContext.Users.FindAsync(userId); if (userEntity != null) { if (useMoney > 0) { userEntity.Money -= useMoney; } if (useIntegral > 0) { userEntity.Integral -= useIntegral; } if (useMoney2 > 0) { userEntity.Money2 = (userEntity.Money2 ?? 0) - useMoney2; } } } // 创建订单 var order = new Order { UserId = userId, OrderNum = orderNum, OrderTotal = orderTotal, OrderZheTotal = orderTotal, Price = price, UseMoney = useMoney, UseIntegral = useIntegral, UseMoney2 = useMoney2, UseScore = 0, Zhe = 1, GoodsId = request.GoodsId, Num = 0, // 福利屋固定为0 GoodsPrice = goods.Price, GoodsTitle = goods.Title, GoodsImgurl = goods.ImgUrlDetail, PrizeNum = prizeNum, Status = price > 0 ? (byte)0 : (byte)1, // 需要微信支付则待支付,否则已支付 PayType = 1, OrderType = WelfareType, Addtime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds(), CouponId = request.CouponId > 0 ? request.CouponId : null, UseCoupon = 0, IsShouZhe = 0, IsFlw = 1, CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now }; _dbContext.Orders.Add(order); await _dbContext.SaveChangesAsync(); // 如果不需要微信支付,直接创建参与记录 if (price <= 0) { order.Status = 1; order.PayTime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds(); // 创建订单项(参与记录) for (int i = 0; i < prizeNum; i++) { var orderItem = new OrderItem { UserId = userId, OrderId = order.Id, GoodsId = request.GoodsId, Num = 0, OrderType = WelfareType, ShangId = 0, // 未开奖 GoodslistTitle = "", GoodslistImgurl = "", GoodslistMoney = 0, Addtime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds(), ParentGoodsListId = 0, CreatedAt = DateTime.Now, UpdatedAt = DateTime.Now }; _dbContext.OrderItems.Add(orderItem); } await _dbContext.SaveChangesAsync(); } await transaction.CommitAsync(); // 12. 返回结果 if (price > 0) { // 需要微信支付 return new WelfareBuyResponse { Status = 1, OrderNum = orderNum, PayParams = new { message = "请使用微信支付完成订单" } }; } else { // 余额支付成功 return new WelfareBuyResponse { Status = 0, OrderNum = orderNum }; } } catch (Exception ex) { await transaction.RollbackAsync(); _logger.LogError(ex, "福利屋购买失败: UserId={UserId}, GoodsId={GoodsId}", userId, request.GoodsId); throw new InvalidOperationException("购买失败,请刷新重试"); } } }