feat: 迁移自定义功能至 1.5.9.9 版本
包含音乐源限制、CI 防 OOM 优化、数据库连接池优化、管理端权限及 UI 细节定制等功能
This commit is contained in:
@@ -6,29 +6,26 @@
|
||||
|
||||
<Transition name="entry" appear>
|
||||
<div v-show="active" class="content">
|
||||
<div class="label">{{ yearReview.favoriteArtist }}</div>
|
||||
<div class="label">特别偏爱</div>
|
||||
|
||||
<p class="text-intro">{{ yearReview.topArtistIntro }}</p>
|
||||
<p class="text-intro">你的年度歌手是</p>
|
||||
|
||||
<div class="artist-container">
|
||||
<div class="artist-bg-blur" />
|
||||
<h2 class="artist-name">{{ data.topArtist }}</h2>
|
||||
</div>
|
||||
|
||||
<p class="text-desc">{{ yearReview.artistDesc }}</p>
|
||||
<p class="text-desc">Ta 的声音似乎特别吸引你,<br >陪伴了你无数个日夜。</p>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useLocale } from '~/utils/locale'
|
||||
|
||||
defineProps({
|
||||
data: Object,
|
||||
active: Boolean
|
||||
})
|
||||
const { yearReview } = useLocale()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -40,13 +37,13 @@ const { yearReview } = useLocale()
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
background-color: var(--panel-bg-tertiary);
|
||||
background-color: var(--surface-primary, var(--bg-primary, #1a0b2e));
|
||||
}
|
||||
|
||||
.bg-overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(to top, var(--bg-primary), transparent, transparent);
|
||||
background: linear-gradient(to top, var(--bg-primary, #111111), transparent, transparent);
|
||||
opacity: 0.8;
|
||||
z-index: 10;
|
||||
}
|
||||
@@ -56,7 +53,7 @@ const { yearReview } = useLocale()
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(to bottom, var(--color-collab-hover), var(--bg-primary));
|
||||
background: linear-gradient(to bottom, #581c87, #000);
|
||||
opacity: 0.5;
|
||||
animation: pulse 8s infinite;
|
||||
}
|
||||
@@ -72,19 +69,19 @@ const { yearReview } = useLocale()
|
||||
}
|
||||
|
||||
.label {
|
||||
color: var(--color-collab-light); /* purple-300 */
|
||||
color: #d8b4fe; /* purple-300 */
|
||||
letter-spacing: 0.3em;
|
||||
text-transform: uppercase;
|
||||
margin-bottom: 1.5rem;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 700;
|
||||
border-bottom: 1px solid var(--year-review-artist-label-border);
|
||||
border-bottom: 1px solid rgba(168, 85, 247, 0.3);
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.text-intro {
|
||||
font-size: 1.5rem;
|
||||
color: var(--text-primary-lighter);
|
||||
color: #d1d5db;
|
||||
font-weight: 300;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
@@ -101,7 +98,7 @@ const { yearReview } = useLocale()
|
||||
transform: translate(-50%, -50%);
|
||||
width: 120%;
|
||||
height: 120%;
|
||||
background: var(--year-review-artist-bg-blur);
|
||||
background: rgba(168, 85, 247, 0.2);
|
||||
filter: blur(60px);
|
||||
border-radius: 50%;
|
||||
}
|
||||
@@ -112,18 +109,18 @@ const { yearReview } = useLocale()
|
||||
font-weight: 900;
|
||||
font-style: italic;
|
||||
letter-spacing: -0.05em;
|
||||
background-image: linear-gradient(to bottom right, var(--color-collab-light), var(--color-pink), var(--color-orange));
|
||||
background-image: linear-gradient(to bottom right, #e9d5ff, #f472b6, #fb923c);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
filter: drop-shadow(0 25px 25px var(--mask-15));
|
||||
filter: drop-shadow(0 25px 25px rgba(0, 0, 0, 0.15));
|
||||
word-break: break-word;
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
|
||||
.text-desc {
|
||||
margin-top: 3rem;
|
||||
color: var(--text-muted);
|
||||
color: #9ca3af;
|
||||
max-width: 24rem;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
|
||||
<Transition name="entry" appear>
|
||||
<div v-show="active" class="content">
|
||||
<span class="badge">{{ yearReview.firstSongBadge }}</span>
|
||||
<span class="badge">初次相遇</span>
|
||||
|
||||
<p class="text-intro">{{ yearReview.firstSongIntro }}</p>
|
||||
<p class="text-intro">这一年,你点的<span class="highlight">第一首歌</span>是</p>
|
||||
|
||||
<div class="vinyl-container">
|
||||
<div class="vinyl-record">
|
||||
@@ -53,17 +53,14 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useLocale } from '~/utils/locale'
|
||||
|
||||
defineProps({
|
||||
data: Object,
|
||||
active: Boolean
|
||||
})
|
||||
const { yearReview } = useLocale()
|
||||
|
||||
const formatDate = (dateStr) => {
|
||||
const date = new Date(dateStr)
|
||||
return yearReview.value.date(date.getMonth() + 1, date.getDate())
|
||||
return `${date.getMonth() + 1}月${date.getDate()}日`
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -77,7 +74,7 @@ const formatDate = (dateStr) => {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
background-color: var(--bg-primary);
|
||||
background-color: var(--bg-primary, #111111);
|
||||
}
|
||||
|
||||
.bg-blur {
|
||||
@@ -105,25 +102,25 @@ const formatDate = (dateStr) => {
|
||||
display: inline-block;
|
||||
padding: 0.25rem 1rem;
|
||||
border-radius: 9999px;
|
||||
border: 1px solid var(--overlay-20);
|
||||
background: var(--overlay-5);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
backdrop-filter: blur(12px);
|
||||
font-size: 0.875rem;
|
||||
margin-bottom: 1.5rem;
|
||||
letter-spacing: 0.1em;
|
||||
color: var(--color-pink); /* brand-pink */
|
||||
color: #f472b6; /* brand-pink */
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.text-intro {
|
||||
font-size: 1.5rem;
|
||||
color: var(--text-primary-lighter);
|
||||
color: #d1d5db;
|
||||
font-weight: 300;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
color: var(--text-primary);
|
||||
color: var(--text-primary, #ffffff);
|
||||
font-weight: 700;
|
||||
margin: 0 0.5rem;
|
||||
}
|
||||
@@ -142,9 +139,9 @@ const formatDate = (dateStr) => {
|
||||
height: 100%;
|
||||
border-radius: 1rem;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 25px 50px -12px var(--mask-50);
|
||||
border: 1px solid var(--overlay-10);
|
||||
background: var(--panel-bg-dark);
|
||||
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
background: var(--bg-secondary, #111827);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -162,13 +159,13 @@ const formatDate = (dateStr) => {
|
||||
}
|
||||
|
||||
.placeholder-icon {
|
||||
color: var(--text-muted);
|
||||
color: #4b5563;
|
||||
}
|
||||
|
||||
.glossy-overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(to top right, var(--overlay-10), transparent);
|
||||
background: linear-gradient(to top right, rgba(255, 255, 255, 0.1), transparent);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@@ -184,12 +181,12 @@ const formatDate = (dateStr) => {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: var(--text-primary);
|
||||
color: var(--text-primary, #ffffff);
|
||||
}
|
||||
|
||||
.song-artist {
|
||||
font-size: 1.125rem;
|
||||
color: var(--text-muted);
|
||||
color: #9ca3af;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@@ -198,7 +195,7 @@ const formatDate = (dateStr) => {
|
||||
.date-text {
|
||||
margin-top: 2rem;
|
||||
font-size: 1.125rem;
|
||||
color: var(--text-muted);
|
||||
color: #9ca3af;
|
||||
font-family:
|
||||
'MiSans',
|
||||
system-ui,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<Transition name="entry" appear>
|
||||
<div v-show="active" class="content">
|
||||
<div class="year-bg">{{ data.year }}</div>
|
||||
<div class="sub-title">{{ yearReview.reportTitle }}</div>
|
||||
<div class="sub-title">年度点歌报告</div>
|
||||
<h1 class="main-title">VoiceHub</h1>
|
||||
</div>
|
||||
</Transition>
|
||||
@@ -15,13 +15,10 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useLocale } from '~/utils/locale'
|
||||
|
||||
defineProps({
|
||||
data: Object,
|
||||
active: Boolean
|
||||
})
|
||||
const { yearReview } = useLocale()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -34,7 +31,7 @@ const { yearReview } = useLocale()
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
background: radial-gradient(circle at center, var(--panel-bg-dark), var(--bg-primary));
|
||||
background: radial-gradient(circle at center, var(--bg-secondary, #111827), #000000);
|
||||
}
|
||||
|
||||
.blob {
|
||||
@@ -49,7 +46,7 @@ const { yearReview } = useLocale()
|
||||
left: -10%;
|
||||
width: 500px;
|
||||
height: 500px;
|
||||
background: var(--year-review-blob-1-bg);
|
||||
background: rgba(139, 92, 246, 0.4); /* brand-purple */
|
||||
animation: spin 20s linear infinite;
|
||||
}
|
||||
|
||||
@@ -58,7 +55,7 @@ const { yearReview } = useLocale()
|
||||
right: -10%;
|
||||
width: 600px;
|
||||
height: 600px;
|
||||
background: var(--year-review-blob-2-bg);
|
||||
background: rgba(244, 114, 182, 0.2); /* brand-pink */
|
||||
animation: reverse-spin 25s linear infinite;
|
||||
}
|
||||
|
||||
@@ -76,7 +73,7 @@ const { yearReview } = useLocale()
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 14rem;
|
||||
font-weight: 900;
|
||||
color: var(--overlay-3);
|
||||
color: rgba(255, 255, 255, 0.03);
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
line-height: 1;
|
||||
@@ -85,7 +82,7 @@ const { yearReview } = useLocale()
|
||||
.sub-title {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 300;
|
||||
color: var(--text-muted);
|
||||
color: #9ca3af;
|
||||
margin-bottom: 1rem;
|
||||
letter-spacing: 0.2em;
|
||||
text-transform: uppercase;
|
||||
@@ -94,12 +91,12 @@ const { yearReview } = useLocale()
|
||||
.main-title {
|
||||
font-size: 5rem;
|
||||
font-weight: 900;
|
||||
background-image: linear-gradient(to right, var(--text-primary), var(--panel-border-light), var(--text-muted));
|
||||
background-image: linear-gradient(to right, #ffffff, #e5e7eb, #6b7280);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
margin-bottom: 2rem;
|
||||
filter: drop-shadow(0 25px 25px var(--mask-15));
|
||||
filter: drop-shadow(0 25px 25px rgba(0, 0, 0, 0.15));
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
|
||||
@@ -5,18 +5,18 @@
|
||||
<Transition name="entry" appear>
|
||||
<div v-show="active" class="content">
|
||||
<div v-if="data.topPlatform" class="card platform-card">
|
||||
<span class="label">{{ yearReview.commonPlatform }}</span>
|
||||
<span class="label">常用平台</span>
|
||||
<span class="platform-value">{{ formatPlatform(data.topPlatform) }}</span>
|
||||
</div>
|
||||
|
||||
<div class="grid-container">
|
||||
<div v-if="data.activeMonth" class="card active-card">
|
||||
<span class="label">{{ yearReview.mostActive }}</span>
|
||||
<span class="active-value">{{ yearReview.activeMonth(data.activeMonth) }}</span>
|
||||
<span class="label">最活跃</span>
|
||||
<span class="active-value">{{ data.activeMonth }}<span class="unit">月</span></span>
|
||||
</div>
|
||||
|
||||
<div class="card votes-card">
|
||||
<span class="label">{{ yearReview.votesCast }}</span>
|
||||
<span class="label">投出票数</span>
|
||||
<span class="votes-value">{{ data.totalVotes }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -26,16 +26,21 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useLocale } from '~/utils/locale'
|
||||
|
||||
defineProps({
|
||||
data: Object,
|
||||
active: Boolean
|
||||
})
|
||||
const { yearReview } = useLocale()
|
||||
|
||||
const formatPlatform = (platform) => {
|
||||
const map = yearReview.value.platforms
|
||||
const map = {
|
||||
netease: '网易云音乐',
|
||||
bilibili: '哔哩哔哩',
|
||||
qq: 'QQ音乐',
|
||||
kugou: '酷狗音乐',
|
||||
kuwo: '酷我音乐',
|
||||
migu: '咪咕音乐',
|
||||
tencent: 'QQ音乐'
|
||||
}
|
||||
return map[platform] || platform
|
||||
}
|
||||
</script>
|
||||
@@ -49,7 +54,7 @@ const formatPlatform = (platform) => {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
background-color: var(--panel-bg-dark); /* gray-900 */
|
||||
background-color: var(--bg-secondary, #111827); /* gray-900 */
|
||||
}
|
||||
|
||||
.bg-gradient {
|
||||
@@ -58,7 +63,7 @@ const formatPlatform = (platform) => {
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 50%;
|
||||
background: linear-gradient(to bottom, var(--panel-border-subtle), transparent);
|
||||
background: linear-gradient(to bottom, var(--bg-secondary, #1f2937), transparent);
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
@@ -74,8 +79,8 @@ const formatPlatform = (platform) => {
|
||||
.card {
|
||||
padding: 1.5rem;
|
||||
border-radius: 1.5rem;
|
||||
background: var(--overlay-5);
|
||||
border: 1px solid var(--overlay-10);
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
backdrop-filter: blur(12px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -85,7 +90,7 @@ const formatPlatform = (platform) => {
|
||||
|
||||
.label {
|
||||
font-size: 0.75rem;
|
||||
color: var(--year-review-text-tertiary);
|
||||
color: #6b7280;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
margin-bottom: 0.5rem; /* adjusted */
|
||||
@@ -94,7 +99,7 @@ const formatPlatform = (platform) => {
|
||||
.platform-value {
|
||||
font-size: 1.5rem; /* text-2xl */
|
||||
font-weight: 700;
|
||||
background-image: linear-gradient(to right, var(--color-error-light), var(--color-orange));
|
||||
background-image: linear-gradient(to right, #f87171, #fb923c);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
@@ -114,19 +119,19 @@ const formatPlatform = (platform) => {
|
||||
.active-value {
|
||||
font-size: 2.25rem; /* text-4xl */
|
||||
font-weight: 700;
|
||||
color: var(--year-review-text-yellow);
|
||||
color: #fde047; /* yellow-300 */
|
||||
}
|
||||
|
||||
.unit {
|
||||
font-size: 1rem;
|
||||
margin-left: 0.25rem;
|
||||
color: var(--text-muted);
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.votes-value {
|
||||
font-size: 1.875rem; /* text-3xl */
|
||||
font-weight: 700;
|
||||
color: var(--year-review-text-cyan); /* cyan-300 */
|
||||
color: #67e8f9; /* cyan-300 */
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
|
||||
<Transition name="entry" appear>
|
||||
<div v-show="active" class="content">
|
||||
<div class="label">{{ yearReview.future }}</div>
|
||||
<div class="label">未来可期</div>
|
||||
|
||||
<div class="year-container">
|
||||
<h2 class="year-next">{{ data.year + 1 }}</h2>
|
||||
<div class="year-underline" />
|
||||
</div>
|
||||
|
||||
<p class="text-intro">{{ yearReview.futureDesc }}</p>
|
||||
<p class="text-intro">愿音乐继续陪伴你的每一天</p>
|
||||
|
||||
<div class="action-buttons">
|
||||
<NuxtLink to="/" class="btn-primary group">
|
||||
@@ -30,7 +30,7 @@
|
||||
<path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
|
||||
<polyline points="9 22 9 12 15 12 15 22" />
|
||||
</svg>
|
||||
{{ yearReview.backHome }}
|
||||
返回首页
|
||||
</span>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
@@ -40,14 +40,11 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useLocale } from '~/utils/locale'
|
||||
|
||||
defineProps({
|
||||
data: Object,
|
||||
active: Boolean
|
||||
})
|
||||
defineEmits(['share'])
|
||||
const { yearReview } = useLocale()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -59,13 +56,13 @@ const { yearReview } = useLocale()
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
background-color: var(--bg-primary);
|
||||
background-color: var(--bg-primary, #111111);
|
||||
}
|
||||
|
||||
.bg-gradient {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: radial-gradient(circle at center, var(--panel-border-subtle), var(--bg-primary), var(--bg-primary));
|
||||
background: radial-gradient(circle at center, var(--bg-secondary, #1f2937), #000, #000);
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
@@ -78,7 +75,7 @@ const { yearReview } = useLocale()
|
||||
}
|
||||
|
||||
.label {
|
||||
color: var(--year-review-text-tertiary);
|
||||
color: #6b7280;
|
||||
font-size: 0.875rem;
|
||||
letter-spacing: 0.5em;
|
||||
text-transform: uppercase;
|
||||
@@ -95,7 +92,7 @@ const { yearReview } = useLocale()
|
||||
font-size: 6rem;
|
||||
font-weight: 900;
|
||||
line-height: 1;
|
||||
background-image: linear-gradient(to bottom, var(--text-primary), var(--panel-border-subtle));
|
||||
background-image: linear-gradient(to bottom, #fff, #1f2937);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
@@ -107,12 +104,12 @@ const { yearReview } = useLocale()
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
background: linear-gradient(to right, transparent, var(--overlay-20), transparent);
|
||||
background: linear-gradient(to right, transparent, rgba(255, 255, 255, 0.2), transparent);
|
||||
}
|
||||
|
||||
.text-intro {
|
||||
font-size: 1.125rem;
|
||||
color: var(--text-muted);
|
||||
color: #9ca3af;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
@@ -135,8 +132,8 @@ const { yearReview } = useLocale()
|
||||
width: 100%;
|
||||
padding: 1rem 2rem;
|
||||
border-radius: 9999px;
|
||||
background: var(--text-primary);
|
||||
color: var(--bg-primary);
|
||||
background: var(--card-bg, #fff);
|
||||
color: var(--text-primary, #000);
|
||||
font-weight: 700;
|
||||
font-size: 1.125rem;
|
||||
overflow: hidden;
|
||||
@@ -153,7 +150,7 @@ const { yearReview } = useLocale()
|
||||
.btn-bg {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: var(--panel-border-light);
|
||||
background: #e5e7eb;
|
||||
transform: translateY(100%);
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
@@ -174,9 +171,9 @@ const { yearReview } = useLocale()
|
||||
width: 100%;
|
||||
padding: 1rem 2rem;
|
||||
border-radius: 9999px;
|
||||
background: var(--overlay-10);
|
||||
border: 1px solid var(--overlay-20);
|
||||
color: var(--text-primary);
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
color: var(--text-primary, #ffffff);
|
||||
font-weight: 700;
|
||||
font-size: 1.125rem;
|
||||
backdrop-filter: blur(12px);
|
||||
@@ -188,7 +185,7 @@ const { yearReview } = useLocale()
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: var(--overlay-20);
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary:active {
|
||||
|
||||
@@ -12,27 +12,27 @@
|
||||
</div>
|
||||
|
||||
<div class="title-section">
|
||||
<h1 class="main-title">{{ yearReview.reportTitle }}</h1>
|
||||
<h1 class="main-title">年度点歌报告</h1>
|
||||
<p class="subtitle">Music Journey</p>
|
||||
</div>
|
||||
|
||||
<div class="stats-grid">
|
||||
<div class="stat-item">
|
||||
<div class="stat-value">{{ data.totalRequests }}</div>
|
||||
<div class="stat-label">{{ yearReview.requests }}</div>
|
||||
<div class="stat-label">点歌次数</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-value">{{ data.playedRequests }}</div>
|
||||
<div class="stat-label">{{ yearReview.played }}</div>
|
||||
<div class="stat-label">已播放</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-value">{{ data.totalVotes }}</div>
|
||||
<div class="stat-label">{{ yearReview.votes }}</div>
|
||||
<div class="stat-label">投票数</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<div class="footer-text">{{ yearReview.footerSlogan }}</div>
|
||||
<div class="footer-text">用音乐记录每一刻</div>
|
||||
<div class="footer-line" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -41,7 +41,6 @@
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { useLocale } from '~/utils/locale'
|
||||
|
||||
defineProps({
|
||||
data: {
|
||||
@@ -51,7 +50,6 @@ defineProps({
|
||||
})
|
||||
|
||||
const shareCardRef = ref(null)
|
||||
const { yearReview } = useLocale()
|
||||
|
||||
defineExpose({
|
||||
shareCardRef
|
||||
@@ -65,7 +63,7 @@ defineExpose({
|
||||
height: 100%;
|
||||
min-height: 600px;
|
||||
overflow: hidden;
|
||||
background: linear-gradient(135deg, var(--panel-bg-tertiary) 0%, var(--panel-bg-tertiary) 50%, var(--panel-bg-tertiary) 100%);
|
||||
background: linear-gradient(135deg, var(--bg-secondary, #0f0f23) 0%, #1a1a2e 50%, #16213e 100%);
|
||||
}
|
||||
|
||||
.card-background {
|
||||
@@ -77,9 +75,9 @@ defineExpose({
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background:
|
||||
radial-gradient(circle at 20% 30%, var(--index-card-glow) 0%, transparent 50%),
|
||||
radial-gradient(circle at 80% 70%, var(--year-review-gradient-overlay-end) 0%, transparent 50%),
|
||||
radial-gradient(circle at 50% 50%, var(--primary-10) 0%, transparent 60%);
|
||||
radial-gradient(circle at 20% 30%, rgba(139, 92, 246, 0.15) 0%, transparent 50%),
|
||||
radial-gradient(circle at 80% 70%, rgba(244, 114, 182, 0.15) 0%, transparent 50%),
|
||||
radial-gradient(circle at 50% 50%, rgba(59, 130, 246, 0.1) 0%, transparent 60%);
|
||||
}
|
||||
|
||||
.noise-overlay {
|
||||
@@ -108,7 +106,7 @@ defineExpose({
|
||||
.logo {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 900;
|
||||
background: linear-gradient(135deg, var(--color-collab), var(--color-pink));
|
||||
background: linear-gradient(135deg, #8b5cf6, #ec4899);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
@@ -117,7 +115,7 @@ defineExpose({
|
||||
.year {
|
||||
font-size: 3rem;
|
||||
font-weight: 900;
|
||||
color: var(--overlay-10);
|
||||
color: rgba(255, 255, 255, 0.1);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
@@ -129,7 +127,7 @@ defineExpose({
|
||||
.main-title {
|
||||
font-size: 3.5rem;
|
||||
font-weight: 900;
|
||||
background: linear-gradient(135deg, var(--text-primary) 0%, var(--panel-border-light) 50%, var(--text-muted) 100%);
|
||||
background: linear-gradient(135deg, var(--card-bg, #ffffff) 0%, #e5e7eb 50%, #9ca3af 100%);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
@@ -139,7 +137,7 @@ defineExpose({
|
||||
|
||||
.subtitle {
|
||||
font-size: 1.25rem;
|
||||
color: var(--overlay-50);
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
letter-spacing: 0.3em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
@@ -154,16 +152,16 @@ defineExpose({
|
||||
.stat-item {
|
||||
text-align: center;
|
||||
padding: 1.5rem;
|
||||
background: var(--overlay-3);
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
border-radius: 1rem;
|
||||
border: 1px solid var(--overlay-8);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 900;
|
||||
background: linear-gradient(135deg, var(--color-accent-light), var(--color-accent-light));
|
||||
background: linear-gradient(135deg, #60a5fa, #3b82f6);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
@@ -172,7 +170,7 @@ defineExpose({
|
||||
|
||||
.stat-label {
|
||||
font-size: 0.875rem;
|
||||
color: var(--overlay-50);
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
@@ -183,7 +181,7 @@ defineExpose({
|
||||
|
||||
.footer-text {
|
||||
font-size: 0.875rem;
|
||||
color: var(--overlay-40);
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
letter-spacing: 0.1em;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
@@ -191,7 +189,7 @@ defineExpose({
|
||||
.footer-line {
|
||||
width: 100px;
|
||||
height: 2px;
|
||||
background: linear-gradient(90deg, transparent, var(--overlay-20), transparent);
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,23 +4,23 @@
|
||||
|
||||
<Transition name="entry" appear>
|
||||
<div v-show="active" class="content">
|
||||
<div class="label">{{ yearReview.musicJourney }}</div>
|
||||
<div class="label">音乐足迹</div>
|
||||
|
||||
<p class="text-intro">{{ yearReview.totalRequestsIntro }}</p>
|
||||
<p class="text-intro">这一年,你一共发起了</p>
|
||||
|
||||
<div class="number-container">
|
||||
<span class="big-number">{{ data.totalRequests.toLocaleString() }}</span>
|
||||
<span class="suffix">{{ yearReview.requestCount }}</span>
|
||||
<span class="suffix">次点歌</span>
|
||||
</div>
|
||||
|
||||
<div class="sub-stats">
|
||||
<div v-if="data.playedRequests > 0" class="sub-content">
|
||||
<p class="text-base">
|
||||
{{ yearReview.playedSummary(data.playedRequests) }}
|
||||
其中,<span class="highlight-green">{{ data.playedRequests }}</span> 首
|
||||
</p>
|
||||
<p class="text-sub">{{ yearReview.playedDesc }}</p>
|
||||
<p class="text-sub">在广播站被播出,传递给了更多人</p>
|
||||
</div>
|
||||
<p v-else class="text-sub">{{ yearReview.pendingPlayedDesc }}</p>
|
||||
<p v-else class="text-sub">期待你的歌曲早日被播出</p>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
@@ -28,13 +28,10 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useLocale } from '~/utils/locale'
|
||||
|
||||
defineProps({
|
||||
data: Object,
|
||||
active: Boolean
|
||||
})
|
||||
const { yearReview } = useLocale()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -46,7 +43,7 @@ const { yearReview } = useLocale()
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
background-color: var(--panel-bg-darkest); /* gray-950 */
|
||||
background-color: var(--surface-primary, var(--bg-primary, #030712));
|
||||
}
|
||||
|
||||
.bg-gradient {
|
||||
@@ -54,7 +51,7 @@ const { yearReview } = useLocale()
|
||||
inset: 0;
|
||||
background: radial-gradient(
|
||||
ellipse at top right,
|
||||
var(--year-review-stats-bg-gradient),
|
||||
rgba(30, 58, 138, 0.4),
|
||||
transparent,
|
||||
transparent
|
||||
);
|
||||
@@ -69,7 +66,7 @@ const { yearReview } = useLocale()
|
||||
|
||||
.label {
|
||||
margin-bottom: 1rem;
|
||||
color: var(--color-accent-light); /* brand-blue */
|
||||
color: #3b82f6; /* brand-blue */
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.05em;
|
||||
font-size: 1.125rem;
|
||||
@@ -77,7 +74,7 @@ const { yearReview } = useLocale()
|
||||
|
||||
.text-intro {
|
||||
font-size: 1.5rem;
|
||||
color: var(--text-muted);
|
||||
color: #9ca3af;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
@@ -94,16 +91,16 @@ const { yearReview } = useLocale()
|
||||
font-size: 10rem;
|
||||
font-weight: 900;
|
||||
line-height: 1;
|
||||
background-image: linear-gradient(to bottom, var(--color-accent-light), var(--color-accent-light-hover));
|
||||
background-image: linear-gradient(to bottom, #60a5fa, #1d4ed8);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
filter: drop-shadow(0 0 30px var(--year-review-stat-number-shadow));
|
||||
filter: drop-shadow(0 0 30px rgba(37, 99, 235, 0.5));
|
||||
}
|
||||
|
||||
.suffix {
|
||||
font-size: 1.5rem;
|
||||
color: var(--year-review-text-tertiary);
|
||||
color: #6b7280;
|
||||
font-weight: 500;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
@@ -112,8 +109,8 @@ const { yearReview } = useLocale()
|
||||
margin-top: 3rem;
|
||||
padding: 1.5rem;
|
||||
border-radius: 1rem;
|
||||
background: var(--overlay-5);
|
||||
border: 1px solid var(--overlay-10);
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
|
||||
@@ -125,19 +122,19 @@ const { yearReview } = useLocale()
|
||||
|
||||
.text-base {
|
||||
font-size: 1.125rem;
|
||||
color: var(--text-primary-lighter);
|
||||
color: #d1d5db;
|
||||
}
|
||||
|
||||
.highlight-green {
|
||||
font-size: 1.875rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-success-light);
|
||||
color: #4ade80;
|
||||
margin: 0 0.25rem;
|
||||
}
|
||||
|
||||
.text-sub {
|
||||
font-size: 1rem;
|
||||
color: var(--text-muted);
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
|
||||
Reference in New Issue
Block a user