import React, { useMemo, useState } from 'react'; import { Button, Segmented, Select } from 'antd'; import { PlusOutlined, GlobalOutlined, BranchesOutlined } from '@ant-design/icons'; import dayjs from 'dayjs'; import styles from './ActivityCalendar.less'; const weekDays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']; const calendarEvents = [ { id: 'earth-day', title: '世界环保日', start: dayjs('2020-12-14'), end: dayjs('2020-12-15'), tone: 'sand', icon: , }, { id: 'tree-day', title: '全国植树日', start: dayjs('2020-12-24'), end: dayjs('2020-12-31'), tone: 'mint', icon: , }, ]; const buildGrid = (referenceDate, viewMode) => { if (viewMode === 'week') { const startOfWeek = referenceDate.startOf('week'); const days = Array.from({ length: 7 }, (_, index) => startOfWeek.add(index, 'day')); return { days, gridStart: startOfWeek, weeks: 1 }; } const startOfMonth = referenceDate.startOf('month'); const gridStart = startOfMonth.startOf('week'); const days = Array.from({ length: 42 }, (_, index) => gridStart.add(index, 'day')); return { days, gridStart, weeks: 6 }; }; const buildEventSegments = (events, gridStart, weeks) => { const gridEnd = gridStart.add(weeks * 7 - 1, 'day').endOf('day'); const segments = []; events.forEach((event) => { const start = event.start; const end = event.end; if (end.isBefore(gridStart) || start.isAfter(gridEnd)) { return; } for (let weekIndex = 0; weekIndex < weeks; weekIndex += 1) { const weekStart = gridStart.add(weekIndex * 7, 'day'); const weekEnd = weekStart.add(6, 'day').endOf('day'); const segmentStart = start.isAfter(weekStart) ? start : weekStart; const segmentEnd = end.isBefore(weekEnd) ? end : weekEnd; if (segmentEnd.isBefore(weekStart) || segmentStart.isAfter(weekEnd)) { continue; } const columnStart = segmentStart.diff(weekStart, 'day') + 1; const columnEnd = segmentEnd.diff(weekStart, 'day') + 2; segments.push({ id: `${event.id}-${weekIndex}`, title: event.title, tone: event.tone, icon: event.icon, rowStart: weekIndex + 1, rowEnd: weekIndex + 2, columnStart, columnEnd, }); } }); return segments; }; const ActivityCalendar = () => { const [currentDate, setCurrentDate] = useState(dayjs('2020-12-01')); const [viewMode, setViewMode] = useState('month'); const { days, gridStart, weeks } = useMemo(() => buildGrid(currentDate, viewMode), [currentDate, viewMode]); const segments = useMemo(() => buildEventSegments(calendarEvents, gridStart, weeks), [gridStart, weeks]); const yearOptions = useMemo(() => { const baseYear = dayjs().year(); const startYear = Math.min(2020, baseYear - 4); return Array.from({ length: 10 }, (_, index) => startYear + index); }, []); const handleYearChange = (year) => { setCurrentDate((prev) => prev.year(year)); }; const handleMonthChange = (month) => { setCurrentDate((prev) => prev.month(month - 1)); }; const handleViewChange = (mode) => { setViewMode(mode); }; const handleBackToToday = () => { const today = dayjs(); setCurrentDate(today); setViewMode('month'); }; return (
({ value: index + 1, label: `${index + 1}月`, }))} />
{weekDays.map((day) => (
{day}
))}
{days.map((day) => { const isCurrentMonth = day.month() === currentDate.month(); return (
{day.date()}
); })} {segments.map((segment) => (
{segment.title}
{segment.icon}
))}
); }; export default ActivityCalendar;