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("购买失败,请刷新重试");
}
}
}