using System.Security.Claims;
using HoneyBox.Core.Interfaces;
using HoneyBox.Model.Base;
using HoneyBox.Model.Models.Asset;
using HoneyBox.Model.Models.Auth;
using HoneyBox.Model.Models.Vip;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace HoneyBox.Api.Controllers;
///
/// 用户控制器 - 处理用户信息、资产和VIP相关功能
///
///
/// 提供用户信息查询和更新、资产明细查询、VIP信息查询等功能
///
[ApiController]
[Route("api")]
public class UserController : ControllerBase
{
private readonly IUserService _userService;
private readonly IAuthService _authService;
private readonly IAssetService _assetService;
private readonly IVipService _vipService;
private readonly IQuanYiService _quanYiService;
private readonly ILogger _logger;
public UserController(
IUserService userService,
IAuthService authService,
IAssetService assetService,
IVipService vipService,
IQuanYiService quanYiService,
ILogger logger)
{
_userService = userService;
_authService = authService;
_assetService = assetService;
_vipService = vipService;
_quanYiService = quanYiService;
_logger = logger;
}
///
/// 获取用户简要信息(GET方式)
///
///
/// GET /api/userInfo
///
/// 获取当前登录用户的简要信息,直接返回用户数据(不嵌套在userinfo对象中)
/// 用于前端 getUserInfo() 调用
///
/// 用户信息数据
[HttpGet("userInfo")]
[Authorize]
[ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ApiResponse), StatusCodes.Status401Unauthorized)]
public async Task> GetUserInfoSimple()
{
var userId = GetCurrentUserId();
if (userId == null)
{
return ApiResponse.Unauthorized();
}
try
{
var userInfo = await _userService.GetUserInfoAsync(userId.Value);
if (userInfo == null)
{
_logger.LogWarning("User not found: UserId={UserId}", userId);
return ApiResponse.Fail("用户不存在");
}
return ApiResponse.Success(userInfo);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to get user info: UserId={UserId}", userId);
return ApiResponse.Fail("获取用户信息失败");
}
}
///
/// 获取用户完整信息(POST方式)
///
///
/// POST /api/user
///
/// 获取当前登录用户的详细信息,包含余额、积分、VIP等级等
/// 返回数据嵌套在 userinfo 对象中,用于前端 getUser() 调用
/// Requirements: 4.1-4.5
///
/// 用户信息数据
[HttpPost("user")]
[Authorize]
[ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ApiResponse), StatusCodes.Status401Unauthorized)]
public async Task> GetUserInfo()
{
var userId = GetCurrentUserId();
if (userId == null)
{
return ApiResponse.Unauthorized();
}
try
{
var userInfo = await _userService.GetUserInfoAsync(userId.Value);
if (userInfo == null)
{
_logger.LogWarning("User not found: UserId={UserId}", userId);
return ApiResponse.Fail("用户不存在");
}
var response = new UserInfoResponse
{
Userinfo = userInfo,
Other = new OtherConfigDto(),
TaskList = new List()
};
return ApiResponse.Success(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to get user info: UserId={UserId}", userId);
return ApiResponse.Fail("获取用户信息失败");
}
}
///
/// 更新用户信息
/// POST /api/update_userinfo
/// Requirements: 4.2, 4.3
///
[HttpPost("update_userinfo")]
[Authorize]
public async Task UpdateUserInfo([FromBody] UpdateUserInfoRequest request)
{
var userId = GetCurrentUserId();
if (userId == null)
{
return ApiResponse.Unauthorized();
}
if (request == null)
{
return ApiResponse.Fail("请求参数不能为空");
}
try
{
var updateDto = new UpdateUserDto();
var hasUpdate = false;
// 处理昵称更新
if (!string.IsNullOrWhiteSpace(request.Nickname))
{
updateDto.Nickname = request.Nickname;
hasUpdate = true;
}
// 处理头像更新
if (!string.IsNullOrWhiteSpace(request.Imagebase))
{
// Base64图片上传到腾讯云COS
var headimgUrl = await UploadBase64ImageAsync(request.Imagebase, userId.Value);
if (!string.IsNullOrWhiteSpace(headimgUrl))
{
updateDto.Headimg = headimgUrl;
hasUpdate = true;
}
}
else if (!string.IsNullOrWhiteSpace(request.Headimg))
{
// 直接使用传入的头像URL
updateDto.Headimg = request.Headimg;
hasUpdate = true;
}
if (!hasUpdate)
{
return ApiResponse.Fail("没有需要更新的内容");
}
await _userService.UpdateUserAsync(userId.Value, updateDto);
_logger.LogInformation("User info updated: UserId={UserId}", userId);
return ApiResponse.Success("更新成功");
}
catch (InvalidOperationException ex)
{
_logger.LogWarning("Update user info failed: UserId={UserId}, Error={Error}", userId, ex.Message);
return ApiResponse.Fail(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to update user info: UserId={UserId}", userId);
return ApiResponse.Fail("更新用户信息失败");
}
}
///
/// 账号注销
/// POST /api/user_log_off
/// Requirements: 7.1-7.3
///
[HttpPost("user_log_off")]
[Authorize]
public async Task LogOff([FromBody] LogOffRequest? request)
{
var userId = GetCurrentUserId();
if (userId == null)
{
return ApiResponse.Unauthorized();
}
try
{
var type = request?.Type ?? 0;
await _authService.LogOffAsync(userId.Value, type);
var message = type == 0 ? "注销成功" : "取消注销成功";
_logger.LogInformation("User log off: UserId={UserId}, Type={Type}", userId, type);
return ApiResponse.Success(message);
}
catch (InvalidOperationException ex)
{
_logger.LogWarning("Log off failed: UserId={UserId}, Error={Error}", userId, ex.Message);
return ApiResponse.Fail(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to log off: UserId={UserId}", userId);
return ApiResponse.Fail("操作失败");
}
}
#region Asset Endpoints
///
/// 获取余额明细
/// POST /api/profitMoney
/// Requirements: 1.1
///
[HttpPost("profitMoney")]
[Authorize]
public async Task> GetMoneyRecords([FromBody] AssetRecordRequest? request)
{
var userId = GetCurrentUserId();
if (userId == null)
{
return ApiResponse.Unauthorized();
}
try
{
var type = request?.Type ?? 0;
var page = request?.Page ?? 1;
var limit = request?.Limit ?? 15;
if (page < 1) page = 1;
if (limit < 1) limit = 15;
var result = await _assetService.GetMoneyRecordsAsync(userId.Value, type, page, limit);
return ApiResponse.Success(result);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to get money records: UserId={UserId}", userId);
return ApiResponse.Fail("获取余额明细失败");
}
}
///
/// 获取吧唧币明细
/// POST /api/profitIntegral
/// Requirements: 1.2
///
[HttpPost("profitIntegral")]
[Authorize]
public async Task> GetIntegralRecords([FromBody] AssetRecordRequest? request)
{
var userId = GetCurrentUserId();
if (userId == null)
{
return ApiResponse.Unauthorized();
}
try
{
var type = request?.Type ?? 0;
var page = request?.Page ?? 1;
var limit = request?.Limit ?? 15;
if (page < 1) page = 1;
if (limit < 1) limit = 15;
var result = await _assetService.GetIntegralRecordsAsync(userId.Value, type, page, limit);
return ApiResponse.Success(result);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to get integral records: UserId={UserId}", userId);
return ApiResponse.Fail("获取吧唧币明细失败");
}
}
///
/// 获取积分明细
/// POST /api/profitScore
/// Requirements: 1.3
///
[HttpPost("profitScore")]
[Authorize]
public async Task> GetScoreRecords([FromBody] AssetRecordRequest? request)
{
var userId = GetCurrentUserId();
if (userId == null)
{
return ApiResponse.Unauthorized();
}
try
{
var type = request?.Type ?? 0;
var page = request?.Page ?? 1;
var limit = request?.Limit ?? 15;
if (page < 1) page = 1;
if (limit < 1) limit = 15;
var result = await _assetService.GetScoreRecordsAsync(userId.Value, type, page, limit);
return ApiResponse.Success(result);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to get score records: UserId={UserId}", userId);
return ApiResponse.Fail("获取积分明细失败");
}
}
///
/// 获取支付记录
/// POST /api/profitPay
/// Requirements: 1.4
///
[HttpPost("profitPay")]
[Authorize]
public async Task> GetPayRecords([FromBody] AssetRecordRequest? request)
{
var userId = GetCurrentUserId();
if (userId == null)
{
return ApiResponse.Unauthorized();
}
try
{
var page = request?.Page ?? 1;
var limit = request?.Limit ?? 15;
if (page < 1) page = 1;
if (limit < 1) limit = 15;
var result = await _assetService.GetPayRecordsAsync(userId.Value, page, limit);
return ApiResponse.Success(result);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to get pay records: UserId={UserId}", userId);
return ApiResponse.Fail("获取支付记录失败");
}
}
#endregion
#region VIP Endpoints
///
/// 获取VIP信息
///
///
/// POST /api/vip_list
///
/// 获取当前用户的VIP等级信息和权益列表
/// Requirements: 2.1-2.5
///
/// VIP信息数据
[HttpPost("vip_list")]
[Authorize]
[ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ApiResponse), StatusCodes.Status401Unauthorized)]
public async Task> GetVipInfo()
{
var userId = GetCurrentUserId();
if (userId == null)
{
return ApiResponse.Unauthorized();
}
try
{
var result = await _vipService.GetVipInfoAsync(userId.Value);
return ApiResponse.Success(result);
}
catch (InvalidOperationException ex)
{
_logger.LogWarning("Get VIP info failed: UserId={UserId}, Error={Error}", userId, ex.Message);
return ApiResponse.Fail(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to get VIP info: UserId={UserId}", userId);
return ApiResponse.Fail("获取VIP信息失败");
}
}
#endregion
#region QuanYi (VIP Rights) Endpoints
///
/// 获取权益中心信息
///
///
/// Get /api/quan_yi
///
/// 获取当前用户的权益中心信息,包含等级列表和可领取奖品
/// Requirements: 8.1
///
/// 权益中心数据
[HttpGet("quan_yi")]
[Authorize]
[ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ApiResponse), StatusCodes.Status401Unauthorized)]
public async Task> GetQuanYi()
{
var userId = GetCurrentUserId();
if (userId == null)
{
return ApiResponse.Unauthorized();
}
try
{
var result = await _quanYiService.GetQuanYiAsync(userId.Value);
return ApiResponse.Success(result);
}
catch (InvalidOperationException ex)
{
_logger.LogWarning("Get QuanYi failed: UserId={UserId}, Error={Error}", userId, ex.Message);
return ApiResponse.Fail(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to get QuanYi: UserId={UserId}", userId);
return ApiResponse.Fail("获取权益信息失败");
}
}
///
/// 领取权益奖品
///
///
/// POST /api/quan_yi_ling
///
/// 领取指定等级的权益奖品
/// Requirements: 8.2
///
/// 领取请求
/// 领取结果
[HttpPost("quan_yi_ling")]
[Authorize]
[ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ApiResponse), StatusCodes.Status401Unauthorized)]
public async Task> ClaimQuanYi([FromBody] QuanYiLingRequest request)
{
var userId = GetCurrentUserId();
if (userId == null)
{
return ApiResponse.Unauthorized();
}
if (request == null || request.Id <= 0)
{
return ApiResponse.Fail("请选择要领取的等级");
}
try
{
var result = await _quanYiService.ClaimQuanYiAsync(userId.Value, request.Id);
return ApiResponse.Success(result, "领取成功");
}
catch (InvalidOperationException ex)
{
_logger.LogWarning("Claim QuanYi failed: UserId={UserId}, LevelId={LevelId}, Error={Error}",
userId, request.Id, ex.Message);
return ApiResponse.Fail(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to claim QuanYi: UserId={UserId}, LevelId={LevelId}",
userId, request.Id);
return ApiResponse.Fail("领取失败");
}
}
#endregion
#region Private Helper Methods
///
/// 获取当前登录用户ID
///
private int? GetCurrentUserId()
{
var userIdClaim = User.FindFirst(ClaimTypes.NameIdentifier);
if (userIdClaim == null || !int.TryParse(userIdClaim.Value, out var userId))
{
return null;
}
return userId;
}
///
/// 上传Base64图片到腾讯云COS
///
/// Base64编码的图片数据
/// 用户ID
/// 上传后的图片URL
private async Task UploadBase64ImageAsync(string base64Image, int userId)
{
try
{
// 移除Base64前缀(如果有)
var base64Data = base64Image;
if (base64Image.Contains(","))
{
base64Data = base64Image.Split(',')[1];
}
// 解码Base64数据
var imageBytes = Convert.FromBase64String(base64Data);
// TODO: 实现腾讯云COS上传
// 目前返回一个占位URL,实际应该上传到COS并返回真实URL
// 可以在后续添加ICosUploadService接口和实现
// 临时方案:将图片保存到本地并返回相对路径
var fileName = $"avatar_{userId}_{DateTime.UtcNow:yyyyMMddHHmmss}.png";
var uploadPath = Path.Combine("wwwroot", "uploads", "avatars");
if (!Directory.Exists(uploadPath))
{
Directory.CreateDirectory(uploadPath);
}
var filePath = Path.Combine(uploadPath, fileName);
await System.IO.File.WriteAllBytesAsync(filePath, imageBytes);
// 返回相对URL
return $"/uploads/avatars/{fileName}";
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to upload base64 image for user: {UserId}", userId);
return null;
}
}
#endregion
}