This commit is contained in:
zhongluofeng
2026-07-23 16:03:38 +08:00
parent 95a69b0017
commit 62db8e1982
5 changed files with 374 additions and 227 deletions
-2
View File
@@ -36,7 +36,6 @@ const displayModules = computed(() => {
'bg-primary text-primary-foreground shadow-md': activeModule === module.id, 'bg-primary text-primary-foreground shadow-md': activeModule === module.id,
'hover:bg-secondary/50': activeModule !== module.id 'hover:bg-secondary/50': activeModule !== module.id
}" }"
:title="module.name"
@click="emit('change', module.id)" @click="emit('change', module.id)"
> >
<component :is="getModuleIcon(module.icon)" class="h-5 w-5" /> <component :is="getModuleIcon(module.icon)" class="h-5 w-5" />
@@ -61,7 +60,6 @@ const displayModules = computed(() => {
'bg-primary text-primary-foreground shadow-md': activeModule === 'settings', 'bg-primary text-primary-foreground shadow-md': activeModule === 'settings',
'hover:bg-secondary/50': activeModule !== 'settings' 'hover:bg-secondary/50': activeModule !== 'settings'
}" }"
title="常规设置"
@click="emit('change', 'settings')" @click="emit('change', 'settings')"
> >
<Settings class="h-5 w-5" /> <Settings class="h-5 w-5" />
+18 -10
View File
@@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, onMounted, onUnmounted } from 'vue' import { ref, computed, onMounted, onUnmounted } from 'vue'
import { Search, Minus, X, Settings, ChevronRight } from '@lucide/vue' import { Search, Settings, ChevronRight } from '@lucide/vue'
import { Input } from '@/components/ui/input' import { Input } from '@/components/ui/input'
import { getCurrentWindow } from '@tauri-apps/api/window' import { getCurrentWindow } from '@tauri-apps/api/window'
import { useSearchStore, type SearchItem } from '@/stores/searchStore' import { useSearchStore, type SearchItem } from '@/stores/searchStore'
@@ -263,7 +263,10 @@ const handleBlur = () => {
@click="minimize" @click="minimize"
@mousedown.stop @mousedown.stop
> >
<Minus class="h-4 w-4" /> <!-- 最小化水平线1:1 渲染 + 0.5 像素偏移确保锐利 -->
<svg class="w-[10px] h-[10px]" viewBox="0 0 10 10" fill="none" stroke="currentColor" stroke-width="1" shape-rendering="geometricPrecision">
<path d="M0 5.5 H10" />
</svg>
</button> </button>
<button <button
id="titlebar-maximize" id="titlebar-maximize"
@@ -271,14 +274,16 @@ const handleBlur = () => {
@click="maximize" @click="maximize"
@mousedown.stop @mousedown.stop
> >
<!-- 最大化圆角矩形 --> <!-- 最大化正方形Windows 11 原生样式 -->
<svg v-if="!isMaximized" class="h-3 w-3" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <svg v-if="!isMaximized" class="w-[10px] h-[10px]" viewBox="0 0 10 10" fill="none" stroke="currentColor" stroke-width="1" shape-rendering="geometricPrecision">
<rect x="4" y="4" width="16" height="16" rx="2" /> <rect x="0.5" y="0.5" width="9" height="9" />
</svg> </svg>
<!-- 还原单圆角矩形 + 右上角圆角 L形顶边+右边圆角连接 --> <!-- 还原两个重叠正方形前正方形在左下后正方形在右上Windows 11 原生样式 -->
<svg v-else class="h-3 w-3" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <svg v-else class="w-[10px] h-[10px]" viewBox="0 0 10 10" fill="none" stroke="currentColor" stroke-width="1" shape-rendering="geometricPrecision">
<rect x="4" y="4" width="16" height="16" rx="2" /> <!-- 后正方形右上只勾勒未被前正方形遮挡的可见轮廓 (2.5,2.5) (7.5,7.5) 交汇点停止 -->
<path d="M14 4H20V10" /> <path d="M2.5 0.5 H9.5 V7.5 H7.5 V2.5 H2.5 Z" />
<!-- 前正方形左下完整绘制 -->
<path d="M0.5 2.5 H7.5 V9.5 H0.5 Z" />
</svg> </svg>
</button> </button>
<button <button
@@ -286,7 +291,10 @@ const handleBlur = () => {
@click="close" @click="close"
@mousedown.stop @mousedown.stop
> >
<X class="h-4 w-4" /> <!-- 关闭X 对角线 -->
<svg class="w-[10px] h-[10px]" viewBox="0 0 10 10" fill="none" stroke="currentColor" stroke-width="1.05" shape-rendering="geometricPrecision">
<path d="M0.5 0.5 L9.5 9.5 M9.5 0.5 L0.5 9.5" />
</svg>
</button> </button>
</div> </div>
</div> </div>
+284 -182
View File
@@ -21,6 +21,7 @@ import { Switch } from '@/components/ui/switch'
import { Input } from '@/components/ui/input' import { Input } from '@/components/ui/input'
import { Textarea } from '@/components/ui/textarea' import { Textarea } from '@/components/ui/textarea'
import { Label } from '@/components/ui/label' import { Label } from '@/components/ui/label'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
import { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/ui/tabs' import { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/ui/tabs'
import { ScrollArea } from '@/components/ui/scroll-area' import { ScrollArea } from '@/components/ui/scroll-area'
import { Separator } from '@/components/ui/separator' import { Separator } from '@/components/ui/separator'
@@ -506,16 +507,20 @@ const toggleSortOrder = () => {
<!-- 工具栏筛选 / 排序 / 搜索 --> <!-- 工具栏筛选 / 排序 / 搜索 -->
<div class="shrink-0 flex items-center gap-2 flex-wrap"> <div class="shrink-0 flex items-center gap-2 flex-wrap">
<!-- 新建下载按钮 --> <!-- 新建下载按钮 -->
<Button <Tooltip>
size="sm" <TooltipTrigger as-child>
class="h-8 gap-1.5" <Button
:disabled="addingTask" size="sm"
title="添加下载链接" class="h-8 gap-1.5"
@click="addDialogOpen = true" :disabled="addingTask"
> @click="addDialogOpen = true"
<Plus class="h-4 w-4" /> >
新建下载 <Plus class="h-4 w-4" />
</Button> 新建下载
</Button>
</TooltipTrigger>
<TooltipContent>添加下载链接</TooltipContent>
</Tooltip>
<!-- 状态筛选 --> <!-- 状态筛选 -->
<Select v-model="statusFilter"> <Select v-model="statusFilter">
@@ -550,16 +555,20 @@ const toggleSortOrder = () => {
</Select> </Select>
<!-- 升降序切换 --> <!-- 升降序切换 -->
<Button <Tooltip>
size="sm" <TooltipTrigger as-child>
variant="outline" <Button
class="h-8 w-8 p-0 bg-transparent" size="sm"
:title="sortOrder === 'asc' ? '升序(点击切换降序)' : '降序(点击切换升序)'" variant="outline"
@click="toggleSortOrder" class="h-8 w-8 p-0 bg-transparent"
> @click="toggleSortOrder"
<ArrowUp v-if="sortOrder === 'asc'" class="h-4 w-4" /> >
<ArrowDown v-else class="h-4 w-4" /> <ArrowUp v-if="sortOrder === 'asc'" class="h-4 w-4" />
</Button> <ArrowDown v-else class="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>{{ sortOrder === 'asc' ? '升序(点击切换降序)' : '降序(点击切换升序)' }}</TooltipContent>
</Tooltip>
<!-- 搜索框 --> <!-- 搜索框 -->
<div class="relative flex-1 min-w-[180px] max-w-xs"> <div class="relative flex-1 min-w-[180px] max-w-xs">
@@ -571,16 +580,20 @@ const toggleSortOrder = () => {
/> />
</div> </div>
<Button <Tooltip>
size="sm" <TooltipTrigger as-child>
variant="outline" <Button
class="h-8 gap-1.5 bg-transparent" size="sm"
title="下载设置" variant="outline"
@click="downloadSettingsOpen = true" class="h-8 gap-1.5 bg-transparent"
> @click="downloadSettingsOpen = true"
<SettingsIcon class="h-4 w-4" /> >
下载设置 <SettingsIcon class="h-4 w-4" />
</Button> 下载设置
</Button>
</TooltipTrigger>
<TooltipContent>下载设置</TooltipContent>
</Tooltip>
<span class="text-xs text-muted-foreground ml-auto"> <span class="text-xs text-muted-foreground ml-auto">
{{ sortedTasks.length }} 个任务 {{ sortedTasks.length }} 个任务
@@ -603,9 +616,14 @@ const toggleSortOrder = () => {
<div class="flex items-start justify-between gap-3 mb-3"> <div class="flex items-start justify-between gap-3 mb-3">
<div class="flex-1 min-w-0"> <div class="flex-1 min-w-0">
<div class="flex items-center gap-2 mb-1"> <div class="flex items-center gap-2 mb-1">
<span class="font-medium truncate" :title="getFileName(task)"> <Tooltip>
{{ getFileName(task) }} <TooltipTrigger as-child>
</span> <span class="font-medium truncate cursor-default">
{{ getFileName(task) }}
</span>
</TooltipTrigger>
<TooltipContent>{{ getFileName(task) }}</TooltipContent>
</Tooltip>
<Badge <Badge
:variant="getTaskStatusBadge(task).variant" :variant="getTaskStatusBadge(task).variant"
class="shrink-0" class="shrink-0"
@@ -626,67 +644,85 @@ const toggleSortOrder = () => {
<Zap class="h-2.5 w-2.5" /> <Zap class="h-2.5 w-2.5" />
{{ task.segments.length }} 连接 {{ task.segments.length }} 连接
</Badge> </Badge>
<span <Tooltip v-if="task.dir">
v-if="task.dir" <TooltipTrigger as-child>
class="truncate max-w-md cursor-help" <span class="truncate max-w-md cursor-default">
:title="task.dir" {{ truncatePath(task.dir) }}
> </span>
{{ truncatePath(task.dir) }} </TooltipTrigger>
</span> <TooltipContent class="max-w-[400px] break-all">{{ task.dir }}</TooltipContent>
</Tooltip>
<span v-if="task.error" class="text-destructive"> <span v-if="task.error" class="text-destructive">
{{ task.error }} {{ task.error }}
</span> </span>
</div> </div>
</div> </div>
<div class="flex items-center gap-1 shrink-0"> <div class="flex items-center gap-1 shrink-0">
<Button <Tooltip v-if="task.status === 'active' || task.status === 'queued'">
v-if="task.status === 'active' || task.status === 'queued'" <TooltipTrigger as-child>
size="icon" <Button
variant="ghost" size="icon"
class="h-8 w-8" variant="ghost"
:title="task.status === 'queued' ? '取消排队' : '暂停'" class="h-8 w-8"
@click="handlePause(task.id)" @click="handlePause(task.id)"
> >
<Pause class="h-4 w-4" /> <Pause class="h-4 w-4" />
</Button> </Button>
<Button </TooltipTrigger>
v-if="task.status === 'paused' || task.status === 'error'" <TooltipContent>{{ task.status === 'queued' ? '取消排队' : '暂停' }}</TooltipContent>
size="icon" </Tooltip>
variant="ghost" <Tooltip v-if="task.status === 'paused' || task.status === 'error'">
class="h-8 w-8" <TooltipTrigger as-child>
title="继续" <Button
@click="handleResume(task.id)" size="icon"
> variant="ghost"
<Play class="h-4 w-4" /> class="h-8 w-8"
</Button> @click="handleResume(task.id)"
<Button >
size="icon" <Play class="h-4 w-4" />
variant="ghost" </Button>
class="h-8 w-8" </TooltipTrigger>
title="详细信息" <TooltipContent>继续</TooltipContent>
@click="handleShowDetail(task)" </Tooltip>
> <Tooltip>
<Info class="h-4 w-4" /> <TooltipTrigger as-child>
</Button> <Button
<Button size="icon"
v-if="task.dir" variant="ghost"
size="icon" class="h-8 w-8"
variant="ghost" @click="handleShowDetail(task)"
class="h-8 w-8" >
title="打开目录" <Info class="h-4 w-4" />
@click="handleOpenDir(task)" </Button>
> </TooltipTrigger>
<FolderOpen class="h-4 w-4" /> <TooltipContent>详细信息</TooltipContent>
</Button> </Tooltip>
<Button <Tooltip v-if="task.dir">
size="icon" <TooltipTrigger as-child>
variant="ghost" <Button
class="h-8 w-8 text-destructive hover:text-destructive" size="icon"
title="删除" variant="ghost"
@click="handleRemove(task)" class="h-8 w-8"
> @click="handleOpenDir(task)"
<Trash2 class="h-4 w-4" /> >
</Button> <FolderOpen class="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>打开目录</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger as-child>
<Button
size="icon"
variant="ghost"
class="h-8 w-8 text-destructive hover:text-destructive"
@click="handleRemove(task)"
>
<Trash2 class="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>删除</TooltipContent>
</Tooltip>
</div> </div>
</div> </div>
<Progress :model-value="getProgress(task)" class="h-1.5" /> <Progress :model-value="getProgress(task)" class="h-1.5" />
@@ -702,51 +738,67 @@ const toggleSortOrder = () => {
<!-- 分页控件 --> <!-- 分页控件 -->
<div v-if="totalPages > 1" class="flex items-center justify-center gap-2 pt-2 pb-4"> <div v-if="totalPages > 1" class="flex items-center justify-center gap-2 pt-2 pb-4">
<Button <Tooltip>
size="sm" <TooltipTrigger as-child>
variant="outline" <Button
class="h-8 w-8 p-0" size="sm"
:disabled="currentPage <= 1" variant="outline"
title="第一页" class="h-8 w-8 p-0"
@click="currentPage = 1" :disabled="currentPage <= 1"
> @click="currentPage = 1"
<ChevronLeft class="h-4 w-4" /> >
<ChevronLeft class="h-4 w-4 -ml-2" /> <ChevronLeft class="h-4 w-4" />
</Button> <ChevronLeft class="h-4 w-4 -ml-2" />
<Button </Button>
size="sm" </TooltipTrigger>
variant="outline" <TooltipContent>第一页</TooltipContent>
class="h-8 w-8 p-0" </Tooltip>
:disabled="currentPage <= 1" <Tooltip>
title="上一页" <TooltipTrigger as-child>
@click="currentPage--" <Button
> size="sm"
<ChevronLeft class="h-4 w-4" /> variant="outline"
</Button> class="h-8 w-8 p-0"
:disabled="currentPage <= 1"
@click="currentPage--"
>
<ChevronLeft class="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>上一页</TooltipContent>
</Tooltip>
<span class="text-xs text-muted-foreground px-2"> <span class="text-xs text-muted-foreground px-2">
{{ currentPage }} / {{ totalPages }} {{ currentPage }} / {{ totalPages }}
</span> </span>
<Button <Tooltip>
size="sm" <TooltipTrigger as-child>
variant="outline" <Button
class="h-8 w-8 p-0" size="sm"
:disabled="currentPage >= totalPages" variant="outline"
title="下一页" class="h-8 w-8 p-0"
@click="currentPage++" :disabled="currentPage >= totalPages"
> @click="currentPage++"
<ChevronRight class="h-4 w-4" /> >
</Button> <ChevronRight class="h-4 w-4" />
<Button </Button>
size="sm" </TooltipTrigger>
variant="outline" <TooltipContent>下一页</TooltipContent>
class="h-8 w-8 p-0" </Tooltip>
:disabled="currentPage >= totalPages" <Tooltip>
title="最后一页" <TooltipTrigger as-child>
@click="currentPage = totalPages" <Button
> size="sm"
<ChevronRight class="h-4 w-4" /> variant="outline"
<ChevronRight class="h-4 w-4 -ml-2" /> class="h-8 w-8 p-0"
</Button> :disabled="currentPage >= totalPages"
@click="currentPage = totalPages"
>
<ChevronRight class="h-4 w-4" />
<ChevronRight class="h-4 w-4 -ml-2" />
</Button>
</TooltipTrigger>
<TooltipContent>最后一页</TooltipContent>
</Tooltip>
</div> </div>
</ScrollArea> </ScrollArea>
</div> </div>
@@ -781,9 +833,14 @@ const toggleSortOrder = () => {
class="font-mono text-sm" class="font-mono text-sm"
@update:model-value="(v: string | number) => store.settings && (store.settings.downloadDir = String(v))" @update:model-value="(v: string | number) => store.settings && (store.settings.downloadDir = String(v))"
/> />
<Button variant="outline" size="icon" title="选择目录" @click="handleSelectSettingsDir"> <Tooltip>
<FolderOpen class="h-4 w-4" /> <TooltipTrigger as-child>
</Button> <Button variant="outline" size="icon" @click="handleSelectSettingsDir">
<FolderOpen class="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>选择目录</TooltipContent>
</Tooltip>
</div> </div>
</div> </div>
<div class="grid grid-cols-2 gap-3"> <div class="grid grid-cols-2 gap-3">
@@ -900,19 +957,28 @@ const toggleSortOrder = () => {
<div class="flex items-center justify-between gap-2"> <div class="flex items-center justify-between gap-2">
<div class="flex flex-col gap-0.5 min-w-0"> <div class="flex flex-col gap-0.5 min-w-0">
<Label class="text-xs text-muted-foreground">API 地址</Label> <Label class="text-xs text-muted-foreground">API 地址</Label>
<span class="font-mono text-sm truncate" :title="store.extensionInfo.url"> <Tooltip>
{{ store.extensionInfo.url }} <TooltipTrigger as-child>
</span> <span class="font-mono text-sm truncate cursor-default">
{{ store.extensionInfo.url }}
</span>
</TooltipTrigger>
<TooltipContent class="max-w-[400px] break-all">{{ store.extensionInfo.url }}</TooltipContent>
</Tooltip>
</div> </div>
<Button <Tooltip>
size="icon" <TooltipTrigger as-child>
variant="ghost" <Button
class="h-8 w-8 shrink-0" size="icon"
title="复制 API 地址" variant="ghost"
@click="handleCopy(store.extensionInfo.url, 'API 地址')" class="h-8 w-8 shrink-0"
> @click="handleCopy(store.extensionInfo.url, 'API 地址')"
<Copy class="h-4 w-4" /> >
</Button> <Copy class="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>复制 API 地址</TooltipContent>
</Tooltip>
</div> </div>
<div class="flex items-center justify-between gap-2"> <div class="flex items-center justify-between gap-2">
@@ -923,27 +989,33 @@ const toggleSortOrder = () => {
</span> </span>
</div> </div>
<div class="flex gap-1 shrink-0"> <div class="flex gap-1 shrink-0">
<Button <Tooltip v-if="store.extensionInfo.secret">
v-if="store.extensionInfo.secret" <TooltipTrigger as-child>
size="icon" <Button
variant="ghost" size="icon"
class="h-8 w-8" variant="ghost"
:title="showSecret ? '隐藏' : '显示'" class="h-8 w-8"
@click="showSecret = !showSecret" @click="showSecret = !showSecret"
> >
<Eye v-if="!showSecret" class="h-4 w-4" /> <Eye v-if="!showSecret" class="h-4 w-4" />
<EyeOff v-else class="h-4 w-4" /> <EyeOff v-else class="h-4 w-4" />
</Button> </Button>
<Button </TooltipTrigger>
v-if="store.extensionInfo.secret" <TooltipContent>{{ showSecret ? '隐藏' : '显示' }}</TooltipContent>
size="icon" </Tooltip>
variant="ghost" <Tooltip v-if="store.extensionInfo.secret">
class="h-8 w-8" <TooltipTrigger as-child>
title="复制密钥" <Button
@click="handleCopy(store.extensionInfo.secret, '密钥')" size="icon"
> variant="ghost"
<Copy class="h-4 w-4" /> class="h-8 w-8"
</Button> @click="handleCopy(store.extensionInfo.secret, '密钥')"
>
<Copy class="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>复制密钥</TooltipContent>
</Tooltip>
</div> </div>
</div> </div>
</div> </div>
@@ -1002,9 +1074,14 @@ const toggleSortOrder = () => {
class="font-mono text-sm" class="font-mono text-sm"
@update:model-value="(v: string | number) => store.settings && (store.settings.downloadDir = String(v))" @update:model-value="(v: string | number) => store.settings && (store.settings.downloadDir = String(v))"
/> />
<Button variant="outline" size="icon" title="选择目录" @click="handleSelectSettingsDir"> <Tooltip>
<FolderOpen class="h-4 w-4" /> <TooltipTrigger as-child>
</Button> <Button variant="outline" size="icon" @click="handleSelectSettingsDir">
<FolderOpen class="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>选择目录</TooltipContent>
</Tooltip>
</div> </div>
</div> </div>
@@ -1112,9 +1189,14 @@ const toggleSortOrder = () => {
placeholder="留空使用默认目录" placeholder="留空使用默认目录"
class="font-mono text-sm" class="font-mono text-sm"
/> />
<Button variant="outline" size="icon" title="选择目录" @click="handleSelectDir"> <Tooltip>
<FolderOpen class="h-4 w-4" /> <TooltipTrigger as-child>
</Button> <Button variant="outline" size="icon" @click="handleSelectDir">
<FolderOpen class="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>选择目录</TooltipContent>
</Tooltip>
</div> </div>
<p v-if="store.settings?.downloadDir" class="text-xs text-muted-foreground"> <p v-if="store.settings?.downloadDir" class="text-xs text-muted-foreground">
当前默认 当前默认
@@ -1191,9 +1273,14 @@ const toggleSortOrder = () => {
<span class="text-xs text-muted-foreground">文件名</span> <span class="text-xs text-muted-foreground">文件名</span>
<span class="font-medium break-all">{{ detailDialogState.task.filename }}</span> <span class="font-medium break-all">{{ detailDialogState.task.filename }}</span>
</div> </div>
<Button size="icon" variant="ghost" class="h-7 w-7 shrink-0" title="复制文件名" @click="handleCopyText(detailDialogState.task.filename, '文件名')"> <Tooltip>
<Copy class="h-3.5 w-3.5" /> <TooltipTrigger as-child>
</Button> <Button size="icon" variant="ghost" class="h-7 w-7 shrink-0" @click="handleCopyText(detailDialogState.task.filename, '文件名')">
<Copy class="h-3.5 w-3.5" />
</Button>
</TooltipTrigger>
<TooltipContent>复制文件名</TooltipContent>
</Tooltip>
</div> </div>
<Separator /> <Separator />
@@ -1213,9 +1300,14 @@ const toggleSortOrder = () => {
<span class="text-xs text-muted-foreground">下载链接</span> <span class="text-xs text-muted-foreground">下载链接</span>
<span class="font-mono text-xs break-all">{{ detailDialogState.task.url }}</span> <span class="font-mono text-xs break-all">{{ detailDialogState.task.url }}</span>
</div> </div>
<Button size="icon" variant="ghost" class="h-7 w-7 shrink-0" title="复制链接" @click="handleCopyText(detailDialogState.task.url, '下载链接')"> <Tooltip>
<Copy class="h-3.5 w-3.5" /> <TooltipTrigger as-child>
</Button> <Button size="icon" variant="ghost" class="h-7 w-7 shrink-0" @click="handleCopyText(detailDialogState.task.url, '下载链接')">
<Copy class="h-3.5 w-3.5" />
</Button>
</TooltipTrigger>
<TooltipContent>复制链接</TooltipContent>
</Tooltip>
</div> </div>
<Separator /> <Separator />
@@ -1224,12 +1316,22 @@ const toggleSortOrder = () => {
<div class="flex items-start justify-between gap-2"> <div class="flex items-start justify-between gap-2">
<div class="flex flex-col gap-0.5 min-w-0 flex-1"> <div class="flex flex-col gap-0.5 min-w-0 flex-1">
<span class="text-xs text-muted-foreground">保存位置</span> <span class="text-xs text-muted-foreground">保存位置</span>
<span class="font-mono text-xs break-all" :title="detailDialogState.task.dir">{{ detailDialogState.task.dir }}</span> <Tooltip>
<TooltipTrigger as-child>
<span class="font-mono text-xs break-all cursor-default">{{ detailDialogState.task.dir }}</span>
</TooltipTrigger>
<TooltipContent class="max-w-[400px] break-all">{{ detailDialogState.task.dir }}</TooltipContent>
</Tooltip>
<span class="font-mono text-xs text-muted-foreground break-all">{{ detailDialogState.task.filename }}</span> <span class="font-mono text-xs text-muted-foreground break-all">{{ detailDialogState.task.filename }}</span>
</div> </div>
<Button size="icon" variant="ghost" class="h-7 w-7 shrink-0" title="复制完整路径" @click="handleCopyText(detailDialogState.task.dir + '\\' + detailDialogState.task.filename, '完整路径')"> <Tooltip>
<Copy class="h-3.5 w-3.5" /> <TooltipTrigger as-child>
</Button> <Button size="icon" variant="ghost" class="h-7 w-7 shrink-0" @click="handleCopyText(detailDialogState.task.dir + '\\' + detailDialogState.task.filename, '完整路径')">
<Copy class="h-3.5 w-3.5" />
</Button>
</TooltipTrigger>
<TooltipContent>复制完整路径</TooltipContent>
</Tooltip>
</div> </div>
<Separator /> <Separator />
+11 -6
View File
@@ -4,6 +4,7 @@ import { Switch } from '@/components/ui/switch'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Label } from '@/components/ui/label' import { Label } from '@/components/ui/label'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
import { useAppStore, type Theme, type EffectType, type ModuleInfo } from '@/stores/appStore' import { useAppStore, type Theme, type EffectType, type ModuleInfo } from '@/stores/appStore'
import { useSearchStore } from '@/stores/searchStore' import { useSearchStore } from '@/stores/searchStore'
import { useProcessStore } from '@/stores/processStore' import { useProcessStore } from '@/stores/processStore'
@@ -265,12 +266,16 @@ const onDragEnd = () => {
:class="{ 'opacity-60': isModuleToggling(module.id) }" :class="{ 'opacity-60': isModuleToggling(module.id) }"
> >
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<div <Tooltip>
class="drag-handle cursor-grab active:cursor-grabbing text-muted-foreground/40 hover:text-muted-foreground transition-colors" <TooltipTrigger as-child>
title="拖拽排序" <div
> class="drag-handle cursor-grab active:cursor-grabbing text-muted-foreground/40 hover:text-muted-foreground transition-colors"
<GripVertical class="h-4 w-4 no-native-drag" /> >
</div> <GripVertical class="h-4 w-4 no-native-drag" />
</div>
</TooltipTrigger>
<TooltipContent>拖拽排序</TooltipContent>
</Tooltip>
<div <div
class="w-9 h-9 rounded-lg flex items-center justify-center" class="w-9 h-9 rounded-lg flex items-center justify-center"
:class="module.enabled ? 'bg-primary/10 text-primary' : 'bg-muted text-muted-foreground'" :class="module.enabled ? 'bg-primary/10 text-primary' : 'bg-muted text-muted-foreground'"
+61 -27
View File
@@ -22,6 +22,7 @@ import { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/ui/tabs'
import { ScrollArea } from '@/components/ui/scroll-area' import { ScrollArea } from '@/components/ui/scroll-area'
import { Separator } from '@/components/ui/separator' import { Separator } from '@/components/ui/separator'
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from '@/components/ui/accordion' import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from '@/components/ui/accordion'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
import { Progress } from '@/components/ui/progress' import { Progress } from '@/components/ui/progress'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
import { import {
@@ -924,9 +925,14 @@ const saveSettingsForm = async () => {
</div> </div>
<div v-if="store.kernel?.exists" class="flex items-center justify-between"> <div v-if="store.kernel?.exists" class="flex items-center justify-between">
<span class="text-muted-foreground">当前版本</span> <span class="text-muted-foreground">当前版本</span>
<Badge variant="secondary" class="font-mono text-xs" :title="store.kernel?.version ?? ''"> <Tooltip>
{{ versionShort }} <TooltipTrigger as-child>
</Badge> <Badge variant="secondary" class="font-mono text-xs cursor-default">
{{ versionShort }}
</Badge>
</TooltipTrigger>
<TooltipContent>{{ store.kernel?.version ?? '' }}</TooltipContent>
</Tooltip>
</div> </div>
<div v-if="kernelUpdateInfo" class="flex items-center justify-between"> <div v-if="kernelUpdateInfo" class="flex items-center justify-between">
<span class="text-muted-foreground">最新版本</span> <span class="text-muted-foreground">最新版本</span>
@@ -947,19 +953,33 @@ const saveSettingsForm = async () => {
<div class="flex items-center justify-between gap-3"> <div class="flex items-center justify-between gap-3">
<span class="text-muted-foreground shrink-0">路径</span> <span class="text-muted-foreground shrink-0">路径</span>
<div class="flex items-center gap-1.5 min-w-0"> <div class="flex items-center gap-1.5 min-w-0">
<span <Tooltip>
v-if="store.kernel?.exists" <TooltipTrigger as-child>
class="font-mono text-xs text-right truncate" <span
:title="store.kernel?.path ?? ''" v-if="store.kernel?.exists"
>{{ pathDisplay || pathShort }}</span> class="font-mono text-xs text-right truncate cursor-default"
<span v-else class="font-mono text-xs text-right" :title="store.kernel?.path ?? ''">{{ pathShort }}</span> >{{ pathDisplay || pathShort }}</span>
<span v-else class="font-mono text-xs text-right cursor-default">{{ pathShort }}</span>
</TooltipTrigger>
<TooltipContent class="max-w-[400px] break-all">{{ store.kernel?.path ?? '' }}</TooltipContent>
</Tooltip>
<template v-if="store.kernel?.exists"> <template v-if="store.kernel?.exists">
<Button size="icon-xs" variant="ghost" title="复制路径" @click="copyPath"> <Tooltip>
<Copy class="size-3" /> <TooltipTrigger as-child>
</Button> <Button size="icon-xs" variant="ghost" @click="copyPath">
<Button size="icon-xs" variant="ghost" title="在文件夹中显示" @click="openFolder"> <Copy class="size-3" />
<FolderOpen class="size-3" /> </Button>
</Button> </TooltipTrigger>
<TooltipContent>复制路径</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger as-child>
<Button size="icon-xs" variant="ghost" @click="openFolder">
<FolderOpen class="size-3" />
</Button>
</TooltipTrigger>
<TooltipContent>在文件夹中显示</TooltipContent>
</Tooltip>
</template> </template>
</div> </div>
</div> </div>
@@ -1448,18 +1468,32 @@ const saveSettingsForm = async () => {
</p> </p>
</div> </div>
<div class="flex gap-1 shrink-0"> <div class="flex gap-1 shrink-0">
<Button size="icon-sm" variant="ghost" title="更新" @click="doUpdate(p.id)"> <Tooltip>
<RefreshCw class="size-3.5" /> <TooltipTrigger as-child>
</Button> <Button size="icon-sm" variant="ghost" @click="doUpdate(p.id)">
<Button <RefreshCw class="size-3.5" />
v-if="store.settings.currentProfile !== p.id" </Button>
size="icon-sm" variant="ghost" title="切换" @click="doActivate(p.id)" </TooltipTrigger>
> <TooltipContent>更新</TooltipContent>
<Check class="size-3.5" /> </Tooltip>
</Button> <Tooltip v-if="store.settings.currentProfile !== p.id">
<Button size="icon-sm" variant="ghost" title="删除" @click="doDelete(p.id, p.name)"> <TooltipTrigger as-child>
<Trash2 class="size-3.5 text-destructive" /> <Button
</Button> size="icon-sm" variant="ghost" @click="doActivate(p.id)"
>
<Check class="size-3.5" />
</Button>
</TooltipTrigger>
<TooltipContent>切换</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger as-child>
<Button size="icon-sm" variant="ghost" @click="doDelete(p.id, p.name)">
<Trash2 class="size-3.5 text-destructive" />
</Button>
</TooltipTrigger>
<TooltipContent>删除</TooltipContent>
</Tooltip>
</div> </div>
</div> </div>
</div> </div>