Files
web-fusion/src/App.vue
2026-03-26 13:38:35 +08:00

278 lines
8.8 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>
<!-- 强制更新检查 -->
<!-- <UpdateChecker v-if="false" @ready="updateReady = true" /> -->
<UpdateChecker v-if="!isDev && isElectronEnv && !updateReady" @ready="updateReady = true" />
<template v-else>
<!-- 滚动通知栏登录页和工作台都显示 -->
<NoticeBar />
<!-- 登录页面 -->
<LoginPage v-if="currentPage === 'login'" @login-success="currentPage = 'browser'" class="animate-fadeIn" />
<template v-else>
<!-- 配置页面 - 使用 v-show 保持状态 -->
<div class="h-full w-full animate-fadeIn" v-show="currentPage === 'config'">
<ConfigPage @go-to-browser="handleGoToBrowser" @logout="handleLogout" />
<!-- 更新通知组件启动时已在 UpdateChecker 检查此处暂不显示 -->
<!-- <UpdateNotification /> -->
</div>
<!-- 浏览器页面 -->
<div class="h-full w-full animate-fadeIn" v-show="currentPage === 'browser'">
<WorkbenchLayout :account-groups="accountGroups" :rotation-status="rotationStatus"
:greeting-stats="greetingStats" :automation-logs="automationLogs" @go-back="handleGoToConfig"
@stop-all="handleStopAll" @logout="handleLogout" />
</div>
</template>
</template>
</template>
<script setup>
import { ref, computed, onMounted, onUnmounted, watch } from 'vue'
import { isElectron, getAppVersion } from './utils/electronBridge'
import LoginPage from './pages/LoginPage.vue'
import ConfigPage from './pages/ConfigPage.vue'
import UpdateChecker from './pages/UpdateChecker.vue'
import WorkbenchLayout from './layout/WorkbenchLayout.vue'
import UpdateNotification from './components/UpdateNotification.vue'
import NoticeBar from './components/NoticeBar.vue'
import { useNoticeStore } from './stores/noticeStore'
// Constants
const USER_KEY = 'user_data'
const CONFIG_KEY = 'autoDm_runConfig'
// State
const updateReady = ref(false)
const currentPage = ref('login')
const isLoading = ref(false)
const automationStatus = ref({})
const accountGroups = ref([])
const viewAccountMap = ref({})
const rotationStatus = ref(null)
const greetingStats = ref({ greetingCount: 0, inviteCount: 0 })
const automationLogs = ref([])
const isElectronEnv = isElectron()
const isDev = window.location.port === '5173'
// 公告通知
const noticeStore = useNoticeStore()
noticeStore.fetchNotices()
// Lifecycle
onMounted(() => {
// Set Title
getAppVersion().then(version => {
document.title = `Yolo终端v${version}`
}).catch(() => {
document.title = 'Yolo终端'
})
console.log('[App]', !isDev, isElectronEnv, !updateReady.value)
// Check Login
try {
const userData = localStorage.getItem(USER_KEY)
if (userData) {
const user = JSON.parse(userData)
if (user && user.tokenValue) {
currentPage.value = 'browser'
}
}
} catch { } // eslint-disable-line no-empty
// Listeners
if (isElectronEnv) {
window.electronAPI.onRequestClearLogin(() => {
console.log('[App] 收到清除登录状态请求')
localStorage.removeItem(USER_KEY)
})
// Rotation Status
window.electronAPI.getRotationStatus().then(status => {
rotationStatus.value = status
}).catch(console.error)
window.electronAPI.onRotationStatusChanged(status => {
rotationStatus.value = status
console.log('[App] 收到轮换状态变化123:', status)
// Auto switch tab if group changes
if (status && status.currentActiveGroup && status.enabled) {
console.log('[App] 收到轮换状态变化456:', status)
const targetTab = tabs.value.find(t => t.label === status.currentActiveGroup || t.id === status.currentActiveGroup)
if (targetTab && targetTab.id !== currentTab.value) {
console.log('[App] 自动切换到轮换组789:', targetTab.id)
handleTabSwitch(targetTab.id)
}
}
})
// Stats
window.electronAPI.getGreetingStats().then(stats => {
greetingStats.value = stats
}).catch(console.error)
window.electronAPI.onGreetingStatsChanged(stats => {
greetingStats.value = stats
})
// Logs
window.electronAPI.onAutomationLog(log => {
automationLogs.value = [...automationLogs.value.slice(-99), { ...log, timestamp: Date.now() }]
})
}
window.addEventListener('beforeunload', handleBeforeUnload)
window.addEventListener('storage', handleStorageChange)
loadConfig()
// Health Check
startHealthCheck()
})
onUnmounted(() => {
window.removeEventListener('beforeunload', handleBeforeUnload)
window.removeEventListener('storage', handleStorageChange)
stopHealthCheck()
})
// Handlers
const handleBeforeUnload = () => {
localStorage.removeItem(USER_KEY)
}
const handleStorageChange = (e) => {
if (e.key === CONFIG_KEY) {
loadConfig()
}
}
let healthCheckInterval = null
const startHealthCheck = () => {
const check = async () => {
if (currentPage.value === 'login' || !isElectron()) return
try {
const result = await window.electronAPI.checkHealth()
if (result.success && result.code === 40400) {
alert('当前账号已在其他地方登录,请重新登录')
localStorage.removeItem(USER_KEY)
// 隐藏所有 BrowserView 并停止自动化,防止视图悬浮在登录页上方
try {
await window.electronAPI.hideViews()
await handleStopAll()
} catch (e) {
console.warn('[App] 清理视图失败:', e)
}
currentPage.value = 'login'
}
} catch (error) {
console.error('[App] 健康检查失败:', error)
}
}
check()
healthCheckInterval = setInterval(check, 5000)
}
const stopHealthCheck = () => {
if (healthCheckInterval) clearInterval(healthCheckInterval)
}
const loadConfig = () => {
try {
const savedConfig = localStorage.getItem(CONFIG_KEY)
if (savedConfig) {
const config = JSON.parse(savedConfig)
accountGroups.value = config.accountGroups || []
const map = {}
config.accountGroups.forEach((group, groupIndex) => {
const viewsPerGroup = 3
group.accounts.forEach((account, accIndex) => {
const viewId = groupIndex * viewsPerGroup + accIndex + 1
if (viewId <= 9 && account.email && account.pwd) {
map[viewId] = { ...account, group: group.name }
}
})
})
viewAccountMap.value = map
}
} catch { } // eslint-disable-line no-empty
}
watch(currentPage, (newVal) => {
if (newVal === 'browser') {
loadConfig()
}
})
// Actions
const handleGoToBrowser = async () => {
if (isElectron()) {
await window.electronAPI.showViews()
}
currentPage.value = 'browser'
}
const handleGoToConfig = async () => {
if (isElectron()) {
await window.electronAPI.hideViews()
}
currentPage.value = 'config'
}
const handleLogout = async () => {
stopHealthCheck()
currentPage.value = 'login'
localStorage.removeItem(USER_KEY)
if (isElectron()) {
try { await window.electronAPI.logout() } catch (e) { console.warn('[App] logout失败:', e) }
try {
await window.electronAPI.hideViews()
await handleStopAll()
} catch (e) {
console.warn('[App] 清理视图失败:', e)
}
}
}
const handleStopAll = async () => {
if (!isElectron()) return
console.log('[App] 开始并行停止所有任务...')
await Promise.allSettled(
Array.from({ length: 9 }, (_, i) => i + 1).map(viewId =>
window.electronAPI.stopTikTokAutomation(viewId).catch((e) => {
console.warn(`[App] 停止视图 ${viewId} 失败:`, e)
})
)
)
try {
await window.electronAPI.updateAutomationConfig({
rotationEnabled: false
})
} catch (e) {
console.warn('[App] 停止轮换服务失败:', e)
}
automationStatus.value = {}
rotationStatus.value = null
try {
console.log('[App] 正在清空缓存...')
if (window.electronAPI.clearAllCache) await window.electronAPI.clearAllCache()
console.log('[App] 缓存清空完成')
} catch (e) {
console.warn('[App] 清空缓存失败:', e)
}
console.log('[App] 已并行停止所有任务并清空缓存')
}
</script>