import { useEffect, useState } from 'react' import { Routes, Route, useNavigate, useLocation } from 'react-router-dom' import TitleBar from './components/TitleBar' import Sidebar from './components/Sidebar' import RouteGuard from './components/RouteGuard' import WelcomePage from './pages/WelcomePage' import HomePage from './pages/HomePage' import ChatPage from './pages/ChatPage' import AnalyticsPage from './pages/AnalyticsPage' import AnalyticsWelcomePage from './pages/AnalyticsWelcomePage' import AnnualReportPage from './pages/AnnualReportPage' import AnnualReportWindow from './pages/AnnualReportWindow' import DualReportPage from './pages/DualReportPage' import DualReportWindow from './pages/DualReportWindow' import AgreementPage from './pages/AgreementPage' import GroupAnalyticsPage from './pages/GroupAnalyticsPage' import SettingsPage from './pages/SettingsPage' import ExportPage from './pages/ExportPage' import VideoWindow from './pages/VideoWindow' import ImageWindow from './pages/ImageWindow' import SnsPage from './pages/SnsPage' import ContactsPage from './pages/ContactsPage' import ChatHistoryPage from './pages/ChatHistoryPage' import NotificationWindow from './pages/NotificationWindow' import { useAppStore } from './stores/appStore' import { themes, useThemeStore, type ThemeId } from './stores/themeStore' import * as configService from './services/config' import { Download, X, Shield } from 'lucide-react' import './App.scss' import UpdateDialog from './components/UpdateDialog' import UpdateProgressCapsule from './components/UpdateProgressCapsule' import LockScreen from './components/LockScreen' import { GlobalSessionMonitor } from './components/GlobalSessionMonitor' function App() { const navigate = useNavigate() const location = useLocation() const { setDbConnected, updateInfo, setUpdateInfo, isDownloading, setIsDownloading, downloadProgress, setDownloadProgress, showUpdateDialog, setShowUpdateDialog, setUpdateError, isLocked, setLocked } = useAppStore() const { currentTheme, themeMode, setTheme, setThemeMode } = useThemeStore() const isAgreementWindow = location.pathname === '/agreement-window' const isOnboardingWindow = location.pathname === '/onboarding-window' const isVideoPlayerWindow = location.pathname === '/video-player-window' const isChatHistoryWindow = location.pathname.startsWith('/chat-history/') const isNotificationWindow = location.pathname === '/notification-window' const [themeHydrated, setThemeHydrated] = useState(false) // 锁定状态 // const [isLocked, setIsLocked] = useState(false) // Moved to store const [lockAvatar, setLockAvatar] = useState( localStorage.getItem('app_lock_avatar') || undefined ) const [lockUseHello, setLockUseHello] = useState(false) // 协议同意状态 const [showAgreement, setShowAgreement] = useState(false) const [agreementChecked, setAgreementChecked] = useState(false) const [agreementLoading, setAgreementLoading] = useState(true) useEffect(() => { const root = document.documentElement const body = document.body const appRoot = document.getElementById('app') if (isOnboardingWindow || isNotificationWindow) { root.style.background = 'transparent' body.style.background = 'transparent' body.style.overflow = 'hidden' if (appRoot) { appRoot.style.background = 'transparent' appRoot.style.overflow = 'hidden' } } else { root.style.background = 'var(--bg-primary)' body.style.background = 'var(--bg-primary)' body.style.overflow = '' if (appRoot) { appRoot.style.background = '' appRoot.style.overflow = '' } } }, [isOnboardingWindow]) // 应用主题 useEffect(() => { document.documentElement.setAttribute('data-theme', currentTheme) document.documentElement.setAttribute('data-mode', themeMode) // 更新窗口控件颜色以适配主题 const symbolColor = themeMode === 'dark' ? '#ffffff' : '#1a1a1a' if (!isOnboardingWindow && !isNotificationWindow) { window.electronAPI.window.setTitleBarOverlay({ symbolColor }) } }, [currentTheme, themeMode, isOnboardingWindow, isNotificationWindow]) // 读取已保存的主题设置 useEffect(() => { const loadTheme = async () => { try { const [savedThemeId, savedThemeMode] = await Promise.all([ configService.getThemeId(), configService.getTheme() ]) if (savedThemeId && themes.some((theme) => theme.id === savedThemeId)) { setTheme(savedThemeId as ThemeId) } if (savedThemeMode === 'light' || savedThemeMode === 'dark') { setThemeMode(savedThemeMode) } } catch (e) { console.error('读取主题配置失败:', e) } finally { setThemeHydrated(true) } } loadTheme() }, [setTheme, setThemeMode]) // 保存主题设置 useEffect(() => { if (!themeHydrated) return const saveTheme = async () => { try { await Promise.all([ configService.setThemeId(currentTheme), configService.setTheme(themeMode) ]) } catch (e) { console.error('保存主题配置失败:', e) } } saveTheme() }, [currentTheme, themeMode, themeHydrated]) // 检查是否已同意协议 useEffect(() => { const checkAgreement = async () => { try { const agreed = await configService.getAgreementAccepted() if (!agreed) { setShowAgreement(true) } } catch (e) { console.error('检查协议状态失败:', e) } finally { setAgreementLoading(false) } } checkAgreement() }, []) const handleAgree = async () => { if (!agreementChecked) return await configService.setAgreementAccepted(true) setShowAgreement(false) } const handleDisagree = () => { window.electronAPI.window.close() } // 监听启动时的更新通知 useEffect(() => { if (isNotificationWindow) return // Skip updates in notification window const removeUpdateListener = window.electronAPI?.app?.onUpdateAvailable?.((info: any) => { // 发现新版本时自动打开更新弹窗 if (info) { setUpdateInfo({ ...info, hasUpdate: true }) setShowUpdateDialog(true) } }) const removeProgressListener = window.electronAPI?.app?.onDownloadProgress?.((progress: any) => { setDownloadProgress(progress) }) return () => { removeUpdateListener?.() removeProgressListener?.() } }, [setUpdateInfo, setDownloadProgress, setShowUpdateDialog, isNotificationWindow]) const handleUpdateNow = async () => { setShowUpdateDialog(false) setIsDownloading(true) setDownloadProgress({ percent: 0 }) try { await window.electronAPI.app.downloadAndInstall() } catch (e: any) { console.error('更新失败:', e) setIsDownloading(false) // Extract clean error message if possible const errorMsg = e.message || String(e) setUpdateError(errorMsg.includes('暂时禁用') ? '自动更新已暂时禁用' : errorMsg) } } const handleIgnoreUpdate = async () => { if (!updateInfo || !updateInfo.version) return try { await window.electronAPI.app.ignoreUpdate(updateInfo.version) setShowUpdateDialog(false) setUpdateInfo(null) } catch (e: any) { console.error('忽略更新失败:', e) } } const dismissUpdate = () => { setUpdateInfo(null) } // 启动时自动检查配置并连接数据库 useEffect(() => { if (isAgreementWindow || isOnboardingWindow) return const autoConnect = async () => { try { const dbPath = await configService.getDbPath() const decryptKey = await configService.getDecryptKey() const wxid = await configService.getMyWxid() const onboardingDone = await configService.getOnboardingDone() const wxidConfig = wxid ? await configService.getWxidConfig(wxid) : null const effectiveDecryptKey = wxidConfig?.decryptKey || decryptKey if (wxidConfig?.decryptKey && wxidConfig.decryptKey !== decryptKey) { await configService.setDecryptKey(wxidConfig.decryptKey) } // 如果配置完整,自动测试连接 if (dbPath && effectiveDecryptKey && wxid) { if (!onboardingDone) { await configService.setOnboardingDone(true) } const result = await window.electronAPI.chat.connect() if (result.success) { setDbConnected(true, dbPath) // 如果当前在欢迎页,跳转到首页 if (window.location.hash === '#/' || window.location.hash === '') { navigate('/home') } } else { // 如果错误信息包含 VC++ 或 DLL 相关内容,不清除配置,只提示用户 // 其他错误可能需要重新配置 const errorMsg = result.error || '' if (errorMsg.includes('Visual C++') || errorMsg.includes('DLL') || errorMsg.includes('Worker') || errorMsg.includes('126') || errorMsg.includes('模块')) { console.warn('检测到可能的运行时依赖问题:', errorMsg) // 不清除配置,让用户安装 VC++ 后重试 } } } } catch (e) { console.error('自动连接出错:', e) // 捕获异常但不清除配置,防止循环重新引导 } } autoConnect() }, [isAgreementWindow, isOnboardingWindow, navigate, setDbConnected]) // 检查应用锁 useEffect(() => { if (isAgreementWindow || isOnboardingWindow || isVideoPlayerWindow) return const checkLock = async () => { // 并行获取配置,减少等待 const [enabled, useHello] = await Promise.all([ configService.getAuthEnabled(), configService.getAuthUseHello() ]) if (enabled) { setLockUseHello(useHello) setLocked(true) // 尝试获取头像 try { const result = await window.electronAPI.chat.getMyAvatarUrl() if (result && result.success && result.avatarUrl) { setLockAvatar(result.avatarUrl) localStorage.setItem('app_lock_avatar', result.avatarUrl) } } catch (e) { console.error('获取锁屏头像失败', e) } } } checkLock() }, [isAgreementWindow, isOnboardingWindow, isVideoPlayerWindow]) // 独立协议窗口 if (isAgreementWindow) { return } if (isOnboardingWindow) { return } // 独立视频播放窗口 if (isVideoPlayerWindow) { return } // 独立图片查看窗口 const isImageViewerWindow = location.pathname === '/image-viewer-window' if (isImageViewerWindow) { return } // 独立聊天记录窗口 if (isChatHistoryWindow) { return } // 独立通知窗口 if (isNotificationWindow) { return } // 主窗口 - 完整布局 return (
{isLocked && ( setLocked(false)} avatar={lockAvatar} useHello={lockUseHello} /> )} {/* 全局悬浮进度胶囊 (处理:新版本提示、下载进度、错误提示) */} {/* 全局会话监听与通知 */} {/* 用户协议弹窗 */} {showAgreement && !agreementLoading && (

用户协议与隐私政策

欢迎使用WeFlow!在使用本软件前,请仔细阅读以下条款:

这是免费软件,如果你是付费购买的话请骂死那个骗子。 我们唯一的官方网站: https://github.com/hicccc77/WeFlow

1. 数据安全

本软件所有数据处理均在本地完成,不会上传任何聊天记录、个人信息到服务器。你的数据完全由你自己掌控。

2. 使用须知

本软件仅供个人学习研究使用,请勿用于任何非法用途。使用本软件解密、查看、分析的数据应为你本人所有或已获得授权。

3. 免责声明

因使用本软件产生的任何直接或间接损失,开发者不承担任何责任。请确保你的使用行为符合当地法律法规。

4. 隐私保护

本软件不收集任何用户数据。软件更新检测仅获取版本信息,不涉及任何个人隐私。

)} {/* 更新提示对话框 */} setShowUpdateDialog(false)} onUpdate={handleUpdateNow} onIgnore={handleIgnoreUpdate} isDownloading={isDownloading} progress={downloadProgress} />
} /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> } />
) } export default App