Files
autoAiWorkSys/app/App.vue
张成 e17d5610f5 1
2025-12-22 16:26:59 +08:00

279 lines
8.3 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="container">
<header class="header">
<div class="header-left">
<h1>Boss - 远程监听服务 <span style="font-size: 0.7em; opacity: 0.8;">v{{ currentVersion }}</span></h1>
<div class="status-indicator">
<span :class="statusDotClass"></span>
<span>{{ isConnected ? '已连接' : '未连接' }}</span>
</div>
</div>
<div class="header-right">
<!-- 登录页面不显示 UserMenu -->
<UserMenu v-if="showSidebar" />
</div>
</header>
<div class="main-content">
<!-- 左侧菜单 - 登录页面不显示 -->
<Sidebar v-if="showSidebar" />
<!-- 内容区域 - 使用 router-view 切换页面 -->
<div class="content-area" :class="{ 'full-width': !showSidebar }">
<router-view />
</div>
</div>
<!-- 更新弹窗 - 使用 store 管理状态 -->
<UpdateDialog />
</div>
</template>
<script>
import Sidebar from './components/Sidebar.vue';
import UpdateDialog from './components/UpdateDialog.vue';
import UserMenu from './components/UserMenu.vue';
// 导入 Vuex helpers
import { mapState } from 'vuex';
// 导入 Mixins
import logMixin from './mixins/logMixin.js';
import authMixin from './mixins/authMixin.js';
import mqttMixin from './mixins/mqttMixin.js';
import taskMixin from './mixins/taskMixin.js';
import systemInfoMixin from './mixins/systemInfoMixin.js';
import platformMixin from './mixins/platformMixin.js';
import qrCodeMixin from './mixins/qrCodeMixin.js';
import updateMixin from './mixins/updateMixin.js';
import eventListenerMixin from './mixins/eventListenerMixin.js';
// Vue 应用主组件逻辑
export default {
name: 'App',
mixins: [
logMixin,
authMixin,
mqttMixin,
taskMixin,
systemInfoMixin,
platformMixin,
qrCodeMixin,
updateMixin,
eventListenerMixin
],
components: {
Sidebar,
UpdateDialog,
UserMenu
},
data() {
return {
// 应用启动时间(用于计算运行时间)
startTime: Date.now(),
// 应用加载状态
isLoading: true,
// 浏览器窗口状态
browserWindowVisible: false
};
},
mounted() {
this.init();
},
// beforeDestroy 已在 taskMixin 中定义
watch: {
// 监听登录状态变化
isLoggedIn(newVal, oldVal) {
// 未登录时自动跳转到登录页面
if (!newVal && this.$route.name !== 'Login') {
this.$router.push('/login');
}
// 登录状态从 false 变为 true 时,检查 MQTT 状态(连接由主进程自动处理)
if (newVal && !oldVal) {
// 延迟一下,确保 store 中的 snCode 已经更新
this.$nextTick(() => {
setTimeout(() => {
// MQTT 连接由主进程自动处理,这里只检查状态
if (this.checkMQTTStatus) {
this.checkMQTTStatus();
}
// 开始获取任务状态
if (this.startTaskStatusUpdate) {
this.startTaskStatusUpdate();
}
}, 500);
});
}
}
},
methods: {
async init() {
try {
// 先隐藏加载屏幕,避免一直显示
this.hideLoadingScreen();
if (window.electronAPI && window.electronAPI.invoke) {
const result = await window.electronAPI.invoke('system:get-version');
if (result && result.success && result.version) {
this.currentVersion = result.version;
this.addLog('info', `当前版本: v${this.currentVersion}`);
} else if (window.appInfo && window.appInfo.version) {
this.currentVersion = window.appInfo.version;
}
} else if (window.appInfo && window.appInfo.version) {
this.currentVersion = window.appInfo.version;
}
} catch (error) {
console.error('获取版本号失败:', error);
if (window.appInfo && window.appInfo.version) {
this.$store.commit('app/SET_VERSION', window.appInfo.version);
}
}
this.setupEventListeners();
await this.loadSavedConfig();
// 加载投递配置到 store
if (this.$store && this.$store.dispatch) {
await this.$store.dispatch('delivery/loadDeliveryConfig');
}
this.startSystemInfoUpdate();
// 尝试自动登录
const autoLoginSuccess = await this.tryAutoLogin();
// 如果已登录,开始获取任务状态
if (this.$store.state.auth.isLoggedIn) {
this.startTaskStatusUpdate();
// 检查 MQTT 连接状态
this.checkMQTTStatus();
} else if (!autoLoginSuccess) {
// 未登录时,自动跳转到登录页面
this.$router.push('/login');
}
},
hideLoadingScreen() {
setTimeout(() => {
const loadingScreen = document.getElementById('loading-screen');
const app = document.getElementById('app');
if (loadingScreen) {
loadingScreen.classList.add('hidden');
setTimeout(() => {
if (loadingScreen.parentNode) {
loadingScreen.remove();
}
}, 500);
}
if (app) {
app.style.display = 'block';
}
this.isLoading = false;
}, 500);
},
// setupEventListeners 已在 eventListenerMixin 中定义
// loadSavedConfig, checkActivationStatus, userLogin, tryAutoLogin 已在 authMixin 中定义
// startTaskStatusUpdate, updateCurrentTask, onTaskStatusUpdate 已在 taskMixin 中定义
// connectMQTT, disconnectMQTT, onMQTTConnected, onMQTTDisconnected, onMQTTMessage, onMQTTStatusChange 已在 mqttMixin 中定义
// handleMenuChange, handleUpdateDeliveryConfig, handleLoginFromPage, handleLoginFromDialog 已不需要,使用路由和组件内部处理
/**
* 检查 MQTT 连接状态,如果未连接则尝试重新连接
*/
async checkMQTTStatus() {
try {
if (!window.electronAPI || !window.electronAPI.invoke) {
console.warn('[App] electronAPI 不可用');
return;
}
// 获取当前 MQTT 状态
const status = await window.electronAPI.invoke('mqtt:status');
console.log('[App] MQTT 状态查询结果:', status);
if (status && status.isConnected) {
// 如果已经连接,更新状态
if (this.$store) {
this.$store.dispatch('mqtt/setConnected', true);
console.log('[App] MQTT 状态已更新为已连接');
}
} else {
// 如果未连接,尝试重新连接(需要 snCode
const snCode = this.$store?.state?.auth?.snCode;
if (snCode) {
console.log('[App] MQTT 未连接,尝试重新连接...');
try {
await window.electronAPI.invoke('mqtt:connect', snCode);
console.log('[App] MQTT 重新连接成功');
if (this.$store) {
this.$store.dispatch('mqtt/setConnected', true);
}
} catch (error) {
console.warn('[App] MQTT 重新连接失败:', error);
if (this.$store) {
this.$store.dispatch('mqtt/setConnected', false);
}
}
} else {
console.warn('[App] 无法重新连接 MQTT: 缺少 snCode');
}
}
} catch (error) {
console.error('[App] 检查 MQTT 状态失败:', error);
}
}
},
computed: {
...mapState('app', ['currentVersion']),
...mapState('mqtt', ['isConnected']),
...mapState('auth', ['isLoggedIn', 'userName', 'snCode', 'deviceId', 'remainingDays', 'phone']),
// 根据路由 meta 决定是否显示侧边栏,默认为 true
showSidebar() {
return this.$route.meta.showSidebar !== false;
},
statusDotClass() {
return {
'status-dot': true,
'connected': this.isConnected
};
}
// logEntries 已在 logMixin 中定义
}
// snCode watch 已在 authMixin 中定义
};
</script>
<style lang="less" scoped>
// 登录页面时内容区域不需要背景和padding
.content-area.full-width {
// 当侧边栏隐藏时,登录页面应该有特殊样式
&.login-page {
padding: 0;
background: transparent;
border-radius: 0;
box-shadow: none;
}
}
</style>