Files
AI-Health/backend/src/Health.Application/Diets/DietService.cs
MingNian 4d213b5a44 feat: 后端架构重构 — Endpoint→Service→Repository分层 + AI确认机制 + 异步任务持久化
- 核心业务拆分为 Endpoint → Application Service → Repository 三层
- AI写入操作必须用户确认后才写库(确认卡片机制)
- 报告/饮食/用药分析改为持久化任务队列(原子领取/重试/重启恢复)
- 运动计划修复: 连续真实日期替代周模板
- 用药提醒去重 + 通知Outbox预留
- 认证收拢到AuthService, 管理员收拢到AdminService
- AI会话加用户归属校验防串号
- 提示词调整为患者视角
- 开发假数据已关闭
- 21/21测试通过, 0警告0错误
2026-06-20 20:41:42 +08:00

78 lines
2.7 KiB
C#

using Health.Domain.Entities;
using Health.Domain.Enums;
namespace Health.Application.Diets;
public sealed class DietService(IDietRepository diets) : IDietService
{
private readonly IDietRepository _diets = diets;
public async Task<IReadOnlyList<DietRecordDto>> ListAsync(Guid userId, string? date, string? mealType, CancellationToken ct)
{
var recordedAt = DateOnly.TryParse(date, out var d) ? d : (DateOnly?)null;
var parsedMealType = Enum.TryParse<MealType>(mealType, ignoreCase: true, out var mt) ? mt : (MealType?)null;
var records = await _diets.ListAsync(userId, recordedAt, parsedMealType, ct);
return records.Select(ToDto).ToList();
}
public async Task<Guid> CreateAsync(Guid userId, DietRecordCreateRequest request, CancellationToken ct)
{
var record = new DietRecord
{
Id = Guid.NewGuid(),
UserId = userId,
MealType = request.MealType,
TotalCalories = request.TotalCalories,
HealthScore = request.HealthScore,
RecordedAt = request.RecordedAt,
CreatedAt = DateTime.UtcNow,
};
foreach (var item in request.FoodItems)
{
record.FoodItems.Add(new DietFoodItem
{
Id = Guid.NewGuid(),
Name = item.Name,
Portion = item.Portion,
Calories = item.Calories,
SortOrder = item.SortOrder,
});
}
await _diets.AddAsync(record, ct);
await _diets.SaveChangesAsync(ct);
return record.Id;
}
public async Task<bool> DeleteAsync(Guid userId, Guid recordId, CancellationToken ct)
{
var record = await _diets.GetOwnedAsync(userId, recordId, ct);
if (record == null) return false;
_diets.Delete(record);
await _diets.SaveChangesAsync(ct);
return true;
}
public async Task<bool> UpdateAsync(Guid userId, Guid recordId, DietRecordPatchRequest request, CancellationToken ct)
{
var record = await _diets.GetOwnedAsync(userId, recordId, ct);
if (record == null) return false;
if (request.TotalCalories.HasValue) record.TotalCalories = request.TotalCalories.Value;
if (request.HealthScore.HasValue) record.HealthScore = request.HealthScore.Value;
await _diets.SaveChangesAsync(ct);
return true;
}
private static DietRecordDto ToDto(DietRecord record) => new(
record.Id,
record.MealType.ToString(),
record.TotalCalories,
record.HealthScore,
record.RecordedAt,
record.FoodItems.OrderBy(f => f.SortOrder).Select(f => new DietFoodItemDto(f.Name, f.Portion, f.Calories)).ToList());
}