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 }