本文目录导读:

我来详细讲解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响应格式,你可以根据项目需求进行调整和扩展。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播