PHP项目日历功能如何后端生成数据

wen PHP项目 30

本文目录导读:

PHP项目日历功能如何后端生成数据

  1. 基础日历数据结构
  2. 事件和日程管理
  3. 组合日历数据
  4. 节假日管理
  5. API响应格式
  6. 前端数据结构示例

我来详细讲解PHP项目日历功能的后端数据生成方案。

基础日历数据结构

核心数据模型

class CalendarData {
    // 获取某月的日历数据
    public static function getMonthData($year, $month) {
        $firstDay = mktime(0, 0, 0, $month, 1, $year);
        $daysInMonth = date('t', $firstDay);
        $firstDayOfWeek = date('w', $firstDay); // 0=周日, 1=周一...
        $monthData = [];
        // 上月填充
        $prevMonth = $month == 1 ? 12 : $month - 1;
        $prevYear = $month == 1 ? $year - 1 : $year;
        $prevDays = date('t', mktime(0, 0, 0, $prevMonth, 1, $prevYear));
        $dayCount = 0;
        // 填充上月最后几天
        for ($i = 0; $i < $firstDayOfWeek; $i++) {
            $monthData[] = [
                'day' => $prevDays - $firstDayOfWeek + $i + 1,
                'month' => $prevMonth,
                'year' => $prevYear,
                'isCurrentMonth' => false,
                'date' => sprintf('%d-%02d-%02d', $prevYear, $prevMonth, $prevDays - $firstDayOfWeek + $i + 1),
                'timestamp' => mktime(0, 0, 0, $prevMonth, $prevDays - $firstDayOfWeek + $i + 1, $prevYear)
            ];
        }
        // 当月天数
        for ($i = 1; $i <= $daysInMonth; $i++) {
            $currentDate = sprintf('%d-%02d-%02d', $year, $month, $i);
            $timestamp = mktime(0, 0, 0, $month, $i, $year);
            $monthData[] = [
                'day' => $i,
                'month' => $month,
                'year' => $year,
                'isCurrentMonth' => true,
                'isToday' => $currentDate == date('Y-m-d'),
                'date' => $currentDate,
                'timestamp' => $timestamp,
                'dayOfWeek' => date('w', $timestamp)
            ];
        }
        // 下月填充(补齐6行)
        $remainingCells = 42 - count($monthData); // 6行x7列=42
        $nextMonth = $month == 12 ? 1 : $month + 1;
        $nextYear = $month == 12 ? $year + 1 : $year;
        for ($i = 1; $i <= $remainingCells; $i++) {
            $monthData[] = [
                'day' => $i,
                'month' => $nextMonth,
                'year' => $nextYear,
                'isCurrentMonth' => false,
                'date' => sprintf('%d-%02d-%02d', $nextYear, $nextMonth, $i),
                'timestamp' => mktime(0, 0, 0, $nextMonth, $i, $nextYear)
            ];
        }
        return [
            'year' => $year,
            'month' => $month,
            'monthName' => date('F', $firstDay),
            'days' => $monthData,
            'totalDays' => $daysInMonth,
            'startDayOfWeek' => $firstDayOfWeek
        ];
    }
}

事件和日程管理

数据库表结构

CREATE TABLE calendar_events (
    id INT PRIMARY KEY AUTO_INCREMENT,
    user_id INT NOT NULL,VARCHAR(200) NOT NULL,
    description TEXT,
    event_date DATE NOT NULL,
    start_time TIME,
    end_time TIME,
    event_type ENUM('event', 'task', 'reminder', 'holiday') DEFAULT 'event',
    status ENUM('pending', 'completed', 'cancelled') DEFAULT 'pending',
    color VARCHAR(7) DEFAULT '#1890ff',
    is_recurring BOOLEAN DEFAULT FALSE,
    recurrence_rule TEXT, -- JSON格式的重复规则
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users(id),
    INDEX idx_user_date (user_id, event_date)
);

事件查询类

