From 8caa374699b0f500ca9a73b55368a940f62a9c58 Mon Sep 17 00:00:00 2001 From: MingNian <1281442923@qq.com> Date: Fri, 22 May 2026 10:59:46 +0800 Subject: [PATCH] fix: prevent duplicate consultations in backend, health calendar shows medication dots --- .../Services/ConsultationService.cs | 6 ++ .../src/pages/health/HealthCalendarPage.tsx | 97 +++++++++++-------- 2 files changed, 64 insertions(+), 39 deletions(-) diff --git a/backend/src/HealthManager.Application/Services/ConsultationService.cs b/backend/src/HealthManager.Application/Services/ConsultationService.cs index 2996d19..80d9666 100644 --- a/backend/src/HealthManager.Application/Services/ConsultationService.cs +++ b/backend/src/HealthManager.Application/Services/ConsultationService.cs @@ -28,6 +28,12 @@ public class ConsultationService(AppDbContext db) public async Task StartAsync(Guid patientId, Guid doctorId, string subject) { + // Reuse existing active consultation between this patient and doctor + var existing = await db.Consultations + .FirstOrDefaultAsync(c => c.PatientId == patientId && c.DoctorId == doctorId && c.Status == "active"); + if (existing != null) + return existing; + var consultation = new Consultation { PatientId = patientId, diff --git a/frontend-patient/src/pages/health/HealthCalendarPage.tsx b/frontend-patient/src/pages/health/HealthCalendarPage.tsx index 45177a9..c79b828 100644 --- a/frontend-patient/src/pages/health/HealthCalendarPage.tsx +++ b/frontend-patient/src/pages/health/HealthCalendarPage.tsx @@ -1,60 +1,87 @@ -import { useState, useMemo } from 'react'; +import { useState, useMemo, useEffect } from 'react'; import { PageHeader } from '@/components/layout/PageHeader'; import { Card } from '@/components/common/Card'; import type { CalendarDay } from '@/types'; +import { api } from '@/services/api-client'; import dayjs from 'dayjs'; import styles from './HealthCalendarPage.module.css'; -const MARKER_COLORS: Record = { - medication_taken: '#10B981', - medication_missed: '#EF4444', - follow_up: '#F59E0B', - measurement: '#2563EB', -}; +interface MedRecord { medicationId: string; timeSlot: string; takenAt?: string | null; isTaken: boolean; } +interface HealthRecord { id: string; type: string; recordedAt: string; } +interface Medication { id: string; drugName: string; timeSlots: string[]; status: string; startDate: string; endDate?: string | null; } export function HealthCalendarPage() { const [currentDate, setCurrentDate] = useState(dayjs()); + const [medRecords, setMedRecords] = useState([]); + const [medications, setMedications] = useState([]); + + useEffect(() => { + // Fetch all active medications and their records + api.get('/api/medications').then((res) => { + const active = res.data.filter((m) => m.status === 'active'); + setMedications(active); + // Fetch records for each active medication + Promise.all(active.map((m) => + api.get(`/api/medications/${m.id}/records`) + .then((r) => r.data) + .catch(() => [] as MedRecord[]) + )).then((all) => setMedRecords(all.flat())); + }); + }, []); const calendarDays = useMemo(() => { const startOfMonth = currentDate.startOf('month'); const endOfMonth = currentDate.endOf('month'); const startDay = startOfMonth.day(); const days: CalendarDay[] = []; - const today = dayjs().format('YYYY-MM-DD'); + // Build a map: date -> { taken, missed } + const dateMap: Record = {}; + medRecords.forEach((r) => { + const d = r.takenAt?.split('T')[0]; + if (!d) return; + if (!dateMap[d]) dateMap[d] = { taken: 0, missed: 0 }; + if (r.isTaken) dateMap[d].taken++; + else dateMap[d].missed++; + }); + + // Pad previous month for (let i = startDay - 1; i >= 0; i--) { const d = startOfMonth.subtract(i + 1, 'day'); - days.push({ - date: d.format('YYYY-MM-DD'), - year: d.year(), - month: d.month() + 1, - day: d.date(), - isCurrentMonth: false, - isToday: d.format('YYYY-MM-DD') === today, - markers: [], - }); + days.push({ date: d.format('YYYY-MM-DD'), year: d.year(), month: d.month() + 1, day: d.date(), isCurrentMonth: false, isToday: d.format('YYYY-MM-DD') === today, markers: [] }); } for (let d = startOfMonth; d.isBefore(endOfMonth) || d.isSame(endOfMonth, 'day'); d = d.add(1, 'day')) { const dateStr = d.format('YYYY-MM-DD'); const markers: CalendarDay['markers'] = []; + const dm = dateMap[dateStr]; - // Calendar markers would be populated from real API data + if (dm) { + if (dm.taken > 0) { + markers.push({ type: 'medication_taken', color: '#10B981', count: dm.taken }); + } + if (dm.missed > 0) { + markers.push({ type: 'medication_missed', color: '#EF4444', count: dm.missed }); + } + } else { + // Check if any medication should have been taken on this date + const dateInRange = medications.some((m) => { + if (m.status !== 'active') return false; + const sd = m.startDate; + const ed = m.endDate || '9999-12-31'; + return dateStr >= sd && dateStr <= ed; + }); + if (dateInRange && medications.length > 0) { + markers.push({ type: 'medication_missed', color: '#FFA500', count: 0 }); + } + } - days.push({ - date: dateStr, - year: d.year(), - month: d.month() + 1, - day: d.date(), - isCurrentMonth: true, - isToday: dateStr === today, - markers, - }); + days.push({ date: dateStr, year: d.year(), month: d.month() + 1, day: d.date(), isCurrentMonth: true, isToday: dateStr === today, markers }); } return days; - }, [currentDate]); + }, [currentDate, medRecords, medications]); const weeks: CalendarDay[][] = []; for (let i = 0; i < calendarDays.length; i += 7) { @@ -79,18 +106,11 @@ export function HealthCalendarPage() { {weeks.map((week, wi) => (
{week.map((day) => ( -
+
{day.day}
{day.markers.slice(0, 3).map((m, i) => ( - + ))}
@@ -101,10 +121,9 @@ export function HealthCalendarPage() {
图例
- 测量日 已服药 漏服药 - 复查日 + 未记录