using HoneyBox.Core.Interfaces; using HoneyBox.Model.Data; using HoneyBox.Model.Entities; using HoneyBox.Model.Models.Auth; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; namespace HoneyBox.Core.Services; /// /// 用户服务实现 /// public class UserService : BaseService, IUserService { private readonly ILogger _logger; public UserService(HoneyBoxDbContext dbContext, ILogger logger) : base(dbContext) { _logger = logger; } /// public async Task GetUserByIdAsync(int userId) { return await _dbSet.FirstOrDefaultAsync(u => u.Id == userId); } /// public async Task GetUserByOpenIdAsync(string openId) { if (string.IsNullOrWhiteSpace(openId)) return null; return await _dbSet.FirstOrDefaultAsync(u => u.OpenId == openId); } /// public async Task GetUserByUnionIdAsync(string unionId) { if (string.IsNullOrWhiteSpace(unionId)) return null; return await _dbSet.FirstOrDefaultAsync(u => u.UnionId == unionId); } /// public async Task GetUserByMobileAsync(string mobile) { if (string.IsNullOrWhiteSpace(mobile)) return null; return await _dbSet.FirstOrDefaultAsync(u => u.Mobile == mobile); } /// public async Task CreateUserAsync(CreateUserDto dto) { if (dto == null) throw new ArgumentNullException(nameof(dto)); // Generate UID var uid = GenerateUid(); var user = new User { OpenId = dto.OpenId ?? string.Empty, UnionId = dto.UnionId, Mobile = dto.Mobile, Uid = uid, Nickname = dto.Nickname ?? $"User{Random.Shared.Next(1000, 9999)}", HeadImg = dto.Headimg ?? string.Empty, Pid = dto.Pid, ClickId = dto.ClickId, Money = 0, Money2 = 0, Integral = 0, Score = 0, Vip = 0, Status = 1, IsTest = 0, CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow }; await _dbSet.AddAsync(user); await _dbContext.SaveChangesAsync(); _logger.LogInformation($"User created: Id={user.Id}, Uid={user.Uid}, OpenId={user.OpenId}"); return user; } /// public async Task UpdateUserAsync(int userId, UpdateUserDto dto) { if (dto == null) throw new ArgumentNullException(nameof(dto)); var user = await GetUserByIdAsync(userId); if (user == null) throw new InvalidOperationException($"User with id {userId} not found"); if (!string.IsNullOrWhiteSpace(dto.Nickname)) user.Nickname = dto.Nickname; if (!string.IsNullOrWhiteSpace(dto.Headimg)) user.HeadImg = dto.Headimg; if (!string.IsNullOrWhiteSpace(dto.Mobile)) user.Mobile = dto.Mobile; if (!string.IsNullOrWhiteSpace(dto.UnionId)) user.UnionId = dto.UnionId; user.UpdatedAt = DateTime.UtcNow; _dbSet.Update(user); await _dbContext.SaveChangesAsync(); _logger.LogInformation($"User updated: Id={user.Id}"); } /// public async Task GetUserInfoAsync(int userId) { var user = await GetUserByIdAsync(userId); if (user == null) return null; var couponCount = await _dbContext.CouponReceives .Where(cr => cr.UserId == userId && cr.State == 0) .CountAsync(); var registrationDays = (int)(DateTime.UtcNow - user.CreatedAt).TotalDays; var maskedMobile = MaskMobileNumber(user.Mobile); var mobileIs = string.IsNullOrWhiteSpace(user.Mobile) ? 0 : 1; // 计算权益等级信息 var quanYiLevel = await CalculateQuanYiLevelAsync(user.Score); return new UserInfoDto { Id = user.Id, Uid = user.Uid, Nickname = user.Nickname, Headimg = user.HeadImg, Mobile = maskedMobile, MobileIs = mobileIs, Money = user.Money, Money2 = user.Money2 ?? 0, Integral = user.Integral, Score = user.Score, Vip = user.Vip, VipImgurl = GetVipImageUrl(user.Vip), Coupon = couponCount, Day = registrationDays, QuanYiLevel = quanYiLevel }; } /// /// 计算用户权益等级信息 /// /// 用户欧气值 /// 权益等级DTO private async Task CalculateQuanYiLevelAsync(decimal score) { var userScore = (int)score; // 获取所有权益等级,按所需积分升序排列 var levels = await _dbContext.EquityLevels .Where(e => e.DeletedAt == null) .OrderBy(e => e.RequiredPoints) .ToListAsync(); if (!levels.Any()) { return new QuanYiLevelDto { Level = 0, Cha = -1, Jindu = 0 }; } // 找到当前等级和下一等级 int currentLevel = 0; int currentLevelPoints = 0; int nextLevelPoints = 0; bool isMaxLevel = false; for (int i = 0; i < levels.Count; i++) { if (userScore >= levels[i].RequiredPoints) { currentLevel = levels[i].Level; currentLevelPoints = levels[i].RequiredPoints; if (i + 1 < levels.Count) { nextLevelPoints = levels[i + 1].RequiredPoints; } else { isMaxLevel = true; } } else { if (currentLevel == 0) { // 用户还没达到第一级 nextLevelPoints = levels[i].RequiredPoints; } break; } } // 计算差值和进度 int cha = isMaxLevel ? -1 : nextLevelPoints - userScore; int jindu = 0; if (isMaxLevel) { jindu = 100; } else if (nextLevelPoints > currentLevelPoints) { var progress = (userScore - currentLevelPoints) * 100 / (nextLevelPoints - currentLevelPoints); jindu = Math.Max(0, Math.Min(100, progress)); } return new QuanYiLevelDto { Level = currentLevel, Cha = cha, Jindu = jindu }; } /// public async Task CalculateVipLevelAsync(int userId, int currentVip) { var user = await GetUserByIdAsync(userId); if (user == null) return currentVip; // Get all VIP levels ordered by level var vipLevels = await _dbContext.VipLevels .Where(v => v.DeletedAt == null) .OrderBy(v => v.Level) .ToListAsync(); if (!vipLevels.Any()) return currentVip; // Calculate VIP level based on total spending (Money) var totalSpending = user.Money; int newVipLevel = 0; foreach (var vipLevel in vipLevels) { if (totalSpending >= vipLevel.Number) { newVipLevel = vipLevel.Level; } else { break; } } return newVipLevel; } /// /// Generate a unique UID for new user /// private string GenerateUid() { // Generate a numeric UID based on timestamp and random number var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); var random = Random.Shared.Next(1000, 9999); return $"{timestamp}{random}"; } /// /// Mask mobile number for privacy (e.g., 13812345678 -> 138****5678) /// private string? MaskMobileNumber(string? mobile) { if (string.IsNullOrWhiteSpace(mobile) || mobile.Length < 11) return null; return $"{mobile.Substring(0, 3)}****{mobile.Substring(mobile.Length - 4)}"; } /// /// Get VIP image URL based on VIP level /// private string? GetVipImageUrl(int vipLevel) { if (vipLevel <= 0) return null; // Return a placeholder URL - actual URLs should be configured return $"https://example.com/vip/level_{vipLevel}.png"; } }