From bf12f1f29a2b2133cfab581394ec67bab26159b2 Mon Sep 17 00:00:00 2001 From: AoXuan Date: Sun, 10 Aug 2025 23:19:44 +0800 Subject: [PATCH] =?UTF-8?q?feat(initialization):=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=BC=BA=E5=88=B6=E9=87=8D=E6=96=B0=E5=AE=89=E8=A3=85=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E5=B9=B6=E4=BC=98=E5=8C=96=E7=8E=AF=E5=A2=83=E6=A3=80?= =?UTF-8?q?=E6=9F=A5=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 PythonStep、PipStep 和 GitStep 组件中添加强制重新安装功能 -优化环境检查逻辑,增加关键文件存在性检查 - 调整自动模式启动条件,确保关键文件存在 - 修复部分组件引用,增加必要的 ref --- .../components/initialization/AutoMode.vue | 43 ++++-- .../src/components/initialization/GitStep.vue | 60 ++++++- .../components/initialization/ManualMode.vue | 6 +- .../src/components/initialization/PipStep.vue | 60 ++++++- .../components/initialization/PythonStep.vue | 56 ++++++- frontend/src/views/Initialization.vue | 146 ++++++++++++++---- frontend/src/vite-env.d.ts | 54 ++++++- 7 files changed, 374 insertions(+), 51 deletions(-) diff --git a/frontend/src/components/initialization/AutoMode.vue b/frontend/src/components/initialization/AutoMode.vue index 49320f5..96c1034 100644 --- a/frontend/src/components/initialization/AutoMode.vue +++ b/frontend/src/components/initialization/AutoMode.vue @@ -99,15 +99,29 @@ async function startAutoProcess() { if (!result.success) { throw new Error(`代码更新失败: ${result.error}`) } + } - progressText.value = '更新依赖包...' - progress.value = 60 + // 无论是否有更新,都检查并安装依赖 + progressText.value = '检查并安装依赖包...' + progress.value = 60 - // 使用配置中保存的pip镜像源 - const pipResult = await window.electronAPI.installDependencies(config.selectedPipMirror) - if (!pipResult.success) { - throw new Error(`依赖更新失败: ${pipResult.error}`) - } + // 先尝试使用初始化时的镜像源 + let pipMirror = config.selectedPipMirror || 'tsinghua' + let pipResult = await window.electronAPI.installDependencies(pipMirror) + + // 如果初始化时的镜像源不通,让用户重新选择 + if (!pipResult.success) { + logger.warn(`使用镜像源 ${pipMirror} 安装依赖失败,需要重新选择镜像源`) + + // 切换到手动模式让用户重新选择镜像源 + progressText.value = '依赖安装失败,需要重新配置镜像源' + progressStatus.value = 'exception' + + setTimeout(() => { + progressText.value = '请点击下方按钮重新配置环境' + }, 2000) + + return } progressText.value = '启动后端服务...' @@ -121,7 +135,6 @@ async function startAutoProcess() { logger.info('自动启动流程完成,即将进入应用') // 延迟0.5秒后自动进入应用 - // todo 记得修改这里,为了调试加长了5000s setTimeout(() => { props.onAutoComplete() }, 500) @@ -139,11 +152,17 @@ async function startAutoProcess() { } } -// 检查Git更新(简化版本,实际可以调用Git API) +// 检查Git更新 async function checkGitUpdate(): Promise { - // 这里可以实现更复杂的Git更新检查逻辑 - // 暂时返回false,表示没有更新 - return false + try { + // 调用Electron API检查Git仓库是否有更新 + const result = await window.electronAPI.checkGitUpdate() + return result.hasUpdate || false + } catch (error) { + logger.warn('检查Git更新失败:', error) + // 如果检查失败,假设有更新,这样会触发代码拉取和依赖安装 + return true + } } // 根据镜像源key获取对应的URL diff --git a/frontend/src/components/initialization/GitStep.vue b/frontend/src/components/initialization/GitStep.vue index 44444ee..9e05dd8 100644 --- a/frontend/src/components/initialization/GitStep.vue +++ b/frontend/src/components/initialization/GitStep.vue @@ -13,15 +13,57 @@
- + +
+ + {{ reinstalling ? '正在重新安装...' : '强制重新安装' }} + +

