HaniBlindBox/server/HoneyBox/src/HoneyBox.Core/Services/WelfareService.cs
2026-02-04 00:53:45 +08:00

1022 lines
35 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
/// <summary>
/// 福利屋服务实现
/// </summary>
public class WelfareService : IWelfareService
{
private readonly HoneyBoxDbContext _dbContext;
private readonly ILogger<WelfareService> _logger;
private const int WelfareType = 15; // 福利屋商品类型
public WelfareService(HoneyBoxDbContext dbContext, ILogger<WelfareService> logger)
{
_dbContext = dbContext;
_logger = logger;
}
/// <inheritdoc />
public async Task<WelfareListResponse> 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<Good> 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
};
}
/// <inheritdoc />
public async Task<WelfareDetailResponse> 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
};
}
/// <inheritdoc />
public async Task<List<ParticipantDto>> 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();
}
/// <inheritdoc />
public async Task<List<WinningRecordDto>> 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();
}
/// <inheritdoc />
public async Task<List<UserParticipationDto>> 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();
}
/// <inheritdoc />
public async Task<List<UserWinningDto>> 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();
}
/// <summary>
/// 将DateTime转换为Unix时间戳
/// </summary>
private static int ToUnixTimestamp(DateTime dateTime)
{
return (int)(dateTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds;
}
/// <inheritdoc />
public async Task<FuliwuListResponse> 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<Good> 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
};
}
/// <inheritdoc />
public async Task<WelfareBuyResponse> 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("购买失败,请刷新重试");
}
}
}