完整的教务系统前端项目 - 包含所有修复和9月份数据

This commit is contained in:
KQL
2025-09-03 13:26:13 +08:00
commit 87b06d3176
270 changed files with 116169 additions and 0 deletions

View File

@@ -0,0 +1,139 @@
import { useEffect } from "react";
import Portal from "@/components/Portal";
const EventDetailModal = ({ isOpen, event, onClose }) => {
// ESC键关闭模态框
useEffect(() => {
const handleEscKey = (e) => {
if (e.key === "Escape" && isOpen) {
onClose();
}
};
if (isOpen) {
document.addEventListener("keydown", handleEscKey);
}
return () => {
document.removeEventListener("keydown", handleEscKey);
};
}, [isOpen, onClose]);
// 如果未打开或无事件数据,不渲染
if (!isOpen || !event) {
return null;
}
// 事件类型映射
const eventTypeNames = {
class: "课程",
meeting: "会议",
lab: "实验",
exam: "考试",
};
// 处理遮罩层点击
const handleOverlayClick = (e) => {
if (e.target === e.currentTarget) {
onClose();
}
};
// 处理关闭按钮点击
const handleCloseClick = () => {
onClose();
};
// 格式化时间显示
const formatTimeRange = (startTime, endTime) => {
const startDate = new Date(startTime.replace(" ", "T"));
const endDate = new Date(endTime.replace(" ", "T"));
const formatTime = (date) => {
return date.toLocaleTimeString("zh-CN", {
hour: "2-digit",
minute: "2-digit",
hour12: false,
});
};
const formatDate = (date) => {
return date.toLocaleDateString("zh-CN", {
year: "numeric",
month: "long",
day: "numeric",
weekday: "long",
});
};
return {
date: formatDate(startDate),
timeRange: `${formatTime(startDate)} - ${formatTime(endDate)}`,
};
};
const { date, timeRange } = formatTimeRange(event.startTime, event.endTime);
return (
<Portal className="event-detail-portal">
<div className="event-detail-overlay" onClick={handleOverlayClick}>
<div className="event-detail-modal">
{/* 模态框头部 */}
<div className="event-detail-header">
<h3 className="event-detail-title">事件详情</h3>
<button
className="event-detail-close"
onClick={handleCloseClick}
type="button"
>
×
</button>
</div>
{/* 模态框内容 */}
<div className="event-detail-content">
{/* 事件标题 */}
<div className="event-detail-field">
<div className="event-detail-label">事件标题</div>
<div className="event-detail-value">{event.title}</div>
</div>
{/* 事件类型 */}
<div className="event-detail-field">
<div className="event-detail-label">事件类型</div>
<div className="event-detail-value">
<span className={`event-type-badge event-type-${event.type}`}>
{eventTypeNames[event.type] || event.type}
</span>
</div>
</div>
{/* 日期 */}
<div className="event-detail-field">
<div className="event-detail-label">日期</div>
<div className="event-detail-value">{date}</div>
</div>
{/* 时间 */}
<div className="event-detail-field">
<div className="event-detail-label">时间</div>
<div className="event-detail-value">
<div className="event-time-range">{timeRange}</div>
</div>
</div>
{/* 详细描述 */}
{event.description && (
<div className="event-detail-field">
<div className="event-detail-label">详细描述</div>
<div className="event-detail-value">{event.description}</div>
</div>
)}
</div>
</div>
</div>
</Portal>
);
};
export default EventDetailModal;