using System.Net.Http; using System.Net.Http.Headers; using System.Text; using System.Text.Json; namespace XafPet.Desktop.PetEngine; /// CFC 后端 API 客户端。所有接口统一 POST + JWT Bearer。 public sealed class ApiClient { private readonly HttpClient _http; private readonly string _baseUrl; private string _token; private static readonly JsonSerializerOptions JsonOpts = new(JsonSerializerDefaults.Web); public ApiClient(HttpClient http, string baseUrl, string token) { _http = http; _baseUrl = baseUrl.TrimEnd('/'); _token = token; } public void UpdateToken(string token) => _token = token; private async Task PostAsync(string path, object? body = null) { using var req = new HttpRequestMessage(HttpMethod.Post, $"{_baseUrl}{path}"); req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _token); if (body != null) { req.Content = new StringContent(JsonSerializer.Serialize(body, JsonOpts), Encoding.UTF8, "application/json"); } var resp = await _http.SendAsync(req); var json = await resp.Content.ReadAsStringAsync(); var result = JsonSerializer.Deserialize>(json, JsonOpts) ?? throw new ApiException(-1, "响应解析失败"); if (!result.IsSuccess) throw new ApiException(result.Code, result.Message ?? "未知错误"); return result.Data; } /// POST /api/tasks/today — 今日任务 public Task?> GetTodayTasksAsync() => PostAsync>("/api/tasks/today", new Dictionary()); /// POST /api/energy/overview — 五维能量概览 public Task GetEnergyOverviewAsync() => PostAsync("/api/energy/overview"); /// POST /api/daily/checkin — 今日打卡状态 public Task GetDailyCheckinAsync() => PostAsync("/api/daily/checkin"); /// POST /api/daily/checkin — 完成喝水打卡(body: {"type":"water"}) public async Task?> CompleteDrinkWaterAsync() { using var req = new HttpRequestMessage(HttpMethod.Post, $"{_baseUrl}/api/daily/checkin"); req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _token); req.Content = new StringContent("""{"type":"water"}""", Encoding.UTF8, "application/json"); var resp = await _http.SendAsync(req); var json = await resp.Content.ReadAsStringAsync(); var result = JsonSerializer.Deserialize>(json, JsonOpts) ?? throw new ApiException(-1, "响应解析失败"); if (!result.IsSuccess) throw new ApiException(result.Code, result.Message ?? "未知错误"); return result; } /// POST /api/user/mascot/get — 获取用户已选吉祥物 public Task GetMascotAsync() => PostAsync("/api/user/mascot/get"); /// POST /api/user/mascot/set — 设置吉祥物 public Task SetMascotAsync(string mascotId) => PostAsync("/api/user/mascot/set", new { mascotId }); }