点击此按钮将删除现有Git环境并重新安装

+
\ No newline at end of file diff --git a/frontend/src/components/initialization/ManualMode.vue b/frontend/src/components/initialization/ManualMode.vue index d82e85b..8503c27 100644 --- a/frontend/src/components/initialization/ManualMode.vue +++ b/frontend/src/components/initialization/ManualMode.vue @@ -46,10 +46,10 @@ - + - + @@ -152,6 +152,8 @@ const progressText = ref('') // 组件引用 const themeStepRef = ref() const pythonStepRef = ref() +const pipStepRef = ref() +const gitStepRef = ref() const backendStepRef = ref() const dependenciesStepRef = ref() const serviceStepRef = ref() diff --git a/frontend/src/components/initialization/PipStep.vue b/frontend/src/components/initialization/PipStep.vue index e7c697f..9f7c28d 100644 --- a/frontend/src/components/initialization/PipStep.vue +++ b/frontend/src/components/initialization/PipStep.vue @@ -14,15 +14,57 @@
- + +
+ + {{ reinstalling ? '正在重新安装...' : '强制重新安装' }} + +

点击此按钮将删除现有pip环境并重新安装

+
\ No newline at end of file diff --git a/frontend/src/components/initialization/PythonStep.vue b/frontend/src/components/initialization/PythonStep.vue index bc4d09a..e4b6d39 100644 --- a/frontend/src/components/initialization/PythonStep.vue +++ b/frontend/src/components/initialization/PythonStep.vue @@ -28,7 +28,13 @@
- + +
+ + {{ reinstalling ? '正在重新安装...' : '强制重新安装' }} + +

点击此按钮将删除现有Python环境并重新安装

