From b36fb8956664bd10cc035b6f3c4cdaf9823d1d91 Mon Sep 17 00:00:00 2001 From: DLmaster361 Date: Sat, 13 Sep 2025 17:43:36 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=87=AA=E5=8A=A8=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E6=8C=89=E9=92=AE=E7=94=9F=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/App.vue | 20 ++-- .../components/initialization/AdminCheck.vue | 12 ++- .../components/initialization/AutoMode.vue | 56 ++++++++++- .../components/initialization/ManualMode.vue | 92 +++++++++++++++---- frontend/src/composables/useUpdateChecker.ts | 77 ++++++++++++++-- frontend/src/views/Initialization.vue | 18 ++-- frontend/src/views/Settings.vue | 18 ++++ 7 files changed, 244 insertions(+), 49 deletions(-) diff --git a/frontend/src/App.vue b/frontend/src/App.vue index e566052..a4cfc6b 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -3,7 +3,7 @@ import { onMounted, computed } from 'vue' import { useRoute } from 'vue-router' import { ConfigProvider } from 'ant-design-vue' import { useTheme } from './composables/useTheme.ts' -import { useUpdateChecker } from './composables/useUpdateChecker.ts' +import { useUpdateModal } from './composables/useUpdateChecker.ts' import AppLayout from './components/AppLayout.vue' import TitleBar from './components/TitleBar.vue' import UpdateModal from './components/UpdateModal.vue' @@ -12,7 +12,7 @@ import { logger } from '@/utils/logger' const route = useRoute() const { antdTheme, initTheme } = useTheme() -const { updateVisible, updateData, onUpdateConfirmed } = useUpdateChecker() +const { updateVisible, updateData, onUpdateConfirmed } = useUpdateModal() // 判断是否为初始化页面 const isInitializationPage = computed(() => route.name === 'Initialization') @@ -55,24 +55,28 @@ onMounted(() => { .app-container { height: 100vh; - overflow: hidden; display: flex; flex-direction: column; } .initialization-container { height: 100vh; - overflow: hidden; display: flex; flex-direction: column; } .initialization-content { flex: 1; - overflow: auto; + overflow-y: auto; + overflow-x: hidden; width: 100%; - height: 100%; - scrollbar-width: none; - -ms-overflow-style: none; + /* 隐藏滚动条但保留滚动功能 */ + scrollbar-width: none; /* Firefox */ + -ms-overflow-style: none; /* IE/Edge */ +} + +/* 隐藏 Webkit 浏览器的滚动条 */ +.initialization-content::-webkit-scrollbar { + display: none; } diff --git a/frontend/src/components/initialization/AdminCheck.vue b/frontend/src/components/initialization/AdminCheck.vue index 46492b7..c2642a4 100644 --- a/frontend/src/components/initialization/AdminCheck.vue +++ b/frontend/src/components/initialization/AdminCheck.vue @@ -29,6 +29,16 @@ async function handleRestartAsAdmin() { display: flex; justify-content: center; align-items: center; - min-height: 60vh; + min-height: calc(100vh - 120px); /* 减去标题栏和一些边距 */ + padding: 20px; + box-sizing: border-box; +} + +/* 响应式优化 */ +@media (max-height: 600px) { + .admin-check { + min-height: auto; + padding: 10px; + } } diff --git a/frontend/src/components/initialization/AutoMode.vue b/frontend/src/components/initialization/AutoMode.vue index 11fa8d3..a7ffb90 100644 --- a/frontend/src/components/initialization/AutoMode.vue +++ b/frontend/src/components/initialization/AutoMode.vue @@ -42,6 +42,7 @@ import { ref, onMounted } from 'vue' import { getConfig } from '@/utils/config' import { getMirrorUrl } from '@/config/mirrors' import router from '@/router' +import { useUpdateChecker } from '@/composables/useUpdateChecker' import { connectAfterBackendStart } from '@/composables/useWebSocket' @@ -54,6 +55,9 @@ interface Props { const props = defineProps() +// 使用更新检查器 +const { startPolling } = useUpdateChecker() + // 状态 const progress = ref(0) const progressText = ref('') @@ -195,6 +199,10 @@ async function startBackendService() { } else { console.log('WebSocket连接建立成功') } + + // WebSocket连接完成后,启动版本检查定时任务 + console.log('启动版本检查定时任务...') + await startPolling() } // 组件挂载时开始自动流程 @@ -210,14 +218,14 @@ onMounted(() => { flex-direction: column; align-items: center; justify-content: center; - min-height: 60vh; + min-height: calc(100vh - 120px); /* 减去标题栏和一些边距 */ + padding: 20px; + box-sizing: border-box; } .header { text-align: center; margin-bottom: 40px; - margin-top: 100px; - flex: auto; display: flex; align-items: center; justify-content: center; @@ -236,13 +244,19 @@ onMounted(() => { height: 100px; } +.tip { + margin-bottom: 20px; + text-align: center; +} + .auto-progress { display: flex; flex-direction: column; align-items: center; gap: 20px; margin: 40px 0; - width: 400px; + width: 100%; + max-width: 400px; } .progress-text { @@ -255,5 +269,39 @@ onMounted(() => { margin-top: 20px; display: flex; gap: 20px; + flex-wrap: wrap; + justify-content: center; +} + +/* 响应式优化 */ +@media (max-height: 700px) { + .auto-mode { + min-height: auto; + padding: 10px; + } + + .header { + margin-bottom: 20px; + } + + .header h1 { + font-size: 32px; + } + + .logo { + width: 80px; + height: 80px; + } +} + +@media (max-width: 600px) { + .auto-actions { + flex-direction: column; + align-items: center; + } + + .auto-actions .ant-btn { + width: 200px; + } } diff --git a/frontend/src/components/initialization/ManualMode.vue b/frontend/src/components/initialization/ManualMode.vue index ad1bad8..020240c 100644 --- a/frontend/src/components/initialization/ManualMode.vue +++ b/frontend/src/components/initialization/ManualMode.vue @@ -49,12 +49,12 @@ - - - - - - + + + + + + @@ -139,6 +139,7 @@ import { ref, watch } from 'vue' import { notification } from 'ant-design-vue' import { saveConfig } from '@/utils/config' +import { useUpdateChecker } from '@/composables/useUpdateChecker' import ThemeStep from './ThemeStep.vue' import PythonStep from './PythonStep.vue' @@ -167,6 +168,9 @@ interface Props { const props = defineProps() +// 使用更新检查器 +const { startPolling } = useUpdateChecker() + // 基础状态 const currentStep = ref(0) const stepStatus = ref<'wait' | 'process' | 'finish' | 'error'>('process') @@ -391,6 +395,23 @@ async function autoStartBackendService() { if (result.success) { if (serviceStepRef.value) { serviceStepRef.value.serviceProgress = 100 + serviceStepRef.value.serviceStatus = '后端服务启动成功,正在建立WebSocket连接...' + } + + // 后端启动成功,建立WebSocket连接 + console.log('后端自动启动成功,正在建立WebSocket连接...') + const wsConnected = await connectAfterBackendStart() + if (!wsConnected) { + console.warn('WebSocket连接建立失败,但继续进入应用') + } else { + console.log('WebSocket连接建立成功') + } + + // WebSocket连接完成后,启动版本检查定时任务 + console.log('启动版本检查定时任务...') + await startPolling() + + if (serviceStepRef.value) { serviceStepRef.value.serviceStatus = '后端服务启动成功,即将进入主页...' } stepStatus.value = 'finish' @@ -448,6 +469,10 @@ async function startBackendService() { console.log('WebSocket连接建立成功') } + // WebSocket连接完成后,启动版本检查定时任务 + console.log('启动版本检查定时任务...') + await startPolling() + if (serviceStepRef.value) { serviceStepRef.value.serviceStatus = '后端服务启动成功,即将进入主页...' } @@ -514,25 +539,23 @@ watch(errorMessage, val => { diff --git a/frontend/src/composables/useUpdateChecker.ts b/frontend/src/composables/useUpdateChecker.ts index 25a9440..6945dd9 100644 --- a/frontend/src/composables/useUpdateChecker.ts +++ b/frontend/src/composables/useUpdateChecker.ts @@ -1,4 +1,4 @@ -import { ref, onMounted, onUnmounted } from 'vue' +import { ref, onUnmounted } from 'vue' import { Service } from '@/api' import { message } from 'ant-design-vue' @@ -17,11 +17,32 @@ const isPolling = ref(false) // 防止重复弹出的状态 let lastShownVersion: string | null = null +// 检查自动更新设置是否开启 +const checkAutoUpdateEnabled = async (): Promise => { + try { + const response = await Service.getScriptsApiSettingGetPost() + if (response.code === 200 && response.data) { + return response.data.Update?.IfAutoUpdate || false + } + } catch (error) { + console.warn('[useUpdateChecker] 获取自动更新设置失败:', error) + } + return false +} + export function useUpdateChecker() { // 执行一次更新检查 - 完全参考顶栏的 pollOnce 逻辑 const pollOnce = async () => { if (isPolling.value) return + + // 检查自动更新设置是否开启 + const autoUpdateEnabled = await checkAutoUpdateEnabled() + if (!autoUpdateEnabled) { + console.log('[useUpdateChecker] 自动检查更新已关闭,跳过定时检查') + return + } + isPolling.value = true try { @@ -89,8 +110,23 @@ export function useUpdateChecker() { updateVisible.value = false } - // 组件挂载时启动检查器 - 参考顶栏的 onMounted 逻辑 - onMounted(async () => { + // 启动定时检查器 + const startPolling = async () => { + // 检查自动更新设置是否开启 + const autoUpdateEnabled = await checkAutoUpdateEnabled() + if (!autoUpdateEnabled) { + console.log('[useUpdateChecker] 自动检查更新已关闭,不启动定时任务') + return + } + + // 如果已经在检查中,则不重复启动 + if (updateCheckTimer) { + console.log('[useUpdateChecker] 定时任务已存在,跳过启动') + return + } + + console.log('[useUpdateChecker] 启动定时版本检查任务') + // 延迟3秒后再执行首次检查,确保后端已经完全启动 setTimeout(async () => { await pollOnce() @@ -98,20 +134,47 @@ export function useUpdateChecker() { // 每 4 小时检查一次更新 updateCheckTimer = setInterval(pollOnce, POLL_MS) - }) + } - // 组件卸载时清理定时器 - 参考顶栏的 onBeforeUnmount 逻辑 - onUnmounted(() => { + // 停止定时检查器 + const stopPolling = () => { if (updateCheckTimer) { clearInterval(updateCheckTimer) updateCheckTimer = null + console.log('[useUpdateChecker] 停止定时版本检查任务') } + } + + // 重新启动定时检查器(当设置变更时调用) + const restartPolling = async () => { + console.log('[useUpdateChecker] 重新启动定时检查任务') + stopPolling() // 先停止现有任务 + await startPolling() // 再根据设置重新启动 + } + + // 组件卸载时清理定时器 + onUnmounted(() => { + stopPolling() }) return { updateVisible, updateData, checkUpdate, - onUpdateConfirmed + onUpdateConfirmed, + startPolling, + stopPolling, + restartPolling + } +} + +// 创建一个仅用于显示弹窗的轻量版本(给App.vue使用) +export function useUpdateModal() { + return { + updateVisible, + updateData, + onUpdateConfirmed: () => { + updateVisible.value = false + } } } diff --git a/frontend/src/views/Initialization.vue b/frontend/src/views/Initialization.vue index 06857b4..d3da8ca 100644 --- a/frontend/src/views/Initialization.vue +++ b/frontend/src/views/Initialization.vue @@ -1,5 +1,5 @@