From 357876a716d27ffca434befa358a784f771d2a16 Mon Sep 17 00:00:00 2001
From: HenryDu8133 <813367384@qq.com>
Date: Sat, 19 Sep 2026 00:43:46 +0800
Subject: [PATCH] =?UTF-8?q?fix(ui+permission):=20=E7=A7=BB=E9=99=A4?=
=?UTF-8?q?=E8=81=94=E5=90=88=E6=8A=95=E7=A8=BF=20/=20emoji=E6=8D=A2SVG=20?=
=?UTF-8?q?/=20=E4=BF=AE=E5=A4=8D=E7=A7=BB=E5=8A=A8=E7=AB=AF=E6=B5=85?=
=?UTF-8?q?=E8=89=B2=E9=80=82=E9=85=8D=20/=20=E5=B7=B2=E6=8E=92=E6=9C=9F?=
=?UTF-8?q?=E6=98=BE=E7=A4=BA=E6=97=A5=E6=9C=9F=20/=20=E9=9A=90=E8=97=8F.e?=
=?UTF-8?q?nv=E6=8F=90=E7=A4=BA=20/=20=E5=85=AC=E5=BC=80=E6=8E=92=E6=9C=9F?=
=?UTF-8?q?=E6=A1=A3=E6=9C=9F=E6=B8=B8=E5=AE=A2=E8=AE=BF=E9=97=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
具体改动:
1. feat(投稿表单): 移除 RequestForm.vue 联合投稿功能整套模板+状态+payload+CSS(10处残留)
2. feat(图标): Icon.vue 新增 sparkles/star 图标; 首页档期卡片📅🎵✨和排期列表空状态🎵📅换成 lucide SVG Icon
3. fix(浅色适配): ScheduleList.vue 日期选择弹窗桌面端+移动端(content/header/h3/close-btn/item)全部改为 bg-primary + var text + indigo 主色, 修复竖屏选择日期标题白字看不见
4. feat(歌曲列表): SongList.vue scheduled-tag 内联追加 formatScheduleDate, 徽章+日期双胶囊显示
5. fix(登录): OAuthButtons.vue showPlaceholderHint 强制 false, 隐藏虚线框 .env 配置提示
6. fix(权限): server/middleware/auth.ts + auth-route-policy.ts 双白名单同步追加 /api/expected-play-dates GET 公共访问, 修复未登录 Authentication expired 401
---
app/components/Auth/OAuthButtons.vue | 2 +-
app/components/Songs/RequestForm.vue | 155 --------------------------
app/components/Songs/ScheduleList.vue | 53 +++++----
app/components/Songs/SongList.vue | 53 ++++++---
app/components/UI/Icon.vue | 5 +
app/pages/index.vue | 6 +-
server/middleware/auth.ts | 1 +
server/utils/auth-route-policy.ts | 1 +
8 files changed, 79 insertions(+), 197 deletions(-)
diff --git a/app/components/Auth/OAuthButtons.vue b/app/components/Auth/OAuthButtons.vue
index 8911837..3ede813 100644
--- a/app/components/Auth/OAuthButtons.vue
+++ b/app/components/Auth/OAuthButtons.vue
@@ -70,7 +70,7 @@ const hasEnabledProviders = computed(() => {
return config.public.oauth && Object.values(config.public.oauth).some((enabled) => enabled)
})
-const showPlaceholderHint = computed(() => props.alwaysShow && !hasEnabledProviders.value)
+const showPlaceholderHint = computed(() => false)
const loginWith = (provider: string) => {
navigateTo(`/api/auth/${provider}`, { external: true })
diff --git a/app/components/Songs/RequestForm.vue b/app/components/Songs/RequestForm.vue
index 3deab98..4d30940 100644
--- a/app/components/Songs/RequestForm.vue
+++ b/app/components/Songs/RequestForm.vue
@@ -128,31 +128,6 @@
从往期导入
-
-
-
-
联合投稿
-
-
- {{ user.name }}
-
-
-
-
-
@@ -652,16 +627,6 @@
@import-success="handleImportSuccess"
/>
-
-
-
{
}
}
-const handleUserSelect = (users) => {
- if (Array.isArray(users)) {
- // 过滤掉已存在的
- const newUsers = users.filter((u) => !collaborators.value.some((c) => c.id === u.id))
- collaborators.value.push(...newUsers)
- } else if (users) {
- if (!collaborators.value.some((c) => c.id === users.id)) {
- collaborators.value.push(users)
- }
- }
-}
-
-const removeCollaborator = (userId) => {
- collaborators.value = collaborators.value.filter((c) => c.id !== userId)
-}
-
// 获取播出时段
const fetchPlayTimes = async () => {
loadingPlayTimes.value = true
@@ -1456,13 +1401,6 @@ watch(
}
)
-watch(enableCollaborativeSubmission, (enabled) => {
- if (!enabled) {
- showUserSearchModal.value = false
- collaborators.value = []
- }
-})
-
watch(enableSubmissionRemarks, (enabled) => {
if (!enabled) {
submissionNote.value = ''
@@ -2288,7 +2226,6 @@ const submitSong = async (result, options = {}) => {
playUrl: selectedUrl.value || null,
submissionNote: submissionNote.value.trim() || null,
submissionNotePublic: submissionNotePublic.value,
- collaborators: collaborators.value.map((u) => u.id),
bilibiliCid: bilibiliCid || null,
bilibiliPage: bilibiliPage,
expectedPlayDate: expectedPlayDate.value || null,
@@ -2678,7 +2615,6 @@ const resetAfterSubmit = () => {
manualArtist.value = ''
manualCover.value = ''
manualPlayUrl.value = ''
- collaborators.value = []
submissionNote.value = ''
submissionNotePublic.value = true
// 重置URL验证状态
@@ -3268,83 +3204,6 @@ defineExpose({
box-shadow: 0 2px 6px rgba(79, 70, 229, 0.1);
}
-/* 联合投稿人区域 */
-.collaborators-section {
- display: flex;
- align-items: center;
- gap: 1rem;
- flex: 1;
- min-width: 200px;
-}
-
-.section-label {
- font-family: 'MiSans', sans-serif;
- font-weight: 700;
- font-size: 16px;
- color: var(--text-primary, #09090b);
- white-space: nowrap;
- flex-shrink: 0;
-}
-
-.collaborators-list {
- display: flex;
- flex-wrap: wrap;
- gap: 0.5rem;
- align-items: center;
-}
-
-.collaborator-tag {
- display: flex;
- align-items: center;
- gap: 0.5rem;
- background: rgba(79, 70, 229, 0.08);
- border: 1px solid rgba(79, 70, 229, 0.2);
- border-radius: 10px;
- padding: 0.3rem 0.6rem;
- font-size: 13px;
- color: var(--primary, #4f46e5);
- font-weight: 600;
-}
-
-.remove-collaborator {
- background: none;
- border: none;
- color: var(--primary, #4f46e5);
- cursor: pointer;
- display: flex;
- align-items: center;
- padding: 0;
- opacity: 0.7;
- transition: opacity 0.2s;
-}
-
-.remove-collaborator:hover {
- opacity: 1;
- color: #4338ca;
-}
-
-.add-collaborator-btn {
- display: flex;
- align-items: center;
- gap: 0.3rem;
- background: var(--bg-secondary, #f4f4f5);
- border: 1px solid var(--border-secondary, #e4e4e7);
- border-radius: 10px;
- padding: 0.45rem 0.9rem;
- font-size: 13px;
- font-weight: 600;
- color: var(--text-secondary, #52525b);
- cursor: pointer;
- transition: all 0.2s ease;
-}
-
-.add-collaborator-btn:hover {
- background: var(--primary, #4f46e5);
- color: #ffffff;
- border-color: var(--primary, #4f46e5);
- box-shadow: 0 4px 10px rgba(79, 70, 229, 0.18);
-}
-
/* 自定义复选框样式 */
.custom-checkbox-wrapper {
display: flex;
@@ -5122,20 +4981,6 @@ defineExpose({
min-width: unset; /* 移除桌面端的最小宽度限制 */
}
- .collaborators-section {
- flex-direction: row;
- align-items: center;
- gap: 1rem;
- margin-bottom: 1rem;
- flex: none;
- width: 100%;
- flex-wrap: wrap;
- }
-
- .section-label {
- font-size: 14px;
- }
-
.search-label {
font-size: 14px;
}
diff --git a/app/components/Songs/ScheduleList.vue b/app/components/Songs/ScheduleList.vue
index 7966c04..39ef65a 100644
--- a/app/components/Songs/ScheduleList.vue
+++ b/app/components/Songs/ScheduleList.vue
@@ -104,13 +104,13 @@
-
🎵
+
暂无排期信息
点歌后等待管理员安排播出时间
@@ -3168,33 +3168,35 @@ const vRipple = {
/* 日期选择弹窗 */
.date-picker-content {
- background: var(--surface-primary, var(--bg-primary, #1a1a1f));
+ background: var(--bg-primary, #ffffff);
border-radius: 20px 20px 0 0;
width: 100%;
max-width: 100%;
max-height: 70vh;
border: none;
- box-shadow: 0 -10px 40px rgba(0, 0, 0, 0.5);
+ box-shadow: 0 -10px 40px rgba(0, 0, 0, 0.12);
}
.date-picker-header {
padding: 20px;
- border-bottom: 1px solid rgba(255, 255, 255, 0.06);
+ border-bottom: 1px solid var(--border-secondary, rgba(0, 0, 0, 0.06));
}
.date-picker-header h3 {
font-size: 17px;
font-weight: 600;
+ color: var(--text-primary, #09090b);
}
.close-btn {
width: 32px;
height: 32px;
border-radius: 10px;
- background: rgba(255, 255, 255, 0.06);
+ background: var(--bg-tertiary, rgba(0, 0, 0, 0.06));
display: flex;
align-items: center;
justify-content: center;
+ color: var(--text-secondary, #52525b);
}
.date-picker-list {
@@ -3205,20 +3207,23 @@ const vRipple = {
padding: 14px 16px;
border-radius: 12px;
margin-bottom: 6px;
- background: rgba(255, 255, 255, 0.03);
+ background: var(--bg-secondary, #f4f4f5);
border: none;
font-size: 14px;
+ color: var(--text-primary, #09090b);
+ font-weight: 600;
}
.date-picker-item:hover {
- background: rgba(255, 255, 255, 0.06);
+ background: rgba(79, 70, 229, 0.08);
transform: none;
+ color: var(--primary, #4f46e5);
}
.date-picker-item.active {
- background: rgba(11, 90, 254, 0.15);
+ background: rgba(79, 70, 229, 0.14);
border-left: none;
- color: #0b5afe;
+ color: var(--primary, #4f46e5);
}
}
@@ -3453,10 +3458,10 @@ const vRipple = {
width: 85%;
max-width: 350px;
max-height: 70vh;
- 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);
+ background: var(--bg-primary, #ffffff);
+ border-radius: 18px;
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.12);
+ border: 1px solid var(--border-secondary, #e4e4e7);
overflow: hidden;
animation: scale-in 0.2s ease;
display: flex;
@@ -3468,19 +3473,19 @@ const vRipple = {
justify-content: space-between;
align-items: center;
padding: 1rem;
- border-bottom: 1px solid rgba(255, 255, 255, 0.1);
+ border-bottom: 1px solid var(--border-secondary, rgba(0, 0, 0, 0.08));
}
.date-picker-header h3 {
margin: 0;
font-size: 16px;
- color: white;
+ color: var(--text-primary, #09090b);
}
.close-btn {
background: none;
border: none;
- color: rgba(255, 255, 255, 0.6);
+ color: var(--text-secondary, #52525b);
font-size: 22px;
cursor: pointer;
padding: 0 5px;
@@ -3495,24 +3500,28 @@ const vRipple = {
.date-picker-item {
padding: 0.75rem 1rem;
- border-radius: 8px;
+ border-radius: 10px;
margin-bottom: 0.5rem;
cursor: pointer;
transition: all 0.2s ease;
- background: rgba(255, 255, 255, 0.05);
+ background: var(--bg-secondary, #f4f4f5);
position: relative;
overflow: hidden;
white-space: pre-line;
+ color: var(--text-primary, #09090b);
+ font-weight: 600;
}
.date-picker-item:hover {
- background: rgba(11, 90, 254, 0.1);
+ background: rgba(79, 70, 229, 0.1);
transform: translateY(-2px);
+ color: var(--primary, #4f46e5);
}
.date-picker-item.active {
- background: rgba(11, 90, 254, 0.2);
- border-left: 3px solid #0b5afe;
+ background: rgba(79, 70, 229, 0.14);
+ border-left: 3px solid var(--primary, #4f46e5);
+ color: var(--primary, #4f46e5);
}
/* 过渡动画 */
diff --git a/app/components/Songs/SongList.vue b/app/components/Songs/SongList.vue
index 8c6b2e2..8973f13 100644
--- a/app/components/Songs/SongList.vue
+++ b/app/components/Songs/SongList.vue
@@ -234,14 +234,16 @@
- 已排期
+ 已排期
+
+ {{ formatScheduleDate(song.scheduleDate) }}
+
重播
+
+
+
+
+
diff --git a/app/pages/index.vue b/app/pages/index.vue
index 5582382..7f2e8e1 100644
--- a/app/pages/index.vue
+++ b/app/pages/index.vue
@@ -109,7 +109,7 @@
-
📅
+
今日可点排期
{{ todaySchedulesCount }}
@@ -118,7 +118,7 @@
{{ todayLabel }}
-
🎵
+
待播歌曲总数
{{ totalSchedulesCount }}
@@ -127,7 +127,7 @@
累计审核通过 / 审核中
-
✨
+
当前空闲档期
{{ totalFreeSlots }}
diff --git a/server/middleware/auth.ts b/server/middleware/auth.ts
index 4e57b5f..e2d393d 100644
--- a/server/middleware/auth.ts
+++ b/server/middleware/auth.ts
@@ -25,6 +25,7 @@ export default defineEventHandler(async (event) => {
'/api/auth/verify', // verify端点自行处理token验证
'/api/semesters/current',
'/api/play-times',
+ '/api/expected-play-dates',
'/api/schedules/public',
'/api/songs/count',
'/api/songs/public',
diff --git a/server/utils/auth-route-policy.ts b/server/utils/auth-route-policy.ts
index b0ef35b..ff2ab06 100644
--- a/server/utils/auth-route-policy.ts
+++ b/server/utils/auth-route-policy.ts
@@ -33,6 +33,7 @@ export const PUBLIC_API_EXACT_ROUTES: readonly RoutePolicy[] = [
{ path: '/api/auth/captcha', methods: GET_METHODS },
{ path: '/api/semesters/current', methods: GET_METHODS },
{ path: '/api/play-times', methods: GET_METHODS },
+ { path: '/api/expected-play-dates', methods: GET_METHODS },
{ path: '/api/schedules/public', methods: GET_METHODS },
{ path: '/api/songs/count', methods: GET_METHODS },
{ path: '/api/songs/public', methods: GET_METHODS },