/* 加载动画 */ .loading-spinner { width: 40px; height: 40px; border: 4px solid #f3f4f6; border-top: 4px solid #3b82f6; border-radius: 50%; animation: spin 1s linear infinite; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } /* 小型加载动画 */ .loading-spinner-sm { width: 20px; height: 20px; border: 2px solid #f3f4f6; border-top: 2px solid #3b82f6; border-radius: 50%; animation: spin 1s linear infinite; } /* 表格加载效果 */ .skeleton-loader { background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%); background-size: 200% 100%; animation: loading 1.5s infinite; } @keyframes loading { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } } /* 通话状态指示器 */ .call-status { position: relative; display: inline-flex; align-items: center; } .call-status.active::before { content: ''; position: absolute; top: 50%; left: 50%; width: 12px; height: 12px; background-color: #22c55e; border-radius: 50%; transform: translate(-50%, -50%); animation: pulse 2s infinite; } .call-status.pending::before { content: ''; position: absolute; top: 50%; left: 50%; width: 12px; height: 12px; background-color: #f59e0b; border-radius: 50%; transform: translate(-50%, -50%); animation: pulse 2s infinite; } .call-status.ended::before { content: ''; position: absolute; top: 50%; left: 50%; width: 12px; height: 12px; background-color: #ef4444; border-radius: 50%; transform: translate(-50%, -50%); } @keyframes pulse { 0%, 100% { transform: translate(-50%, -50%) scale(1); opacity: 1; } 50% { transform: translate(-50%, -50%) scale(1.1); opacity: 0.8; } } /* 状态徽章 */ .status-badge { display: inline-flex; align-items: center; padding: 0.25rem 0.75rem; border-radius: 9999px; font-size: 0.75rem; font-weight: 500; text-transform: uppercase; letter-spacing: 0.025em; } .status-badge.active { background-color: #d1fae5; color: #065f46; } .status-badge.pending { background-color: #fef3c7; color: #92400e; } .status-badge.ended { background-color: #fee2e2; color: #991b1b; } .status-badge.paused { background-color: #e5e7eb; color: #374151; } /* 卡片悬停效果 */ .card-hover { transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out; } .card-hover:hover { transform: translateY(-2px); box-shadow: 0 10px 25px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); } /* 按钮样式 */ .btn { display: inline-flex; align-items: center; padding: 0.5rem 1rem; border-radius: 0.375rem; font-size: 0.875rem; font-weight: 500; line-height: 1.25rem; cursor: pointer; transition: all 0.2s ease-in-out; text-decoration: none; } .btn:disabled { opacity: 0.5; cursor: not-allowed; } .btn-primary { background-color: #3b82f6; color: white; } .btn-primary:hover:not(:disabled) { background-color: #2563eb; } .btn-secondary { background-color: #6b7280; color: white; } .btn-secondary:hover:not(:disabled) { background-color: #4b5563; } .btn-success { background-color: #10b981; color: white; } .btn-success:hover:not(:disabled) { background-color: #059669; } .btn-warning { background-color: #f59e0b; color: white; } .btn-warning:hover:not(:disabled) { background-color: #d97706; } .btn-danger { background-color: #ef4444; color: white; } .btn-danger:hover:not(:disabled) { background-color: #dc2626; } .btn-outline { border: 1px solid #d1d5db; background-color: transparent; color: #374151; } .btn-outline:hover:not(:disabled) { background-color: #f9fafb; border-color: #9ca3af; } /* 表单样式 */ .form-input { display: block; width: 100%; padding: 0.5rem 0.75rem; border: 1px solid #d1d5db; border-radius: 0.375rem; font-size: 0.875rem; line-height: 1.25rem; transition: border-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out; } .form-input:focus { outline: none; border-color: #3b82f6; box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); } .form-input.error { border-color: #ef4444; } .form-input.error:focus { border-color: #ef4444; box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1); } .form-label { display: block; font-size: 0.875rem; font-weight: 500; color: #374151; margin-bottom: 0.25rem; } .form-error { margin-top: 0.25rem; font-size: 0.75rem; color: #ef4444; } .form-help { margin-top: 0.25rem; font-size: 0.75rem; color: #6b7280; } /* 模态框样式 */ .modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; z-index: 50; } .modal-content { background-color: white; border-radius: 0.5rem; box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); max-width: 90vw; max-height: 90vh; overflow: auto; } /* 通知样式 */ .notification { position: fixed; top: 1rem; right: 1rem; max-width: 320px; background-color: white; border-radius: 0.5rem; box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); border-left: 4px solid #3b82f6; padding: 1rem; z-index: 40; animation: slideIn 0.3s ease-out; } .notification.success { border-left-color: #10b981; } .notification.warning { border-left-color: #f59e0b; } .notification.error { border-left-color: #ef4444; } @keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } } /* 进度条 */ .progress-bar { width: 100%; height: 0.5rem; background-color: #e5e7eb; border-radius: 9999px; overflow: hidden; } .progress-fill { height: 100%; background-color: #3b82f6; transition: width 0.3s ease-in-out; } /* 数据表格样式 */ .data-table { width: 100%; border-collapse: collapse; } .data-table th, .data-table td { padding: 0.75rem; text-align: left; border-bottom: 1px solid #e5e7eb; } .data-table th { background-color: #f9fafb; font-weight: 500; color: #374151; font-size: 0.875rem; text-transform: uppercase; letter-spacing: 0.025em; } .data-table tr:hover { background-color: #f9fafb; } .data-table .sortable { cursor: pointer; user-select: none; } .data-table .sortable:hover { background-color: #f3f4f6; } /* 响应式设计 */ @media (max-width: 640px) { .card-hover { transform: none; } .card-hover:hover { transform: none; box-shadow: none; } .btn { padding: 0.375rem 0.75rem; font-size: 0.75rem; } .modal-content { margin: 1rem; max-width: calc(100vw - 2rem); } } /* 打印样式 */ @media print { .btn, .loading-spinner, .modal-overlay { display: none !important; } .card-hover { box-shadow: none !important; } }