From 278f007b5ee94830fd4a652ac0b1b83124f40d91 Mon Sep 17 00:00:00 2001
From: xbh <6726613@qq.com>
Date: Sun, 26 Oct 2025 22:41:53 +0800
Subject: [PATCH] =?UTF-8?q?=E6=8E=92=E8=A1=8C=E6=A6=9C=E5=89=8D=E7=AB=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
frontend/index.html | 6 +
frontend/src/App.vue | 442 ++++++++++++++++++++++++++++------------
frontend/vite.config.js | 2 -
3 files changed, 314 insertions(+), 136 deletions(-)
diff --git a/frontend/index.html b/frontend/index.html
index 4240845..5ad635b 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -6,6 +6,12 @@
Vite App
+
diff --git a/frontend/src/App.vue b/frontend/src/App.vue
index 28535a9..d33645f 100644
--- a/frontend/src/App.vue
+++ b/frontend/src/App.vue
@@ -9,11 +9,49 @@ const loading = ref(false)
const selectedDate = ref('')
const currentPage = ref(1)
const totalPages = ref(1)
+const updateTime = ref('') // 添加更新时间字段
+const showDatePicker = ref(false) // 控制日期选择器显示
+const dateOptions = ref([]) // 日期选项列表
// 初始化日期为今天
const initDate = () => {
const today = new Date()
selectedDate.value = today.toISOString().split('T')[0]
+ generateDateOptions()
+}
+
+// 生成日期选项(今天和往前7天)
+const generateDateOptions = () => {
+ const options = []
+ const today = new Date()
+
+ for (let i = 0; i < 8; i++) {
+ const date = new Date(today)
+ date.setDate(today.getDate() - i)
+
+ const value = date.toISOString().split('T')[0]
+ const weekdays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
+ const weekday = weekdays[date.getDay()]
+
+ let label = ''
+ if (i === 0) {
+ label = '今天'
+ } else if (i === 1) {
+ label = '昨天'
+ } else {
+ label = `${i}天前`
+ }
+
+ const display = `${date.getMonth() + 1}月${date.getDate()}日 ${weekday}`
+
+ options.push({
+ value,
+ label,
+ display
+ })
+ }
+
+ dateOptions.value = options
}
// 获取排行榜数据
@@ -33,6 +71,8 @@ const fetchRankingData = async () => {
if (response.data.success) {
rankingData.value = response.data.data
totalPages.value = response.data.pagination.pages
+ // 获取后端返回的更新时间
+ updateTime.value = response.data.update_time || ''
} else {
console.error('获取数据失败:', response.data.message)
rankingData.value = []
@@ -76,7 +116,7 @@ const formatGrowth = (item) => {
const changeRate = timelineData.play_vv_change_rate || 0
if (change > 0) {
- return `+${formatPlayCount(change)} (${changeRate.toFixed(1)}%)`
+ return `${formatPlayCount(change)}`
}
return '暂无数据'
}
@@ -89,12 +129,85 @@ const switchTab = (tab) => {
}
}
+// 获取图片源地址
+const getImageSrc = (item) => {
+ // 优先使用 cover_image_url
+ if (item.cover_image_url) {
+ return item.cover_image_url
+ }
+
+ // 如果有备用链接,使用第一个
+ if (item.cover_backup_urls && item.cover_backup_urls.length > 0) {
+ return item.cover_backup_urls[0]
+ }
+
+ // 最后使用占位符
+ return '/placeholder-poster.svg'
+}
+
+// 处理图片加载错误
+const handleImageError = (event, item) => {
+ const img = event.target
+ console.log('图片加载失败:', img.src, '视频:', item.title)
+
+ // 如果当前显示的是主链接,尝试备用链接
+ if (img.src === item.cover_image_url && item.cover_backup_urls && item.cover_backup_urls.length > 0) {
+ console.log('尝试备用链接:', item.cover_backup_urls[0])
+ // 尝试第一个备用链接
+ img.src = item.cover_backup_urls[0]
+ return
+ }
+
+ // 如果当前显示的是第一个备用链接,尝试其他备用链接
+ if (item.cover_backup_urls && item.cover_backup_urls.length > 1) {
+ const currentIndex = item.cover_backup_urls.indexOf(img.src)
+ if (currentIndex >= 0 && currentIndex < item.cover_backup_urls.length - 1) {
+ console.log('尝试下一个备用链接:', item.cover_backup_urls[currentIndex + 1])
+ img.src = item.cover_backup_urls[currentIndex + 1]
+ return
+ }
+ }
+
+ // 所有链接都失败,使用占位符
+ console.log('使用占位符图片')
+ img.src = '/placeholder-poster.svg'
+}
+
// 日期改变处理
const onDateChange = () => {
currentPage.value = 1
fetchRankingData()
}
+// 格式化显示日期
+const formatDisplayDate = (dateStr) => {
+ if (!dateStr) return '选择日期'
+
+ const date = new Date(dateStr)
+ const today = new Date()
+ const diffTime = today.getTime() - date.getTime()
+ const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24))
+ return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`
+
+}
+
+// 切换日期选择器显示状态
+const toggleDatePicker = () => {
+ showDatePicker.value = !showDatePicker.value
+}
+
+// 关闭日期选择器
+const closeDatePicker = () => {
+ showDatePicker.value = false
+}
+
+// 选择日期
+const selectDate = (dateValue) => {
+ selectedDate.value = dateValue
+ showDatePicker.value = false
+ onDateChange()
+}
+
// 页面加载时初始化
onMounted(() => {
initDate()
@@ -111,26 +224,44 @@ onMounted(() => {
-
-
-
-
+
+
+
+ {{ formatDisplayDate(selectedDate) }}
+
+
+
+
+
+
+
@@ -154,9 +285,9 @@ onMounted(() => {
@@ -172,15 +303,11 @@ onMounted(() => {
{{ formatPlayCount(item.play_vv) }}
-
-
- {{ item.summary || item.title || item.mix_name || '暂无简介' }}
-
- 🔥
+
{{ formatGrowth(item) }}
@@ -234,7 +361,6 @@ onMounted(() => {
.app {
min-height: 100vh;
- background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
padding-bottom: 80px; /* 为底部导航留出空间 */
color: white;
@@ -251,7 +377,6 @@ onMounted(() => {
/* 标题区域 */
.header {
text-align: center;
- margin-bottom: 20px;
}
.title-container {
@@ -268,11 +393,10 @@ onMounted(() => {
}
.title {
- color: white;
+ color: #555;
font-size: 24px;
font-weight: bold;
margin: 0;
- text-shadow: 0 2px 4px rgba(0,0,0,0.3);
}
.update-time {
@@ -289,35 +413,141 @@ onMounted(() => {
color: #4CAF50;
}
-/* 日期选择器 */
-.date-selector {
- background: rgba(255, 255, 255, 0.9);
- padding: 15px;
- border-radius: 12px;
- margin-bottom: 20px;
- display: flex;
- align-items: center;
- gap: 10px;
- box-shadow: 0 4px 12px rgba(0,0,0,0.1);
+/* 自定义日期选择器 */
+.custom-date-selector {
+ padding: 16px 0 8px;
}
-.date-selector label {
+.date-display {
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+ cursor: pointer;
+}
+
+.date-text {
+ font-size: 12px;
+ font-weight: 500;
+ color: #999;
+}
+
+/* 日期选择弹窗 */
+.date-picker-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(0, 0, 0, 0.5);
+ display: flex;
+ align-items: flex-end;
+ z-index: 1000;
+ animation: fadeIn 0.3s ease;
+}
+
+.date-picker-popup {
+ width: 100%;
+ max-height: 70vh;
+ background: white;
+ border-radius: 20px 20px 0 0;
+ animation: slideUp 0.3s ease;
+ overflow: hidden;
+}
+
+.date-picker-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 20px;
+ border-bottom: 1px solid #eee;
+ background: #f8f9fa;
+}
+
+.date-picker-header h3 {
+ margin: 0;
+ font-size: 18px;
+ font-weight: 600;
+ color: #333;
+}
+
+.close-btn {
+ background: none;
+ border: none;
+ font-size: 24px;
+ color: #666;
+ cursor: pointer;
+ padding: 0;
+ width: 30px;
+ height: 30px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 50%;
+ transition: all 0.2s ease;
+}
+
+.close-btn:hover {
+ background: #e9ecef;
+ color: #333;
+}
+
+.date-list {
+ max-height: 400px;
+ overflow-y: auto;
+}
+
+.date-option {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 16px 20px;
+ cursor: pointer;
+ transition: all 0.2s ease;
+ border-bottom: 1px solid #f0f0f0;
+}
+
+.date-option:hover {
+ background: #f8f9fa;
+}
+
+.date-option.active {
+ background: #e3f2fd;
+ border-left: 4px solid #2196f3;
+}
+
+.date-option.active .date-label {
+ color: #2196f3;
+ font-weight: 600;
+}
+
+.date-label {
+ font-size: 16px;
font-weight: 500;
color: #333;
}
-.date-input {
- flex: 1;
- padding: 8px 12px;
- border: 2px solid #e1e5e9;
- border-radius: 8px;
- font-size: 16px;
- background: white;
+.date-value {
+ font-size: 14px;
+ color: #666;
}
-.date-input:focus {
- outline: none;
- border-color: #667eea;
+/* 动画效果 */
+@keyframes fadeIn {
+ from {
+ opacity: 0;
+ }
+ to {
+ opacity: 1;
+ }
+}
+
+@keyframes slideUp {
+ from {
+ transform: translateY(100%);
+ }
+ to {
+ transform: translateY(0);
+ }
}
/* 加载状态 */
@@ -350,35 +580,44 @@ onMounted(() => {
}
.ranking-item {
- background: rgba(255, 255, 255, 0.95);
border-radius: 16px;
- padding: 15px;
display: flex;
align-items: flex-start;
gap: 15px;
- box-shadow: 0 4px 20px rgba(0,0,0,0.1);
- transition: transform 0.2s ease, box-shadow 0.2s ease;
-}
-
-.ranking-item:hover {
- transform: translateY(-2px);
- box-shadow: 0 8px 25px rgba(0,0,0,0.15);
+ padding: 4px;
}
/* 排名数字 */
.rank-number {
- background: linear-gradient(135deg, #ff6b6b, #ee5a24);
- color: white;
- width: 32px;
- height: 32px;
- border-radius: 50%;
+ color: #333;
+ width: 16px;
+ height: 80px;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
- font-size: 14px;
+ font-size: 16px;
flex-shrink: 0;
- box-shadow: 0 2px 8px rgba(255,107,107,0.3);
+}
+
+/* 前三名特殊样式 */
+.rank-first {
+ color: #ffd700;
+ font-size: 24px;
+}
+
+.rank-second {
+ color: #afe3f6;
+ font-size: 24px;
+}
+
+.rank-third {
+ color: #cd7f32;
+ font-size: 24px;
+}
+
+.rank-normal {
+ color: #666;
}
/* 海报 */
@@ -387,8 +626,7 @@ onMounted(() => {
}
.poster-img {
- width: 60px;
- height: 80px;
+ width: 72px;
object-fit: cover;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
@@ -403,11 +641,14 @@ onMounted(() => {
.drama-name {
font-size: 16px;
font-weight: bold;
- color: #2c3e50;
+ color: #555;
margin: 0 0 8px 0;
line-height: 1.3;
}
-
+.growth-data {
+ color: #e74c3c;
+ font-size: 14px;
+}
.growth-info, .play-count {
display: flex;
align-items: center;
@@ -430,16 +671,6 @@ onMounted(() => {
font-weight: 600;
}
-.description {
- color: #7f8c8d;
- font-size: 12px;
- line-height: 1.4;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- margin-top: 8px;
-}
-
/* 空状态 */
.empty-state {
text-align: center;
@@ -499,61 +730,4 @@ onMounted(() => {
font-weight: 500;
}
-/* 移动端适配 */
-@media (max-width: 768px) {
- .main-content {
- padding: 15px;
- }
-
- .title {
- font-size: 20px;
- }
-
- .ranking-item {
- padding: 12px;
- gap: 12px;
- }
-
- .poster-img {
- width: 50px;
- height: 67px;
- }
-
- .drama-name {
- font-size: 15px;
- }
-
- .date-selector {
- padding: 12px;
- flex-direction: column;
- align-items: stretch;
- gap: 8px;
- }
-
- .date-input {
- width: 100%;
- }
-}
-
-@media (max-width: 480px) {
- .main-content {
- padding: 10px;
- }
-
- .ranking-item {
- padding: 10px;
- gap: 10px;
- }
-
- .poster-img {
- width: 45px;
- height: 60px;
- }
-
- .rank-number {
- width: 28px;
- height: 28px;
- font-size: 12px;
- }
-}
diff --git a/frontend/vite.config.js b/frontend/vite.config.js
index 4217010..63d1997 100644
--- a/frontend/vite.config.js
+++ b/frontend/vite.config.js
@@ -2,13 +2,11 @@ import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
-import vueDevTools from 'vite-plugin-vue-devtools'
// https://vite.dev/config/
export default defineConfig({
plugins: [
vue(),
- vueDevTools(),
],
resolve: {
alias: {