添加项目文件。
This commit is contained in:
@@ -0,0 +1,202 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using MongoRepository;
|
||||
using MongoDB.Driver;
|
||||
using CommonDomain;
|
||||
using UserDomain.Entity;
|
||||
|
||||
namespace CommonService
|
||||
{
|
||||
public class LotteryService : ILotteryService
|
||||
{
|
||||
|
||||
|
||||
private readonly IMongoBaseRepository<LotteryRecord> _recordRepo;
|
||||
|
||||
private readonly IMongoBaseRepository<LotteryUserStatus> _userStatusRepo;
|
||||
|
||||
private readonly IUserService _userService;
|
||||
|
||||
private readonly ICapPublisher _capPublisher;
|
||||
|
||||
public LotteryService(
|
||||
IMongoBaseRepository<ActivityConfig> activityRepo,
|
||||
IMongoBaseRepository<LotteryRecord> recordRepo,
|
||||
IMongoBaseRepository<LotteryUserStatus> userStatusRepo,
|
||||
IUserService userService,
|
||||
ICapPublisher capPublisher)
|
||||
{
|
||||
_activityRepo = activityRepo;
|
||||
_recordRepo = recordRepo;
|
||||
_userStatusRepo = userStatusRepo;
|
||||
_userService = userService;
|
||||
_capPublisher = capPublisher;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public async Task<LotteryUserStatus?> GetUserStatus(string userId)
|
||||
{
|
||||
var status = await _userStatusRepo.FindOneAsync(s => s.UserId == userId && s.ActivityId == activityId);
|
||||
if (status == null)
|
||||
{
|
||||
status = new LotteryUserStatus
|
||||
{
|
||||
UserId = userId
|
||||
};
|
||||
await _userStatusRepo.InsertOneAsync(status);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
public async Task<(bool success, string message, LotteryPrize? prize, long cost)> Draw(string userId)
|
||||
{
|
||||
var activity = await GetActivity(activityId);
|
||||
if (activity == null)
|
||||
return (false, "活动不存在或未开启", null, 0);
|
||||
|
||||
var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||
if (now < activity.StartTime)
|
||||
return (false, "活动未开始", null, 0);
|
||||
if (now > activity.EndTime)
|
||||
return (false, "活动已结束", null, 0);
|
||||
|
||||
var userStatus = await GetUserStatus(userId, activityId);
|
||||
if (userStatus.IsFinished)
|
||||
return (false, "您已抽完所有奖项,活动结束", null, 0);
|
||||
|
||||
if (activity.UserMaxDraw > 0 && userStatus.TotalDrawCount >= activity.UserMaxDraw)
|
||||
return (false, "已达最大抽奖次数", null, 0);
|
||||
|
||||
var costIndex = Math.Min(userStatus.TotalDrawCount, activity.Costs.Count - 1);
|
||||
var cost = activity.Costs[costIndex];
|
||||
|
||||
var user = await _userService.GetUser(userId);
|
||||
if (user == null)
|
||||
return (false, "用户不存在", null, 0);
|
||||
if (user.Assets.Gold < cost)
|
||||
return (false, "金币不足", null, 0);
|
||||
|
||||
var level = DrawLevel(activity.Pools);
|
||||
if (level == null)
|
||||
return (false, "奖池已空", null, 0);
|
||||
|
||||
var prize = DrawPrize(level, userStatus.DrawnPrizeIds);
|
||||
if (prize == null)
|
||||
{
|
||||
prize = DrawPrizeFromAll(activity.Pools, userStatus.DrawnPrizeIds);
|
||||
if (prize == null)
|
||||
return (false, "所有奖项已抽完", null, 0);
|
||||
level = activity.Pools.FirstOrDefault(p => p.PrizeList.Any(x => x.PrizeId == prize.PrizeId));
|
||||
}
|
||||
|
||||
if (prize.TotalCount > 0 && prize.DrawnCount >= prize.TotalCount)
|
||||
return (false, "该奖项已抽完", null, 0);
|
||||
|
||||
user.Assets.Gold -= cost;
|
||||
await _userService.UpdateUser(user);
|
||||
|
||||
var record = new LotteryRecord
|
||||
{
|
||||
UserId = userId,
|
||||
ActivityId = activityId,
|
||||
PrizeId = prize.PrizeId,
|
||||
Level = level.Level,
|
||||
Cost = cost,
|
||||
DrawTime = now
|
||||
};
|
||||
await _recordRepo.InsertOneAsync(record);
|
||||
|
||||
userStatus.DrawnPrizeIds.Add(prize.PrizeId);
|
||||
userStatus.TotalDrawCount++;
|
||||
|
||||
var allPrizeIds = activity.Pools.SelectMany(p => p.PrizeList).Select(x => x.PrizeId).ToList();
|
||||
if (allPrizeIds.All(id => userStatus.DrawnPrizeIds.Contains(id)))
|
||||
{
|
||||
userStatus.IsFinished = true;
|
||||
}
|
||||
await _userStatusRepo.ReplaceOneAsync(userStatus);
|
||||
|
||||
prize.DrawnCount++;
|
||||
|
||||
await _capPublisher.Publish("Lottery.DrawPrize", new LotteryDrawMessage
|
||||
{
|
||||
UserId = userId,
|
||||
PrizeId = prize.PrizeId,
|
||||
PrizeName = prize.Name,
|
||||
Type = prize.Type,
|
||||
Count = prize.Count,
|
||||
OtherId = prize.OtherId
|
||||
});
|
||||
|
||||
return (true, "抽奖成功", prize, cost);
|
||||
}
|
||||
|
||||
private LotteryPoolLevel? DrawLevel(List<LotteryPoolLevel> pools)
|
||||
{
|
||||
var availablePools = pools.Where(p =>
|
||||
p.PrizeList.Any(x => !x.TotalCount.Equals(0) && x.DrawnCount < x.TotalCount)).ToList();
|
||||
if (!availablePools.Any())
|
||||
return null;
|
||||
|
||||
long totalWeight = availablePools.Sum(p => (long)p.Weight);
|
||||
if (totalWeight <= 0)
|
||||
return null;
|
||||
|
||||
long randomValue = NextInt64(0, totalWeight);
|
||||
long currentWeightSum = 0;
|
||||
|
||||
foreach (var pool in availablePools)
|
||||
{
|
||||
currentWeightSum += pool.Weight;
|
||||
if (randomValue < currentWeightSum)
|
||||
return pool;
|
||||
}
|
||||
return availablePools.LastOrDefault();
|
||||
}
|
||||
|
||||
private LotteryPrize? DrawPrize(LotteryPoolLevel level, List<string> drawnPrizeIds)
|
||||
{
|
||||
var availablePrizes = level.PrizeList
|
||||
.Where(p => !drawnPrizeIds.Contains(p.PrizeId) &&
|
||||
(p.TotalCount == 0 || p.DrawnCount < p.TotalCount))
|
||||
.ToList();
|
||||
if (!availablePrizes.Any())
|
||||
return null;
|
||||
|
||||
int totalWeight = availablePrizes.Sum(p => p.Weight);
|
||||
if (totalWeight <= 0)
|
||||
return null;
|
||||
|
||||
int randomValue = Next(0, totalWeight);
|
||||
int currentWeightSum = 0;
|
||||
|
||||
foreach (var prize in availablePrizes)
|
||||
{
|
||||
currentWeightSum += prize.Weight;
|
||||
if (randomValue < currentWeightSum)
|
||||
return prize;
|
||||
}
|
||||
return availablePrizes.LastOrDefault();
|
||||
}
|
||||
|
||||
private LotteryPrize? DrawPrizeFromAll(List<LotteryPoolLevel> pools, List<string> drawnPrizeIds)
|
||||
{
|
||||
foreach (var pool in pools.OrderByDescending(p => p.Weight))
|
||||
{
|
||||
var prize = DrawPrize(pool, drawnPrizeIds);
|
||||
if (prize != null)
|
||||
return prize;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<List<string>> GetUserDrawnPrizes(string userId, string activityId)
|
||||
{
|
||||
var status = await GetUserStatus(userId, activityId);
|
||||
return status?.DrawnPrizeIds ?? new List<string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user