Files
spark-store/src/components/DownloadQueue.vue
T
xiyidaiwa b89c001401 refactor: 基于 upstream/Erotica 重新整合本地功能(来源选择/合并详情/计数/窗口/首页)
将本地在 upstream !408(已安装应用合并+统计)之上的后续改动重新整合到最新 upstream/Erotica:
- 已安装应用:卸载/打开按 APM/Spark 来源选择;计数总数=APM+Spark 包数(双来源计为独立包)
- 查看详情:已安装页复用所有应用页合并详情视图(单来源优先已装类型,双来源自动模式)
- 窗口:恢复阈值改为 1600x900,过大回退默认尺寸并居中,不自动最大化
- 首页推荐:致谢卡片移至其他内容下方,加大标题/卡片/致谢间距
- 隐藏排行榜/荣耀榜侧栏入口(代码保留,v-if=false)
- 新增 scripts/test-build.sh 测试打包脚本(版本末段+1 加 -test)并更新 AGENTS.md

冲突文件(index.ts/App.vue/InstalledAppsModal.vue)均取本地完整实现(为上游版本的超集)。
2026-08-03 11:06:28 +08:00

185 lines
6.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<!-- 空队列仅显示右下角小按钮 -->
<button
v-if="downloads.length === 0"
type="button"
class="fixed bottom-4 right-4 z-40 inline-flex h-10 w-10 items-center justify-center rounded-full border border-slate-200/70 bg-white text-slate-500 shadow-lg transition hover:-translate-y-0.5 hover:text-brand dark:border-slate-700 dark:bg-slate-900 dark:text-slate-400 dark:hover:text-white sm:bottom-6 sm:right-6"
title="暂无下载任务"
aria-label="下载队列"
>
<i class="fas fa-download"></i>
</button>
<!-- 有任务展开为完整面板默认展开可点 chevron 折叠列表 -->
<div
v-else
class="fixed inset-x-4 bottom-4 z-40 rounded-3xl border border-slate-200/70 bg-white shadow-2xl transition-all duration-200 dark:border-slate-800/70 dark:bg-slate-900 sm:left-auto sm:right-6 sm:w-96"
>
<div
class="flex items-center justify-between px-5 py-4"
@click="toggleExpand"
>
<div
class="flex items-center gap-2 text-sm font-semibold text-slate-700 dark:text-slate-200"
>
<i class="fas fa-download text-brand"></i>
<span>下载队列</span>
<span
v-if="downloads.length"
class="rounded-full bg-slate-100 px-2 py-0.5 text-xs font-medium text-slate-500 dark:bg-slate-800/70 dark:text-slate-300"
>
({{ completedDownloads }}/{{ downloads.length }})
</span>
</div>
<div class="flex items-center gap-2">
<button
v-if="downloads.length"
type="button"
class="inline-flex h-9 w-9 items-center justify-center rounded-full border border-slate-200/70 text-slate-500 transition hover:text-slate-900 dark:border-slate-700 dark:text-slate-400"
title="清除已完成"
@click.stop="clearCompleted"
>
<i class="fas fa-broom"></i>
</button>
<button
type="button"
class="inline-flex h-9 w-9 items-center justify-center rounded-full border border-slate-200/70 text-slate-500 transition hover:text-slate-900 dark:border-slate-700 dark:text-slate-400 dark:hover:bg-slate-800 dark:hover:text-white"
@click.stop="toggleExpand"
>
<i
class="fas"
:class="isExpanded ? 'fa-chevron-down' : 'fa-chevron-up'"
></i>
</button>
</div>
</div>
<Transition
enter-active-class="duration-200 ease-out"
enter-from-class="opacity-0 -translate-y-2"
enter-to-class="opacity-100 translate-y-0"
leave-active-class="duration-150 ease-in"
leave-from-class="opacity-100 translate-y-0"
leave-to-class="opacity-0 -translate-y-2"
>
<div
v-show="isExpanded"
class="max-h-96 overflow-y-auto overscroll-contain px-3 pb-4"
>
<div class="space-y-2">
<div
v-for="download in downloads"
:key="download.id"
class="flex cursor-pointer items-center gap-3 rounded-2xl border border-slate-200/70 bg-white/90 p-3 shadow-sm transition hover:border-brand/40 hover:shadow-lg dark:border-slate-800/70 dark:bg-slate-900"
:class="
download.status === 'failed'
? 'border-rose-300/70 dark:border-rose-500/40'
: ''
"
@click="showDownloadDetail(download)"
>
<div
class="h-12 w-12 overflow-hidden rounded-xl bg-slate-100 dark:bg-slate-800"
>
<img
:src="download.icon"
:alt="download.name"
class="h-full w-full object-cover"
/>
</div>
<div class="flex-1">
<p
class="truncate text-sm font-semibold text-slate-800 dark:text-slate-100"
>
{{ download.name }}
</p>
<p class="text-xs text-slate-500 dark:text-slate-400">
<span v-if="download.status === 'downloading'"
>下载中 {{ Math.floor(download.progress * 100) }}%</span
>
<span v-else-if="download.status === 'installing'"
>安装中...</span
>
<span v-else-if="download.status === 'completed'">已完成</span>
<span v-else-if="download.status === 'failed'"
>失败: {{ download.error }}</span
>
<span v-else-if="download.status === 'paused'">已暂停</span>
<span v-else>等待中...</span>
</p>
<div
v-if="download.status === 'downloading'"
class="mt-2 h-1.5 rounded-full bg-slate-100 dark:bg-slate-800"
>
<div
class="h-full rounded-full bg-brand"
:style="{ width: `${download.progress * 100}%` }"
></div>
</div>
</div>
<div class="flex items-center gap-2">
<button
v-if="download.status === 'failed'"
type="button"
class="inline-flex h-9 w-9 items-center justify-center rounded-full border border-rose-200/60 text-rose-500 transition hover:bg-rose-50"
title="重试"
@click.stop="retryDownload(download)"
>
<i class="fas fa-redo"></i>
</button>
</div>
</div>
</div>
</div>
</Transition>
</div>
</template>
<script setup lang="ts">
import { computed, ref, watch } from "vue";
import type { DownloadItem } from "../global/typedefinition";
const props = defineProps<{
downloads: DownloadItem[];
}>();
const emit = defineEmits<{
(e: "pause", download: DownloadItem): void;
(e: "resume", download: DownloadItem): void;
(e: "cancel", download: DownloadItem): void;
(e: "retry", download: DownloadItem): void;
(e: "clear-completed"): void;
(e: "show-detail", download: DownloadItem): void;
}>();
const isExpanded = ref(true);
const completedDownloads = computed(() => {
return props.downloads.filter((d) => d.status === "completed").length;
});
const toggleExpand = () => {
isExpanded.value = !isExpanded.value;
};
const retryDownload = (download: DownloadItem) => {
emit("retry", download);
};
const clearCompleted = () => {
emit("clear-completed");
};
const showDownloadDetail = (download: DownloadItem) => {
emit("show-detail", download);
};
// 从无任务到有任务时,自动展开面板("有任务时再向左边伸出")
watch(
() => props.downloads.length > 0,
(hasTasks) => {
if (hasTasks) isExpanded.value = true;
},
);
</script>