refactor: 重构环境检查逻辑,添加环境不完整提示页面

This commit is contained in:
2025-09-14 02:04:31 +08:00
parent a15b2bd8ce
commit 4d8d71f294
6 changed files with 296 additions and 34 deletions

View File

@@ -516,6 +516,47 @@ ipcMain.handle('check-environment', async () => {
return checkEnvironment(appRoot)
})
// 关键文件检查 - 每次都重新检查exe文件是否存在
ipcMain.handle('check-critical-files', async () => {
try {
const appRoot = getAppRoot()
// 检查Python可执行文件
const pythonPath = path.join(appRoot, 'environment', 'python', 'python.exe')
const pythonExists = fs.existsSync(pythonPath)
// 检查pip通常与Python一起安装
const pipPath = path.join(appRoot, 'environment', 'python', 'Scripts', 'pip.exe')
const pipExists = fs.existsSync(pipPath)
// 检查Git可执行文件
const gitPath = path.join(appRoot, 'environment', 'git', 'bin', 'git.exe')
const gitExists = fs.existsSync(gitPath)
// 检查后端主文件
const mainPyPath = path.join(appRoot, 'main.py')
const mainPyExists = fs.existsSync(mainPyPath)
const result = {
pythonExists,
pipExists,
gitExists,
mainPyExists
}
log.info('关键文件检查结果:', result)
return result
} catch (error) {
log.error('检查关键文件失败:', error)
return {
pythonExists: false,
pipExists: false,
gitExists: false,
mainPyExists: false
}
}
})
// Python相关
ipcMain.handle('download-python', async (_event, mirror = 'tsinghua') => {
const appRoot = getAppRoot()
@@ -547,6 +588,17 @@ ipcMain.handle('download-git', async () => {
return downloadGit(appRoot)
})
ipcMain.handle('check-git-update', async () => {
try {
// 这里可以实现检查Git仓库更新的逻辑
// 暂时返回false表示没有更新
return { hasUpdate: false }
} catch (error) {
log.error('检查Git更新失败:', error)
return { hasUpdate: false, error: error instanceof Error ? error.message : String(error) }
}
})
ipcMain.handle(
'clone-backend',
async (_event, repoUrl = 'https://github.com/AUTO-MAS-Project/AUTO-MAS.git') => {

View File

@@ -19,9 +19,11 @@ contextBridge.exposeInMainWorld('electronAPI', {
// 初始化相关API
checkEnvironment: () => ipcRenderer.invoke('check-environment'),
checkCriticalFiles: () => ipcRenderer.invoke('check-critical-files'),
downloadPython: (mirror?: string) => ipcRenderer.invoke('download-python', mirror),
installPip: () => ipcRenderer.invoke('install-pip'),
downloadGit: () => ipcRenderer.invoke('download-git'),
checkGitUpdate: () => ipcRenderer.invoke('check-git-update'),
installDependencies: (mirror?: string) => ipcRenderer.invoke('install-dependencies', mirror),
cloneBackend: (repoUrl?: string) => ipcRenderer.invoke('clone-backend', repoUrl),
updateBackend: (repoUrl?: string) => ipcRenderer.invoke('update-backend', repoUrl),

View File

@@ -32,7 +32,7 @@
</div>
</div>
<!-- 弹窗 -->
<!-- 强行进入应用弹窗 -->
<a-modal
v-model:open="forceEnterVisible"
title="警告"
@@ -47,6 +47,8 @@
show-icon
/>
</a-modal>
</template>
<script setup lang="ts">
@@ -83,11 +85,6 @@ const aborted = ref(false)
// 状态:控制弹窗显隐
const forceEnterVisible = ref(false)
// 镜像源重试相关状态
const currentMirrorIndex = ref(0)
const availableMirrors = ref<any[]>([])
const maxRetries = ref(3)
// 点击“强行进入应用”按钮,显示弹窗
function handleForceEnter() {
forceEnterVisible.value = true
@@ -197,11 +194,6 @@ async function checkGitUpdate(): Promise<boolean> {
}
}
// 根据镜像源key获取对应的URL
function getGitMirrorUrl(mirrorKey: string): string {
return getMirrorUrl('git', mirrorKey)
}
// 尝试更新后端代码,支持镜像源重试
async function tryUpdateBackendWithRetry(config: any): Promise<boolean> {
// 获取所有Git镜像源

View File

@@ -0,0 +1,185 @@
<template>
<div class="environment-incomplete">
<div class="header">
<img src="/src/assets/AUTO-MAS.ico" alt="logo" class="logo" />
<a-typography-title :level="1">AUTO-MAS</a-typography-title>
</div>
<div class="content">
<a-result
status="warning"
title="环境不完整"
sub-title="检测到运行环境中缺少必要的组件需要重新配置环境"
>
<template #extra>
<div class="missing-components">
<a-typography-title :level="4">缺失的组件</a-typography-title>
<a-list :data-source="missingComponents" size="small">
<template #renderItem="{ item }">
<a-list-item>
<a-typography-text type="danger">
<ExclamationCircleOutlined /> {{ item }}
</a-typography-text>
</a-list-item>
</template>
</a-list>
</div>
<div class="description">
<a-typography-paragraph>
这种情况通常由以下原因导致
</a-typography-paragraph>
<ul>
<li>杀毒软件误删了相关文件</li>
<li>手动删除了环境文件</li>
<li>系统更新或清理工具清理了相关文件</li>
</ul>
<a-typography-paragraph>
建议重新配置环境以确保程序正常运行
</a-typography-paragraph>
</div>
<div class="actions">
<a-button
type="primary"
size="large"
@click="handleReconfigure"
>
重新配置环境
</a-button>
<a-button
size="large"
@click="handleForceEnter"
style="margin-left: 16px"
>
强行进入应用
</a-button>
</div>
</template>
</a-result>
</div>
</div>
</template>
<script setup lang="ts">
import { ExclamationCircleOutlined } from '@ant-design/icons-vue'
import router from '@/router'
// Props
interface Props {
missingComponents: string[]
onSwitchToManual: () => void
}
const props = defineProps<Props>()
// 重新配置环境
function handleReconfigure() {
props.onSwitchToManual()
}
// 强行进入应用
function handleForceEnter() {
router.push('/home')
}
</script>
<style scoped>
.environment-incomplete {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: calc(100vh - 120px);
padding: 20px;
box-sizing: border-box;
}
.header {
text-align: center;
margin-bottom: 40px;
display: flex;
align-items: center;
justify-content: center;
gap: 16px;
}
.header h1 {
font-size: 38px;
font-weight: 600;
color: var(--ant-color-text);
margin-bottom: 8px;
}
.logo {
width: 100px;
height: 100px;
}
.content {
width: 100%;
max-width: 600px;
}
.missing-components {
margin-bottom: 24px;
text-align: left;
}
.missing-components h4 {
margin-bottom: 12px;
}
.description {
text-align: left;
margin-bottom: 24px;
}
.description ul {
margin: 12px 0;
padding-left: 20px;
}
.description li {
margin: 4px 0;
color: var(--ant-color-text-secondary);
}
.actions {
text-align: center;
}
/* 响应式优化 */
@media (max-height: 700px) {
.environment-incomplete {
min-height: auto;
padding: 10px;
}
.header {
margin-bottom: 20px;
}
.header h1 {
font-size: 32px;
}
.logo {
width: 80px;
height: 80px;
}
}
@media (max-width: 600px) {
.actions {
display: flex;
flex-direction: column;
gap: 12px;
align-items: center;
}
.actions .ant-btn {
width: 200px;
}
}
</style>

View File

@@ -48,7 +48,7 @@
<!-- </div>-->
</div>
<a-steps :current="currentStep" :status="stepStatus" class="init-steps">
<a-steps :current="displayCurrentStep" :status="stepStatus" class="init-steps">
<a-step title="设置主题" />
<a-step title="配置环境" />
<a-step title="Git 工具" />
@@ -136,7 +136,7 @@
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
import { ref, watch, computed } from 'vue'
import { notification } from 'ant-design-vue'
import { saveConfig } from '@/utils/config'
import { useUpdateChecker } from '@/composables/useUpdateChecker'
@@ -177,6 +177,11 @@ const stepStatus = ref<'wait' | 'process' | 'finish' | 'error'>('process')
const errorMessage = ref('')
const isProcessing = ref(false)
// 显示的当前步骤就是实际步骤
const displayCurrentStep = computed(() => {
return currentStep.value
})
// 全局进度条状态
const globalProgress = ref(0)
const globalProgressStatus = ref<'normal' | 'exception' | 'success'>('normal')
@@ -239,9 +244,8 @@ async function handleNextStep() {
break
case 4: // 依赖安装
console.log('执行依赖安装')
if (!props.dependenciesInstalled) {
await installDependencies()
}
// 总是执行依赖安装,确保环境完整
await installDependencies()
break
case 5: // 启动服务
console.log('执行启动服务')
@@ -274,7 +278,7 @@ function getNextButtonText() {
case 3:
return props.backendExists ? '更新代码' : '获取代码'
case 4:
return '安装依赖'
return props.dependenciesInstalled ? '重新安装依赖' : '安装依赖'
case 5:
return '启动服务'
default:

View File

@@ -3,9 +3,16 @@
<!-- 管理员权限检查 -->
<AdminCheck v-if="!isAdmin" />
<!-- 环境不完整页面 -->
<EnvironmentIncomplete
v-if="showEnvironmentIncomplete"
:missing-components="missingComponents"
:on-switch-to-manual="switchToManualMode"
/>
<!-- 自动初始化模式 -->
<AutoMode
v-if="autoMode"
v-else-if="autoMode"
:on-switch-to-manual="switchToManualMode"
:on-auto-complete="enterApp"
/>
@@ -33,6 +40,7 @@ import { getConfig, saveConfig, setInitialized } from '@/utils/config'
import AdminCheck from '@/components/initialization/AdminCheck.vue'
import AutoMode from '@/components/initialization/AutoMode.vue'
import ManualMode from '@/components/initialization/ManualMode.vue'
import EnvironmentIncomplete from '@/components/initialization/EnvironmentIncomplete.vue'
import type { DownloadProgress } from '@/types/initialization'
import { mirrorManager } from '@/utils/mirrorManager'
@@ -41,6 +49,8 @@ const router = useRouter()
// 基础状态
const isAdmin = ref(true)
const autoMode = ref(false)
const showEnvironmentIncomplete = ref(false)
const missingComponents = ref<string[]>([])
// 安装状态
const pythonInstalled = ref(false)
@@ -64,7 +74,9 @@ function skipToHome() {
}
function switchToManualMode() {
showEnvironmentIncomplete.value = false
autoMode.value = false
console.log('切换到手动模式')
}
// 进入应用
@@ -143,8 +155,7 @@ async function checkCriticalFiles() {
// 检查环境状态
async function checkEnvironment() {
try {
// 只检查关键exe文件是否存在
// 每次都重新检查关键exe文件是否存在不依赖持久化配置
const criticalFiles = await checkCriticalFiles()
console.log('关键文件检查结果:', criticalFiles)
@@ -154,7 +165,7 @@ async function checkEnvironment() {
gitInstalled.value = criticalFiles.gitExists
backendExists.value = criticalFiles.mainPyExists
// 检查配置文件中的依赖安装状态
// 依赖安装状态从配置文件读取,但在手动模式中会重新安装
const config = await getConfig()
dependenciesInstalled.value = config.dependenciesInstalled || false
@@ -180,27 +191,43 @@ async function checkEnvironment() {
console.log('- main.py存在:', criticalFiles.mainPyExists)
console.log('- 所有关键文件存在:', allExeFilesExist)
// 检查是否应该进入自动模式
// 新的自动模式判断逻辑只要所有关键exe文件都存在且不是第一次启动就进入自动模式
console.log('自动模式判断条件:')
console.log('- 不是第一次启动:', !isFirst)
console.log('- 配置显示已初始化:', config.init)
console.log('- 所有关键文件存在:', allExeFilesExist)
// 只有在非首次启动、配置显示已初始化、且所有关键exe文件都存在时才进入自动模式
if (!isFirst && config.init && allExeFilesExist) {
// 只要不是第一次启动且所有关键exe文件都存在进入自动模式
if (!isFirst && allExeFilesExist) {
console.log('进入自动模式,开始自动启动流程')
autoMode.value = true
} else {
console.log('进入手动模式')
console.log(
'原因: isFirst =',
isFirst,
', config.init =',
config.init,
', allExeFilesExist =',
allExeFilesExist
)
if (isFirst) {
console.log('原因: 第一次启动')
// 第一次启动直接进入手动模式
autoMode.value = false
showEnvironmentIncomplete.value = false
} else if (!allExeFilesExist) {
console.log('原因: 关键exe文件缺失')
console.log(' - python.exe缺失:', !criticalFiles.pythonExists)
console.log(' - git.exe缺失:', !criticalFiles.gitExists)
console.log(' - main.py缺失:', !criticalFiles.mainPyExists)
// 显示环境不完整页面
const missing = []
if (!criticalFiles.pythonExists) missing.push('Python 环境')
if (!criticalFiles.gitExists) missing.push('Git 工具')
if (!criticalFiles.mainPyExists) missing.push('后端代码')
missingComponents.value = missing
showEnvironmentIncomplete.value = true
autoMode.value = false
} else {
// 其他情况直接进入手动模式
autoMode.value = false
showEnvironmentIncomplete.value = false
}
// 如果关键文件缺失,重置初始化状态
if (!allExeFilesExist && config.init) {
console.log('检测到关键exe文件缺失重置初始化状态')