Initial commit: HealthManager full-stack health management platform
Backend: .NET 10 + PostgreSQL + EF Core + JWT + SignalR Frontend patient: React 19 + TypeScript + Vite (mobile H5) Frontend doctor: React 19 + TypeScript + Vite (desktop web)
This commit is contained in:
112
frontend-patient/src/pages/health/HealthCalendarPage.tsx
Normal file
112
frontend-patient/src/pages/health/HealthCalendarPage.tsx
Normal file
@@ -0,0 +1,112 @@
|
||||
import { useState, useMemo } from 'react';
|
||||
import { PageHeader } from '@/components/layout/PageHeader';
|
||||
import { Card } from '@/components/common/Card';
|
||||
import type { CalendarDay } from '@/types';
|
||||
import dayjs from 'dayjs';
|
||||
import styles from './HealthCalendarPage.module.css';
|
||||
|
||||
const MARKER_COLORS: Record<string, string> = {
|
||||
medication_taken: '#10B981',
|
||||
medication_missed: '#EF4444',
|
||||
follow_up: '#F59E0B',
|
||||
measurement: '#2563EB',
|
||||
};
|
||||
|
||||
export function HealthCalendarPage() {
|
||||
const [currentDate, setCurrentDate] = useState(dayjs());
|
||||
|
||||
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');
|
||||
|
||||
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: [],
|
||||
});
|
||||
}
|
||||
|
||||
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'] = [];
|
||||
|
||||
// Calendar markers would be populated from real API data
|
||||
|
||||
days.push({
|
||||
date: dateStr,
|
||||
year: d.year(),
|
||||
month: d.month() + 1,
|
||||
day: d.date(),
|
||||
isCurrentMonth: true,
|
||||
isToday: dateStr === today,
|
||||
markers,
|
||||
});
|
||||
}
|
||||
|
||||
return days;
|
||||
}, [currentDate]);
|
||||
|
||||
const weeks: CalendarDay[][] = [];
|
||||
for (let i = 0; i < calendarDays.length; i += 7) {
|
||||
weeks.push(calendarDays.slice(i, i + 7));
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="page--no-tab">
|
||||
<PageHeader title="健康日历" />
|
||||
<div className={styles.monthNav}>
|
||||
<button onClick={() => setCurrentDate((d) => d.subtract(1, 'month'))}>‹</button>
|
||||
<span className={styles.monthTitle}>{currentDate.format('YYYY年 M月')}</span>
|
||||
<button onClick={() => setCurrentDate((d) => d.add(1, 'month'))}>›</button>
|
||||
</div>
|
||||
|
||||
<div className={styles.weekdays}>
|
||||
{['日', '一', '二', '三', '四', '五', '六'].map((w) => (
|
||||
<span key={w} className={styles.weekday}>{w}</span>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{weeks.map((week, wi) => (
|
||||
<div key={wi} className={styles.week}>
|
||||
{week.map((day) => (
|
||||
<div
|
||||
key={day.date}
|
||||
className={`${styles.day} ${!day.isCurrentMonth ? styles.outside : ''} ${day.isToday ? styles.today : ''}`}
|
||||
>
|
||||
<span className={styles.dayNum}>{day.day}</span>
|
||||
<div className={styles.markers}>
|
||||
{day.markers.slice(0, 3).map((m, i) => (
|
||||
<span
|
||||
key={i}
|
||||
className={styles.dot}
|
||||
style={{ background: m.color }}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
|
||||
<Card className={styles.legend}>
|
||||
<div className={styles.legendTitle}>图例</div>
|
||||
<div className={styles.legendItems}>
|
||||
<span className={styles.legendItem}><span className={styles.dot} style={{ background: '#2563EB' }} /> 测量日</span>
|
||||
<span className={styles.legendItem}><span className={styles.dot} style={{ background: '#10B981' }} /> 已服药</span>
|
||||
<span className={styles.legendItem}><span className={styles.dot} style={{ background: '#EF4444' }} /> 漏服药</span>
|
||||
<span className={styles.legendItem}><span className={styles.dot} style={{ background: '#F59E0B' }} /> 复查日</span>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user