8397 lines
238 KiB
Diff
8397 lines
238 KiB
Diff
From 9fc5e3e607f7083a3fdede858a401eb4453397c1 Mon Sep 17 00:00:00 2001
|
||
From: HenryDu8133 <813367384@qq.com>
|
||
Date: Sat, 12 Sep 2026 15:56:10 +0800
|
||
Subject: [PATCH 55/58] =?UTF-8?q?fix(ui):=20=E6=89=B9=E9=87=8F=E6=9B=BF?=
|
||
=?UTF-8?q?=E6=8D=A2=E6=89=80=E6=9C=89=E7=BB=84=E4=BB=B6=E4=B8=AD=E6=AE=8B?=
|
||
=?UTF-8?q?=E7=95=99=E7=9A=84=E7=A1=AC=E7=BC=96=E7=A0=81=E6=B7=B1=E8=89=B2?=
|
||
=?UTF-8?q?=E5=80=BC=E4=BB=A5=E5=BD=BB=E5=BA=95=E6=94=AF=E6=8C=81=E6=B5=85?=
|
||
=?UTF-8?q?=E8=89=B2=E4=B8=BB=E9=A2=98?=
|
||
MIME-Version: 1.0
|
||
Content-Type: text/plain; charset=UTF-8
|
||
Content-Transfer-Encoding: 8bit
|
||
|
||
---
|
||
app/components/Admin/ApiKeyManager.vue | 4 +-
|
||
app/components/Admin/BackupManager.vue | 54 +-
|
||
app/components/Admin/BlacklistManager.vue | 2 +-
|
||
app/components/Admin/EmailTemplateManager.vue | 2 +-
|
||
app/components/Admin/NotificationSender.vue | 2 +-
|
||
app/components/Admin/OverviewDashboard.vue | 2 +-
|
||
app/components/Admin/RequestTimeManager.vue | 2 +-
|
||
app/components/Admin/ScheduleItemPrint.vue | 26 +-
|
||
app/components/Admin/SchedulePrinter.vue | 34 +-
|
||
app/components/Admin/Sidebar.vue | 2 +-
|
||
app/components/Admin/SongDownloadDialog.vue | 2 +-
|
||
app/components/Admin/SongManagement.vue | 2 +-
|
||
app/components/Admin/VotersModal.vue | 46 +-
|
||
app/components/Auth/OAuthButtons.vue | 16 +-
|
||
app/components/Auth/RegisterForm.vue | 2 +-
|
||
.../Notifications/NotificationSettings.vue | 4 +-
|
||
app/components/Player/PlayerLyric/AMLyric.vue | 2 +-
|
||
.../Player/PlayerLyric/DefaultLyric.vue | 2 +-
|
||
app/components/Songs/RequestForm.vue | 100 +-
|
||
app/components/Songs/ScheduleList.vue | 76 +-
|
||
app/components/Songs/SongList.vue | 58 +-
|
||
app/components/UI/AudioPlayer.vue | 50 +-
|
||
app/components/UI/Common/CustomSelect.vue | 2 +-
|
||
app/components/UI/LyricsModal.vue | 18 +-
|
||
app/components/UI/Notification.vue | 12 +-
|
||
app/components/UI/NotificationContainer.vue | 12 +-
|
||
app/components/UserTutorial.vue | 12 +-
|
||
app/components/year-review/ArtistSlide.vue | 2 +-
|
||
app/components/year-review/FirstSongSlide.vue | 8 +-
|
||
app/components/year-review/IntroSlide.vue | 2 +-
|
||
app/components/year-review/MiscSlide.vue | 4 +-
|
||
app/components/year-review/OutroSlide.vue | 10 +-
|
||
app/components/year-review/ShareCard.vue | 4 +-
|
||
app/pages/change-password.vue | 2 +-
|
||
app/pages/index.vue | 12 +-
|
||
app/pages/year-review.vue | 10 +-
|
||
fix-colors.mjs | 128 +
|
||
old-index.vue | 3661 +++++++++++++++++
|
||
old-nuxt.config.ts | 447 ++
|
||
old-nuxt2.config.ts | 433 ++
|
||
old-variables.css | 556 +++
|
||
old-variables2.css | 556 +++
|
||
42 files changed, 6081 insertions(+), 300 deletions(-)
|
||
create mode 100644 fix-colors.mjs
|
||
create mode 100644 old-index.vue
|
||
create mode 100644 old-nuxt.config.ts
|
||
create mode 100644 old-nuxt2.config.ts
|
||
create mode 100644 old-variables.css
|
||
create mode 100644 old-variables2.css
|
||
|
||
diff --git a/app/components/Admin/ApiKeyManager.vue b/app/components/Admin/ApiKeyManager.vue
|
||
index 8a21229..b20a430 100644
|
||
--- a/app/components/Admin/ApiKeyManager.vue
|
||
+++ b/app/components/Admin/ApiKeyManager.vue
|
||
@@ -1026,7 +1026,7 @@ onMounted(() => {
|
||
width: 24px;
|
||
height: 24px;
|
||
border: 2px solid rgba(255, 255, 255, 0.1);
|
||
- border-top-color: #3b82f6;
|
||
+ border-top-color: var(--border-secondary, #3b82f6);
|
||
border-radius: 50%;
|
||
animation: spin 1s linear infinite;
|
||
}
|
||
@@ -1044,7 +1044,7 @@ onMounted(() => {
|
||
background: transparent;
|
||
}
|
||
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||
- background: #27272a;
|
||
+ background: var(--bg-tertiary, #27272a);
|
||
border-radius: 10px;
|
||
}
|
||
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
||
diff --git a/app/components/Admin/BackupManager.vue b/app/components/Admin/BackupManager.vue
|
||
index efe60d0..3d78253 100644
|
||
--- a/app/components/Admin/BackupManager.vue
|
||
+++ b/app/components/Admin/BackupManager.vue
|
||
@@ -556,8 +556,8 @@ const formatFileSize = (bytes) => {
|
||
|
||
/* 操作卡片 */
|
||
.action-card {
|
||
- background: #2a2a2a;
|
||
- border: 1px solid #404040;
|
||
+ background: var(--bg-tertiary, #2a2a2a);
|
||
+ border: 1px solid var(--border-secondary, #404040);
|
||
border-radius: 12px;
|
||
padding: 2rem;
|
||
text-align: center;
|
||
@@ -566,7 +566,7 @@ const formatFileSize = (bytes) => {
|
||
|
||
.action-card:hover {
|
||
border-color: #606060;
|
||
- background: #2f2f2f;
|
||
+ background: var(--bg-tertiary, #2f2f2f);
|
||
}
|
||
|
||
.action-card .card-content {
|
||
@@ -587,7 +587,7 @@ const formatFileSize = (bytes) => {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
}
|
||
|
||
.action-icon svg {
|
||
@@ -599,7 +599,7 @@ const formatFileSize = (bytes) => {
|
||
.action-card h4 {
|
||
font-size: 1.5rem;
|
||
font-weight: 600;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
margin: 0 0 0.75rem 0;
|
||
}
|
||
|
||
@@ -672,8 +672,8 @@ const formatFileSize = (bytes) => {
|
||
}
|
||
|
||
.modal {
|
||
- background: #2a2a2a;
|
||
- border: 1px solid #404040;
|
||
+ background: var(--bg-tertiary, #2a2a2a);
|
||
+ border: 1px solid var(--border-secondary, #404040);
|
||
border-radius: 12px;
|
||
max-width: 600px;
|
||
width: 100%;
|
||
@@ -724,7 +724,7 @@ const formatFileSize = (bytes) => {
|
||
.progress-details h5,
|
||
.progress-errors h5 {
|
||
margin: 0 0 10px 0;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
}
|
||
@@ -736,14 +736,14 @@ const formatFileSize = (bytes) => {
|
||
border: 1px solid #505050;
|
||
border-radius: 6px;
|
||
padding: 10px;
|
||
- background: #333333;
|
||
+ background: var(--bg-quaternary, #333333);
|
||
}
|
||
|
||
.detail-item {
|
||
padding: 4px 0;
|
||
color: #a0a0a0;
|
||
font-size: 13px;
|
||
- border-bottom: 1px solid #404040;
|
||
+ border-bottom: 1px solid var(--border-secondary, #404040);
|
||
}
|
||
|
||
.detail-item:last-child {
|
||
@@ -754,7 +754,7 @@ const formatFileSize = (bytes) => {
|
||
padding: 4px 0;
|
||
color: #ff6b6b;
|
||
font-size: 13px;
|
||
- border-bottom: 1px solid #4a2a2a;
|
||
+ border-bottom: 1px solid var(--border-secondary, #4a2a2a);
|
||
}
|
||
|
||
.error-item:last-child {
|
||
@@ -772,7 +772,7 @@ const formatFileSize = (bytes) => {
|
||
.modal-title {
|
||
font-size: 1.75rem;
|
||
font-weight: 600;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
margin: 0;
|
||
}
|
||
|
||
@@ -788,7 +788,7 @@ const formatFileSize = (bytes) => {
|
||
|
||
.close-btn:hover {
|
||
background: #505050;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
}
|
||
|
||
.close-btn svg {
|
||
@@ -802,11 +802,11 @@ const formatFileSize = (bytes) => {
|
||
|
||
.modal-footer {
|
||
padding: 1.5rem 2rem;
|
||
- border-top: 1px solid #404040;
|
||
+ border-top: 1px solid var(--border-secondary, #404040);
|
||
display: flex;
|
||
gap: 1rem;
|
||
justify-content: flex-end;
|
||
- background: #252525;
|
||
+ background: var(--bg-tertiary, #252525);
|
||
}
|
||
|
||
.modal-footer button {
|
||
@@ -822,7 +822,7 @@ const formatFileSize = (bytes) => {
|
||
display: block;
|
||
font-size: 1.125rem;
|
||
font-weight: 600;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
@@ -838,7 +838,7 @@ const formatFileSize = (bytes) => {
|
||
align-items: flex-start;
|
||
gap: 1rem;
|
||
padding: 1.25rem;
|
||
- background: #333333;
|
||
+ background: var(--bg-quaternary, #333333);
|
||
border: 1px solid #505050;
|
||
border-radius: 8px;
|
||
cursor: pointer;
|
||
@@ -870,7 +870,7 @@ const formatFileSize = (bytes) => {
|
||
display: block;
|
||
font-size: 1rem;
|
||
font-weight: 500;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
margin-bottom: 0.25rem;
|
||
}
|
||
|
||
@@ -907,12 +907,12 @@ const formatFileSize = (bytes) => {
|
||
text-align: center;
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
- background: #333333;
|
||
+ background: var(--bg-quaternary, #333333);
|
||
}
|
||
|
||
.upload-area:hover,
|
||
.upload-area.drag-over {
|
||
- border-color: #4a90e2;
|
||
+ border-color: var(--border-secondary, #4a90e2);
|
||
background: #383838;
|
||
}
|
||
|
||
@@ -926,7 +926,7 @@ const formatFileSize = (bytes) => {
|
||
.upload-area h4 {
|
||
font-size: 1.25rem;
|
||
font-weight: 600;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
margin: 0 0 0.5rem 0;
|
||
}
|
||
|
||
@@ -941,7 +941,7 @@ const formatFileSize = (bytes) => {
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 1.25rem;
|
||
- background: #333333;
|
||
+ background: var(--bg-quaternary, #333333);
|
||
border: 1px solid #505050;
|
||
border-radius: 8px;
|
||
margin-top: 1rem;
|
||
@@ -969,7 +969,7 @@ const formatFileSize = (bytes) => {
|
||
display: block;
|
||
font-size: 1rem;
|
||
font-weight: 500;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
margin-bottom: 0.25rem;
|
||
}
|
||
|
||
@@ -1056,8 +1056,8 @@ const formatFileSize = (bytes) => {
|
||
}
|
||
|
||
.notification.success {
|
||
- background: #2e7d32;
|
||
- border: 1px solid #4caf50;
|
||
+ background: var(--bg-tertiary, #2e7d32);
|
||
+ border: 1px solid var(--border-secondary, #4caf50);
|
||
}
|
||
|
||
.notification.error {
|
||
@@ -1071,8 +1071,8 @@ const formatFileSize = (bytes) => {
|
||
}
|
||
|
||
.notification.info {
|
||
- background: #1976d2;
|
||
- border: 1px solid #2196f3;
|
||
+ background: var(--bg-secondary, #1976d2);
|
||
+ border: 1px solid var(--border-secondary, #2196f3);
|
||
}
|
||
|
||
@keyframes slideInRight {
|
||
diff --git a/app/components/Admin/BlacklistManager.vue b/app/components/Admin/BlacklistManager.vue
|
||
index a31371f..b5ec8a4 100644
|
||
--- a/app/components/Admin/BlacklistManager.vue
|
||
+++ b/app/components/Admin/BlacklistManager.vue
|
||
@@ -645,7 +645,7 @@ onMounted(() => {
|
||
background: transparent;
|
||
}
|
||
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||
- background: #27272a;
|
||
+ background: var(--bg-tertiary, #27272a);
|
||
border-radius: 10px;
|
||
}
|
||
</style>
|
||
diff --git a/app/components/Admin/EmailTemplateManager.vue b/app/components/Admin/EmailTemplateManager.vue
|
||
index 89fda18..a995f31 100644
|
||
--- a/app/components/Admin/EmailTemplateManager.vue
|
||
+++ b/app/components/Admin/EmailTemplateManager.vue
|
||
@@ -336,7 +336,7 @@ onMounted(() => {
|
||
background: transparent;
|
||
}
|
||
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||
- background: #27272a;
|
||
+ background: var(--bg-tertiary, #27272a);
|
||
border-radius: 10px;
|
||
}
|
||
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
||
diff --git a/app/components/Admin/NotificationSender.vue b/app/components/Admin/NotificationSender.vue
|
||
index de4cd46..23bd005 100644
|
||
--- a/app/components/Admin/NotificationSender.vue
|
||
+++ b/app/components/Admin/NotificationSender.vue
|
||
@@ -742,7 +742,7 @@ onUnmounted(() => {
|
||
background: transparent;
|
||
}
|
||
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||
- background: #27272a;
|
||
+ background: var(--bg-tertiary, #27272a);
|
||
border-radius: 10px;
|
||
}
|
||
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
||
diff --git a/app/components/Admin/OverviewDashboard.vue b/app/components/Admin/OverviewDashboard.vue
|
||
index 7ac7086..148318c 100644
|
||
--- a/app/components/Admin/OverviewDashboard.vue
|
||
+++ b/app/components/Admin/OverviewDashboard.vue
|
||
@@ -366,7 +366,7 @@ onMounted(() => {
|
||
background: transparent;
|
||
}
|
||
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||
- background: #27272a;
|
||
+ background: var(--bg-tertiary, #27272a);
|
||
border-radius: 10px;
|
||
}
|
||
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
||
diff --git a/app/components/Admin/RequestTimeManager.vue b/app/components/Admin/RequestTimeManager.vue
|
||
index bf35bb6..762281f 100644
|
||
--- a/app/components/Admin/RequestTimeManager.vue
|
||
+++ b/app/components/Admin/RequestTimeManager.vue
|
||
@@ -842,7 +842,7 @@ const cancelForm = () => {
|
||
background: transparent;
|
||
}
|
||
::-webkit-scrollbar-thumb {
|
||
- background: #27272a;
|
||
+ background: var(--bg-tertiary, #27272a);
|
||
border-radius: 10px;
|
||
}
|
||
::-webkit-scrollbar-thumb:hover {
|
||
diff --git a/app/components/Admin/ScheduleItemPrint.vue b/app/components/Admin/ScheduleItemPrint.vue
|
||
index 51b2c1b..703e42a 100644
|
||
--- a/app/components/Admin/ScheduleItemPrint.vue
|
||
+++ b/app/components/Admin/ScheduleItemPrint.vue
|
||
@@ -112,7 +112,7 @@ const handleImageError = (event) => {
|
||
justify-content: center;
|
||
font-weight: bold;
|
||
font-size: 14px;
|
||
- color: #333;
|
||
+ color: var(--text-quaternary, #333333);
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
@@ -141,7 +141,7 @@ const handleImageError = (event) => {
|
||
display: none;
|
||
align-items: center;
|
||
justify-content: center;
|
||
- color: #999;
|
||
+ color: var(--text-tertiary, #999999);
|
||
}
|
||
|
||
.cover-placeholder.show {
|
||
@@ -161,7 +161,7 @@ const handleImageError = (event) => {
|
||
.song-title {
|
||
font-weight: bold;
|
||
font-size: 16px;
|
||
- color: #333;
|
||
+ color: var(--text-quaternary, #333333);
|
||
margin-bottom: 2px;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
@@ -176,7 +176,7 @@ const handleImageError = (event) => {
|
||
display: inline-block;
|
||
padding: 1px 4px;
|
||
background: #e3f2fd;
|
||
- border: 1px solid #2196f3;
|
||
+ border: 1px solid var(--border-secondary, #2196f3);
|
||
border-radius: 3px;
|
||
color: #1976d2;
|
||
font-size: 10px;
|
||
@@ -186,7 +186,7 @@ const handleImageError = (event) => {
|
||
|
||
.song-artist {
|
||
font-size: 14px;
|
||
- color: #666;
|
||
+ color: var(--text-quaternary, #666666);
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
@@ -197,7 +197,7 @@ const handleImageError = (event) => {
|
||
display: flex;
|
||
align-items: center;
|
||
font-size: 12px;
|
||
- color: #666;
|
||
+ color: var(--text-quaternary, #666666);
|
||
white-space: nowrap;
|
||
}
|
||
|
||
@@ -207,14 +207,14 @@ const handleImageError = (event) => {
|
||
}
|
||
|
||
.value {
|
||
- color: #333;
|
||
+ color: var(--text-quaternary, #333333);
|
||
}
|
||
|
||
/* 打印样式 */
|
||
@media print {
|
||
.schedule-item-print {
|
||
- color: #000 !important;
|
||
- background: #fff !important;
|
||
+ color: var(--text-primary, #000) !important;
|
||
+ background: var(--card-bg, #fff) !important;
|
||
width: 100% !important;
|
||
max-width: none !important;
|
||
box-sizing: border-box !important;
|
||
@@ -230,7 +230,7 @@ const handleImageError = (event) => {
|
||
|
||
.sequence-number {
|
||
background: #f0f0f0 !important;
|
||
- color: #000 !important;
|
||
+ color: var(--text-primary, #000) !important;
|
||
width: 30px !important;
|
||
height: 30px !important;
|
||
flex-shrink: 0 !important;
|
||
@@ -264,7 +264,7 @@ const handleImageError = (event) => {
|
||
}
|
||
|
||
.song-title {
|
||
- color: #000 !important;
|
||
+ color: var(--text-primary, #000) !important;
|
||
font-size: 16px !important;
|
||
white-space: nowrap !important;
|
||
overflow: hidden !important;
|
||
@@ -274,11 +274,11 @@ const handleImageError = (event) => {
|
||
.song-artist,
|
||
.label,
|
||
.value {
|
||
- color: #333 !important;
|
||
+ color: var(--text-quaternary, #333333) !important;
|
||
}
|
||
|
||
.time-range {
|
||
- color: #666 !important;
|
||
+ color: var(--text-quaternary, #666666) !important;
|
||
}
|
||
|
||
.requester-info,
|
||
diff --git a/app/components/Admin/SchedulePrinter.vue b/app/components/Admin/SchedulePrinter.vue
|
||
index 71bf445..9b26695 100644
|
||
--- a/app/components/Admin/SchedulePrinter.vue
|
||
+++ b/app/components/Admin/SchedulePrinter.vue
|
||
@@ -1383,15 +1383,15 @@ watch(
|
||
/* 预览区域和打印样式的核心CSS - 保持原生CSS以确保精确控制 */
|
||
|
||
.preview-content {
|
||
- background: #ffffff;
|
||
+ background: var(--card-bg, #ffffff);
|
||
padding: 0;
|
||
position: relative;
|
||
}
|
||
|
||
/* 打印页面样式 */
|
||
.print-page {
|
||
- background: #ffffff;
|
||
- color: #000000;
|
||
+ background: var(--card-bg, #ffffff);
|
||
+ color: var(--text-primary, #000000);
|
||
width: 100%;
|
||
margin: 0 auto;
|
||
padding: 30px;
|
||
@@ -1426,7 +1426,7 @@ watch(
|
||
.logo-divider {
|
||
width: 2px;
|
||
height: 60px;
|
||
- background: linear-gradient(to bottom, #ddd, #999, #ddd);
|
||
+ background: linear-gradient(to bottom, var(--border-secondary, #dddddd), #999, #ddd);
|
||
border-radius: 1px;
|
||
margin: 0 4px;
|
||
}
|
||
@@ -1445,19 +1445,19 @@ watch(
|
||
font-size: 24px;
|
||
font-weight: normal;
|
||
margin: 0 0 4px 0;
|
||
- color: #000;
|
||
+ color: var(--text-primary, #000);
|
||
}
|
||
|
||
.title-section h2 {
|
||
font-size: 18px;
|
||
font-weight: 500;
|
||
margin: 0;
|
||
- color: #666;
|
||
+ color: var(--text-quaternary, #666666);
|
||
}
|
||
|
||
.date-info {
|
||
font-size: 14px;
|
||
- color: #666;
|
||
+ color: var(--text-quaternary, #666666);
|
||
text-align: right;
|
||
display: flex;
|
||
align-items: flex-start;
|
||
@@ -1477,14 +1477,14 @@ watch(
|
||
.no-data-message {
|
||
text-align: center;
|
||
padding: 60px 20px;
|
||
- color: #666;
|
||
+ color: var(--text-quaternary, #666666);
|
||
}
|
||
|
||
.no-data-icon {
|
||
width: 64px;
|
||
height: 64px;
|
||
margin: 0 auto 20px;
|
||
- color: #ccc;
|
||
+ color: var(--text-secondary, #cccccc);
|
||
}
|
||
|
||
.no-data-icon svg {
|
||
@@ -1496,7 +1496,7 @@ watch(
|
||
font-size: 18px;
|
||
font-weight: 500;
|
||
margin: 0 0 12px 0;
|
||
- color: #333;
|
||
+ color: var(--text-quaternary, #333333);
|
||
}
|
||
|
||
.no-data-message p {
|
||
@@ -1512,15 +1512,15 @@ watch(
|
||
font-weight: bold;
|
||
margin: 24px 0 12px 0;
|
||
padding: 8px 12px;
|
||
- border-bottom: 2px solid #ddd;
|
||
+ border-bottom: 2px solid var(--border-secondary, #ddd);
|
||
background: #f8f9fa;
|
||
- color: #333;
|
||
+ color: var(--text-quaternary, #333333);
|
||
border-radius: 4px 4px 0 0;
|
||
}
|
||
|
||
.playtime-group .group-title {
|
||
background: #e3f2fd;
|
||
- border-bottom-color: #2196f3;
|
||
+ border-bottom-color: var(--border-secondary, #2196f3);
|
||
color: #1565c0;
|
||
}
|
||
|
||
@@ -1533,7 +1533,7 @@ watch(
|
||
.group-count {
|
||
font-size: 14px;
|
||
font-weight: normal;
|
||
- color: #666;
|
||
+ color: var(--text-quaternary, #666666);
|
||
margin-left: 8px;
|
||
}
|
||
|
||
@@ -1547,7 +1547,7 @@ watch(
|
||
margin: 16px 0 8px 0;
|
||
padding: 6px 10px;
|
||
background: #f0f8ff;
|
||
- border-left: 3px solid #2196f3;
|
||
+ border-left: 3px solid var(--border-secondary, #2196f3);
|
||
color: #1565c0;
|
||
border-radius: 0 4px 4px 0;
|
||
}
|
||
@@ -1555,7 +1555,7 @@ watch(
|
||
.playtime-count {
|
||
font-size: 12px;
|
||
font-weight: normal;
|
||
- color: #666;
|
||
+ color: var(--text-quaternary, #666666);
|
||
margin-left: 6px;
|
||
}
|
||
|
||
@@ -1570,7 +1570,7 @@ watch(
|
||
padding-top: 16px;
|
||
border-top: 1px solid #e5e5e5;
|
||
font-size: 12px;
|
||
- color: #666;
|
||
+ color: var(--text-quaternary, #666666);
|
||
}
|
||
|
||
.footer-left {
|
||
diff --git a/app/components/Admin/Sidebar.vue b/app/components/Admin/Sidebar.vue
|
||
index d4dc22a..369f26c 100644
|
||
--- a/app/components/Admin/Sidebar.vue
|
||
+++ b/app/components/Admin/Sidebar.vue
|
||
@@ -279,7 +279,7 @@ const getRoleDisplayName = (role) => {
|
||
background: transparent;
|
||
}
|
||
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||
- background: #27272a;
|
||
+ background: var(--bg-tertiary, #27272a);
|
||
border-radius: 10px;
|
||
}
|
||
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
||
diff --git a/app/components/Admin/SongDownloadDialog.vue b/app/components/Admin/SongDownloadDialog.vue
|
||
index bb81bf2..9268c5a 100644
|
||
--- a/app/components/Admin/SongDownloadDialog.vue
|
||
+++ b/app/components/Admin/SongDownloadDialog.vue
|
||
@@ -1228,7 +1228,7 @@ onUnmounted(() => {
|
||
background: transparent;
|
||
}
|
||
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||
- background: #27272a;
|
||
+ background: var(--bg-tertiary, #27272a);
|
||
border-radius: 10px;
|
||
}
|
||
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
||
diff --git a/app/components/Admin/SongManagement.vue b/app/components/Admin/SongManagement.vue
|
||
index fce2995..a630cc2 100644
|
||
--- a/app/components/Admin/SongManagement.vue
|
||
+++ b/app/components/Admin/SongManagement.vue
|
||
@@ -2179,7 +2179,7 @@ onUnmounted(() => {
|
||
background: transparent;
|
||
}
|
||
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||
- background: #27272a;
|
||
+ background: var(--bg-tertiary, #27272a);
|
||
border-radius: 10px;
|
||
}
|
||
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
||
diff --git a/app/components/Admin/VotersModal.vue b/app/components/Admin/VotersModal.vue
|
||
index d7730f9..52fe766 100644
|
||
--- a/app/components/Admin/VotersModal.vue
|
||
+++ b/app/components/Admin/VotersModal.vue
|
||
@@ -223,14 +223,14 @@ watch(
|
||
.modal-title {
|
||
font-size: 20px;
|
||
font-weight: 600;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
margin: 0;
|
||
}
|
||
|
||
.close-btn {
|
||
background: none;
|
||
border: none;
|
||
- color: #888;
|
||
+ color: var(--text-tertiary, #888888);
|
||
cursor: pointer;
|
||
padding: 8px;
|
||
border-radius: 8px;
|
||
@@ -238,8 +238,8 @@ watch(
|
||
}
|
||
|
||
.close-btn:hover {
|
||
- background: #2a2a2a;
|
||
- color: #ffffff;
|
||
+ background: var(--bg-tertiary, #2a2a2a);
|
||
+ color: var(--text-primary, #ffffff);
|
||
}
|
||
|
||
.close-btn svg {
|
||
@@ -254,22 +254,22 @@ watch(
|
||
}
|
||
|
||
.song-info {
|
||
- background: #2a2a2a;
|
||
+ background: var(--bg-tertiary, #2a2a2a);
|
||
border-radius: 12px;
|
||
padding: 20px;
|
||
margin-bottom: 24px;
|
||
- border: 1px solid #3a3a3a;
|
||
+ border: 1px solid var(--border-secondary, #3a3a3a);
|
||
}
|
||
|
||
.song-title {
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
margin: 0 0 8px 0;
|
||
}
|
||
|
||
.song-artist {
|
||
- color: #888;
|
||
+ color: var(--text-tertiary, #888888);
|
||
margin: 0 0 16px 0;
|
||
font-size: 14px;
|
||
}
|
||
@@ -304,7 +304,7 @@ watch(
|
||
.spinner {
|
||
width: 32px;
|
||
height: 32px;
|
||
- border: 3px solid #3a3a3a;
|
||
+ border: 3px solid var(--border-secondary, #3a3a3a);
|
||
border-top: 3px solid #667eea;
|
||
border-radius: 50%;
|
||
animation: spin 1s linear infinite;
|
||
@@ -366,12 +366,12 @@ watch(
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding-bottom: 12px;
|
||
- border-bottom: 1px solid #3a3a3a;
|
||
+ border-bottom: 1px solid var(--border-secondary, #3a3a3a);
|
||
}
|
||
|
||
.voters-title {
|
||
font-weight: 600;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
font-size: 16px;
|
||
}
|
||
|
||
@@ -388,15 +388,15 @@ watch(
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 12px 16px;
|
||
- background: #2a2a2a;
|
||
+ background: var(--bg-tertiary, #2a2a2a);
|
||
border-radius: 8px;
|
||
- border: 1px solid #3a3a3a;
|
||
+ border: 1px solid var(--border-secondary, #3a3a3a);
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.voter-item:hover {
|
||
- background: #333333;
|
||
- border-color: #4a4a4a;
|
||
+ background: var(--bg-quaternary, #333333);
|
||
+ border-color: var(--border-secondary, #4a4a4a);
|
||
}
|
||
|
||
.voter-info {
|
||
@@ -426,18 +426,18 @@ watch(
|
||
}
|
||
|
||
.voter-name {
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
font-weight: 500;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.vote-time {
|
||
- color: #888;
|
||
+ color: var(--text-tertiary, #888888);
|
||
font-size: 12px;
|
||
}
|
||
|
||
.voter-number {
|
||
- color: #888;
|
||
+ color: var(--text-tertiary, #888888);
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
}
|
||
@@ -454,11 +454,11 @@ watch(
|
||
.empty-icon {
|
||
width: 48px;
|
||
height: 48px;
|
||
- color: #666;
|
||
+ color: var(--text-quaternary, #666666);
|
||
}
|
||
|
||
.empty-state p {
|
||
- color: #888;
|
||
+ color: var(--text-tertiary, #888888);
|
||
margin: 0;
|
||
}
|
||
|
||
@@ -469,8 +469,8 @@ watch(
|
||
}
|
||
|
||
.close-button {
|
||
- background: #3a3a3a;
|
||
- color: #ffffff;
|
||
+ background: var(--bg-quaternary, #3a3a3a);
|
||
+ color: var(--text-primary, #ffffff);
|
||
border: none;
|
||
padding: 12px 24px;
|
||
border-radius: 8px;
|
||
@@ -490,7 +490,7 @@ watch(
|
||
}
|
||
|
||
.voters-container::-webkit-scrollbar-track {
|
||
- background: #2a2a2a;
|
||
+ background: var(--bg-tertiary, #2a2a2a);
|
||
border-radius: 3px;
|
||
}
|
||
|
||
diff --git a/app/components/Auth/OAuthButtons.vue b/app/components/Auth/OAuthButtons.vue
|
||
index 77e08f1..d7a169f 100644
|
||
--- a/app/components/Auth/OAuthButtons.vue
|
||
+++ b/app/components/Auth/OAuthButtons.vue
|
||
@@ -141,21 +141,21 @@ const loginWith = (provider: string) => {
|
||
}
|
||
|
||
.oauth-btn-github:hover {
|
||
- background: #24292e;
|
||
- color: #ffffff;
|
||
- border-color: #24292e;
|
||
+ background: var(--bg-tertiary, #24292e);
|
||
+ color: var(--text-primary, #ffffff);
|
||
+ border-color: var(--border-secondary, #24292e);
|
||
}
|
||
|
||
.oauth-btn-google:hover {
|
||
- background: #ffffff;
|
||
- color: #111111;
|
||
+ background: var(--card-bg, #ffffff);
|
||
+ color: var(--text-primary, #111111);
|
||
border-color: #dadce0;
|
||
}
|
||
|
||
.oauth-btn-aggregate:hover {
|
||
- background: #12b7f5;
|
||
- color: #ffffff;
|
||
- border-color: #12b7f5;
|
||
+ background: var(--bg-secondary, #12b7f5);
|
||
+ color: var(--text-primary, #ffffff);
|
||
+ border-color: var(--border-secondary, #12b7f5);
|
||
}
|
||
|
||
.oauth-empty-hint {
|
||
diff --git a/app/components/Auth/RegisterForm.vue b/app/components/Auth/RegisterForm.vue
|
||
index c9f0dc0..ee8fbf2 100644
|
||
--- a/app/components/Auth/RegisterForm.vue
|
||
+++ b/app/components/Auth/RegisterForm.vue
|
||
@@ -575,7 +575,7 @@ const handleRegister = async () => {
|
||
width: 100%;
|
||
padding: 16px;
|
||
background: var(--primary);
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
border: none;
|
||
border-radius: var(--radius-lg);
|
||
font-size: 16px;
|
||
diff --git a/app/components/Notifications/NotificationSettings.vue b/app/components/Notifications/NotificationSettings.vue
|
||
index e585ebd..b6137f7 100644
|
||
--- a/app/components/Notifications/NotificationSettings.vue
|
||
+++ b/app/components/Notifications/NotificationSettings.vue
|
||
@@ -209,7 +209,7 @@ input[type='range']::-webkit-slider-thumb {
|
||
-webkit-appearance: none;
|
||
width: 18px;
|
||
height: 18px;
|
||
- background: #2563eb; /* blue-600 */
|
||
+ background: var(--bg-tertiary, #2563eb); /* blue-600 */
|
||
border-radius: 50%;
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
@@ -218,7 +218,7 @@ input[type='range']::-webkit-slider-thumb {
|
||
input[type='range']::-moz-range-thumb {
|
||
width: 18px;
|
||
height: 18px;
|
||
- background: #2563eb;
|
||
+ background: var(--bg-tertiary, #2563eb);
|
||
border-radius: 50%;
|
||
cursor: pointer;
|
||
border: none;
|
||
diff --git a/app/components/Player/PlayerLyric/AMLyric.vue b/app/components/Player/PlayerLyric/AMLyric.vue
|
||
index 58ba74a..93ee383 100644
|
||
--- a/app/components/Player/PlayerLyric/AMLyric.vue
|
||
+++ b/app/components/Player/PlayerLyric/AMLyric.vue
|
||
@@ -160,7 +160,7 @@ const jumpSeek = (line: LyricLineMouseEvent) => {
|
||
:deep(.am-lyric .is-active),
|
||
:deep(.am-lyric .lyric-line.current),
|
||
:deep(.am-lyric .lyric-line.is-current) {
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
text-shadow: 0 4px 18px rgba(0, 0, 0, 0.35);
|
||
}
|
||
}
|
||
diff --git a/app/components/Player/PlayerLyric/DefaultLyric.vue b/app/components/Player/PlayerLyric/DefaultLyric.vue
|
||
index 156fec0..259724f 100644
|
||
--- a/app/components/Player/PlayerLyric/DefaultLyric.vue
|
||
+++ b/app/components/Player/PlayerLyric/DefaultLyric.vue
|
||
@@ -824,6 +824,6 @@ onBeforeUnmount(() => {
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 22px;
|
||
- color: #fff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
}
|
||
</style>
|
||
diff --git a/app/components/Songs/RequestForm.vue b/app/components/Songs/RequestForm.vue
|
||
index 538f4f5..8c494ae 100644
|
||
--- a/app/components/Songs/RequestForm.vue
|
||
+++ b/app/components/Songs/RequestForm.vue
|
||
@@ -2912,7 +2912,7 @@ defineExpose({
|
||
<style scoped>
|
||
.request-form {
|
||
width: 100%;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
display: flex;
|
||
gap: 2rem;
|
||
height: calc(100vh - 160px);
|
||
@@ -2954,7 +2954,7 @@ defineExpose({
|
||
font-size: 15px;
|
||
line-height: 1.7;
|
||
letter-spacing: 0.04em;
|
||
- color: #fff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
}
|
||
|
||
.rules-content-desktop p {
|
||
@@ -3181,7 +3181,7 @@ defineExpose({
|
||
font-family: 'MiSans', sans-serif;
|
||
font-weight: 600;
|
||
font-size: 15px;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
white-space: nowrap;
|
||
flex-shrink: 0; /* 防止标签被压缩 */
|
||
}
|
||
@@ -3212,11 +3212,11 @@ defineExpose({
|
||
}
|
||
|
||
.search-button {
|
||
- background: linear-gradient(180deg, #0043f8 0%, #0075f8 100%);
|
||
+ background: linear-gradient(180deg, var(--bg-secondary, #0043f8) 0%, #0075f8 100%);
|
||
border: 1px solid rgba(255, 255, 255, 0.16);
|
||
border-radius: 8px;
|
||
padding: 0.75rem 1.5rem;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
font-family: 'MiSans', sans-serif;
|
||
font-weight: 600;
|
||
font-size: 14px;
|
||
@@ -3250,7 +3250,7 @@ defineExpose({
|
||
font-family: 'MiSans', sans-serif;
|
||
font-weight: 600;
|
||
font-size: 16px;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
white-space: nowrap;
|
||
flex-shrink: 0; /* 防止标签被压缩 */
|
||
}
|
||
@@ -3271,7 +3271,7 @@ defineExpose({
|
||
border-radius: 6px;
|
||
padding: 0.25rem 0.5rem;
|
||
font-size: 14px;
|
||
- color: #fff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
}
|
||
|
||
.remove-collaborator {
|
||
@@ -3285,7 +3285,7 @@ defineExpose({
|
||
}
|
||
|
||
.remove-collaborator:hover {
|
||
- color: #fff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
}
|
||
|
||
.add-collaborator-btn {
|
||
@@ -3304,7 +3304,7 @@ defineExpose({
|
||
|
||
.add-collaborator-btn:hover {
|
||
background: rgba(255, 255, 255, 0.1);
|
||
- color: #fff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
}
|
||
|
||
/* 自定义复选框样式 */
|
||
@@ -3327,7 +3327,7 @@ defineExpose({
|
||
width: 14px;
|
||
height: 14px;
|
||
border-radius: 4px;
|
||
- border: 1px solid #3f3f46;
|
||
+ border: 1px solid var(--border-secondary, #3f3f46);
|
||
background: rgba(24, 24, 27, 0.5);
|
||
transition: all 0.2s ease;
|
||
}
|
||
@@ -3343,7 +3343,7 @@ defineExpose({
|
||
|
||
.custom-checkbox-input:checked + .custom-checkbox-box {
|
||
background: #3b82f6;
|
||
- border-color: #3b82f6;
|
||
+ border-color: var(--border-secondary, #3b82f6);
|
||
}
|
||
|
||
.custom-checkbox-input:checked + .custom-checkbox-box .custom-checkbox-icon {
|
||
@@ -3428,7 +3428,7 @@ defineExpose({
|
||
font-family: 'MiSans', sans-serif;
|
||
font-weight: 600;
|
||
font-size: 13px;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
}
|
||
|
||
.status-item-horizontal .status-value {
|
||
@@ -3615,7 +3615,7 @@ defineExpose({
|
||
}
|
||
|
||
.header-btn:hover {
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
background: rgba(255, 255, 255, 0.08);
|
||
}
|
||
|
||
@@ -3645,7 +3645,7 @@ defineExpose({
|
||
.import-btn:hover {
|
||
background: rgba(255, 255, 255, 0.08);
|
||
border-color: rgba(255, 255, 255, 0.15);
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
}
|
||
|
||
.user-status {
|
||
@@ -3706,7 +3706,7 @@ defineExpose({
|
||
|
||
.action-btn-compact:hover {
|
||
background: rgba(255, 255, 255, 0.08);
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
border-color: rgba(255, 255, 255, 0.12);
|
||
}
|
||
|
||
@@ -3731,7 +3731,7 @@ defineExpose({
|
||
}
|
||
|
||
.radio-label.active {
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
font-weight: 600;
|
||
background: rgba(255, 255, 255, 0.08);
|
||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||
@@ -3775,9 +3775,9 @@ defineExpose({
|
||
}
|
||
|
||
.platform-btn.active {
|
||
- background: linear-gradient(180deg, #0043f8 0%, #0075f8 100%);
|
||
+ background: linear-gradient(180deg, var(--bg-secondary, #0043f8) 0%, #0075f8 100%);
|
||
border-color: rgba(255, 255, 255, 0.16);
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
}
|
||
|
||
.platform-btn:hover:not(.active) {
|
||
@@ -3873,7 +3873,7 @@ defineExpose({
|
||
}
|
||
|
||
.source-item.healthy .source-indicator {
|
||
- background: #22c55e;
|
||
+ background: var(--bg-tertiary, #22c55e);
|
||
box-shadow: 0 0 6px rgba(34, 197, 94, 0.6);
|
||
}
|
||
|
||
@@ -4031,7 +4031,7 @@ defineExpose({
|
||
font-family: 'MiSans', sans-serif;
|
||
font-weight: 600;
|
||
font-size: 15px;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
margin: 0;
|
||
}
|
||
|
||
@@ -4077,7 +4077,7 @@ defineExpose({
|
||
font-family: 'MiSans', sans-serif;
|
||
font-weight: 600;
|
||
font-size: 14px;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
}
|
||
@@ -4103,14 +4103,14 @@ defineExpose({
|
||
}
|
||
|
||
.submit-button {
|
||
- background: linear-gradient(180deg, #0043f8 0%, #0075f8 100%);
|
||
+ background: linear-gradient(180deg, var(--bg-secondary, #0043f8) 0%, #0075f8 100%);
|
||
border: 1px solid rgba(255, 255, 255, 0.16);
|
||
border-radius: 8px;
|
||
padding: 0.5rem 1.5rem;
|
||
font-family: 'MiSans', sans-serif;
|
||
font-weight: 600;
|
||
font-size: 14px;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
}
|
||
@@ -4125,7 +4125,7 @@ defineExpose({
|
||
transform: none;
|
||
}
|
||
.similar-song-alert {
|
||
- background: #21242d;
|
||
+ background: var(--bg-tertiary, #21242d);
|
||
border-radius: 10px;
|
||
padding: 0.5rem 0.75rem;
|
||
box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.3);
|
||
@@ -4157,7 +4157,7 @@ defineExpose({
|
||
font-family: 'MiSans', sans-serif;
|
||
font-weight: 600;
|
||
font-size: 16px;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
}
|
||
|
||
.alert-content {
|
||
@@ -4190,7 +4190,7 @@ defineExpose({
|
||
.song-title {
|
||
margin: 0 0 0.25rem 0;
|
||
font-size: 14px;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
font-weight: 500;
|
||
}
|
||
|
||
@@ -4244,11 +4244,11 @@ defineExpose({
|
||
}
|
||
|
||
.vote-btn {
|
||
- background: linear-gradient(180deg, #0043f8 0%, #0075f8 100%);
|
||
+ background: linear-gradient(180deg, var(--bg-secondary, #0043f8) 0%, #0075f8 100%);
|
||
border: 1px solid rgba(255, 255, 255, 0.16);
|
||
border-radius: 8px;
|
||
padding: 0.5rem 1rem;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
font-family: 'MiSans', sans-serif;
|
||
font-weight: 600;
|
||
font-size: 14px;
|
||
@@ -4272,7 +4272,7 @@ defineExpose({
|
||
border: 1px solid rgba(255, 255, 255, 0.16);
|
||
border-radius: 8px;
|
||
padding: 0.5rem 1rem;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
font-family: 'MiSans', sans-serif;
|
||
font-weight: 600;
|
||
font-size: 14px;
|
||
@@ -4390,7 +4390,7 @@ defineExpose({
|
||
|
||
.modal-header h3 {
|
||
margin: 0;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
font-family: 'MiSans', sans-serif;
|
||
font-weight: 600;
|
||
font-size: 18px;
|
||
@@ -4415,7 +4415,7 @@ defineExpose({
|
||
|
||
.close-btn:hover {
|
||
background: rgba(255, 255, 255, 0.1);
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
transform: rotate(90deg);
|
||
}
|
||
|
||
@@ -4456,14 +4456,14 @@ defineExpose({
|
||
|
||
.btn-secondary:hover {
|
||
background: rgba(255, 255, 255, 0.1);
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
border-color: rgba(255, 255, 255, 0.2);
|
||
}
|
||
|
||
.btn-primary {
|
||
- background: linear-gradient(135deg, #0043f8 0%, #0075f8 100%);
|
||
+ background: linear-gradient(135deg, var(--bg-secondary, #0043f8) 0%, #0075f8 100%);
|
||
border-color: rgba(255, 255, 255, 0.1);
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
box-shadow: 0 4px 12px rgba(0, 67, 248, 0.3);
|
||
}
|
||
|
||
@@ -4527,7 +4527,7 @@ defineExpose({
|
||
border-radius: 12px;
|
||
overflow: hidden;
|
||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
|
||
- background: #18181b;
|
||
+ background: var(--bg-secondary, #18181b);
|
||
}
|
||
|
||
.cover-img {
|
||
@@ -4600,7 +4600,7 @@ defineExpose({
|
||
font-family: 'MiSans', sans-serif;
|
||
font-weight: 600;
|
||
font-size: 15px;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
margin: 0;
|
||
display: -webkit-box;
|
||
-webkit-line-clamp: 2;
|
||
@@ -4662,7 +4662,7 @@ defineExpose({
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
cursor: pointer;
|
||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||
flex-shrink: 0;
|
||
@@ -4713,7 +4713,7 @@ defineExpose({
|
||
border: 1px solid rgba(255, 255, 255, 0.16);
|
||
border-radius: 6px;
|
||
padding: 0.4rem 0.8rem;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
font-family: 'MiSans', sans-serif;
|
||
font-weight: 600;
|
||
font-size: 12px;
|
||
@@ -4750,11 +4750,11 @@ defineExpose({
|
||
}
|
||
|
||
.select-btn {
|
||
- background: linear-gradient(180deg, #0043f8 0%, #0075f8 100%);
|
||
+ background: linear-gradient(180deg, var(--bg-secondary, #0043f8) 0%, #0075f8 100%);
|
||
border: 1px solid rgba(255, 255, 255, 0.16);
|
||
border-radius: 8px;
|
||
padding: 0.5rem 1rem;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
font-family: 'MiSans', sans-serif;
|
||
font-weight: 600;
|
||
font-size: 14px;
|
||
@@ -4812,7 +4812,7 @@ defineExpose({
|
||
font-family: 'MiSans', sans-serif;
|
||
font-weight: 600;
|
||
font-size: 14px;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
}
|
||
@@ -4835,7 +4835,7 @@ defineExpose({
|
||
font-weight: 600;
|
||
font-size: 18px;
|
||
margin-bottom: 1rem;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
}
|
||
|
||
.manual-form {
|
||
@@ -4855,7 +4855,7 @@ defineExpose({
|
||
border: 1px solid rgba(255, 255, 255, 0.16);
|
||
border-radius: 8px;
|
||
padding: 0.5rem 1rem;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
font-family: 'MiSans', sans-serif;
|
||
font-weight: 600;
|
||
font-size: 14px;
|
||
@@ -4868,11 +4868,11 @@ defineExpose({
|
||
}
|
||
|
||
.manual-confirm-btn {
|
||
- background: linear-gradient(180deg, #0043f8 0%, #0075f8 100%);
|
||
+ background: linear-gradient(180deg, var(--bg-secondary, #0043f8) 0%, #0075f8 100%);
|
||
border: 1px solid rgba(255, 255, 255, 0.16);
|
||
border-radius: 8px;
|
||
padding: 0.5rem 1rem;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
font-family: 'MiSans', sans-serif;
|
||
font-weight: 600;
|
||
font-size: 14px;
|
||
@@ -5148,8 +5148,8 @@ defineExpose({
|
||
}
|
||
|
||
.platform-btn.active {
|
||
- background: #0b5afe;
|
||
- color: #ffffff;
|
||
+ background: var(--bg-secondary, #0b5afe);
|
||
+ color: var(--text-primary, #ffffff);
|
||
box-shadow: 0 2px 8px rgba(11, 90, 254, 0.3);
|
||
}
|
||
|
||
@@ -5487,7 +5487,7 @@ defineExpose({
|
||
|
||
.import-semester-btn:hover {
|
||
background: rgba(255, 255, 255, 0.15);
|
||
- color: #fff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
border-color: rgba(255, 255, 255, 0.2);
|
||
}
|
||
|
||
@@ -5513,7 +5513,7 @@ defineExpose({
|
||
font-family: 'MiSans', sans-serif;
|
||
font-weight: 500;
|
||
font-size: 16px;
|
||
- color: #fff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
@@ -5571,7 +5571,7 @@ defineExpose({
|
||
font-family: 'MiSans', sans-serif;
|
||
font-weight: 500;
|
||
font-size: 14px;
|
||
- color: #fff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
}
|
||
|
||
.episode-duration {
|
||
diff --git a/app/components/Songs/ScheduleList.vue b/app/components/Songs/ScheduleList.vue
|
||
index 7df22f8..9ac7c4f 100644
|
||
--- a/app/components/Songs/ScheduleList.vue
|
||
+++ b/app/components/Songs/ScheduleList.vue
|
||
@@ -1608,7 +1608,7 @@ const vRipple = {
|
||
}
|
||
|
||
.semester-label {
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
font-size: 15px;
|
||
font-weight: 500;
|
||
margin-right: 0.75rem;
|
||
@@ -1620,7 +1620,7 @@ const vRipple = {
|
||
background: linear-gradient(135deg, rgba(255, 255, 255, 0.15) 0%, rgba(255, 255, 255, 0.08) 100%);
|
||
border: 1px solid rgba(255, 255, 255, 0.25);
|
||
border-radius: 8px;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
padding: 0.6rem 1rem;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
@@ -1648,8 +1648,8 @@ const vRipple = {
|
||
}
|
||
|
||
.semester-select option {
|
||
- background: #1a1d24;
|
||
- color: #ffffff;
|
||
+ background: var(--bg-secondary, #1a1d24);
|
||
+ color: var(--text-primary, #ffffff);
|
||
padding: 0.5rem;
|
||
}
|
||
|
||
@@ -1703,14 +1703,14 @@ const vRipple = {
|
||
}
|
||
|
||
.date-item:hover {
|
||
- background: #21242d;
|
||
+ background: var(--bg-tertiary, #21242d);
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
||
}
|
||
|
||
.date-item.active {
|
||
- background: #21242d;
|
||
- color: #ffffff;
|
||
+ background: var(--bg-tertiary, #21242d);
|
||
+ color: var(--text-primary, #ffffff);
|
||
font-weight: 600;
|
||
border-radius: 8px;
|
||
box-shadow: 0 4px 12px rgba(11, 90, 254, 0.2);
|
||
@@ -1775,7 +1775,7 @@ const vRipple = {
|
||
font-family: 'MiSans', sans-serif;
|
||
font-weight: 600;
|
||
font-size: 20px;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
margin: 0;
|
||
}
|
||
|
||
@@ -1784,7 +1784,7 @@ const vRipple = {
|
||
padding: 3rem;
|
||
text-align: center;
|
||
border-radius: 10px;
|
||
- background: #21242d;
|
||
+ background: var(--bg-tertiary, #21242d);
|
||
margin: 1rem 0;
|
||
color: rgba(255, 255, 255, 0.6);
|
||
display: flex;
|
||
@@ -1819,7 +1819,7 @@ const vRipple = {
|
||
padding: 2rem;
|
||
text-align: center;
|
||
border-radius: 10px;
|
||
- background: #21242d;
|
||
+ background: var(--bg-tertiary, #21242d);
|
||
margin: 1rem 0;
|
||
color: rgba(255, 255, 255, 0.6);
|
||
}
|
||
@@ -1869,7 +1869,7 @@ const vRipple = {
|
||
.song-card {
|
||
width: 320px;
|
||
flex-shrink: 0;
|
||
- background: #21242d;
|
||
+ background: var(--bg-tertiary, #21242d);
|
||
border-radius: 10px;
|
||
overflow: hidden;
|
||
position: relative;
|
||
@@ -1886,7 +1886,7 @@ const vRipple = {
|
||
border-radius: 999px;
|
||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||
background: rgba(255, 255, 255, 0.1);
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
@@ -1930,7 +1930,7 @@ const vRipple = {
|
||
width: 100%;
|
||
max-width: 580px;
|
||
max-height: 85vh;
|
||
- background: #1e1e24;
|
||
+ background: var(--bg-secondary, #1e1e24);
|
||
border-radius: 20px;
|
||
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
|
||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||
@@ -1964,7 +1964,7 @@ const vRipple = {
|
||
margin: 0;
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
letter-spacing: 0.5px;
|
||
}
|
||
|
||
@@ -1984,7 +1984,7 @@ const vRipple = {
|
||
|
||
.playlist-modal-close:hover {
|
||
background: rgba(255, 255, 255, 0.1);
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
transform: rotate(90deg);
|
||
}
|
||
|
||
@@ -1993,7 +1993,7 @@ const vRipple = {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
padding: 1.5rem;
|
||
- background: #1e1e24;
|
||
+ background: var(--bg-secondary, #1e1e24);
|
||
}
|
||
|
||
/* 滚动条美化 */
|
||
@@ -2066,7 +2066,7 @@ const vRipple = {
|
||
height: 40px;
|
||
border-radius: 50%;
|
||
overflow: hidden;
|
||
- background: #2a2a32;
|
||
+ background: var(--bg-tertiary, #2a2a32);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
@@ -2087,7 +2087,7 @@ const vRipple = {
|
||
|
||
.user-name {
|
||
font-weight: 600;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
font-size: 15px;
|
||
}
|
||
|
||
@@ -2161,9 +2161,9 @@ const vRipple = {
|
||
.custom-select,
|
||
.custom-input {
|
||
width: 100%;
|
||
- background: #141418;
|
||
+ background: var(--bg-secondary, #141418);
|
||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
padding: 0.75rem 1rem;
|
||
border-radius: 10px;
|
||
font-size: 14px;
|
||
@@ -2210,7 +2210,7 @@ const vRipple = {
|
||
|
||
.btn-icon:hover {
|
||
background: rgba(255, 255, 255, 0.1);
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
}
|
||
|
||
.btn-icon:disabled {
|
||
@@ -2421,7 +2421,7 @@ const vRipple = {
|
||
|
||
.song-name {
|
||
font-size: 14px;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
font-weight: 500;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
@@ -2469,7 +2469,7 @@ const vRipple = {
|
||
|
||
.btn-primary {
|
||
background: var(--primary);
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.25);
|
||
}
|
||
|
||
@@ -2488,7 +2488,7 @@ const vRipple = {
|
||
|
||
.btn-secondary {
|
||
background: rgba(255, 255, 255, 0.1);
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
}
|
||
|
||
.btn-secondary:hover {
|
||
@@ -2502,7 +2502,7 @@ const vRipple = {
|
||
|
||
.btn-ghost:hover {
|
||
background: rgba(255, 255, 255, 0.05);
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
}
|
||
|
||
/* 动画定义 */
|
||
@@ -2537,7 +2537,7 @@ const vRipple = {
|
||
border-radius: 50%;
|
||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||
background: rgba(255, 255, 255, 0.1);
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
cursor: pointer;
|
||
margin-right: 0.5rem;
|
||
backdrop-filter: blur(10px);
|
||
@@ -2661,8 +2661,8 @@ const vRipple = {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
- background: linear-gradient(135deg, #0043f8 0%, #0075f8 100%);
|
||
- color: #ffffff;
|
||
+ background: linear-gradient(135deg, var(--bg-secondary, #0043f8) 0%, #0075f8 100%);
|
||
+ color: var(--text-primary, #ffffff);
|
||
font-size: 28px;
|
||
font-weight: bold;
|
||
font-family: 'MiSans', sans-serif;
|
||
@@ -2725,7 +2725,7 @@ const vRipple = {
|
||
font-weight: 600;
|
||
font-size: 16px;
|
||
letter-spacing: 0.04em;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
margin-bottom: 0.5rem;
|
||
display: flex;
|
||
align-items: flex-start;
|
||
@@ -2824,7 +2824,7 @@ const vRipple = {
|
||
font-family: 'MiSans', sans-serif;
|
||
font-weight: 600;
|
||
font-size: 12px;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
opacity: 0.4;
|
||
}
|
||
|
||
@@ -2919,7 +2919,7 @@ const vRipple = {
|
||
.date-text {
|
||
font-size: 15px;
|
||
font-weight: 600;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
white-space: nowrap;
|
||
text-shadow:
|
||
0 0 10px rgba(255, 255, 255, 0.2),
|
||
@@ -2928,7 +2928,7 @@ const vRipple = {
|
||
|
||
.dropdown-icon {
|
||
opacity: 0.5;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
}
|
||
|
||
.mobile-action-btn {
|
||
@@ -2937,7 +2937,7 @@ const vRipple = {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
- background: linear-gradient(135deg, #0b5afe 0%, #0043f8 100%);
|
||
+ background: linear-gradient(135deg, var(--bg-secondary, #0b5afe) 0%, #0043f8 100%);
|
||
border: none;
|
||
border-radius: 16px;
|
||
box-shadow: 0 4px 15px rgba(11, 90, 254, 0.4);
|
||
@@ -3118,7 +3118,7 @@ const vRipple = {
|
||
font-weight: 600;
|
||
margin-bottom: 2px;
|
||
line-height: 1.4;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
letter-spacing: 0.01em;
|
||
}
|
||
|
||
@@ -3366,7 +3366,7 @@ const vRipple = {
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 1rem;
|
||
- background: #21242d;
|
||
+ background: var(--bg-tertiary, #21242d);
|
||
border-radius: 10px;
|
||
padding: 0.75rem 1rem;
|
||
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
|
||
@@ -3379,7 +3379,7 @@ const vRipple = {
|
||
.date-nav-btn {
|
||
background: rgba(11, 90, 254, 0.1);
|
||
border: 1px solid rgba(11, 90, 254, 0.2);
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
border-radius: 50%;
|
||
width: 36px;
|
||
height: 36px;
|
||
@@ -3403,7 +3403,7 @@ const vRipple = {
|
||
font-family: 'MiSans', sans-serif;
|
||
font-weight: 600;
|
||
font-size: 16px;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
text-align: center;
|
||
flex: 1;
|
||
white-space: pre-line;
|
||
@@ -3453,7 +3453,7 @@ const vRipple = {
|
||
width: 85%;
|
||
max-width: 350px;
|
||
max-height: 70vh;
|
||
- background: #1a1d24;
|
||
+ background: var(--bg-secondary, #1a1d24);
|
||
border-radius: 12px;
|
||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
|
||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||
diff --git a/app/components/Songs/SongList.vue b/app/components/Songs/SongList.vue
|
||
index f6134f6..22c31ac 100644
|
||
--- a/app/components/Songs/SongList.vue
|
||
+++ b/app/components/Songs/SongList.vue
|
||
@@ -1691,14 +1691,14 @@ const vRipple = {
|
||
border-radius: 12px;
|
||
padding: 12px 16px 12px 42px;
|
||
font-size: 14px;
|
||
- color: #fff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
width: 100%;
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.mobile-search-input:focus {
|
||
background: rgba(255, 255, 255, 0.08);
|
||
- border-color: #3b82f6;
|
||
+ border-color: var(--border-secondary, #3b82f6);
|
||
outline: none;
|
||
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);
|
||
}
|
||
@@ -1785,7 +1785,7 @@ const vRipple = {
|
||
}
|
||
|
||
.tab-button.active {
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
border-bottom-color: #0b5afe;
|
||
transform: none;
|
||
box-shadow: none;
|
||
@@ -1834,7 +1834,7 @@ const vRipple = {
|
||
justify-content: center;
|
||
width: 36px;
|
||
height: 36px;
|
||
- background: #21242d;
|
||
+ background: var(--bg-tertiary, #21242d);
|
||
border: 1px solid rgba(255, 255, 255, 0.16);
|
||
border-radius: 8px;
|
||
cursor: pointer;
|
||
@@ -1845,7 +1845,7 @@ const vRipple = {
|
||
}
|
||
|
||
.semester-toggle-btn:hover {
|
||
- background: #2a2e38;
|
||
+ background: var(--bg-tertiary, #2a2e38);
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
||
color: #0b5afe;
|
||
@@ -1855,7 +1855,7 @@ const vRipple = {
|
||
position: absolute;
|
||
top: calc(100% + 8px);
|
||
right: 0;
|
||
- background: #1a1d24;
|
||
+ background: var(--bg-secondary, #1a1d24);
|
||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||
border-radius: 8px;
|
||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||
@@ -1879,7 +1879,7 @@ const vRipple = {
|
||
|
||
.semester-option:hover {
|
||
background: rgba(11, 90, 254, 0.1);
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
}
|
||
|
||
.semester-option.active {
|
||
@@ -1925,7 +1925,7 @@ const vRipple = {
|
||
justify-content: center;
|
||
width: 36px;
|
||
height: 36px;
|
||
- background: #21242d;
|
||
+ background: var(--bg-tertiary, #21242d);
|
||
border: 1px solid rgba(255, 255, 255, 0.16);
|
||
border-radius: 8px;
|
||
cursor: pointer;
|
||
@@ -1934,7 +1934,7 @@ const vRipple = {
|
||
}
|
||
|
||
.refresh-button:hover {
|
||
- background: #2a2e38;
|
||
+ background: var(--bg-tertiary, #2a2e38);
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
||
}
|
||
@@ -2028,7 +2028,7 @@ const vRipple = {
|
||
|
||
.song-card-main {
|
||
padding: 1rem 0 1rem 1rem; /* 移除右侧内边距,保留左侧、上下内边距 */
|
||
- background: #21242d;
|
||
+ background: var(--bg-tertiary, #21242d);
|
||
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
|
||
position: relative;
|
||
height: 100px; /* 减小卡片高度 */
|
||
@@ -2076,8 +2076,8 @@ const vRipple = {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
- background: linear-gradient(135deg, #0043f8 0%, #0075f8 100%);
|
||
- color: #ffffff;
|
||
+ background: linear-gradient(135deg, var(--bg-secondary, #0043f8) 0%, #0075f8 100%);
|
||
+ color: var(--text-primary, #ffffff);
|
||
font-size: 28px;
|
||
font-weight: bold;
|
||
font-family: 'MiSans-Demibold', sans-serif;
|
||
@@ -2139,7 +2139,7 @@ const vRipple = {
|
||
font-weight: 600;
|
||
font-size: 16px;
|
||
letter-spacing: 0.04em;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
margin-bottom: 0.5rem;
|
||
width: 100%; /* 确保标题占满整个容器宽度 */
|
||
display: flex;
|
||
@@ -2215,7 +2215,7 @@ const vRipple = {
|
||
font-family: 'MiSans-Demibold', sans-serif;
|
||
font-weight: 600;
|
||
font-size: 12px;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
opacity: 0.4;
|
||
}
|
||
|
||
@@ -2231,7 +2231,7 @@ const vRipple = {
|
||
justify-content: center;
|
||
width: 48px;
|
||
height: 45px;
|
||
- background: linear-gradient(180deg, #0043f8 0%, #0075f8 100%);
|
||
+ background: linear-gradient(180deg, var(--bg-secondary, #0043f8) 0%, #0075f8 100%);
|
||
border: 1px solid rgba(255, 255, 255, 0.16);
|
||
border-radius: 8px;
|
||
cursor: pointer;
|
||
@@ -2239,8 +2239,8 @@ const vRipple = {
|
||
}
|
||
|
||
.like-button.liked {
|
||
- background: #1a1d24;
|
||
- border-color: #242f38;
|
||
+ background: var(--bg-secondary, #1a1d24);
|
||
+ border-color: var(--border-secondary, #242f38);
|
||
background-image: none;
|
||
}
|
||
|
||
@@ -2329,7 +2329,7 @@ const vRipple = {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
- background: #21242d;
|
||
+ background: var(--bg-tertiary, #21242d);
|
||
border-radius: 0 0 10px 10px;
|
||
padding: 0.5rem 1rem;
|
||
width: 95%;
|
||
@@ -2355,7 +2355,7 @@ const vRipple = {
|
||
font-family: 'MiSans-Demibold', sans-serif;
|
||
font-weight: 600;
|
||
font-size: 12px;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
height: 27px;
|
||
@@ -2368,12 +2368,12 @@ const vRipple = {
|
||
}
|
||
|
||
.replay-cancel-btn {
|
||
- background: linear-gradient(180deg, #0b5afe 0%, #3d7fff 100%);
|
||
+ background: linear-gradient(180deg, var(--bg-secondary, #0b5afe) 0%, #3d7fff 100%);
|
||
min-width: 75px;
|
||
}
|
||
|
||
.replay-request-btn {
|
||
- background: linear-gradient(180deg, #0b5afe 0%, #3d7fff 100%);
|
||
+ background: linear-gradient(180deg, var(--bg-secondary, #0b5afe) 0%, #3d7fff 100%);
|
||
min-width: 75px;
|
||
}
|
||
|
||
@@ -2408,13 +2408,13 @@ button:disabled {
|
||
border-radius: 4px;
|
||
padding: 0.25rem 0.5rem;
|
||
font-size: 0.875rem;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.page-number.active {
|
||
- background: #0b5afe;
|
||
+ background: var(--bg-secondary, #0b5afe);
|
||
border-color: #0b5afe;
|
||
}
|
||
|
||
@@ -2444,7 +2444,7 @@ button:disabled {
|
||
border-radius: 4px;
|
||
padding: 0.25rem 0.5rem;
|
||
font-size: 0.875rem;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
width: 60px;
|
||
text-align: center;
|
||
transition: all 0.2s ease;
|
||
@@ -2467,7 +2467,7 @@ button:disabled {
|
||
border-radius: 4px;
|
||
padding: 0.25rem 0.5rem;
|
||
font-size: 0.875rem;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
white-space: nowrap;
|
||
@@ -2705,7 +2705,7 @@ button:disabled {
|
||
font-weight: 700;
|
||
margin-bottom: 4px;
|
||
line-height: 1.2;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
letter-spacing: 0.01em;
|
||
}
|
||
|
||
@@ -2930,7 +2930,7 @@ button:disabled {
|
||
border-radius: 12px;
|
||
background: rgba(255, 255, 255, 0.05);
|
||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||
- color: #fff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
@@ -2964,7 +2964,7 @@ button:disabled {
|
||
width: 40px;
|
||
background: transparent;
|
||
border: none;
|
||
- color: #fff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
text-align: center;
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
@@ -2991,7 +2991,7 @@ button:disabled {
|
||
|
||
.page-nav-btn:hover:not(:disabled) {
|
||
background: rgba(255, 255, 255, 0.1);
|
||
- border-color: #3b82f6;
|
||
+ border-color: var(--border-secondary, #3b82f6);
|
||
}
|
||
|
||
.page-nav-btn:disabled {
|
||
diff --git a/app/components/UI/AudioPlayer.vue b/app/components/UI/AudioPlayer.vue
|
||
index 1f4c7e6..ff92789 100644
|
||
--- a/app/components/UI/AudioPlayer.vue
|
||
+++ b/app/components/UI/AudioPlayer.vue
|
||
@@ -1528,7 +1528,7 @@ const getFirstChar = (text) => {
|
||
|
||
.mobile-top-progress .progress-fill {
|
||
height: 100%;
|
||
- background: #0b5afe;
|
||
+ background: var(--bg-secondary, #0b5afe);
|
||
box-shadow: 0 0 8px rgba(11, 90, 254, 0.6);
|
||
border-radius: 0 1px 1px 0;
|
||
}
|
||
@@ -1729,7 +1729,7 @@ const getFirstChar = (text) => {
|
||
align-items: center;
|
||
justify-content: center;
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
font-family:
|
||
@@ -1756,7 +1756,7 @@ const getFirstChar = (text) => {
|
||
line-height: 22px;
|
||
padding-bottom: 2px;
|
||
letter-spacing: -0.4px;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
font-family:
|
||
'SF Pro', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', SimHei, Arial, Helvetica,
|
||
sans-serif;
|
||
@@ -1776,7 +1776,7 @@ const getFirstChar = (text) => {
|
||
overflow: hidden;
|
||
line-height: 20px;
|
||
letter-spacing: -0.4px;
|
||
- color: #ffffff75;
|
||
+ color: var(--text-primary, #ffffff)75;
|
||
font-family:
|
||
'SF Pro', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', SimHei, Arial, Helvetica,
|
||
sans-serif;
|
||
@@ -1797,7 +1797,7 @@ const getFirstChar = (text) => {
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: 100px;
|
||
- background: #00000042;
|
||
+ background: var(--bg-primary, #111111)42;
|
||
padding: 6px;
|
||
width: 32px;
|
||
height: 32px;
|
||
@@ -1814,7 +1814,7 @@ const getFirstChar = (text) => {
|
||
}
|
||
|
||
.close-icon {
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
font-size: 15px;
|
||
line-height: 1;
|
||
font-family:
|
||
@@ -1851,7 +1851,7 @@ const getFirstChar = (text) => {
|
||
display: flex;
|
||
flex-shrink: 0;
|
||
align-items: center;
|
||
- border: 1px solid #1a1a1a;
|
||
+ border: 1px solid var(--border-secondary, #1a1a1a);
|
||
border-radius: 7px;
|
||
height: 8px;
|
||
width: 100%;
|
||
@@ -1864,14 +1864,14 @@ const getFirstChar = (text) => {
|
||
}
|
||
|
||
.ios-progress-bar:hover {
|
||
- border-color: #333;
|
||
+ border-color: var(--border-secondary, #333);
|
||
box-shadow:
|
||
0 0 20px rgba(255, 255, 255, 0.1),
|
||
inset 0 1px 0 rgba(255, 255, 255, 0.1);
|
||
}
|
||
|
||
.progress-fill {
|
||
- background: linear-gradient(90deg, #ffffffb2, #ffffff);
|
||
+ background: linear-gradient(90deg, var(--card-bg, #ffffff)b2, #ffffff);
|
||
height: 8px;
|
||
transition: width 0.1s linear;
|
||
border-radius: 7px;
|
||
@@ -1916,7 +1916,7 @@ const getFirstChar = (text) => {
|
||
}
|
||
|
||
.clickable-time:hover {
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
transform: scale(1.05);
|
||
}
|
||
|
||
@@ -1931,10 +1931,10 @@ const getFirstChar = (text) => {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
- background: #ffffff1a;
|
||
+ background: var(--card-bg, #ffffff)1a;
|
||
border-radius: 4px;
|
||
padding: 0 8px;
|
||
- color: #ffffffb3;
|
||
+ color: var(--text-primary, #ffffff)b3;
|
||
font-size: 10px;
|
||
font-weight: 600;
|
||
backdrop-filter: blur(10px);
|
||
@@ -1944,8 +1944,8 @@ const getFirstChar = (text) => {
|
||
}
|
||
|
||
.audio-quality-badge:hover {
|
||
- background: #ffffff26;
|
||
- color: #ffffff;
|
||
+ background: var(--card-bg, #ffffff)26;
|
||
+ color: var(--text-primary, #ffffff);
|
||
}
|
||
|
||
/* 控制按钮区域 */
|
||
@@ -1962,7 +1962,7 @@ const getFirstChar = (text) => {
|
||
.ios-control-btn {
|
||
background: none;
|
||
border: none;
|
||
- color: #ffffff92;
|
||
+ color: var(--text-primary, #ffffff)92;
|
||
cursor: pointer;
|
||
transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||
display: flex;
|
||
@@ -1997,7 +1997,7 @@ const getFirstChar = (text) => {
|
||
}
|
||
|
||
.ios-control-btn:hover {
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
transform: scale(1.1);
|
||
box-shadow:
|
||
0 0 20px rgba(255, 255, 255, 0.2),
|
||
@@ -2196,7 +2196,7 @@ const getFirstChar = (text) => {
|
||
width: 60px;
|
||
line-height: 18px;
|
||
letter-spacing: 0.42px;
|
||
- color: #ffffffb3;
|
||
+ color: var(--text-primary, #ffffff)b3;
|
||
font-family:
|
||
'SF Pro', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', SimHei, Arial, Helvetica,
|
||
sans-serif;
|
||
@@ -2215,10 +2215,10 @@ const getFirstChar = (text) => {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
- background: #ffffff1a;
|
||
+ background: var(--card-bg, #ffffff)1a;
|
||
border-radius: 4px;
|
||
padding: 0 8px;
|
||
- color: #ffffffb3;
|
||
+ color: var(--text-primary, #ffffff)b3;
|
||
font-size: 10px;
|
||
font-weight: 600;
|
||
backdrop-filter: blur(10px);
|
||
@@ -2228,8 +2228,8 @@ const getFirstChar = (text) => {
|
||
}
|
||
|
||
.audio-quality:hover {
|
||
- background: #ffffff26;
|
||
- color: #ffffff;
|
||
+ background: var(--card-bg, #ffffff)26;
|
||
+ color: var(--text-primary, #ffffff);
|
||
}
|
||
|
||
.audio-quality:active {
|
||
@@ -2251,13 +2251,13 @@ const getFirstChar = (text) => {
|
||
width: 39px;
|
||
font-size: 25px;
|
||
text-align: center;
|
||
- color: #ffffff92;
|
||
+ color: var(--text-primary, #ffffff)92;
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.lyrics-btn:hover {
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
transform: scale(1.1);
|
||
}
|
||
|
||
@@ -2265,7 +2265,7 @@ const getFirstChar = (text) => {
|
||
.control-btn {
|
||
line-height: 1;
|
||
font-size: 24px;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
display: flex;
|
||
@@ -2290,7 +2290,7 @@ const getFirstChar = (text) => {
|
||
.play-pause-btn {
|
||
line-height: 44px;
|
||
font-size: 37px;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
display: flex;
|
||
diff --git a/app/components/UI/Common/CustomSelect.vue b/app/components/UI/Common/CustomSelect.vue
|
||
index 80231e9..98ac764 100644
|
||
--- a/app/components/UI/Common/CustomSelect.vue
|
||
+++ b/app/components/UI/Common/CustomSelect.vue
|
||
@@ -216,7 +216,7 @@ onUnmounted(() => {
|
||
background: transparent;
|
||
}
|
||
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||
- background: #27272a;
|
||
+ background: var(--bg-tertiary, #27272a);
|
||
border-radius: 10px;
|
||
}
|
||
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
||
diff --git a/app/components/UI/LyricsModal.vue b/app/components/UI/LyricsModal.vue
|
||
index 25c07ac..7863815 100644
|
||
--- a/app/components/UI/LyricsModal.vue
|
||
+++ b/app/components/UI/LyricsModal.vue
|
||
@@ -1136,7 +1136,7 @@ onUnmounted(() => {
|
||
.default-cover {
|
||
width: 100%;
|
||
height: 100%;
|
||
- background: linear-gradient(135deg, #333, #555);
|
||
+ background: linear-gradient(135deg, var(--bg-quaternary, #333333), #555);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
@@ -1152,7 +1152,7 @@ onUnmounted(() => {
|
||
font-size: 2.2rem;
|
||
font-weight: 700;
|
||
margin: 0 0 0.5rem 0;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
line-height: 1.2;
|
||
letter-spacing: -0.02em;
|
||
white-space: normal;
|
||
@@ -1246,7 +1246,7 @@ onUnmounted(() => {
|
||
|
||
.progress-fill {
|
||
height: 100%;
|
||
- background: #ffffff;
|
||
+ background: var(--card-bg, #ffffff);
|
||
border-radius: 3px;
|
||
pointer-events: none;
|
||
}
|
||
@@ -1256,7 +1256,7 @@ onUnmounted(() => {
|
||
top: 50%;
|
||
width: 14px;
|
||
height: 14px;
|
||
- background: #ffffff;
|
||
+ background: var(--card-bg, #ffffff);
|
||
border-radius: 50%;
|
||
transform: translate(-50%, -50%) scale(0);
|
||
transition: transform 0.1s ease;
|
||
@@ -1306,7 +1306,7 @@ onUnmounted(() => {
|
||
|
||
.secondary-btn.active {
|
||
opacity: 1;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
text-shadow: 0 0 8px rgba(255, 255, 255, 0.4);
|
||
}
|
||
|
||
@@ -1472,7 +1472,7 @@ onUnmounted(() => {
|
||
width: 100%;
|
||
text-align: center;
|
||
background: transparent;
|
||
- color: #333; /* 深色文字 */
|
||
+ color: var(--text-quaternary, #333333); /* 深色文字 */
|
||
padding: 8px 12px; /* 减小内边距 */
|
||
border-radius: 8px;
|
||
font-size: 0.85rem; /* 稍微减小字体 */
|
||
@@ -1490,7 +1490,7 @@ onUnmounted(() => {
|
||
|
||
.badge-quality-option.active {
|
||
color: #007aff; /* 蓝色字 */
|
||
- background: #ffffff;
|
||
+ background: var(--card-bg, #ffffff);
|
||
font-weight: 600;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||
}
|
||
@@ -1522,7 +1522,7 @@ onUnmounted(() => {
|
||
width: 20px;
|
||
height: 5px;
|
||
border-radius: 3px;
|
||
- background: #ffffff;
|
||
+ background: var(--card-bg, #ffffff);
|
||
box-shadow: 0 0 10px rgba(255, 255, 255, 0.3);
|
||
}
|
||
|
||
@@ -1759,7 +1759,7 @@ onUnmounted(() => {
|
||
}
|
||
|
||
.progress-fill {
|
||
- background: #ffffff;
|
||
+ background: var(--card-bg, #ffffff);
|
||
}
|
||
|
||
.progress-thumb {
|
||
diff --git a/app/components/UI/Notification.vue b/app/components/UI/Notification.vue
|
||
index b16b050..a2f69a2 100644
|
||
--- a/app/components/UI/Notification.vue
|
||
+++ b/app/components/UI/Notification.vue
|
||
@@ -70,8 +70,8 @@ defineEmits(['close'])
|
||
padding: 16px;
|
||
border-radius: 8px;
|
||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
|
||
- background: #21242d;
|
||
- color: #ffffff;
|
||
+ background: var(--bg-tertiary, #21242d);
|
||
+ color: var(--text-primary, #ffffff);
|
||
max-width: 400px;
|
||
min-width: 300px;
|
||
font-family: 'MiSans', sans-serif;
|
||
@@ -79,7 +79,7 @@ defineEmits(['close'])
|
||
}
|
||
|
||
.notification.success {
|
||
- border-left: 4px solid #10b981;
|
||
+ border-left: 4px solid var(--border-secondary, #10b981);
|
||
}
|
||
|
||
.notification.error {
|
||
@@ -140,7 +140,7 @@ defineEmits(['close'])
|
||
}
|
||
|
||
.notification-close:hover {
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
}
|
||
|
||
/* 进度条 */
|
||
@@ -161,7 +161,7 @@ defineEmits(['close'])
|
||
}
|
||
|
||
.success .notification-progress-bar {
|
||
- background-color: #10b981;
|
||
+ background-color: var(--bg-secondary, #10b981);
|
||
}
|
||
|
||
.error .notification-progress-bar {
|
||
@@ -169,7 +169,7 @@ defineEmits(['close'])
|
||
}
|
||
|
||
.info .notification-progress-bar {
|
||
- background-color: #0b5afe;
|
||
+ background-color: var(--bg-secondary, #0b5afe);
|
||
}
|
||
|
||
@keyframes progress-shrink {
|
||
diff --git a/app/components/UI/NotificationContainer.vue b/app/components/UI/NotificationContainer.vue
|
||
index 146ac16..f782fa7 100644
|
||
--- a/app/components/UI/NotificationContainer.vue
|
||
+++ b/app/components/UI/NotificationContainer.vue
|
||
@@ -82,8 +82,8 @@ onMounted(() => {
|
||
padding: 16px;
|
||
border-radius: 8px;
|
||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
|
||
- background: #21242d;
|
||
- color: #ffffff;
|
||
+ background: var(--bg-tertiary, #21242d);
|
||
+ color: var(--text-primary, #ffffff);
|
||
max-width: 400px;
|
||
min-width: 300px;
|
||
font-family: 'MiSans', sans-serif;
|
||
@@ -94,7 +94,7 @@ onMounted(() => {
|
||
}
|
||
|
||
.notification-item.success {
|
||
- border-left: 4px solid #10b981;
|
||
+ border-left: 4px solid var(--border-secondary, #10b981);
|
||
}
|
||
|
||
.notification-item.error {
|
||
@@ -158,7 +158,7 @@ onMounted(() => {
|
||
}
|
||
|
||
.notification-close:hover {
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
}
|
||
|
||
/* 进度条 */
|
||
@@ -179,7 +179,7 @@ onMounted(() => {
|
||
}
|
||
|
||
.success .notification-progress-bar {
|
||
- background-color: #10b981;
|
||
+ background-color: var(--bg-secondary, #10b981);
|
||
}
|
||
|
||
.error .notification-progress-bar {
|
||
@@ -187,7 +187,7 @@ onMounted(() => {
|
||
}
|
||
|
||
.info .notification-progress-bar {
|
||
- background-color: #0b5afe;
|
||
+ background-color: var(--bg-secondary, #0b5afe);
|
||
}
|
||
|
||
@keyframes progress-shrink {
|
||
diff --git a/app/components/UserTutorial.vue b/app/components/UserTutorial.vue
|
||
index 3ad45ac..c42bed2 100644
|
||
--- a/app/components/UserTutorial.vue
|
||
+++ b/app/components/UserTutorial.vue
|
||
@@ -359,15 +359,15 @@ onMounted(() => {
|
||
z-index: 9999;
|
||
border-radius: 8px;
|
||
box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.5), 0 0 15px rgba(0, 0, 0, 0.5);
|
||
- border: 2px solid #3b82f6;
|
||
+ border: 2px solid var(--border-secondary, #3b82f6);
|
||
pointer-events: none;
|
||
transition: all 0.4s ease;
|
||
background: transparent;
|
||
}
|
||
|
||
.tour-popover {
|
||
- background: #18181b;
|
||
- border: 1px solid #27272a;
|
||
+ background: var(--bg-secondary, #18181b);
|
||
+ border: 1px solid var(--border-secondary, #27272a);
|
||
border-radius: 12px;
|
||
padding: 1.25rem;
|
||
width: 320px;
|
||
@@ -440,9 +440,9 @@ onMounted(() => {
|
||
}
|
||
|
||
.tour-btn-secondary {
|
||
- background: #27272a;
|
||
+ background: var(--bg-tertiary, #27272a);
|
||
color: #d4d4d8;
|
||
- border: 1px solid #3f3f46;
|
||
+ border: 1px solid var(--border-secondary, #3f3f46);
|
||
}
|
||
|
||
.tour-btn-secondary:hover {
|
||
@@ -456,6 +456,6 @@ onMounted(() => {
|
||
}
|
||
|
||
.tour-btn-primary:hover {
|
||
- background: #2563eb;
|
||
+ background: var(--bg-tertiary, #2563eb);
|
||
}
|
||
</style>
|
||
diff --git a/app/components/year-review/ArtistSlide.vue b/app/components/year-review/ArtistSlide.vue
|
||
index 41a2cd4..1b060d8 100644
|
||
--- a/app/components/year-review/ArtistSlide.vue
|
||
+++ b/app/components/year-review/ArtistSlide.vue
|
||
@@ -43,7 +43,7 @@ defineProps({
|
||
.bg-overlay {
|
||
position: absolute;
|
||
inset: 0;
|
||
- background: linear-gradient(to top, #000, transparent, transparent);
|
||
+ background: linear-gradient(to top, var(--bg-primary, #111111), transparent, transparent);
|
||
opacity: 0.8;
|
||
z-index: 10;
|
||
}
|
||
diff --git a/app/components/year-review/FirstSongSlide.vue b/app/components/year-review/FirstSongSlide.vue
|
||
index 630ef15..9ab57af 100644
|
||
--- a/app/components/year-review/FirstSongSlide.vue
|
||
+++ b/app/components/year-review/FirstSongSlide.vue
|
||
@@ -74,7 +74,7 @@ const formatDate = (dateStr) => {
|
||
align-items: center;
|
||
justify-content: center;
|
||
overflow: hidden;
|
||
- background-color: #000;
|
||
+ background-color: var(--bg-primary, #111111);
|
||
}
|
||
|
||
.bg-blur {
|
||
@@ -120,7 +120,7 @@ const formatDate = (dateStr) => {
|
||
}
|
||
|
||
.highlight {
|
||
- color: #fff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
font-weight: 700;
|
||
margin: 0 0.5rem;
|
||
}
|
||
@@ -141,7 +141,7 @@ const formatDate = (dateStr) => {
|
||
overflow: hidden;
|
||
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
|
||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||
- background: #111827;
|
||
+ background: var(--bg-secondary, #111827);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
@@ -181,7 +181,7 @@ const formatDate = (dateStr) => {
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
- color: #fff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
}
|
||
|
||
.song-artist {
|
||
diff --git a/app/components/year-review/IntroSlide.vue b/app/components/year-review/IntroSlide.vue
|
||
index 266bbb7..4c5e496 100644
|
||
--- a/app/components/year-review/IntroSlide.vue
|
||
+++ b/app/components/year-review/IntroSlide.vue
|
||
@@ -31,7 +31,7 @@ defineProps({
|
||
align-items: center;
|
||
justify-content: center;
|
||
overflow: hidden;
|
||
- background: radial-gradient(circle at center, #111827, #000000);
|
||
+ background: radial-gradient(circle at center, var(--bg-secondary, #111827), #000000);
|
||
}
|
||
|
||
.blob {
|
||
diff --git a/app/components/year-review/MiscSlide.vue b/app/components/year-review/MiscSlide.vue
|
||
index cc65ec1..6221775 100644
|
||
--- a/app/components/year-review/MiscSlide.vue
|
||
+++ b/app/components/year-review/MiscSlide.vue
|
||
@@ -54,7 +54,7 @@ const formatPlatform = (platform) => {
|
||
align-items: center;
|
||
justify-content: center;
|
||
overflow: hidden;
|
||
- background-color: #111827; /* gray-900 */
|
||
+ background-color: var(--bg-secondary, #111827); /* gray-900 */
|
||
}
|
||
|
||
.bg-gradient {
|
||
@@ -63,7 +63,7 @@ const formatPlatform = (platform) => {
|
||
left: 0;
|
||
width: 100%;
|
||
height: 50%;
|
||
- background: linear-gradient(to bottom, #1f2937, transparent);
|
||
+ background: linear-gradient(to bottom, var(--bg-secondary, #1f2937), transparent);
|
||
opacity: 0.2;
|
||
}
|
||
|
||
diff --git a/app/components/year-review/OutroSlide.vue b/app/components/year-review/OutroSlide.vue
|
||
index 0fe78e7..f62251c 100644
|
||
--- a/app/components/year-review/OutroSlide.vue
|
||
+++ b/app/components/year-review/OutroSlide.vue
|
||
@@ -56,13 +56,13 @@ defineEmits(['share'])
|
||
align-items: center;
|
||
justify-content: center;
|
||
overflow: hidden;
|
||
- background-color: #000;
|
||
+ background-color: var(--bg-primary, #111111);
|
||
}
|
||
|
||
.bg-gradient {
|
||
position: absolute;
|
||
inset: 0;
|
||
- background: radial-gradient(circle at center, #1f2937, #000, #000);
|
||
+ background: radial-gradient(circle at center, var(--bg-secondary, #1f2937), #000, #000);
|
||
opacity: 0.5;
|
||
}
|
||
|
||
@@ -132,8 +132,8 @@ defineEmits(['share'])
|
||
width: 100%;
|
||
padding: 1rem 2rem;
|
||
border-radius: 9999px;
|
||
- background: #fff;
|
||
- color: #000;
|
||
+ background: var(--card-bg, #fff);
|
||
+ color: var(--text-primary, #000);
|
||
font-weight: 700;
|
||
font-size: 1.125rem;
|
||
overflow: hidden;
|
||
@@ -173,7 +173,7 @@ defineEmits(['share'])
|
||
border-radius: 9999px;
|
||
background: rgba(255, 255, 255, 0.1);
|
||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||
- color: #fff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
font-weight: 700;
|
||
font-size: 1.125rem;
|
||
backdrop-filter: blur(12px);
|
||
diff --git a/app/components/year-review/ShareCard.vue b/app/components/year-review/ShareCard.vue
|
||
index b1f2e91..bd33395 100644
|
||
--- a/app/components/year-review/ShareCard.vue
|
||
+++ b/app/components/year-review/ShareCard.vue
|
||
@@ -63,7 +63,7 @@ defineExpose({
|
||
height: 100%;
|
||
min-height: 600px;
|
||
overflow: hidden;
|
||
- background: linear-gradient(135deg, #0f0f23 0%, #1a1a2e 50%, #16213e 100%);
|
||
+ background: linear-gradient(135deg, var(--bg-secondary, #0f0f23) 0%, #1a1a2e 50%, #16213e 100%);
|
||
}
|
||
|
||
.card-background {
|
||
@@ -127,7 +127,7 @@ defineExpose({
|
||
.main-title {
|
||
font-size: 3.5rem;
|
||
font-weight: 900;
|
||
- background: linear-gradient(135deg, #ffffff 0%, #e5e7eb 50%, #9ca3af 100%);
|
||
+ background: linear-gradient(135deg, var(--card-bg, #ffffff) 0%, #e5e7eb 50%, #9ca3af 100%);
|
||
-webkit-background-clip: text;
|
||
background-clip: text;
|
||
color: transparent;
|
||
diff --git a/app/pages/change-password.vue b/app/pages/change-password.vue
|
||
index 506d5e6..7cad842 100644
|
||
--- a/app/pages/change-password.vue
|
||
+++ b/app/pages/change-password.vue
|
||
@@ -195,7 +195,7 @@ onMounted(async () => {
|
||
font-size: 36px;
|
||
font-weight: 700;
|
||
margin: 0;
|
||
- background: linear-gradient(135deg, #ffffff 0%, #f0f0f0 100%);
|
||
+ background: linear-gradient(135deg, var(--card-bg, #ffffff) 0%, #f0f0f0 100%);
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
background-clip: text;
|
||
diff --git a/app/pages/index.vue b/app/pages/index.vue
|
||
index 8d450c0..7ec75dd 100644
|
||
--- a/app/pages/index.vue
|
||
+++ b/app/pages/index.vue
|
||
@@ -1910,7 +1910,7 @@ if (
|
||
height: 18px;
|
||
border-radius: 9px;
|
||
background-color: var(--error, #ef4444);
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
font-size: 10px;
|
||
font-weight: 700;
|
||
display: flex;
|
||
@@ -3405,7 +3405,7 @@ if (
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
box-shadow: 0 10px 25px -5px rgba(139, 92, 246, 0.35);
|
||
z-index: 2;
|
||
transform: rotate(-5deg);
|
||
@@ -3485,7 +3485,7 @@ if (
|
||
background: var(--primary, #0b5afe);
|
||
border: none;
|
||
border-radius: 16px;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
font-size: 16px;
|
||
font-weight: 700;
|
||
display: flex;
|
||
@@ -3600,7 +3600,7 @@ if (
|
||
width: 8px;
|
||
height: 8px;
|
||
border-radius: 50%;
|
||
- background-color: #0b5afe;
|
||
+ background-color: var(--bg-secondary, #0b5afe);
|
||
display: inline-block;
|
||
z-index: 2;
|
||
}
|
||
@@ -3664,9 +3664,9 @@ if (
|
||
}
|
||
|
||
.login-button {
|
||
- background: linear-gradient(180deg, #0043f8 0%, #0075f8 100%);
|
||
+ background: linear-gradient(180deg, var(--bg-secondary, #0043f8) 0%, #0075f8 100%);
|
||
border: none;
|
||
- color: #ffffff;
|
||
+ color: var(--text-primary, #ffffff);
|
||
padding: 10px 20px;
|
||
border-radius: 6px;
|
||
font-weight: 600;
|
||
diff --git a/app/pages/year-review.vue b/app/pages/year-review.vue
|
||
index aae3219..398dd2c 100644
|
||
--- a/app/pages/year-review.vue
|
||
+++ b/app/pages/year-review.vue
|
||
@@ -211,8 +211,8 @@ const handleTouchEnd = (e) => {
|
||
.review-page {
|
||
position: fixed;
|
||
inset: 0;
|
||
- background-color: #000;
|
||
- color: #fff;
|
||
+ background-color: var(--bg-primary, #111111);
|
||
+ color: var(--text-primary, #ffffff);
|
||
z-index: 9999;
|
||
font-family:
|
||
'MiSans',
|
||
@@ -230,7 +230,7 @@ const handleTouchEnd = (e) => {
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
- background-color: #000;
|
||
+ background-color: var(--bg-primary, #111111);
|
||
z-index: 50;
|
||
}
|
||
|
||
@@ -285,7 +285,7 @@ const handleTouchEnd = (e) => {
|
||
.empty .empty-icon-circle {
|
||
width: 5rem;
|
||
height: 5rem;
|
||
- background: #111827;
|
||
+ background: var(--bg-secondary, #111827);
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
@@ -364,7 +364,7 @@ const handleTouchEnd = (e) => {
|
||
|
||
.indicator-dot.active {
|
||
height: 1.5rem;
|
||
- background: #fff;
|
||
+ background: var(--card-bg, #fff);
|
||
}
|
||
|
||
/* 滚动提示 */
|
||
diff --git a/fix-colors.mjs b/fix-colors.mjs
|
||
new file mode 100644
|
||
index 0000000..003e18b
|
||
--- /dev/null
|
||
+++ b/fix-colors.mjs
|
||
@@ -0,0 +1,128 @@
|
||
+import fs from 'fs/promises';
|
||
+import path from 'path';
|
||
+
|
||
+async function walk(dir) {
|
||
+ const files = await fs.readdir(dir, { withFileTypes: true });
|
||
+ let results = [];
|
||
+ for (const file of files) {
|
||
+ const res = path.resolve(dir, file.name);
|
||
+ if (file.isDirectory()) {
|
||
+ results = results.concat(await walk(res));
|
||
+ } else if (file.name.endsWith('.vue')) {
|
||
+ results.push(res);
|
||
+ }
|
||
+ }
|
||
+ return results;
|
||
+}
|
||
+
|
||
+async function fixColors() {
|
||
+ const dirs = [path.resolve('app', 'components'), path.resolve('app', 'pages'), path.resolve('app', 'layouts')];
|
||
+ let files = [];
|
||
+ for (const dir of dirs) {
|
||
+ try {
|
||
+ files = files.concat(await walk(dir));
|
||
+ } catch (e) {
|
||
+ // Ignore if dir doesn't exist
|
||
+ }
|
||
+ }
|
||
+
|
||
+ for (const file of files) {
|
||
+ let content = await fs.readFile(file, 'utf-8');
|
||
+ let original = content;
|
||
+
|
||
+ // Generic regex for hardcoded grayscales in styles
|
||
+ const grayscales = {
|
||
+ '#000000': 'var(--bg-primary, #111111)',
|
||
+ '#000': 'var(--bg-primary, #111111)',
|
||
+ '#111111': 'var(--bg-primary, #111111)',
|
||
+ '#111': 'var(--bg-primary, #111111)',
|
||
+ '#1a1a1a': 'var(--bg-secondary, #1a1a1a)',
|
||
+ '#222222': 'var(--bg-tertiary, #222222)',
|
||
+ '#222': 'var(--bg-tertiary, #222222)',
|
||
+ '#2a2a2a': 'var(--bg-tertiary, #2a2a2a)',
|
||
+ '#333333': 'var(--bg-quaternary, #333333)',
|
||
+ '#333': 'var(--bg-quaternary, #333333)',
|
||
+ '#3a3a3a': 'var(--bg-quaternary, #3a3a3a)',
|
||
+ '#444444': 'var(--text-disabled, #444444)',
|
||
+ '#444': 'var(--text-disabled, #444444)',
|
||
+ '#666666': 'var(--text-quaternary, #666666)',
|
||
+ '#666': 'var(--text-quaternary, #666666)',
|
||
+ '#888888': 'var(--text-tertiary, #888888)',
|
||
+ '#888': 'var(--text-tertiary, #888888)',
|
||
+ '#999999': 'var(--text-tertiary, #999999)',
|
||
+ '#999': 'var(--text-tertiary, #999999)',
|
||
+ '#aaaaaa': 'var(--text-secondary, #aaaaaa)',
|
||
+ '#aaa': 'var(--text-secondary, #aaaaaa)',
|
||
+ '#cccccc': 'var(--text-secondary, #cccccc)',
|
||
+ '#ccc': 'var(--text-secondary, #cccccc)',
|
||
+ '#dddddd': 'var(--border-secondary, #dddddd)',
|
||
+ '#ddd': 'var(--border-secondary, #dddddd)',
|
||
+ '#eeeeee': 'var(--border-primary, #eeeeee)',
|
||
+ '#eee': 'var(--border-primary, #eeeeee)',
|
||
+ '#ffffff': 'var(--text-primary, #ffffff)',
|
||
+ '#fff': 'var(--text-primary, #ffffff)'
|
||
+ };
|
||
+
|
||
+ // We only want to replace inside <style> blocks.
|
||
+ const styleBlocks = content.match(/<style[^>]*>[\s\S]*?<\/style>/gi);
|
||
+ if (styleBlocks) {
|
||
+ for (const block of styleBlocks) {
|
||
+ let newBlock = block;
|
||
+
|
||
+ // Match CSS properties like background: #1a1a1a;
|
||
+ newBlock = newBlock.replace(/(background(-color)?|color|border(-color)?|border-(top|right|bottom|left)(-color)?|fill|stroke):\s*([^;}]*?)(#[0-9a-fA-F]{3,6})/gi, (match, p1, p2, p3, p4, p5, p6, hex) => {
|
||
+ const hexLower = hex.toLowerCase();
|
||
+
|
||
+ // Don't replace if it's already inside a var()
|
||
+ if (p6.includes('var(')) return match;
|
||
+
|
||
+ let replacement = hex;
|
||
+
|
||
+ if (grayscales[hexLower]) {
|
||
+ // Determine if it's a background, border, or text color
|
||
+ if (p1.startsWith('border')) {
|
||
+ replacement = `var(--border-secondary, ${hexLower})`;
|
||
+ } else if (p1.startsWith('background')) {
|
||
+ if (hexLower === '#ffffff' || hexLower === '#fff') {
|
||
+ replacement = `var(--card-bg, ${hexLower})`; // White background is usually a card
|
||
+ } else {
|
||
+ replacement = grayscales[hexLower].replace('text', 'bg'); // Force bg variables for background
|
||
+ }
|
||
+ } else if (p1 === 'color') {
|
||
+ if (['#000000', '#000', '#111111', '#111', '#1a1a1a', '#222222', '#222', '#2a2a2a'].includes(hexLower)) {
|
||
+ replacement = `var(--text-primary, ${hexLower})`;
|
||
+ } else {
|
||
+ replacement = grayscales[hexLower].replace('bg', 'text'); // Force text variables for color
|
||
+ }
|
||
+ } else {
|
||
+ replacement = grayscales[hexLower];
|
||
+ }
|
||
+ } else {
|
||
+ // Heuristic for unknown grayscales or dark colors
|
||
+ // Check if it's a dark shade (e.g. #040e15, #242f38)
|
||
+ if (p1.startsWith('background') && match.match(/#0[0-9a-f]{5}/i)) {
|
||
+ replacement = `var(--bg-secondary, ${hexLower})`;
|
||
+ } else if (p1.startsWith('background') && match.match(/#1[0-9a-f]{5}/i)) {
|
||
+ replacement = `var(--bg-secondary, ${hexLower})`;
|
||
+ } else if (p1.startsWith('background') && match.match(/#2[0-9a-f]{5}/i)) {
|
||
+ replacement = `var(--bg-tertiary, ${hexLower})`;
|
||
+ } else if (p1.startsWith('border') && match.match(/#[1-4][0-9a-f]{5}/i)) {
|
||
+ replacement = `var(--border-secondary, ${hexLower})`;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return `${p1}: ${p6}${replacement}`;
|
||
+ });
|
||
+
|
||
+ content = content.replace(block, newBlock);
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (content !== original) {
|
||
+ await fs.writeFile(file, content, 'utf-8');
|
||
+ console.log('Fixed', file);
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+fixColors().catch(console.error);
|
||
diff --git a/old-index.vue b/old-index.vue
|
||
new file mode 100644
|
||
index 0000000..778186b
|
||
--- /dev/null
|
||
+++ b/old-index.vue
|
||
@@ -0,0 +1,3661 @@
|
||
+<template>
|
||
+ <div class="home">
|
||
+ <div class="ellipse-effect" />
|
||
+ <div class="main-content">
|
||
+ <div class="top-bar">
|
||
+ <div class="logo-section">
|
||
+ <NuxtLink class="logo-link" to="/">
|
||
+ <img
|
||
+ alt="VoiceHub Logo"
|
||
+ class="logo-image"
|
||
+ :src="logo"
|
||
+ width="90"
|
||
+ height="90"
|
||
+ decoding="async"
|
||
+ fetchpriority="high"
|
||
+ >
|
||
+ </NuxtLink>
|
||
+ <!-- 妯嚎鍜屽鏍ogo -->
|
||
+ <div v-if="schoolLogoHomeUrl && schoolLogoHomeUrl.trim()" class="logo-divider-container">
|
||
+ <div class="logo-divider" />
|
||
+ <img
|
||
+ :src="proxiedSchoolLogoUrl"
|
||
+ alt="瀛︽牎Logo"
|
||
+ class="school-logo"
|
||
+ width="200"
|
||
+ height="80"
|
||
+ decoding="async"
|
||
+ fetchpriority="high"
|
||
+ >
|
||
+ </div>
|
||
+ </div>
|
||
+
|
||
+ <!-- 鐢ㄦ埛淇℃伅鍖哄煙 -->
|
||
+ <div class="user-section">
|
||
+ <ClientOnly>
|
||
+ <!-- 涓婚鍒囨崲鎸夐挳 -->
|
||
+ <button
|
||
+ class="utility-btn theme-toggle-btn"
|
||
+ type="button"
|
||
+ aria-label="涓婚"
|
||
+ title="鍒囨崲涓婚"
|
||
+ @click="handleToggleTheme"
|
||
+ >
|
||
+ <Icon :name="isDark ? 'sun' : 'moon'" :size="18" />
|
||
+ <span class="utility-btn-label">涓婚</span>
|
||
+ </button>
|
||
+
|
||
+ <!-- 璇█鍒囨崲鎸夐挳锛堝崰浣嶆寜閽紝褰撳墠鍗曡绉嶏級 -->
|
||
+ <button
|
||
+ class="utility-btn lang-toggle-btn"
|
||
+ type="button"
|
||
+ aria-label="璇█"
|
||
+ title="璇█"
|
||
+ @click="handleLanguageClick"
|
||
+ >
|
||
+ <Icon name="globe" :size="18" />
|
||
+ <span class="utility-btn-label">璇█</span>
|
||
+ </button>
|
||
+
|
||
+ <div v-if="isClientAuthenticated" class="user-info">
|
||
+ <div class="user-details-desktop">
|
||
+ <span class="user-name">{{ user?.name || '鐢ㄦ埛' }}</span>
|
||
+ <span v-if="isAdmin" class="user-badge admin">{{ roleName }}</span>
|
||
+ <span v-else class="user-badge">{{ userClassInfo }}</span>
|
||
+ </div>
|
||
+
|
||
+ <NuxtLink v-if="isAdmin" class="enter-admin-btn" to="/dashboard">
|
||
+ <Icon name="settings" :size="16" />
|
||
+ <span>杩涘叆鍚庡彴</span>
|
||
+ </NuxtLink>
|
||
+
|
||
+ <div class="user-avatar-wrapper" @click="toggleUserActions">
|
||
+ <img
|
||
+ v-if="user?.avatar && !avatarError"
|
||
+ :src="user.avatar"
|
||
+ class="user-avatar"
|
||
+ @error="avatarError = true"
|
||
+ >
|
||
+ <div v-else class="user-avatar-placeholder">
|
||
+ {{ user?.name?.[0] || 'U' }}
|
||
+ </div>
|
||
+ </div>
|
||
+
|
||
+ <Transition name="dropdown-fade">
|
||
+ <div v-if="showUserActions" class="user-actions-dropdown">
|
||
+ <NuxtLink class="action-item" to="/account">
|
||
+ <Icon name="user" :size="16" />
|
||
+ <span>璐﹀彿绠$悊</span>
|
||
+ </NuxtLink>
|
||
+ <NuxtLink v-if="isAdmin" class="action-item" to="/dashboard">
|
||
+ <Icon name="settings" :size="16" />
|
||
+ <span>绠$悊鍚庡彴</span>
|
||
+ </NuxtLink>
|
||
+ <button class="action-item logout" @click="handleLogout">
|
||
+ <Icon name="logout" :size="16" />
|
||
+ <span>閫€鍑虹櫥褰?/span>
|
||
+ </button>
|
||
+ </div>
|
||
+ </Transition>
|
||
+ </div>
|
||
+
|
||
+ <div v-else class="login-options">
|
||
+ <NuxtLink class="login-btn" to="/login">
|
||
+ <Icon name="user" :size="16" />
|
||
+ <span>鐧诲綍/娉ㄥ唽</span>
|
||
+ </NuxtLink>
|
||
+ </div>
|
||
+ </ClientOnly>
|
||
+ </div>
|
||
+ </div>
|
||
+
|
||
+ <div v-if="siteTitle" class="site-title">
|
||
+ <div class="title-container">
|
||
+ <h2 class="main-title">{{ siteTitle }}</h2>
|
||
+ <div class="title-divider" />
|
||
+ <span class="sub-title">VoiceHub 鏍″洯骞挎挱绯荤粺</span>
|
||
+ </div>
|
||
+ </div>
|
||
+
|
||
+ <!-- 涓棿涓讳綋鍐呭鍖哄煙 -->
|
||
+ <div class="content-area">
|
||
+ <!-- 閫夐」鍗″尯鍩?-->
|
||
+ <div class="tabs-row">
|
||
+ <div
|
||
+ :class="{ active: activeTab === 'schedule' }"
|
||
+ class="section-tab schedule-tab"
|
||
+ @click="handleTabClick('schedule')"
|
||
+ >
|
||
+ <Icon class="tab-icon" name="calendar" :size="20" />
|
||
+ <span class="tab-text">鎾嚭鎺掓湡</span>
|
||
+ </div>
|
||
+ <div
|
||
+ :class="{ active: activeTab === 'songs' }"
|
||
+ class="section-tab songs-tab"
|
||
+ @click="handleTabClick('songs')"
|
||
+ >
|
||
+ <Icon class="tab-icon" name="music" :size="20" />
|
||
+ <span class="tab-text">姝屾洸鍒楄〃</span>
|
||
+ </div>
|
||
+ <div
|
||
+ :class="{ active: activeTab === 'request' }"
|
||
+ class="section-tab request-tab"
|
||
+ @click="handleTabClick('request')"
|
||
+ >
|
||
+ <Icon class="tab-icon" name="search" :size="20" />
|
||
+ <span class="tab-text">鎶曠姝屾洸</span>
|
||
+ </div>
|
||
+ <ClientOnly>
|
||
+ <div
|
||
+ ref="notificationTabRef"
|
||
+ :class="{ active: activeTab === 'notification', disabled: !isClientAuthenticated }"
|
||
+ class="section-tab"
|
||
+ data-tab="notification"
|
||
+ @click="isClientAuthenticated ? handleTabClick('notification') : showLoginNotice()"
|
||
+ >
|
||
+ <div class="icon-wrapper">
|
||
+ <Icon class="tab-icon" name="message-circle" :size="20" />
|
||
+ <span
|
||
+ v-if="isClientAuthenticated && hasUnreadNotifications"
|
||
+ class="notification-badge-tab"
|
||
+ />
|
||
+ </div>
|
||
+ <span class="tab-text">
|
||
+ 娑堟伅
|
||
+ <span
|
||
+ v-if="isClientAuthenticated && hasUnreadNotifications"
|
||
+ class="notification-badge-desktop"
|
||
+ />
|
||
+ </span>
|
||
+ </div>
|
||
+ <template #fallback>
|
||
+ <div class="section-tab disabled" data-tab="notification">
|
||
+ <Icon class="tab-icon" name="message-circle" :size="20" />
|
||
+ <span class="tab-text">娑堟伅</span>
|
||
+ </div>
|
||
+ </template>
|
||
+ </ClientOnly>
|
||
+ </div>
|
||
+
|
||
+ <!-- 鍐呭鍖哄煙 -->
|
||
+ <div class="tab-content-container">
|
||
+ <ClientOnly>
|
||
+ <!-- 鎾嚭鎺掓湡鍐呭 -->
|
||
+ <div v-if="activeTab === 'schedule'" key="schedule" class="tab-pane schedule-tab-pane">
|
||
+ <div class="full-width">
|
||
+ <SongsScheduleList
|
||
+ :error="error"
|
||
+ :loading="loading"
|
||
+ :schedules="publicSchedules"
|
||
+ @semester-change="handleSemesterChange"
|
||
+ />
|
||
+ </div>
|
||
+
|
||
+ <!-- 鐢ㄦ埛浣跨敤鎸囧崡缁勪欢 -->
|
||
+ <UserTutorial />
|
||
+ </div>
|
||
+
|
||
+ <!-- 姝屾洸鍒楄〃鍐呭 -->
|
||
+ <div v-else-if="activeTab === 'songs'" key="songs" class="tab-pane">
|
||
+ <div class="song-list-container">
|
||
+ <SongsSongList
|
||
+ :error="error"
|
||
+ :is-admin="isAdmin"
|
||
+ :loading="loading"
|
||
+ :songs="filteredSongs"
|
||
+ @refresh="refreshSongs"
|
||
+ @vote="handleVote"
|
||
+ @withdraw="handleWithdraw"
|
||
+ @cancel-replay="handleCancelReplay"
|
||
+ @request-replay="handleRequestReplay"
|
||
+ @semester-change="handleSemesterChange"
|
||
+ />
|
||
+ </div>
|
||
+ </div>
|
||
+
|
||
+ <!-- 鎶曠姝屾洸鍐呭 -->
|
||
+ <div v-else-if="activeTab === 'request'" key="request" class="tab-pane request-pane">
|
||
+ <SongsRequestForm
|
||
+ ref="requestFormRef"
|
||
+ :loading="loading"
|
||
+ @request="handleRequest"
|
||
+ @vote="handleVote"
|
||
+ />
|
||
+ </div>
|
||
+
|
||
+ <!-- 閫氱煡鍐呭 -->
|
||
+ <div
|
||
+ v-else-if="activeTab === 'notification'"
|
||
+ key="notification"
|
||
+ class="tab-pane notification-pane"
|
||
+ >
|
||
+ <div v-if="!isClientAuthenticated" class="login-required-container">
|
||
+ <div class="login-required-content">
|
||
+ <Lock class="login-icon" :size="48" />
|
||
+ <h3>闇€瑕佺櫥褰?/h3>
|
||
+ <p>鎮ㄩ渶瑕佺櫥褰曟墠鑳芥煡鐪嬮€氱煡</p>
|
||
+ <button class="login-button" @click="navigateToLogin">绔嬪嵆鐧诲綍</button>
|
||
+ </div>
|
||
+ </div>
|
||
+ <div v-else class="notification-container">
|
||
+ <!-- 鏍囬鍜岃缃寜閽?-->
|
||
+ <div class="notification-header">
|
||
+ <h2 class="notification-title">閫氱煡涓績</h2>
|
||
+ <button class="settings-icon" @click="toggleNotificationSettings">
|
||
+ <svg
|
||
+ fill="none"
|
||
+ height="20"
|
||
+ stroke="currentColor"
|
||
+ stroke-linecap="round"
|
||
+ stroke-linejoin="round"
|
||
+ stroke-width="2"
|
||
+ viewBox="0 0 24 24"
|
||
+ width="20"
|
||
+ xmlns="http://www.w3.org/2000/svg"
|
||
+ >
|
||
+ <circle cx="12" cy="12" r="3" />
|
||
+ <path
|
||
+ d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"
|
||
+ />
|
||
+ </svg>
|
||
+ </button>
|
||
+ </div>
|
||
+
|
||
+ <!-- 閫氱煡鍒楄〃 -->
|
||
+ <div class="notification-list">
|
||
+ <div v-if="notificationsLoading" class="loading-indicator">
|
||
+ <div class="loading-spinner" />
|
||
+ <span>鍔犺浇涓?..</span>
|
||
+ </div>
|
||
+
|
||
+ <div v-else-if="userNotifications.length === 0" class="empty-notification">
|
||
+ <div class="empty-icon">
|
||
+ <Icon :size="48" color="#6b7280" name="bell" />
|
||
+ </div>
|
||
+ <p>鏆傛棤閫氱煡</p>
|
||
+ </div>
|
||
+
|
||
+ <Transition mode="out-in" name="notification-list-fade">
|
||
+ <div
|
||
+ v-if="userNotifications.length > 0"
|
||
+ :key="notificationsService.currentPage.value"
|
||
+ class="notification-items"
|
||
+ >
|
||
+ <div
|
||
+ v-for="(notification, index) in userNotifications"
|
||
+ :key="notification.id"
|
||
+ :class="{ unread: !notification.read }"
|
||
+ :style="{ '--animation-delay': index * 0.1 + 's' }"
|
||
+ class="notification-card"
|
||
+ @click="viewNotification(notification)"
|
||
+ >
|
||
+ <div class="notification-card-header">
|
||
+ <div class="notification-icon-type">
|
||
+ <Icon
|
||
+ v-if="notification.type === 'SONG_SELECTED'"
|
||
+ :size="20"
|
||
+ color="#4f46e5"
|
||
+ name="check"
|
||
+ />
|
||
+ <Icon
|
||
+ v-else-if="notification.type === 'SONG_PLAYED'"
|
||
+ :size="20"
|
||
+ color="#10b981"
|
||
+ name="play"
|
||
+ />
|
||
+ <Icon
|
||
+ v-else-if="notification.type === 'SONG_VOTED'"
|
||
+ :size="20"
|
||
+ color="#f59e0b"
|
||
+ name="thumbs-up"
|
||
+ />
|
||
+ <Icon
|
||
+ v-else-if="notification.type === 'SONG_REJECTED'"
|
||
+ :size="20"
|
||
+ color="#ef4444"
|
||
+ name="x-circle"
|
||
+ />
|
||
+ <Icon
|
||
+ v-else-if="notification.type === 'COLLABORATION_INVITE'"
|
||
+ :size="20"
|
||
+ color="#0B5AFE"
|
||
+ name="users"
|
||
+ />
|
||
+ <Icon
|
||
+ v-else-if="notification.type === 'COLLABORATION_RESPONSE'"
|
||
+ :size="20"
|
||
+ color="#8b5cf6"
|
||
+ name="message-circle"
|
||
+ />
|
||
+ <Icon v-else :size="20" color="#6b7280" name="bell" />
|
||
+ </div>
|
||
+ <div class="notification-title-row">
|
||
+ <div class="notification-title">
|
||
+ <span v-if="notification.type === 'SONG_SELECTED'">姝屾洸宸查€変腑</span>
|
||
+ <span v-else-if="notification.type === 'SONG_PLAYED'"
|
||
+ >姝屾洸宸叉挱鏀?/span
|
||
+ >
|
||
+ <span v-else-if="notification.type === 'SONG_VOTED'">鏀跺埌鏂版姇绁?/span>
|
||
+ <span v-else-if="notification.type === 'SONG_REJECTED'"
|
||
+ >姝屾洸琚┏鍥?/span
|
||
+ >
|
||
+ <span v-else-if="notification.type === 'COLLABORATION_INVITE'">
|
||
+ 鑱斿悎鎶曠閭€璇? <span
|
||
+ v-if="notification.handled"
|
||
+ :class="[
|
||
+ 'status-tag',
|
||
+ notification.status === 'ACCEPTED'
|
||
+ ? 'accepted'
|
||
+ : notification.status === 'INVALID'
|
||
+ ? 'invalid'
|
||
+ : 'rejected'
|
||
+ ]"
|
||
+ >
|
||
+ {{
|
||
+ notification.status === 'ACCEPTED'
|
||
+ ? '- 宸叉帴鍙?
|
||
+ : notification.status === 'INVALID'
|
||
+ ? '- 宸插け鏁?
|
||
+ : '- 宸叉嫆缁?
|
||
+ }}
|
||
+ </span>
|
||
+ </span>
|
||
+ <span v-else-if="notification.type === 'COLLABORATION_RESPONSE'"
|
||
+ >鑱斿悎鎶曠鍥炲</span
|
||
+ >
|
||
+ <span v-else>绯荤粺閫氱煡</span>
|
||
+ <span v-if="!notification.read" class="unread-indicator" />
|
||
+ </div>
|
||
+ <div class="notification-time">
|
||
+ {{ formatNotificationTime(notification.createdAt) }}
|
||
+ </div>
|
||
+ </div>
|
||
+ </div>
|
||
+ <div class="notification-card-body">
|
||
+ <div class="notification-text">{{ notification.message }}</div>
|
||
+
|
||
+ <!-- 鑱斿悎鎶曠閭€璇锋搷浣滄寜閽?-->
|
||
+ <div
|
||
+ v-if="
|
||
+ notification.type === 'COLLABORATION_INVITE' && !notification.handled
|
||
+ "
|
||
+ class="invite-actions"
|
||
+ >
|
||
+ <button
|
||
+ :disabled="notification.processing"
|
||
+ class="action-button accept-btn"
|
||
+ @click.stop="handleCollaborationReply(notification, true)"
|
||
+ >
|
||
+ {{ notification.processing ? '澶勭悊涓?..' : '鎺ュ彈閭€璇? }}
|
||
+ </button>
|
||
+ <button
|
||
+ :disabled="notification.processing"
|
||
+ class="action-button reject-btn"
|
||
+ @click.stop="handleCollaborationReply(notification, false)"
|
||
+ >
|
||
+ 鎷掔粷
|
||
+ </button>
|
||
+ </div>
|
||
+ </div>
|
||
+ <div class="notification-card-actions">
|
||
+ <button
|
||
+ class="action-button delete"
|
||
+ title="鍒犻櫎"
|
||
+ @click.stop="deleteNotification(notification.id)"
|
||
+ >
|
||
+ <svg
|
||
+ fill="none"
|
||
+ height="16"
|
||
+ stroke="currentColor"
|
||
+ stroke-linecap="round"
|
||
+ stroke-linejoin="round"
|
||
+ stroke-width="2"
|
||
+ viewBox="0 0 24 24"
|
||
+ width="16"
|
||
+ xmlns="http://www.w3.org/2000/svg"
|
||
+ >
|
||
+ <polyline points="3 6 5 6 21 6" />
|
||
+ <path
|
||
+ d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"
|
||
+ />
|
||
+ </svg>
|
||
+ <span>鍒犻櫎</span>
|
||
+ </button>
|
||
+ </div>
|
||
+ </div>
|
||
+ </div>
|
||
+ </Transition>
|
||
+ </div>
|
||
+
|
||
+ <!-- 鍒嗛〉鎺т欢 -->
|
||
+ <div
|
||
+ v-if="notificationsService.totalCount.value > 0"
|
||
+ class="notification-pagination"
|
||
+ >
|
||
+ <div class="pagination-info">
|
||
+ <span class="pagination-text">
|
||
+ 鍏?{{ notificationsService.totalCount.value }} 鏉¢€氱煡锛?绗? {{ notificationsService.currentPage.value }} /
|
||
+ {{ notificationsService.totalPages.value }} 椤? </span>
|
||
+ </div>
|
||
+
|
||
+ <div class="pagination-controls">
|
||
+ <!-- 姣忛〉鏄剧ず鏁伴噺閫夋嫨鍣?-->
|
||
+ <div class="page-size-selector">
|
||
+ <label for="pageSize">姣忛〉鏄剧ず锛?/label>
|
||
+ <CustomSelect
|
||
+ id="pageSize"
|
||
+ :model-value="notificationsService.pageSize.value"
|
||
+ :options="pageSizeOptions"
|
||
+ class="page-size-custom-select"
|
||
+ @update:model-value="handlePageSizeChange"
|
||
+ />
|
||
+ </div>
|
||
+
|
||
+ <!-- 椤电爜瀵艰埅 -->
|
||
+ <div class="page-navigation">
|
||
+ <button
|
||
+ :disabled="
|
||
+ !notificationsService.hasPrevPage.value ||
|
||
+ notificationsService.isPaginationLoading.value
|
||
+ "
|
||
+ class="page-nav-button"
|
||
+ title="涓婁竴椤?
|
||
+ @click="notificationsService.prevPage()"
|
||
+ >
|
||
+ <svg
|
||
+ fill="none"
|
||
+ height="16"
|
||
+ stroke="currentColor"
|
||
+ stroke-linecap="round"
|
||
+ stroke-linejoin="round"
|
||
+ stroke-width="2"
|
||
+ viewBox="0 0 24 24"
|
||
+ width="16"
|
||
+ xmlns="http://www.w3.org/2000/svg"
|
||
+ >
|
||
+ <polyline points="15 18 9 12 15 6" />
|
||
+ </svg>
|
||
+ </button>
|
||
+
|
||
+ <!-- 椤电爜鎸夐挳 -->
|
||
+ <div class="page-numbers">
|
||
+ <template v-for="page in getVisiblePages()" :key="page">
|
||
+ <button
|
||
+ v-if="page !== '...'"
|
||
+ :class="[
|
||
+ 'page-number-button',
|
||
+ { active: page === notificationsService.currentPage.value }
|
||
+ ]"
|
||
+ :disabled="notificationsService.isPaginationLoading.value"
|
||
+ @click="notificationsService.goToPage(page)"
|
||
+ >
|
||
+ {{ page }}
|
||
+ </button>
|
||
+ <span v-else class="page-ellipsis">...</span>
|
||
+ </template>
|
||
+ </div>
|
||
+
|
||
+ <button
|
||
+ :disabled="
|
||
+ !notificationsService.hasNextPage.value ||
|
||
+ notificationsService.isPaginationLoading.value
|
||
+ "
|
||
+ class="page-nav-button"
|
||
+ title="涓嬩竴椤?
|
||
+ @click="notificationsService.nextPage()"
|
||
+ >
|
||
+ <svg
|
||
+ fill="none"
|
||
+ height="16"
|
||
+ stroke="currentColor"
|
||
+ stroke-linecap="round"
|
||
+ stroke-linejoin="round"
|
||
+ stroke-width="2"
|
||
+ viewBox="0 0 24 24"
|
||
+ width="16"
|
||
+ xmlns="http://www.w3.org/2000/svg"
|
||
+ >
|
||
+ <polyline points="9 18 15 12 9 6" />
|
||
+ </svg>
|
||
+ </button>
|
||
+ </div>
|
||
+ </div>
|
||
+
|
||
+ <!-- 鍒嗛〉鍔犺浇鐘舵€?-->
|
||
+ <div
|
||
+ v-if="notificationsService.isPaginationLoading.value"
|
||
+ class="pagination-loading"
|
||
+ >
|
||
+ <div class="loading-spinner" />
|
||
+ <span>鍔犺浇涓?..</span>
|
||
+ </div>
|
||
+ </div>
|
||
+
|
||
+ <!-- 搴曢儴鎿嶄綔鎸夐挳 -->
|
||
+ <div v-if="userNotifications.length > 0" class="notification-actions-bar">
|
||
+ <button
|
||
+ :class="{ disabled: !hasUnreadNotifications }"
|
||
+ :disabled="!hasUnreadNotifications"
|
||
+ class="action-button-large"
|
||
+ @click="markAllNotificationsAsRead"
|
||
+ >
|
||
+ 鍏ㄩ儴鏍囪涓哄凡璇? </button>
|
||
+ <button class="action-button-large danger" @click="clearAllNotifications">
|
||
+ 娓呯┖鎵€鏈夋秷鎭? </button>
|
||
+ </div>
|
||
+
|
||
+ <!-- 纭瀵硅瘽妗?-->
|
||
+ <ConfirmDialog
|
||
+ v-model:show="showConfirmDialog"
|
||
+ :cancel-text="confirmDialogConfig.cancelText"
|
||
+ :confirm-text="confirmDialogConfig.confirmText"
|
||
+ :message="confirmDialogConfig.message"
|
||
+ :title="confirmDialogConfig.title"
|
||
+ :type="confirmDialogConfig.type"
|
||
+ @cancel="handleCancelAction"
|
||
+ @confirm="handleConfirmAction"
|
||
+ />
|
||
+ </div>
|
||
+ </div>
|
||
+ </ClientOnly>
|
||
+ </div>
|
||
+ </div>
|
||
+
|
||
+ <!-- 椤佃剼淇℃伅鏄剧ず -->
|
||
+ <SiteFooter />
|
||
+ </div>
|
||
+
|
||
+ <!-- 瑙勫垯寮圭獥 -->
|
||
+ <Teleport to="body">
|
||
+ <Transition
|
||
+ enter-active-class="transition duration-300 ease-out"
|
||
+ enter-from-class="opacity-0 scale-95"
|
||
+ enter-to-class="opacity-100 scale-100"
|
||
+ leave-active-class="transition duration-200 ease-in"
|
||
+ leave-from-class="opacity-100 scale-100"
|
||
+ leave-to-class="opacity-0 scale-95"
|
||
+ >
|
||
+ <div
|
||
+ v-if="showRules"
|
||
+ class="fixed inset-0 z-[70] flex items-center justify-center p-4 bg-black/80 backdrop-blur-sm"
|
||
+ @click.self="showRules = false"
|
||
+ >
|
||
+ <div
|
||
+ class="bg-zinc-900 border border-zinc-800 w-full max-w-lg rounded-3xl overflow-hidden shadow-2xl flex flex-col"
|
||
+ >
|
||
+ <div class="p-8 pb-4 flex items-center justify-between">
|
||
+ <div>
|
||
+ <h3 class="text-xl font-black text-zinc-100 tracking-tight flex items-center gap-3">
|
||
+ <div
|
||
+ class="w-10 h-10 rounded-2xl bg-blue-600/10 flex items-center justify-center text-blue-500"
|
||
+ >
|
||
+ <Icon name="bell" :size="20" />
|
||
+ </div>
|
||
+ 鐐规瓕瑙勫垯
|
||
+ </h3>
|
||
+ <p class="text-xs text-zinc-500 mt-1 ml-13">鎶曠鍓嶈浠旂粏闃呰浠ヤ笅瑙勫垯</p>
|
||
+ </div>
|
||
+ <button
|
||
+ class="p-3 bg-zinc-800/50 hover:bg-zinc-800 text-zinc-500 hover:text-zinc-200 rounded-2xl transition-all"
|
||
+ @click="showRules = false"
|
||
+ >
|
||
+ <Icon name="x" :size="20" />
|
||
+ </button>
|
||
+ </div>
|
||
+
|
||
+ <div class="p-8 pt-4 space-y-8">
|
||
+ <div class="rules-group space-y-4">
|
||
+ <h4
|
||
+ class="text-[10px] font-black text-zinc-500 uppercase tracking-widest flex items-center gap-2"
|
||
+ >
|
||
+ <Icon name="message-circle" :size="12" />
|
||
+ 鎶曠椤荤煡
|
||
+ </h4>
|
||
+ <div
|
||
+ v-if="submissionGuidelines"
|
||
+ class="text-sm text-zinc-400 leading-relaxed font-medium bg-zinc-950/50 p-6 rounded-3xl border border-zinc-800/50"
|
||
+ v-html="submissionGuidelines.replace(/\n/g, '<br>')"
|
||
+ />
|
||
+ <div
|
||
+ v-else
|
||
+ class="space-y-3 bg-zinc-950/50 p-6 rounded-3xl border border-zinc-800/50"
|
||
+ >
|
||
+ <div class="flex gap-3 text-sm text-zinc-400 font-medium">
|
||
+ <span class="text-blue-500 font-black">01</span>
|
||
+ <p>鎶曠鏃舵棤闇€鍔犲叆涔﹀悕鍙?/p>
|
||
+ </div>
|
||
+ <div class="flex gap-3 text-sm text-zinc-400 font-medium">
|
||
+ <span class="text-blue-500 font-black">02</span>
|
||
+ <p>闄J澶栵紝鍏朵粬绫诲瀷姝屾洸鍧囨帴鏀讹紙鍖呮嫭灏忚绉嶏級</p>
|
||
+ </div>
|
||
+ <div class="flex gap-3 text-sm text-zinc-400 font-medium">
|
||
+ <span class="text-blue-500 font-black">03</span>
|
||
+ <p>绂佹鎶曢€掑惈鏈夎繚瑙勫唴瀹圭殑姝屾洸</p>
|
||
+ </div>
|
||
+ </div>
|
||
+ </div>
|
||
+
|
||
+ <div class="rules-group space-y-4">
|
||
+ <h4
|
||
+ class="text-[10px] font-black text-zinc-500 uppercase tracking-widest flex items-center gap-2"
|
||
+ >
|
||
+ <Icon name="calendar" :size="12" />
|
||
+ 鎾斁鏃堕棿
|
||
+ </h4>
|
||
+ <div
|
||
+ class="bg-blue-600/10 border border-blue-500/20 p-6 rounded-3xl flex items-center gap-4"
|
||
+ >
|
||
+ <div
|
||
+ class="w-12 h-12 rounded-2xl bg-blue-600 flex items-center justify-center text-white shadow-lg shadow-blue-900/40"
|
||
+ >
|
||
+ <Icon name="clock" :size="24" />
|
||
+ </div>
|
||
+ <div>
|
||
+ <p class="text-sm font-black text-zinc-100">姣忓ぉ澶滆嚜淇潤鐝墠</p>
|
||
+ <p class="text-[10px] text-zinc-500 font-bold uppercase tracking-widest mt-0.5">
|
||
+ PLAYBACK TIME
|
||
+ </p>
|
||
+ </div>
|
||
+ </div>
|
||
+ </div>
|
||
+ </div>
|
||
+
|
||
+ <div class="p-8 pt-0">
|
||
+ <button
|
||
+ class="w-full px-6 py-4 bg-zinc-800 hover:bg-zinc-700 text-zinc-300 text-xs font-black rounded-2xl transition-all uppercase tracking-widest shadow-lg active:scale-95"
|
||
+ @click="showRules = false"
|
||
+ >
|
||
+ 鎴戠煡閬撲簡
|
||
+ </button>
|
||
+ </div>
|
||
+ </div>
|
||
+ </div>
|
||
+ </Transition>
|
||
+ </Teleport>
|
||
+
|
||
+ <div
|
||
+ v-if="statisticsCodeEnabled && statisticsCode"
|
||
+ id="site-statistics-code"
|
||
+ class="hidden"
|
||
+ v-html="statisticsCode"
|
||
+ />
|
||
+ </div>
|
||
+</template>
|
||
+
|
||
+<script setup>
|
||
+import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
|
||
+import { Lock } from '@lucide/vue'
|
||
+import { useRouter } from 'vue-router'
|
||
+
|
||
+import logo from '~~/public/images/logo.png'
|
||
+import Icon from '~/components/UI/Icon.vue'
|
||
+import ConfirmDialog from '~/components/UI/ConfirmDialog.vue'
|
||
+
|
||
+import { useNotifications } from '~/composables/useNotifications'
|
||
+import { useSiteConfig } from '~/composables/useSiteConfig'
|
||
+import { useTheme } from '~/composables/useTheme'
|
||
+import CustomSelect from '~/components/UI/Common/CustomSelect.vue'
|
||
+
|
||
+// 鑾峰彇杩愯鏃堕厤缃?const config = useRuntimeConfig()
|
||
+const router = useRouter()
|
||
+
|
||
+// 涓婚
|
||
+const { isDark, toggleTheme } = useTheme()
|
||
+const handleToggleTheme = () => {
|
||
+ toggleTheme()
|
||
+}
|
||
+const handleLanguageClick = () => {
|
||
+ if (typeof window !== 'undefined' && window.$showNotification) {
|
||
+ window.$showNotification('褰撳墠鐗堟湰鏆備笉鏀寔澶氳瑷€鍒囨崲', 'info')
|
||
+ }
|
||
+}
|
||
+
|
||
+// 绔欑偣閰嶇疆
|
||
+const {
|
||
+ siteTitle,
|
||
+ description: siteDescription,
|
||
+ guidelines: submissionGuidelines,
|
||
+ icp: icpNumber,
|
||
+ schoolLogoHomeUrl,
|
||
+ statisticsCode,
|
||
+ statisticsCodeEnabled,
|
||
+ initSiteConfig
|
||
+} = useSiteConfig()
|
||
+
|
||
+const auth = useAuth()
|
||
+
|
||
+const isClientAuthenticated = computed(() => auth?.isAuthenticated?.value || false)
|
||
+const isAdmin = computed(() => auth?.isAdmin?.value || false)
|
||
+const user = computed(() => auth?.user?.value || null)
|
||
+
|
||
+const roleName = computed(() => {
|
||
+ const role = user.value?.role
|
||
+ const map = {
|
||
+ ADMIN: '閮ㄩ暱',
|
||
+ SUPER_ADMIN: '鎶€鏈繍缁?,
|
||
+ SONG_ADMIN: '宸ヤ綔浜哄憳',
|
||
+ VICE_MINISTER: '鍓儴',
|
||
+ RESIDENT: '甯搁┗',
|
||
+ TEACHER: '鏁欏笀',
|
||
+ USER: '瀛︾敓锛堟櫘閫氱敤鎴凤級'
|
||
+ }
|
||
+ return map[role] || '绠$悊鍛?
|
||
+})
|
||
+
|
||
+const userClassInfo = computed(() => {
|
||
+ if (user.value?.grade && user.value?.class) {
|
||
+ return `${user.value.grade} ${user.value.class}`
|
||
+ }
|
||
+ return '鍚屽'
|
||
+})
|
||
+
|
||
+const songs = useSongs()
|
||
+// 绔嬪嵆鍒濆鍖栭€氱煡鏈嶅姟锛岄伩鍏嶆椂搴忛棶棰?const notificationsService = useNotifications()
|
||
+const unreadNotificationCount = ref(0)
|
||
+
|
||
+// 妯℃嫙鏁版嵁鍒濆鍊?const songCount = ref(0)
|
||
+const scheduleCount = ref(0)
|
||
+const isRequestOpen = ref(true)
|
||
+
|
||
+// 寮圭獥鐘舵€?const showRequestModal = ref(false)
|
||
+const showRules = ref(false)
|
||
+const showUserActions = ref(false)
|
||
+const avatarError = ref(false)
|
||
+
|
||
+const toggleUserActions = (event) => {
|
||
+ event.stopPropagation()
|
||
+ showUserActions.value = !showUserActions.value
|
||
+}
|
||
+
|
||
+// 鐩戝惉鐢ㄦ埛澶村儚鍙樺寲锛岄噸缃敊璇姸鎬?watch(
|
||
+ () => user.value?.avatar,
|
||
+ () => {
|
||
+ avatarError.value = false
|
||
+ }
|
||
+)
|
||
+
|
||
+// 鐐瑰嚮澶栭儴鍏抽棴涓嬫媺鑿滃崟
|
||
+const handleClickOutside = (event) => {
|
||
+ if (showUserActions.value) {
|
||
+ const dropdown = document.querySelector('.user-actions-dropdown')
|
||
+ const avatar = document.querySelector('.user-avatar-wrapper')
|
||
+ if (dropdown && !dropdown.contains(event.target) && !avatar.contains(event.target)) {
|
||
+ showUserActions.value = false
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+onMounted(() => {
|
||
+ window.addEventListener('click', handleClickOutside)
|
||
+})
|
||
+
|
||
+onUnmounted(() => {
|
||
+ window.removeEventListener('click', handleClickOutside)
|
||
+})
|
||
+
|
||
+// 鏍囩椤电姸鎬?const activeTab = ref('schedule') // 榛樿鏄剧ず鎾嚭鎺掓湡
|
||
+
|
||
+const tabOrder = ['schedule', 'songs', 'request', 'notification']
|
||
+const activeIndex = computed(() => {
|
||
+ const index = tabOrder.indexOf(activeTab.value)
|
||
+ return index === -1 ? 0 : index
|
||
+})
|
||
+
|
||
+// 閫氱煡鎸夐挳寮哄埗鏇存柊鐩稿叧
|
||
+const notificationTabRef = ref(null)
|
||
+const hasInitializedAuthData = ref(isClientAuthenticated.value)
|
||
+
|
||
+let refreshInterval = null
|
||
+let lastDataRevision = ''
|
||
+
|
||
+const fetchDataRevision = async () => {
|
||
+ try {
|
||
+ const url = isClientAuthenticated.value ? '/api/songs/revision' : '/api/songs/public-revision'
|
||
+ const authConfig = isClientAuthenticated.value ? auth.getAuthConfig() : {}
|
||
+ const result = await $fetch(url, {
|
||
+ ...authConfig,
|
||
+ query: { t: Date.now() }
|
||
+ })
|
||
+ return result?.revision || ''
|
||
+ } catch (e) {
|
||
+ console.error('鑾峰彇鏁版嵁淇鍙峰け璐?', e)
|
||
+ return ''
|
||
+ }
|
||
+}
|
||
+
|
||
+const setupRefreshInterval = async () => {
|
||
+ if (refreshInterval) {
|
||
+ clearInterval(refreshInterval)
|
||
+ }
|
||
+
|
||
+ const intervalSeconds = Math.max(5, Math.min(30, notificationSettings.value.refreshInterval || 10))
|
||
+ const intervalMs = intervalSeconds * 1000
|
||
+
|
||
+ lastDataRevision = await fetchDataRevision()
|
||
+
|
||
+ refreshInterval = setInterval(async () => {
|
||
+ try {
|
||
+ const nextRevision = await fetchDataRevision()
|
||
+ if (!nextRevision || nextRevision === lastDataRevision) return
|
||
+ lastDataRevision = nextRevision
|
||
+
|
||
+ if (isClientAuthenticated.value) {
|
||
+ await Promise.allSettled([
|
||
+ songs.fetchSongs(false, undefined, true, true),
|
||
+ songs.fetchPublicSchedules(false, undefined, true, true),
|
||
+ loadNotifications()
|
||
+ ])
|
||
+ } else {
|
||
+ await Promise.allSettled([songs.fetchPublicSchedules(false, undefined, true, true), songs.fetchSongCount()])
|
||
+ }
|
||
+
|
||
+ await updateSongCounts()
|
||
+ } catch (error) {
|
||
+ console.error('瀹氭湡鍒锋柊澶辫触:', error)
|
||
+ }
|
||
+ }, intervalMs)
|
||
+}
|
||
+
|
||
+// 娣诲姞閫氱煡鐩稿叧鍙橀噺
|
||
+const userNotifications = computed(() => notificationsService?.notifications?.value || [])
|
||
+const notificationsLoading = computed(() => notificationsService?.loading?.value || false)
|
||
+const hasUnreadNotifications = computed(() => {
|
||
+ // 纭繚notificationsService宸插垵濮嬪寲涓旀湁unreadCount
|
||
+ if (!notificationsService || !notificationsService.unreadCount) {
|
||
+ return false
|
||
+ }
|
||
+ const unreadCount = notificationsService.unreadCount.value
|
||
+ return unreadCount > 0
|
||
+})
|
||
+const showNotificationSettings = ref(false)
|
||
+
|
||
+const pageSizeOptions = [
|
||
+ { label: '5鏉?, value: 5 },
|
||
+ { label: '10鏉?, value: 10 },
|
||
+ { label: '20鏉?, value: 20 },
|
||
+ { label: '50鏉?, value: 50 }
|
||
+]
|
||
+
|
||
+const notificationSettings = ref({
|
||
+ songSelectedNotify: true,
|
||
+ songPlayedNotify: true,
|
||
+ songVotedNotify: true,
|
||
+ songVotedThreshold: 1,
|
||
+ systemNotify: true,
|
||
+ refreshInterval: 60
|
||
+})
|
||
+
|
||
+// 璺宠浆鍒伴€氱煡璁剧疆椤甸潰
|
||
+const toggleNotificationSettings = () => {
|
||
+ navigateTo('/notification-settings')
|
||
+}
|
||
+
|
||
+// 鑾峰彇閫氱煡璁剧疆
|
||
+const fetchNotificationSettings = async () => {
|
||
+ if (notificationsService) {
|
||
+ await notificationsService.fetchNotificationSettings()
|
||
+ if (notificationsService.settings.value) {
|
||
+ notificationSettings.value = {
|
||
+ songSelectedNotify: notificationsService.settings.value.songSelectedNotify,
|
||
+ songPlayedNotify: notificationsService.settings.value.songPlayedNotify,
|
||
+ songVotedNotify: notificationsService.settings.value.songVotedNotify,
|
||
+ songVotedThreshold: notificationsService.settings.value.songVotedThreshold || 1,
|
||
+ systemNotify: notificationsService.settings.value.systemNotify,
|
||
+ refreshInterval: notificationsService.settings.value.refreshInterval || 60
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+// 淇濆瓨閫氱煡璁剧疆
|
||
+const saveNotificationSettings = async () => {
|
||
+ if (notificationsService) {
|
||
+ await notificationsService.updateNotificationSettings(notificationSettings.value)
|
||
+
|
||
+ // 濡傛灉鍦ㄩ椤碉紝鏇存柊鍒锋柊闂撮殧
|
||
+ if (typeof setupRefreshInterval === 'function') {
|
||
+ setupRefreshInterval()
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+// 鍔犺浇閫氱煡
|
||
+const loadNotifications = async () => {
|
||
+ if (isClientAuthenticated.value && notificationsService) {
|
||
+ try {
|
||
+ await notificationsService.fetchNotifications()
|
||
+ } catch (error) {
|
||
+ console.error('[閫氱煡鑾峰彇] 鍔犺浇閫氱煡澶辫触:', error)
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+// 鏍囪閫氱煡涓哄凡璇?const markNotificationAsRead = async (id) => {
|
||
+ if (notificationsService) {
|
||
+ await notificationsService.markAsRead(id)
|
||
+ }
|
||
+}
|
||
+
|
||
+// 鏍囪鎵€鏈夐€氱煡涓哄凡璇?const markAllNotificationsAsRead = async () => {
|
||
+ try {
|
||
+ if (notificationsService) {
|
||
+ await notificationsService.markAllAsRead()
|
||
+ }
|
||
+ } catch (error) {
|
||
+ console.error('[閫氱煡鎿嶄綔] 鏍囪鎵€鏈夐€氱煡涓哄凡璇诲け璐?', error)
|
||
+ }
|
||
+}
|
||
+
|
||
+// 鍒犻櫎閫氱煡
|
||
+const deleteNotification = async (id) => {
|
||
+ pendingAction.value = 'delete'
|
||
+ pendingId.value = id
|
||
+ confirmDialogConfig.value = {
|
||
+ title: '鍒犻櫎娑堟伅',
|
||
+ message: '纭畾瑕佸垹闄ゆ娑堟伅鍚楋紵',
|
||
+ type: 'warning',
|
||
+ confirmText: '鍒犻櫎',
|
||
+ cancelText: '鍙栨秷'
|
||
+ }
|
||
+ showConfirmDialog.value = true
|
||
+}
|
||
+
|
||
+// 娓呯┖鎵€鏈夐€氱煡
|
||
+const clearAllNotifications = async () => {
|
||
+ pendingAction.value = 'clearAll'
|
||
+ confirmDialogConfig.value = {
|
||
+ title: '娓呯┖鎵€鏈夋秷鎭?,
|
||
+ message: '纭畾瑕佹竻绌烘墍鏈夋秷鎭悧锛熸鎿嶄綔涓嶅彲鎾ら攢銆?,
|
||
+ type: 'danger',
|
||
+ confirmText: '娓呯┖',
|
||
+ cancelText: '鍙栨秷'
|
||
+ }
|
||
+ showConfirmDialog.value = true
|
||
+}
|
||
+
|
||
+// 纭瀵硅瘽妗嗙浉鍏崇姸鎬?const showConfirmDialog = ref(false)
|
||
+const confirmDialogConfig = ref({
|
||
+ title: '',
|
||
+ message: '',
|
||
+ type: 'warning',
|
||
+ confirmText: '纭畾',
|
||
+ cancelText: '鍙栨秷'
|
||
+})
|
||
+const pendingAction = ref('')
|
||
+const pendingId = ref(null)
|
||
+
|
||
+// 澶勭悊纭鎿嶄綔
|
||
+const handleConfirmAction = async () => {
|
||
+ if (notificationsService) {
|
||
+ if (pendingAction.value === 'delete') {
|
||
+ await notificationsService.deleteNotification(pendingId.value)
|
||
+ pendingId.value = null
|
||
+ } else if (pendingAction.value === 'clearAll') {
|
||
+ await notificationsService.clearAllNotifications()
|
||
+ }
|
||
+ }
|
||
+ showConfirmDialog.value = false
|
||
+ pendingAction.value = ''
|
||
+}
|
||
+
|
||
+// 澶勭悊鍙栨秷鎿嶄綔
|
||
+const handleCancelAction = () => {
|
||
+ showConfirmDialog.value = false
|
||
+ pendingAction.value = ''
|
||
+ pendingId.value = null
|
||
+}
|
||
+
|
||
+// 鍒嗛〉鐩稿叧鏂规硶
|
||
+const handlePageSizeChange = async (newSize) => {
|
||
+ const size = parseInt(newSize)
|
||
+ if (notificationsService) {
|
||
+ await notificationsService.changePageSize(size)
|
||
+ }
|
||
+}
|
||
+
|
||
+// 鑾峰彇鍙鐨勯〉鐮佸垪琛?const getVisiblePages = () => {
|
||
+ if (!notificationsService) return []
|
||
+
|
||
+ const currentPage = notificationsService.currentPage.value
|
||
+ const totalPages = notificationsService.totalPages.value
|
||
+ const pages = []
|
||
+
|
||
+ if (totalPages <= 7) {
|
||
+ // 鎬婚〉鏁板皯浜庣瓑浜?椤碉紝鏄剧ず鎵€鏈夐〉鐮? for (let i = 1; i <= totalPages; i++) {
|
||
+ pages.push(i)
|
||
+ }
|
||
+ } else {
|
||
+ // 鎬婚〉鏁板ぇ浜?椤碉紝鏄剧ず鐪佺暐鍙? if (currentPage <= 4) {
|
||
+ // 褰撳墠椤靛湪鍓嶉潰
|
||
+ for (let i = 1; i <= 5; i++) {
|
||
+ pages.push(i)
|
||
+ }
|
||
+ pages.push('...')
|
||
+ pages.push(totalPages)
|
||
+ } else if (currentPage >= totalPages - 3) {
|
||
+ // 褰撳墠椤靛湪鍚庨潰
|
||
+ pages.push(1)
|
||
+ pages.push('...')
|
||
+ for (let i = totalPages - 4; i <= totalPages; i++) {
|
||
+ pages.push(i)
|
||
+ }
|
||
+ } else {
|
||
+ // 褰撳墠椤靛湪涓棿
|
||
+ pages.push(1)
|
||
+ pages.push('...')
|
||
+ for (let i = currentPage - 1; i <= currentPage + 1; i++) {
|
||
+ pages.push(i)
|
||
+ }
|
||
+ pages.push('...')
|
||
+ pages.push(totalPages)
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return pages
|
||
+}
|
||
+
|
||
+// 鏍煎紡鍖栭€氱煡鏃堕棿
|
||
+const formatNotificationTime = (timeString) => {
|
||
+ const date = new Date(timeString)
|
||
+ const now = new Date()
|
||
+ const diff = now.getTime() - date.getTime()
|
||
+
|
||
+ // 灏忎簬1鍒嗛挓
|
||
+ if (diff < 60000) {
|
||
+ return '鍒氬垰'
|
||
+ }
|
||
+
|
||
+ // 灏忎簬1灏忔椂
|
||
+ if (diff < 3600000) {
|
||
+ return `${Math.floor(diff / 60000)}鍒嗛挓鍓峘
|
||
+ }
|
||
+
|
||
+ // 灏忎簬24灏忔椂
|
||
+ if (diff < 86400000) {
|
||
+ return `${Math.floor(diff / 3600000)}灏忔椂鍓峘
|
||
+ }
|
||
+
|
||
+ // 灏忎簬30澶? if (diff < 2592000000) {
|
||
+ return `${Math.floor(diff / 86400000)}澶╁墠`
|
||
+ }
|
||
+
|
||
+ // 澶т簬30澶╋紝鏄剧ず鍏蜂綋鏃ユ湡
|
||
+ return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`
|
||
+}
|
||
+
|
||
+// 鐩戝惉鏍囩椤靛垏鎹紝濡傛灉鍒囨崲鍒伴€氱煡鏍囩椤碉紝鍔犺浇閫氱煡
|
||
+watch(activeTab, (newTab) => {
|
||
+ if (newTab === 'notification') {
|
||
+ loadNotifications()
|
||
+ }
|
||
+})
|
||
+
|
||
+watch(
|
||
+ () => auth?.isAuthenticated?.value,
|
||
+ async (newAuthState, oldAuthState) => {
|
||
+ if (newAuthState && !oldAuthState) {
|
||
+ hasInitializedAuthData.value = true
|
||
+ await Promise.allSettled([loadNotifications(), fetchNotificationSettings(), songs.fetchSongs()])
|
||
+ await updateSongCounts()
|
||
+ return
|
||
+ }
|
||
+
|
||
+ if (!newAuthState && oldAuthState) {
|
||
+ hasInitializedAuthData.value = false
|
||
+ await Promise.allSettled([songs.fetchSongCount(), songs.fetchPublicSchedules()])
|
||
+ unreadNotificationCount.value = 0
|
||
+ await updateSongCounts()
|
||
+ }
|
||
+ },
|
||
+ { flush: 'post' }
|
||
+)
|
||
+
|
||
+// 鍒濆鍖栨椂濡傛灉宸茬粡鍦ㄩ€氱煡鏍囩椤碉紝鍒欏姞杞介€氱煡
|
||
+onMounted(() => {
|
||
+ if (activeTab.value === 'notification') {
|
||
+ loadNotifications()
|
||
+ }
|
||
+})
|
||
+
|
||
+// 鑾峰彇褰撳墠鏃ユ湡鍜屾槦鏈?const getCurrentDate = () => {
|
||
+ const now = new Date()
|
||
+ const year = now.getFullYear()
|
||
+ const month = now.getMonth() + 1
|
||
+ const date = now.getDate()
|
||
+ const weekDays = ['鏃?, '涓€', '浜?, '涓?, '鍥?, '浜?, '鍏?]
|
||
+ const weekDay = weekDays[now.getDay()]
|
||
+
|
||
+ return `${year}骞?{month}鏈?{date}鏃?鍛?{weekDay}`
|
||
+}
|
||
+
|
||
+// RequestForm缁勪欢寮曠敤
|
||
+const requestFormRef = ref(null)
|
||
+
|
||
+// 鏃х殑showNotification鍑芥暟宸茬Щ闄わ紝浣跨敤鍏ㄥ眬閫氱煡绯荤粺
|
||
+
|
||
+// 鏇存柊姝屾洸鏁伴噺缁熻锛堜紭鍖栫増鏈紝閬垮厤閲嶅璇锋眰锛?const updateSongCounts = async (semester = null) => {
|
||
+ try {
|
||
+ // 鏇存柊鎺掓湡姝屾洸鏁伴噺
|
||
+ const schedules = songs?.publicSchedules?.value || []
|
||
+ scheduleCount.value = schedules.length
|
||
+
|
||
+ // 鏇存柊鎬绘瓕鏇叉暟閲? if (isClientAuthenticated.value && songs?.songs?.value) {
|
||
+ // 宸茬櫥褰曠敤鎴凤細浣跨敤瀹屾暣姝屾洸鍒楄〃
|
||
+ songCount.value = songs.songs.value.length
|
||
+ } else {
|
||
+ // 鏈櫥褰曠敤鎴凤細浣跨敤缂撳瓨鐨勬瓕鏇叉€绘暟
|
||
+ songCount.value = songs?.songCount?.value || 0
|
||
+ }
|
||
+ } catch (e) {
|
||
+ console.error('鏇存柊姝屾洸缁熻澶辫触', e)
|
||
+ }
|
||
+}
|
||
+
|
||
+// 鐩戝惉siteTitle鍙樺寲锛岀‘淇濋椤祎itle姝g‘璁剧疆
|
||
+watch(
|
||
+ siteTitle,
|
||
+ (newSiteTitle) => {
|
||
+ if (typeof document !== 'undefined' && newSiteTitle) {
|
||
+ document.title = `棣栭〉 | ${newSiteTitle}`
|
||
+ }
|
||
+ },
|
||
+ { immediate: true }
|
||
+)
|
||
+
|
||
+// 鍦ㄧ粍浠舵寕杞藉悗鍒濆鍖栬璇佸拰姝屾洸锛堝彧浼氬湪瀹㈡埛绔墽琛岋級
|
||
+onMounted(async () => {
|
||
+ try {
|
||
+ await initSiteConfig()
|
||
+
|
||
+ const currentUser = await auth.initAuth()
|
||
+
|
||
+ if (typeof document !== 'undefined' && siteTitle.value) {
|
||
+ document.title = `棣栭〉 | ${siteTitle.value}`
|
||
+ }
|
||
+
|
||
+ if (isClientAuthenticated.value) {
|
||
+ hasInitializedAuthData.value = true
|
||
+ await Promise.allSettled([
|
||
+ songs.fetchSongs(),
|
||
+ songs.fetchPublicSchedules(),
|
||
+ loadNotifications(),
|
||
+ fetchNotificationSettings()
|
||
+ ])
|
||
+ await checkPasswordChangeRequired(currentUser)
|
||
+ } else {
|
||
+ hasInitializedAuthData.value = false
|
||
+ await Promise.allSettled([songs.fetchSongCount(), songs.fetchPublicSchedules()])
|
||
+ }
|
||
+
|
||
+ await updateSongCounts()
|
||
+
|
||
+ await setupRefreshInterval()
|
||
+
|
||
+ if (songs.notification) {
|
||
+ watch(songs.notification, (newVal) => {
|
||
+ if (newVal.show) {
|
||
+ showNotification(newVal.message, newVal.type)
|
||
+ }
|
||
+ })
|
||
+ }
|
||
+
|
||
+ // 娉ㄥ叆绔欑偣缁熻浠g爜锛堝厹搴曟柟妗堬細鍔ㄦ€佹彃鍏?script 鍒?body 鏈熬锛? if (statisticsCodeEnabled.value && statisticsCode.value) {
|
||
+ try {
|
||
+ injectStatisticsCode(statisticsCode.value)
|
||
+ } catch (e) {
|
||
+ console.warn('缁熻浠g爜娉ㄥ叆澶辫触:', e)
|
||
+ }
|
||
+ }
|
||
+ } catch (error) {
|
||
+ console.error('棣栭〉鍒濆鍖栧け璐?', error)
|
||
+ await Promise.allSettled([songs.fetchPublicSchedules(), songs.fetchSongCount()])
|
||
+ await updateSongCounts()
|
||
+ }
|
||
+})
|
||
+
|
||
+// 缁勪欢鍗歌浇鏃舵竻闄ゅ畾鏃跺櫒
|
||
+onUnmounted(() => {
|
||
+ if (refreshInterval) {
|
||
+ clearInterval(refreshInterval)
|
||
+ }
|
||
+})
|
||
+
|
||
+// 瀹炴椂璁$畻姝屾洸鎬绘暟
|
||
+const realSongCount = computed(() => {
|
||
+ return songs?.visibleSongs?.value?.length || 0
|
||
+})
|
||
+
|
||
+// 浣跨敤璁$畻灞炴€у畨鍏ㄥ湴璁块棶鏁版嵁
|
||
+const publicSchedules = computed(() => songs?.publicSchedules?.value || [])
|
||
+const allSongs = computed(() => songs?.visibleSongs?.value || [])
|
||
+const filteredSongs = computed(() => {
|
||
+ // 杩斿洖鎵€鏈夋瓕鏇诧紝浣嗗皢宸叉挱鏀剧殑姝屾洸鎺掑湪鏈€鍚? if (allSongs.value && allSongs.value.length > 0) {
|
||
+ const unplayedSongs = allSongs.value.filter((song) => !song.played)
|
||
+ const playedSongs = allSongs.value.filter((song) => song.played)
|
||
+ return [...unplayedSongs, ...playedSongs]
|
||
+ }
|
||
+ return []
|
||
+})
|
||
+const loading = computed(() => songs?.loading?.value || false)
|
||
+const error = computed(() => songs?.error?.value || '')
|
||
+
|
||
+// 澶勭悊瀛︽牎logo鐨凥TTP/HTTPS浠g悊
|
||
+const proxiedSchoolLogoUrl = computed(() => {
|
||
+ if (!schoolLogoHomeUrl.value || !schoolLogoHomeUrl.value.trim()) {
|
||
+ return ''
|
||
+ }
|
||
+
|
||
+ const logoUrl = schoolLogoHomeUrl.value.trim()
|
||
+
|
||
+ // 濡傛灉鏄疕TTP閾炬帴锛岄€氳繃浠g悊璁块棶
|
||
+ if (logoUrl.startsWith('http://')) {
|
||
+ return `/api/proxy/image?url=${encodeURIComponent(logoUrl)}`
|
||
+ }
|
||
+
|
||
+ // HTTPS閾炬帴鎴栫浉瀵硅矾寰勭洿鎺ヨ繑鍥? return logoUrl
|
||
+})
|
||
+
|
||
+// 澶勭悊鎶曠璇锋眰
|
||
+const handleRequest = async (songData, done) => {
|
||
+ if (!auth || !isClientAuthenticated.value) {
|
||
+ if (window.$showNotification) {
|
||
+ window.$showNotification('闇€瑕佺櫥褰曟墠鑳芥姇绋挎瓕鏇?, 'error')
|
||
+ }
|
||
+ showRequestModal.value = false
|
||
+ if (typeof done === 'function') done(false)
|
||
+ return false
|
||
+ }
|
||
+
|
||
+ try {
|
||
+ console.log('澶勭悊姝屾洸璇锋眰:', songData.title)
|
||
+ // 鐩存帴浼犻€掓暣涓猻ongData瀵硅薄锛岀‘淇滼SON鏍煎紡姝g‘
|
||
+ const result = await songs.requestSong(songData)
|
||
+ if (result) {
|
||
+ // 鏄剧ず鎶曠鎴愬姛閫氱煡
|
||
+ if (window.$showNotification) {
|
||
+ window.$showNotification(`銆?{songData.title} - ${songData.artist}銆嬫姇绋挎垚鍔燂紒`, 'success')
|
||
+ }
|
||
+
|
||
+ // 寮哄埗鍒锋柊姝屾洸鍒楄〃
|
||
+ console.log('鎶曠鎴愬姛锛屽埛鏂版瓕鏇插垪琛?)
|
||
+ await refreshSongs()
|
||
+
|
||
+ // 鍒锋柊鎶曠鐘舵€? if (requestFormRef.value && requestFormRef.value.refreshSubmissionStatus) {
|
||
+ await requestFormRef.value.refreshSubmissionStatus()
|
||
+ }
|
||
+
|
||
+ // 濡傛灉褰撳墠鍦ㄦ瓕鏇插垪琛ㄩ〉锛岃嚜鍔ㄥ垏鎹㈠埌璇ラ〉闈? if (activeTab.value !== 'songs') {
|
||
+ setTimeout(() => {
|
||
+ handleTabClick('songs')
|
||
+ }, 500)
|
||
+ }
|
||
+
|
||
+ if (typeof done === 'function') done(true)
|
||
+ return true
|
||
+ }
|
||
+ if (typeof done === 'function') done(false)
|
||
+ return false
|
||
+ } catch (err) {
|
||
+ if (window.$showNotification) {
|
||
+ window.$showNotification(err.message || '鐐规瓕澶辫触', 'error')
|
||
+ }
|
||
+ if (typeof done === 'function') done(false)
|
||
+ return false
|
||
+ }
|
||
+}
|
||
+
|
||
+// 澶勭悊鎶曠エ
|
||
+const handleVote = async (song) => {
|
||
+ if (!isClientAuthenticated.value) {
|
||
+ showNotification('璇峰厛鐧诲綍鍚庡啀鎶曠エ', 'error')
|
||
+ return
|
||
+ }
|
||
+
|
||
+ try {
|
||
+ if (!songs) return
|
||
+
|
||
+ // 璋冪敤鎶曠エAPI - 閫氱煡宸插湪composable涓鐞? // 妫€鏌ユ槸鍚︽槸鍙栨秷鎶曠エ璇锋眰
|
||
+ if (song.unvote) {
|
||
+ // 浼犻€掑畬鏁村璞′互鏀寔鎾ら攢鎶曠エ鍔熻兘
|
||
+ await songs.voteSong(song)
|
||
+ } else {
|
||
+ // 淇濇寔鍚戝悗鍏煎锛屼紶閫扞D
|
||
+ await songs.voteSong(song.id)
|
||
+ }
|
||
+
|
||
+ // 闈欓粯鍒锋柊姝屾洸鍒楄〃浠ヨ幏鍙栨渶鏂扮姸鎬侊紝浣嗕笉褰卞搷褰撳墠瑙嗗浘
|
||
+ setTimeout(() => {
|
||
+ songs.refreshSongsSilent().catch((err) => {
|
||
+ console.error('鍒锋柊姝屾洸鍒楄〃澶辫触', err)
|
||
+ })
|
||
+ }, 500)
|
||
+ } catch (err) {
|
||
+ // 涓嶅仛浠讳綍澶勭悊锛屽洜涓簎seSongs涓凡缁忓鐞嗕簡閿欒鎻愮ず
|
||
+ console.log('API閿欒宸插湪useSongs涓鐞?)
|
||
+ }
|
||
+}
|
||
+
|
||
+const handleCancelReplay = async (song) => {
|
||
+ if (!isClientAuthenticated.value) {
|
||
+ showNotification('璇峰厛鐧诲綍鎵嶈兘鍙栨秷閲嶆挱鐢宠', 'error')
|
||
+ return
|
||
+ }
|
||
+
|
||
+ try {
|
||
+ if (!songs) return
|
||
+ await songs.withdrawReplay(song.id)
|
||
+ updateSongCounts()
|
||
+ } catch (err) {
|
||
+ console.log('API閿欒宸插湪useSongs涓鐞?)
|
||
+ }
|
||
+}
|
||
+
|
||
+const handleRequestReplay = async (song) => {
|
||
+ if (!isClientAuthenticated.value) {
|
||
+ showNotification('璇峰厛鐧诲綍鎵嶈兘鐢宠閲嶆挱', 'error')
|
||
+ return
|
||
+ }
|
||
+
|
||
+ try {
|
||
+ if (!songs) return
|
||
+ await songs.requestReplay(song.id)
|
||
+ updateSongCounts()
|
||
+ } catch (err) {
|
||
+ console.log('API閿欒宸插湪useSongs涓鐞?)
|
||
+ }
|
||
+}
|
||
+
|
||
+// 澶勭悊鎾ゅ洖鎶曠
|
||
+const handleWithdraw = async (song) => {
|
||
+ if (!isClientAuthenticated.value) {
|
||
+ showNotification('璇峰厛鐧诲綍鎵嶈兘鎾ゅ洖鎶曠', 'error')
|
||
+ return
|
||
+ }
|
||
+
|
||
+ try {
|
||
+ if (!songs) return
|
||
+
|
||
+ // 璋冪敤鎾ゅ洖API - 閫氱煡宸插湪composable涓鐞? await songs.withdrawSong(song.id)
|
||
+ // 鏇存柊璁℃暟
|
||
+ updateSongCounts()
|
||
+ } catch (err) {
|
||
+ // 涓嶅仛浠讳綍澶勭悊锛屽洜涓簎seSongs涓凡缁忓鐞嗕簡閿欒鎻愮ず
|
||
+ console.log('API閿欒宸插湪useSongs涓鐞?)
|
||
+ }
|
||
+}
|
||
+
|
||
+// 鍒锋柊姝屾洸鍒楄〃锛堜紭鍖栫増鏈級
|
||
+const refreshSongs = async () => {
|
||
+ try {
|
||
+ if (isClientAuthenticated.value) {
|
||
+ await songs.fetchSongs(false, undefined, true) // forceRefresh=true
|
||
+ } else {
|
||
+ await songs.fetchPublicSchedules(false, undefined, true) // forceRefresh=true
|
||
+ }
|
||
+
|
||
+ updateSongCounts()
|
||
+ } catch (err) {
|
||
+ console.error('鍒锋柊姝屾洸鍒楄〃澶辫触', err)
|
||
+ }
|
||
+}
|
||
+
|
||
+// 澶勭悊瀛︽湡鍙樺寲锛堝墠绔繃婊ょ増鏈級
|
||
+const handleSemesterChange = async (semester) => {
|
||
+ try {
|
||
+ // 閫氳繃浜嬩欢鎬荤嚎閫氱煡SongList缁勪欢杩涜鍓嶇杩囨护
|
||
+ // 浣跨敤nextTick纭繚浜嬩欢鍦―OM鏇存柊鍚庤Е鍙? await nextTick()
|
||
+
|
||
+ // 瑙﹀彂鑷畾涔変簨浠讹紝閫氱煡鎵€鏈夌洃鍚殑缁勪欢
|
||
+ const event = new CustomEvent('semester-filter-change', {
|
||
+ detail: { semester }
|
||
+ })
|
||
+ window.dispatchEvent(event)
|
||
+
|
||
+ console.log('瀛︽湡鍒囨崲浜嬩欢宸插彂閫?', semester)
|
||
+
|
||
+ // 鏇存柊姝屾洸璁℃暟锛堝熀浜庡綋鍓嶅凡鏈夋暟鎹級
|
||
+ await updateSongCounts(semester)
|
||
+ } catch (err) {
|
||
+ console.error('鍒囨崲瀛︽湡澶辫触', err)
|
||
+ }
|
||
+}
|
||
+
|
||
+// 鏇存柊閫氱煡鏁伴噺 - 鍙互淇濈暀杩欎釜鍑芥暟浣嗕笉鍐嶈皟鐢?const updateNotificationCount = async () => {
|
||
+ // 鍑芥暟淇濈暀浣嗕笉鍐嶄娇鐢?}
|
||
+
|
||
+// 澶勭悊鐧诲嚭
|
||
+const handleLogout = () => {
|
||
+ if (auth) {
|
||
+ auth.logout()
|
||
+ }
|
||
+}
|
||
+
|
||
+// 澶勭悊杩涘叆鍚庡彴鐨勭偣鍑诲姩鐢?const handleDashboardClick = (event) => {
|
||
+ const button = event.currentTarget
|
||
+ button.classList.add('clicking')
|
||
+
|
||
+ // 娣诲姞娑熸吉鏁堟灉
|
||
+ const ripple = document.createElement('span')
|
||
+ ripple.classList.add('ripple')
|
||
+ button.appendChild(ripple)
|
||
+
|
||
+ setTimeout(() => {
|
||
+ button.classList.remove('clicking')
|
||
+ ripple.remove()
|
||
+ }, 300)
|
||
+}
|
||
+
|
||
+// 娣诲姞鏌ョ湅閫氱煡骞舵爣璁颁负宸茶
|
||
+const viewNotification = async (notification) => {
|
||
+ if (!notification.read) {
|
||
+ await notificationsService.markAsRead(notification.id)
|
||
+ }
|
||
+}
|
||
+
|
||
+// 澶勭悊鑱斿悎鎶曠鍥炲
|
||
+const handleCollaborationReply = async (notification, accept) => {
|
||
+ if (notification.processing) return
|
||
+ notification.processing = true
|
||
+
|
||
+ try {
|
||
+ await $fetch('/api/songs/collaborators/reply', {
|
||
+ method: 'POST',
|
||
+ body: {
|
||
+ songId: notification.songId,
|
||
+ accept
|
||
+ }
|
||
+ })
|
||
+
|
||
+ // 鏍囪涓哄凡澶勭悊
|
||
+ notification.handled = true
|
||
+ notification.status = accept ? 'ACCEPTED' : 'REJECTED'
|
||
+ notification.repliedAt = new Date()
|
||
+ // notification.message += accept ? ' (宸叉帴鍙?' : ' (宸叉嫆缁?'
|
||
+
|
||
+ if (window.$showNotification) {
|
||
+ window.$showNotification(accept ? '宸叉帴鍙楄仈鍚堟姇绋块個璇? : '宸叉嫆缁濊仈鍚堟姇绋块個璇?, 'success')
|
||
+ }
|
||
+
|
||
+ // 鏍囪閫氱煡涓哄凡璇? await markNotificationAsRead(notification.id)
|
||
+
|
||
+ // 鍒锋柊姝屾洸鍒楄〃
|
||
+ refreshSongs()
|
||
+
|
||
+ // 鍒锋柊閫氱煡鍒楄〃
|
||
+ await loadNotifications()
|
||
+ } catch (error) {
|
||
+ console.error('澶勭悊鑱斿悎鎶曠閭€璇峰け璐?', error)
|
||
+ if (window.$showNotification) {
|
||
+ window.$showNotification(error.statusMessage || '鎿嶄綔澶辫触', 'error')
|
||
+ }
|
||
+ } finally {
|
||
+ notification.processing = false
|
||
+ }
|
||
+}
|
||
+
|
||
+// 鏍煎紡鍖栧埛鏂伴棿闅?const formatRefreshInterval = (seconds) => {
|
||
+ if (seconds < 60) {
|
||
+ return `${seconds}绉抈
|
||
+ } else {
|
||
+ const minutes = Math.floor(seconds / 60)
|
||
+ const remainingSeconds = seconds % 60
|
||
+ return remainingSeconds > 0 ? `${minutes}鍒?{remainingSeconds}绉抈 : `${minutes}鍒嗛挓`
|
||
+ }
|
||
+}
|
||
+
|
||
+// 娉㈢汗鏁堟灉鎸囦护
|
||
+const vRipple = {
|
||
+ mounted(el) {
|
||
+ el.addEventListener('click', (e) => {
|
||
+ const rect = el.getBoundingClientRect()
|
||
+ const x = e.clientX - rect.left
|
||
+ const y = e.clientY - rect.top
|
||
+
|
||
+ const ripple = document.createElement('span')
|
||
+ ripple.className = 'ripple-effect'
|
||
+ ripple.style.left = `${x}px`
|
||
+ ripple.style.top = `${y}px`
|
||
+
|
||
+ el.appendChild(ripple)
|
||
+
|
||
+ setTimeout(() => {
|
||
+ ripple.remove()
|
||
+ }, 600) // 涓嶤SS鍔ㄧ敾鏃堕棿涓€鑷? })
|
||
+ }
|
||
+}
|
||
+
|
||
+// 澶勭悊鏍囩鐐瑰嚮浜嬩欢锛屾坊鍔犲姩鐢绘晥鏋?const handleTabClick = (tab) => {
|
||
+ activeTab.value = tab
|
||
+}
|
||
+
|
||
+// 娣诲姞瀵艰埅鍒扮櫥褰曢〉闈㈢殑鏂规硶
|
||
+const navigateToLogin = () => {
|
||
+ router.push('/login')
|
||
+}
|
||
+
|
||
+// 鏄剧ず鐧诲綍鎻愮ず
|
||
+const showLoginNotice = () => {
|
||
+ if (window.$showNotification) {
|
||
+ window.$showNotification('闇€瑕佺櫥褰曟墠鑳芥煡鐪嬮€氱煡', 'info')
|
||
+ }
|
||
+}
|
||
+
|
||
+// 娉ㄥ叆绔欑偣缁熻浠g爜锛堝厹搴曟柟妗堬細鍔ㄦ€佽В鏋愬苟鎻掑叆 script 鍏冪礌鍒?body 鏈熬锛?const injectStatisticsCode = (code) => {
|
||
+ if (typeof document === 'undefined' || !code) return
|
||
+
|
||
+ // 鍏堝皾璇曠敤涓存椂瀹瑰櫒瑙f瀽 HTML锛屾彁鍙栧叾涓殑 script 鏍囩
|
||
+ const tempDiv = document.createElement('div')
|
||
+ tempDiv.innerHTML = code
|
||
+
|
||
+ // 灏嗛潪 script 鐨勫厓绱犲厛闄勫姞鍒板鍣ㄤ腑
|
||
+ const container = document.getElementById('site-statistics-code')
|
||
+ if (container) {
|
||
+ Array.from(tempDiv.childNodes).forEach((node) => {
|
||
+ if (node.nodeType === 1 && node.tagName && node.tagName.toLowerCase() !== 'script') {
|
||
+ container.appendChild(node.cloneNode(true))
|
||
+ }
|
||
+ })
|
||
+ }
|
||
+
|
||
+ // 鍗曠嫭澶勭悊 script 鏍囩锛氬姩鎬佸垱寤哄苟鎻掑叆鍒?body 鏈熬锛岀‘淇濊兘姝g‘鎵ц
|
||
+ const scripts = tempDiv.querySelectorAll('script')
|
||
+ scripts.forEach((oldScript) => {
|
||
+ const newScript = document.createElement('script')
|
||
+ Array.from(oldScript.attributes).forEach((attr) => {
|
||
+ newScript.setAttribute(attr.name, attr.value)
|
||
+ })
|
||
+ if (oldScript.textContent) {
|
||
+ newScript.textContent = oldScript.textContent
|
||
+ }
|
||
+ document.body.appendChild(newScript)
|
||
+ })
|
||
+}
|
||
+
|
||
+// 妫€鏌ョ敤鎴锋槸鍚﹂渶瑕佷慨鏀瑰瘑鐮?const checkPasswordChangeRequired = async (user = null) => {
|
||
+ try {
|
||
+ // 浣跨敤浼犲叆鐨勭敤鎴蜂俊鎭垨褰撳墠璁よ瘉鐘舵€佷腑鐨勭敤鎴蜂俊鎭? const currentUser = user || auth?.user?.value
|
||
+
|
||
+ if (currentUser && currentUser.requirePasswordChange) {
|
||
+ // 寤惰繜1绉掓樉绀洪€氱煡锛岀‘淇濋〉闈㈠姞杞藉畬鎴? setTimeout(() => {
|
||
+ if (window.$showNotification) {
|
||
+ window.$showNotification(
|
||
+ '涓轰簡鎮ㄧ殑璐︽埛瀹夊叏锛屽缓璁偍淇敼瀵嗙爜銆傛偍鍙互鐐瑰嚮鍙充笂瑙掔殑"淇敼瀵嗙爜"鎸夐挳杩涜淇敼銆?,
|
||
+ 'info',
|
||
+ true,
|
||
+ 8000 // 鏄剧ず8绉? )
|
||
+ }
|
||
+ }, 1000)
|
||
+ }
|
||
+ } catch (error) {
|
||
+ console.error('妫€鏌ュ瘑鐮佷慨鏀圭姸鎬佸け璐?', error)
|
||
+ }
|
||
+}
|
||
+
|
||
+// 鏃х殑showToast鍑芥暟宸茬Щ闄わ紝浣跨敤鍏ㄥ眬閫氱煡绯荤粺
|
||
+
|
||
+// 娣诲姞鏈閫氱煡璁℃暟
|
||
+// 涔嬪墠宸插0鏄庝簡unreadNotificationCount锛岃繖閲屽鍏惰繘琛屽寮?if (
|
||
+ notificationsService &&
|
||
+ notificationsService.unreadCount &&
|
||
+ notificationsService.unreadCount.value
|
||
+) {
|
||
+ const count = notificationsService.unreadCount.value
|
||
+ unreadNotificationCount.value = count
|
||
+}
|
||
+</script>
|
||
+
|
||
+<style scoped>
|
||
+.home {
|
||
+ width: 100%;
|
||
+ flex: 1;
|
||
+ background-color: #121318;
|
||
+ padding: 1.5rem;
|
||
+ color: #ffffff;
|
||
+ display: flex;
|
||
+ flex-direction: column;
|
||
+ min-height: 100vh; /* 纭繚鑷冲皯鍗犳弧瑙嗗彛 */
|
||
+}
|
||
+
|
||
+.main-content {
|
||
+ width: 100%;
|
||
+ max-width: 1440px;
|
||
+ margin: 0 auto;
|
||
+ position: relative;
|
||
+ display: flex;
|
||
+ flex-direction: column;
|
||
+ height: 100%; /* 鏀逛负鍗犳弧鐖跺鍣ㄩ珮搴﹁€屼笉鏄鍙i珮搴?*/
|
||
+}
|
||
+
|
||
+/* 娣诲姞椤堕儴Ellipse 1鏁堟灉 */
|
||
+.ellipse-effect {
|
||
+ position: absolute;
|
||
+ top: -165px;
|
||
+ left: 50%;
|
||
+ transform: translateX(-50%) perspective(500px) rotateX(10deg);
|
||
+ width: 1110px;
|
||
+ height: 309px;
|
||
+ background: radial-gradient(
|
||
+ ellipse at center,
|
||
+ rgba(11, 90, 254, 0.3) 0%,
|
||
+ rgba(11, 90, 254, 0.15) 30%,
|
||
+ rgba(11, 90, 254, 0) 70%
|
||
+ );
|
||
+ z-index: 0;
|
||
+ pointer-events: none;
|
||
+}
|
||
+
|
||
+/* 椤堕儴鍖哄煙鏍峰紡 */
|
||
+.top-bar {
|
||
+ display: flex;
|
||
+ justify-content: space-between;
|
||
+ align-items: center;
|
||
+ margin-bottom: 2rem;
|
||
+ margin-top: -2rem;
|
||
+}
|
||
+
|
||
+.logo-section {
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ gap: 20px;
|
||
+ min-height: 160px;
|
||
+}
|
||
+
|
||
+.logo-link {
|
||
+ display: block;
|
||
+ text-decoration: none;
|
||
+}
|
||
+
|
||
+.logo-image {
|
||
+ width: 80px;
|
||
+ height: auto;
|
||
+ object-fit: contain;
|
||
+}
|
||
+
|
||
+/* 妯嚎鍜屽鏍ogo瀹瑰櫒 */
|
||
+.logo-divider-container {
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ gap: 30px;
|
||
+}
|
||
+
|
||
+/* 妯嚎鏍峰紡 */
|
||
+.logo-divider {
|
||
+ width: 2px;
|
||
+ height: 100px;
|
||
+ background: linear-gradient(
|
||
+ to bottom,
|
||
+ rgba(255, 255, 255, 0.3),
|
||
+ rgba(255, 255, 255, 0.8),
|
||
+ rgba(255, 255, 255, 0.3)
|
||
+ );
|
||
+ border-radius: 1px;
|
||
+}
|
||
+
|
||
+/* 瀛︽牎logo鏍峰紡 */
|
||
+.school-logo {
|
||
+ max-width: 200px;
|
||
+ max-height: 80px;
|
||
+ width: auto;
|
||
+ height: auto;
|
||
+ object-fit: contain;
|
||
+}
|
||
+
|
||
+.user-section {
|
||
+ position: relative;
|
||
+ z-index: 100;
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ gap: 10px;
|
||
+}
|
||
+
|
||
+/* 閫氱敤宸ュ叿鎸夐挳锛堜富棰?璇█锛?*/
|
||
+.utility-btn {
|
||
+ display: inline-flex;
|
||
+ align-items: center;
|
||
+ gap: 6px;
|
||
+ padding: 7px 12px;
|
||
+ background: var(--utility-btn-bg, rgba(255, 255, 255, 0.06));
|
||
+ color: var(--utility-btn-color, rgba(255, 255, 255, 0.78));
|
||
+ border: 1px solid var(--utility-btn-border, rgba(255, 255, 255, 0.12));
|
||
+ border-radius: 10px;
|
||
+ font-size: 13px;
|
||
+ font-weight: 500;
|
||
+ line-height: 1;
|
||
+ cursor: pointer;
|
||
+ transition:
|
||
+ background 0.2s ease,
|
||
+ color 0.2s ease,
|
||
+ border-color 0.2s ease,
|
||
+ transform 0.15s ease;
|
||
+ backdrop-filter: blur(6px);
|
||
+}
|
||
+
|
||
+.utility-btn:hover {
|
||
+ background: var(--utility-btn-hover-bg, rgba(255, 255, 255, 0.12));
|
||
+ color: var(--utility-btn-hover-color, #ffffff);
|
||
+ border-color: var(--utility-btn-hover-border, rgba(255, 255, 255, 0.22));
|
||
+}
|
||
+
|
||
+.utility-btn:active {
|
||
+ transform: scale(0.97);
|
||
+}
|
||
+
|
||
+.utility-btn-label {
|
||
+ white-space: nowrap;
|
||
+}
|
||
+
|
||
+@media (max-width: 768px) {
|
||
+ .utility-btn-label {
|
||
+ display: none;
|
||
+ }
|
||
+ .utility-btn {
|
||
+ padding: 7px 8px;
|
||
+ border-radius: 9px;
|
||
+ }
|
||
+}
|
||
+
|
||
+.user-info {
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ gap: 12px;
|
||
+ cursor: pointer;
|
||
+}
|
||
+
|
||
+.login-options {
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ gap: 12px;
|
||
+}
|
||
+
|
||
+.enter-admin-btn {
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ gap: 6px;
|
||
+ padding: 6px 12px;
|
||
+ background: rgba(59, 130, 246, 0.15);
|
||
+ color: #60a5fa;
|
||
+ border: 1px solid rgba(59, 130, 246, 0.3);
|
||
+ border-radius: 8px;
|
||
+ font-size: 0.85rem;
|
||
+ font-weight: 600;
|
||
+ transition: all 0.2s ease;
|
||
+ cursor: pointer;
|
||
+ text-decoration: none;
|
||
+ margin-right: 8px;
|
||
+}
|
||
+
|
||
+.enter-admin-btn:hover {
|
||
+ background: rgba(59, 130, 246, 0.25);
|
||
+ transform: translateY(-1px);
|
||
+}
|
||
+
|
||
+.user-details-desktop {
|
||
+ display: flex;
|
||
+ flex-direction: column;
|
||
+ align-items: flex-end;
|
||
+}
|
||
+
|
||
+.user-name {
|
||
+ font-size: 14px;
|
||
+ font-weight: 600;
|
||
+ color: rgba(255, 255, 255, 0.9);
|
||
+}
|
||
+
|
||
+.user-badge {
|
||
+ font-size: 10px;
|
||
+ padding: 1px 6px;
|
||
+ background: rgba(255, 255, 255, 0.1);
|
||
+ color: rgba(255, 255, 255, 0.5);
|
||
+ border-radius: 4px;
|
||
+ margin-top: 2px;
|
||
+}
|
||
+
|
||
+.user-badge.admin {
|
||
+ background: rgba(59, 130, 246, 0.2);
|
||
+ color: #3b82f6;
|
||
+}
|
||
+
|
||
+.user-avatar-wrapper {
|
||
+ width: 36px;
|
||
+ height: 36px;
|
||
+ border-radius: 50%;
|
||
+ overflow: hidden;
|
||
+ background: #2a2a2a;
|
||
+ border: 1px solid rgba(255, 255, 255, 0.1);
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ justify-content: center;
|
||
+}
|
||
+
|
||
+.user-avatar {
|
||
+ width: 100%;
|
||
+ height: 100%;
|
||
+ object-fit: cover;
|
||
+}
|
||
+
|
||
+.user-avatar-placeholder {
|
||
+ font-size: 16px;
|
||
+ font-weight: 700;
|
||
+ color: var(--primary);
|
||
+}
|
||
+
|
||
+.user-actions-dropdown {
|
||
+ position: absolute;
|
||
+ top: calc(100% + 12px);
|
||
+ right: 0;
|
||
+ background: #1a1a1f;
|
||
+ border: 1px solid rgba(255, 255, 255, 0.1);
|
||
+ border-radius: 12px;
|
||
+ padding: 8px;
|
||
+ min-width: 160px;
|
||
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
|
||
+ display: flex;
|
||
+ flex-direction: column;
|
||
+ gap: 4px;
|
||
+}
|
||
+
|
||
+.action-item {
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ gap: 10px;
|
||
+ padding: 10px 12px;
|
||
+ border-radius: 8px;
|
||
+ color: rgba(255, 255, 255, 0.7);
|
||
+ font-size: 14px;
|
||
+ transition: all 0.2s;
|
||
+ text-decoration: none;
|
||
+ background: transparent;
|
||
+ width: 100%;
|
||
+ text-align: left;
|
||
+}
|
||
+
|
||
+.action-item:hover {
|
||
+ background: rgba(255, 255, 255, 0.05);
|
||
+ color: white;
|
||
+}
|
||
+
|
||
+.action-item.logout:hover {
|
||
+ background: rgba(239, 68, 68, 0.1);
|
||
+ color: #ef4444;
|
||
+}
|
||
+
|
||
+.notification-badge {
|
||
+ position: absolute;
|
||
+ top: -5px;
|
||
+ right: -5px;
|
||
+ min-width: 18px;
|
||
+ height: 18px;
|
||
+ border-radius: 9px;
|
||
+ background-color: #f44336;
|
||
+ color: white;
|
||
+ font-size: 10px;
|
||
+ font-weight: bold;
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ justify-content: center;
|
||
+ padding: 0 4px;
|
||
+}
|
||
+
|
||
+/* 鐧诲綍鎸夐挳 - 妗岄潰绔?*/
|
||
+.login-options .login-btn {
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ gap: 10px;
|
||
+ padding: 10px 24px;
|
||
+ border-radius: 14px;
|
||
+ font-size: 14px;
|
||
+ font-weight: 600;
|
||
+ background: rgba(255, 255, 255, 0.04);
|
||
+ backdrop-filter: blur(12px);
|
||
+ -webkit-backdrop-filter: blur(12px);
|
||
+ color: #ffffff;
|
||
+ border: 1px solid rgba(255, 255, 255, 0.1);
|
||
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
|
||
+ transition: all 0.4s cubic-bezier(0.23, 1, 0.32, 1);
|
||
+ text-decoration: none;
|
||
+ position: relative;
|
||
+ overflow: hidden;
|
||
+}
|
||
+
|
||
+.login-options .login-btn:hover {
|
||
+ background: rgba(255, 255, 255, 0.08);
|
||
+ border-color: rgba(59, 130, 246, 0.5);
|
||
+ transform: translateY(-2px);
|
||
+ box-shadow: 0 8px 25px rgba(59, 130, 246, 0.2);
|
||
+ color: white;
|
||
+}
|
||
+
|
||
+.login-options .login-btn :deep(.icon),
|
||
+.login-options .login-btn i {
|
||
+ color: #3b82f6;
|
||
+ transition: all 0.3s ease;
|
||
+}
|
||
+
|
||
+.login-options .login-btn:hover :deep(.icon),
|
||
+.login-options .login-btn:hover i {
|
||
+ transform: scale(1.1);
|
||
+ filter: drop-shadow(0 0 5px rgba(59, 130, 246, 0.5));
|
||
+}
|
||
+
|
||
+.login-options .login-btn:active {
|
||
+ transform: translateY(0) scale(0.96);
|
||
+ transition: all 0.1s;
|
||
+}
|
||
+
|
||
+/* 绔欑偣鏍囬 */
|
||
+.site-title {
|
||
+ text-align: center;
|
||
+ margin: 3rem 0;
|
||
+ padding: 0 1rem;
|
||
+}
|
||
+
|
||
+.title-container {
|
||
+ display: inline-flex;
|
||
+ flex-direction: column;
|
||
+ align-items: center;
|
||
+ gap: 0.75rem;
|
||
+}
|
||
+
|
||
+.main-title {
|
||
+ font-family: 'MiSans', sans-serif;
|
||
+ font-weight: 800;
|
||
+ font-size: 42px;
|
||
+ letter-spacing: -0.02em;
|
||
+ background: linear-gradient(135deg, #ffffff 0%, rgba(255, 255, 255, 0.7) 100%);
|
||
+ -webkit-background-clip: text;
|
||
+ -webkit-text-fill-color: transparent;
|
||
+ text-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
|
||
+ margin: 0;
|
||
+ line-height: 1.2;
|
||
+}
|
||
+
|
||
+.title-divider {
|
||
+ width: 40px;
|
||
+ height: 4px;
|
||
+ background: #0b5afe;
|
||
+ border-radius: 2px;
|
||
+ box-shadow: 0 0 15px rgba(11, 90, 254, 0.6);
|
||
+}
|
||
+
|
||
+.sub-title {
|
||
+ font-family: 'MiSans', sans-serif;
|
||
+ font-weight: 500;
|
||
+ font-size: 14px;
|
||
+ color: rgba(255, 255, 255, 0.4);
|
||
+ letter-spacing: 0.2em;
|
||
+ text-transform: uppercase;
|
||
+}
|
||
+
|
||
+/* 鍐呭鍖哄煙缁撴瀯 */
|
||
+.content-area {
|
||
+ display: flex;
|
||
+ flex-direction: column;
|
||
+ gap: 0;
|
||
+ flex: 1; /* 鍗犳嵁鍓╀綑绌洪棿 */
|
||
+ min-height: 0; /* 鍏佽 flex 瀛愬厓绱犳敹缂?*/
|
||
+ width: 100%; /* 纭繚瀹藉害鍗犳弧 */
|
||
+}
|
||
+
|
||
+/* 閫夐」鍗℃牱寮?- 妗岄潰绔?*/
|
||
+.tabs-row {
|
||
+ display: flex;
|
||
+ gap: 5px;
|
||
+ margin-bottom: 0;
|
||
+ overflow-x: auto;
|
||
+ white-space: nowrap;
|
||
+ scrollbar-width: none;
|
||
+ -ms-overflow-style: none;
|
||
+ padding-bottom: 2px;
|
||
+}
|
||
+
|
||
+.tabs-row::-webkit-scrollbar {
|
||
+ display: none;
|
||
+}
|
||
+
|
||
+.section-tab {
|
||
+ background: #1a1b24;
|
||
+ border-radius: 15px 15px 0 0;
|
||
+ padding: 15px 24px;
|
||
+ font-family: 'MiSans', sans-serif;
|
||
+ font-weight: 600;
|
||
+ font-size: 16px;
|
||
+ color: rgba(255, 255, 255, 0.8);
|
||
+ border: 2px solid #282830;
|
||
+ border-bottom: none;
|
||
+ cursor: pointer;
|
||
+ flex: 0 0 auto;
|
||
+}
|
||
+
|
||
+.section-tab.active {
|
||
+ background: #21242d;
|
||
+ color: #ffffff;
|
||
+ position: relative;
|
||
+ z-index: 1;
|
||
+}
|
||
+
|
||
+@keyframes tab-pane-enter {
|
||
+ 0% {
|
||
+ opacity: 0;
|
||
+ transform: translateY(20px);
|
||
+ }
|
||
+ 100% {
|
||
+ opacity: 1;
|
||
+ transform: translateY(0);
|
||
+ }
|
||
+}
|
||
+
|
||
+/* 閫氱煡鍒楄〃杩囨浮鍔ㄧ敾 */
|
||
+.notification-list-fade-enter-active,
|
||
+.notification-list-fade-leave-active {
|
||
+ transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||
+}
|
||
+
|
||
+.notification-list-fade-enter-from {
|
||
+ opacity: 0;
|
||
+ transform: translateY(30px) scale(0.95);
|
||
+}
|
||
+
|
||
+.notification-list-fade-leave-to {
|
||
+ opacity: 0;
|
||
+ transform: translateY(-20px) scale(1.02);
|
||
+}
|
||
+
|
||
+/* 閫氱煡椤逛氦閿欒繘鍏ュ姩鐢?*/
|
||
+.notification-card {
|
||
+ animation: notification-item-enter 0.6s cubic-bezier(0.4, 0, 0.2, 1) forwards;
|
||
+ animation-delay: var(--animation-delay, 0s);
|
||
+ opacity: 0;
|
||
+ transform: translateY(20px);
|
||
+ will-change: transform, opacity;
|
||
+ transition:
|
||
+ transform 0.2s cubic-bezier(0.4, 0, 0.2, 1),
|
||
+ box-shadow 0.2s ease;
|
||
+}
|
||
+
|
||
+.notification-card:hover {
|
||
+ transform: translateY(-2px) scale(1.02);
|
||
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
|
||
+}
|
||
+
|
||
+@keyframes notification-item-enter {
|
||
+ 0% {
|
||
+ opacity: 0;
|
||
+ transform: translateY(20px) scale(0.95);
|
||
+ }
|
||
+ 100% {
|
||
+ opacity: 1;
|
||
+ transform: translateY(0) scale(1);
|
||
+ }
|
||
+}
|
||
+
|
||
+/* 閫夐」鍗″垏鎹㈠姩鐢?*/
|
||
+.section-tab {
|
||
+ position: relative;
|
||
+ transition: all 0.3s ease;
|
||
+ overflow: hidden;
|
||
+ padding: 0.75rem 1.5rem;
|
||
+ z-index: 10; /* 纭繚鍦ㄥ唴瀹逛箣涓?*/
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ justify-content: center;
|
||
+ gap: 8px;
|
||
+}
|
||
+
|
||
+.section-tab .tab-icon {
|
||
+ display: none; /* PC绔粯璁ら殣钘忓浘鏍?*/
|
||
+}
|
||
+
|
||
+.section-tab .icon-wrapper {
|
||
+ display: none; /* PC绔粯璁ら殣钘忓浘鏍囧鍣紝閬垮厤闂磋窛闂 */
|
||
+}
|
||
+
|
||
+.section-tab .tab-text {
|
||
+ display: inline;
|
||
+ position: relative;
|
||
+}
|
||
+
|
||
+/* PC绔€氱煡灏忓渾鐐?*/
|
||
+.notification-badge-desktop {
|
||
+ position: absolute;
|
||
+ top: -2px;
|
||
+ right: -8px;
|
||
+ width: 6px;
|
||
+ height: 6px;
|
||
+ background: #0b5afe;
|
||
+ border-radius: 50%;
|
||
+ box-shadow: 0 0 5px rgba(11, 90, 254, 0.5);
|
||
+}
|
||
+
|
||
+.section-tab::after {
|
||
+ content: '';
|
||
+ position: absolute;
|
||
+ bottom: 0;
|
||
+ left: 50%;
|
||
+ width: 0;
|
||
+ height: 2px;
|
||
+ background: #0b5afe;
|
||
+ transition: all 0.3s ease;
|
||
+ transform: translateX(-50%);
|
||
+}
|
||
+
|
||
+.section-tab:hover::after {
|
||
+ width: 50%;
|
||
+}
|
||
+
|
||
+.section-tab.active::after {
|
||
+ width: 100%;
|
||
+}
|
||
+
|
||
+/* 绉婚櫎涓婃诞鏁堟灉 */
|
||
+.section-tab:hover {
|
||
+ transform: none; /* 绉婚櫎涓婃诞鏁堟灉 */
|
||
+ background-color: transparent; /* 绉婚櫎鑳屾櫙鑹?*/
|
||
+ box-shadow: none; /* 绉婚櫎鍐呴槾褰?*/
|
||
+ color: rgba(255, 255, 255, 0.9);
|
||
+}
|
||
+
|
||
+.section-tab.active:hover {
|
||
+ background-color: transparent;
|
||
+ box-shadow: none;
|
||
+ color: #ffffff;
|
||
+}
|
||
+
|
||
+/* 鍐呭瀹瑰櫒 */
|
||
+.tab-content-container {
|
||
+ background: #1a1b24;
|
||
+ border: 2px solid #282830;
|
||
+ border-radius: 0 15px 15px 15px;
|
||
+ padding: 1.5rem;
|
||
+ margin-top: -2px; /* 浣垮唴瀹瑰鍣ㄤ笌鏍囩杩炴帴 */
|
||
+ box-sizing: border-box;
|
||
+ width: 100%;
|
||
+ display: flex;
|
||
+ flex-direction: column;
|
||
+ flex: 1; /* 鍗犳嵁鍓╀綑绌洪棿 */
|
||
+ min-height: 0; /* 鍏佽 flex 瀛愬厓绱犳敹缂?*/
|
||
+ overflow: hidden; /* 闃叉鍐呭婧㈠嚭 */
|
||
+}
|
||
+
|
||
+@media (max-width: 768px) {
|
||
+ .tab-content-container {
|
||
+ padding: 1rem;
|
||
+ width: 100%;
|
||
+ max-width: 100%;
|
||
+ box-sizing: border-box;
|
||
+ }
|
||
+}
|
||
+
|
||
+.tab-pane {
|
||
+ width: 100%;
|
||
+ box-sizing: border-box;
|
||
+ animation: tab-pane-enter 0.45s ease;
|
||
+}
|
||
+
|
||
+/* 閽堝鎺掓湡鏍囩椤电殑鐗规畩鏍峰紡 */
|
||
+.schedule-tab-pane {
|
||
+ width: 100%;
|
||
+ box-sizing: border-box;
|
||
+ padding: 0;
|
||
+ display: flex;
|
||
+ flex-direction: column;
|
||
+ flex: 1; /* 鍗犳弧鐖跺鍣ㄩ珮搴?*/
|
||
+ min-height: 0; /* 鍏佽 flex 瀛愬厓绱犳敹缂?*/
|
||
+ overflow: hidden; /* 闃叉鍐呭婧㈠嚭 */
|
||
+}
|
||
+
|
||
+.schedule-tab-pane .full-width {
|
||
+ flex: 1; /* 鍗犳嵁鍓╀綑绌洪棿 */
|
||
+ display: flex;
|
||
+ flex-direction: column;
|
||
+ min-height: 0; /* 鍏佽 flex 瀛愬厓绱犳敹缂?*/
|
||
+ overflow: hidden; /* 闃叉鍐呭婧㈠嚭 */
|
||
+}
|
||
+
|
||
+@media (max-width: 768px) {
|
||
+ .tab-pane {
|
||
+ padding: 0.5rem;
|
||
+ }
|
||
+
|
||
+ .schedule-tab-pane {
|
||
+ padding: 0;
|
||
+ }
|
||
+
|
||
+ /* 绉诲姩绔垎椤垫帶浠舵牱寮?*/
|
||
+ .pagination-controls {
|
||
+ flex-direction: column;
|
||
+ gap: 10px;
|
||
+ }
|
||
+
|
||
+ .page-size-selector {
|
||
+ justify-content: center;
|
||
+ }
|
||
+
|
||
+ .page-navigation {
|
||
+ justify-content: center;
|
||
+ flex-wrap: wrap;
|
||
+ }
|
||
+
|
||
+ .page-numbers {
|
||
+ flex-wrap: wrap;
|
||
+ justify-content: center;
|
||
+ }
|
||
+}
|
||
+
|
||
+.song-list-container {
|
||
+ width: 100%;
|
||
+ padding: 1rem 0;
|
||
+}
|
||
+
|
||
+.date-info p {
|
||
+ font-family: 'MiSans', sans-serif;
|
||
+ font-weight: 400;
|
||
+ font-size: 16px;
|
||
+ letter-spacing: 4%;
|
||
+}
|
||
+
|
||
+/* 姝屾洸鏃舵 */
|
||
+.time-label {
|
||
+ font-family: 'MiSans', sans-serif;
|
||
+ font-weight: 400;
|
||
+ font-size: 16px;
|
||
+ letter-spacing: 4%;
|
||
+ color: rgba(255, 255, 255, 0.6);
|
||
+ margin: 1.5rem 0 1rem;
|
||
+}
|
||
+
|
||
+.song-cards {
|
||
+ display: flex;
|
||
+ flex-direction: column;
|
||
+ gap: 1rem;
|
||
+}
|
||
+
|
||
+/* 璇锋眰琛ㄥ崟甯冨眬 */
|
||
+.request-pane {
|
||
+ display: flex;
|
||
+ gap: 2rem;
|
||
+}
|
||
+
|
||
+/* 绌虹姸鎬?*/
|
||
+.empty-state {
|
||
+ text-align: center;
|
||
+ padding: 2rem;
|
||
+ color: rgba(255, 255, 255, 0.6);
|
||
+}
|
||
+
|
||
+/* 涓嬫媺鑿滃崟鍔ㄧ敾 */
|
||
+.dropdown-fade-enter-active,
|
||
+.dropdown-fade-leave-active {
|
||
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||
+}
|
||
+
|
||
+.dropdown-fade-enter-from,
|
||
+.dropdown-fade-leave-to {
|
||
+ opacity: 0;
|
||
+ transform: translateY(-10px) scale(0.95);
|
||
+}
|
||
+
|
||
+/* 閫氱煡闈㈡澘 */
|
||
+.notification-pane {
|
||
+ height: 100%;
|
||
+ display: flex;
|
||
+ flex-direction: column;
|
||
+}
|
||
+
|
||
+.notification-container {
|
||
+ display: flex;
|
||
+ flex-direction: column;
|
||
+ height: 100%;
|
||
+ width: 100%;
|
||
+ position: relative;
|
||
+}
|
||
+
|
||
+/* 閫氱煡澶撮儴 */
|
||
+.notification-header {
|
||
+ display: flex;
|
||
+ justify-content: space-between;
|
||
+ align-items: center;
|
||
+ padding: 1.25rem 0;
|
||
+ margin-bottom: 1.5rem;
|
||
+ border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
||
+}
|
||
+
|
||
+.notification-title {
|
||
+ font-size: 1.25rem;
|
||
+ font-weight: 700;
|
||
+ color: #ffffff;
|
||
+ margin: 0;
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ gap: 0.75rem;
|
||
+}
|
||
+
|
||
+.settings-icon {
|
||
+ background: rgba(255, 255, 255, 0.05);
|
||
+ border: 1px solid rgba(255, 255, 255, 0.1);
|
||
+ color: rgba(255, 255, 255, 0.6);
|
||
+ width: 36px;
|
||
+ height: 36px;
|
||
+ border-radius: 10px;
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ justify-content: center;
|
||
+ cursor: pointer;
|
||
+ transition: all 0.2s ease;
|
||
+}
|
||
+
|
||
+.settings-icon:hover {
|
||
+ background-color: rgba(255, 255, 255, 0.1);
|
||
+ color: #ffffff;
|
||
+ transform: rotate(30deg);
|
||
+}
|
||
+
|
||
+/* 閫氱煡鍒楄〃 */
|
||
+.notification-list {
|
||
+ flex: 1;
|
||
+ display: flex;
|
||
+ flex-direction: column;
|
||
+ overflow-y: auto;
|
||
+ padding: 0.5rem;
|
||
+ margin-bottom: 1.5rem;
|
||
+ min-height: 400px;
|
||
+}
|
||
+
|
||
+.loading-indicator,
|
||
+.empty-notification {
|
||
+ flex: 1;
|
||
+ display: flex;
|
||
+ flex-direction: column;
|
||
+ align-items: center;
|
||
+ justify-content: center;
|
||
+ padding: 3rem 0;
|
||
+ color: rgba(255, 255, 255, 0.4);
|
||
+ gap: 1.25rem;
|
||
+}
|
||
+
|
||
+.empty-icon {
|
||
+ width: 80px;
|
||
+ height: 80px;
|
||
+ background: rgba(255, 255, 255, 0.03);
|
||
+ border-radius: 50%;
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ justify-content: center;
|
||
+ margin-bottom: 0.5rem;
|
||
+}
|
||
+
|
||
+.loading-spinner {
|
||
+ width: 32px;
|
||
+ height: 32px;
|
||
+ border: 3px solid rgba(255, 255, 255, 0.1);
|
||
+ border-top-color: #3b82f6;
|
||
+ border-radius: 50%;
|
||
+ animation: spin 0.8s linear infinite;
|
||
+}
|
||
+
|
||
+@keyframes spin {
|
||
+ to {
|
||
+ transform: rotate(360deg);
|
||
+ }
|
||
+}
|
||
+
|
||
+.notification-items {
|
||
+ display: flex;
|
||
+ flex-direction: column;
|
||
+ gap: 1rem;
|
||
+}
|
||
+
|
||
+.notification-card {
|
||
+ background: rgba(255, 255, 255, 0.03);
|
||
+ backdrop-filter: blur(20px);
|
||
+ border: 1px solid rgba(255, 255, 255, 0.06);
|
||
+ border-radius: 20px;
|
||
+ padding: 1.25rem;
|
||
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||
+ position: relative;
|
||
+ cursor: pointer;
|
||
+}
|
||
+
|
||
+.notification-card:hover {
|
||
+ background: rgba(255, 255, 255, 0.06);
|
||
+ border-color: rgba(255, 255, 255, 0.12);
|
||
+ transform: translateY(-2px);
|
||
+}
|
||
+
|
||
+.notification-card.unread {
|
||
+ background: rgba(59, 130, 246, 0.05);
|
||
+ border-color: rgba(59, 130, 246, 0.2);
|
||
+}
|
||
+
|
||
+.notification-card-header {
|
||
+ display: flex;
|
||
+ align-items: flex-start;
|
||
+ margin-bottom: 1rem;
|
||
+}
|
||
+
|
||
+.notification-icon-type {
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ justify-content: center;
|
||
+ width: 40px;
|
||
+ height: 40px;
|
||
+ background: rgba(59, 130, 246, 0.1);
|
||
+ color: #3b82f6;
|
||
+ border-radius: 12px;
|
||
+ margin-right: 1rem;
|
||
+ flex-shrink: 0;
|
||
+ font-size: 1.25rem;
|
||
+}
|
||
+
|
||
+.notification-title-row {
|
||
+ flex: 1;
|
||
+ min-width: 0;
|
||
+}
|
||
+
|
||
+.notification-title {
|
||
+ font-size: 0.95rem;
|
||
+ font-weight: 600;
|
||
+ color: #ffffff;
|
||
+ margin-bottom: 0.25rem;
|
||
+}
|
||
+
|
||
+.notification-time {
|
||
+ font-size: 0.75rem;
|
||
+ color: rgba(255, 255, 255, 0.4);
|
||
+}
|
||
+
|
||
+.notification-card-body {
|
||
+ padding: 0 0 0 3.5rem;
|
||
+}
|
||
+
|
||
+.notification-text {
|
||
+ color: rgba(255, 255, 255, 0.7);
|
||
+ font-size: 0.875rem;
|
||
+ line-height: 1.6;
|
||
+}
|
||
+
|
||
+.notification-card-actions {
|
||
+ display: flex;
|
||
+ justify-content: flex-end;
|
||
+ margin-top: 1rem;
|
||
+ padding-left: 3.5rem;
|
||
+}
|
||
+
|
||
+.action-button.delete {
|
||
+ background: rgba(239, 68, 68, 0.05);
|
||
+ color: #ef4444;
|
||
+ border: 1px solid rgba(239, 68, 68, 0.1);
|
||
+ padding: 0.4rem 0.75rem;
|
||
+ border-radius: 8px;
|
||
+ font-size: 0.75rem;
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ gap: 0.4rem;
|
||
+ transition: all 0.2s;
|
||
+}
|
||
+
|
||
+.action-button.delete:hover {
|
||
+ background: rgba(239, 68, 68, 0.1);
|
||
+ border-color: rgba(239, 68, 68, 0.2);
|
||
+}
|
||
+
|
||
+.notification-actions-bar {
|
||
+ display: flex;
|
||
+ gap: 1rem;
|
||
+ padding: 1rem 0;
|
||
+ border-top: 1px solid rgba(255, 255, 255, 0.08);
|
||
+}
|
||
+
|
||
+.action-button-large {
|
||
+ flex: 1;
|
||
+ background: rgba(255, 255, 255, 0.05);
|
||
+ border: 1px solid rgba(255, 255, 255, 0.1);
|
||
+ color: #ffffff;
|
||
+ padding: 0.75rem;
|
||
+ border-radius: 12px;
|
||
+ font-size: 0.875rem;
|
||
+ font-weight: 600;
|
||
+ cursor: pointer;
|
||
+ transition: all 0.2s;
|
||
+}
|
||
+
|
||
+.action-button-large:hover:not(.disabled) {
|
||
+ background: rgba(255, 255, 255, 0.1);
|
||
+}
|
||
+
|
||
+.action-button-large.danger {
|
||
+ color: #ef4444;
|
||
+}
|
||
+
|
||
+.action-button-large.danger:hover {
|
||
+ background: rgba(239, 68, 68, 0.1);
|
||
+}
|
||
+
|
||
+.action-button-large.disabled {
|
||
+ opacity: 0.5;
|
||
+ cursor: not-allowed;
|
||
+}
|
||
+
|
||
+/* 鍒嗛〉鎺т欢鏍峰紡 */
|
||
+.notification-pagination {
|
||
+ padding: 15px 0;
|
||
+ border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||
+}
|
||
+
|
||
+.pagination-info {
|
||
+ text-align: center;
|
||
+ margin-bottom: 15px;
|
||
+}
|
||
+
|
||
+.pagination-text {
|
||
+ color: rgba(255, 255, 255, 0.7);
|
||
+ font-size: 0.85rem;
|
||
+}
|
||
+
|
||
+.pagination-controls {
|
||
+ display: flex;
|
||
+ justify-content: space-between;
|
||
+ align-items: center;
|
||
+ gap: 15px;
|
||
+}
|
||
+
|
||
+.page-size-selector {
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ gap: 8px;
|
||
+}
|
||
+
|
||
+.page-size-selector label {
|
||
+ color: rgba(255, 255, 255, 0.7);
|
||
+ font-size: 0.85rem;
|
||
+ white-space: nowrap;
|
||
+}
|
||
+
|
||
+.page-size-custom-select {
|
||
+ width: 90px;
|
||
+}
|
||
+
|
||
+.page-navigation {
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ gap: 8px;
|
||
+}
|
||
+
|
||
+.page-nav-button {
|
||
+ background-color: rgba(255, 255, 255, 0.1);
|
||
+ border: 1px solid rgba(255, 255, 255, 0.2);
|
||
+ color: var(--light);
|
||
+ width: 32px;
|
||
+ height: 32px;
|
||
+ border-radius: 6px;
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ justify-content: center;
|
||
+ cursor: pointer;
|
||
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||
+ will-change: transform, background-color;
|
||
+}
|
||
+
|
||
+.page-nav-button:hover:not(:disabled) {
|
||
+ background-color: rgba(255, 255, 255, 0.2);
|
||
+ border-color: rgba(255, 255, 255, 0.3);
|
||
+ transform: translateY(-1px);
|
||
+}
|
||
+
|
||
+.page-nav-button:active:not(:disabled) {
|
||
+ transform: translateY(0) scale(0.95);
|
||
+ transition: all 0.1s ease;
|
||
+}
|
||
+
|
||
+.page-nav-button:disabled {
|
||
+ background-color: rgba(255, 255, 255, 0.05);
|
||
+ border-color: rgba(255, 255, 255, 0.1);
|
||
+ color: rgba(255, 255, 255, 0.3);
|
||
+ cursor: not-allowed;
|
||
+}
|
||
+
|
||
+.page-numbers {
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ gap: 4px;
|
||
+}
|
||
+
|
||
+.page-number-button {
|
||
+ background-color: rgba(255, 255, 255, 0.1);
|
||
+ border: 1px solid rgba(255, 255, 255, 0.2);
|
||
+ color: var(--light);
|
||
+ width: 32px;
|
||
+ height: 32px;
|
||
+ border-radius: 6px;
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ justify-content: center;
|
||
+ cursor: pointer;
|
||
+ font-size: 0.85rem;
|
||
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||
+ will-change: transform, background-color;
|
||
+ position: relative;
|
||
+ overflow: hidden;
|
||
+}
|
||
+
|
||
+.page-number-button:hover:not(:disabled) {
|
||
+ background-color: rgba(255, 255, 255, 0.2);
|
||
+ border-color: rgba(255, 255, 255, 0.3);
|
||
+ transform: translateY(-1px);
|
||
+}
|
||
+
|
||
+.page-number-button:active:not(:disabled) {
|
||
+ transform: translateY(0) scale(0.95);
|
||
+ transition: all 0.1s ease;
|
||
+}
|
||
+
|
||
+.page-number-button.active {
|
||
+ background-color: var(--primary);
|
||
+ border-color: var(--primary);
|
||
+ color: white;
|
||
+}
|
||
+
|
||
+.page-number-button.active:hover {
|
||
+ background-color: #0952e8;
|
||
+ border-color: #0952e8;
|
||
+}
|
||
+
|
||
+.page-number-button:disabled {
|
||
+ background-color: rgba(255, 255, 255, 0.05);
|
||
+ border-color: rgba(255, 255, 255, 0.1);
|
||
+ color: rgba(255, 255, 255, 0.3);
|
||
+ cursor: not-allowed;
|
||
+}
|
||
+
|
||
+.page-ellipsis {
|
||
+ color: rgba(255, 255, 255, 0.5);
|
||
+ padding: 0 4px;
|
||
+ font-size: 0.85rem;
|
||
+}
|
||
+
|
||
+/* 鍒嗛〉鍔犺浇鐘舵€?*/
|
||
+.pagination-loading {
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ justify-content: center;
|
||
+ gap: 8px;
|
||
+ padding: 10px 0;
|
||
+ color: rgba(255, 255, 255, 0.7);
|
||
+ font-size: 0.85rem;
|
||
+ animation: fade-in 0.3s ease;
|
||
+}
|
||
+
|
||
+.loading-spinner {
|
||
+ width: 16px;
|
||
+ height: 16px;
|
||
+ border: 2px solid rgba(255, 255, 255, 0.2);
|
||
+ border-top: 2px solid var(--primary);
|
||
+ border-radius: 50%;
|
||
+ animation: spin 0.8s cubic-bezier(0.4, 0, 0.2, 1) infinite;
|
||
+ will-change: transform;
|
||
+}
|
||
+
|
||
+@keyframes spin {
|
||
+ 0% {
|
||
+ transform: rotate(0deg);
|
||
+ }
|
||
+ 100% {
|
||
+ transform: rotate(360deg);
|
||
+ }
|
||
+}
|
||
+
|
||
+@keyframes fade-in {
|
||
+ 0% {
|
||
+ opacity: 0;
|
||
+ transform: translateY(10px);
|
||
+ }
|
||
+ 100% {
|
||
+ opacity: 1;
|
||
+ transform: translateY(0);
|
||
+ }
|
||
+}
|
||
+
|
||
+/* 搴曢儴鎿嶄綔鏍?*/
|
||
+.notification-actions-bar {
|
||
+ display: flex;
|
||
+ justify-content: center;
|
||
+ gap: 10px;
|
||
+ padding: 15px 0;
|
||
+ border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||
+}
|
||
+
|
||
+.action-button-large {
|
||
+ background-color: rgba(255, 255, 255, 0.1);
|
||
+ border: none;
|
||
+ color: var(--light);
|
||
+ padding: 8px 16px;
|
||
+ border-radius: 6px;
|
||
+ cursor: pointer;
|
||
+ font-size: 0.9rem;
|
||
+ transition: all 0.2s ease;
|
||
+}
|
||
+
|
||
+.action-button-large:hover {
|
||
+ background-color: rgba(255, 255, 255, 0.2);
|
||
+}
|
||
+
|
||
+.action-button-large.danger {
|
||
+ color: #ef4444;
|
||
+}
|
||
+
|
||
+.action-button-large.danger:hover {
|
||
+ background-color: rgba(239, 68, 68, 0.2);
|
||
+}
|
||
+
|
||
+.action-button-large.disabled {
|
||
+ background-color: rgba(255, 255, 255, 0.05);
|
||
+ color: rgba(255, 255, 255, 0.3);
|
||
+ cursor: not-allowed;
|
||
+ opacity: 0.5;
|
||
+}
|
||
+
|
||
+.action-button-large.disabled:hover {
|
||
+ background-color: rgba(255, 255, 255, 0.05);
|
||
+}
|
||
+
|
||
+/* ==================== 绉诲姩绔璁?==================== */
|
||
+
|
||
+/* 鍩虹绉诲姩绔€傞厤 */
|
||
+@media (max-width: 768px) {
|
||
+ .home {
|
||
+ padding: 0;
|
||
+ background-color: #0a0a0f;
|
||
+ }
|
||
+
|
||
+ .main-content {
|
||
+ padding: 0;
|
||
+ }
|
||
+
|
||
+ /* 闅愯棌鍘熸湁鐨別llipse鏁堟灉锛屼娇鐢ㄦ洿寰鐨勮儗鏅?*/
|
||
+ .ellipse-effect {
|
||
+ display: none;
|
||
+ }
|
||
+
|
||
+ /* 椤堕儴鍖哄煙 */
|
||
+ .top-bar {
|
||
+ flex-direction: row;
|
||
+ justify-content: space-between;
|
||
+ align-items: center;
|
||
+ padding: 10px 12px;
|
||
+ margin: 0;
|
||
+ background: linear-gradient(180deg, rgba(11, 90, 254, 0.08) 0%, transparent 100%);
|
||
+ border-bottom: 1px solid rgba(255, 255, 255, 0.05);
|
||
+ }
|
||
+
|
||
+ .logo-section {
|
||
+ min-height: auto;
|
||
+ gap: 8px;
|
||
+ }
|
||
+
|
||
+ .logo-image {
|
||
+ width: 76px;
|
||
+ height: auto;
|
||
+ }
|
||
+
|
||
+ .logo-divider-container {
|
||
+ gap: 8px;
|
||
+ }
|
||
+
|
||
+ .logo-divider {
|
||
+ height: 28px;
|
||
+ width: 1px;
|
||
+ background: rgba(255, 255, 255, 0.15);
|
||
+ }
|
||
+
|
||
+ /* 绉诲姩绔殑涓婚〉闈㈤噷涓嶉渶瑕佸啓瀛︽牎鍚嶏紝淇濇寔绠€娲?*/
|
||
+ .site-title {
|
||
+ display: none;
|
||
+ }
|
||
+
|
||
+ .school-logo {
|
||
+ max-width: 120px;
|
||
+ max-height: 36px;
|
||
+ }
|
||
+
|
||
+ /* 鐢ㄦ埛鍖哄煙绠€鍖?*/
|
||
+ .user-section {
|
||
+ width: auto;
|
||
+ }
|
||
+
|
||
+ .user-details-desktop {
|
||
+ display: none; /* 绉诲姩绔粎鏄剧ず澶村儚 */
|
||
+ }
|
||
+
|
||
+ .user-avatar-wrapper {
|
||
+ width: 32px;
|
||
+ height: 32px;
|
||
+ background: rgba(255, 255, 255, 0.05);
|
||
+ border-color: rgba(255, 255, 255, 0.1);
|
||
+ }
|
||
+
|
||
+ .user-avatar-placeholder {
|
||
+ font-size: 14px;
|
||
+ }
|
||
+
|
||
+ .user-actions-dropdown {
|
||
+ top: calc(100% + 10px);
|
||
+ min-width: 140px;
|
||
+ padding: 6px;
|
||
+ }
|
||
+
|
||
+ .action-item {
|
||
+ padding: 8px 10px;
|
||
+ font-size: 13px;
|
||
+ }
|
||
+
|
||
+ /* 鐧诲綍鎸夐挳 */
|
||
+ .login-options .login-btn {
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ gap: 8px;
|
||
+ padding: 8px 18px;
|
||
+ border-radius: 12px;
|
||
+ font-size: 14px;
|
||
+ font-weight: 600;
|
||
+ background: rgba(255, 255, 255, 0.08);
|
||
+ backdrop-filter: blur(10px);
|
||
+ -webkit-backdrop-filter: blur(10px);
|
||
+ color: white;
|
||
+ border: 1px solid rgba(255, 255, 255, 0.1);
|
||
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||
+ }
|
||
+
|
||
+ .login-options .login-btn :deep(.icon) {
|
||
+ color: #3b82f6;
|
||
+ }
|
||
+
|
||
+ .login-options .login-btn:active {
|
||
+ transform: scale(0.95);
|
||
+ background: rgba(255, 255, 255, 0.15);
|
||
+ border-color: rgba(59, 130, 246, 0.4);
|
||
+ }
|
||
+
|
||
+ /* Footer 闂磋窛浼樺寲 */
|
||
+ :deep(.site-footer) {
|
||
+ padding-bottom: calc(80px + env(safe-area-inset-bottom, 0px));
|
||
+ }
|
||
+
|
||
+ /* 鍐呭鍖哄煙 - 鍏ㄥ鏃犺竟妗?*/
|
||
+ .content-area {
|
||
+ min-height: auto;
|
||
+ overflow-x: hidden; /* 闃叉妯悜婧㈠嚭 */
|
||
+ max-width: 100vw; /* 纭繚涓嶈秴杩囪鍙e搴?*/
|
||
+ box-sizing: border-box; /* 纭繚padding璁″叆鎬诲搴?*/
|
||
+ }
|
||
+
|
||
+ .tabs-row {
|
||
+ position: fixed;
|
||
+ bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
|
||
+ left: 1rem;
|
||
+ right: 1rem;
|
||
+ margin: 0 auto;
|
||
+ max-width: 500px;
|
||
+ display: flex;
|
||
+ justify-content: space-around;
|
||
+ align-items: stretch; /* 淇敼涓?stretch 浠ラ厤鍚堝瓙鍏冪礌 height: 100% */
|
||
+ gap: 0;
|
||
+ padding: 0 0.5rem;
|
||
+ height: 64px;
|
||
+ background: rgba(28, 28, 30, 0.9);
|
||
+ backdrop-filter: blur(20px) saturate(180%);
|
||
+ -webkit-backdrop-filter: blur(20px) saturate(180%);
|
||
+ border: 1px solid rgba(255, 255, 255, 0.1);
|
||
+ border-radius: 9999px;
|
||
+ z-index: 1000;
|
||
+ box-shadow: 0 12px 40px rgba(0, 0, 0, 0.6);
|
||
+ }
|
||
+
|
||
+ .section-tab {
|
||
+ flex: 1;
|
||
+ height: 100%; /* 纭繚濉弧瀹瑰櫒楂樺害 */
|
||
+ background: transparent;
|
||
+ border: none;
|
||
+ border-radius: 0;
|
||
+ padding: 0; /* 绉婚櫎鍥哄畾鍐呰竟璺濓紝鏀圭敤 flex 灞呬腑 */
|
||
+ font-size: 10px;
|
||
+ font-weight: 500;
|
||
+ color: #71717a; /* text-zinc-500 */
|
||
+ display: flex;
|
||
+ flex-direction: column;
|
||
+ align-items: center;
|
||
+ justify-content: center; /* 鍨傜洿灞呬腑鍐呭 */
|
||
+ gap: 4px;
|
||
+ position: relative;
|
||
+ transition: all 0.2s ease;
|
||
+ }
|
||
+
|
||
+ .section-tab .tab-icon {
|
||
+ display: block;
|
||
+ margin-bottom: 2px;
|
||
+ transition: all 0.2s ease;
|
||
+ color: currentColor;
|
||
+ }
|
||
+
|
||
+ .section-tab .tab-text {
|
||
+ font-size: 9px;
|
||
+ font-weight: 700;
|
||
+ letter-spacing: 0.02em;
|
||
+ transition: all 0.2s ease;
|
||
+ }
|
||
+
|
||
+ .section-tab.active {
|
||
+ color: #3b82f6 !important; /* text-blue-500 - Force blue */
|
||
+ background: transparent !important;
|
||
+ transform: none !important;
|
||
+ text-shadow: 0 0 12px rgba(59, 130, 246, 0.6); /* Text Glow */
|
||
+ }
|
||
+
|
||
+ /* Prevent hover from turning it white on mobile */
|
||
+ .section-tab.active:hover {
|
||
+ color: #3b82f6 !important;
|
||
+ background: transparent !important;
|
||
+ box-shadow: none !important;
|
||
+ }
|
||
+
|
||
+ .section-tab.active .tab-icon {
|
||
+ opacity: 1;
|
||
+ color: currentColor;
|
||
+ transform: none;
|
||
+ filter: drop-shadow(0 0 8px rgba(59, 130, 246, 0.5)); /* Icon Glow */
|
||
+ }
|
||
+
|
||
+ .section-tab.active .tab-text {
|
||
+ font-weight: 700;
|
||
+ }
|
||
+
|
||
+ /* 绉婚櫎鍘熸湁鐨勪吉鍏冪礌鍥炬爣 */
|
||
+ .section-tab::before {
|
||
+ display: none;
|
||
+ }
|
||
+
|
||
+ /* 绉婚櫎搴曢儴鎸囩ず鍣紙妯潯锛? 褰诲簳闅愯棌 */
|
||
+ .section-tab::after {
|
||
+ display: none !important;
|
||
+ }
|
||
+
|
||
+ @keyframes dot-pop-in {
|
||
+ 0% {
|
||
+ transform: scale(0);
|
||
+ opacity: 0;
|
||
+ }
|
||
+ 100% {
|
||
+ transform: scale(1);
|
||
+ opacity: 1;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ .icon-wrapper {
|
||
+ position: relative;
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ justify-content: center;
|
||
+ width: 24px;
|
||
+ height: 24px;
|
||
+ margin: 0 auto;
|
||
+ }
|
||
+
|
||
+ .section-tab .icon-wrapper {
|
||
+ display: flex; /* 绉诲姩绔樉绀哄浘鏍囧鍣?*/
|
||
+ }
|
||
+
|
||
+ /* 閫氱煡寰界珷 - 鍥炲綊钃濊壊椋庢牸 */
|
||
+ .notification-badge-tab {
|
||
+ position: absolute;
|
||
+ top: 0;
|
||
+ right: 0;
|
||
+ width: 8px;
|
||
+ height: 8px;
|
||
+ background: #0b5afe;
|
||
+ border-radius: 50%;
|
||
+ border: 1.5px solid #0a0a0f;
|
||
+ box-shadow: 0 0 5px rgba(11, 90, 254, 0.4);
|
||
+ z-index: 2;
|
||
+ }
|
||
+
|
||
+ .notification-badge-desktop {
|
||
+ display: none; /* 绉诲姩绔殣钘忔闈㈢増寰界珷 */
|
||
+ }
|
||
+
|
||
+ @keyframes badge-pulse {
|
||
+ /* 绉婚櫎瀵艰嚧浣嶇Щ鐨勫姩鐢?*/
|
||
+ }
|
||
+
|
||
+ .section-tab.disabled {
|
||
+ opacity: 0.3;
|
||
+ filter: grayscale(1);
|
||
+ }
|
||
+
|
||
+ /* 鍐呭瀹瑰櫒 */
|
||
+ .tab-content-container {
|
||
+ background: transparent;
|
||
+ border: none;
|
||
+ border-radius: 0;
|
||
+ padding: 0 6px calc(80px + env(safe-area-inset-bottom, 0px));
|
||
+ margin: 0;
|
||
+ min-height: calc(100vh - 120px);
|
||
+ }
|
||
+
|
||
+ .tab-pane {
|
||
+ padding: 0;
|
||
+ overflow-x: hidden; /* 闃叉妯悜婧㈠嚭 */
|
||
+ max-width: 100%; /* 纭繚涓嶈秴杩囪鍙e搴?*/
|
||
+ }
|
||
+
|
||
+ /* 鎺掓湡鏍囩椤典紭鍖?*/
|
||
+ .schedule-tab-pane {
|
||
+ padding: 0;
|
||
+ min-height: auto;
|
||
+ }
|
||
+
|
||
+ /* 璇锋眰琛ㄥ崟鍖哄煙 */
|
||
+ .request-pane {
|
||
+ flex-direction: column;
|
||
+ gap: 16px;
|
||
+ overflow-x: hidden; /* 闃叉妯悜婧㈠嚭 */
|
||
+ max-width: 100%; /* 纭繚涓嶈秴杩囪鍙e搴?*/
|
||
+ padding: 0 0.5rem; /* 娣诲姞宸﹀彸鍐呰竟璺濓紝闃叉鍐呭璐磋竟 */
|
||
+ box-sizing: border-box; /* 纭繚padding璁″叆鎬诲搴?*/
|
||
+ }
|
||
+
|
||
+ /* 鐧诲綍閫夐」 */
|
||
+ .login-options {
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ }
|
||
+
|
||
+ .login-options .btn-outline {
|
||
+ padding: 6px 14px;
|
||
+ font-size: 12px;
|
||
+ border-radius: 6px;
|
||
+ background: rgba(11, 90, 254, 0.15);
|
||
+ border: 1px solid rgba(11, 90, 254, 0.3);
|
||
+ }
|
||
+}
|
||
+
|
||
+/* 灏忓睆骞曡澶囬澶栦紭鍖?*/
|
||
+@media (max-width: 480px) {
|
||
+ .top-bar {
|
||
+ padding: 8px 10px;
|
||
+ }
|
||
+
|
||
+ .logo-image {
|
||
+ width: 90px;
|
||
+ }
|
||
+
|
||
+ .school-logo {
|
||
+ max-width: 100px;
|
||
+ max-height: 32px;
|
||
+ }
|
||
+
|
||
+ .action-button {
|
||
+ padding: 5px 8px;
|
||
+ font-size: 10px;
|
||
+ }
|
||
+
|
||
+ .site-title {
|
||
+ margin: 6px 0 10px;
|
||
+ padding: 0 12px;
|
||
+ }
|
||
+
|
||
+ .site-title h2 {
|
||
+ font-size: 16px;
|
||
+ }
|
||
+
|
||
+ .tab-content-container {
|
||
+ padding: 0 4px calc(80px + env(safe-area-inset-bottom, 0px));
|
||
+ }
|
||
+}
|
||
+
|
||
+/* 瓒呭皬灞忓箷璁惧 */
|
||
+@media (max-width: 360px) {
|
||
+ .logo-image {
|
||
+ width: 60px;
|
||
+ }
|
||
+
|
||
+ .school-logo {
|
||
+ max-width: 80px;
|
||
+ max-height: 28px;
|
||
+ }
|
||
+
|
||
+ .action-button {
|
||
+ padding: 4px 6px;
|
||
+ font-size: 9px;
|
||
+ }
|
||
+
|
||
+ .section-tab {
|
||
+ font-size: 9px;
|
||
+ }
|
||
+}
|
||
+
|
||
+/* 寮圭獥閬僵灞?*/
|
||
+.modal-overlay {
|
||
+ position: fixed;
|
||
+ top: 0;
|
||
+ left: 0;
|
||
+ right: 0;
|
||
+ bottom: 0;
|
||
+ background: rgba(0, 0, 0, 0.6);
|
||
+ backdrop-filter: blur(8px);
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ justify-content: center;
|
||
+ z-index: 1000;
|
||
+ animation: overlay-fade-in 0.4s ease-out;
|
||
+}
|
||
+
|
||
+@keyframes overlay-fade-in {
|
||
+ from {
|
||
+ opacity: 0;
|
||
+ }
|
||
+ to {
|
||
+ opacity: 1;
|
||
+ }
|
||
+}
|
||
+
|
||
+/* 寮圭獥鍐呭 */
|
||
+.modal-content {
|
||
+ background: linear-gradient(135deg, #1a1b24 0%, #121318 100%);
|
||
+ border-radius: 20px;
|
||
+ border: 1px solid rgba(255, 255, 255, 0.1);
|
||
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
|
||
+ max-width: 420px;
|
||
+ width: 90%;
|
||
+ overflow: hidden;
|
||
+ animation: modal-slide-up 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||
+}
|
||
+
|
||
+@keyframes modal-slide-up {
|
||
+ from {
|
||
+ opacity: 0;
|
||
+ transform: translateY(30px) scale(0.95);
|
||
+ }
|
||
+ to {
|
||
+ opacity: 1;
|
||
+ transform: translateY(0) scale(1);
|
||
+ }
|
||
+}
|
||
+
|
||
+/* 寮圭獥澶撮儴 */
|
||
+.modal-header {
|
||
+ display: flex;
|
||
+ justify-content: space-between;
|
||
+ align-items: center;
|
||
+ padding: 24px 28px 16px;
|
||
+ border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
||
+}
|
||
+
|
||
+.modal-header h2 {
|
||
+ font-family:
|
||
+ 'MiSans',
|
||
+ system-ui,
|
||
+ -apple-system,
|
||
+ sans-serif;
|
||
+ font-size: 20px;
|
||
+ font-weight: 700;
|
||
+ color: #ffffff;
|
||
+ margin: 0;
|
||
+ letter-spacing: 0.02em;
|
||
+}
|
||
+
|
||
+/* 鍏抽棴鎸夐挳 */
|
||
+.close-button {
|
||
+ width: 32px;
|
||
+ height: 32px;
|
||
+ border-radius: 50%;
|
||
+ background: rgba(255, 255, 255, 0.08);
|
||
+ border: none;
|
||
+ color: rgba(255, 255, 255, 0.6);
|
||
+ font-size: 24px;
|
||
+ line-height: 1;
|
||
+ cursor: pointer;
|
||
+ transition: all 0.2s ease;
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ justify-content: center;
|
||
+}
|
||
+
|
||
+.close-button:hover {
|
||
+ background: rgba(255, 255, 255, 0.15);
|
||
+ color: #ffffff;
|
||
+ transform: rotate(90deg);
|
||
+}
|
||
+
|
||
+/* 寮圭獥涓讳綋 */
|
||
+.modal-body {
|
||
+ padding: 24px 28px 28px;
|
||
+}
|
||
+
|
||
+.rules-container {
|
||
+ display: flex;
|
||
+ flex-direction: column;
|
||
+ gap: 1.5rem;
|
||
+}
|
||
+
|
||
+.rules-group {
|
||
+ display: flex;
|
||
+ flex-direction: column;
|
||
+ gap: 0.75rem;
|
||
+}
|
||
+
|
||
+.rules-subtitle {
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ gap: 0.5rem;
|
||
+ font-size: 16px;
|
||
+ font-weight: 700;
|
||
+ color: #ffffff;
|
||
+ margin: 0;
|
||
+}
|
||
+
|
||
+.rules-icon {
|
||
+ color: #3b82f6;
|
||
+}
|
||
+
|
||
+.rules-text {
|
||
+ font-size: 14px;
|
||
+ color: rgba(255, 255, 255, 0.6);
|
||
+ line-height: 1.6;
|
||
+ margin: 0;
|
||
+}
|
||
+
|
||
+.guidelines-content {
|
||
+ font-size: 14px;
|
||
+ color: rgba(255, 255, 255, 0.6);
|
||
+ line-height: 1.6;
|
||
+}
|
||
+
|
||
+.default-rules {
|
||
+ display: flex;
|
||
+ flex-direction: column;
|
||
+ gap: 0.5rem;
|
||
+}
|
||
+
|
||
+.rule-item {
|
||
+ display: flex;
|
||
+ font-size: 14px;
|
||
+ color: rgba(255, 255, 255, 0.6);
|
||
+ line-height: 1.5;
|
||
+}
|
||
+
|
||
+.rule-item span {
|
||
+ margin-right: 0.5rem;
|
||
+ color: rgba(255, 255, 255, 0.3);
|
||
+ font-weight: 600;
|
||
+}
|
||
+
|
||
+/* 骞村害鎶ュ憡寮圭獥 */
|
||
+.year-review-overlay {
|
||
+ backdrop-filter: blur(8px);
|
||
+ background: rgba(0, 0, 0, 0.4);
|
||
+}
|
||
+
|
||
+.year-review-card {
|
||
+ position: relative;
|
||
+ width: 90%;
|
||
+ max-width: 400px;
|
||
+ background: #12121a;
|
||
+ border-radius: 32px;
|
||
+ overflow: hidden;
|
||
+ border: 1px solid rgba(255, 255, 255, 0.1);
|
||
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
|
||
+ animation: card-appear 0.6s cubic-bezier(0.16, 1, 0.3, 1);
|
||
+}
|
||
+
|
||
+.card-glow {
|
||
+ position: absolute;
|
||
+ top: -50%;
|
||
+ left: -50%;
|
||
+ width: 200%;
|
||
+ height: 200%;
|
||
+ background: radial-gradient(circle, rgba(139, 92, 246, 0.15) 0%, transparent 70%);
|
||
+ pointer-events: none;
|
||
+}
|
||
+
|
||
+.card-pattern {
|
||
+ position: absolute;
|
||
+ inset: 0;
|
||
+ background-image: radial-gradient(rgba(255, 255, 255, 0.05) 1px, transparent 1px);
|
||
+ background-size: 20px 20px;
|
||
+ opacity: 0.5;
|
||
+}
|
||
+
|
||
+.card-close {
|
||
+ position: absolute;
|
||
+ top: 20px;
|
||
+ right: 20px;
|
||
+ width: 36px;
|
||
+ height: 36px;
|
||
+ border-radius: 12px;
|
||
+ background: rgba(255, 255, 255, 0.05);
|
||
+ border: 1px solid rgba(255, 255, 255, 0.1);
|
||
+ color: rgba(255, 255, 255, 0.4);
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ justify-content: center;
|
||
+ cursor: pointer;
|
||
+ z-index: 10;
|
||
+ transition: all 0.2s ease;
|
||
+}
|
||
+
|
||
+.card-close:hover {
|
||
+ background: rgba(255, 255, 255, 0.1);
|
||
+ color: #fff;
|
||
+ transform: translateY(2px);
|
||
+}
|
||
+
|
||
+.card-content {
|
||
+ position: relative;
|
||
+ padding: 40px 32px;
|
||
+ text-align: center;
|
||
+ z-index: 5;
|
||
+}
|
||
+
|
||
+.brand-badge {
|
||
+ display: inline-block;
|
||
+ padding: 4px 12px;
|
||
+ background: rgba(139, 92, 246, 0.1);
|
||
+ border: 1px solid rgba(139, 92, 246, 0.2);
|
||
+ border-radius: 99px;
|
||
+ color: #a78bfa;
|
||
+ font-size: 12px;
|
||
+ font-weight: 700;
|
||
+ letter-spacing: 0.1em;
|
||
+ margin-bottom: 32px;
|
||
+}
|
||
+
|
||
+.visual-container {
|
||
+ position: relative;
|
||
+ height: 120px;
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ justify-content: center;
|
||
+ margin-bottom: 24px;
|
||
+}
|
||
+
|
||
+.main-icon {
|
||
+ width: 80px;
|
||
+ height: 80px;
|
||
+ background: linear-gradient(135deg, #8b5cf6 0%, #6d28d9 100%);
|
||
+ border-radius: 24px;
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ justify-content: center;
|
||
+ color: #fff;
|
||
+ box-shadow: 0 10px 25px -5px rgba(139, 92, 246, 0.5);
|
||
+ z-index: 2;
|
||
+ transform: rotate(-5deg);
|
||
+}
|
||
+
|
||
+.music-bars {
|
||
+ position: absolute;
|
||
+ display: flex;
|
||
+ align-items: flex-end;
|
||
+ gap: 4px;
|
||
+ height: 40px;
|
||
+ opacity: 0.3;
|
||
+}
|
||
+
|
||
+.bar {
|
||
+ width: 4px;
|
||
+ background: #8b5cf6;
|
||
+ border-radius: 2px;
|
||
+ animation: bar-dance 1.2s ease-in-out infinite;
|
||
+}
|
||
+
|
||
+.bar:nth-child(1) {
|
||
+ height: 20px;
|
||
+ animation-delay: 0.1s;
|
||
+}
|
||
+.bar:nth-child(2) {
|
||
+ height: 35px;
|
||
+ animation-delay: 0.3s;
|
||
+}
|
||
+.bar:nth-child(3) {
|
||
+ height: 25px;
|
||
+ animation-delay: 0.2s;
|
||
+}
|
||
+.bar:nth-child(4) {
|
||
+ height: 40px;
|
||
+ animation-delay: 0.4s;
|
||
+}
|
||
+.bar:nth-child(5) {
|
||
+ height: 30px;
|
||
+ animation-delay: 0.2s;
|
||
+}
|
||
+
|
||
+@keyframes bar-dance {
|
||
+ 0%,
|
||
+ 100% {
|
||
+ transform: scaleY(1);
|
||
+ }
|
||
+ 50% {
|
||
+ transform: scaleY(0.6);
|
||
+ }
|
||
+}
|
||
+
|
||
+.card-title {
|
||
+ font-size: 24px;
|
||
+ font-weight: 800;
|
||
+ color: #fff;
|
||
+ margin-bottom: 12px;
|
||
+ letter-spacing: -0.01em;
|
||
+}
|
||
+
|
||
+.card-description {
|
||
+ font-size: 15px;
|
||
+ color: rgba(255, 255, 255, 0.5);
|
||
+ line-height: 1.6;
|
||
+ margin-bottom: 32px;
|
||
+}
|
||
+
|
||
+.card-actions {
|
||
+ display: flex;
|
||
+ flex-direction: column;
|
||
+ gap: 12px;
|
||
+}
|
||
+
|
||
+.btn-primary {
|
||
+ width: 100%;
|
||
+ padding: 16px;
|
||
+ background: #fff;
|
||
+ border: none;
|
||
+ border-radius: 16px;
|
||
+ color: #000;
|
||
+ font-size: 16px;
|
||
+ font-weight: 700;
|
||
+ display: flex;
|
||
+ align-items: center;
|
||
+ justify-content: center;
|
||
+ gap: 8px;
|
||
+ cursor: pointer;
|
||
+ transition: all 0.3s cubic-bezier(0.23, 1, 0.32, 1);
|
||
+}
|
||
+
|
||
+.btn-primary:hover {
|
||
+ transform: translateY(-2px);
|
||
+ box-shadow: 0 10px 20px rgba(255, 255, 255, 0.1);
|
||
+ background: #f4f4f4;
|
||
+}
|
||
+
|
||
+.btn-primary:active {
|
||
+ transform: translateY(0);
|
||
+}
|
||
+
|
||
+.btn-secondary {
|
||
+ width: 100%;
|
||
+ padding: 14px;
|
||
+ background: transparent;
|
||
+ border: 1px solid rgba(255, 255, 255, 0.1);
|
||
+ border-radius: 16px;
|
||
+ color: rgba(255, 255, 255, 0.6);
|
||
+ font-size: 14px;
|
||
+ font-weight: 600;
|
||
+ cursor: pointer;
|
||
+ transition: all 0.2s ease;
|
||
+}
|
||
+
|
||
+.btn-secondary:hover {
|
||
+ background: rgba(255, 255, 255, 0.05);
|
||
+ color: #fff;
|
||
+ border-color: rgba(255, 255, 255, 0.2);
|
||
+}
|
||
+
|
||
+@keyframes card-appear {
|
||
+ from {
|
||
+ opacity: 0;
|
||
+ transform: translateY(30px) scale(0.95);
|
||
+ }
|
||
+ to {
|
||
+ opacity: 1;
|
||
+ transform: translateY(0) scale(1);
|
||
+ }
|
||
+}
|
||
+
|
||
+/* 瑕嗙洊鏃у姩鐢?*/
|
||
+.modal-animation-enter-active,
|
||
+.modal-animation-leave-active {
|
||
+ transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1);
|
||
+}
|
||
+
|
||
+.modal-animation-enter-from,
|
||
+.modal-animation-leave-to {
|
||
+ opacity: 0;
|
||
+ backdrop-filter: blur(0);
|
||
+}
|
||
+
|
||
+.modal-animation-enter-from .year-review-card,
|
||
+.modal-animation-leave-to .year-review-card {
|
||
+ transform: translateY(40px) scale(0.9);
|
||
+}
|
||
+
|
||
+/* 娉㈢汗鏁堟灉 */
|
||
+.section-tab {
|
||
+ position: relative;
|
||
+ overflow: hidden;
|
||
+ transition: all 0.3s ease;
|
||
+ cursor: pointer;
|
||
+}
|
||
+
|
||
+.ripple-effect {
|
||
+ position: absolute;
|
||
+ border-radius: 50%;
|
||
+ background-color: rgba(255, 255, 255, 0.3);
|
||
+ transform: scale(0);
|
||
+ animation: ripple 0.6s linear;
|
||
+ pointer-events: none;
|
||
+ width: 100px;
|
||
+ height: 100px;
|
||
+ margin-left: -50px; /* 灞呬腑瀹氫綅 */
|
||
+ margin-top: -50px; /* 灞呬腑瀹氫綅 */
|
||
+}
|
||
+
|
||
+@keyframes ripple {
|
||
+ to {
|
||
+ transform: scale(4);
|
||
+ opacity: 0;
|
||
+ }
|
||
+}
|
||
+
|
||
+/* 纭繚鍏ㄥ鏄剧ず */
|
||
+.full-width,
|
||
+.full-width > div {
|
||
+ width: 100% !important;
|
||
+ max-width: 100% !important;
|
||
+ box-sizing: border-box !important;
|
||
+ padding: 0 !important;
|
||
+ margin: 0 !important;
|
||
+ display: block !important;
|
||
+}
|
||
+
|
||
+/* 閫氱煡鏍囩涓婄殑鏈寰界珷 */
|
||
+.notification-badge-tab {
|
||
+ position: absolute; /* 淇敼涓虹粷瀵瑰畾浣嶏紝闃叉鎸ゅ帇鍥炬爣 */
|
||
+ top: 0;
|
||
+ right: 0;
|
||
+ width: 8px;
|
||
+ height: 8px;
|
||
+ border-radius: 50%;
|
||
+ background-color: #0b5afe;
|
||
+ display: inline-block;
|
||
+ z-index: 2;
|
||
+}
|
||
+
|
||
+@keyframes pulse {
|
||
+ 0% {
|
||
+ transform: scale(1);
|
||
+ box-shadow: 0 0 0 0 rgba(0, 122, 255, 0.4);
|
||
+ }
|
||
+ 70% {
|
||
+ transform: scale(1.05);
|
||
+ box-shadow: 0 0 0 5px rgba(0, 122, 255, 0);
|
||
+ }
|
||
+ 100% {
|
||
+ transform: scale(1);
|
||
+ box-shadow: 0 0 0 0 rgba(0, 122, 255, 0);
|
||
+ }
|
||
+}
|
||
+
|
||
+/* 绂佺敤鐨勬爣绛鹃〉鏍峰紡 */
|
||
+.section-tab.disabled {
|
||
+ opacity: 0.6;
|
||
+ cursor: not-allowed;
|
||
+}
|
||
+
|
||
+/* 鏈櫥褰曟彁绀烘牱寮?*/
|
||
+.login-required-container {
|
||
+ display: flex;
|
||
+ flex-direction: column;
|
||
+ align-items: center;
|
||
+ justify-content: center;
|
||
+ height: 100%;
|
||
+ padding: 40px 0;
|
||
+}
|
||
+
|
||
+.login-required-content {
|
||
+ text-align: center;
|
||
+ max-width: 400px;
|
||
+ padding: 30px;
|
||
+ background-color: rgba(30, 41, 59, 0.5);
|
||
+ border-radius: 12px;
|
||
+ border: 1px solid rgba(255, 255, 255, 0.1);
|
||
+ box-shadow: 0 5px 20px rgba(0, 0, 0, 0.2);
|
||
+}
|
||
+
|
||
+.login-icon {
|
||
+ font-size: 3rem;
|
||
+ margin-bottom: 15px;
|
||
+}
|
||
+
|
||
+.login-required-content h3 {
|
||
+ font-size: 1.5rem;
|
||
+ margin-bottom: 10px;
|
||
+ color: var(--light);
|
||
+}
|
||
+
|
||
+.login-required-content p {
|
||
+ margin-bottom: 20px;
|
||
+ color: rgba(255, 255, 255, 0.7);
|
||
+}
|
||
+
|
||
+.login-button {
|
||
+ background: linear-gradient(180deg, #0043f8 0%, #0075f8 100%);
|
||
+ border: none;
|
||
+ color: white;
|
||
+ padding: 10px 20px;
|
||
+ border-radius: 6px;
|
||
+ font-weight: 600;
|
||
+ cursor: pointer;
|
||
+ transition: all 0.2s ease;
|
||
+}
|
||
+
|
||
+.login-button:hover {
|
||
+ transform: translateY(-2px);
|
||
+ box-shadow: 0 5px 15px rgba(0, 67, 248, 0.3);
|
||
+}
|
||
+</style>
|
||
diff --git a/old-nuxt.config.ts b/old-nuxt.config.ts
|
||
new file mode 100644
|
||
index 0000000..b5c3581
|
||
--- /dev/null
|
||
+++ b/old-nuxt.config.ts
|
||
@@ -0,0 +1,447 @@
|
||
+import wasm from 'vite-plugin-wasm'
|
||
+import glsl from 'vite-plugin-glsl'
|
||
+import { fileURLToPath } from 'url'
|
||
+import { index, uniqueIndex } from 'drizzle-orm'
|
||
+
|
||
+const customSeoConfig: Record<string, unknown> | null = (() => {
|
||
+ const raw = process.env.NUXT_PUBLIC_SEO_CONFIG
|
||
+ if (!raw) return null
|
||
+ try {
|
||
+ const parsed = JSON.parse(raw)
|
||
+ if (parsed && typeof parsed === 'object') return parsed as Record<string, unknown>
|
||
+ return null
|
||
+ } catch {
|
||
+ return null
|
||
+ }
|
||
+})()
|
||
+
|
||
+function readNumberEnv(name: string, defaultValue: number): number {
|
||
+ const raw = process.env[name]
|
||
+ if (raw === undefined || raw === '') return defaultValue
|
||
+ const num = Number(raw)
|
||
+ return Number.isFinite(num) ? num : defaultValue
|
||
+}
|
||
+
|
||
+// https://nuxt.com/docs/api/configuration/nuxt-config
|
||
+export default defineNuxtConfig({
|
||
+ compatibilityDate: '2026-01-30',
|
||
+ future: {
|
||
+ compatibilityVersion: 4
|
||
+ },
|
||
+ srcDir: 'app',
|
||
+ serverDir: fileURLToPath(new URL('./server', import.meta.url)),
|
||
+ dir: {
|
||
+ public: fileURLToPath(new URL('./public', import.meta.url))
|
||
+ },
|
||
+ devtools: { enabled: process.env.NODE_ENV === 'development' },
|
||
+ devServer: {
|
||
+ host: '0.0.0.0',
|
||
+ port: 3000
|
||
+ },
|
||
+ modules: [
|
||
+ '@nuxtjs/tailwindcss',
|
||
+ ...((process.env.NODE_ENV === 'development' || process.env.npm_lifecycle_event?.includes('lint'))
|
||
+ ? ['@nuxt/eslint']
|
||
+ : []),
|
||
+ ...((process.env.PWA_ENABLED || 'false') === 'true'
|
||
+ ? ['@vite-pwa/nuxt']
|
||
+ : [])
|
||
+ ],
|
||
+
|
||
+ pwa: (process.env.PWA_ENABLED || 'false') === 'true'
|
||
+ ? {
|
||
+ registerType: 'autoUpdate',
|
||
+ manifest: {
|
||
+ name: process.env.NUXT_PUBLIC_SITE_TITLE || '鏍″洯骞挎挱绔欑偣姝岀郴缁?,
|
||
+ short_name: process.env.NUXT_PUBLIC_SITE_TITLE || 'VoiceHub',
|
||
+ description: process.env.NUXT_PUBLIC_SITE_DESCRIPTION || '鏍″洯骞挎挱绔欑偣姝岀郴缁?,
|
||
+ display: (process.env.PWA_DISPLAY as any) || 'standalone',
|
||
+ background_color: process.env.PWA_BACKGROUND_COLOR || '#000000',
|
||
+ theme_color: process.env.PWA_THEME_COLOR || '#111111',
|
||
+ icons: [
|
||
+ {
|
||
+ src: '/images/logo.png',
|
||
+ sizes: '192x192',
|
||
+ type: 'image/png'
|
||
+ },
|
||
+ {
|
||
+ src: '/images/logo.png',
|
||
+ sizes: '512x512',
|
||
+ type: 'image/png'
|
||
+ }
|
||
+ ]
|
||
+ },
|
||
+ workbox: {
|
||
+ navigateFallback: '/',
|
||
+ globPatterns: ['**/*.{js,css,html,png,jpg,jpeg,svg,ico,webp,woff2}']
|
||
+ },
|
||
+ client: {
|
||
+ installPrompt: true,
|
||
+ periodicSyncForUpdates: 3600
|
||
+ },
|
||
+ devOptions: {
|
||
+ enabled: process.env.NODE_ENV === 'development'
|
||
+ }
|
||
+ }
|
||
+ : {},
|
||
+
|
||
+ // 寮曞叆鍏ㄥ眬CSS
|
||
+ css: [
|
||
+ '~/assets/css/variables.css',
|
||
+ '~/assets/css/components.css',
|
||
+ '~/assets/css/main.css',
|
||
+ '~/assets/css/transitions.css',
|
||
+ '~/assets/css/mobile-admin.css',
|
||
+ '~/assets/css/print-fix.css',
|
||
+ '~/assets/css/sf-pro-icons.css'
|
||
+ ],
|
||
+
|
||
+ build: {
|
||
+ transpile: []
|
||
+ },
|
||
+
|
||
+ // 瀹為獙鎬т紭鍖栧姛鑳? experimental: {
|
||
+ payloadExtraction: true,
|
||
+ renderJsonPayloads: true,
|
||
+ viewTransition: true
|
||
+ },
|
||
+
|
||
+ // 閰嶇疆杩愯鏃堕厤缃? runtimeConfig: {
|
||
+ // 鏈嶅姟鍣ㄧ鏈夐敭锛堜笉浼氭毚闇插埌瀹㈡埛绔級
|
||
+ jwtSecret: process.env.JWT_SECRET || 'your-secret-key',
|
||
+ // Redis閰嶇疆锛堝彲閫夛級
|
||
+ redisUrl: process.env.REDIS_URL || '',
|
||
+ redisKeyPrefix: process.env.REDIS_KEY_PREFIX || '',
|
||
+ // Sentry 鏈嶅姟绔厤缃紙涓嶄細鏆撮湶鍒板鎴风锛? sentry: {
|
||
+ serverDsn: process.env.SENTRY_SERVER_DSN || process.env.SENTRY_DSN || '',
|
||
+ dsn: process.env.SENTRY_DSN || '',
|
||
+ errorSampleRate: readNumberEnv('SENTRY_ERROR_SAMPLE_RATE', 1.0),
|
||
+ tracesSampleRate: readNumberEnv('SENTRY_TRACES_SAMPLE_RATE', 1.0),
|
||
+ replaySessionSampleRate: readNumberEnv('SENTRY_REPLAY_SESSION_SAMPLE_RATE', 0),
|
||
+ replayOnErrorSampleRate: readNumberEnv('SENTRY_REPLAY_ON_ERROR_SAMPLE_RATE', 0),
|
||
+ release: process.env.SENTRY_RELEASE || '',
|
||
+ environment: process.env.SENTRY_ENVIRONMENT || process.env.NODE_ENV || 'production'
|
||
+ },
|
||
+ // 鍏叡閿紙浼氭毚闇插埌瀹㈡埛绔級
|
||
+ public: {
|
||
+ host: process.env.NUXT_PUBLIC_HOST || '',
|
||
+ apiBase: '/api',
|
||
+ oauth: {
|
||
+ github: !!process.env.GITHUB_CLIENT_ID,
|
||
+ casdoor: !!process.env.CASDOOR_CLIENT_ID,
|
||
+ google: !!process.env.GOOGLE_CLIENT_ID,
|
||
+ aggregate: !!process.env.AGGREGATE_OAUTH_APP_ID
|
||
+ },
|
||
+ siteTitle: process.env.NUXT_PUBLIC_SITE_TITLE || '鏍″洯骞挎挱绔欑偣姝岀郴缁?,
|
||
+ siteLogo: process.env.NUXT_PUBLIC_SITE_LOGO || '',
|
||
+ siteDescription:
|
||
+ process.env.NUXT_PUBLIC_SITE_DESCRIPTION || '鏍″洯骞挎挱绔欑偣姝岀郴缁?- 璁╀綘鐨勫0闊宠鍚',
|
||
+ isNetlify: process.env.NETLIFY === 'true',
|
||
+ // SEO 鑷畾涔夐厤缃紙閫氳繃 NUXT_PUBLIC_SEO_CONFIG 娉ㄥ叆 JSON 瀛楃涓诧級
|
||
+ seoConfig: customSeoConfig ?? {},
|
||
+ // 鍥惧舰楠岃瘉鐮佺浉鍏? captcha: {
|
||
+ enabled: (process.env.CAPTCHA_ENABLED || 'false') === 'true',
|
||
+ provider: process.env.CAPTCHA_PROVIDER || 'turnstile',
|
||
+ siteKey: process.env.CAPTCHA_SITE_KEY || ''
|
||
+ },
|
||
+ // PWA 鐩稿叧缁撴瀯锛堟湰鍦颁笉鍚敤妯″潡锛屼絾淇濈暀閰嶇疆椤逛互渚夸笂灞傚簲鐢ㄤ娇鐢級
|
||
+ pwa: {
|
||
+ enabled: (process.env.PWA_ENABLED || 'false') === 'true',
|
||
+ display: process.env.PWA_DISPLAY || 'standalone',
|
||
+ backgroundColor: process.env.PWA_BACKGROUND_COLOR || '#000000',
|
||
+ themeColor: process.env.PWA_THEME_COLOR || '#111111'
|
||
+ },
|
||
+ // 涓婚閰嶇疆
|
||
+ defaultTheme: process.env.NUXT_PUBLIC_DEFAULT_THEME || 'ClassicLight',
|
||
+ enabledThemes: (process.env.NUXT_PUBLIC_ENABLED_THEMES || 'ClassicLight,ModernLight')
|
||
+ .split(',')
|
||
+ .map((s) => s.trim())
|
||
+ .filter(Boolean),
|
||
+ // Sentry 瀹㈡埛绔厤缃紙浠呭叕寮€ DSN 涓庨噰鏍风巼锛? sentry: {
|
||
+ dsn: process.env.SENTRY_DSN || '',
|
||
+ tracesSampleRate: readNumberEnv('SENTRY_TRACES_SAMPLE_RATE', 1.0),
|
||
+ replaySessionSampleRate: readNumberEnv('SENTRY_REPLAY_SESSION_SAMPLE_RATE', 0),
|
||
+ replayOnErrorSampleRate: readNumberEnv('SENTRY_REPLAY_ON_ERROR_SAMPLE_RATE', 0)
|
||
+ }
|
||
+ }
|
||
+ },
|
||
+
|
||
+ // 閰嶇疆鐜鍙橀噺
|
||
+ app: {
|
||
+ head: {
|
||
+ title: process.env.NUXT_PUBLIC_SITE_TITLE || '鏍″洯骞挎挱绔欑偣姝岀郴缁?,
|
||
+ htmlAttrs: { lang: 'zh-CN' },
|
||
+ meta: [
|
||
+ { charset: 'utf-8' },
|
||
+ {
|
||
+ name: 'viewport',
|
||
+ content:
|
||
+ 'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover'
|
||
+ },
|
||
+ {
|
||
+ name: 'description',
|
||
+ content:
|
||
+ process.env.NUXT_PUBLIC_SITE_DESCRIPTION || '鏍″洯骞挎挱绔欑偣姝岀郴缁?- 璁╀綘鐨勫0闊宠鍚'
|
||
+ },
|
||
+ // 绉诲姩绔紭鍖? { name: 'theme-color', content: '#111111' },
|
||
+ {
|
||
+ name: 'x-default-theme',
|
||
+ content: process.env.NUXT_PUBLIC_DEFAULT_THEME || 'ClassicLight'
|
||
+ },
|
||
+ {
|
||
+ name: 'x-enabled-themes',
|
||
+ content: process.env.NUXT_PUBLIC_ENABLED_THEMES || 'ClassicLight,ModernLight'
|
||
+ },
|
||
+ { name: 'apple-mobile-web-app-capable', content: 'yes' },
|
||
+ { name: 'apple-mobile-web-app-status-bar-style', content: 'black-translucent' },
|
||
+ { name: 'apple-mobile-web-app-title', content: 'VoiceHub绠$悊' },
|
||
+ { name: 'mobile-web-app-capable', content: 'yes' },
|
||
+ { name: 'format-detection', content: 'telephone=no' }
|
||
+ ],
|
||
+ script: [
|
||
+ {
|
||
+ type: 'text/javascript',
|
||
+ tagPosition: 'head',
|
||
+ children: [
|
||
+ `(function(){try{`,
|
||
+ ` var k='voicehub:theme', d=document, r=d.documentElement, s=null, eff=null, def=null, list=[];`,
|
||
+ ` try{`,
|
||
+ ` var mt=d.querySelector('meta[name="x-enabled-themes"]');`,
|
||
+ ` if(mt && mt.content){list=String(mt.content).split(',').map(function(x){return x.replace(/^\\s+|\\s+$/g,'')}).filter(Boolean)}`,
|
||
+ ` }catch(e){list=[]}`,
|
||
+ ` try{`,
|
||
+ ` var md=d.querySelector('meta[name="x-default-theme"]');`,
|
||
+ ` if(md && md.content){def=md.content}`,
|
||
+ ` }catch(e){def=null}`,
|
||
+ ` if(!def){def='ClassicLight'}`,
|
||
+ ` if(list.length===0){list=['ClassicLight','ModernLight']}`,
|
||
+ ` function valid(t){`,
|
||
+ ` if(list.indexOf(t)!==-1){return t}`,
|
||
+ ` if(list.indexOf(def)!==-1){return def}`,
|
||
+ ` return list[0]`,
|
||
+ ` }`,
|
||
+ ` try{s=localStorage.getItem(k)}catch(e){s=null}`,
|
||
+ ` if(!s){s=def}`,
|
||
+ ` else{s=valid(s)}`,
|
||
+ ` if(typeof s==='string' && (s==='System'||s==='system')){eff=window.matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light'}`,
|
||
+ ` else if(typeof s==='string'){eff=s.endsWith('Dark')||s==='dark'?'dark':(s.endsWith('Light')||s==='light'?'light':s)}`,
|
||
+ ` else{eff='light'}`,
|
||
+ ` r.setAttribute('data-theme', (typeof s==='string'?s:eff));`,
|
||
+ ` if(eff==='dark'){r.classList.add('dark'); r.classList.remove('light'); r.style.colorScheme='dark'}`,
|
||
+ ` else if(eff==='light'){r.classList.add('light'); r.classList.remove('dark'); r.style.colorScheme='light'}`,
|
||
+ ` else{r.classList.remove('dark','light'); r.style.colorScheme='light dark'}`,
|
||
+ ` try{`,
|
||
+ ` var tm=d.querySelector('meta[name="theme-color"]');`,
|
||
+ ` if(tm){tm.content=(eff==='light'?'#f8fafc':'#111111')}`,
|
||
+ ` }catch(e){}`,
|
||
+ `}catch(e){}})();`
|
||
+ ].join('')
|
||
+ }
|
||
+ ],
|
||
+ link: [
|
||
+ { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
|
||
+ { rel: 'preload', as: 'image', href: '/images/logo.png' },
|
||
+ { rel: 'preload', as: 'image', href: '/images/site-logo.png' },
|
||
+ { rel: 'preload', as: 'image', href: '/images/school-logo-white.png' },
|
||
+ // 浼樺厛鍔犺浇甯歌瀛椾綋锛岀‘淇濋〉闈㈠揩閫熸樉绀? {
|
||
+ rel: 'preload',
|
||
+ as: 'style',
|
||
+ href: 'https://cdn.jsdelivr.net/npm/misans@4.1.0/lib/Normal/MiSans-Regular.min.css'
|
||
+ },
|
||
+ {
|
||
+ rel: 'stylesheet',
|
||
+ href: 'https://cdn.jsdelivr.net/npm/misans@4.1.0/lib/Normal/MiSans-Regular.min.css'
|
||
+ },
|
||
+ // 寤惰繜鍔犺浇鍏朵粬瀛楅噸锛岄伩鍏嶉樆濉為〉闈㈡覆鏌? {
|
||
+ rel: 'preload',
|
||
+ as: 'style',
|
||
+ href: 'https://cdn.jsdelivr.net/npm/misans@4.1.0/lib/Normal/MiSans-Medium.min.css',
|
||
+ onload: "this.onload=null;this.rel='stylesheet'"
|
||
+ },
|
||
+ {
|
||
+ rel: 'preload',
|
||
+ as: 'style',
|
||
+ href: 'https://cdn.jsdelivr.net/npm/misans@4.1.0/lib/Normal/MiSans-Semibold.min.css',
|
||
+ onload: "this.onload=null;this.rel='stylesheet'"
|
||
+ },
|
||
+ {
|
||
+ rel: 'preload',
|
||
+ as: 'style',
|
||
+ href: 'https://cdn.jsdelivr.net/npm/misans@4.1.0/lib/Normal/MiSans-Bold.min.css',
|
||
+ onload: "this.onload=null;this.rel='stylesheet'"
|
||
+ }
|
||
+ ]
|
||
+ }
|
||
+ },
|
||
+
|
||
+ features: {
|
||
+ inlineStyles: false
|
||
+ },
|
||
+
|
||
+ // TypeScript閰嶇疆
|
||
+ typescript: {
|
||
+ strict: true
|
||
+ },
|
||
+
|
||
+ // 鏈嶅姟鍣ㄧ閰嶇疆
|
||
+ nitro: {
|
||
+ compressPublicAssets: true,
|
||
+ preset: process.env.VERCEL
|
||
+ ? 'vercel'
|
||
+ : process.env.NETLIFY
|
||
+ ? 'netlify'
|
||
+ : process.env.NITRO_PRESET || 'node-server',
|
||
+ // 澧炲己閿欒澶勭悊鍜岀ǔ瀹氭€? experimental: {
|
||
+ wasm: true,
|
||
+ asyncContext: true
|
||
+ },
|
||
+ timing: true,
|
||
+ // 澧炲姞璇锋眰瓒呮椂鏃堕棿
|
||
+ routeRules: {
|
||
+ // 瀹屽叏绂佺敤鎵€鏈堿PI璺敱鐨勭紦瀛橈紝纭繚姣忔閮借姹傛暟鎹簱
|
||
+ '/api/**': {
|
||
+ headers: {
|
||
+ 'Cache-Control': 'no-cache, no-store, must-revalidate',
|
||
+ Pragma: 'no-cache',
|
||
+ Expires: '0',
|
||
+ Connection: 'keep-alive'
|
||
+ }
|
||
+ },
|
||
+ // 闈欐€佽祫婧愭枃浠剁紦瀛橀厤缃? '/_nuxt/**': {
|
||
+ headers: {
|
||
+ 'Cache-Control': 'public, max-age=31536000, immutable'
|
||
+ }
|
||
+ },
|
||
+ '/assets/**': {
|
||
+ headers: {
|
||
+ 'Cache-Control': 'public, max-age=31536000, immutable'
|
||
+ }
|
||
+ },
|
||
+ '/favicon.ico': {
|
||
+ headers: {
|
||
+ 'Cache-Control': 'public, max-age=86400'
|
||
+ }
|
||
+ },
|
||
+ // 鍥剧墖銆丆SS銆丣S绛夐潤鎬佽祫婧愮紦瀛? '/**/*.{png,jpg,jpeg,gif,webp,svg,ico}': {
|
||
+ headers: {
|
||
+ 'Cache-Control': 'public, max-age=31536000, immutable'
|
||
+ }
|
||
+ },
|
||
+ '/**/*.{css,js}': {
|
||
+ headers: {
|
||
+ 'Cache-Control': 'public, max-age=31536000, immutable'
|
||
+ }
|
||
+ },
|
||
+ // 璁よ瘉鐩稿叧椤甸潰涓嶇紦瀛? '/login': {
|
||
+ headers: {
|
||
+ 'Cache-Control': 'no-cache, no-store, must-revalidate',
|
||
+ Pragma: 'no-cache',
|
||
+ Expires: '0'
|
||
+ }
|
||
+ },
|
||
+ '/dashboard': {
|
||
+ headers: {
|
||
+ 'Cache-Control': 'no-cache, no-store, must-revalidate',
|
||
+ Pragma: 'no-cache',
|
||
+ Expires: '0'
|
||
+ }
|
||
+ },
|
||
+ '/change-password': {
|
||
+ headers: {
|
||
+ 'Cache-Control': 'no-cache, no-store, must-revalidate',
|
||
+ Pragma: 'no-cache',
|
||
+ Expires: '0'
|
||
+ }
|
||
+ },
|
||
+ '/auth/**': {
|
||
+ headers: {
|
||
+ 'Cache-Control': 'no-cache, no-store, must-revalidate',
|
||
+ Pragma: 'no-cache',
|
||
+ Expires: '0'
|
||
+ }
|
||
+ },
|
||
+ '/notification-settings': {
|
||
+ headers: {
|
||
+ 'Cache-Control': 'no-cache, no-store, must-revalidate',
|
||
+ Pragma: 'no-cache',
|
||
+ Expires: '0'
|
||
+ }
|
||
+ }
|
||
+ },
|
||
+ // 鏍规嵁閮ㄧ讲鐜璋冩暣閰嶇疆
|
||
+ ...(process.env.VERCEL
|
||
+ ? {
|
||
+ // Vercel 鐜锛氫娇鐢ㄦ爣鍑嗛厤缃? }
|
||
+ : process.env.NETLIFY
|
||
+ ? {
|
||
+ // Netlify 鐜锛氱‘淇?Drizzle 姝g‘鎵撳寘
|
||
+ experimental: {
|
||
+ wasm: true
|
||
+ }
|
||
+ }
|
||
+ : {
|
||
+ // 鍏朵粬鐜锛氫娇鐢ㄦ爣鍑嗛厤缃? })
|
||
+ },
|
||
+
|
||
+ // Vite 閰嶇疆
|
||
+ vite: {
|
||
+ build: {
|
||
+ chunkSizeWarningLimit: 2000,
|
||
+ cssCodeSplit: true,
|
||
+ rollupOptions: {
|
||
+ maxParallelFileOps: 2,
|
||
+ output: {
|
||
+ manualChunks(id) {
|
||
+ if (id.includes('node_modules/lucide-vue-next')) {
|
||
+ return 'lucide'
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ },
|
||
+ resolve: {
|
||
+ alias: [
|
||
+ {
|
||
+ find: '@applemusic-like-lyrics/core/style.css',
|
||
+ replacement: fileURLToPath(
|
||
+ new URL('./vendor/amll-core/src/styles/index.css', import.meta.url)
|
||
+ )
|
||
+ },
|
||
+ {
|
||
+ find: '@applemusic-like-lyrics/core',
|
||
+ replacement: fileURLToPath(new URL('./vendor/amll-core/src/index.ts', import.meta.url))
|
||
+ }
|
||
+ ]
|
||
+ },
|
||
+ plugins: [wasm(), glsl()],
|
||
+ optimizeDeps: {
|
||
+ include: ['drizzle-orm'],
|
||
+ exclude: ['@applemusic-like-lyrics/vue', '@applemusic-like-lyrics/lyric']
|
||
+ },
|
||
+ build: {
|
||
+ sourcemap: false,
|
||
+ rollupOptions: {
|
||
+ output: {
|
||
+ manualChunks(id) {
|
||
+ if (!id.includes('node_modules')) return
|
||
+ if (id.includes('lucide-vue-next')) return 'icons'
|
||
+ if (id.includes('@pixi')) return 'pixi'
|
||
+ if (id.includes('@applemusic-like-lyrics')) return 'lyric-engine'
|
||
+ if (id.includes('drizzle-orm') || id.includes('postgres')) return 'database'
|
||
+ if (id.includes('xlsx') || id.includes('jspdf') || id.includes('jszip')) return 'office'
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ },
|
||
+ // 娣诲姞 WASM 鏀寔閰嶇疆
|
||
+ assetsInclude: ['**/*.wasm'],
|
||
+ // SSR閰嶇疆
|
||
+ ssr: {
|
||
+ noExternal: process.env.NETLIFY
|
||
+ ? ['drizzle-orm', 'postgres']
|
||
+ : process.env.VERCEL
|
||
+ ? []
|
||
+ : ['drizzle-orm', 'postgres']
|
||
+ }
|
||
+ }
|
||
+})
|
||
diff --git a/old-nuxt2.config.ts b/old-nuxt2.config.ts
|
||
new file mode 100644
|
||
index 0000000..41bc534
|
||
--- /dev/null
|
||
+++ b/old-nuxt2.config.ts
|
||
@@ -0,0 +1,433 @@
|
||
+import wasm from 'vite-plugin-wasm'
|
||
+import glsl from 'vite-plugin-glsl'
|
||
+import { fileURLToPath } from 'url'
|
||
+import { index, uniqueIndex } from 'drizzle-orm'
|
||
+
|
||
+const customSeoConfig: Record<string, unknown> | null = (() => {
|
||
+ const raw = process.env.NUXT_PUBLIC_SEO_CONFIG
|
||
+ if (!raw) return null
|
||
+ try {
|
||
+ const parsed = JSON.parse(raw)
|
||
+ if (parsed && typeof parsed === 'object') return parsed as Record<string, unknown>
|
||
+ return null
|
||
+ } catch {
|
||
+ return null
|
||
+ }
|
||
+})()
|
||
+
|
||
+function readNumberEnv(name: string, defaultValue: number): number {
|
||
+ const raw = process.env[name]
|
||
+ if (raw === undefined || raw === '') return defaultValue
|
||
+ const num = Number(raw)
|
||
+ return Number.isFinite(num) ? num : defaultValue
|
||
+}
|
||
+
|
||
+// https://nuxt.com/docs/api/configuration/nuxt-config
|
||
+export default defineNuxtConfig({
|
||
+ compatibilityDate: '2026-01-30',
|
||
+ future: {
|
||
+ compatibilityVersion: 4
|
||
+ },
|
||
+ srcDir: 'app',
|
||
+ serverDir: fileURLToPath(new URL('./server', import.meta.url)),
|
||
+ dir: {
|
||
+ public: fileURLToPath(new URL('./public', import.meta.url))
|
||
+ },
|
||
+ devtools: { enabled: process.env.NODE_ENV === 'development' },
|
||
+ devServer: {
|
||
+ host: '0.0.0.0',
|
||
+ port: 3000
|
||
+ },
|
||
+ modules: [
|
||
+ '@nuxtjs/tailwindcss',
|
||
+ ...((process.env.NODE_ENV === 'development' || process.env.npm_lifecycle_event?.includes('lint'))
|
||
+ ? ['@nuxt/eslint']
|
||
+ : []),
|
||
+ ...((process.env.PWA_ENABLED || 'false') === 'true'
|
||
+ ? ['@vite-pwa/nuxt']
|
||
+ : [])
|
||
+ ],
|
||
+
|
||
+ pwa: (process.env.PWA_ENABLED || 'false') === 'true'
|
||
+ ? {
|
||
+ registerType: 'autoUpdate',
|
||
+ manifest: {
|
||
+ name: process.env.NUXT_PUBLIC_SITE_TITLE || '鏍″洯骞挎挱绔欑偣姝岀郴缁?,
|
||
+ short_name: process.env.NUXT_PUBLIC_SITE_TITLE || 'VoiceHub',
|
||
+ description: process.env.NUXT_PUBLIC_SITE_DESCRIPTION || '鏍″洯骞挎挱绔欑偣姝岀郴缁?,
|
||
+ display: (process.env.PWA_DISPLAY as any) || 'standalone',
|
||
+ background_color: process.env.PWA_BACKGROUND_COLOR || '#000000',
|
||
+ theme_color: process.env.PWA_THEME_COLOR || '#111111',
|
||
+ icons: [
|
||
+ {
|
||
+ src: '/images/logo.png',
|
||
+ sizes: '192x192',
|
||
+ type: 'image/png'
|
||
+ },
|
||
+ {
|
||
+ src: '/images/logo.png',
|
||
+ sizes: '512x512',
|
||
+ type: 'image/png'
|
||
+ }
|
||
+ ]
|
||
+ },
|
||
+ workbox: {
|
||
+ navigateFallback: '/',
|
||
+ globPatterns: ['**/*.{js,css,html,png,jpg,jpeg,svg,ico,webp,woff2}']
|
||
+ },
|
||
+ client: {
|
||
+ installPrompt: true,
|
||
+ periodicSyncForUpdates: 3600
|
||
+ },
|
||
+ devOptions: {
|
||
+ enabled: process.env.NODE_ENV === 'development'
|
||
+ }
|
||
+ }
|
||
+ : {},
|
||
+
|
||
+ // 寮曞叆鍏ㄥ眬CSS
|
||
+ css: [
|
||
+ '~/assets/css/variables.css',
|
||
+ '~/assets/css/components.css',
|
||
+ '~/assets/css/main.css',
|
||
+ '~/assets/css/transitions.css',
|
||
+ '~/assets/css/mobile-admin.css',
|
||
+ '~/assets/css/print-fix.css',
|
||
+ '~/assets/css/sf-pro-icons.css'
|
||
+ ],
|
||
+
|
||
+ build: {
|
||
+ transpile: []
|
||
+ },
|
||
+
|
||
+ // 瀹為獙鎬т紭鍖栧姛鑳? experimental: {
|
||
+ payloadExtraction: true,
|
||
+ renderJsonPayloads: true,
|
||
+ viewTransition: true
|
||
+ },
|
||
+
|
||
+ // 閰嶇疆杩愯鏃堕厤缃? runtimeConfig: {
|
||
+ // 鏈嶅姟鍣ㄧ鏈夐敭锛堜笉浼氭毚闇插埌瀹㈡埛绔級
|
||
+ jwtSecret: process.env.JWT_SECRET || 'your-secret-key',
|
||
+ // Redis閰嶇疆锛堝彲閫夛級
|
||
+ redisUrl: process.env.REDIS_URL || '',
|
||
+ redisKeyPrefix: process.env.REDIS_KEY_PREFIX || '',
|
||
+ // Sentry 鏈嶅姟绔厤缃紙涓嶄細鏆撮湶鍒板鎴风锛? sentry: {
|
||
+ serverDsn: process.env.SENTRY_SERVER_DSN || process.env.SENTRY_DSN || '',
|
||
+ dsn: process.env.SENTRY_DSN || '',
|
||
+ errorSampleRate: readNumberEnv('SENTRY_ERROR_SAMPLE_RATE', 1.0),
|
||
+ tracesSampleRate: readNumberEnv('SENTRY_TRACES_SAMPLE_RATE', 1.0),
|
||
+ replaySessionSampleRate: readNumberEnv('SENTRY_REPLAY_SESSION_SAMPLE_RATE', 0),
|
||
+ replayOnErrorSampleRate: readNumberEnv('SENTRY_REPLAY_ON_ERROR_SAMPLE_RATE', 0),
|
||
+ release: process.env.SENTRY_RELEASE || '',
|
||
+ environment: process.env.SENTRY_ENVIRONMENT || process.env.NODE_ENV || 'production'
|
||
+ },
|
||
+ // 鍏叡閿紙浼氭毚闇插埌瀹㈡埛绔級
|
||
+ public: {
|
||
+ host: process.env.NUXT_PUBLIC_HOST || '',
|
||
+ apiBase: '/api',
|
||
+ oauth: {
|
||
+ github: !!process.env.GITHUB_CLIENT_ID,
|
||
+ casdoor: !!process.env.CASDOOR_CLIENT_ID,
|
||
+ google: !!process.env.GOOGLE_CLIENT_ID,
|
||
+ aggregate: !!process.env.AGGREGATE_OAUTH_APP_ID
|
||
+ },
|
||
+ siteTitle: process.env.NUXT_PUBLIC_SITE_TITLE || '鏍″洯骞挎挱绔欑偣姝岀郴缁?,
|
||
+ siteLogo: process.env.NUXT_PUBLIC_SITE_LOGO || '',
|
||
+ siteDescription:
|
||
+ process.env.NUXT_PUBLIC_SITE_DESCRIPTION || '鏍″洯骞挎挱绔欑偣姝岀郴缁?- 璁╀綘鐨勫0闊宠鍚',
|
||
+ isNetlify: process.env.NETLIFY === 'true',
|
||
+ // SEO 鑷畾涔夐厤缃紙閫氳繃 NUXT_PUBLIC_SEO_CONFIG 娉ㄥ叆 JSON 瀛楃涓诧級
|
||
+ seoConfig: customSeoConfig ?? {},
|
||
+ // 鍥惧舰楠岃瘉鐮佺浉鍏? captcha: {
|
||
+ enabled: (process.env.CAPTCHA_ENABLED || 'false') === 'true',
|
||
+ provider: process.env.CAPTCHA_PROVIDER || 'turnstile',
|
||
+ siteKey: process.env.CAPTCHA_SITE_KEY || ''
|
||
+ },
|
||
+ // PWA 鐩稿叧缁撴瀯锛堟湰鍦颁笉鍚敤妯″潡锛屼絾淇濈暀閰嶇疆椤逛互渚夸笂灞傚簲鐢ㄤ娇鐢級
|
||
+ pwa: {
|
||
+ enabled: (process.env.PWA_ENABLED || 'false') === 'true',
|
||
+ display: process.env.PWA_DISPLAY || 'standalone',
|
||
+ backgroundColor: process.env.PWA_BACKGROUND_COLOR || '#000000',
|
||
+ themeColor: process.env.PWA_THEME_COLOR || '#111111'
|
||
+ },
|
||
+ // 涓婚閰嶇疆
|
||
+ defaultTheme: process.env.NUXT_PUBLIC_DEFAULT_THEME || 'ClassicLight',
|
||
+ enabledThemes: (process.env.NUXT_PUBLIC_ENABLED_THEMES || 'ClassicLight,ModernLight')
|
||
+ .split(',')
|
||
+ .map((s) => s.trim())
|
||
+ .filter(Boolean),
|
||
+ // Sentry 瀹㈡埛绔厤缃紙浠呭叕寮€ DSN 涓庨噰鏍风巼锛? sentry: {
|
||
+ dsn: process.env.SENTRY_DSN || '',
|
||
+ tracesSampleRate: readNumberEnv('SENTRY_TRACES_SAMPLE_RATE', 1.0),
|
||
+ replaySessionSampleRate: readNumberEnv('SENTRY_REPLAY_SESSION_SAMPLE_RATE', 0),
|
||
+ replayOnErrorSampleRate: readNumberEnv('SENTRY_REPLAY_ON_ERROR_SAMPLE_RATE', 0)
|
||
+ }
|
||
+ }
|
||
+ },
|
||
+
|
||
+ // 閰嶇疆鐜鍙橀噺
|
||
+ app: {
|
||
+ head: {
|
||
+ title: process.env.NUXT_PUBLIC_SITE_TITLE || '鏍″洯骞挎挱绔欑偣姝岀郴缁?,
|
||
+ htmlAttrs: { lang: 'zh-CN' },
|
||
+ meta: [
|
||
+ { charset: 'utf-8' },
|
||
+ {
|
||
+ name: 'viewport',
|
||
+ content:
|
||
+ 'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover'
|
||
+ },
|
||
+ {
|
||
+ name: 'description',
|
||
+ content:
|
||
+ process.env.NUXT_PUBLIC_SITE_DESCRIPTION || '鏍″洯骞挎挱绔欑偣姝岀郴缁?- 璁╀綘鐨勫0闊宠鍚'
|
||
+ },
|
||
+ // 绉诲姩绔紭鍖? { name: 'theme-color', content: '#111111' },
|
||
+ {
|
||
+ name: 'x-default-theme',
|
||
+ content: process.env.NUXT_PUBLIC_DEFAULT_THEME || 'System'
|
||
+ },
|
||
+ { name: 'apple-mobile-web-app-capable', content: 'yes' },
|
||
+ { name: 'apple-mobile-web-app-status-bar-style', content: 'black-translucent' },
|
||
+ { name: 'apple-mobile-web-app-title', content: 'VoiceHub绠$悊' },
|
||
+ { name: 'mobile-web-app-capable', content: 'yes' },
|
||
+ { name: 'format-detection', content: 'telephone=no' }
|
||
+ ],
|
||
+ script: [
|
||
+ {
|
||
+ type: 'text/javascript',
|
||
+ tagPosition: 'head',
|
||
+ children: [
|
||
+ `(function(){try{`,
|
||
+ ` var k='voicehub:theme', d=document, r=d.documentElement, s=null, eff=null;`,
|
||
+ ` try{s=localStorage.getItem(k)}catch(e){s=null}`,
|
||
+ ` if(!s){`,
|
||
+ ` try{`,
|
||
+ ` var meta=document.querySelector('meta[name="x-default-theme"]');`,
|
||
+ ` if(meta && meta.content){s=meta.content}`,
|
||
+ ` }catch(e){s=null}`,
|
||
+ ` if(!s){s='System'}`,
|
||
+ ` }`,
|
||
+ ` if(s==='System'||s==='system'){eff=window.matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light'}`,
|
||
+ ` else if(typeof s==='string'){eff=s.endsWith('Dark')||s==='dark'?'dark':(s.endsWith('Light')||s==='light'?'light':s)}`,
|
||
+ ` else{eff='dark'}`,
|
||
+ ` r.setAttribute('data-theme', (typeof s==='string'?s:eff));`,
|
||
+ ` if(eff==='dark'){r.classList.add('dark'); r.classList.remove('light'); r.style.colorScheme='dark'}`,
|
||
+ ` else if(eff==='light'){r.classList.add('light'); r.classList.remove('dark'); r.style.colorScheme='light'}`,
|
||
+ ` else{r.classList.remove('dark','light'); r.style.colorScheme='light dark'}`,
|
||
+ ` try{`,
|
||
+ ` var tm=d.querySelector('meta[name="theme-color"]');`,
|
||
+ ` if(tm){tm.content=(eff==='light'?'#f8fafc':'#111111')}`,
|
||
+ ` }catch(e){}`,
|
||
+ `}catch(e){}})();`
|
||
+ ].join('')
|
||
+ }
|
||
+ ],
|
||
+ link: [
|
||
+ { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
|
||
+ { rel: 'preload', as: 'image', href: '/images/logo.png' },
|
||
+ { rel: 'preload', as: 'image', href: '/images/site-logo.png' },
|
||
+ { rel: 'preload', as: 'image', href: '/images/school-logo-white.png' },
|
||
+ // 浼樺厛鍔犺浇甯歌瀛椾綋锛岀‘淇濋〉闈㈠揩閫熸樉绀? {
|
||
+ rel: 'preload',
|
||
+ as: 'style',
|
||
+ href: 'https://cdn.jsdelivr.net/npm/misans@4.1.0/lib/Normal/MiSans-Regular.min.css'
|
||
+ },
|
||
+ {
|
||
+ rel: 'stylesheet',
|
||
+ href: 'https://cdn.jsdelivr.net/npm/misans@4.1.0/lib/Normal/MiSans-Regular.min.css'
|
||
+ },
|
||
+ // 寤惰繜鍔犺浇鍏朵粬瀛楅噸锛岄伩鍏嶉樆濉為〉闈㈡覆鏌? {
|
||
+ rel: 'preload',
|
||
+ as: 'style',
|
||
+ href: 'https://cdn.jsdelivr.net/npm/misans@4.1.0/lib/Normal/MiSans-Medium.min.css',
|
||
+ onload: "this.onload=null;this.rel='stylesheet'"
|
||
+ },
|
||
+ {
|
||
+ rel: 'preload',
|
||
+ as: 'style',
|
||
+ href: 'https://cdn.jsdelivr.net/npm/misans@4.1.0/lib/Normal/MiSans-Semibold.min.css',
|
||
+ onload: "this.onload=null;this.rel='stylesheet'"
|
||
+ },
|
||
+ {
|
||
+ rel: 'preload',
|
||
+ as: 'style',
|
||
+ href: 'https://cdn.jsdelivr.net/npm/misans@4.1.0/lib/Normal/MiSans-Bold.min.css',
|
||
+ onload: "this.onload=null;this.rel='stylesheet'"
|
||
+ }
|
||
+ ]
|
||
+ }
|
||
+ },
|
||
+
|
||
+ features: {
|
||
+ inlineStyles: false
|
||
+ },
|
||
+
|
||
+ // TypeScript閰嶇疆
|
||
+ typescript: {
|
||
+ strict: true
|
||
+ },
|
||
+
|
||
+ // 鏈嶅姟鍣ㄧ閰嶇疆
|
||
+ nitro: {
|
||
+ compressPublicAssets: true,
|
||
+ preset: process.env.VERCEL
|
||
+ ? 'vercel'
|
||
+ : process.env.NETLIFY
|
||
+ ? 'netlify'
|
||
+ : process.env.NITRO_PRESET || 'node-server',
|
||
+ // 澧炲己閿欒澶勭悊鍜岀ǔ瀹氭€? experimental: {
|
||
+ wasm: true,
|
||
+ asyncContext: true
|
||
+ },
|
||
+ timing: true,
|
||
+ // 澧炲姞璇锋眰瓒呮椂鏃堕棿
|
||
+ routeRules: {
|
||
+ // 瀹屽叏绂佺敤鎵€鏈堿PI璺敱鐨勭紦瀛橈紝纭繚姣忔閮借姹傛暟鎹簱
|
||
+ '/api/**': {
|
||
+ headers: {
|
||
+ 'Cache-Control': 'no-cache, no-store, must-revalidate',
|
||
+ Pragma: 'no-cache',
|
||
+ Expires: '0',
|
||
+ Connection: 'keep-alive'
|
||
+ }
|
||
+ },
|
||
+ // 闈欐€佽祫婧愭枃浠剁紦瀛橀厤缃? '/_nuxt/**': {
|
||
+ headers: {
|
||
+ 'Cache-Control': 'public, max-age=31536000, immutable'
|
||
+ }
|
||
+ },
|
||
+ '/assets/**': {
|
||
+ headers: {
|
||
+ 'Cache-Control': 'public, max-age=31536000, immutable'
|
||
+ }
|
||
+ },
|
||
+ '/favicon.ico': {
|
||
+ headers: {
|
||
+ 'Cache-Control': 'public, max-age=86400'
|
||
+ }
|
||
+ },
|
||
+ // 鍥剧墖銆丆SS銆丣S绛夐潤鎬佽祫婧愮紦瀛? '/**/*.{png,jpg,jpeg,gif,webp,svg,ico}': {
|
||
+ headers: {
|
||
+ 'Cache-Control': 'public, max-age=31536000, immutable'
|
||
+ }
|
||
+ },
|
||
+ '/**/*.{css,js}': {
|
||
+ headers: {
|
||
+ 'Cache-Control': 'public, max-age=31536000, immutable'
|
||
+ }
|
||
+ },
|
||
+ // 璁よ瘉鐩稿叧椤甸潰涓嶇紦瀛? '/login': {
|
||
+ headers: {
|
||
+ 'Cache-Control': 'no-cache, no-store, must-revalidate',
|
||
+ Pragma: 'no-cache',
|
||
+ Expires: '0'
|
||
+ }
|
||
+ },
|
||
+ '/dashboard': {
|
||
+ headers: {
|
||
+ 'Cache-Control': 'no-cache, no-store, must-revalidate',
|
||
+ Pragma: 'no-cache',
|
||
+ Expires: '0'
|
||
+ }
|
||
+ },
|
||
+ '/change-password': {
|
||
+ headers: {
|
||
+ 'Cache-Control': 'no-cache, no-store, must-revalidate',
|
||
+ Pragma: 'no-cache',
|
||
+ Expires: '0'
|
||
+ }
|
||
+ },
|
||
+ '/auth/**': {
|
||
+ headers: {
|
||
+ 'Cache-Control': 'no-cache, no-store, must-revalidate',
|
||
+ Pragma: 'no-cache',
|
||
+ Expires: '0'
|
||
+ }
|
||
+ },
|
||
+ '/notification-settings': {
|
||
+ headers: {
|
||
+ 'Cache-Control': 'no-cache, no-store, must-revalidate',
|
||
+ Pragma: 'no-cache',
|
||
+ Expires: '0'
|
||
+ }
|
||
+ }
|
||
+ },
|
||
+ // 鏍规嵁閮ㄧ讲鐜璋冩暣閰嶇疆
|
||
+ ...(process.env.VERCEL
|
||
+ ? {
|
||
+ // Vercel 鐜锛氫娇鐢ㄦ爣鍑嗛厤缃? }
|
||
+ : process.env.NETLIFY
|
||
+ ? {
|
||
+ // Netlify 鐜锛氱‘淇?Drizzle 姝g‘鎵撳寘
|
||
+ experimental: {
|
||
+ wasm: true
|
||
+ }
|
||
+ }
|
||
+ : {
|
||
+ // 鍏朵粬鐜锛氫娇鐢ㄦ爣鍑嗛厤缃? })
|
||
+ },
|
||
+
|
||
+ // Vite 閰嶇疆
|
||
+ vite: {
|
||
+ build: {
|
||
+ chunkSizeWarningLimit: 2000,
|
||
+ cssCodeSplit: true,
|
||
+ rollupOptions: {
|
||
+ maxParallelFileOps: 2,
|
||
+ output: {
|
||
+ manualChunks(id) {
|
||
+ if (id.includes('node_modules/lucide-vue-next')) {
|
||
+ return 'lucide'
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ },
|
||
+ resolve: {
|
||
+ alias: [
|
||
+ {
|
||
+ find: '@applemusic-like-lyrics/core/style.css',
|
||
+ replacement: fileURLToPath(
|
||
+ new URL('./vendor/amll-core/src/styles/index.css', import.meta.url)
|
||
+ )
|
||
+ },
|
||
+ {
|
||
+ find: '@applemusic-like-lyrics/core',
|
||
+ replacement: fileURLToPath(new URL('./vendor/amll-core/src/index.ts', import.meta.url))
|
||
+ }
|
||
+ ]
|
||
+ },
|
||
+ plugins: [wasm(), glsl()],
|
||
+ optimizeDeps: {
|
||
+ include: ['drizzle-orm'],
|
||
+ exclude: ['@applemusic-like-lyrics/vue', '@applemusic-like-lyrics/lyric']
|
||
+ },
|
||
+ build: {
|
||
+ sourcemap: false,
|
||
+ rollupOptions: {
|
||
+ output: {
|
||
+ manualChunks(id) {
|
||
+ if (!id.includes('node_modules')) return
|
||
+ if (id.includes('lucide-vue-next')) return 'icons'
|
||
+ if (id.includes('@pixi')) return 'pixi'
|
||
+ if (id.includes('@applemusic-like-lyrics')) return 'lyric-engine'
|
||
+ if (id.includes('drizzle-orm') || id.includes('postgres')) return 'database'
|
||
+ if (id.includes('xlsx') || id.includes('jspdf') || id.includes('jszip')) return 'office'
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ },
|
||
+ // 娣诲姞 WASM 鏀寔閰嶇疆
|
||
+ assetsInclude: ['**/*.wasm'],
|
||
+ // SSR閰嶇疆
|
||
+ ssr: {
|
||
+ noExternal: process.env.NETLIFY
|
||
+ ? ['drizzle-orm', 'postgres']
|
||
+ : process.env.VERCEL
|
||
+ ? []
|
||
+ : ['drizzle-orm', 'postgres']
|
||
+ }
|
||
+ }
|
||
+})
|
||
diff --git a/old-variables.css b/old-variables.css
|
||
new file mode 100644
|
||
index 0000000..3fe2829
|
||
--- /dev/null
|
||
+++ b/old-variables.css
|
||
@@ -0,0 +1,556 @@
|
||
+/* 鍏ㄥ眬CSS鍙橀噺 - 缁熶竴閰嶈壊鏂规 */
|
||
+:root {
|
||
+ /* 涓昏壊璋?*/
|
||
+ --primary: #3b82f6;
|
||
+ --primary-hover: #2563eb;
|
||
+ --primary-light: rgba(59, 130, 246, 0.1);
|
||
+ --primary-border: rgba(59, 130, 246, 0.2);
|
||
+
|
||
+ /* 鎴愬姛鑹?*/
|
||
+ --success: #10b981;
|
||
+ --success-hover: #059669;
|
||
+ --success-light: rgba(16, 185, 129, 0.1);
|
||
+ --success-border: rgba(16, 185, 129, 0.2);
|
||
+
|
||
+ /* 璀﹀憡鑹?*/
|
||
+ --warning: #f59e0b;
|
||
+ --warning-hover: #d97706;
|
||
+ --warning-light: rgba(245, 158, 11, 0.1);
|
||
+ --warning-border: rgba(245, 158, 11, 0.2);
|
||
+
|
||
+ /* 閿欒鑹?*/
|
||
+ --error: #ef4444;
|
||
+ --error-hover: #dc2626;
|
||
+ --error-light: rgba(239, 68, 68, 0.1);
|
||
+ --error-border: rgba(239, 68, 68, 0.2);
|
||
+
|
||
+ /* 淇℃伅鑹?*/
|
||
+ --info: #3b82f6;
|
||
+ --info-hover: #2563eb;
|
||
+ --info-light: rgba(59, 130, 246, 0.1);
|
||
+ --info-border: rgba(59, 130, 246, 0.2);
|
||
+
|
||
+ /* 鑳屾櫙鑹?*/
|
||
+ --bg-primary: #111111;
|
||
+ --bg-secondary: #1a1a1a;
|
||
+ --bg-tertiary: #2a2a2a;
|
||
+ --bg-quaternary: #3a3a3a;
|
||
+ --bg-hover: #1f1f1f;
|
||
+
|
||
+ /* 鏂囧瓧棰滆壊 */
|
||
+ --text-primary: #ffffff;
|
||
+ --text-secondary: #cccccc;
|
||
+ --text-tertiary: #888888;
|
||
+ --text-quaternary: #666666;
|
||
+ --text-disabled: #444444;
|
||
+
|
||
+ /* 杈规棰滆壊 */
|
||
+ --border-primary: #1f1f1f;
|
||
+ --border-secondary: #2a2a2a;
|
||
+ --border-tertiary: #3a3a3a;
|
||
+ --border-quaternary: #4a4a4a;
|
||
+
|
||
+ /* 闃村奖 */
|
||
+ --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||
+ --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||
+ --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
|
||
+ --shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.1);
|
||
+
|
||
+ /* 鍦嗚 */
|
||
+ --radius-sm: 4px;
|
||
+ --radius-md: 6px;
|
||
+ --radius-lg: 8px;
|
||
+ --radius-xl: 12px;
|
||
+ --radius-2xl: 16px;
|
||
+
|
||
+ /* 闂磋窛 */
|
||
+ --spacing-xs: 4px;
|
||
+ --spacing-sm: 8px;
|
||
+ --spacing-md: 12px;
|
||
+ --spacing-lg: 16px;
|
||
+ --spacing-xl: 20px;
|
||
+ --spacing-2xl: 24px;
|
||
+ --spacing-3xl: 32px;
|
||
+
|
||
+ /* 瀛椾綋澶у皬 */
|
||
+ --text-xs: 12px;
|
||
+ --text-sm: 14px;
|
||
+ --text-base: 16px;
|
||
+ --text-lg: 18px;
|
||
+ --text-xl: 20px;
|
||
+ --text-2xl: 24px;
|
||
+ --text-3xl: 30px;
|
||
+
|
||
+ /* 瀛椾綋绮楃粏 */
|
||
+ --font-normal: 400;
|
||
+ --font-medium: 500;
|
||
+ --font-semibold: 600;
|
||
+ --font-bold: 700;
|
||
+
|
||
+ /* 杩囨浮鍔ㄧ敾 */
|
||
+ --transition-fast: 0.15s ease;
|
||
+ --transition-normal: 0.2s ease;
|
||
+ --transition-slow: 0.3s ease;
|
||
+
|
||
+ /* Z-index灞傜骇 */
|
||
+ --z-dropdown: 100;
|
||
+ --z-sticky: 200;
|
||
+ --z-fixed: 300;
|
||
+ --z-modal-backdrop: 400;
|
||
+ --z-modal: 500;
|
||
+ --z-popover: 600;
|
||
+ --z-tooltip: 700;
|
||
+ --z-toast: 800;
|
||
+
|
||
+ /* 鐗规畩鐘舵€侀鑹?*/
|
||
+ --status-pending: #fbbf24;
|
||
+ --status-pending-light: rgba(251, 191, 36, 0.1);
|
||
+ --status-approved: #10b981;
|
||
+ --status-approved-light: rgba(16, 185, 129, 0.1);
|
||
+ --status-played: #6b7280;
|
||
+ --status-played-light: rgba(107, 114, 128, 0.1);
|
||
+
|
||
+ /* 鎶曠エ鐩稿叧棰滆壊 */
|
||
+ --vote-heart: #ef4444;
|
||
+ --vote-heart-hover: #dc2626;
|
||
+ --vote-count: var(--text-tertiary);
|
||
+
|
||
+ /* 鎷栨嫿鐘舵€侀鑹?*/
|
||
+ --drag-over: var(--primary-light);
|
||
+ --drag-over-border: var(--primary);
|
||
+ --dragging-opacity: 0.5;
|
||
+
|
||
+ /* 琛ㄦ牸棰滆壊 */
|
||
+ --table-header-bg: var(--bg-tertiary);
|
||
+ --table-row-hover: var(--bg-hover);
|
||
+ --table-border: var(--border-secondary);
|
||
+ --table-selected: var(--primary-light);
|
||
+
|
||
+ /* 鍗$墖棰滆壊 */
|
||
+ --card-bg: var(--bg-secondary);
|
||
+ --card-border: var(--border-secondary);
|
||
+ --card-hover-border: var(--border-tertiary);
|
||
+ --card-shadow: var(--shadow-md);
|
||
+
|
||
+ /* 鎸夐挳棰滆壊 */
|
||
+ --btn-primary-bg: var(--primary);
|
||
+ --btn-primary-hover: var(--primary-hover);
|
||
+ --btn-primary-text: var(--text-primary);
|
||
+ --btn-primary-border: var(--primary-border);
|
||
+
|
||
+ --btn-secondary-bg: #3a3a3a;
|
||
+ --btn-secondary-hover: #4a4a4a;
|
||
+ --btn-secondary-text: var(--text-primary);
|
||
+ --btn-secondary-border: #555555;
|
||
+
|
||
+ --btn-success-bg: var(--success);
|
||
+ --btn-success-hover: var(--success-hover);
|
||
+ --btn-success-text: var(--text-primary);
|
||
+ --btn-success-border: var(--success-border);
|
||
+
|
||
+ --btn-warning-bg: var(--warning);
|
||
+ --btn-warning-hover: var(--warning-hover);
|
||
+ --btn-warning-text: var(--text-primary);
|
||
+ --btn-warning-border: var(--warning-border);
|
||
+
|
||
+ --btn-error-bg: var(--error);
|
||
+ --btn-error-hover: var(--error-hover);
|
||
+ --btn-error-text: var(--text-primary);
|
||
+ --btn-error-border: var(--error-border);
|
||
+
|
||
+ --btn-disabled-bg: var(--bg-tertiary);
|
||
+ --btn-disabled-text: var(--text-disabled);
|
||
+
|
||
+ /* 杈撳叆妗嗛鑹?*/
|
||
+ --input-bg: var(--bg-tertiary);
|
||
+ --input-border: var(--border-tertiary);
|
||
+ --input-border-focus: var(--primary);
|
||
+ --input-text: var(--text-primary);
|
||
+ --input-placeholder: var(--text-quaternary);
|
||
+ --input-shadow-focus: 0 0 0 3px var(--primary-light);
|
||
+
|
||
+ /* 妯℃€佹棰滆壊 */
|
||
+ --modal-backdrop: rgba(0, 0, 0, 0.7);
|
||
+ --modal-bg: var(--bg-secondary);
|
||
+ --modal-border: var(--border-secondary);
|
||
+ --modal-header-border: var(--border-secondary);
|
||
+ --modal-footer-border: var(--border-secondary);
|
||
+
|
||
+ /* 閫氱煡棰滆壊 */
|
||
+ --notification-success-bg: var(--success-light);
|
||
+ --notification-success-border: var(--success-border);
|
||
+ --notification-success-text: var(--success);
|
||
+
|
||
+ --notification-warning-bg: var(--warning-light);
|
||
+ --notification-warning-border: var(--warning-border);
|
||
+ --notification-warning-text: var(--warning);
|
||
+
|
||
+ --notification-error-bg: var(--error-light);
|
||
+ --notification-error-border: var(--error-border);
|
||
+ --notification-error-text: var(--error);
|
||
+
|
||
+ --notification-info-bg: var(--info-light);
|
||
+ --notification-info-border: var(--info-border);
|
||
+ --notification-info-text: var(--info);
|
||
+
|
||
+ /* 鍔犺浇鍔ㄧ敾棰滆壊 */
|
||
+ --spinner-primary: var(--primary);
|
||
+ --spinner-secondary: var(--bg-tertiary);
|
||
+
|
||
+ /* 婊氬姩鏉¢鑹?*/
|
||
+ --scrollbar-track: var(--bg-tertiary);
|
||
+ --scrollbar-thumb: var(--bg-quaternary);
|
||
+ --scrollbar-thumb-hover: #4a4a4a;
|
||
+}
|
||
+
|
||
+:root[data-theme='light'],
|
||
+:root[data-theme='ClassicLight'],
|
||
+:root[data-theme='ModernLight'] {
|
||
+ --bg-primary: #f8fafc;
|
||
+ --bg-secondary: #f1f5f9;
|
||
+ --bg-tertiary: #e2e8f0;
|
||
+ --bg-quaternary: #cbd5e1;
|
||
+ --bg-hover: #e2e8f0;
|
||
+
|
||
+ --text-primary: #0f172a;
|
||
+ --text-secondary: #334155;
|
||
+ --text-tertiary: #475569;
|
||
+ --text-quaternary: #64748b;
|
||
+ --text-disabled: #94a3b8;
|
||
+
|
||
+ --border-primary: #e2e8f0;
|
||
+ --border-secondary: #cbd5e1;
|
||
+ --border-tertiary: #94a3b8;
|
||
+ --border-quaternary: #64748b;
|
||
+
|
||
+ --modal-backdrop: rgba(0, 0, 0, 0.4);
|
||
+ --scrollbar-thumb-hover: #94a3b8;
|
||
+
|
||
+ --btn-secondary-bg: #f1f5f9;
|
||
+ --btn-secondary-hover: #e2e8f0;
|
||
+ --btn-secondary-text: #0f172a;
|
||
+ --btn-secondary-border: #cbd5e1;
|
||
+
|
||
+ --card-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
|
||
+}
|
||
+
|
||
+:root[data-theme='ClassicLight'] {
|
||
+ --primary: #1e40af;
|
||
+ --primary-hover: #1e3a8a;
|
||
+ --primary-light: rgba(30, 64, 175, 0.08);
|
||
+ --primary-border: rgba(30, 64, 175, 0.15);
|
||
+
|
||
+ --bg-primary: #ffffff;
|
||
+ --bg-secondary: #f5f7fa;
|
||
+ --bg-tertiary: #edf0f5;
|
||
+ --bg-quaternary: #d9dee7;
|
||
+ --bg-hover: #f0f3f8;
|
||
+
|
||
+ --success: #059669;
|
||
+ --success-hover: #047857;
|
||
+ --success-light: rgba(5, 150, 105, 0.08);
|
||
+ --success-border: rgba(5, 150, 105, 0.15);
|
||
+
|
||
+ --warning: #d97706;
|
||
+ --warning-hover: #b45309;
|
||
+ --warning-light: rgba(217, 119, 6, 0.08);
|
||
+ --warning-border: rgba(217, 119, 6, 0.15);
|
||
+
|
||
+ --error: #dc2626;
|
||
+ --error-hover: #b91c1c;
|
||
+ --error-light: rgba(220, 38, 38, 0.08);
|
||
+ --error-border: rgba(220, 38, 38, 0.15);
|
||
+
|
||
+ --info: #2563eb;
|
||
+ --info-hover: #1d4ed8;
|
||
+ --info-light: rgba(37, 99, 235, 0.08);
|
||
+ --info-border: rgba(37, 99, 235, 0.15);
|
||
+
|
||
+ --text-primary: #1a2332;
|
||
+ --text-secondary: #4a5568;
|
||
+ --text-tertiary: #6b7280;
|
||
+ --text-quaternary: #9ca3af;
|
||
+ --text-disabled: #c5cbd3;
|
||
+
|
||
+ --border-primary: #e5e7eb;
|
||
+ --border-secondary: #d1d5db;
|
||
+ --border-tertiary: #9ca3af;
|
||
+ --border-quaternary: #6b7280;
|
||
+
|
||
+ --input-bg: #ffffff;
|
||
+ --input-border: #d1d5db;
|
||
+ --input-border-focus: #1e40af;
|
||
+ --input-text: #1a2332;
|
||
+ --input-placeholder: #9ca3af;
|
||
+ --input-shadow-focus: 0 0 0 3px rgba(30, 64, 175, 0.1);
|
||
+
|
||
+ --card-bg: #ffffff;
|
||
+ --card-border: #e5e7eb;
|
||
+ --card-hover-border: #d1d5db;
|
||
+
|
||
+ --table-header-bg: #f5f7fa;
|
||
+ --table-row-hover: #f9fafb;
|
||
+ --table-border: #e5e7eb;
|
||
+ --table-selected: rgba(30, 64, 175, 0.06);
|
||
+
|
||
+ --scrollbar-track: #f1f5f9;
|
||
+ --scrollbar-thumb: #cbd5e1;
|
||
+ --scrollbar-thumb-hover: #94a3b8;
|
||
+
|
||
+ --status-pending: #ca8a04;
|
||
+ --status-pending-light: rgba(202, 138, 4, 0.08);
|
||
+ --status-approved: #059669;
|
||
+ --status-approved-light: rgba(5, 150, 105, 0.08);
|
||
+ --status-played: #6b7280;
|
||
+ --status-played-light: rgba(107, 114, 128, 0.08);
|
||
+
|
||
+ --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.04);
|
||
+ --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.06), 0 2px 4px -2px rgba(0, 0, 0, 0.04);
|
||
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.06), 0 4px 6px -4px rgba(0, 0, 0, 0.04);
|
||
+ --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.06), 0 8px 10px -6px rgba(0, 0, 0, 0.04);
|
||
+
|
||
+ --radius-sm: 3px;
|
||
+ --radius-md: 5px;
|
||
+ --radius-lg: 6px;
|
||
+ --radius-xl: 8px;
|
||
+ --radius-2xl: 10px;
|
||
+}
|
||
+
|
||
+:root[data-theme='ModernLight'] {
|
||
+ --primary: #4f46e5;
|
||
+ --primary-hover: #4338ca;
|
||
+ --primary-light: rgba(79, 70, 229, 0.1);
|
||
+ --primary-border: rgba(79, 70, 229, 0.2);
|
||
+
|
||
+ --bg-primary: #fafafa;
|
||
+ --bg-secondary: #f4f4f5;
|
||
+ --bg-tertiary: #e4e4e7;
|
||
+ --bg-quaternary: #d4d4d8;
|
||
+ --bg-hover: #eeeeef;
|
||
+
|
||
+ --success: #16a34a;
|
||
+ --success-hover: #15803d;
|
||
+ --success-light: rgba(22, 163, 74, 0.1);
|
||
+ --success-border: rgba(22, 163, 74, 0.2);
|
||
+
|
||
+ --warning: #ea580c;
|
||
+ --warning-hover: #c2410c;
|
||
+ --warning-light: rgba(234, 88, 12, 0.1);
|
||
+ --warning-border: rgba(234, 88, 12, 0.2);
|
||
+
|
||
+ --error: #e11d48;
|
||
+ --error-hover: #be123c;
|
||
+ --error-light: rgba(225, 29, 72, 0.1);
|
||
+ --error-border: rgba(225, 29, 72, 0.2);
|
||
+
|
||
+ --info: #0ea5e9;
|
||
+ --info-hover: #0284c7;
|
||
+ --info-light: rgba(14, 165, 233, 0.1);
|
||
+ --info-border: rgba(14, 165, 233, 0.2);
|
||
+
|
||
+ --text-primary: #09090b;
|
||
+ --text-secondary: #3f3f46;
|
||
+ --text-tertiary: #71717a;
|
||
+ --text-quaternary: #a1a1aa;
|
||
+ --text-disabled: #d4d4d8;
|
||
+
|
||
+ --border-primary: #e4e4e7;
|
||
+ --border-secondary: #d4d4d8;
|
||
+ --border-tertiary: #a1a1aa;
|
||
+ --border-quaternary: #71717a;
|
||
+
|
||
+ --input-bg: #ffffff;
|
||
+ --input-border: #e4e4e7;
|
||
+ --input-border-focus: #4f46e5;
|
||
+ --input-text: #09090b;
|
||
+ --input-placeholder: #a1a1aa;
|
||
+ --input-shadow-focus: 0 0 0 3px rgba(79, 70, 229, 0.12);
|
||
+
|
||
+ --card-bg: #ffffff;
|
||
+ --card-border: #e4e4e7;
|
||
+ --card-hover-border: #d4d4d8;
|
||
+
|
||
+ --table-header-bg: #f4f4f5;
|
||
+ --table-row-hover: #fafafa;
|
||
+ --table-border: #e4e4e7;
|
||
+ --table-selected: rgba(79, 70, 229, 0.08);
|
||
+
|
||
+ --scrollbar-track: #f4f4f5;
|
||
+ --scrollbar-thumb: #d4d4d8;
|
||
+ --scrollbar-thumb-hover: #a1a1aa;
|
||
+
|
||
+ --status-pending: #eab308;
|
||
+ --status-pending-light: rgba(234, 179, 8, 0.12);
|
||
+ --status-approved: #22c55e;
|
||
+ --status-approved-light: rgba(34, 197, 94, 0.12);
|
||
+ --status-played: #71717a;
|
||
+ --status-played-light: rgba(113, 113, 122, 0.12);
|
||
+
|
||
+ --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.03);
|
||
+ --shadow-md: 0 2px 8px -2px rgba(0, 0, 0, 0.05), 0 1px 3px 0 rgba(0, 0, 0, 0.03);
|
||
+ --shadow-lg: 0 8px 24px -4px rgba(0, 0, 0, 0.06), 0 2px 8px -4px rgba(0, 0, 0, 0.04);
|
||
+ --shadow-xl: 0 16px 40px -8px rgba(0, 0, 0, 0.08), 0 4px 16px -8px rgba(0, 0, 0, 0.05);
|
||
+
|
||
+ --radius-sm: 4px;
|
||
+ --radius-md: 6px;
|
||
+ --radius-lg: 8px;
|
||
+ --radius-xl: 10px;
|
||
+ --radius-2xl: 12px;
|
||
+}
|
||
+
|
||
+/* 娣辫壊涓婚鐗瑰畾璋冩暣 */
|
||
+@media (prefers-color-scheme: dark) {
|
||
+ :root {
|
||
+ /* 鍦ㄦ繁鑹叉ā寮忎笅鍙互杩涜寰皟 */
|
||
+ }
|
||
+}
|
||
+
|
||
+/* 楂樺姣斿害妯″紡鏀寔 */
|
||
+@media (prefers-contrast: high) {
|
||
+ :root {
|
||
+ --border-primary: #444444;
|
||
+ --border-secondary: #555555;
|
||
+ --border-tertiary: #666666;
|
||
+ --text-tertiary: #aaaaaa;
|
||
+ --text-quaternary: #888888;
|
||
+ }
|
||
+}
|
||
+
|
||
+/* 鍑忓皯鍔ㄧ敾妯″紡鏀寔 */
|
||
+@media (prefers-reduced-motion: reduce) {
|
||
+ :root {
|
||
+ --transition-fast: 0s;
|
||
+ --transition-normal: 0s;
|
||
+ --transition-slow: 0s;
|
||
+ }
|
||
+}
|
||
+
|
||
+/* 鍏ㄥ眬婊氬姩鏉℃牱寮?*/
|
||
+* {
|
||
+ scrollbar-width: thin;
|
||
+ scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
|
||
+}
|
||
+
|
||
+*::-webkit-scrollbar {
|
||
+ width: 8px;
|
||
+ height: 8px;
|
||
+}
|
||
+
|
||
+*::-webkit-scrollbar-track {
|
||
+ background: var(--scrollbar-track);
|
||
+}
|
||
+
|
||
+*::-webkit-scrollbar-thumb {
|
||
+ background: var(--scrollbar-thumb);
|
||
+ border-radius: var(--radius-md);
|
||
+}
|
||
+
|
||
+*::-webkit-scrollbar-thumb:hover {
|
||
+ background: var(--scrollbar-thumb-hover);
|
||
+}
|
||
+
|
||
+/* 鍏ㄥ眬閫夋嫨鏂囨湰鏍峰紡 */
|
||
+::selection {
|
||
+ background: var(--primary-light);
|
||
+ color: var(--text-primary);
|
||
+}
|
||
+
|
||
+/* 鍏ㄥ眬鐒︾偣鏍峰紡 */
|
||
+*:focus {
|
||
+ outline: 2px solid var(--primary);
|
||
+ outline-offset: 2px;
|
||
+}
|
||
+
|
||
+*:focus:not(:focus-visible) {
|
||
+ outline: none;
|
||
+}
|
||
+
|
||
+/* 鍏ㄥ眬绂佺敤鐘舵€佹牱寮?*/
|
||
+*:disabled {
|
||
+ cursor: not-allowed;
|
||
+ opacity: 0.6;
|
||
+}
|
||
+
|
||
+/* 鍏ㄥ眬閾炬帴鏍峰紡 */
|
||
+a {
|
||
+ color: var(--primary);
|
||
+ text-decoration: none;
|
||
+ transition: color var(--transition-normal);
|
||
+}
|
||
+
|
||
+a:hover {
|
||
+ color: var(--primary-hover);
|
||
+}
|
||
+
|
||
+/* 鍏ㄥ眬鎸夐挳閲嶇疆 */
|
||
+button {
|
||
+ border: none;
|
||
+ background: none;
|
||
+ cursor: pointer;
|
||
+ font-family: inherit;
|
||
+}
|
||
+
|
||
+* {
|
||
+ -webkit-tap-highlight-color: transparent;
|
||
+}
|
||
+
|
||
+button,
|
||
+a,
|
||
+input,
|
||
+textarea {
|
||
+ -webkit-tap-highlight-color: transparent;
|
||
+}
|
||
+
|
||
+@media (hover: none) and (pointer: coarse) {
|
||
+ *:focus {
|
||
+ outline: none !important;
|
||
+ }
|
||
+ button,
|
||
+ a {
|
||
+ -webkit-user-select: none;
|
||
+ user-select: none;
|
||
+ }
|
||
+}
|
||
+
|
||
+/* 鍏ㄥ眬杈撳叆妗嗛噸缃?*/
|
||
+input,
|
||
+textarea,
|
||
+select {
|
||
+ font-family: inherit;
|
||
+ font-size: inherit;
|
||
+}
|
||
+
|
||
+/* 鍏ㄥ眬鍥剧墖鏍峰紡 */
|
||
+img {
|
||
+ max-width: 100%;
|
||
+ height: auto;
|
||
+}
|
||
+
|
||
+/* 鍏ㄥ眬琛ㄦ牸鏍峰紡 */
|
||
+table {
|
||
+ border-collapse: collapse;
|
||
+ width: 100%;
|
||
+}
|
||
+
|
||
+/* 鍏ㄥ眬浠g爜鏍峰紡 */
|
||
+code,
|
||
+pre {
|
||
+ font-family: 'Fira Code', 'Monaco', 'Consolas', monospace;
|
||
+ background: var(--bg-tertiary);
|
||
+ border-radius: var(--radius-sm);
|
||
+}
|
||
+
|
||
+code {
|
||
+ padding: 2px 4px;
|
||
+ font-size: 0.875em;
|
||
+}
|
||
+
|
||
+pre {
|
||
+ padding: var(--spacing-lg);
|
||
+ overflow-x: auto;
|
||
+}
|
||
+
|
||
+pre code {
|
||
+ padding: 0;
|
||
+ background: none;
|
||
+}
|
||
diff --git a/old-variables2.css b/old-variables2.css
|
||
new file mode 100644
|
||
index 0000000..3fe2829
|
||
--- /dev/null
|
||
+++ b/old-variables2.css
|
||
@@ -0,0 +1,556 @@
|
||
+/* 鍏ㄥ眬CSS鍙橀噺 - 缁熶竴閰嶈壊鏂规 */
|
||
+:root {
|
||
+ /* 涓昏壊璋?*/
|
||
+ --primary: #3b82f6;
|
||
+ --primary-hover: #2563eb;
|
||
+ --primary-light: rgba(59, 130, 246, 0.1);
|
||
+ --primary-border: rgba(59, 130, 246, 0.2);
|
||
+
|
||
+ /* 鎴愬姛鑹?*/
|
||
+ --success: #10b981;
|
||
+ --success-hover: #059669;
|
||
+ --success-light: rgba(16, 185, 129, 0.1);
|
||
+ --success-border: rgba(16, 185, 129, 0.2);
|
||
+
|
||
+ /* 璀﹀憡鑹?*/
|
||
+ --warning: #f59e0b;
|
||
+ --warning-hover: #d97706;
|
||
+ --warning-light: rgba(245, 158, 11, 0.1);
|
||
+ --warning-border: rgba(245, 158, 11, 0.2);
|
||
+
|
||
+ /* 閿欒鑹?*/
|
||
+ --error: #ef4444;
|
||
+ --error-hover: #dc2626;
|
||
+ --error-light: rgba(239, 68, 68, 0.1);
|
||
+ --error-border: rgba(239, 68, 68, 0.2);
|
||
+
|
||
+ /* 淇℃伅鑹?*/
|
||
+ --info: #3b82f6;
|
||
+ --info-hover: #2563eb;
|
||
+ --info-light: rgba(59, 130, 246, 0.1);
|
||
+ --info-border: rgba(59, 130, 246, 0.2);
|
||
+
|
||
+ /* 鑳屾櫙鑹?*/
|
||
+ --bg-primary: #111111;
|
||
+ --bg-secondary: #1a1a1a;
|
||
+ --bg-tertiary: #2a2a2a;
|
||
+ --bg-quaternary: #3a3a3a;
|
||
+ --bg-hover: #1f1f1f;
|
||
+
|
||
+ /* 鏂囧瓧棰滆壊 */
|
||
+ --text-primary: #ffffff;
|
||
+ --text-secondary: #cccccc;
|
||
+ --text-tertiary: #888888;
|
||
+ --text-quaternary: #666666;
|
||
+ --text-disabled: #444444;
|
||
+
|
||
+ /* 杈规棰滆壊 */
|
||
+ --border-primary: #1f1f1f;
|
||
+ --border-secondary: #2a2a2a;
|
||
+ --border-tertiary: #3a3a3a;
|
||
+ --border-quaternary: #4a4a4a;
|
||
+
|
||
+ /* 闃村奖 */
|
||
+ --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||
+ --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||
+ --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
|
||
+ --shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.1);
|
||
+
|
||
+ /* 鍦嗚 */
|
||
+ --radius-sm: 4px;
|
||
+ --radius-md: 6px;
|
||
+ --radius-lg: 8px;
|
||
+ --radius-xl: 12px;
|
||
+ --radius-2xl: 16px;
|
||
+
|
||
+ /* 闂磋窛 */
|
||
+ --spacing-xs: 4px;
|
||
+ --spacing-sm: 8px;
|
||
+ --spacing-md: 12px;
|
||
+ --spacing-lg: 16px;
|
||
+ --spacing-xl: 20px;
|
||
+ --spacing-2xl: 24px;
|
||
+ --spacing-3xl: 32px;
|
||
+
|
||
+ /* 瀛椾綋澶у皬 */
|
||
+ --text-xs: 12px;
|
||
+ --text-sm: 14px;
|
||
+ --text-base: 16px;
|
||
+ --text-lg: 18px;
|
||
+ --text-xl: 20px;
|
||
+ --text-2xl: 24px;
|
||
+ --text-3xl: 30px;
|
||
+
|
||
+ /* 瀛椾綋绮楃粏 */
|
||
+ --font-normal: 400;
|
||
+ --font-medium: 500;
|
||
+ --font-semibold: 600;
|
||
+ --font-bold: 700;
|
||
+
|
||
+ /* 杩囨浮鍔ㄧ敾 */
|
||
+ --transition-fast: 0.15s ease;
|
||
+ --transition-normal: 0.2s ease;
|
||
+ --transition-slow: 0.3s ease;
|
||
+
|
||
+ /* Z-index灞傜骇 */
|
||
+ --z-dropdown: 100;
|
||
+ --z-sticky: 200;
|
||
+ --z-fixed: 300;
|
||
+ --z-modal-backdrop: 400;
|
||
+ --z-modal: 500;
|
||
+ --z-popover: 600;
|
||
+ --z-tooltip: 700;
|
||
+ --z-toast: 800;
|
||
+
|
||
+ /* 鐗规畩鐘舵€侀鑹?*/
|
||
+ --status-pending: #fbbf24;
|
||
+ --status-pending-light: rgba(251, 191, 36, 0.1);
|
||
+ --status-approved: #10b981;
|
||
+ --status-approved-light: rgba(16, 185, 129, 0.1);
|
||
+ --status-played: #6b7280;
|
||
+ --status-played-light: rgba(107, 114, 128, 0.1);
|
||
+
|
||
+ /* 鎶曠エ鐩稿叧棰滆壊 */
|
||
+ --vote-heart: #ef4444;
|
||
+ --vote-heart-hover: #dc2626;
|
||
+ --vote-count: var(--text-tertiary);
|
||
+
|
||
+ /* 鎷栨嫿鐘舵€侀鑹?*/
|
||
+ --drag-over: var(--primary-light);
|
||
+ --drag-over-border: var(--primary);
|
||
+ --dragging-opacity: 0.5;
|
||
+
|
||
+ /* 琛ㄦ牸棰滆壊 */
|
||
+ --table-header-bg: var(--bg-tertiary);
|
||
+ --table-row-hover: var(--bg-hover);
|
||
+ --table-border: var(--border-secondary);
|
||
+ --table-selected: var(--primary-light);
|
||
+
|
||
+ /* 鍗$墖棰滆壊 */
|
||
+ --card-bg: var(--bg-secondary);
|
||
+ --card-border: var(--border-secondary);
|
||
+ --card-hover-border: var(--border-tertiary);
|
||
+ --card-shadow: var(--shadow-md);
|
||
+
|
||
+ /* 鎸夐挳棰滆壊 */
|
||
+ --btn-primary-bg: var(--primary);
|
||
+ --btn-primary-hover: var(--primary-hover);
|
||
+ --btn-primary-text: var(--text-primary);
|
||
+ --btn-primary-border: var(--primary-border);
|
||
+
|
||
+ --btn-secondary-bg: #3a3a3a;
|
||
+ --btn-secondary-hover: #4a4a4a;
|
||
+ --btn-secondary-text: var(--text-primary);
|
||
+ --btn-secondary-border: #555555;
|
||
+
|
||
+ --btn-success-bg: var(--success);
|
||
+ --btn-success-hover: var(--success-hover);
|
||
+ --btn-success-text: var(--text-primary);
|
||
+ --btn-success-border: var(--success-border);
|
||
+
|
||
+ --btn-warning-bg: var(--warning);
|
||
+ --btn-warning-hover: var(--warning-hover);
|
||
+ --btn-warning-text: var(--text-primary);
|
||
+ --btn-warning-border: var(--warning-border);
|
||
+
|
||
+ --btn-error-bg: var(--error);
|
||
+ --btn-error-hover: var(--error-hover);
|
||
+ --btn-error-text: var(--text-primary);
|
||
+ --btn-error-border: var(--error-border);
|
||
+
|
||
+ --btn-disabled-bg: var(--bg-tertiary);
|
||
+ --btn-disabled-text: var(--text-disabled);
|
||
+
|
||
+ /* 杈撳叆妗嗛鑹?*/
|
||
+ --input-bg: var(--bg-tertiary);
|
||
+ --input-border: var(--border-tertiary);
|
||
+ --input-border-focus: var(--primary);
|
||
+ --input-text: var(--text-primary);
|
||
+ --input-placeholder: var(--text-quaternary);
|
||
+ --input-shadow-focus: 0 0 0 3px var(--primary-light);
|
||
+
|
||
+ /* 妯℃€佹棰滆壊 */
|
||
+ --modal-backdrop: rgba(0, 0, 0, 0.7);
|
||
+ --modal-bg: var(--bg-secondary);
|
||
+ --modal-border: var(--border-secondary);
|
||
+ --modal-header-border: var(--border-secondary);
|
||
+ --modal-footer-border: var(--border-secondary);
|
||
+
|
||
+ /* 閫氱煡棰滆壊 */
|
||
+ --notification-success-bg: var(--success-light);
|
||
+ --notification-success-border: var(--success-border);
|
||
+ --notification-success-text: var(--success);
|
||
+
|
||
+ --notification-warning-bg: var(--warning-light);
|
||
+ --notification-warning-border: var(--warning-border);
|
||
+ --notification-warning-text: var(--warning);
|
||
+
|
||
+ --notification-error-bg: var(--error-light);
|
||
+ --notification-error-border: var(--error-border);
|
||
+ --notification-error-text: var(--error);
|
||
+
|
||
+ --notification-info-bg: var(--info-light);
|
||
+ --notification-info-border: var(--info-border);
|
||
+ --notification-info-text: var(--info);
|
||
+
|
||
+ /* 鍔犺浇鍔ㄧ敾棰滆壊 */
|
||
+ --spinner-primary: var(--primary);
|
||
+ --spinner-secondary: var(--bg-tertiary);
|
||
+
|
||
+ /* 婊氬姩鏉¢鑹?*/
|
||
+ --scrollbar-track: var(--bg-tertiary);
|
||
+ --scrollbar-thumb: var(--bg-quaternary);
|
||
+ --scrollbar-thumb-hover: #4a4a4a;
|
||
+}
|
||
+
|
||
+:root[data-theme='light'],
|
||
+:root[data-theme='ClassicLight'],
|
||
+:root[data-theme='ModernLight'] {
|
||
+ --bg-primary: #f8fafc;
|
||
+ --bg-secondary: #f1f5f9;
|
||
+ --bg-tertiary: #e2e8f0;
|
||
+ --bg-quaternary: #cbd5e1;
|
||
+ --bg-hover: #e2e8f0;
|
||
+
|
||
+ --text-primary: #0f172a;
|
||
+ --text-secondary: #334155;
|
||
+ --text-tertiary: #475569;
|
||
+ --text-quaternary: #64748b;
|
||
+ --text-disabled: #94a3b8;
|
||
+
|
||
+ --border-primary: #e2e8f0;
|
||
+ --border-secondary: #cbd5e1;
|
||
+ --border-tertiary: #94a3b8;
|
||
+ --border-quaternary: #64748b;
|
||
+
|
||
+ --modal-backdrop: rgba(0, 0, 0, 0.4);
|
||
+ --scrollbar-thumb-hover: #94a3b8;
|
||
+
|
||
+ --btn-secondary-bg: #f1f5f9;
|
||
+ --btn-secondary-hover: #e2e8f0;
|
||
+ --btn-secondary-text: #0f172a;
|
||
+ --btn-secondary-border: #cbd5e1;
|
||
+
|
||
+ --card-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
|
||
+}
|
||
+
|
||
+:root[data-theme='ClassicLight'] {
|
||
+ --primary: #1e40af;
|
||
+ --primary-hover: #1e3a8a;
|
||
+ --primary-light: rgba(30, 64, 175, 0.08);
|
||
+ --primary-border: rgba(30, 64, 175, 0.15);
|
||
+
|
||
+ --bg-primary: #ffffff;
|
||
+ --bg-secondary: #f5f7fa;
|
||
+ --bg-tertiary: #edf0f5;
|
||
+ --bg-quaternary: #d9dee7;
|
||
+ --bg-hover: #f0f3f8;
|
||
+
|
||
+ --success: #059669;
|
||
+ --success-hover: #047857;
|
||
+ --success-light: rgba(5, 150, 105, 0.08);
|
||
+ --success-border: rgba(5, 150, 105, 0.15);
|
||
+
|
||
+ --warning: #d97706;
|
||
+ --warning-hover: #b45309;
|
||
+ --warning-light: rgba(217, 119, 6, 0.08);
|
||
+ --warning-border: rgba(217, 119, 6, 0.15);
|
||
+
|
||
+ --error: #dc2626;
|
||
+ --error-hover: #b91c1c;
|
||
+ --error-light: rgba(220, 38, 38, 0.08);
|
||
+ --error-border: rgba(220, 38, 38, 0.15);
|
||
+
|
||
+ --info: #2563eb;
|
||
+ --info-hover: #1d4ed8;
|
||
+ --info-light: rgba(37, 99, 235, 0.08);
|
||
+ --info-border: rgba(37, 99, 235, 0.15);
|
||
+
|
||
+ --text-primary: #1a2332;
|
||
+ --text-secondary: #4a5568;
|
||
+ --text-tertiary: #6b7280;
|
||
+ --text-quaternary: #9ca3af;
|
||
+ --text-disabled: #c5cbd3;
|
||
+
|
||
+ --border-primary: #e5e7eb;
|
||
+ --border-secondary: #d1d5db;
|
||
+ --border-tertiary: #9ca3af;
|
||
+ --border-quaternary: #6b7280;
|
||
+
|
||
+ --input-bg: #ffffff;
|
||
+ --input-border: #d1d5db;
|
||
+ --input-border-focus: #1e40af;
|
||
+ --input-text: #1a2332;
|
||
+ --input-placeholder: #9ca3af;
|
||
+ --input-shadow-focus: 0 0 0 3px rgba(30, 64, 175, 0.1);
|
||
+
|
||
+ --card-bg: #ffffff;
|
||
+ --card-border: #e5e7eb;
|
||
+ --card-hover-border: #d1d5db;
|
||
+
|
||
+ --table-header-bg: #f5f7fa;
|
||
+ --table-row-hover: #f9fafb;
|
||
+ --table-border: #e5e7eb;
|
||
+ --table-selected: rgba(30, 64, 175, 0.06);
|
||
+
|
||
+ --scrollbar-track: #f1f5f9;
|
||
+ --scrollbar-thumb: #cbd5e1;
|
||
+ --scrollbar-thumb-hover: #94a3b8;
|
||
+
|
||
+ --status-pending: #ca8a04;
|
||
+ --status-pending-light: rgba(202, 138, 4, 0.08);
|
||
+ --status-approved: #059669;
|
||
+ --status-approved-light: rgba(5, 150, 105, 0.08);
|
||
+ --status-played: #6b7280;
|
||
+ --status-played-light: rgba(107, 114, 128, 0.08);
|
||
+
|
||
+ --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.04);
|
||
+ --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.06), 0 2px 4px -2px rgba(0, 0, 0, 0.04);
|
||
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.06), 0 4px 6px -4px rgba(0, 0, 0, 0.04);
|
||
+ --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.06), 0 8px 10px -6px rgba(0, 0, 0, 0.04);
|
||
+
|
||
+ --radius-sm: 3px;
|
||
+ --radius-md: 5px;
|
||
+ --radius-lg: 6px;
|
||
+ --radius-xl: 8px;
|
||
+ --radius-2xl: 10px;
|
||
+}
|
||
+
|
||
+:root[data-theme='ModernLight'] {
|
||
+ --primary: #4f46e5;
|
||
+ --primary-hover: #4338ca;
|
||
+ --primary-light: rgba(79, 70, 229, 0.1);
|
||
+ --primary-border: rgba(79, 70, 229, 0.2);
|
||
+
|
||
+ --bg-primary: #fafafa;
|
||
+ --bg-secondary: #f4f4f5;
|
||
+ --bg-tertiary: #e4e4e7;
|
||
+ --bg-quaternary: #d4d4d8;
|
||
+ --bg-hover: #eeeeef;
|
||
+
|
||
+ --success: #16a34a;
|
||
+ --success-hover: #15803d;
|
||
+ --success-light: rgba(22, 163, 74, 0.1);
|
||
+ --success-border: rgba(22, 163, 74, 0.2);
|
||
+
|
||
+ --warning: #ea580c;
|
||
+ --warning-hover: #c2410c;
|
||
+ --warning-light: rgba(234, 88, 12, 0.1);
|
||
+ --warning-border: rgba(234, 88, 12, 0.2);
|
||
+
|
||
+ --error: #e11d48;
|
||
+ --error-hover: #be123c;
|
||
+ --error-light: rgba(225, 29, 72, 0.1);
|
||
+ --error-border: rgba(225, 29, 72, 0.2);
|
||
+
|
||
+ --info: #0ea5e9;
|
||
+ --info-hover: #0284c7;
|
||
+ --info-light: rgba(14, 165, 233, 0.1);
|
||
+ --info-border: rgba(14, 165, 233, 0.2);
|
||
+
|
||
+ --text-primary: #09090b;
|
||
+ --text-secondary: #3f3f46;
|
||
+ --text-tertiary: #71717a;
|
||
+ --text-quaternary: #a1a1aa;
|
||
+ --text-disabled: #d4d4d8;
|
||
+
|
||
+ --border-primary: #e4e4e7;
|
||
+ --border-secondary: #d4d4d8;
|
||
+ --border-tertiary: #a1a1aa;
|
||
+ --border-quaternary: #71717a;
|
||
+
|
||
+ --input-bg: #ffffff;
|
||
+ --input-border: #e4e4e7;
|
||
+ --input-border-focus: #4f46e5;
|
||
+ --input-text: #09090b;
|
||
+ --input-placeholder: #a1a1aa;
|
||
+ --input-shadow-focus: 0 0 0 3px rgba(79, 70, 229, 0.12);
|
||
+
|
||
+ --card-bg: #ffffff;
|
||
+ --card-border: #e4e4e7;
|
||
+ --card-hover-border: #d4d4d8;
|
||
+
|
||
+ --table-header-bg: #f4f4f5;
|
||
+ --table-row-hover: #fafafa;
|
||
+ --table-border: #e4e4e7;
|
||
+ --table-selected: rgba(79, 70, 229, 0.08);
|
||
+
|
||
+ --scrollbar-track: #f4f4f5;
|
||
+ --scrollbar-thumb: #d4d4d8;
|
||
+ --scrollbar-thumb-hover: #a1a1aa;
|
||
+
|
||
+ --status-pending: #eab308;
|
||
+ --status-pending-light: rgba(234, 179, 8, 0.12);
|
||
+ --status-approved: #22c55e;
|
||
+ --status-approved-light: rgba(34, 197, 94, 0.12);
|
||
+ --status-played: #71717a;
|
||
+ --status-played-light: rgba(113, 113, 122, 0.12);
|
||
+
|
||
+ --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.03);
|
||
+ --shadow-md: 0 2px 8px -2px rgba(0, 0, 0, 0.05), 0 1px 3px 0 rgba(0, 0, 0, 0.03);
|
||
+ --shadow-lg: 0 8px 24px -4px rgba(0, 0, 0, 0.06), 0 2px 8px -4px rgba(0, 0, 0, 0.04);
|
||
+ --shadow-xl: 0 16px 40px -8px rgba(0, 0, 0, 0.08), 0 4px 16px -8px rgba(0, 0, 0, 0.05);
|
||
+
|
||
+ --radius-sm: 4px;
|
||
+ --radius-md: 6px;
|
||
+ --radius-lg: 8px;
|
||
+ --radius-xl: 10px;
|
||
+ --radius-2xl: 12px;
|
||
+}
|
||
+
|
||
+/* 娣辫壊涓婚鐗瑰畾璋冩暣 */
|
||
+@media (prefers-color-scheme: dark) {
|
||
+ :root {
|
||
+ /* 鍦ㄦ繁鑹叉ā寮忎笅鍙互杩涜寰皟 */
|
||
+ }
|
||
+}
|
||
+
|
||
+/* 楂樺姣斿害妯″紡鏀寔 */
|
||
+@media (prefers-contrast: high) {
|
||
+ :root {
|
||
+ --border-primary: #444444;
|
||
+ --border-secondary: #555555;
|
||
+ --border-tertiary: #666666;
|
||
+ --text-tertiary: #aaaaaa;
|
||
+ --text-quaternary: #888888;
|
||
+ }
|
||
+}
|
||
+
|
||
+/* 鍑忓皯鍔ㄧ敾妯″紡鏀寔 */
|
||
+@media (prefers-reduced-motion: reduce) {
|
||
+ :root {
|
||
+ --transition-fast: 0s;
|
||
+ --transition-normal: 0s;
|
||
+ --transition-slow: 0s;
|
||
+ }
|
||
+}
|
||
+
|
||
+/* 鍏ㄥ眬婊氬姩鏉℃牱寮?*/
|
||
+* {
|
||
+ scrollbar-width: thin;
|
||
+ scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
|
||
+}
|
||
+
|
||
+*::-webkit-scrollbar {
|
||
+ width: 8px;
|
||
+ height: 8px;
|
||
+}
|
||
+
|
||
+*::-webkit-scrollbar-track {
|
||
+ background: var(--scrollbar-track);
|
||
+}
|
||
+
|
||
+*::-webkit-scrollbar-thumb {
|
||
+ background: var(--scrollbar-thumb);
|
||
+ border-radius: var(--radius-md);
|
||
+}
|
||
+
|
||
+*::-webkit-scrollbar-thumb:hover {
|
||
+ background: var(--scrollbar-thumb-hover);
|
||
+}
|
||
+
|
||
+/* 鍏ㄥ眬閫夋嫨鏂囨湰鏍峰紡 */
|
||
+::selection {
|
||
+ background: var(--primary-light);
|
||
+ color: var(--text-primary);
|
||
+}
|
||
+
|
||
+/* 鍏ㄥ眬鐒︾偣鏍峰紡 */
|
||
+*:focus {
|
||
+ outline: 2px solid var(--primary);
|
||
+ outline-offset: 2px;
|
||
+}
|
||
+
|
||
+*:focus:not(:focus-visible) {
|
||
+ outline: none;
|
||
+}
|
||
+
|
||
+/* 鍏ㄥ眬绂佺敤鐘舵€佹牱寮?*/
|
||
+*:disabled {
|
||
+ cursor: not-allowed;
|
||
+ opacity: 0.6;
|
||
+}
|
||
+
|
||
+/* 鍏ㄥ眬閾炬帴鏍峰紡 */
|
||
+a {
|
||
+ color: var(--primary);
|
||
+ text-decoration: none;
|
||
+ transition: color var(--transition-normal);
|
||
+}
|
||
+
|
||
+a:hover {
|
||
+ color: var(--primary-hover);
|
||
+}
|
||
+
|
||
+/* 鍏ㄥ眬鎸夐挳閲嶇疆 */
|
||
+button {
|
||
+ border: none;
|
||
+ background: none;
|
||
+ cursor: pointer;
|
||
+ font-family: inherit;
|
||
+}
|
||
+
|
||
+* {
|
||
+ -webkit-tap-highlight-color: transparent;
|
||
+}
|
||
+
|
||
+button,
|
||
+a,
|
||
+input,
|
||
+textarea {
|
||
+ -webkit-tap-highlight-color: transparent;
|
||
+}
|
||
+
|
||
+@media (hover: none) and (pointer: coarse) {
|
||
+ *:focus {
|
||
+ outline: none !important;
|
||
+ }
|
||
+ button,
|
||
+ a {
|
||
+ -webkit-user-select: none;
|
||
+ user-select: none;
|
||
+ }
|
||
+}
|
||
+
|
||
+/* 鍏ㄥ眬杈撳叆妗嗛噸缃?*/
|
||
+input,
|
||
+textarea,
|
||
+select {
|
||
+ font-family: inherit;
|
||
+ font-size: inherit;
|
||
+}
|
||
+
|
||
+/* 鍏ㄥ眬鍥剧墖鏍峰紡 */
|
||
+img {
|
||
+ max-width: 100%;
|
||
+ height: auto;
|
||
+}
|
||
+
|
||
+/* 鍏ㄥ眬琛ㄦ牸鏍峰紡 */
|
||
+table {
|
||
+ border-collapse: collapse;
|
||
+ width: 100%;
|
||
+}
|
||
+
|
||
+/* 鍏ㄥ眬浠g爜鏍峰紡 */
|
||
+code,
|
||
+pre {
|
||
+ font-family: 'Fira Code', 'Monaco', 'Consolas', monospace;
|
||
+ background: var(--bg-tertiary);
|
||
+ border-radius: var(--radius-sm);
|
||
+}
|
||
+
|
||
+code {
|
||
+ padding: 2px 4px;
|
||
+ font-size: 0.875em;
|
||
+}
|
||
+
|
||
+pre {
|
||
+ padding: var(--spacing-lg);
|
||
+ overflow-x: auto;
|
||
+}
|
||
+
|
||
+pre code {
|
||
+ padding: 0;
|
||
+ background: none;
|
||
+}
|
||
--
|
||
2.45.1.windows.1
|
||
|