feat: 后端架构重构 — Endpoint→Service→Repository分层 + AI确认机制 + 异步任务持久化
- 核心业务拆分为 Endpoint → Application Service → Repository 三层 - AI写入操作必须用户确认后才写库(确认卡片机制) - 报告/饮食/用药分析改为持久化任务队列(原子领取/重试/重启恢复) - 运动计划修复: 连续真实日期替代周模板 - 用药提醒去重 + 通知Outbox预留 - 认证收拢到AuthService, 管理员收拢到AdminService - AI会话加用户归属校验防串号 - 提示词调整为患者视角 - 开发假数据已关闭 - 21/21测试通过, 0警告0错误
This commit is contained in:
51
backend/src/Health.Infrastructure/Users/EfUserRepository.cs
Normal file
51
backend/src/Health.Infrastructure/Users/EfUserRepository.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using Health.Application.Users;
|
||||
|
||||
namespace Health.Infrastructure.Users;
|
||||
|
||||
public sealed class EfUserRepository(AppDbContext db) : IUserRepository
|
||||
{
|
||||
private readonly AppDbContext _db = db;
|
||||
|
||||
public Task<User?> GetAsync(Guid userId, CancellationToken ct) =>
|
||||
_db.Users.FirstOrDefaultAsync(u => u.Id == userId, ct);
|
||||
|
||||
public Task SaveChangesAsync(CancellationToken ct) =>
|
||||
_db.SaveChangesAsync(ct);
|
||||
|
||||
public async Task DeleteAccountDataAsync(Guid userId, CancellationToken ct)
|
||||
{
|
||||
await using var transaction = await _db.Database.BeginTransactionAsync(ct);
|
||||
|
||||
var profile = await _db.DoctorProfiles.FirstOrDefaultAsync(p => p.UserId == userId, ct);
|
||||
if (profile?.DoctorId != null)
|
||||
{
|
||||
await _db.Users.Where(u => u.DoctorId == profile.DoctorId)
|
||||
.ExecuteUpdateAsync(u => u.SetProperty(x => x.DoctorId, (Guid?)null), ct);
|
||||
await _db.Doctors.Where(d => d.Id == profile.DoctorId).ExecuteDeleteAsync(ct);
|
||||
}
|
||||
|
||||
await _db.HealthRecords.Where(r => r.UserId == userId).ExecuteDeleteAsync(ct);
|
||||
await _db.MedicationLogs.Where(l => l.UserId == userId).ExecuteDeleteAsync(ct);
|
||||
await _db.Medications.Where(m => m.UserId == userId).ExecuteDeleteAsync(ct);
|
||||
await _db.DietFoodItems.Where(i => i.DietRecord!.UserId == userId).ExecuteDeleteAsync(ct);
|
||||
await _db.DietRecords.Where(d => d.UserId == userId).ExecuteDeleteAsync(ct);
|
||||
await _db.ExercisePlanItems.Where(i => i.Plan!.UserId == userId).ExecuteDeleteAsync(ct);
|
||||
await _db.ExercisePlans.Where(p => p.UserId == userId).ExecuteDeleteAsync(ct);
|
||||
await _db.ReportAnalysisTasks.Where(t => _db.Reports.Any(r => r.Id == t.ReportId && r.UserId == userId)).ExecuteDeleteAsync(ct);
|
||||
await _db.Reports.Where(r => r.UserId == userId).ExecuteDeleteAsync(ct);
|
||||
await _db.ConversationMessages.Where(m => m.Conversation!.UserId == userId).ExecuteDeleteAsync(ct);
|
||||
await _db.Conversations.Where(c => c.UserId == userId).ExecuteDeleteAsync(ct);
|
||||
await _db.ConsultationMessages.Where(m => m.Consultation!.UserId == userId).ExecuteDeleteAsync(ct);
|
||||
await _db.Consultations.Where(c => c.UserId == userId).ExecuteDeleteAsync(ct);
|
||||
await _db.FollowUps.Where(f => f.UserId == userId).ExecuteDeleteAsync(ct);
|
||||
await _db.RefreshTokens.Where(t => t.UserId == userId).ExecuteDeleteAsync(ct);
|
||||
await _db.DeviceTokens.Where(t => t.UserId == userId).ExecuteDeleteAsync(ct);
|
||||
await _db.NotificationPreferences.Where(p => p.UserId == userId).ExecuteDeleteAsync(ct);
|
||||
await _db.HealthArchives.Where(a => a.UserId == userId).ExecuteDeleteAsync(ct);
|
||||
await _db.AiWriteCommands.Where(c => c.UserId == userId).ExecuteDeleteAsync(ct);
|
||||
await _db.DoctorProfiles.Where(p => p.UserId == userId).ExecuteDeleteAsync(ct);
|
||||
await _db.Users.Where(u => u.Id == userId).ExecuteDeleteAsync(ct);
|
||||
|
||||
await transaction.CommitAsync(ct);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user