class EventManager {
    private $db;
    public function __construct(PDO $db) {
        $this->db = $db;
    }
    // 获取某月的事件
    public function getMonthEvents($userId, $year, $month) {
        $startDate = sprintf('%d-%02d-01', $year, $month);
        $endDate = date('Y-m-t', strtotime($startDate));
        $stmt = $this->db->prepare("
            SELECT * FROM calendar_events 
            WHERE user_id = ? 
            AND event_date BETWEEN ? AND ?
            ORDER BY event_date, start_time
        ");
        $stmt->execute([$userId, $startDate, $endDate]);
        $events = $stmt->fetchAll(PDO::FETCH_ASSOC);
        // 处理重复事件
        $recurringEvents = $this->getRecurringEvents($userId, $startDate, $endDate);
        return array_merge($events, $recurringEvents);
    }
    // 获取重复事件
    private function getRecurringEvents($userId, $startDate, $endDate) {
        $stmt = $this->db->prepare("
            SELECT * FROM calendar_events 
            WHERE user_id = ? 
            AND is_recurring = TRUE
            AND (event_date <= ? OR event_date IS NULL)
        ");
        $stmt->execute([$userId, $endDate]);
        $recurringEvents = $stmt->fetchAll(PDO::FETCH_ASSOC);
        $expandedEvents = [];
        foreach ($recurringEvents as $event) {
            $rule = json_decode($event['recurrence_rule'], true);
            if ($rule) {
                $expanded = $this->expandRecurringEvent($event, $rule, $startDate, $endDate);
                $expandedEvents = array_merge($expandedEvents, $expanded);
            }
        }
        return $expandedEvents;
    }
    // 展开重复事件
    private function expandRecurringEvent($event, $rule, $startDate, $endDate) {
        $events = [];
        $currentDate = $event['event_date'];
        $start = new DateTime($startDate);
        $end = new DateTime($endDate);
        switch ($rule['type']) {
            case 'daily':
                $interval = new DateInterval("P1D");
                break;
            case 'weekly':
                $interval = new DateInterval("P1W");
                break;
            case 'monthly':
                $interval = new DateInterval("P1M");
                break;
            case 'yearly':
                $interval = new DateInterval("P1Y");
                break;
            default:
                return [];
        }
        if (isset($rule['end_date'])) {
            $endDateLimit = min($end, new DateTime($rule['end_date']));
        } else {
            $endDateLimit = $end;
        }
        $dateIterator = new DateTime($event['event_date']);
        while ($dateIterator <= $endDateLimit) {
            if ($dateIterator >= $start) {
                $newEvent = $event;
                $newEvent['event_date'] = $dateIterator->format('Y-m-d');
                $newEvent['is_recurring_instance'] = true;
                $newEvent['original_event_id'] = $event['id'];
                $events[] = $newEvent;
            }
            $dateIterator->add($interval);
            // 防止无限循环
            if (count($events) > 365) break;
        }
        return $events;
    }
}

组合日历数据

完整日历响应类

class CalendarService {
    private $eventManager;
    private $holidayManager;
    public function __construct(PDO $db) {
        $this->eventManager = new EventManager($db);
        $this->holidayManager = new HolidayManager();
    }
    // 获取完整日历数据
    public function getFullCalendarData($userId, $year, $month, $options = []) {
        // 基础日历数据
        $calendarData = CalendarData::getMonthData($year, $month);
        // 获取事件
        $events = $this->eventManager->getMonthEvents($userId, $year, $month);
        // 获取节假日
        $holidays = [];
        if ($options['include_holidays'] ?? true) {
            $holidays = $this->holidayManager->getMonthHolidays($year, $month);
        }
        // 合并数据到每一天
        $eventMap = $this->indexEventsByDate($events);
        $holidayMap = $this->indexEventsByDate($holidays);
        foreach ($calendarData['days'] as &$day) {
            $date = $day['date'];
            // 添加事件
            $day['events'] = $eventMap[$date] ?? [];
            // 添加节假日
            $day['holidays'] = $holidayMap[$date] ?? [];
            // 添加节日标记
            $day['isHoliday'] = !empty($day['holidays']);
            // 计算事件数量
            $day['eventCount'] = count($day['events']);
            // 判断是否有重要事件
            $day['hasImportantEvent'] = $this->hasImportantEvent($day['events']);
        }
        // 添加周信息
        $calendarData['weeks'] = $this->groupByWeeks($calendarData['days']);
        // 添加月份统计
        $calendarData['statistics'] = $this->getMonthStatistics($events, $year, $month);
        return $calendarData;
    }
    // 按日期索引事件
    private function indexEventsByDate($events) {
        $indexed = [];
        foreach ($events as $event) {
            $date = $event['event_date'];
            if (!isset($indexed[$date])) {
                $indexed[$date] = [];
            }
            $indexed[$date][] = $event;
        }
        return $indexed;
    }
    // 分组为周
    private function groupByWeeks($days) {
        $weeks = [];
        $currentWeek = [];
        foreach ($days as $index => $day) {
            $currentWeek[] = $day;
            // 每7天为一组(从周日开始)
            if (($index + 1) % 7 == 0) {
                $weeks[] = $currentWeek;
                $currentWeek = [];
            }
        }
        // 处理剩余天数
        if (!empty($currentWeek)) {
            $weeks[] = $currentWeek;
        }
        return $weeks;
    }
    // 月度统计
    private function getMonthStatistics($events, $year, $month) {
        $totalEvents = count($events);
        $completedEvents = 0;
        $eventTypes = [];
        foreach ($events as $event) {
            if ($event['status'] == 'completed') {
                $completedEvents++;
            }
            $type = $event['event_type'];
            if (!isset($eventTypes[$type])) {
                $eventTypes[$type] = 0;
            }
            $eventTypes[$type]++;
        }
        return [
            'totalEvents' => $totalEvents,
            'completedEvents' => $completedEvents,
            'completionRate' => $totalEvents > 0 ? round($completedEvents / $totalEvents * 100, 2) : 0,
            'eventTypes' => $eventTypes
        ];
    }
    private function hasImportantEvent($events) {
        foreach ($events as $event) {
            if ($event['event_type'] == 'reminder' || $event['priority'] == 'high') {
                return true;
            }
        }
        return false;
    }
}

节假日管理

class HolidayManager {
    // 中国节假日API(示例)
    public function getMonthHolidays($year, $month) {
        // 方式1:调用外部API
        // $holidays = $this->fetchFromApi($year, $month);
        // 方式2:本地节假日数据
        $holidays = $this->getLocalHolidays($year, $month);
        return $holidays;
    }
    private function getLocalHolidays($year, $month) {
        $holidays = [];
        // 固定假日
        $fixedHolidays = [
            '01-01' => '元旦',
            '02-14' => '情人节',
            '03-08' => '妇女节',
            '04-01' => '愚人节',
            '05-01' => '劳动节',
            '06-01' => '儿童节',
            '10-01' => '国庆节',
            '12-25' => '圣诞节'
        ];
        foreach ($fixedHolidays as $date => $name) {
            list($holidayMonth, $holidayDay) = explode('-', $date);
            if ($holidayMonth == sprintf('%02d', $month)) {
                $dateStr = sprintf('%d-%s', $year, $date);
                $holidays[] = [
                    'date' => $dateStr,
                    'name' => $name,
                    'type' => 'fixed',
                    'isWorkday' => false
                ];
            }
        }
        // 计算农历节日(需要农历转换库)
        if ($lunarHolidays = $this->getLunarHolidays($year, $month)) {
            $holidays = array_merge($holidays, $lunarHolidays);
        }
        return $holidays;
    }
    private function getLunarHolidays($year, $month) {
        // 需要使用农历转换库,如 lunar-calendar
        // 这里仅作示例
        return [];
    }
}

API响应格式

class CalendarController {
    public function getMonthData() {
        $year = $_GET['year'] ?? date('Y');
        $month = $_GET['month'] ?? date('m');
        $userId = $this->getCurrentUserId();
        $service = new CalendarService($this->db);
        $data = $service->getFullCalendarData($userId, $year, $month);
        return json_encode([
            'success' => true,
            'data' => $data,
            'pagination' => [
                'prevMonth' => $month == 1 ? 12 : $month - 1,
                'prevYear' => $month == 1 ? $year - 1 : $year,
                'nextMonth' => $month == 12 ? 1 : $month + 1,
                'nextYear' => $month == 12 ? $year + 1 : $year
            ]
        ]);
    }
}

前端数据结构示例

// 前端接收的日历数据结构
{
  year: 2024,
  month: 1,
  monthName: "January",
  days: [
    {
      day: 29,
      month: 12,
      year: 2023,
      isCurrentMonth: false,
      date: "2023-12-29",
      events: [],
      holidays: [],
      isHoliday: false,
      eventCount: 0,
      hasImportantEvent: false
    },
    {
      day: 1,
      month: 1,
      year: 2024,
      isCurrentMonth: true,
      isToday: true,
      date: "2024-01-01",
      events: [
        {
          id: 1,
          title: "新年快乐",
          start_time: "09:00:00",
          end_time: "10:00:00",
          event_type: "holiday",
          color: "#ff4d4f"
        }
      ],
      holidays: [
        {
          date: "2024-01-01",
          name: "元旦",
          type: "fixed",
          isWorkday: false
        }
      ],
      isHoliday: true,
      eventCount: 1,
      hasImportantEvent: true
    }
  ],
  weeks: [
    // 每周7天分组
  ],
  statistics: {
    totalEvents: 5,
    completedEvents: 2,
    completionRate: 40,
    eventTypes: {
      event: 3,
      task: 2
    }
  }
}

这个方案提供了完整的后端日历数据生成方案,包括基础日历结构、事件管理、节假日处理和完整的API响应格式,你可以根据项目需求进行调整和扩展。

抱歉,评论功能暂时关闭!