chore: 全面规范化代码,遵循 CLAUDE.md 编码规范

- C# 文件命名改为 snake_case(28 个文件重命名)
- C# 类转换为主构造函数(8 个类)
- 空 catch 添加异常类型(2 处)
- 新建 GlobalUsings.cs(Health.Infrastructure、Health.WebApi)
- Flutter 移除 go_router,改用 Riverpod 路由栈
- Flutter 移除 flutter_secure_storage,改用 sqflite 持久化
- 修复 Flutter 构建路径(Flutter SDK 迁至 D 盘)
- 后端端口改为 0.0.0.0:5000,支持局域网访问
This commit is contained in:
MingNian
2026-06-02 12:41:06 +08:00
parent 14d7c30d3d
commit 6e69f1085e
47 changed files with 342 additions and 428 deletions

View File

@@ -1,29 +1,20 @@
using Microsoft.Extensions.Configuration;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
namespace Health.Infrastructure.AI;
/// <summary>
/// DeepSeek LLM 客户端(对话 + Tool Calling
/// </summary>
public sealed class DeepSeekClient
public sealed class DeepSeekClient(HttpClient http, IConfiguration config)
{
private readonly HttpClient _http;
private readonly string _model;
private readonly JsonSerializerOptions _jsonOptions;
public DeepSeekClient(HttpClient http, IConfiguration config)
private readonly HttpClient _http = http;
private readonly string _model = config["DEEPSEEK_MODEL"] ?? "deepseek-chat";
private readonly JsonSerializerOptions _jsonOptions = new()
{
_http = http;
_model = config["DEEPSEEK_MODEL"] ?? "deepseek-chat";
_jsonOptions = new()
{
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
PropertyNameCaseInsensitive = true
};
}
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
PropertyNameCaseInsensitive = true
};
/// <summary>
/// 流式 Chat Completions
@@ -96,22 +87,15 @@ public sealed class DeepSeekClient
/// <summary>
/// 千问 VL 视觉客户端(食物识别 + 报告解读)
/// </summary>
public sealed class QwenVisionClient
public sealed class QwenVisionClient(HttpClient http, IConfiguration config)
{
private readonly HttpClient _http;
private readonly string _model;
private readonly JsonSerializerOptions _jsonOptions;
public QwenVisionClient(HttpClient http, IConfiguration config)
private readonly HttpClient _http = http;
private readonly string _model = config["QWEN_VISION_MODEL"] ?? "qwen-vl-max";
private readonly JsonSerializerOptions _jsonOptions = new()
{
_http = http;
_model = config["QWEN_VISION_MODEL"] ?? "qwen-vl-max";
_jsonOptions = new()
{
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
PropertyNameCaseInsensitive = true
};
}
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
PropertyNameCaseInsensitive = true
};
public async Task<ChatCompletionResponse> VisionAsync(
string systemPrompt,

View File

@@ -1,33 +1,30 @@
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
namespace Health.Infrastructure.AI;
/// <summary>
/// OpenAI 兼容协议 HTTP 客户端,统一调用 DeepSeek / 千问 VL
/// </summary>
public sealed class OpenAiCompatibleClient
public sealed class OpenAiCompatibleClient(string baseUrl, string apiKey, string model)
{
private readonly HttpClient _http;
private readonly string _model;
private readonly JsonSerializerOptions _jsonOptions;
public OpenAiCompatibleClient(string baseUrl, string apiKey, string model)
private readonly HttpClient _http = CreateHttpClient(baseUrl, apiKey);
private readonly string _model = model;
private readonly JsonSerializerOptions _jsonOptions = new()
{
_http = new HttpClient
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
PropertyNameCaseInsensitive = true
};
private static HttpClient CreateHttpClient(string baseUrl, string apiKey)
{
var client = new HttpClient
{
BaseAddress = new Uri(baseUrl.TrimEnd('/') + "/"),
Timeout = TimeSpan.FromSeconds(60)
};
_http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
_http.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
_model = model;
_jsonOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
PropertyNameCaseInsensitive = true
};
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
return client;
}
/// <summary>

View File

@@ -1,5 +1,3 @@
using Health.Domain.Enums;
namespace Health.Infrastructure.AI;
/// <summary>

View File

@@ -1,4 +1,3 @@
using Health.Domain.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
@@ -7,9 +6,8 @@ namespace Health.Infrastructure.Data;
/// <summary>
/// 应用程序数据库上下文
/// </summary>
public sealed class AppDbContext : DbContext
public sealed class AppDbContext(DbContextOptions<AppDbContext> options) : DbContext(options)
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
// 核心业务表
public DbSet<User> Users => Set<User>();

View File

@@ -1,5 +1,3 @@
using Health.Domain.Entities;
namespace Health.Infrastructure.Data;
/// <summary>

View File

@@ -1,5 +1,3 @@
using Health.Domain.Entities;
using Health.Domain.Enums;
using Microsoft.Extensions.Configuration;
namespace Health.Infrastructure.Data;

View File

@@ -0,0 +1,4 @@
global using Health.Domain.Entities;
global using Health.Domain.Enums;
global using System.Text;
global using System.Text.Json;

View File

@@ -3,25 +3,17 @@ using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
namespace Health.Infrastructure.Services;
/// <summary>
/// JWT Token 生成与验证服务
/// </summary>
public sealed class JwtProvider
public sealed class JwtProvider(IConfiguration configuration)
{
private readonly string _secret;
private readonly string _issuer;
private readonly string _audience;
public JwtProvider(IConfiguration configuration)
{
_secret = configuration["JWT_SECRET"] ?? "dev-secret-key-change-in-production-min-32-chars!!";
_issuer = configuration["JWT_ISSUER"] ?? "health-manager";
_audience = configuration["JWT_AUDIENCE"] ?? "health-manager-app";
}
private readonly string _secret = configuration["JWT_SECRET"] ?? "dev-secret-key-change-in-production-min-32-chars!!";
private readonly string _issuer = configuration["JWT_ISSUER"] ?? "health-manager";
private readonly string _audience = configuration["JWT_AUDIENCE"] ?? "health-manager-app";
/// <summary>
/// 生成 access_token30 分钟有效)