178 lines
5.1 KiB
C#
178 lines
5.1 KiB
C#
using MiAssessment.Core.Interfaces;
|
||
using MiAssessment.Model.Data;
|
||
using MiAssessment.Model.Entities;
|
||
using MiAssessment.Model.Models.Auth;
|
||
using Microsoft.EntityFrameworkCore;
|
||
using Microsoft.Extensions.Logging;
|
||
|
||
namespace MiAssessment.Core.Services;
|
||
|
||
/// <summary>
|
||
/// <20>û<EFBFBD><C3BB><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5>
|
||
/// </summary>
|
||
public class UserService : BaseService<User, long>, IUserService
|
||
{
|
||
private readonly ILogger<UserService> _logger;
|
||
|
||
public UserService(MiAssessmentDbContext dbContext, ILogger<UserService> logger)
|
||
: base(dbContext)
|
||
{
|
||
_logger = logger;
|
||
}
|
||
|
||
/// <inheritdoc/>
|
||
public async Task<User?> GetUserByIdAsync(long userId)
|
||
{
|
||
return await _dbSet.FirstOrDefaultAsync(u => u.Id == userId);
|
||
}
|
||
|
||
/// <inheritdoc/>
|
||
public async Task<User?> GetUserByOpenIdAsync(string openId)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(openId))
|
||
return null;
|
||
|
||
return await _dbSet.FirstOrDefaultAsync(u => u.OpenId == openId);
|
||
}
|
||
|
||
/// <inheritdoc/>
|
||
public async Task<User?> GetUserByUnionIdAsync(string unionId)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(unionId))
|
||
return null;
|
||
|
||
return await _dbSet.FirstOrDefaultAsync(u => u.UnionId == unionId);
|
||
}
|
||
|
||
/// <inheritdoc/>
|
||
public async Task<User?> GetUserByMobileAsync(string mobile)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(mobile))
|
||
return null;
|
||
|
||
return await _dbSet.FirstOrDefaultAsync(u => u.Phone == mobile);
|
||
}
|
||
|
||
/// <inheritdoc/>
|
||
public async Task<User> CreateUserAsync(CreateUserDto dto)
|
||
{
|
||
if (dto == null)
|
||
throw new ArgumentNullException(nameof(dto));
|
||
|
||
// <20><><EFBFBD><EFBFBD>ΨһUID
|
||
var uid = await GenerateUidAsync();
|
||
|
||
var user = new User
|
||
{
|
||
OpenId = dto.OpenId ?? string.Empty,
|
||
UnionId = dto.UnionId,
|
||
Phone = dto.Mobile,
|
||
Uid = uid,
|
||
Nickname = dto.Nickname ?? $"User{Random.Shared.Next(1000, 9999)}",
|
||
Avatar = dto.Headimg ?? string.Empty,
|
||
ParentUserId = dto.Pid > 0 ? dto.Pid : null,
|
||
Status = 1,
|
||
IsTest = 0,
|
||
CreateTime = DateTime.Now,
|
||
UpdateTime = DateTime.Now
|
||
};
|
||
|
||
await _dbSet.AddAsync(user);
|
||
await _dbContext.SaveChangesAsync();
|
||
|
||
_logger.LogInformation($"User created: Id={user.Id}, Uid={user.Uid}, OpenId={user.OpenId}");
|
||
|
||
return user;
|
||
}
|
||
|
||
/// <inheritdoc/>
|
||
public async Task UpdateUserAsync(long 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.Avatar = dto.Headimg;
|
||
|
||
if (!string.IsNullOrWhiteSpace(dto.Mobile))
|
||
user.Phone = dto.Mobile;
|
||
|
||
if (!string.IsNullOrWhiteSpace(dto.UnionId))
|
||
user.UnionId = dto.UnionId;
|
||
|
||
user.UpdateTime = DateTime.Now;
|
||
|
||
_dbSet.Update(user);
|
||
await _dbContext.SaveChangesAsync();
|
||
|
||
_logger.LogInformation($"User updated: Id={user.Id}");
|
||
}
|
||
|
||
/// <inheritdoc/>
|
||
public async Task<UserInfoDto?> GetUserInfoAsync(long userId)
|
||
{
|
||
var user = await GetUserByIdAsync(userId);
|
||
if (user == null)
|
||
return null;
|
||
|
||
var registrationDays = (int)(DateTime.Now - user.CreateTime).TotalDays;
|
||
|
||
var maskedMobile = MaskMobileNumber(user.Phone);
|
||
var mobileIs = string.IsNullOrWhiteSpace(user.Phone) ? 0 : 1;
|
||
|
||
return new UserInfoDto
|
||
{
|
||
Id = user.Id,
|
||
Uid = user.Uid,
|
||
Nickname = user.Nickname,
|
||
Headimg = user.Avatar,
|
||
Mobile = maskedMobile,
|
||
MobileIs = mobileIs,
|
||
Vip = 0, // 用户等级,待接入业务逻辑
|
||
Day = registrationDays
|
||
};
|
||
}
|
||
|
||
/// <inheritdoc/>
|
||
public Task<int> CalculateVipLevelAsync(long userId, int currentVip)
|
||
{
|
||
// VIP<49>ȼ<EFBFBD><C8BC><EFBFBD><EFBFBD>㹦<EFBFBD><E3B9A6><EFBFBD><EFBFBD><EFBFBD>Ƴ<EFBFBD><C6B3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0
|
||
return Task.FromResult(0);
|
||
}
|
||
|
||
/// <summary>
|
||
/// <20><><EFBFBD><EFBFBD>6λΨһ<CEA8>û<EFBFBD>UID
|
||
/// </summary>
|
||
private async Task<string> GenerateUidAsync()
|
||
{
|
||
const int maxAttempts = 10;
|
||
for (var i = 0; i < maxAttempts; i++)
|
||
{
|
||
var uid = Random.Shared.Next(100000, 999999).ToString();
|
||
var exists = await _dbSet.AnyAsync(u => u.Uid == uid);
|
||
if (!exists)
|
||
return uid;
|
||
}
|
||
// <20><><EFBFBD>ף<EFBFBD>ʹ<EFBFBD><CAB9>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD>6λ
|
||
return DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString()[^6..];
|
||
}
|
||
|
||
/// <summary>
|
||
/// Mask mobile number for privacy (e.g., 13812345678 -> 138****5678)
|
||
/// </summary>
|
||
private string? MaskMobileNumber(string? mobile)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(mobile) || mobile.Length < 11)
|
||
return null;
|
||
|
||
return $"{mobile.Substring(0, 3)}****{mobile.Substring(mobile.Length - 4)}";
|
||
}
|
||
}
|