添加项目文件。

This commit is contained in:
2026-10-12 16:22:04 +08:00
parent 7c68a0ca0a
commit aad11be43d
1000 changed files with 120807 additions and 0 deletions
+202
View File
@@ -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>();
}
}
}