签到与活动配置:后台配置接口、用户签到流程、UserEntity 扩展

This commit is contained in:
2026-10-19 00:24:22 +08:00
parent d7a672cdf4
commit ff2b779a56
13 changed files with 569 additions and 425 deletions
+3 -1
View File
@@ -92,7 +92,9 @@ namespace UserService.User
Task<(bool isok, string msg)> BuyDiamondPayCallBack(string orderId);
Task<(bool isok, string msg, long gold)> Sign(LoginUser loginUser);
Task<(bool isok, string msg, SignRewardResult result)> Sign(LoginUser loginUser);
Task<SignStatusResult> GetSignStatus(LoginUser loginUser);
Task<(bool isok, string msg)> ChangeCannon(string number, LoginUser loginUser);
@@ -0,0 +1,38 @@
using CommonDomain.BaseModel;
namespace UserService.Param
{
/// <summary>签到奖励返回</summary>
public class SignRewardResult
{
/// <summary>本次签到对应第几天(1~7)</summary>
public int Day { get; set; } = 0;
public long Gold { get; set; } = 0;
public int Diamond { get; set; } = 0;
public List<BaseProductCount> Product { get; set; } = new List<BaseProductCount>();
}
/// <summary>签到状态返回</summary>
public class SignStatusResult
{
public bool IsOpen { get; set; } = false;
/// <summary>勾选=不可中断(漏签不回退);未勾选=可中断(漏签重置)</summary>
public bool CannotInterrupt { get; set; } = false;
/// <summary>当前周期已完成到第几天(0~7)</summary>
public int SignDay { get; set; } = 0;
/// <summary>今天签到对应的天数(已签则为其已签天数;未签则为下一次目标天数)</summary>
public int TodayDay { get; set; } = 0;
/// <summary>今天是否已签到</summary>
public bool IsTodaySigned { get; set; } = false;
/// <summary>7 天奖励配置</summary>
public List<SignConfig> Days { get; set; } = new List<SignConfig>();
}
}
+88 -51
View File
@@ -1364,36 +1364,107 @@ namespace UserService.User
}
public async Task<(bool isok, string msg, long gold)> Sign(LoginUser loginUser)
public async Task<(bool isok, string msg, SignRewardResult result)> Sign(LoginUser loginUser)
{
var user = await GetUser(loginUser.UserId);
if (user == null)
throw new BusinessException("用户不存在");
// if (user.Assets.VipLevel == 0)
// if (user.Sign.IsSign)
var activityConfig = await _activityConfigService.Get();
var signList = activityConfig.SignConfigs;
if (signList.Count == 0)
var signConfig = activityConfig?.SignActivityConfig;
if (signConfig == null || !signConfig.IsOpen)
throw new BusinessException("签到活动未开启");
if (signConfig.Days == null || signConfig.Days.Count == 0)
throw new BusinessException("签到配置不存在");
var sign = GetRandomSignConfig(activityConfig);
if (user.Sign == null)
user.Sign = new SignInfo();
var gold = Convert.ToInt64(sign.Gold * (1 + user.Assets.VipSignInAdd));
var now = DateTime.Now;
var today = now.Date;
DateTime? lastSignDate = user.Sign.SignTime > 0 ? user.Sign.SignTime.ToDateTime().Date : (DateTime?)null;
if (lastSignDate.HasValue && lastSignDate.Value == today)
throw new BusinessException("今日已签到");
user.Sign.IsSign = true;
user.Sign.SignTime = DateTime.Now.ToTimeStamp();
var day = CalcSignDay(user.Sign.SignDay, lastSignDate, today, signConfig.CannotInterrupt);
var dayConfig = signConfig.Days.FirstOrDefault(c => c.Day == day) ?? signConfig.Days.OrderBy(c => c.Day).First();
if (dayConfig == null || dayConfig.GiftList == null || dayConfig.GiftList.Count == 0)
throw new BusinessException($"第{day}天签到奖励未配置");
var gift = GetGift(dayConfig.GiftList);
var gold = Convert.ToInt64(gift.Gold * (1 + user.Assets.VipSignInAdd));
var res = await UpdateAssets(new UserAssetParam
{
UserId = user.Id,
ChangeType = UserAssetChangeTypeEnum.增加,
Source = RewardSource.签到,
Remark = $"第{day}天签到奖励",
Gold = gold,
Diamond = gift.Diamond,
RewardItems = gift.Product
});
if (!res.isok)
return (false, res.msg, null);
var signUpdate = Builders<UserEntity>.Update
.Set(p => p.Sign.IsSign, true)
.Set(p => p.Sign.SignTime, now.ToTimeStamp())
.Set(p => p.Sign.SignDay, day);
await _userMongo.UpdateByIdAsync(user.Id, signUpdate);
return (true, "签到成功", new SignRewardResult
{
Day = day,
Gold = gold,
Diamond = gift.Diamond,
Product = gift.Product ?? new List<BaseProductCount>()
});
}
UserReward userReward = new UserReward() { UserId = user.Id, ChangeCount = gold, CurrencyType = 1, Remark = "签到获取金币", Source = RewardSource.签到, Type = 1, BeforeCount = user.Assets.Gold };
user.Assets.Gold += gold;
userReward.AfterCount = user.Assets.Gold;
await _rewardMongo.InsertOneAsync(userReward);
public async Task<SignStatusResult> GetSignStatus(LoginUser loginUser)
{
var user = await GetUser(loginUser.UserId);
var activityConfig = await _activityConfigService.Get();
var signConfig = activityConfig?.SignActivityConfig;
await _userMongo.ReplaceOneAsync(user);
var result = new SignStatusResult
{
IsOpen = signConfig?.IsOpen ?? false,
CannotInterrupt = signConfig?.CannotInterrupt ?? false,
Days = signConfig?.Days?.OrderBy(c => c.Day).ToList() ?? new List<SignConfig>()
};
return (true, "签到成功", gold);
var today = DateTime.Now.Date;
DateTime? lastSignDate = user?.Sign != null && user.Sign.SignTime > 0
? user.Sign.SignTime.ToDateTime().Date
: (DateTime?)null;
result.SignDay = user?.Sign?.SignDay ?? 0;
result.IsTodaySigned = lastSignDate.HasValue && lastSignDate.Value == today;
result.TodayDay = result.IsTodaySigned
? result.SignDay
: CalcSignDay(result.SignDay, lastSignDate, today, result.CannotInterrupt);
return result;
}
private const int SignCycleDays = 7;
/// <summary>计算本次签到对应的天数(1~7)</summary>
private static int CalcSignDay(int currentDay, DateTime? lastSignDate, DateTime today, bool cannotInterrupt)
{
// 上次签到为昨天:连续签到,天数顺延
if (lastSignDate.HasValue && lastSignDate.Value.Date == today.AddDays(-1))
return currentDay > 0 ? currentDay % SignCycleDays + 1 : 1;
// 漏签:不可中断则继续顺延(累计循环);可中断则重置回第1天
if (currentDay > 0 && cannotInterrupt)
return currentDay % SignCycleDays + 1;
return 1;
}
@@ -2328,40 +2399,6 @@ namespace UserService.User
}
public SignConfig GetRandomSignConfig(ActivityConfig activityConfig)
{
if (activityConfig?.SignConfigs == null || !activityConfig.SignConfigs.Any())
{
return null;
}
var configs = activityConfig.SignConfigs;
var totalProbability = configs.Sum(c => Math.Max(0, c.Probability));
if (totalProbability <= 0)
{
return null;
}
var randomValue = System.Random.Shared.NextDouble() * totalProbability;
double cumulativeProbability = 0;
foreach (var config in configs)
{
var currentProbability = Math.Max(0, config.Probability);
cumulativeProbability += currentProbability;
if (randomValue <= cumulativeProbability)
{
return config;
}
}
return configs.LastOrDefault();
}
public GiftResponse GetGift(List<GiftConfig> giftConfigs)
{
GiftResponse response = new GiftResponse();