Files
WeChatDataAnalysis/frontend/app.vue
T
2977094657 49da1173b4 improvement(entry-ui): 优化检测与导入首屏流程
- 重构检测结果页布局,补充版本/账号/数据库统计与更清晰的加载态

- 首页移除直接解密入口,/import 页面隐藏侧边栏,统一首屏使用路径

- 导入页优化预览、错误和重试体验,并补充 SSE 连接清理逻辑
2026-04-23 21:32:46 +08:00

148 lines
4.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div :class="rootClass">
<SidebarRail v-if="showSidebar" />
<div class="flex-1 flex flex-col min-h-0">
<!-- Desktop titlebar lives above the page content (right column) -->
<DesktopTitleBar v-if="showDesktopTitleBar" />
<div :class="contentClass">
<NuxtPage />
</div>
</div>
<SettingsDialog :open="settingsDialogOpen" @close="closeSettingsDialog" />
<ClientOnly v-if="isDesktopUpdater">
<DesktopUpdateDialog
:open="desktopUpdate.open.value"
:info="desktopUpdate.info.value"
:is-downloading="desktopUpdate.isDownloading.value"
:ready-to-install="desktopUpdate.readyToInstall.value"
:progress="desktopUpdate.progress.value"
:error="desktopUpdate.error.value"
:has-ignore="true"
@close="desktopUpdate.dismiss"
@update="desktopUpdate.startUpdate"
@install="desktopUpdate.installUpdate"
@ignore="desktopUpdate.ignore"
/>
</ClientOnly>
</div>
</template>
<script setup>
import { useThemeStore } from '~/stores/theme'
import { useChatAccountsStore } from '~/stores/chatAccounts'
import { usePrivacyStore } from '~/stores/privacy'
const route = useRoute()
const desktopUpdate = useDesktopUpdate()
const { open: settingsDialogOpen, closeDialog: closeSettingsDialog } = useSettingsDialog()
const themeStore = useThemeStore()
if (process.client) {
themeStore.init()
}
// In Electron the server/pre-render doesn't know about `window.wechatDesktop`.
// If we render different DOM on server vs client, Vue hydration will keep the
// server HTML (no patch) and the layout/CSS fixes won't apply reliably.
// So we detect desktop onMounted and update reactively.
const isDesktop = ref(false)
const isDesktopUpdater = ref(false)
const updateDprVar = () => {
const dpr = window.devicePixelRatio || 1
document.documentElement.style.setProperty('--dpr', String(dpr))
}
onMounted(() => {
const isElectron = /electron/i.test(String(navigator.userAgent || ''))
const api = window?.wechatDesktop
isDesktop.value = isElectron && !!api
const brandOk = !api?.__brand || api.__brand === 'WeChatDataAnalysisDesktop'
isDesktopUpdater.value =
isDesktop.value &&
brandOk &&
typeof api?.checkForUpdates === 'function' &&
typeof api?.downloadAndInstall === 'function'
updateDprVar()
window.addEventListener('resize', updateDprVar)
if (isDesktopUpdater.value) {
void desktopUpdate.initListeners()
}
// Init global UI state.
const chatAccounts = useChatAccountsStore()
const privacy = usePrivacyStore()
void chatAccounts.ensureLoaded()
privacy.init()
themeStore.init()
})
onBeforeUnmount(() => {
window.removeEventListener('resize', updateDprVar)
})
const rootClass = computed(() => {
const base = 'theme-app-shell'
return isDesktop.value
? `wechat-desktop h-screen flex overflow-hidden ${base}`
: `h-screen flex overflow-hidden ${base}`
})
const contentClass = computed(() =>
isDesktop.value
? 'wechat-desktop-content flex-1 overflow-auto min-h-0'
: 'flex-1 overflow-auto min-h-0'
)
const showDesktopTitleBar = computed(() => isDesktop.value)
const showSidebar = computed(() => {
const path = String(route.path || '')
if (path === '/' || path === '/import') return false
if (path === '/decrypt' || path === '/detection-result' || path === '/decrypt-result') return false
return !(path === '/wrapped' || path.startsWith('/wrapped/'))
})
</script>
<style>
:root {
--dpr: 1;
/* Left sidebar rail (chat/sns): icon size + spacing */
--sidebar-rail-step: 48px;
--sidebar-rail-btn: 32px;
--sidebar-rail-icon: 24px;
}
/* Electron 桌面端使用自绘标题栏(frame: false)。
* 页面里如果继续用 Tailwind 的 h-screen/min-h-screen100vh),会把标题栏高度叠加进去,从而出现外层滚动条。
* 这里把 “screen” 在桌面端视为内容区高度(100%),让标题栏高度自然内嵌在布局里。 */
.wechat-desktop {
--desktop-titlebar-height: 32px;
--desktop-titlebar-btn-width: 46px;
}
/* 仅重解释页面根节点的 h-screen/min-h-screen,避免影响页面内其它布局。
* 使用 100% 跟随 flex 内容区高度,避免 100vh/calc 在某些缩放比例下产生 1px 误差导致滚动条。 */
.wechat-desktop .wechat-desktop-content > .h-screen {
height: 100%;
}
.wechat-desktop .wechat-desktop-content > .min-h-screen {
min-height: 100%;
}
.theme-app-shell {
background:
radial-gradient(circle at top left, rgba(7, 193, 96, 0.08), transparent 32%),
radial-gradient(circle at top right, rgba(16, 174, 239, 0.08), transparent 36%),
linear-gradient(135deg, #f0fdf4 0%, #ecfdf5 45%, #dcfce7 100%);
}
html[data-theme='dark'] .theme-app-shell {
background: var(--app-shell-bg);
}
</style>