+
@@ -58,6 +64,7 @@ const pythonMirrors = ref([ const selectedPythonMirror = ref('tsinghua') const testingSpeed = ref(false) +const reinstalling = ref(false) // 加载配置中的镜像源选择 async function loadMirrorConfig() { @@ -130,9 +137,38 @@ function getSpeedClass(speed: number | null) { return 'speed-slow' } +// 强制重新安装Python +async function handleForceReinstall() { + reinstalling.value = true + try { + console.log('开始强制重新安装Python') + // 先删除现有Python目录 + const deleteResult = await window.electronAPI.deletePython() + if (!deleteResult.success) { + throw new Error(`删除Python目录失败: ${deleteResult.error}`) + } + + // 重新下载安装Python + const installResult = await window.electronAPI.downloadPython(selectedPythonMirror.value) + if (!installResult.success) { + throw new Error(`重新安装Python失败: ${installResult.error}`) + } + + console.log('Python强制重新安装成功') + // 通知父组件更新状态 + window.location.reload() // 简单的页面刷新来更新状态 + } catch (error) { + console.error('Python强制重新安装失败:', error) + // 这里可以添加错误提示 + } finally { + reinstalling.value = false + } +} + defineExpose({ selectedPythonMirror, - testPythonMirrorSpeed + testPythonMirrorSpeed, + handleForceReinstall }) // 组件挂载时加载配置并自动开始测速 @@ -267,8 +303,24 @@ onMounted(async () => { .already-installed { display: flex; + flex-direction: column; justify-content: center; align-items: center; min-height: 200px; + gap: 20px; +} + +.reinstall-section { + display: flex; + flex-direction: column; + align-items: center; + gap: 12px; +} + +.reinstall-note { + font-size: 12px; + color: var(--ant-color-text-tertiary); + text-align: center; + margin: 0; } \ No newline at end of file diff --git a/frontend/src/views/Initialization.vue b/frontend/src/views/Initialization.vue index 5164053..3ad575e 100644 --- a/frontend/src/views/Initialization.vue +++ b/frontend/src/views/Initialization.vue @@ -76,66 +76,148 @@ async function enterApp() { } } +// 检查关键文件是否存在 +async function checkCriticalFiles() { + try { + logger.info('开始检查关键文件存在性') + console.log('🔍 正在调用 window.electronAPI.checkCriticalFiles()...') + + // 检查API是否存在 + if (!window.electronAPI.checkCriticalFiles) { + console.warn('⚠️ window.electronAPI.checkCriticalFiles 不存在,使用配置文件状态') + // 如果API不存在,从配置文件读取状态 + const config = await getConfig() + return { + pythonExists: config.pythonInstalled || false, + pipExists: config.pipInstalled || false, + gitExists: config.gitInstalled || false, + mainPyExists: config.backendExists || false + } + } + + // 检查关键文件 + const criticalFiles = await window.electronAPI.checkCriticalFiles() + + console.log('🔍 electronAPI.checkCriticalFiles() 原始返回结果:', criticalFiles) + console.log('🔍 详细检查结果:') + console.log(' - pythonExists:', criticalFiles.pythonExists, typeof criticalFiles.pythonExists) + console.log(' - pipExists:', criticalFiles.pipExists, typeof criticalFiles.pipExists) + console.log(' - gitExists:', criticalFiles.gitExists, typeof criticalFiles.gitExists) + console.log(' - mainPyExists:', criticalFiles.mainPyExists, typeof criticalFiles.mainPyExists) + + const result = { + pythonExists: criticalFiles.pythonExists, + pipExists: criticalFiles.pipExists, + gitExists: criticalFiles.gitExists, + mainPyExists: criticalFiles.mainPyExists + } + + console.log('🔍 最终返回结果:', result) + return result + } catch (error) { + logger.error('检查关键文件失败', error) + console.error('❌ 检查关键文件失败,使用配置文件状态:', error) + + // 如果检查失败,从配置文件读取状态 + try { + const config = await getConfig() + console.log('📄 使用配置文件中的状态:', { + pythonInstalled: config.pythonInstalled, + pipInstalled: config.pipInstalled, + gitInstalled: config.gitInstalled, + backendExists: config.backendExists + }) + return { + pythonExists: config.pythonInstalled || false, + pipExists: config.pipInstalled || false, + gitExists: config.gitInstalled || false, + mainPyExists: config.backendExists || false + } + } catch (configError) { + console.error('❌ 读取配置文件也失败了:', configError) + return { + pythonExists: false, + pipExists: false, + gitExists: false, + mainPyExists: false + } + } + } +} + // 检查环境状态 async function checkEnvironment() { try { logger.info('开始检查环境状态') - const status = await window.electronAPI.checkEnvironment() - logger.info('环境检查结果', status) - console.log('环境检查结果:', status) + // 只检查关键exe文件是否存在 + const criticalFiles = await checkCriticalFiles() - pythonInstalled.value = status.pythonExists - gitInstalled.value = status.gitExists - backendExists.value = status.backendExists - dependenciesInstalled.value = status.dependenciesInstalled + console.log('关键文件检查结果:', criticalFiles) - // 检查配置文件中的状态 + // 直接根据exe文件存在性设置状态 + pythonInstalled.value = criticalFiles.pythonExists + pipInstalled.value = criticalFiles.pipExists + gitInstalled.value = criticalFiles.gitExists + backendExists.value = criticalFiles.mainPyExists + + // 检查配置文件中的依赖安装状态 const config = await getConfig() - pipInstalled.value = config.pipInstalled || false + dependenciesInstalled.value = config.dependenciesInstalled || false - // 更新配置文件中的状态,确保与实际环境一致 - const needsUpdate = - config.pythonInstalled !== status.pythonExists || - config.gitInstalled !== status.gitExists || - config.backendExists !== status.backendExists || - config.dependenciesInstalled !== status.dependenciesInstalled - - if (needsUpdate) { - console.log('更新配置文件中的环境状态') - await saveConfig({ - pythonInstalled: status.pythonExists, - gitInstalled: status.gitExists, - backendExists: status.backendExists, - dependenciesInstalled: status.dependenciesInstalled - }) - } + console.log('📊 最终状态设置:') + console.log(' - pythonInstalled:', pythonInstalled.value) + console.log(' - pipInstalled:', pipInstalled.value) + console.log(' - gitInstalled:', gitInstalled.value) + console.log(' - backendExists:', backendExists.value) + console.log(' - dependenciesInstalled:', dependenciesInstalled.value) // 检查是否第一次启动 const isFirst = config.isFirstLaunch console.log('是否第一次启动:', isFirst) + // 检查所有关键exe文件是否都存在 + const allExeFilesExist = criticalFiles.pythonExists && + criticalFiles.pipExists && + criticalFiles.gitExists && + criticalFiles.mainPyExists + + console.log('关键exe文件状态检查:') + console.log('- python.exe存在:', criticalFiles.pythonExists) + console.log('- pip.exe存在:', criticalFiles.pipExists) + console.log('- git.exe存在:', criticalFiles.gitExists) + console.log('- main.py存在:', criticalFiles.mainPyExists) + console.log('- 所有关键文件存在:', allExeFilesExist) + // 检查是否应该进入自动模式 console.log('自动模式判断条件:') console.log('- 不是第一次启动:', !isFirst) console.log('- 配置显示已初始化:', config.init) - console.log('- 环境检查结果:', status.isInitialized) + console.log('- 所有关键文件存在:', allExeFilesExist) - // 如果配置显示已初始化且不是第一次启动,进入自动模式 - // 不再依赖环境检查结果,因为配置文件更准确 - if (!isFirst && config.init) { - logger.info('非首次启动且配置显示已初始化,进入自动模式') + // 只有在非首次启动、配置显示已初始化、且所有关键exe文件都存在时才进入自动模式 + if (!isFirst && config.init && allExeFilesExist) { + logger.info('非首次启动、配置显示已初始化且所有关键文件存在,进入自动模式') console.log('进入自动模式,开始自动启动流程') autoMode.value = true } else { - logger.info('首次启动或配置显示未初始化,进入手动模式') + logger.info('需要进入手动模式进行配置') console.log('进入手动模式') - console.log('原因: isFirst =', isFirst, ', config.init =', config.init) + console.log('原因: isFirst =', isFirst, ', config.init =', config.init, ', allExeFilesExist =', allExeFilesExist) + + // 如果关键文件缺失,重置初始化状态 + if (!allExeFilesExist && config.init) { + console.log('检测到关键exe文件缺失,重置初始化状态') + await saveConfig({ init: false }) + } } } catch (error) { const errorMsg = `环境检查失败: ${error instanceof Error ? error.message : String(error)}` logger.error('环境检查失败', error) console.error('环境检查失败:', error) + + // 检查失败时强制进入手动模式 + autoMode.value = false } } diff --git a/frontend/src/vite-env.d.ts b/frontend/src/vite-env.d.ts index 70b004c..8d5878d 100644 --- a/frontend/src/vite-env.d.ts +++ b/frontend/src/vite-env.d.ts @@ -2,10 +2,62 @@ declare global { interface Window { - electronAPI?: { + electronAPI: { + // 开发工具 openDevTools: () => Promise selectFolder: () => Promise selectFile: (filters?: Array<{ name: string; extensions: string[] }>) => Promise + + // 管理员权限检查 + checkAdmin: () => Promise + + // 环境检查 + checkEnvironment: () => Promise<{ + pythonExists: boolean + gitExists: boolean + backendExists: boolean + dependenciesInstalled: boolean + isInitialized: boolean + }> + + // 关键文件检查 + checkCriticalFiles: () => Promise<{ + pythonExists: boolean + pipExists: boolean + gitExists: boolean + mainPyExists: boolean + }> + + // Python相关 + downloadPython: (mirror: string) => Promise<{ success: boolean; error?: string }> + deletePython: () => Promise<{ success: boolean; error?: string }> + + // pip相关 + installPip: () => Promise<{ success: boolean; error?: string }> + deletePip: () => Promise<{ success: boolean; error?: string }> + + // Git相关 + downloadGit: () => Promise<{ success: boolean; error?: string }> + deleteGit: () => Promise<{ success: boolean; error?: string }> + checkGitUpdate: () => Promise<{ hasUpdate: boolean; error?: string }> + + // 后端代码相关 + cloneBackend: (gitUrl: string) => Promise<{ success: boolean; error?: string }> + updateBackend: (gitUrl: string) => Promise<{ success: boolean; error?: string }> + + // 依赖安装 + installDependencies: (mirror: string) => Promise<{ success: boolean; error?: string }> + + // 后端服务 + startBackend: () => Promise<{ success: boolean; error?: string }> + + // 下载进度监听 + onDownloadProgress: (callback: (progress: { + progress: number + status: string + message: string + }) => void) => void + removeDownloadProgressListener: () => void } } }