优化扫描
All checks were successful
Go CI / test-and-build (push) Successful in 14s
Web CI / lint-test-build (push) Successful in 28s

This commit is contained in:
2026-04-11 13:57:48 +08:00
parent 169b2c1858
commit 3f82e29c6c
11 changed files with 392 additions and 76 deletions

View File

@@ -4,6 +4,20 @@
<FolderOpen :size="32" />
</div>
<h4 class="card-name">{{ props.name }}</h4>
<div v-if="scanStatus" class="scan-status" :class="{ running: scanStatus.running, failed: !!scanStatus.error }">
<span class="scan-status-title">
{{ scanStatus.running ? '扫描中' : scanStatus.error ? '扫描失败' : '最近一次扫描' }}
</span>
<span v-if="scanStatus.running && scanStatus.report" class="scan-status-text">
{{ scanStatus.report.processed }} / {{ scanStatus.report.total_files || 0 }}
</span>
<span v-else-if="scanStatus.report" class="scan-status-text">
新增 {{ scanStatus.report.added }} · 跳过 {{ scanStatus.report.skipped }} · 失败 {{ scanStatus.report.failed_files?.length || 0 }}
</span>
<span v-else-if="scanStatus.error" class="scan-status-text">{{ scanStatus.error }}</span>
</div>
<DropDown>
<template v-slot:trigger>
<button class="card-menu-btn" aria-label="更多操作"><EllipsisVertical :size="16" /></button>
@@ -12,9 +26,9 @@
<ListMusic class="dropdown-icon" :size="16" />
<span class="dropdown-text">查看歌曲</span>
</button>
<button class="dropdown-item" @click="scanCard">
<RotateCw class="dropdown-icon" :size="16" />
<span class="dropdown-text">扫描</span>
<button class="dropdown-item" :disabled="scanStatus?.running" @click="scanCard">
<RotateCw class="dropdown-icon" :class="{ spinning: scanStatus?.running }" :size="16" />
<span class="dropdown-text">{{ scanStatus?.running ? '扫描中' : '扫描' }}</span>
</button>
<button class="dropdown-item danger" type="button" @click="deleteCard">
<Trash2 class="dropdown-icon" :size="16" />
@@ -31,10 +45,12 @@ import DropDown from './DropDown.vue'
const props = defineProps({
name: String,
id: Number,
scanStatus: Object,
})
const emit = defineEmits(['delete', 'scan', 'viewSongs'])
const scanCard = () => {
if (props.scanStatus?.running) return
emit('scan', props.id)
}
const deleteCard = () => {
@@ -90,7 +106,34 @@ const viewSongs = () => {
max-width: 100%;
}
/* 菜单按钮 */
.scan-status {
display: flex;
flex-direction: column;
align-items: center;
gap: 2px;
min-height: 40px;
text-align: center;
}
.scan-status-title {
font-size: var(--font-size-0);
color: var(--text-secondary);
font-weight: 600;
}
.scan-status-text {
font-size: var(--font-size-0);
color: var(--text-muted);
}
.scan-status.running .scan-status-title {
color: var(--brand);
}
.scan-status.failed .scan-status-title {
color: var(--red-7);
}
.card-menu-btn {
position: absolute;
top: var(--size-2);
@@ -116,4 +159,22 @@ const viewSongs = () => {
background-color: var(--gray-3);
color: var(--text-primary);
}
.dropdown-item:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.spinning {
animation: spin 1s linear infinite;
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
</style>