下载/主界面优化

This commit is contained in:
2026-07-22 22:26:40 +08:00
parent f7d3c13f35
commit 95a69b0017
16 changed files with 295 additions and 106 deletions
+4 -4
View File
@@ -640,17 +640,17 @@ const toggleSortOrder = () => {
</div>
<div class="flex items-center gap-1 shrink-0">
<Button
v-if="task.status === 'active'"
v-if="task.status === 'active' || task.status === 'queued'"
size="icon"
variant="ghost"
class="h-8 w-8"
title="暂停"
:title="task.status === 'queued' ? '取消排队' : '暂停'"
@click="handlePause(task.id)"
>
<Pause class="h-4 w-4" />
</Button>
<Button
v-if="task.status === 'paused' || task.status === 'queued' || task.status === 'error'"
v-if="task.status === 'paused' || task.status === 'error'"
size="icon"
variant="ghost"
class="h-8 w-8"
@@ -1099,7 +1099,7 @@ const toggleSortOrder = () => {
<Textarea
v-model="addUriText"
placeholder="https://example.com/file.zip&#10;https://example.com/file2.zip"
class="min-h-[120px] font-mono text-sm"
class="min-h-[120px] font-mono text-sm [field-sizing:fixed] break-all"
/>
</div>
+101 -23
View File
@@ -558,26 +558,40 @@ const handleCheckUpdate = async () => {
}
const handleUpdateKernel = async () => {
const ok = await showConfirm({
title: '更新内核',
description: '更新内核需要先停止 mihomo,确认继续?',
confirmText: '继续更新'
})
if (!ok) return
updatingKernel.value = true
try {
// 先停止
if (running.value) {
// 展开更新区块(下载源选择 + 进度),由 handleStartUpdate 执行实际更新
updateExpanded.value = true
}
/** 是否展开"更新内核"区块(下载源 + 进度) */
const updateExpanded = ref(false)
/** 开始更新:停止 mihomo → 调用 updateKernel(复用 installProgress 进度机制) */
const handleStartUpdate = async () => {
if (store.installing) return
// 确认停止 mihomo
if (running.value) {
const ok = await showConfirm({
title: '更新内核',
description: '更新内核需要先停止 mihomo,确认继续?',
confirmText: '继续更新'
})
if (!ok) return
updatingKernel.value = true
try {
await store.stop()
} catch (e) {
toast.error('停止 mihomo 失败', { description: String(e) })
updatingKernel.value = false
return
} finally {
updatingKernel.value = false
}
toast.info('正在下载并安装内核...')
await store.updateKernel()
toast.success('内核更新完成')
kernelUpdateInfo.value = null
}
toast.info('开始下载更新...')
try {
await store.updateKernel(selectedMirrorPrefix.value)
} catch (e) {
toast.error('内核更新失败', { description: String(e) })
} finally {
updatingKernel.value = false
}
}
@@ -653,7 +667,8 @@ const handleInstallKernel = async () => {
}
}
// 监听安装进度终态,弹 toast 并延时清空进度
// 监听安装/更新进度终态,弹 toast 并延时清空进度
// 同时处理更新场景下的 updateExpanded 清理(与 installProgress 同步清除,避免更新区块闪烁)
watch(
() => store.installProgress?.stage,
(stage) => {
@@ -661,13 +676,22 @@ watch(
toast.success('内核安装完成', {
description: store.installProgress?.message
})
// 2 秒后清空进度,让用户看到 100% 终态
setTimeout(() => store.clearInstallProgress(), 2000)
if (updateExpanded.value) {
kernelUpdateInfo.value = null
}
// 2 秒后同时清空进度和更新区块,让用户看到 100% 终态
setTimeout(() => {
store.clearInstallProgress()
updateExpanded.value = false
}, 2000)
} else if (stage === 'error') {
toast.error('内核安装失败', {
description: store.installProgress?.message
})
setTimeout(() => store.clearInstallProgress(), 5000)
setTimeout(() => {
store.clearInstallProgress()
// 错误时不清除 updateExpanded,让用户可以重新选择下载源重试
}, 5000)
}
}
)
@@ -912,11 +936,10 @@ const saveSettingsForm = async () => {
v-if="kernelUpdateInfo.hasUpdate"
key="btn-update"
size="xs" variant="default"
:disabled="updatingKernel"
:disabled="store.installing || updateExpanded"
@click="handleUpdateKernel"
>
<Loader2 v-if="updatingKernel" class="size-3 animate-spin" />
<Download v-else key="icon-download" class="size-3" />更新
<Download key="icon-download" class="size-3" />更新
</Button>
<Check v-else key="icon-updated" class="size-3 text-emerald-500" />
</span>
@@ -941,6 +964,61 @@ const saveSettingsForm = async () => {
</div>
</div>
<!-- 更新内核区块检查到更新且用户点击"更新"后展开复用首次安装的下载源选择 UI -->
<div
v-if="updateExpanded && !store.installProgress"
class="space-y-2 pt-2 border-t"
>
<div class="space-y-1.5">
<Label class="text-xs text-muted-foreground">下载源</Label>
<Select v-model="mirrorChoice">
<SelectTrigger size="sm" class="w-full">
<SelectValue placeholder="选择下载源" />
</SelectTrigger>
<SelectContent>
<SelectItem
v-for="m in MIRROR_PRESETS"
:key="m.value"
:value="m.value"
>
{{ m.label }}
</SelectItem>
</SelectContent>
</Select>
<p class="text-xs text-muted-foreground">
{{ MIRROR_PRESETS.find(m => m.value === mirrorChoice)?.hint }}
</p>
</div>
<div v-if="mirrorChoice === '__custom'" class="space-y-1.5">
<Label class="text-xs text-muted-foreground">镜像站前缀</Label>
<Input
v-model="customMirror"
placeholder="如 https://ghproxy.net/"
class="h-8 text-xs"
/>
<p class="text-xs text-muted-foreground">
前缀会拼接到 GitHub 下载链接前需以 / 结尾自动补全
</p>
</div>
<div class="flex gap-2">
<Button
size="sm" variant="outline" class="flex-1"
:disabled="store.installing || updatingKernel"
@click="updateExpanded = false"
>
取消
</Button>
<Button
size="sm" variant="default" class="flex-1"
:disabled="store.installing || updatingKernel || (mirrorChoice === '__custom' && !customMirror.trim())"
@click="handleStartUpdate"
>
<Loader2 v-if="store.installing || updatingKernel" class="size-4 animate-spin" />
<DownloadCloud v-else class="size-4" />开始更新
</Button>
</div>
</div>
<!-- 首次安装区块仅在内核未安装且不在安装中且已初始化时显示 -->
<div
v-if="store.initialized && !store.kernel?.exists && !store.installProgress"