improvement(entry-ui): 优化首页检测与导入流程界面

- 重构首页布局,突出检测、导入、导出归档和聊天回看等常用入口
- 优化检测结果页的信息层级、加载态、手动路径选择和微信安装目录设置区域
- 优化导入页面布局,补充目录选择说明、导入流程提示、导入进度和完成态展示
- 统一入口页面的卡片、按钮、背景和响应式样式,提升操作引导清晰度
This commit is contained in:
2977094657
2026-04-25 23:24:52 +08:00
Unverified
parent 2f8af245ea
commit a1c8d3059c
3 changed files with 565 additions and 474 deletions
+226 -234
View File
@@ -1,297 +1,289 @@
<template>
<div class="detection-result-page min-h-screen relative overflow-hidden">
<!-- 网格背景 -->
<div class="absolute inset-0 bg-grid-pattern opacity-5 pointer-events-none"></div>
<!-- 装饰元素 -->
<div class="absolute top-20 left-20 w-72 h-72 bg-[#07C160] opacity-5 rounded-full blur-3xl pointer-events-none"></div>
<div class="absolute top-40 right-20 w-96 h-96 bg-[#10AEEF] opacity-5 rounded-full blur-3xl pointer-events-none"></div>
<div class="absolute -bottom-8 left-40 w-80 h-80 bg-[#91D300] opacity-5 rounded-full blur-3xl pointer-events-none"></div>
<!-- 主要内容 -->
<div class="relative z-10 w-full max-w-5xl mx-auto px-4 sm:px-5 py-6 sm:py-8 animate-fade-in">
<!-- 顶部操作栏 -->
<div class="flex items-center justify-between mb-4">
<div>
<h2 class="text-[22px] font-bold leading-none">
<span class="bg-gradient-to-r from-[#07C160] to-[#10AEEF] bg-clip-text text-transparent">检测结果</span>
</h2>
<div class="detection-result-page relative min-h-screen overflow-hidden px-3 py-4 text-[#000000e6] sm:px-5 sm:py-5">
<div class="pointer-events-none absolute inset-0 bg-grid-pattern opacity-5"></div>
<div class="pointer-events-none absolute left-20 top-20 h-72 w-72 rounded-full bg-[#07C160] opacity-5 blur-3xl"></div>
<div class="pointer-events-none absolute right-20 top-40 h-96 w-96 rounded-full bg-[#10AEEF] opacity-5 blur-3xl"></div>
<div class="pointer-events-none absolute -bottom-8 left-40 h-80 w-80 rounded-full bg-[#91D300] opacity-5 blur-3xl"></div>
<main class="relative z-10 mx-auto w-full max-w-6xl">
<div class="mb-3 flex flex-col gap-3 rounded-lg border border-[#DDEBE0] bg-[#F4FAF6]/82 p-4 backdrop-blur sm:p-5 lg:flex-row lg:items-start lg:justify-between">
<div class="min-w-0">
<p class="text-[12px] font-medium tracking-[0.16em] text-[#07C160]">本地检测</p>
<h1 class="mt-1.5 text-[30px] font-semibold leading-tight tracking-[-0.04em] text-[#000000e6] sm:text-[38px]">
{{ loading ? '正在检测微信数据' : detectionResult?.error ? '需要手动指定目录' : '找到可操作的微信账号' }}
</h1>
<p class="mt-2 max-w-3xl text-[14px] leading-6 text-[#6B7280]">
{{ loading ? '正在检查微信安装信息、账号目录和数据库文件。' : detectionResult?.error ? '自动检测没有找到可用数据,可以在下方手动选择 xwechat_files 目录后重试。' : '选择要处理的账号进入解密提取。如果结果不完整,可以手动指定数据根目录后重新检测。' }}
</p>
</div>
<NuxtLink to="/"
class="inline-flex items-center px-3 py-1.5 rounded-lg text-xs text-[#07C160] hover:text-[#06AD56] hover:bg-white/80 font-medium transition-colors">
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"/>
<NuxtLink
to="/"
class="inline-flex shrink-0 items-center rounded-lg border border-[#CFEEDB] bg-[#F7FDF9]/82 px-2.5 py-1.5 text-xs font-medium text-[#07C160] transition hover:border-[#CFEEDB] hover:bg-[#F7FDF9] focus:outline-none focus:ring-2 focus:ring-[#07C160]/20"
>
<svg class="mr-1.5 h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
</svg>
返回首页
</NuxtLink>
</div>
<div
v-if="detectionResult && !loading && !detectionResult.error"
class="grid grid-cols-1 sm:grid-cols-3 gap-2.5 mb-4"
>
<div class="bg-white/90 backdrop-blur rounded-xl px-4 py-3 border border-[#EDEDED]">
<div class="flex items-center justify-between gap-3">
<div class="min-w-0">
<p class="text-[11px] tracking-[0.08em] uppercase text-[#7F7F7F]">微信版本</p>
<p class="mt-1 text-lg font-semibold text-[#000000e6] truncate">{{ detectionResult.data?.wechat_version || '未知' }}</p>
<div v-if="loading" class="flex min-h-[48vh] items-center justify-center">
<div class="w-full max-w-3xl rounded-lg border border-[#DDF4E7] bg-[#F7FDF9]/76 p-4 backdrop-blur sm:p-5">
<div class="flex flex-col gap-4">
<div class="flex items-start justify-between gap-3">
<div class="min-w-0">
<div class="flex items-center gap-2 text-[13px] font-medium text-[#07C160]">
<svg class="h-4 w-4 animate-spin" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2.5" class="opacity-20"></circle>
<path d="M21 12a9 9 0 0 0-9-9" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"></path>
</svg>
<span>正在检测</span>
</div>
<h3 class="mt-2 text-[22px] font-semibold leading-tight tracking-[-0.03em] text-[#000000e6] sm:text-[28px]">
正在寻找可用的微信数据
</h3>
<p class="mt-1.5 max-w-2xl text-[14px] leading-6 text-[#6B7280]">
这一步会自动检查本机环境匹配账号并统计数据库文件检测期间请保持当前页面打开
</p>
</div>
<span class="hidden shrink-0 rounded-md border border-[#CFEEDB] bg-[#F4FBF6]/86 px-2.5 py-1 text-[12px] font-medium text-[#07C160] sm:inline-flex">
自动进行
</span>
</div>
<div class="w-9 h-9 shrink-0 bg-[#07C160]/10 rounded-lg flex items-center justify-center">
<svg class="w-[18px] h-[18px] text-[#07C160]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
</div>
</div>
</div>
<div class="bg-white/90 backdrop-blur rounded-xl px-4 py-3 border border-[#EDEDED]">
<div class="flex items-center justify-between gap-3">
<div class="min-w-0">
<p class="text-[11px] tracking-[0.08em] uppercase text-[#7F7F7F]">检测账号</p>
<p class="mt-1 text-lg font-semibold text-[#000000e6]">{{ detectionResult.data?.total_accounts || 0 }} </p>
</div>
<div class="w-9 h-9 shrink-0 bg-[#10AEEF]/10 rounded-lg flex items-center justify-center">
<svg class="w-[18px] h-[18px] text-[#10AEEF]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283-.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"/>
</svg>
</div>
</div>
</div>
<div class="space-y-2.5 rounded-lg border border-[#DDEBE0] bg-[#F4FAF6]/82 p-3">
<div class="h-2 overflow-hidden rounded-full border border-[#DDF4E7] bg-[#F7FCF8]/86">
<div class="h-full w-1/2 rounded-full bg-[#07C160] animate-pulse"></div>
</div>
<div class="bg-white/90 backdrop-blur rounded-xl px-4 py-3 border border-[#EDEDED]">
<div class="flex items-center justify-between gap-3">
<div class="min-w-0">
<p class="text-[11px] tracking-[0.08em] uppercase text-[#7F7F7F]">数据库文件</p>
<p class="mt-1 text-lg font-semibold text-[#000000e6]">{{ detectionResult.data?.total_databases || 0 }} </p>
<div class="grid gap-2 sm:grid-cols-3">
<div class="rounded-md border border-[#E1EFE5] bg-[#F7FCF8]/86 px-2.5 py-2.5">
<div class="flex items-center gap-2 text-[13px] font-medium text-[#000000e6]">
<span class="h-1.5 w-1.5 rounded-full bg-[#07C160]"></span>
<span>检查环境</span>
</div>
<p class="mt-1 text-[12px] leading-5 text-[#7F7F7F]">读取微信安装与数据目录</p>
</div>
<div class="rounded-md border border-[#E1EFE5] bg-[#F7FCF8]/86 px-2.5 py-2.5">
<div class="flex items-center gap-2 text-[13px] font-medium text-[#000000e6]">
<span class="h-1.5 w-1.5 rounded-full bg-[#07C160]"></span>
<span>匹配账号</span>
</div>
<p class="mt-1 text-[12px] leading-5 text-[#7F7F7F]">找到可操作的本地账号</p>
</div>
<div class="rounded-md border border-[#E1EFE5] bg-[#F7FCF8]/86 px-2.5 py-2.5">
<div class="flex items-center gap-2 text-[13px] font-medium text-[#000000e6]">
<span class="h-1.5 w-1.5 rounded-full bg-[#07C160]"></span>
<span>汇总数据</span>
</div>
<p class="mt-1 text-[12px] leading-5 text-[#7F7F7F]">整理后续解密所需信息</p>
</div>
</div>
</div>
<div class="w-9 h-9 shrink-0 bg-[#91D300]/10 rounded-lg flex items-center justify-center">
<svg class="w-[18px] h-[18px] text-[#91D300]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4"/>
</svg>
<div class="flex flex-col gap-2 border-t border-[#DDF4E7] pt-3 text-[12px] leading-5 text-[#7F7F7F] sm:flex-row sm:items-center sm:justify-between">
<span>如果等待时间较长通常是本地文件较多或磁盘读取较慢</span>
<span class="font-medium text-[#07C160]">请稍候</span>
</div>
</div>
</div>
</div>
<!-- 第一步检测数据目录与微信安装目录都在这里设置 -->
<div v-if="!loading" class="bg-white/90 backdrop-blur rounded-xl p-3.5 md:p-4 border border-[#EDEDED] mb-4 space-y-3">
<div class="flex flex-col md:flex-row md:items-center justify-between gap-3">
<div>
<h3 class="text-[13px] font-semibold text-[#000000e6] flex items-center">
未找到想要的账号
<!-- <span class="ml-2 px-2 py-0.5 bg-gray-100 text-gray-500 rounded text-xs font-normal">深度检测兜底</span>-->
</h3>
<p class="text-[11px] text-[#7F7F7F] mt-1">
<span v-if="customPath">当前指定检测路径:<span class="font-mono bg-gray-50 px-1 rounded text-[#000000e6]">{{ customPath }}</span></span>
<span v-else>如果自动检测漏了您可以手动指定微信数据根目录 (通常名为 xwechat_files) 让系统重新扫描</span>
</p>
<section v-else class="grid gap-4 lg:grid-cols-[0.82fr_1.18fr]">
<aside class="space-y-3">
<div
v-if="detectionResult && !detectionResult.error"
class="grid grid-cols-1 gap-2.5 sm:grid-cols-3 lg:grid-cols-3"
>
<div class="rounded-lg border border-[#CFEEDB] bg-[#EFFAF3]/82 p-3 backdrop-blur">
<p class="text-[12px] font-medium text-[#5F6F66]">微信版本</p>
<p class="mt-1.5 truncate text-[22px] font-semibold tracking-[-0.03em] text-[#000000e6]">{{ detectionResult.data?.wechat_version || '未知' }}</p>
</div>
<div class="rounded-lg border border-[#DDEBE0] bg-[#F4FAF6]/82 p-3 backdrop-blur">
<p class="text-[12px] font-medium text-[#5F6F66]">检测账号</p>
<p class="mt-1.5 text-[22px] font-semibold tracking-[-0.03em] text-[#000000e6]">{{ detectionResult.data?.total_accounts || 0 }} </p>
</div>
<div class="rounded-lg border border-[#CFEEDB] bg-[#F1FAF4]/82 p-3 backdrop-blur">
<p class="text-[12px] font-medium text-[#5F6F66]">数据库文件</p>
<p class="mt-1.5 text-[22px] font-semibold tracking-[-0.03em] text-[#000000e6]">{{ detectionResult.data?.total_databases || 0 }} </p>
</div>
</div>
<button @click="handlePickDirectory" :disabled="loading"
class="shrink-0 px-4 py-2.5 bg-[#07C160] text-white rounded-xl text-xs font-medium hover:bg-[#06AD56] focus:ring-2 focus:ring-[#07C160] focus:ring-offset-1 disabled:opacity-50 transition-all duration-200 flex items-center justify-center">
<svg v-if="!loading" class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"/>
</svg>
<svg v-else class="w-4 h-4 mr-2 animate-spin" fill="none" viewBox="0 0 48 48" aria-hidden="true">
<circle class="opacity-20" cx="24" cy="24" r="18" stroke="currentColor" stroke-width="6"></circle>
<circle
cx="24"
cy="24"
r="18"
stroke="currentColor"
stroke-width="6"
stroke-linecap="round"
stroke-dasharray="28 72"
pathLength="100"
transform="rotate(-90 24 24)"
></circle>
</svg>
{{ loading ? '检测中...' : '手动选择目录检测' }}
</button>
</div>
<div class="pt-3 border-t border-[#F3F3F3]">
<label for="wechatInstallPath" class="block text-[13px] font-medium text-[#000000e6] mb-2">
微信安装目录第一步先填这里
</label>
<div class="flex flex-col lg:flex-row gap-3">
<div class="rounded-lg border border-[#DDEBE0] bg-[#F4FAF6]/82 p-4 backdrop-blur sm:p-5">
<div class="flex items-center justify-between gap-2.5">
<div>
<div class="text-[15px] font-medium text-[#000000e6]">手动补充路径</div>
<p class="mt-1 text-[12px] leading-5 text-[#7F7F7F]">自动检测不完整时可以指定微信数据根目录重新扫描</p>
</div>
</div>
<div v-if="customPath" class="mt-3 rounded-md border border-[#E1EFE5] bg-[#F7FCF8]/86 px-2.5 py-2.5">
<p class="text-[12px] font-medium text-[#5F6F66]">当前检测路径</p>
<p class="mt-1 break-all font-mono text-[12px] leading-5 text-[#000000d9]">{{ customPath }}</p>
</div>
<button
type="button"
:disabled="loading"
class="mt-3 inline-flex w-full items-center justify-center rounded-lg bg-[#07C160] px-3 py-2.5 text-sm font-medium text-white transition hover:bg-[#06AD56] focus:outline-none focus:ring-2 focus:ring-[#07C160]/25 disabled:opacity-50"
@click="handlePickDirectory"
>
<svg v-if="!loading" class="mr-2 h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" />
</svg>
<svg v-else class="mr-2 h-4 w-4 animate-spin" fill="none" viewBox="0 0 48 48" aria-hidden="true">
<circle class="opacity-20" cx="24" cy="24" r="18" stroke="currentColor" stroke-width="6"></circle>
<circle cx="24" cy="24" r="18" stroke="currentColor" stroke-width="6" stroke-linecap="round" stroke-dasharray="28 72" pathLength="100" transform="rotate(-90 24 24)"></circle>
</svg>
{{ loading ? '检测中...' : '选择 xwechat_files 目录' }}
</button>
</div>
<div class="rounded-lg border border-[#DDEBE0] bg-[#F4FAF6]/82 p-4 backdrop-blur sm:p-5">
<label for="wechatInstallPath" class="block text-[15px] font-medium text-[#000000e6]">
微信安装目录
</label>
<p class="mt-1 text-[12px] leading-5 text-[#7F7F7F]">
一键获取数据库密钥会优先使用这里的路径
</p>
<input
id="wechatInstallPath"
v-model="wechatInstallPath"
type="text"
placeholder="例如: D:\Program Files\Tencent\WeChat 或 D:\Program Files\Tencent\WeChat\Weixin.exe"
class="flex-1 px-4 py-2.5 bg-white border border-[#EDEDED] rounded-lg font-mono text-[13px] focus:outline-none focus:ring-2 focus:ring-[#07C160] focus:border-transparent transition-all duration-200"
class="mt-3 w-full rounded-lg border border-[#DDEBE0] bg-[#F7FCF8]/86 px-3 py-2 font-mono text-[13px] text-[#000000d9] transition focus:border-[#07C160] focus:outline-none focus:ring-2 focus:ring-[#07C160]/20"
@blur="persistWechatInstallPath"
/>
<button
type="button"
@click="pickWechatInstallDirectory"
:disabled="isPickingWechatInstallPath"
class="shrink-0 px-4 py-2.5 bg-white border border-[#EDEDED] text-[#000000e6] rounded-xl text-xs font-medium hover:bg-gray-50 disabled:opacity-50 disabled:cursor-wait transition-all duration-200"
class="mt-2 inline-flex w-full items-center justify-center rounded-lg border border-[#DDEBE0] bg-[#F7FCF8]/86 px-3 py-2 text-sm font-medium text-[#4A4A4A] transition hover:bg-[#F1FAF4] focus:outline-none focus:ring-2 focus:ring-[#07C160]/15 disabled:cursor-wait disabled:opacity-50"
@click="pickWechatInstallDirectory"
>
{{ isPickingWechatInstallPath ? '选择中...' : '选择微信目录' }}
</button>
</div>
<p class="text-[11px] text-[#7F7F7F] mt-2">
一键获取数据库密钥会优先使用这里填写的路径支持填写安装目录也支持直接填写 <span class="font-mono">Weixin.exe</span> / <span class="font-mono">WeChat.exe</span> 路径
</p>
</div>
</div>
<!-- 主内容区域 -->
<div :class="loading ? 'flex min-h-[52vh] items-center justify-center' : ''">
<!-- 检测中状态 -->
<div v-if="loading" class="w-full max-w-3xl rounded-[24px] border border-[#EDEDED] bg-white/92 px-5 py-6 sm:px-8 sm:py-7">
<div class="flex flex-col items-center text-center">
<div class="relative flex h-12 w-12 items-center justify-center rounded-2xl bg-[#07C160]/10">
<span class="absolute inset-0 rounded-2xl border border-[#07C160]/10"></span>
<svg class="h-5 w-5 animate-spin text-[#07C160]" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2.5" class="opacity-20"></circle>
<path d="M21 12a9 9 0 0 0-9-9" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"></path>
</svg>
</div>
</aside>
<div class="mt-4 flex flex-wrap items-center justify-center gap-2">
<span class="inline-flex items-center rounded-full bg-[#07C160]/10 px-2.5 py-1 text-[11px] font-medium text-[#07C160]">
检测中
</span>
<span class="text-[11px] text-[#7F7F7F]">正在自动读取本机微信环境</span>
</div>
<h3 class="mt-3 text-[20px] font-semibold text-[#000000e6] leading-tight">正在检查账号与数据库文件</h3>
<p class="mt-2 max-w-[560px] text-[13px] leading-6 text-[#7F7F7F]">
会依次确认微信安装信息最近登录账号以及可用数据库通常几秒内完成
</p>
<div class="mt-5 h-1.5 w-full max-w-[620px] overflow-hidden rounded-full bg-[#F3F4F6]">
<div class="h-full w-2/5 rounded-full bg-gradient-to-r from-[#07C160] via-[#34D17A] to-[#8CE0AF] animate-pulse"></div>
</div>
<div class="mt-5 flex flex-wrap items-center justify-center gap-2.5">
<div class="inline-flex items-center gap-2 rounded-full border border-[#EDEDED] bg-[#FAFAFA] px-3 py-2 text-[12px] text-[#000000d9]">
<span class="h-2 w-2 rounded-full bg-[#07C160] animate-pulse"></span>
<span>安装信息</span>
</div>
<div class="inline-flex items-center gap-2 rounded-full border border-[#EDEDED] bg-[#FAFAFA] px-3 py-2 text-[12px] text-[#000000d9]">
<span class="h-2 w-2 rounded-full bg-[#07C160] animate-pulse"></span>
<span>账号匹配</span>
</div>
<div class="inline-flex items-center gap-2 rounded-full border border-[#EDEDED] bg-[#FAFAFA] px-3 py-2 text-[12px] text-[#000000d9]">
<span class="h-2 w-2 rounded-full bg-[#07C160] animate-pulse"></span>
<span>数据库汇总</span>
<div class="rounded-lg border border-[#DDEBE0] bg-[#F4FAF6]/82 p-4 backdrop-blur sm:p-5">
<div v-if="detectionResult?.error" class="flex min-h-[340px] flex-col justify-between gap-4">
<div>
<div class="flex items-center gap-2 text-[13px] font-medium text-[#D64A4A]">
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<span>未找到微信数据</span>
</div>
<h2 class="mt-3 text-[22px] font-semibold tracking-[-0.03em] text-[#000000e6] sm:text-[28px]">可以手动指定目录重试</h2>
<p class="mt-2 text-[14px] leading-6 text-[#9C5F5F]">{{ detectionResult.error }}</p>
</div>
<div class="rounded-lg border border-[#F4D6D6] bg-[#FFF7F7] p-3 text-[13px] leading-6 text-[#9C5F5F]">
请尝试选择微信数据根目录通常名为 <span class="font-mono">xwechat_files</span>
</div>
<button
type="button"
class="inline-flex w-full items-center justify-center rounded-lg bg-[#07C160] px-3 py-2.5 text-sm font-medium text-white transition hover:bg-[#06AD56] focus:outline-none focus:ring-2 focus:ring-[#07C160]/25"
@click="handlePickDirectory"
>
重新选择目录
</button>
</div>
</div>
<!-- detection result content -->
<div v-if="detectionResult && !loading">
<!-- 错误信息 -->
<div v-if="detectionResult.error" class="bg-red-50 rounded-2xl border border-red-100 p-6">
<div class="flex items-center">
<svg class="w-8 h-8 text-red-500 mr-3 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
<div v-else-if="detectionResult?.data?.accounts && detectionResult.data.accounts.length > 0" class="space-y-3">
<div class="flex flex-col gap-2 border-b border-[#DDEBE0] pb-3 sm:flex-row sm:items-end sm:justify-between">
<div>
<p class="text-lg font-bold text-red-800">未找到微信数据</p>
<p class="text-red-600 mt-1 text-sm">{{ detectionResult.error }}</p>
<h2 class="text-[22px] font-semibold tracking-[-0.03em] text-[#000000e6]">可操作的微信账号</h2>
<p class="mt-1 text-[13px] leading-6 text-[#7F7F7F]">点击解密提取会将该账号信息带入下一步</p>
</div>
<span class="rounded-md border border-[#CFEEDB] bg-[#F4FBF6]/86 px-2.5 py-1 text-[12px] font-medium text-[#07C160]">
{{ sortedAccounts.length }} 个账号
</span>
</div>
</div>
<!-- 成功结果 -->
<div v-else class="space-y-3">
<!-- 账户列表 -->
<div v-if="detectionResult.data?.accounts && detectionResult.data.accounts.length > 0"
class="bg-white/92 backdrop-blur rounded-2xl border border-[#EDEDED] overflow-hidden">
<div class="px-4 py-3 border-b border-[#EDEDED] bg-[#fafafa] flex items-center justify-between">
<h3 class="text-[15px] font-semibold text-[#000000e6]">可操作的微信账户</h3>
<span class="text-[11px] text-gray-500">点击解密即可提取数据</span>
</div>
<div class="divide-y divide-[#EDEDED] max-h-[420px] overflow-y-auto">
<div v-for="(account, index) in sortedAccounts" :key="index"
:class="['px-4 py-3.5 transition-all duration-200 relative overflow-hidden', isCurrentAccount(account.account_name) ? 'bg-[#07C160]/5 border border-[#07C160]/20' : 'hover:bg-[#F9F9F9]']">
<div v-if="isCurrentAccount(account.account_name)" class="absolute top-0 right-0 bg-gradient-to-l from-[#07C160]/20 to-transparent px-3 py-1 rounded-bl-xl flex items-center">
<span class="text-xs text-[#07C160] font-bold flex items-center">
<svg class="w-3 h-3 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
最近登录账户
</span>
</div>
<div class="max-h-[460px] space-y-2.5 overflow-y-auto pr-1">
<div
v-for="(account, index) in sortedAccounts"
:key="index"
:class="[
'rounded-lg border p-3 transition',
isCurrentAccount(account.account_name)
? 'border-[#AEE6C4] bg-[#EAF8EF]/86'
: 'border-[#E1EFE5] bg-[#F7FCF8]/86 hover:border-[#CFEEDB] hover:bg-[#F1FAF4]'
]"
>
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<div class="flex min-w-0 items-center gap-2.5">
<template v-if="isCurrentAccount(account.account_name) && currentAccountInfo?.avatar">
<img :src="currentAccountInfo.avatar" class="h-12 w-12 shrink-0 rounded-md border border-[#AEE6C4] bg-white object-cover" alt="" />
</template>
<template v-else>
<div class="flex h-12 w-12 shrink-0 items-center justify-center rounded-md border border-[#CFEEDB] bg-[#F4FBF6]/86">
<span class="text-[17px] font-semibold text-[#07C160]">{{ account.account_name?.charAt(0)?.toUpperCase() || 'U' }}</span>
</div>
</template>
<div class="flex items-center justify-between gap-3 mt-1">
<div class="flex-1">
<div class="flex items-center">
<template v-if="isCurrentAccount(account.account_name) && currentAccountInfo?.avatar">
<img :src="currentAccountInfo.avatar" class="w-12 h-12 rounded-xl border-2 border-[#07C160]/30 mr-3 object-cover bg-white" alt=""/>
<div class="min-w-0">
<div class="flex flex-wrap items-center gap-2">
<template v-if="isCurrentAccount(account.account_name) && currentAccountInfo?.nickname">
<p class="truncate text-[18px] font-semibold tracking-[-0.03em] text-[#000000e6]">{{ currentAccountInfo.nickname }}</p>
</template>
<template v-else>
<div class="w-12 h-12 bg-gradient-to-br from-[#07C160]/10 to-[#91D300]/10 rounded-xl flex items-center justify-center mr-3">
<span class="text-[#07C160] font-bold text-lg">{{ account.account_name?.charAt(0)?.toUpperCase() || 'U' }}</span>
</div>
<p class="truncate text-[16px] font-semibold text-[#000000e6]">{{ account.account_name || '未知账户' }}</p>
</template>
</div>
<div>
<div class="flex flex-col">
<template v-if="isCurrentAccount(account.account_name) && currentAccountInfo?.nickname">
<p class="text-lg font-bold text-[#000000e6] leading-tight">{{ currentAccountInfo.nickname }}</p>
<p class="text-[11px] text-[#7F7F7F] mt-0.5 font-mono">wxid: {{ account.account_name }}</p>
</template>
<template v-else>
<p class="text-[15px] font-semibold text-[#000000e6]">{{ account.account_name || '未知账户' }}</p>
</template>
</div>
<p v-if="isCurrentAccount(account.account_name) && currentAccountInfo?.nickname" class="mt-1 truncate font-mono text-[12px] text-[#7F7F7F]">
wxid: {{ account.account_name }}
</p>
<div class="flex items-center mt-1.5 space-x-3 text-[12px] text-[#7F7F7F]">
<span class="flex items-center">
<svg class="w-4 h-4 mr-1 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4"/>
</svg>
{{ account.database_count }} 个库文件
</span>
<span v-if="account.data_dir" class="flex items-center">
<svg class="w-4 h-4 mr-1 text-[#07C160]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
</svg>
路径已确认
</span>
</div>
</div>
<div class="mt-1.5 flex flex-wrap items-center gap-2 text-[12px] text-[#7F7F7F]">
<span class="rounded-md border border-[#E1EFE5] bg-[#F4FAF6]/82 px-2 py-1">{{ account.database_count }} 个库文件</span>
<span v-if="isCurrentAccount(account.account_name)" class="rounded-md border border-[#CFEEDB] bg-[#F4FBF6]/86 px-2 py-1 font-medium text-[#07C160]">最近登录</span>
<span v-if="account.data_dir" class="rounded-md border border-[#CFEEDB] bg-[#F4FBF6]/86 px-2 py-1 text-[#07C160]">路径已确认</span>
</div>
</div>
<button @click="goToDecrypt(account)"
class="inline-flex items-center px-4 py-2 bg-[#07C160] text-white rounded-lg font-semibold hover:bg-[#06AD56] hover:-translate-y-0.5 transition-all duration-200 text-xs shrink-0 z-10">
解密提取
<svg class="w-4 h-4 ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
</svg>
</button>
</div>
<div class="mt-3 pt-2.5 border-t border-dashed border-gray-200 text-sm text-gray-400">
<p v-if="account.data_dir" class="font-mono text-[11px] truncate" title="复制路径">
📂 {{ account.data_dir }}
</p>
</div>
<button
type="button"
class="inline-flex shrink-0 items-center justify-center rounded-lg bg-[#07C160] px-3 py-2 text-sm font-medium text-white transition hover:bg-[#06AD56] focus:outline-none focus:ring-2 focus:ring-[#07C160]/25"
@click="goToDecrypt(account)"
>
解密提取
<svg class="ml-1.5 h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
</button>
</div>
<div v-if="account.data_dir" class="mt-3 border-t border-dashed border-[#DDEBE0] pt-2.5">
<p class="truncate font-mono text-[12px] text-[#7F7F7F]" :title="account.data_dir">
{{ account.data_dir }}
</p>
</div>
</div>
</div>
</div>
<!-- 无账户提示 -->
<div v-else class="bg-white rounded-2xl p-8 text-center border border-[#EDEDED]">
<svg class="w-12 h-12 mx-auto text-gray-300 mb-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.172 16.172a4 4 0 015.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
<p class="text-base text-[#000000e6] font-medium">没有在这台设备上发现微信数据</p>
<p class="text-sm text-gray-500 mt-2">您可以尝试通过上方的按钮手动指定 "xwechat_files" 文件夹路径</p>
</div>
<div v-else class="flex min-h-[340px] flex-col items-center justify-center rounded-lg border border-[#DDEBE0] bg-[#F7FCF8]/86 p-5 text-center">
<svg class="mb-3 h-10 w-10 text-[#9CA3AF]" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.172 16.172a4 4 0 015.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<p class="text-[18px] font-semibold tracking-[-0.03em] text-[#000000e6]">没有发现微信数据</p>
<p class="mt-1.5 max-w-md text-[13px] leading-6 text-[#7F7F7F]">可以尝试手动指定 <span class="font-mono">xwechat_files</span> 文件夹后重新检测</p>
</div>
</div>
</div>
</div>
</section>
</main>
</div>
</template>
<script setup>
import {computed, onMounted, ref} from 'vue'
import {useApi} from '~/composables/useApi'
+199 -144
View File
@@ -1,102 +1,143 @@
<template>
<div class="import-page min-h-screen relative overflow-hidden">
<div class="absolute inset-0 bg-grid-pattern opacity-5 pointer-events-none"></div>
<div class="import-page relative min-h-screen overflow-hidden px-4 py-5 text-[#000000e6] sm:px-6 sm:py-5">
<div class="pointer-events-none absolute inset-0 bg-grid-pattern opacity-5"></div>
<div class="pointer-events-none absolute left-20 top-20 h-72 w-72 rounded-full bg-[#07C160] opacity-5 blur-3xl"></div>
<div class="pointer-events-none absolute right-20 top-40 h-96 w-96 rounded-full bg-[#10AEEF] opacity-5 blur-3xl"></div>
<div class="pointer-events-none absolute -bottom-8 left-40 h-80 w-80 rounded-full bg-[#91D300] opacity-5 blur-3xl"></div>
<div class="relative z-10 mx-auto flex min-h-screen w-full max-w-4xl items-center justify-center px-4 py-6 sm:px-6 sm:py-8">
<div class="w-full rounded-[28px] border border-[#EDEDED] bg-white/92 backdrop-blur-sm">
<div class="px-5 py-5 sm:px-7 sm:py-7">
<div class="mb-5 flex items-start justify-between gap-3">
<div class="flex min-w-0 items-center gap-3">
<div class="flex h-11 w-11 shrink-0 items-center justify-center rounded-2xl bg-[#07C160]/10 text-[#07C160]">
<svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
</svg>
</div>
<div class="min-w-0">
<p class="text-[11px] uppercase tracking-[0.12em] text-[#7F7F7F]">导入备份</p>
<h1 class="mt-1 text-[24px] font-semibold leading-none text-[#000000e6]">数据导入</h1>
<p class="mt-2 text-sm text-[#7F7F7F]">导入已解密的微信备份目录支持本项目导出和 wxdump output/wxid_xxx 结构</p>
</div>
</div>
<main class="relative z-10 mx-auto flex min-h-[calc(100vh-40px)] w-full max-w-6xl flex-col justify-start">
<div class="mb-4 flex items-start justify-between gap-4 rounded-lg border border-[#DDEBE0] bg-[#F4FAF6]/82 p-5 backdrop-blur">
<div class="min-w-0">
<p class="text-[12px] font-medium tracking-[0.16em] text-[#07C160]">导入备份</p>
<h1 class="mt-2 text-[30px] font-semibold leading-tight tracking-[-0.04em] text-[#000000e6] sm:text-[38px]">
接入已准备好的本地数据
</h1>
<p class="mt-3 max-w-2xl text-[14px] leading-7 text-[#6B7280]">
选择已解密的微信备份目录先检查账号与文件结构确认后再导入到本地数据区
</p>
</div>
<NuxtLink
to="/"
class="inline-flex shrink-0 items-center rounded-lg px-3 py-1.5 text-xs font-medium text-[#07C160] transition-colors hover:bg-[#F3FBF6] hover:text-[#06AD56]"
>
<svg class="mr-1 h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
<NuxtLink
to="/"
class="inline-flex shrink-0 items-center rounded-lg border border-[#CFEEDB] bg-[#F7FDF9]/82 px-2.5 py-1.5 text-xs font-medium text-[#07C160] transition hover:border-[#CFEEDB] hover:bg-[#F7FDF9] focus:outline-none focus:ring-2 focus:ring-[#07C160]/20"
>
<svg class="mr-1.5 h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
</svg>
返回首页
</NuxtLink>
</div>
<section class="grid gap-5 lg:grid-cols-[0.82fr_1.18fr]">
<aside class="space-y-4">
<div class="rounded-lg border border-[#CFEEDB] bg-[#EFFAF3]/82 p-5 backdrop-blur">
<div class="flex items-center gap-2 text-[15px] font-medium text-[#000000e6]">
<svg class="h-5 w-5 text-[#07C160]" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" />
</svg>
返回首页
</NuxtLink>
<span>选择哪个目录</span>
</div>
<p class="mt-3 text-[13px] leading-6 text-[#6B7280]">
建议直接选择账号目录如果是 wxdump 导出 output 下只有一个账号也可以选择 output 根目录
</p>
<div class="mt-4 flex flex-wrap gap-2">
<span class="rounded-md border border-[#CFEEDB] bg-[#F4FBF6]/86 px-2.5 py-1 text-[12px] font-mono text-[#4A4A4A]">wxid_xxxxx/</span>
<span class="rounded-md border border-[#CFEEDB] bg-[#F4FBF6]/86 px-2.5 py-1 text-[12px] font-mono text-[#4A4A4A]">databases/</span>
<span class="rounded-md border border-[#CFEEDB] bg-[#F4FBF6]/86 px-2.5 py-1 text-[12px] font-mono text-[#4A4A4A]">database/</span>
<span class="rounded-md border border-[#CFEEDB] bg-[#F4FBF6]/86 px-2.5 py-1 text-[12px] font-mono text-[#4A4A4A]">media/</span>
</div>
</div>
<div class="mb-5 rounded-[22px] border border-[#E8EFE8] bg-[#F8FBF8] px-4 py-4 sm:px-5">
<div class="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
<div class="flex min-w-0 items-start gap-3">
<div class="mt-0.5 flex h-8 w-8 shrink-0 items-center justify-center rounded-xl bg-white text-[#07C160] ring-1 ring-[#E7F1E8]">
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
<div class="min-w-0">
<div class="text-[13px] font-semibold text-[#000000d9]">目录要求</div>
<p class="mt-1 text-sm leading-6 text-[#6F6F6F]">支持本项目导出和 wxdump 导出优先选择账号目录 output 下只有一个账号也可直接选 output</p>
<div class="rounded-lg border border-[#CFEEDB] bg-[#F1FAF4]/82 p-5 backdrop-blur">
<div class="text-[15px] font-medium text-[#000000e6]">导入流程</div>
<div class="mt-4 space-y-3">
<div class="flex gap-3">
<span class="mt-1 flex h-5 w-5 shrink-0 items-center justify-center rounded-md border border-[#CFEEDB] text-[11px] font-medium text-[#07C160]">1</span>
<div>
<div class="text-[13px] font-medium text-[#000000d9]">选择目录</div>
<p class="mt-2 text-[12px] leading-5 text-[#7F7F7F]">使用系统目录选择器定位备份</p>
</div>
</div>
<div class="flex shrink-0 flex-wrap gap-2 sm:justify-end">
<span class="inline-flex items-center rounded-full border border-[#DDEBE0] bg-white px-3 py-1 text-xs font-medium text-[#4A4A4A]">databases/</span>
<span class="inline-flex items-center rounded-full border border-[#DDEBE0] bg-white px-3 py-1 text-xs font-medium text-[#4A4A4A]">database/</span>
<span class="inline-flex items-center rounded-full border border-[#DDEBE0] bg-white px-3 py-1 text-xs font-medium text-[#4A4A4A]">media/</span>
<div class="flex gap-3">
<span class="mt-1 flex h-5 w-5 shrink-0 items-center justify-center rounded-md border border-[#CFEEDB] text-[11px] font-medium text-[#07C160]">2</span>
<div>
<div class="text-[13px] font-medium text-[#000000d9]">预览确认</div>
<p class="mt-2 text-[12px] leading-5 text-[#7F7F7F]">先识别账号数据库和资源文件</p>
</div>
</div>
<div class="flex gap-3">
<span class="mt-1 flex h-5 w-5 shrink-0 items-center justify-center rounded-md border border-[#CFEEDB] text-[11px] font-medium text-[#07C160]">3</span>
<div>
<div class="text-[13px] font-medium text-[#000000d9]">执行导入</div>
<p class="mt-2 text-[12px] leading-5 text-[#7F7F7F]">如果账号已存在会先备份旧数据</p>
</div>
</div>
</div>
</div>
<div v-if="!importPreview && !importError && !importing" class="animate-fade-in">
<div
class="group cursor-pointer rounded-[24px] border border-dashed border-[#D8E5DA] bg-[#FCFDFC] px-6 py-10 text-center transition-colors duration-200 hover:border-[#07C160] hover:bg-white"
@click="handlePickDirectory"
>
<div class="mx-auto flex h-14 w-14 items-center justify-center rounded-2xl bg-white text-[#07C160] ring-1 ring-[#EDEDED]">
<svg class="h-7 w-7" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<div class="rounded-lg border border-[#DDEBE0] bg-[#F4FAF6]/82 p-4 text-[12px] leading-6 text-[#5F6F66] backdrop-blur">
<span class="font-medium text-[#2F6F4A]">提示</span>
导入会复制数据到应用的本地数据区不会直接在原备份目录上修改
</div>
</aside>
<div class="rounded-lg border border-[#DDEBE0] bg-[#F4FAF6]/82 p-5 backdrop-blur">
<div v-if="!importPreview && !importError && !importing && !importComplete" class="animate-fade-in">
<div class="flex min-h-[340px] flex-col justify-between gap-5">
<div>
<div class="flex items-center gap-2 text-[13px] font-medium text-[#07C160]">
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
</svg>
<span>第一步</span>
</div>
<h2 class="mt-4 text-[24px] font-semibold tracking-[-0.03em] text-[#000000e6] sm:text-[30px]">选择备份目录</h2>
<p class="mt-3 max-w-xl text-[14px] leading-7 text-[#6B7280]">
点击下方按钮后选择已解密的账号目录系统会先做结构检查不会立即导入
</p>
</div>
<button
type="button"
class="group flex min-h-[132px] cursor-pointer flex-col items-center justify-center rounded-lg border border-dashed border-[#BFE6CF] bg-[#F3FFF8] px-5 py-6 text-center transition hover:border-[#07C160] hover:bg-[#EFFAF3] focus:outline-none focus:ring-2 focus:ring-[#07C160]/20"
@click="handlePickDirectory"
>
<svg class="h-8 w-8 text-[#07C160] transition group-hover:-translate-y-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" />
</svg>
</div>
<h3 class="mt-4 text-lg font-semibold text-[#000000e6]">选择解密备份目录</h3>
<p class="mt-2 text-sm text-[#7F7F7F]">建议选择 `wxid_xxxxx` 层级wxdump `output` 根目录在单账号时也支持</p>
<div class="mt-5 inline-flex items-center rounded-full bg-[#07C160] px-4 py-2 text-sm font-medium text-white transition-colors duration-200 group-hover:bg-[#06AD56]">
点击开始选择
</div>
<p class="mt-4 text-xs text-[#A3A3A3]">桌面端优先使用系统目录选择器异常时会自动回退到手动输入</p>
<span class="mt-4 text-[15px] font-medium text-[#000000e6]">打开目录选择器</span>
<span class="mt-2 text-[12px] leading-5 text-[#7F7F7F]">建议选到 wxid_xxxxx 账号层级</span>
</button>
</div>
</div>
<div v-if="importing" class="animate-fade-in">
<div class="rounded-[24px] border border-[#EDEDED] bg-[#FCFDFC] px-5 py-8 sm:px-6">
<div class="mx-auto flex w-fit items-center gap-2 rounded-full bg-[#07C160]/10 px-3 py-1 text-xs font-medium text-[#07C160]">
<span class="inline-flex h-2 w-2 rounded-full bg-current animate-pulse"></span>
正在导入
<div class="flex min-h-[340px] flex-col justify-between gap-5">
<div>
<div class="flex items-center gap-2 text-[13px] font-medium text-[#07C160]">
<span class="h-2 w-2 rounded-full bg-[#07C160] animate-pulse"></span>
<span>正在导入</span>
</div>
<h2 class="mt-4 text-[24px] font-semibold tracking-[-0.03em] text-[#000000e6] sm:text-[30px]">{{ importMessage }}</h2>
<p class="mt-3 text-[14px] leading-7 text-[#6B7280]">请保持程序运行导入完成后可以进入聊天页面查看</p>
</div>
<div class="mt-5 text-center">
<p class="text-xl font-semibold text-[#000000e6]">{{ importMessage }}</p>
<p class="mt-2 text-sm text-[#7F7F7F]">请保持程序运行导入完成后可手动进入聊天页面</p>
</div>
<div class="mt-6 overflow-hidden rounded-full bg-[#EDF3EE]">
<div
class="h-2 rounded-full bg-[#07C160] transition-all duration-500"
:style="{ width: `${Math.min(Math.max(importProgress, 0), 100)}%` }"
></div>
</div>
<div class="mt-3 flex items-center justify-between text-xs text-[#7F7F7F]">
<span>已连接导入任务</span>
<span>{{ importProgress }}%</span>
<div class="rounded-lg border border-[#CFEEDB] bg-[#EAF8EF]/82 p-4 sm:p-5">
<div class="h-2 overflow-hidden rounded-full border border-[#DDF4E7] bg-[#F7FCF8]/86">
<div
class="h-full rounded-full bg-[#07C160] transition-all duration-500"
:style="{ width: `${Math.min(Math.max(importProgress, 0), 100)}%` }"
></div>
</div>
<div class="mt-2 flex items-center justify-between text-[12px] text-[#7F7F7F]">
<span>已连接导入任务</span>
<span class="font-medium text-[#07C160]">{{ importProgress }}%</span>
</div>
</div>
<button
class="mt-5 inline-flex w-full items-center justify-center rounded-2xl border border-[#F0D7D7] bg-white px-4 py-3 text-sm font-medium text-[#D64A4A] transition-colors hover:bg-[#FFF7F7]"
type="button"
class="inline-flex w-full items-center justify-center rounded-lg border border-[#F0D7D7] bg-[#FFF7F7]/76 px-4 py-3 text-sm font-medium text-[#D64A4A] transition hover:bg-[#FFF7F7] focus:outline-none focus:ring-2 focus:ring-[#D64A4A]/15"
@click="cancelImport"
>
取消导入
@@ -104,34 +145,41 @@
</div>
</div>
<div v-if="importComplete && !importing" class="animate-fade-in space-y-4">
<div class="rounded-[24px] border border-[#DCEFE2] bg-[#F7FCF8] px-5 py-7 text-center sm:px-6">
<div class="mx-auto flex h-14 w-14 items-center justify-center rounded-2xl bg-[#07C160]/10 text-[#07C160]">
<svg class="h-7 w-7" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
</svg>
<div v-if="importComplete && !importing" class="animate-fade-in">
<div class="flex min-h-[340px] flex-col justify-between gap-5">
<div>
<div class="flex items-center gap-2 text-[13px] font-medium text-[#07C160]">
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
</svg>
<span>导入完成</span>
</div>
<h2 class="mt-4 text-[24px] font-semibold tracking-[-0.03em] text-[#000000e6] sm:text-[30px]">数据已就绪</h2>
<p class="mt-3 text-[14px] leading-7 text-[#6B7280]">{{ importComplete.message || '账号数据已成功导入。' }}</p>
</div>
<h2 class="mt-4 text-xl font-semibold text-[#000000e6]">导入完成</h2>
<p class="mt-2 text-sm leading-6 text-[#6F6F6F]">{{ importComplete.message || '账号数据已成功导入。' }}</p>
<div class="mt-4 rounded-2xl border border-[#E2EFE5] bg-white px-4 py-3 text-left text-sm text-[#4A4A4A]">
<div class="flex items-center justify-between gap-3">
<div class="rounded-lg border border-[#CFEEDB] bg-[#EAF8EF]/82 p-3 text-sm">
<div class="flex items-center justify-between gap-2.5">
<span class="text-[#7F7F7F]">账号</span>
<span class="min-w-0 truncate font-mono text-xs">{{ importComplete.account }}</span>
<span class="min-w-0 truncate font-mono text-xs text-[#000000d9]">{{ importComplete.account }}</span>
</div>
<div v-if="importComplete.backup_dir" class="mt-2 flex items-start justify-between gap-3">
<div v-if="importComplete.backup_dir" class="mt-2 flex items-start justify-between gap-2.5 border-t border-[#DDF4E7] pt-2.5">
<span class="shrink-0 text-[#7F7F7F]">旧数据备份</span>
<span class="min-w-0 break-all text-right text-xs">{{ importComplete.backup_dir }}</span>
<span class="min-w-0 break-all text-right text-xs text-[#000000d9]">{{ importComplete.backup_dir }}</span>
</div>
</div>
<div class="mt-5 grid gap-3 sm:grid-cols-2">
<div class="grid gap-3 sm:grid-cols-2">
<button
class="inline-flex items-center justify-center rounded-2xl border border-[#E2E2E2] bg-white px-4 py-3 text-sm font-medium text-[#4A4A4A] transition-colors hover:bg-[#F8F8F8]"
type="button"
class="inline-flex items-center justify-center rounded-lg border border-[#DDEBE0] bg-[#F7FCF8]/86 px-4 py-3 text-sm font-medium text-[#4A4A4A] transition hover:bg-[#F1FAF4] focus:outline-none focus:ring-2 focus:ring-[#07C160]/15"
@click="retryPickDirectory"
>
继续导入其他目录
继续导入
</button>
<button
class="inline-flex items-center justify-center rounded-2xl bg-[#07C160] px-4 py-3 text-sm font-medium text-white transition-colors hover:bg-[#06AD56]"
type="button"
class="inline-flex items-center justify-center rounded-lg bg-[#07C160] px-4 py-3 text-sm font-medium text-white transition hover:bg-[#06AD56] focus:outline-none focus:ring-2 focus:ring-[#07C160]/25"
@click="navigateTo('/chat')"
>
进入聊天页面
@@ -140,55 +188,62 @@
</div>
</div>
<div v-if="importPreview && !importing && !importComplete" class="animate-fade-in space-y-4">
<div class="rounded-[24px] border border-[#EDEDED] bg-[#FCFDFC] px-5 py-5 sm:px-6">
<div v-if="importPreview && !importing && !importComplete" class="animate-fade-in space-y-3">
<div class="rounded-lg border border-[#CFEEDB] bg-[#EAF8EF]/82 p-4 sm:p-5">
<div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
<div class="flex min-w-0 items-center gap-4">
<div class="h-16 w-16 shrink-0 overflow-hidden rounded-2xl border border-[#EDEDED] bg-white">
<img :src="importPreview.avatar_url || '/Contact.png'" class="h-full w-full object-cover" alt="头像" />
</div>
<div class="flex min-w-0 items-center gap-3">
<img :src="importPreview.avatar_url || '/Contact.png'" class="h-16 w-16 shrink-0 rounded-md border border-[#EDEDED] bg-white object-cover" alt="头像" />
<div class="min-w-0">
<p class="text-[11px] uppercase tracking-[0.12em] text-[#7F7F7F]">检测到的账号</p>
<div class="mt-1 truncate text-xl font-semibold text-[#000000e6]">{{ importPreview.nick || '未命名账号' }}</div>
<div class="mt-2 inline-flex max-w-full items-center rounded-full border border-[#EDEDED] bg-white px-3 py-1 text-xs font-mono text-[#7F7F7F]">
<span class="truncate">{{ importPreview.username }}</span>
</div>
<p class="text-[12px] font-medium tracking-[0.12em] text-[#07C160]">检测到的账号</p>
<div class="mt-1 truncate text-[24px] font-semibold tracking-[-0.03em] text-[#000000e6]">{{ importPreview.nick || '未命名账号' }}</div>
<div class="mt-1.5 truncate font-mono text-[12px] text-[#7F7F7F]">{{ importPreview.username }}</div>
</div>
</div>
<div class="inline-flex w-fit items-center rounded-full bg-[#07C160]/10 px-3 py-1 text-xs font-medium text-[#07C160]">
可导入
</div>
<span class="inline-flex w-fit rounded-md border border-[#CFEEDB] bg-[#F4FBF6]/86 px-2.5 py-1 text-[12px] font-medium text-[#07C160]">可导入</span>
</div>
<div v-if="selectedImportPath" class="mt-4 rounded-[18px] border border-[#EDEDED] bg-white px-3 py-3">
<p class="text-[11px] uppercase tracking-[0.12em] text-[#7F7F7F]">导入路径</p>
<p class="mt-1 break-all text-sm text-[#000000d9]">{{ selectedImportPath }}</p>
<div v-if="selectedImportPath" class="mt-4 rounded-md border border-[#E1EFE5] bg-[#F7FCF8]/86 px-3 py-3">
<p class="text-[12px] font-medium text-[#7F7F7F]">导入路径</p>
<p class="mt-1 break-all text-[13px] leading-6 text-[#000000d9]">{{ selectedImportPath }}</p>
</div>
</div>
<div class="mt-4 flex flex-wrap gap-2">
<span class="inline-flex items-center gap-2 rounded-full border border-[#EDEDED] bg-white px-3 py-1.5 text-xs text-[#4A4A4A]">
<div class="grid gap-3 sm:grid-cols-2">
<div class="rounded-lg border border-[#E1EFE5] bg-[#F7FCF8]/86 p-4">
<div class="flex items-center gap-2 text-[13px] font-medium text-[#000000e6]">
<span class="h-2 w-2 rounded-full bg-[#07C160]"></span>
数据库已就绪
</span>
<span class="inline-flex items-center gap-2 rounded-full border border-[#EDEDED] bg-white px-3 py-1.5 text-xs text-[#4A4A4A]">
<span class="h-2 w-2 rounded-full" :class="importPreview.has_resource ? 'bg-[#07C160]' : 'bg-[#C9D2CB]'"></span>
资源文件{{ importPreview.has_resource ? '已发现' : '未发现' }}
</span>
<span>数据库</span>
</div>
<p class="mt-2 text-[12px] leading-5 text-[#7F7F7F]">已检测到可导入的数据库文件</p>
</div>
<div class="rounded-lg border border-[#E1EFE5] bg-[#F7FCF8]/86 p-4">
<div class="flex items-center gap-2 text-[13px] font-medium text-[#000000e6]">
<span class="h-2 w-2 rounded-full" :class="importPreview.has_resource ? 'bg-[#07C160]' : 'bg-[#C9D2CB]'"></span>
<span>资源文件</span>
</div>
<p class="mt-2 text-[12px] leading-5 text-[#7F7F7F]">{{ importPreview.has_resource ? '已发现图片、视频等资源文件。' : '未发现资源文件,仍可导入数据库。' }}</p>
</div>
</div>
<div v-if="importPreview.source_overlaps_target" class="rounded-lg border border-[#F4D6D6] bg-[#FFF7F7] p-4 text-[13px] leading-6 text-[#9C5F5F]">
导入源目录与目标数据目录相同或相互包含请重新选择外部备份目录
</div>
<div v-else-if="importPreview.target_exists" class="rounded-lg border border-[#CFEEDB] bg-[#F1FAF4] p-4 text-[13px] leading-6 text-[#5F6F66]">
该账号在本地已存在确认导入时会先备份旧目录再写入新数据
</div>
<div class="grid gap-3 sm:grid-cols-[minmax(0,1fr)_minmax(0,1.35fr)]">
<button
class="inline-flex items-center justify-center rounded-2xl border border-[#E2E2E2] bg-white px-4 py-3 text-sm font-medium text-[#4A4A4A] transition-colors hover:bg-[#F8F8F8]"
type="button"
class="inline-flex items-center justify-center rounded-lg border border-[#DDEBE0] bg-[#F7FCF8]/86 px-4 py-3 text-sm font-medium text-[#4A4A4A] transition hover:bg-[#F1FAF4] focus:outline-none focus:ring-2 focus:ring-[#07C160]/15"
@click="handlePickDirectory"
>
重新选择目录
重新选择
</button>
<button
type="button"
:disabled="importing || importPreview?.source_overlaps_target"
class="inline-flex items-center justify-center rounded-2xl bg-[#07C160] px-4 py-3 text-sm font-medium text-white transition-colors hover:bg-[#06AD56] disabled:cursor-not-allowed disabled:bg-[#8FD9AE]"
class="inline-flex items-center justify-center rounded-lg bg-[#07C160] px-4 py-3 text-sm font-medium text-white transition hover:bg-[#06AD56] focus:outline-none focus:ring-2 focus:ring-[#07C160]/25 disabled:cursor-not-allowed disabled:bg-[#8FD9AE]"
@click="confirmImport"
>
确认导入此账号
@@ -196,36 +251,36 @@
</div>
</div>
<div v-if="importError && !importing" class="animate-fade-in space-y-4">
<div class="rounded-[22px] border border-[#F4D6D6] bg-[#FFF7F7] px-5 py-5">
<div class="flex items-start gap-3">
<div class="mt-0.5 flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-white text-[#E05A5A] ring-1 ring-[#F0D7D7]">
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<div v-if="importError && !importing" class="animate-fade-in">
<div class="flex min-h-[340px] flex-col justify-between gap-5">
<div>
<div class="flex items-center gap-2 text-[13px] font-medium text-[#D64A4A]">
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<span>导入失败</span>
</div>
<div class="min-w-0">
<p class="text-base font-semibold text-[#B64545]">导入失败</p>
<p class="mt-1 text-sm leading-6 text-[#9C5F5F]">{{ importError }}</p>
</div>
<h2 class="mt-4 text-[24px] font-semibold tracking-[-0.03em] text-[#000000e6] sm:text-[30px]">目录暂时无法识别</h2>
<p class="mt-2 text-[14px] leading-6 text-[#9C5F5F]">{{ importError }}</p>
</div>
<div v-if="selectedImportPath" class="mt-4 rounded-[18px] border border-[#F1E3E3] bg-white/80 px-3 py-3">
<p class="text-[11px] uppercase tracking-[0.12em] text-[#B26B6B]">当前路径</p>
<p class="mt-1 break-all text-sm text-[#7A4B4B]">{{ selectedImportPath }}</p>
<div v-if="selectedImportPath" class="rounded-lg border border-[#F1E3E3] bg-[#FFF7F7] px-2.5 py-2.5">
<p class="text-[12px] font-medium text-[#B26B6B]">当前路径</p>
<p class="mt-1 break-all text-[13px] leading-6 text-[#7A4B4B]">{{ selectedImportPath }}</p>
</div>
<button
type="button"
class="inline-flex w-full items-center justify-center rounded-lg border border-[#DDEBE0] bg-[#F7FCF8]/86 px-4 py-3 text-sm font-medium text-[#4A4A4A] transition hover:bg-[#F1FAF4] focus:outline-none focus:ring-2 focus:ring-[#07C160]/15"
@click="retryPickDirectory"
>
重新选择目录
</button>
</div>
<button
class="inline-flex w-full items-center justify-center rounded-2xl border border-[#E2E2E2] bg-white px-4 py-3 text-sm font-medium text-[#4A4A4A] transition-colors hover:bg-[#F8F8F8]"
@click="retryPickDirectory"
>
重新选择目录
</button>
</div>
</div>
</div>
</div>
</section>
</main>
</div>
</template>
+140 -96
View File
@@ -1,77 +1,146 @@
<template>
<div class="landing-page min-h-screen flex items-center justify-center relative overflow-hidden">
<!-- 网格背景 -->
<div class="absolute inset-0 bg-grid-pattern opacity-5"></div>
<!-- 装饰元素 -->
<div class="absolute top-20 left-20 w-72 h-72 bg-[#07C160] opacity-5 rounded-full blur-3xl"></div>
<div class="absolute top-40 right-20 w-96 h-96 bg-[#10AEEF] opacity-5 rounded-full blur-3xl"></div>
<div class="absolute -bottom-8 left-40 w-80 h-80 bg-[#91D300] opacity-5 rounded-full blur-3xl"></div>
<!-- 主要内容区域 -->
<div class="relative z-10 text-center">
<!-- Logo和标题部分 -->
<div class="mb-12 animate-fade-in">
<!-- Logo -->
<div class="flex justify-center mb-8">
<img src="/logo.png" alt="微信解密助手Logo" class="w-48 h-48 object-contain">
<div class="landing-page relative h-full min-h-0 overflow-hidden px-4 py-6 text-[#000000e6] sm:px-6 sm:py-8">
<div class="pointer-events-none absolute inset-0 bg-grid-pattern opacity-5"></div>
<div class="pointer-events-none absolute left-20 top-20 h-72 w-72 rounded-full bg-[#07C160] opacity-5 blur-3xl"></div>
<div class="pointer-events-none absolute right-20 top-40 h-96 w-96 rounded-full bg-[#10AEEF] opacity-5 blur-3xl"></div>
<div class="pointer-events-none absolute -bottom-8 left-40 h-80 w-80 rounded-full bg-[#91D300] opacity-5 blur-3xl"></div>
<main class="relative z-10 mx-auto flex h-full min-h-0 w-full max-w-6xl flex-col justify-center">
<section class="space-y-5">
<div class="flex flex-col gap-5 rounded-lg border border-[#EDEDED] bg-white/78 p-6 backdrop-blur sm:p-8 lg:flex-row lg:items-center lg:justify-between">
<div class="flex items-start gap-4 text-left">
<img src="/logo.png" alt="微信解密助手Logo" class="h-16 w-16 shrink-0 object-contain" />
<div>
<p class="text-[13px] font-medium tracking-[0.16em] text-[#07C160]">本地整理·安心备份</p>
<h1 class="mt-3 text-[34px] font-semibold leading-tight tracking-[-0.04em] text-[#000000e6] sm:text-[46px]">
把微信记录留在本地
</h1>
<p class="mt-3 max-w-2xl text-[15px] leading-7 text-[#6B7280]">
从检测开始再查看聊天导入备份或导出归档
</p>
</div>
</div>
<button
type="button"
class="inline-flex shrink-0 items-center justify-center gap-2 rounded-lg bg-[#07C160] px-6 py-3 text-[14px] font-medium text-white transition hover:bg-[#06AD56] focus:outline-none focus:ring-2 focus:ring-[#07C160]/25"
@click="startDetection"
>
<svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
<span>开始检测</span>
</button>
</div>
<h1 class="text-5xl font-bold text-[#000000e6] mb-4">
<span class="bg-gradient-to-r from-[#07C160] to-[#10AEEF] bg-clip-text text-transparent">微信</span>
<span class="text-[#000000e6]">解密助手</span>
</h1>
<p class="text-xl text-[#7F7F7F] font-normal">轻松解锁你的聊天记录</p>
</div>
<!-- 主要按钮 -->
<div class="flex flex-col sm:flex-row gap-4 justify-center animate-slide-up">
<button @click="startDetection"
class="group inline-flex items-center px-12 py-4 bg-[#07C160] text-white rounded-lg text-lg font-medium hover:bg-[#06AD56] transform hover:scale-105 transition-all duration-200">
<svg class="w-6 h-6 mr-3 group-hover:rotate-12 transition-transform duration-200" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
</svg>
<span>开始检测</span>
</button>
<NuxtLink to="/import"
class="group inline-flex items-center px-12 py-4 bg-white text-[#91D300] border border-[#91D300] rounded-lg text-lg font-medium hover:bg-[#F7F7F7] transform hover:scale-105 transition-all duration-200">
<svg class="w-6 h-6 mr-3 transition-transform duration-200" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/>
</svg>
<span>数据导入</span>
</NuxtLink>
<NuxtLink to="/chat"
class="group inline-flex items-center px-12 py-4 bg-white text-[#10AEEF] border border-[#10AEEF] rounded-lg text-lg font-medium hover:bg-[#F7F7F7] transform hover:scale-105 transition-all duration-200">
<svg class="w-6 h-6 mr-3 transition-transform duration-200" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M8 10h8M8 14h5M4 6h16v12a2 2 0 01-2 2H6a2 2 0 01-2-2V6z"/>
</svg>
<span>聊天预览</span>
</NuxtLink>
<div class="grid gap-4 lg:grid-cols-[1.25fr_0.75fr]">
<button
type="button"
class="group min-h-[300px] rounded-lg border border-[#CFEEDB] bg-[#F3FFF8] p-6 text-left transition hover:border-[#AEE6C4] hover:bg-[#EFFAF3] focus:outline-none focus:ring-2 focus:ring-[#07C160]/20 sm:p-8"
@click="startDetection"
>
<div class="flex h-full flex-col justify-between gap-8">
<div>
<div class="flex items-center gap-3 text-[#07C160]">
<svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
<span class="text-[13px] font-medium">推荐第一步</span>
</div>
<h2 class="mt-5 text-[28px] font-semibold tracking-[-0.03em] text-[#000000e6] sm:text-[36px]">检测本机微信数据</h2>
<p class="mt-3 max-w-xl text-[14px] leading-7 text-[#6B7280]">
找到可用账号数据库文件和本地路径后续查看解密和归档都从这里开始
</p>
</div>
<NuxtLink to="/wrapped"
class="group inline-flex items-center px-12 py-4 bg-white text-[#B37800] border border-[#F2AA00] rounded-lg text-lg font-medium hover:bg-[#F7F7F7] transform hover:scale-105 transition-all duration-200">
<svg class="w-6 h-6 mr-3 transition-transform duration-200" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<rect x="4" y="4" width="16" height="16" rx="2" stroke-width="2.5" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M8 16v-5" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M12 16v-8" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M16 16v-3" />
</svg>
<span>年度总结</span>
</NuxtLink>
</div>
</div>
<div class="flex items-center justify-between border-t border-[#DDF4E7] pt-5">
<span class="text-[13px] font-medium text-[#07C160]">开始检测</span>
<svg class="h-5 w-5 text-[#07C160] transition group-hover:translate-x-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
</div>
</div>
</button>
<div class="grid gap-4">
<NuxtLink
to="/import"
class="group rounded-lg border border-[#EDEDED] bg-white/72 p-5 text-left transition hover:border-[#CFEEDB] hover:bg-[#F7FDF9] focus:outline-none focus:ring-2 focus:ring-[#07C160]/20"
>
<div class="flex items-start justify-between gap-4">
<div>
<div class="flex items-center gap-2 text-[15px] font-medium text-[#000000e6]">
<svg class="h-5 w-5 text-[#07C160]" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
</svg>
<span>导入备份</span>
</div>
<p class="mt-2 text-[13px] leading-6 text-[#7F7F7F]">接入已准备好的本地备份目录</p>
</div>
<svg class="mt-1 h-4 w-4 shrink-0 text-[#A1A1AA] transition group-hover:translate-x-0.5 group-hover:text-[#07C160]" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
</div>
</NuxtLink>
<button
type="button"
class="group rounded-lg border border-[#EDEDED] bg-white/72 p-5 text-left transition hover:border-[#CFEEDB] hover:bg-[#F7FDF9] focus:outline-none focus:ring-2 focus:ring-[#07C160]/20"
@click="openExportDialog"
>
<div class="flex items-start justify-between gap-4">
<div>
<div class="flex items-center gap-2 text-[15px] font-medium text-[#000000e6]">
<svg class="h-5 w-5 text-[#07C160]" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v11" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7.5 10.5L12 15l4.5-4.5" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 19h16" />
</svg>
<span>导出归档</span>
</div>
<p class="mt-2 text-[13px] leading-6 text-[#7F7F7F]">打包当前账号的数据库和资源文件</p>
</div>
<svg class="mt-1 h-4 w-4 shrink-0 text-[#A1A1AA] transition group-hover:translate-x-0.5 group-hover:text-[#07C160]" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
</div>
</button>
<NuxtLink
to="/chat"
class="group rounded-lg border border-[#EDEDED] bg-white/72 p-5 text-left transition hover:border-[#CFEEDB] hover:bg-[#F7FDF9] focus:outline-none focus:ring-2 focus:ring-[#07C160]/20"
>
<div class="flex items-start justify-between gap-4">
<div>
<div class="flex items-center gap-2 text-[15px] font-medium text-[#000000e6]">
<svg class="h-5 w-5 text-[#07C160]" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 10h8M8 14h5M4 6h16v12a2 2 0 01-2 2H6a2 2 0 01-2-2V6z" />
</svg>
<span>回看聊天</span>
</div>
<p class="mt-2 text-[13px] leading-6 text-[#7F7F7F]">查看会话搜索片段找到需要的内容</p>
</div>
<svg class="mt-1 h-4 w-4 shrink-0 text-[#A1A1AA] transition group-hover:translate-x-0.5 group-hover:text-[#07C160]" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
</div>
</NuxtLink>
</div>
</div>
</section>
</main>
<GlobalExportDialog :open="exportDialogOpen" @close="closeExportDialog" />
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import { onMounted, ref } from 'vue'
import { useApi } from '~/composables/useApi'
import { DESKTOP_SETTING_DEFAULT_TO_CHAT_KEY, readLocalBoolSetting } from '~/lib/desktop-settings'
const { listChatAccounts } = useApi()
const exportDialogOpen = ref(false)
onMounted(async () => {
if (!process.client || typeof window === 'undefined') return
@@ -88,47 +157,22 @@ onMounted(async () => {
} catch {}
})
// 开始检测并跳转到结果页面
const openExportDialog = () => {
exportDialogOpen.value = true
}
const closeExportDialog = () => {
exportDialogOpen.value = false
}
const startDetection = async () => {
// 直接跳转到检测结果页面,让该页面处理检测
await navigateTo('/detection-result')
}
</script>
<style scoped>
@keyframes fade-in {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slide-up {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.animate-fade-in {
animation: fade-in 0.8s ease-out;
}
.animate-slide-up {
animation: slide-up 0.8s ease-out 0.3s both;
}
/* 网格背景 */
.bg-grid-pattern {
background-image:
background-image:
linear-gradient(rgba(7, 193, 96, 0.1) 1px, transparent 1px),
linear-gradient(90deg, rgba(7, 193, 96, 0.1) 1px, transparent 1px);
background-size: 50px 50px;