feat: 完成多模块功能迭代与优化
1. 新增宠物皮肤初始枚举值、下拉列表接口及相关DTO 2. 完善商品实体与DTO,新增虚拟商品标记和类型ID字段 3. 重构用户认证体系,支持多用户切换并重新生成JWT令牌 4. 新增签到配置管理全套功能,包括增删改查和状态管理 5. 优化模型验证过滤器和基础响应类的命名规范 6. 新增补签功能,完善签到服务逻辑 7. 拆分用户详情DTO,新增各子数据分页查询接口 8. 重构微信控制器的用户ID获取逻辑,统一使用激活用户ID 9. 修复背包服务中补签卡的扣减逻辑 10. 新增家长姓名修改接口和相关服务实现
This commit is contained in:
@ -152,15 +152,16 @@ public class WeChatAuthService(
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 切换用户(同一 WxUser 下切换 User 身份,JWT 基于 WxUser 无需重新生成)
|
||||
/// 切换用户(同一 WxUser 下切换 User 身份,重新生成 Token)
|
||||
/// </summary>
|
||||
public async Task<WeChatSwitchUserOutput> SwitchUserAsync(long wxUserId, WeChatSwitchUserInput input)
|
||||
public async Task<WeChatSwitchUserOutput> SwitchUserAsync(long wxUserId, long currentUserId, WeChatSwitchUserInput input)
|
||||
{
|
||||
logger.LogInformation("切换用户,WxUserId: {WxUserId}, 目标 UserId: {TargetUserId}", wxUserId, input.UserId);
|
||||
logger.LogInformation("切换用户,WxUserId: {WxUserId}, 当前 UserId: {CurrentUserId}, 目标 UserId: {TargetUserId}",
|
||||
wxUserId, currentUserId, input.UserId);
|
||||
|
||||
// 查询目标用户
|
||||
var targetUser = await wxUserRepository.Context.Queryable<Users>()
|
||||
.Where(u => u.Id == input.UserId)
|
||||
.Where(u => u.Id == input.UserId && !u.IsDeleted)
|
||||
.FirstAsync();
|
||||
|
||||
if (targetUser == null)
|
||||
@ -179,23 +180,32 @@ public class WeChatAuthService(
|
||||
// 更新 IsLastOnline(清除所有,设置目标为 true)
|
||||
await wxUserRepository.Context.Updateable<Users>()
|
||||
.SetColumns(u => u.IsLastOnline == false)
|
||||
.Where(u => u.WxUserId == wxUserId )
|
||||
.Where(u => u.WxUserId == wxUserId && !u.IsDeleted)
|
||||
.ExecuteCommandAsync();
|
||||
|
||||
await wxUserRepository.Context.Updateable<Users>()
|
||||
.SetColumns(u => u.IsLastOnline == true)
|
||||
.Where(u => u.Id == input.UserId )
|
||||
.Where(u => u.Id == input.UserId && !u.IsDeleted)
|
||||
.ExecuteCommandAsync();
|
||||
|
||||
logger.LogInformation("IsLastOnline 已更新,目标用户 {UserId} 设为 true", input.UserId);
|
||||
|
||||
// 重新查询目标用户获取最新数据
|
||||
var refreshedUser = await wxUserRepository.Context.Queryable<Users>()
|
||||
.Where(u => u.Id == input.UserId)
|
||||
.Where(u => u.Id == input.UserId && !u.IsDeleted)
|
||||
.FirstAsync();
|
||||
|
||||
// 生成新 JWT Token(WxUserId + 新 UserId)
|
||||
var jwtSettings = GetJwtSettings();
|
||||
var token = JwtHelper.GenerateToken(wxUserId, refreshedUser.Id, refreshedUser.Name ?? string.Empty, jwtSettings);
|
||||
|
||||
// 清除旧 Redis Token,写入新 Token
|
||||
await RedisHelper.DelAsync($"{TokenKeyPrefix}:{currentUserId}");
|
||||
await RedisHelper.SetAsync($"{TokenKeyPrefix}:{refreshedUser.Id}", token, TimeSpan.FromMinutes(jwtSettings.ExpiryMinutes));
|
||||
|
||||
return new WeChatSwitchUserOutput
|
||||
{
|
||||
Token = token,
|
||||
User = MapUserToOutput(refreshedUser)
|
||||
};
|
||||
}
|
||||
@ -263,21 +273,66 @@ public class WeChatAuthService(
|
||||
return MapUserToOutput(newUser);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 修改家长名字(WxUser.Name)
|
||||
/// </summary>
|
||||
public async Task<WxUserInfoOutput> UpdateWxUserNameAsync(long wxUserId, UpdateWxUserNameInput input)
|
||||
{
|
||||
logger.LogInformation("修改家长名字,WxUserId: {WxUserId}, NewName: {Name}", wxUserId, input.Name);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(input.Name))
|
||||
throw new BusinessException("名字不能为空", 400);
|
||||
|
||||
var wxUser = await wxUserRepository.Context.Queryable<WxUser>()
|
||||
.Where(w => w.Id == wxUserId && !w.IsDeleted)
|
||||
.FirstAsync();
|
||||
|
||||
if (wxUser == null)
|
||||
throw new BusinessException("微信用户不存在", 404);
|
||||
|
||||
await wxUserRepository.Context.Updateable<WxUser>()
|
||||
.SetColumns(w => w.Name == input.Name.Trim())
|
||||
.SetColumns(w => w.UpdatedAt == DateTime.Now)
|
||||
.SetColumns(w => w.UpdatedBy == wxUserId.ToString())
|
||||
.Where(w => w.Id == wxUserId)
|
||||
.ExecuteCommandAsync();
|
||||
|
||||
wxUser.Name = input.Name.Trim();
|
||||
|
||||
logger.LogInformation("家长名字修改成功,WxUserId: {WxUserId}, NewName: {Name}", wxUserId, input.Name);
|
||||
|
||||
return new WxUserInfoOutput
|
||||
{
|
||||
Id = wxUser.Id,
|
||||
OpenId = wxUser.OpenId,
|
||||
UnionId = wxUser.UnionId,
|
||||
Name = wxUser.Name,
|
||||
AvatarUrl = wxUser.AvatarUrl,
|
||||
Phone = wxUser.Phone
|
||||
};
|
||||
}
|
||||
|
||||
#region 私有辅助方法
|
||||
|
||||
/// <summary>
|
||||
/// 构建登录输出(JWT 基于 WxUser,不绑定具体 User)
|
||||
/// 构建登录输出(JWT 同时携带 WxUserId 和当前激活 UserId)
|
||||
/// </summary>
|
||||
private async Task<WeChatLoginOutput> BuildLoginOutputAsync(WxUser wxUser, List<Users> users)
|
||||
{
|
||||
var jwtSettings = GetJwtSettings();
|
||||
var token = JwtHelper.GenerateToken(wxUser.Id, wxUser.Name ?? wxUser.OpenId, jwtSettings);
|
||||
var activeUser = users.FirstOrDefault(u => u.IsLastOnline) ?? users.FirstOrDefault();
|
||||
|
||||
await RedisHelper.SetAsync($"{TokenKeyPrefix}:{wxUser.Id}", token, TimeSpan.FromMinutes(jwtSettings.ExpiryMinutes));
|
||||
var userId = activeUser?.Id ?? 0L;
|
||||
var userName = activeUser?.Name ?? wxUser.Name ?? wxUser.OpenId;
|
||||
|
||||
var jwtSettings = GetJwtSettings();
|
||||
var token = JwtHelper.GenerateToken(wxUser.Id, userId, userName, jwtSettings);
|
||||
|
||||
await RedisHelper.SetAsync($"{TokenKeyPrefix}:{userId}", token, TimeSpan.FromMinutes(jwtSettings.ExpiryMinutes));
|
||||
|
||||
return new WeChatLoginOutput
|
||||
{
|
||||
Token = token,
|
||||
CurrentUserId = userId,
|
||||
WxUser = new WxUserInfoOutput
|
||||
{
|
||||
Id = wxUser.Id,
|
||||
|
||||
Reference in New Issue
Block a user