优化黑夜
This commit is contained in:
parent
83e23b7365
commit
e4a0ac71cc
149
vue/src/App.vue
149
vue/src/App.vue
@ -44,14 +44,39 @@
|
||||
<input
|
||||
v-model="searchKeyword"
|
||||
type="search"
|
||||
placeholder="请输入标题、标签、资源库或维护人"
|
||||
placeholder="🔍 输入关键词搜索..."
|
||||
@focus="isSearchFocused = true"
|
||||
@blur="isSearchFocused = false"
|
||||
@keydown.enter="handleHeroSearch"
|
||||
/>
|
||||
<button type="button" @click="handleHeroSearch">搜索</button>
|
||||
</div>
|
||||
|
||||
<!-- 黑夜/白天模式切换按钮 -->
|
||||
<button
|
||||
type="button"
|
||||
class="theme-toggle-btn"
|
||||
:class="{ 'theme-toggle-btn--dark': isDarkMode }"
|
||||
@click="toggleDarkMode"
|
||||
:title="isDarkMode ? '切换到白天模式' : '切换到黑夜模式'"
|
||||
>
|
||||
<svg class="theme-toggle-btn__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<g v-if="!isDarkMode" class="theme-icon--sun">
|
||||
<circle cx="12" cy="12" r="5"></circle>
|
||||
<line x1="12" y1="1" x2="12" y2="3"></line>
|
||||
<line x1="12" y1="21" x2="12" y2="23"></line>
|
||||
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
|
||||
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
|
||||
<line x1="1" y1="12" x2="3" y2="12"></line>
|
||||
<line x1="21" y1="12" x2="23" y2="12"></line>
|
||||
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
|
||||
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
|
||||
</g>
|
||||
<g v-if="isDarkMode" class="theme-icon--moon">
|
||||
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<!-- 快捷入口按钮和悬浮面板 -->
|
||||
<div class="quick-access-wrapper" ref="quickAccessWrapperRef" @mouseenter="handleQuickAccessEnter" @mouseleave="handleQuickAccessWrapperLeave">
|
||||
<button
|
||||
@ -366,6 +391,14 @@
|
||||
<button type="button" class="folder-tree-actions__btn" @click="handleOpenScraperLogDialog">
|
||||
📋 刮削日志
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="folder-tree-actions__btn folder-tree-actions__btn--refresh"
|
||||
@click="handleRefreshFolders"
|
||||
title="刷新当前网盘文件夹列表"
|
||||
>
|
||||
🗂️ 刷新文件夹
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="folder-tree-actions__btn"
|
||||
@ -458,9 +491,13 @@
|
||||
{{ getStatusText(scrapeStatusData.status) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="scrape-status-message">
|
||||
<div v-if="scrapeStatusData.message" class="scrape-status-message">
|
||||
{{ scrapeStatusData.message }}
|
||||
</div>
|
||||
<!-- 失败时显示详细错误信息 -->
|
||||
<div v-if="scrapeStatusData.status === 'failed' && scrapeStatusData.error" class="scrape-status-error">
|
||||
<strong>失败原因:</strong>{{ scrapeStatusData.error }}
|
||||
</div>
|
||||
<div v-if="scrapeStatusData.posterUrl" class="scrape-status-poster">
|
||||
<img :src="scrapeStatusData.posterUrl" alt="海报" />
|
||||
</div>
|
||||
@ -564,13 +601,13 @@
|
||||
<div class="log-entry__header" @click="toggleLogDetail(log.id)">
|
||||
<div class="log-entry__summary">
|
||||
<span class="log-entry__toggle">{{ log.showDetail ? '▾' : '▸' }}</span>
|
||||
<span class="log-entry__time">{{ log.scanTime || log.createTime || '-' }}</span>
|
||||
<span class="log-entry__desc">{{ log.description || '刮削任务执行记录' }}</span>
|
||||
<span class="log-entry__time">{{ log.scanTime || '-' }}</span>
|
||||
<span class="log-entry__desc">{{ getStatusText(log.status) || '刮削任务执行记录' }}</span>
|
||||
</div>
|
||||
<div class="log-entry__stats">
|
||||
<span class="stat-total">总共: {{ log.totalMovies || log.total || 0 }}</span>
|
||||
<span class="stat-success">成功: {{ log.successCount || log.success || 0 }}</span>
|
||||
<span class="stat-fail">失败: {{ log.failCount || log.failed || 0 }}</span>
|
||||
<span class="stat-total">总共: {{ log.totalMovies || 0 }}</span>
|
||||
<span class="stat-success">成功: {{ log.successCount || 0 }}</span>
|
||||
<span class="stat-fail">失败: {{ log.failCount || 0 }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -578,11 +615,10 @@
|
||||
<Transition name="slide-down">
|
||||
<div v-if="log.showDetail && log.detailList && log.detailList.length > 0" class="log-entry__detail">
|
||||
<div v-for="(item, idx) in log.detailList" :key="idx" class="detail-item">
|
||||
<span class="detail-item__name">{{ item.movieName || item.title || '未知电影' }}</span>
|
||||
<span class="detail-item__status" :class="`detail-item__status--${item.status}`">
|
||||
{{ item.status === 'success' ? '✓ 成功' : item.status === 'failed' ? '✗ 失败' : '⋯ 处理中' }}
|
||||
<span class="detail-item__name">👤 {{ item.username || '用户 ' + (item.userId || idx) }}</span>
|
||||
<span class="detail-item__status detail-item__status--info">
|
||||
处理: {{ item.processed || 0 }} | 成功: {{ item.success || 0 }} | 失败: {{ item.failed || 0 }} | 跳过: {{ item.skipped || 0 }}
|
||||
</span>
|
||||
<span v-if="item.message" class="detail-item__message">{{ item.message }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
@ -845,6 +881,7 @@ const searchKeyword = ref('')
|
||||
const isSearchFocused = ref(false)
|
||||
const hasSearched = ref(false)
|
||||
const currentView = ref('poster')
|
||||
const isDarkMode = ref(false) // 黑夜模式开关
|
||||
const activeSheetId = ref('')
|
||||
const showRecordDialog = ref(false)
|
||||
const showFolderDialog = ref(false)
|
||||
@ -1678,11 +1715,52 @@ async function loadMoreScraperLogs() {
|
||||
|
||||
const logsRes = await fetchScraperLogs(params)
|
||||
|
||||
console.log('[刮削日志] 后端返回原始数据:', logsRes)
|
||||
|
||||
if (logsRes?.code === 200 && Array.isArray(logsRes?.data?.list)) {
|
||||
const newLogs = logsRes.data.list
|
||||
|
||||
console.log('[刮削日志] 日志列表数据:', newLogs)
|
||||
console.log('[刮削日志] 第一条日志的字段:', Object.keys(newLogs[0] || {}))
|
||||
if (newLogs[0]) {
|
||||
console.log('[刮削日志] 第一条日志完整数据:', JSON.stringify(newLogs[0], null, 2))
|
||||
}
|
||||
|
||||
// 标准化日志数据字段(兼容不同的字段名)
|
||||
const normalizedLogs = newLogs.map(log => {
|
||||
// 解析 detail_json 字符串为数组
|
||||
let detailList = []
|
||||
if (log.detail_json) {
|
||||
try {
|
||||
detailList = typeof log.detail_json === 'string'
|
||||
? JSON.parse(log.detail_json)
|
||||
: log.detail_json
|
||||
} catch (e) {
|
||||
console.warn('解析 detail_json 失败:', e)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...log,
|
||||
// 确保 showDetail 属性可设置
|
||||
showDetail: false,
|
||||
// 后端字段映射(使用实际的后端字段名)
|
||||
totalMovies: log.total_processed ?? log.totalMovies ?? log.total ?? 0,
|
||||
successCount: log.total_success ?? log.successCount ?? log.success ?? 0,
|
||||
failCount: log.total_failed ?? log.failCount ?? log.failed ?? 0,
|
||||
totalSkipped: log.total_skipped ?? 0,
|
||||
scanTime: log.start_time ?? log.create_time ?? log.createTime ?? '-',
|
||||
endTime: log.end_time ?? '',
|
||||
durationMs: log.duration_ms ?? 0,
|
||||
status: log.status ?? 'unknown',
|
||||
triggerType: log.trigger_type ?? 'manual',
|
||||
// 解析后的详细信息列表
|
||||
detailList: detailList,
|
||||
}
|
||||
})
|
||||
|
||||
// 追加到现有日志列表
|
||||
scraperLogs.value.push(...newLogs)
|
||||
scraperLogs.value.push(...normalizedLogs)
|
||||
|
||||
// 更新分页信息
|
||||
scraperLogPagination.total = logsRes.data.total || 0
|
||||
@ -2491,6 +2569,28 @@ function preloadImage(url) {
|
||||
img.src = url
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新当前网盘文件夹列表
|
||||
*/
|
||||
async function handleRefreshFolders() {
|
||||
const driveId = activeSheetId.value
|
||||
if (!driveId) {
|
||||
setErrorMessage('请先选择一个网盘')
|
||||
return
|
||||
}
|
||||
|
||||
driveLoading.value = true
|
||||
try {
|
||||
await loadDriveFolders(driveId)
|
||||
setSuccessMessage('文件夹列表已刷新')
|
||||
} catch (err) {
|
||||
console.error('刷新文件夹列表失败', err)
|
||||
setErrorMessage(err?.message || '刷新文件夹列表失败')
|
||||
} finally {
|
||||
driveLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 刮削状态查询
|
||||
function handleScrapeStatus(node) {
|
||||
// 只有文件类型才显示刮削状态
|
||||
@ -2521,7 +2621,7 @@ function handleScrapeStatus(node) {
|
||||
rating: data.rating,
|
||||
category: data.category,
|
||||
tags: data.tags,
|
||||
error: data.error,
|
||||
error: data.error || data.message,
|
||||
}
|
||||
} else {
|
||||
setErrorMessage(result?.message || '查询刮削状态失败')
|
||||
@ -2805,6 +2905,27 @@ onMounted(() => {
|
||||
resumeFeaturedAutoplay()
|
||||
})
|
||||
|
||||
// 黑夜/白天模式切换函数
|
||||
function toggleDarkMode() {
|
||||
isDarkMode.value = !isDarkMode.value
|
||||
// 更新 body 的 class
|
||||
document.body.classList.toggle('dark-mode', isDarkMode.value)
|
||||
// 保存到 localStorage
|
||||
localStorage.setItem('darkMode', isDarkMode.value ? '1' : '0')
|
||||
}
|
||||
|
||||
// 从 localStorage 读取黑夜模式偏好
|
||||
function initDarkMode() {
|
||||
const savedMode = localStorage.getItem('darkMode')
|
||||
if (savedMode === '1') {
|
||||
isDarkMode.value = true
|
||||
document.body.classList.add('dark-mode')
|
||||
}
|
||||
}
|
||||
|
||||
// 在 onMounted 之前调用初始化
|
||||
initDarkMode()
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('wangpan:unauthorized', handleUnauthorized)
|
||||
window.removeEventListener('wangpan:forbidden', handleForbidden)
|
||||
|
||||
1246
vue/src/style.css
1246
vue/src/style.css
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user