HaniBlindBox/server/HoneyBox/src/HoneyBox.Core/Services/InvitationService.cs
2026-01-04 01:47:02 +08:00

260 lines
7.9 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.Models.Invitation;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System.Text.Json;
namespace HoneyBox.Core.Services;
/// <summary>
/// 推荐服务实现
/// </summary>
public class InvitationService : IInvitationService
{
private readonly HoneyBoxDbContext _dbContext;
private readonly ILogger<InvitationService> _logger;
private const int PageSize = 15;
public InvitationService(HoneyBoxDbContext dbContext, ILogger<InvitationService> logger)
{
_dbContext = dbContext;
_logger = logger;
}
/// <inheritdoc />
public async Task<InvitationInfoResponse> GetInvitationInfoAsync(int userId, int page)
{
// 获取被邀请用户列表pid = userId 且 status = 1
var query = _dbContext.Users
.Where(u => u.Pid == userId && u.Status == 1)
.OrderByDescending(u => u.Id);
// 获取总数
var totalCount = await query.CountAsync();
// 计算分页
var totalPages = (int)Math.Ceiling((double)totalCount / PageSize);
var skip = (page - 1) * PageSize;
// 获取当前页数据
var invitedUsers = await query
.Skip(skip)
.Take(PageSize)
.Select(u => new
{
u.Id,
u.Nickname,
u.HeadImg,
u.Pid,
u.CreatedAt
})
.ToListAsync();
// 计算每个被邀请用户带来的佣金
var invitationRecords = new List<InvitationRecordDto>();
foreach (var user in invitedUsers)
{
var commissionMoney = await CalculateCommissionMoneyAsync(userId, user.Id);
invitationRecords.Add(new InvitationRecordDto
{
Id = user.Id,
Nickname = user.Nickname,
Headimg = user.HeadImg,
Pid = user.Pid,
Addtime = user.CreatedAt.ToString("yyyy-MM-dd HH:mm:ss"),
CommissionMoney = commissionMoney
});
}
// 计算总奖励金额
var totalMoney = await CalculateTotalRewardAsync(userId);
// 获取分享配置
var shareTitle = await GetShareTitleAsync();
var shareImage = string.Empty; // 海报图片需要单独生成,这里暂时返回空
return new InvitationInfoResponse
{
ShareTitle = shareTitle,
ShareImage = shareImage,
Count = totalCount,
Money = totalMoney,
Data = invitationRecords,
LastPage = totalPages
};
}
/// <inheritdoc />
public async Task<BindInviteCodeResponse> BindInviteCodeAsync(int userId, string inviteCode)
{
// 获取当前用户
var user = await _dbContext.Users.FindAsync(userId);
if (user == null)
{
return new BindInviteCodeResponse
{
Success = false,
Message = "用户不存在"
};
}
// 检查是否已绑定推荐人
if (user.Pid > 0)
{
return new BindInviteCodeResponse
{
Success = false,
Message = "您已绑定过邀请码"
};
}
// 检查是否在注册24小时内
var registerTime = user.CreatedAt;
var deadline = registerTime.AddHours(24);
if (DateTime.Now > deadline)
{
return new BindInviteCodeResponse
{
Success = false,
Message = "新用户注册24小时内才可以绑定邀请码"
};
}
// 检查是否绑定自己
if (user.Uid == inviteCode)
{
return new BindInviteCodeResponse
{
Success = false,
Message = "不能绑定自己"
};
}
// 查找邀请人
var inviter = await _dbContext.Users
.FirstOrDefaultAsync(u => u.Uid == inviteCode);
if (inviter == null)
{
return new BindInviteCodeResponse
{
Success = false,
Message = "邀请码不存在"
};
}
// 绑定邀请码
user.Pid = inviter.Id;
user.UpdatedAt = DateTime.Now;
await _dbContext.SaveChangesAsync();
_logger.LogInformation("用户 {UserId} 成功绑定邀请码 {InviteCode}推荐人ID: {InviterId}",
userId, inviteCode, inviter.Id);
return new BindInviteCodeResponse
{
Success = true,
Message = "绑定成功"
};
}
#region
/// <summary>
/// 计算某个被邀请用户带来的佣金
/// 佣金来源type=5 的 ProfitMoney 和 ProfitIntegral 记录
/// </summary>
/// <param name="inviterId">邀请人ID</param>
/// <param name="invitedUserId">被邀请用户ID</param>
/// <returns>佣金金额</returns>
private async Task<decimal> CalculateCommissionMoneyAsync(int inviterId, int invitedUserId)
{
// 从 ProfitMoney 获取佣金type=5, share_uid=被邀请用户ID, change_money>0
var moneyCommission = await _dbContext.ProfitMoneys
.Where(p => p.UserId == inviterId)
.Where(p => p.Type == 5)
.Where(p => p.ShareUid == invitedUserId)
.Where(p => p.ChangeMoney > 0)
.SumAsync(p => p.ChangeMoney);
// 从 ProfitIntegral 获取佣金type=5, share_uid=被邀请用户ID, change_money>0
var integralCommission = await _dbContext.ProfitIntegrals
.Where(p => p.UserId == inviterId)
.Where(p => p.Type == 5)
.Where(p => p.ShareUid == invitedUserId)
.Where(p => p.ChangeMoney > 0)
.SumAsync(p => p.ChangeMoney);
// 积分转换为金额除以100
if (integralCommission > 0)
{
moneyCommission += Math.Round(integralCommission / 100, 2);
}
return moneyCommission;
}
/// <summary>
/// 计算用户的总推荐奖励金额
/// </summary>
/// <param name="userId">用户ID</param>
/// <returns>总奖励金额</returns>
private async Task<decimal> CalculateTotalRewardAsync(int userId)
{
// 从 ProfitMoney 获取总佣金type=5, change_money>0
var moneyReward = await _dbContext.ProfitMoneys
.Where(p => p.UserId == userId)
.Where(p => p.Type == 5)
.Where(p => p.ChangeMoney > 0)
.SumAsync(p => p.ChangeMoney);
// 从 ProfitIntegral 获取总佣金type=5, change_money>0
var integralReward = await _dbContext.ProfitIntegrals
.Where(p => p.UserId == userId)
.Where(p => p.Type == 5)
.Where(p => p.ChangeMoney > 0)
.SumAsync(p => p.ChangeMoney);
// 积分转换为金额除以100
if (integralReward > 0)
{
moneyReward += Math.Round(integralReward / 100, 2);
}
return moneyReward;
}
/// <summary>
/// 获取分享标题配置
/// </summary>
/// <returns>分享标题</returns>
private async Task<string> GetShareTitleAsync()
{
var config = await _dbContext.Configs
.FirstOrDefaultAsync(c => c.ConfigKey == "base");
if (config?.ConfigValue == null)
{
return string.Empty;
}
try
{
var jsonDoc = JsonSerializer.Deserialize<JsonElement>(config.ConfigValue);
if (jsonDoc.TryGetProperty("share_title", out var shareTitle))
{
return shareTitle.GetString() ?? string.Empty;
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, "解析分享配置失败");
}
return string.Empty;
}
#endregion
}