feat: 用药打卡全面重构 - 按次追踪 + 独立打卡页 + 任务区汇总

- 后端用药提醒改为按次粒度(每个服药时间独立判断)
- 新增 per-dose 打卡/取消打卡 API
- 新增 MedicationCheckInPage 独立打卡页(每药每时间单独toggle)
- 用药列表删底部弹窗(编辑/停药),点药品直接进该药打卡页
- 任务区用药汇总为一行(过期待服已服)
- 支持隔天(EveryOtherDay)/每周频率判断
- 删历史对话功能(ConversationItem + conversationListProvider + UI)
This commit is contained in:
MingNian
2026-06-08 16:21:13 +08:00
parent fc7150ad60
commit 16d1d3d305
17 changed files with 519 additions and 373 deletions

View File

@@ -9,8 +9,16 @@ public static class MedicationAgentHandler
{
Function = new()
{
Name = "manage_medication", Description = "用药管理",
Parameters = new { type = "object", properties = new { action = new { type = "string" }, name = new { type = "string" }, dosage = new { type = "string" } }, required = new[] { "action" } }
Name = "manage_medication", Description = "用药管理(创建/查询/确认服药)",
Parameters = new { type = "object", properties = new {
action = new { type = "string", description = "create/query/confirm" },
name = new { type = "string", description = "药品名称" },
dosage = new { type = "string", description = "剂量,如 100mg" },
frequency = new { type = "string", description = "频率,如 Daily/EveryOtherDay/Weekly" },
time_of_day = new { type = "array", items = new { type = "string" }, description = "服药时间,如 [\"08:00\",\"20:00\"]" },
duration_days = new { type = "integer", description = "服用天数" },
start_date = new { type = "string", description = "开始日期 yyyy-MM-dd" },
}, required = new[] { "action" } }
}
};
@@ -40,16 +48,43 @@ public static class MedicationAgentHandler
private static async Task<object> CreateMedication(AppDbContext db, Guid userId, JsonElement args)
{
var name = args.TryGetProperty("name", out var n) ? n.GetString()! : "";
var dosage = args.TryGetProperty("dosage", out var dg) ? dg.GetString() : null;
var frequencyStr = args.TryGetProperty("frequency", out var f) ? f.GetString() : "Daily";
var frequency = Enum.TryParse<MedicationFrequency>(frequencyStr, out var fr) ? fr : MedicationFrequency.Daily;
List<TimeOnly> times = [];
if (args.TryGetProperty("time_of_day", out var tod) && tod.ValueKind == JsonValueKind.Array)
{
foreach (var t in tod.EnumerateArray())
{
if (TimeOnly.TryParse(t.GetString(), out var parsed)) times.Add(parsed);
}
}
var durationDays = args.TryGetProperty("duration_days", out var dd) ? dd.GetInt32() : 0;
var startDateStr = args.TryGetProperty("start_date", out var sd) && sd.GetString() is string sds ? sds : null;
var med = new Medication
{
Id = Guid.NewGuid(), UserId = userId,
Name = args.TryGetProperty("name", out var n) ? n.GetString()! : "",
Dosage = args.TryGetProperty("dosage", out var dg) ? dg.GetString() : null,
Name = name, Dosage = dosage, Frequency = frequency,
TimeOfDay = times.Count > 0 ? times : [new TimeOnly(8, 0)],
Source = MedicationSource.AiEntry, IsActive = true,
StartDate = DateOnly.TryParse(startDateStr, out var parsedDate) ? parsedDate : DateOnly.FromDateTime(DateTime.Now),
EndDate = durationDays > 0 ? DateOnly.FromDateTime(DateTime.Now).AddDays(durationDays) : null,
};
db.Medications.Add(med);
await db.SaveChangesAsync();
return new { success = true, medication_id = med.Id, med.Name };
var timeLabels = times.Count > 0 ? string.Join(", ", times.Select(t => t.ToString("HH:mm"))) : "08:00";
return new {
success = true, medication_id = med.Id,
name = med.Name, dosage = med.Dosage,
frequency = med.Frequency.ToString(), time = timeLabels,
start_date = med.StartDate?.ToString("yyyy-MM-dd"),
duration_days = durationDays,
};
}
private static async Task<object> QueryMedications(AppDbContext db, Guid userId)