Files
jiaowu-test/src/pages/CalendarPage/index.css

783 lines
14 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* CSS变量定义 */
:root {
--primary-color: #3b82f6;
--border-color: #e5e6eb;
--text-color: #1d2129;
--text-muted: #86909c;
--bg-hover: #f2f3f5;
}
/* 日历页面样式 */
.calendar-page {
width: 100%;
height: 100%;
padding: 20px;
.calendar-page-wrapper {
width: 1120px;
height: 862px;
display: flex;
padding: 20px;
background-color: #fff;
flex-direction: column;
}
}
/* 日历头部控制栏 */
.calendar-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 0;
margin-bottom: 24px;
border-bottom: 1px solid var(--border-color);
}
.calendar-nav {
display: flex;
align-items: center;
gap: 16px;
}
.nav-button {
width: 32px;
height: 32px;
border: 1px solid var(--border-color);
background: white;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.15s ease;
color: var(--text-secondary);
}
.nav-button:hover {
background: #f3f4f6;
border-color: var(--primary-color);
color: var(--primary-color);
}
.nav-button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.calendar-title {
font-size: 20px;
font-weight: 600;
color: var(--text-primary);
margin: 0 8px;
}
.view-switcher {
display: flex;
background: #f3f4f6;
border-radius: 6px;
padding: 2px;
}
.view-button {
padding: 6px 16px;
border: none;
background: none;
border-radius: 4px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.15s ease;
color: var(--text-secondary);
}
.view-button.active {
background: var(--text-primary);
color: white;
}
.view-button:hover:not(.active) {
background: #e5e7eb;
}
/* 日历主体容器 */
.calendar-container {
flex: 1;
background: white;
border-radius: 8px;
box-shadow: var(--shadow);
border: 1px solid var(--border-color);
overflow: hidden;
}
/* 月视图样式 */
.month-view {
height: 100%;
display: flex;
flex-direction: column;
}
.month-header {
display: grid;
grid-template-columns: repeat(7, 1fr);
background: #f8fafc;
border-bottom: 1px solid var(--border-color);
}
.weekday-header {
padding: 12px 8px;
text-align: center;
font-size: 13px;
font-weight: 600;
color: var(--text-secondary);
border-right: 1px solid #e5e7eb;
}
.weekday-header:last-child {
border-right: none;
}
.month-grid {
flex: 1;
display: grid;
grid-template-columns: repeat(7, 1fr);
grid-template-rows: repeat(6, 1fr);
gap: 1px;
background: #e5e7eb;
padding: 1px;
}
.day-cell {
background: white;
padding: 10px;
display: flex;
flex-direction: column;
cursor: pointer;
transition: all 0.3s ease;
min-height: 90px;
position: relative;
border-radius: 10px;
border: 1px solid #e8e8f0;
margin: 3px;
}
.day-cell:hover {
background: linear-gradient(135deg, #fafbff 0%, #f5f7ff 100%);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.08);
transform: translateY(-2px);
border-color: #d4deff;
}
.day-cell.other-month {
background: #fafbfc;
color: #b8bcc8;
opacity: 0.5;
}
.day-cell.today {
background: linear-gradient(135deg, #e8f4ff 0%, #f0f9ff 100%) !important;
border: 2px solid #3b82f6;
box-shadow: 0 6px 16px rgba(59, 130, 246, 0.12);
}
.day-cell.selected {
background: linear-gradient(135deg, #dbeafe 0%, #e6f2ff 100%) !important;
border: 2px solid #2563eb;
box-shadow: 0 4px 12px rgba(37, 99, 235, 0.15);
}
.day-number {
font-size: 14px;
font-weight: 500;
margin-bottom: 4px;
align-self: flex-start;
}
.day-cell.today .day-number {
background: #3b82f6;
color: white;
width: 24px;
height: 24px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
}
.event-list {
flex: 1;
display: flex;
flex-direction: column;
gap: 2px;
overflow: hidden;
}
.event-item {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
font-size: 11px;
padding: 4px 8px;
border-radius: 6px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: pointer;
transition: all 0.3s ease;
margin: 2px 0;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
font-weight: 500;
}
.event-item:hover {
transform: translateX(2px);
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15);
}
.event-item.class {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.event-item.meeting {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
}
.event-item.lab {
background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
}
.event-item.exam {
background: linear-gradient(135deg, #ff6b6b 0%, #ff8e53 100%);
}
.event-more {
font-size: 9px;
color: var(--text-muted);
margin-top: 2px;
}
/* 周视图样式 */
.week-view {
height: 100%;
display: flex;
flex-direction: column;
}
.week-header {
display: grid;
grid-template-columns: 60px repeat(7, 1fr);
background: #f8fafc;
border-bottom: 1px solid var(--border-color);
position: sticky;
top: 0;
z-index: var(--z-header); /* 使用全局header层级确保不干扰弹窗 */
}
.time-header {
padding: 12px 8px;
font-size: 12px;
font-weight: 600;
color: var(--text-secondary);
border-right: 1px solid #e5e7eb;
display: flex;
align-items: center;
justify-content: center;
}
.day-header {
padding: 12px 8px;
text-align: center;
border-right: 1px solid #e5e7eb;
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
}
.day-header:last-child {
border-right: none;
}
.day-name {
font-size: 12px;
font-weight: 500;
color: var(--text-secondary);
}
.day-date {
font-size: 16px;
font-weight: 600;
color: var(--text-primary);
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
}
.day-header.today .day-date {
background: var(--primary-color);
color: white;
}
.week-grid {
flex: 1;
display: grid;
grid-template-columns: 60px repeat(7, 1fr);
overflow-y: auto;
position: relative;
}
.time-column {
border-right: 1px solid #e5e7eb;
background: #fafbfc;
display: flex;
flex-direction: column;
}
.time-slot {
height: 60px;
border-bottom: 1px solid #f3f4f6;
display: flex;
align-items: flex-start;
padding: 4px 8px;
font-size: 11px;
color: var(--text-muted);
position: relative;
}
.time-slot:nth-child(odd) {
background: #fbfcfd;
}
.day-column {
border-right: 1px solid #f3f4f6;
position: relative;
display: flex;
flex-direction: column;
}
.day-column:last-child {
border-right: none;
}
.hour-slot {
height: 60px;
border-bottom: 1px solid #f3f4f6;
position: relative;
}
.hour-slot:nth-child(odd) {
background: #fbfcfd;
}
.event-block {
position: absolute;
left: 4px;
right: 4px;
background: var(--primary-color);
color: white;
border-radius: 4px;
padding: 4px 6px;
font-size: 11px;
z-index: 5;
cursor: pointer;
transition: all 0.15s ease;
overflow: hidden;
display: flex;
flex-direction: column;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.event-block:hover {
transform: translateY(-1px);
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
}
.event-block.class {
background: #3b82f6;
}
.event-block.meeting {
background: #10b981;
}
.event-block.lab {
background: #f59e0b;
}
.event-block.exam {
background: #ef4444;
}
.event-title {
font-weight: 600;
margin-bottom: 2px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.event-time {
font-size: 10px;
opacity: 0.9;
}
/* 当前时间线 - 使用合理的层级 */
.current-time-line {
position: absolute;
left: 60px;
right: 0;
height: 2px;
background: #ef4444;
z-index: var(--z-content); /* 使用内容层级,不需要很高 */
pointer-events: none;
}
.current-time-line::before {
content: "";
position: absolute;
left: -6px;
top: -4px;
width: 10px;
height: 10px;
background: #ef4444;
border-radius: 50%;
}
/* 空状态 */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 200px;
color: var(--text-muted);
}
.empty-state-icon {
font-size: 48px;
margin-bottom: 16px;
opacity: 0.5;
}
.empty-state-text {
font-size: 16px;
margin-bottom: 8px;
}
.empty-state-description {
font-size: 14px;
opacity: 0.7;
}
/* 事件详情提示 - 使用全局z-index系统 */
.event-tooltip {
position: absolute;
background: var(--text-primary);
color: white;
padding: 8px 12px;
border-radius: 6px;
font-size: 12px;
z-index: var(--z-tooltip); /* 使用全局tooltip层级 */
max-width: 200px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
pointer-events: none;
}
.event-tooltip::after {
content: "";
position: absolute;
bottom: -6px;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-top: 6px solid var(--text-primary);
}
/* 事件详情模态框样式 - 遵循跨国企业级后台系统设计哲学v2.0 */
/* 模态框遮罩层 */
.event-detail-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: var(--z-modal);
display: flex;
align-items: center;
justify-content: center;
animation: overlayFadeIn 200ms ease-out;
}
@keyframes overlayFadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
/* 模态框主体 - 零线原则,依赖留白分隔 */
.event-detail-modal {
background: #ffffff;
border-radius: 8px;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15), 0 4px 6px rgba(0, 0, 0, 0.1);
width: 480px;
max-width: 90vw;
max-height: 80vh;
overflow: auto;
animation: modalSlideIn 250ms ease-out;
}
@keyframes modalSlideIn {
from {
opacity: 0;
transform: scale(0.95) translateY(-10px);
}
to {
opacity: 1;
transform: scale(1) translateY(0);
}
}
/* 模态框头部 - 呼吸感间距 */
.event-detail-header {
padding: 24px 24px 16px 24px;
border-bottom: 1px solid #f3f4f6;
display: flex;
justify-content: space-between;
align-items: center;
}
/* 标题 - 意图驱动的信息层级 L1 */
.event-detail-title {
font-size: 18px;
font-weight: 600;
color: #111827;
margin: 0;
}
/* 关闭按钮 - 上下文感知交互 */
.event-detail-close {
width: 32px;
height: 32px;
border: none;
background: #f9fafb;
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
color: #6b7280;
font-size: 18px;
transition: all 150ms ease;
}
.event-detail-close:hover {
background: #f3f4f6;
color: #374151;
}
.event-detail-close:focus {
outline: 2px solid #3b82f6;
outline-offset: 2px;
}
/* 模态框内容区域 - 慷慨的留白 */
.event-detail-content {
padding: 24px;
}
/* 字段容器 - 基于8px栅格的间距 */
.event-detail-field {
margin-bottom: 24px;
}
.event-detail-field:last-child {
margin-bottom: 0;
}
/* 字段标签 - 信息层级 L3 */
.event-detail-label {
font-size: 12px;
font-weight: 600;
color: #6b7280;
text-transform: uppercase;
letter-spacing: 0.05em;
margin-bottom: 8px;
}
/* 字段值 - 信息层级 L2 */
.event-detail-value {
font-size: 15px;
color: #111827;
line-height: 1.5;
}
/* 事件类型徽章 - 语义化状态色板 */
.event-type-badge {
display: inline-block;
padding: 6px 12px;
border-radius: 12px;
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
}
/* 克制的色彩语言 - 柔和且低饱和度 */
.event-type-class {
background: #dbeafe;
color: #1e40af;
}
.event-type-meeting {
background: #d1fae5;
color: #065f46;
}
.event-type-lab {
background: #fef3c7;
color: #92400e;
}
.event-type-exam {
background: #fee2e2;
color: #991b1b;
}
/* 时间范围显示 - 等宽字体增强可读性 */
.event-time-range {
font-family: "SF Mono", "Monaco", "Cascadia Code", "Consolas", monospace;
font-size: 14px;
color: #374151;
background: #f9fafb;
padding: 12px 16px;
border-radius: 6px;
border-left: 3px solid #3b82f6;
font-weight: 500;
}
/* 响应式设计 */
@media (max-width: 1024px) {
.calendar-header {
flex-direction: column;
gap: 16px;
align-items: stretch;
}
.calendar-nav {
justify-content: center;
}
.view-switcher {
align-self: center;
}
.day-cell {
min-height: 60px;
padding: 4px;
}
.event-item {
font-size: 9px;
padding: 1px 2px;
}
}
@media (max-width: 768px) {
.calendar-title {
font-size: 18px;
}
.nav-button {
width: 28px;
height: 28px;
}
.view-button {
padding: 4px 12px;
font-size: 13px;
}
.week-grid {
grid-template-columns: 50px repeat(7, 1fr);
}
.time-header,
.time-column {
width: 50px;
}
.time-slot {
padding: 2px 4px;
font-size: 10px;
}
.day-cell {
min-height: 50px;
padding: 2px;
}
.day-number {
font-size: 12px;
}
.event-item {
font-size: 8px;
padding: 1px;
}
}
/* 加载状态 */
.calendar-loading {
display: flex;
align-items: center;
justify-content: center;
height: 200px;
color: var(--text-muted);
}
.loading-spinner {
width: 32px;
height: 32px;
border: 3px solid #f3f4f6;
border-top: 3px solid var(--primary-color);
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
/* 响应式设计 */
@media (max-width: 640px) {
.event-detail-modal {
width: 95vw;
margin: 16px;
}
.event-detail-header,
.event-detail-content {
padding: 16px;
}
.event-detail-field {
margin-bottom: 16px;
}
}