ApiClient.cs 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. using System.Net.Http;
  2. using System.Net.Http.Headers;
  3. using System.Text;
  4. using System.Text.Json;
  5. namespace XafPet.Desktop.PetEngine;
  6. /// <summary>CFC 后端 API 客户端。所有接口统一 POST + JWT Bearer。</summary>
  7. public sealed class ApiClient
  8. {
  9. private readonly HttpClient _http;
  10. private readonly string _baseUrl;
  11. private string _token;
  12. private static readonly JsonSerializerOptions JsonOpts = new(JsonSerializerDefaults.Web);
  13. public ApiClient(HttpClient http, string baseUrl, string token)
  14. {
  15. _http = http;
  16. _baseUrl = baseUrl.TrimEnd('/');
  17. _token = token;
  18. }
  19. public void UpdateToken(string token) => _token = token;
  20. private async Task<T?> PostAsync<T>(string path, object? body = null)
  21. {
  22. using var req = new HttpRequestMessage(HttpMethod.Post, $"{_baseUrl}{path}");
  23. req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _token);
  24. if (body != null)
  25. {
  26. req.Content = new StringContent(JsonSerializer.Serialize(body, JsonOpts),
  27. Encoding.UTF8, "application/json");
  28. }
  29. var resp = await _http.SendAsync(req);
  30. var json = await resp.Content.ReadAsStringAsync();
  31. var result = JsonSerializer.Deserialize<ApiResult<T>>(json, JsonOpts)
  32. ?? throw new ApiException(-1, "响应解析失败");
  33. if (!result.IsSuccess)
  34. throw new ApiException(result.Code, result.Message ?? "未知错误");
  35. return result.Data;
  36. }
  37. /// <summary>POST /api/tasks/today — 今日任务</summary>
  38. public Task<List<CfcTask>?> GetTodayTasksAsync()
  39. => PostAsync<List<CfcTask>>("/api/tasks/today", new Dictionary<string, object>());
  40. /// <summary>POST /api/energy/overview — 五维能量概览</summary>
  41. public Task<EnergyOverview?> GetEnergyOverviewAsync()
  42. => PostAsync<EnergyOverview>("/api/energy/overview");
  43. /// <summary>POST /api/daily/checkin — 今日打卡状态</summary>
  44. public Task<DailyCheckin?> GetDailyCheckinAsync()
  45. => PostAsync<DailyCheckin>("/api/daily/checkin");
  46. /// <summary>POST /api/daily/checkin — 完成喝水打卡(body: {"type":"water"})</summary>
  47. public async Task<ApiResult<object>?> CompleteDrinkWaterAsync()
  48. {
  49. using var req = new HttpRequestMessage(HttpMethod.Post, $"{_baseUrl}/api/daily/checkin");
  50. req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _token);
  51. req.Content = new StringContent("""{"type":"water"}""", Encoding.UTF8, "application/json");
  52. var resp = await _http.SendAsync(req);
  53. var json = await resp.Content.ReadAsStringAsync();
  54. var result = JsonSerializer.Deserialize<ApiResult<object>>(json, JsonOpts)
  55. ?? throw new ApiException(-1, "响应解析失败");
  56. if (!result.IsSuccess)
  57. throw new ApiException(result.Code, result.Message ?? "未知错误");
  58. return result;
  59. }
  60. /// <summary>POST /api/user/mascot/get — 获取用户已选吉祥物</summary>
  61. public Task<MascotInfo?> GetMascotAsync()
  62. => PostAsync<MascotInfo>("/api/user/mascot/get");
  63. /// <summary>POST /api/user/mascot/set — 设置吉祥物</summary>
  64. public Task<object?> SetMascotAsync(string mascotId)
  65. => PostAsync<object>("/api/user/mascot/set", new { mascotId });
  66. }