From a738f102a606f2d7835c1dc1d924584e224dda08 Mon Sep 17 00:00:00 2001 From: AoXuan Date: Fri, 15 Aug 2025 14:21:16 +0800 Subject: [PATCH] =?UTF-8?q?style:=E6=A0=BC=E5=BC=8F=E5=8C=96=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/electron/main.ts | 54 ++- frontend/electron/preload.ts | 70 ++-- frontend/electron/services/downloadService.ts | 1 - .../electron/services/environmentService.ts | 13 +- frontend/electron/services/gitService.ts | 26 +- frontend/electron/services/pythonService.ts | 168 ++++---- frontend/src/components/AppLayout.vue | 27 +- frontend/src/components/LogViewer.vue | 78 ++-- frontend/src/components/ScriptTable.vue | 7 +- .../components/initialization/AdminCheck.vue | 6 +- .../components/initialization/AutoMode.vue | 10 +- .../components/initialization/BackendStep.vue | 31 +- .../initialization/DependenciesStep.vue | 30 +- .../src/components/initialization/GitStep.vue | 26 +- .../components/initialization/ManualMode.vue | 120 +++--- .../src/components/initialization/PipStep.vue | 28 +- .../components/initialization/PythonStep.vue | 365 +++++++++--------- .../components/initialization/ServiceStep.vue | 2 +- .../components/initialization/ThemeStep.vue | 18 +- .../src/components/queue/QueueItemManager.vue | 66 ++-- frontend/src/composables/usePlanApi.ts | 4 +- frontend/src/composables/useScriptApi.ts | 24 +- frontend/src/composables/useSettingsApi.ts | 8 +- frontend/src/composables/useTheme.ts | 36 +- frontend/src/composables/useUserApi.ts | 20 +- frontend/src/config/mirrors.ts | 48 +-- frontend/src/router/index.ts | 3 - frontend/src/style.css | 114 +++--- frontend/src/types/initialization.ts | 2 +- frontend/src/types/settings.ts | 3 +- frontend/src/utils/config.ts | 13 +- frontend/src/utils/logger.ts | 14 +- frontend/src/utils/mirrorManager.ts | 33 +- frontend/src/views/Home.vue | 2 +- frontend/src/views/Initialization.vue | 82 ++-- frontend/src/views/Logs.vue | 4 +- frontend/src/views/Queue.vue | 109 +++--- frontend/src/views/Scheduler.vue | 51 ++- frontend/src/views/Settings.vue | 344 +++++++++++------ frontend/vite.config.ts | 6 +- 40 files changed, 1144 insertions(+), 922 deletions(-) diff --git a/frontend/electron/main.ts b/frontend/electron/main.ts index 51182f1..9b1e8c1 100644 --- a/frontend/electron/main.ts +++ b/frontend/electron/main.ts @@ -4,7 +4,13 @@ import * as fs from 'fs' import { spawn } from 'child_process' import { getAppRoot, checkEnvironment } from './services/environmentService' import { setMainWindow as setDownloadMainWindow } from './services/downloadService' -import { setMainWindow as setPythonMainWindow, downloadPython, installPipPackage, installDependencies, startBackend } from './services/pythonService' +import { + setMainWindow as setPythonMainWindow, + downloadPython, + installPipPackage, + installDependencies, + startBackend, +} from './services/pythonService' import { setMainWindow as setGitMainWindow, downloadGit, cloneBackend } from './services/gitService' // 检查是否以管理员权限运行 @@ -32,16 +38,20 @@ function restartAsAdmin(): void { if (process.platform === 'win32') { const exePath = process.execPath const args = process.argv.slice(1) - + // 使用PowerShell以管理员权限启动 - spawn('powershell', [ - '-Command', - `Start-Process -FilePath "${exePath}" -ArgumentList "${args.join(' ')}" -Verb RunAs` - ], { - detached: true, - stdio: 'ignore' - }) - + spawn( + 'powershell', + [ + '-Command', + `Start-Process -FilePath "${exePath}" -ArgumentList "${args.join(' ')}" -Verb RunAs`, + ], + { + detached: true, + stdio: 'ignore', + } + ) + app.quit() } } @@ -144,15 +154,21 @@ ipcMain.handle('download-git', async () => { return downloadGit(appRoot) }) -ipcMain.handle('clone-backend', async (event, repoUrl = 'https://github.com/DLmaster361/AUTO_MAA.git') => { - const appRoot = getAppRoot() - return cloneBackend(appRoot, repoUrl) -}) +ipcMain.handle( + 'clone-backend', + async (event, repoUrl = 'https://github.com/DLmaster361/AUTO_MAA.git') => { + const appRoot = getAppRoot() + return cloneBackend(appRoot, repoUrl) + } +) -ipcMain.handle('update-backend', async (event, repoUrl = 'https://github.com/DLmaster361/AUTO_MAA.git') => { - const appRoot = getAppRoot() - return cloneBackend(appRoot, repoUrl) // 使用相同的逻辑,会自动判断是pull还是clone -}) +ipcMain.handle( + 'update-backend', + async (event, repoUrl = 'https://github.com/DLmaster361/AUTO_MAA.git') => { + const appRoot = getAppRoot() + return cloneBackend(appRoot, repoUrl) // 使用相同的逻辑,会自动判断是pull还是clone + } +) // 配置文件操作 ipcMain.handle('save-config', async (event, config) => { @@ -271,4 +287,4 @@ app.on('window-all-closed', () => { app.on('activate', () => { if (mainWindow === null) createWindow() -}) \ No newline at end of file +}) diff --git a/frontend/electron/preload.ts b/frontend/electron/preload.ts index 3a18edf..3ccc9d1 100644 --- a/frontend/electron/preload.ts +++ b/frontend/electron/preload.ts @@ -1,43 +1,43 @@ import { contextBridge, ipcRenderer } from 'electron' window.addEventListener('DOMContentLoaded', () => { - console.log('Preload loaded') + console.log('Preload loaded') }) // 暴露安全的 API 给渲染进程 contextBridge.exposeInMainWorld('electronAPI', { - openDevTools: () => ipcRenderer.invoke('open-dev-tools'), - selectFolder: () => ipcRenderer.invoke('select-folder'), - selectFile: (filters?: any[]) => ipcRenderer.invoke('select-file', filters), - - // 初始化相关API - checkEnvironment: () => ipcRenderer.invoke('check-environment'), - downloadPython: (mirror?: string) => ipcRenderer.invoke('download-python', mirror), - installPip: () => ipcRenderer.invoke('install-pip'), - downloadGit: () => ipcRenderer.invoke('download-git'), - installDependencies: (mirror?: string) => ipcRenderer.invoke('install-dependencies', mirror), - cloneBackend: (repoUrl?: string) => ipcRenderer.invoke('clone-backend', repoUrl), - updateBackend: (repoUrl?: string) => ipcRenderer.invoke('update-backend', repoUrl), - startBackend: () => ipcRenderer.invoke('start-backend'), - - // 管理员权限相关 - checkAdmin: () => ipcRenderer.invoke('check-admin'), - restartAsAdmin: () => ipcRenderer.invoke('restart-as-admin'), - - // 配置文件操作 - saveConfig: (config: any) => ipcRenderer.invoke('save-config', config), - loadConfig: () => ipcRenderer.invoke('load-config'), - resetConfig: () => ipcRenderer.invoke('reset-config'), - - // 日志文件操作 - saveLogsToFile: (logs: string) => ipcRenderer.invoke('save-logs-to-file', logs), - loadLogsFromFile: () => ipcRenderer.invoke('load-logs-from-file'), - - // 监听下载进度 - onDownloadProgress: (callback: (progress: any) => void) => { - ipcRenderer.on('download-progress', (_, progress) => callback(progress)) - }, - removeDownloadProgressListener: () => { - ipcRenderer.removeAllListeners('download-progress') - } + openDevTools: () => ipcRenderer.invoke('open-dev-tools'), + selectFolder: () => ipcRenderer.invoke('select-folder'), + selectFile: (filters?: any[]) => ipcRenderer.invoke('select-file', filters), + + // 初始化相关API + checkEnvironment: () => ipcRenderer.invoke('check-environment'), + downloadPython: (mirror?: string) => ipcRenderer.invoke('download-python', mirror), + installPip: () => ipcRenderer.invoke('install-pip'), + downloadGit: () => ipcRenderer.invoke('download-git'), + installDependencies: (mirror?: string) => ipcRenderer.invoke('install-dependencies', mirror), + cloneBackend: (repoUrl?: string) => ipcRenderer.invoke('clone-backend', repoUrl), + updateBackend: (repoUrl?: string) => ipcRenderer.invoke('update-backend', repoUrl), + startBackend: () => ipcRenderer.invoke('start-backend'), + + // 管理员权限相关 + checkAdmin: () => ipcRenderer.invoke('check-admin'), + restartAsAdmin: () => ipcRenderer.invoke('restart-as-admin'), + + // 配置文件操作 + saveConfig: (config: any) => ipcRenderer.invoke('save-config', config), + loadConfig: () => ipcRenderer.invoke('load-config'), + resetConfig: () => ipcRenderer.invoke('reset-config'), + + // 日志文件操作 + saveLogsToFile: (logs: string) => ipcRenderer.invoke('save-logs-to-file', logs), + loadLogsFromFile: () => ipcRenderer.invoke('load-logs-from-file'), + + // 监听下载进度 + onDownloadProgress: (callback: (progress: any) => void) => { + ipcRenderer.on('download-progress', (_, progress) => callback(progress)) + }, + removeDownloadProgressListener: () => { + ipcRenderer.removeAllListeners('download-progress') + }, }) diff --git a/frontend/electron/services/downloadService.ts b/frontend/electron/services/downloadService.ts index c40759d..61561be 100644 --- a/frontend/electron/services/downloadService.ts +++ b/frontend/electron/services/downloadService.ts @@ -18,7 +18,6 @@ export function downloadFile(url: string, outputPath: string): Promise { // 创建HTTP客户端,兼容https和http const client = url.startsWith('https') ? https : http - client .get(url, response => { const totalSize = parseInt(response.headers['content-length'] || '0', 10) diff --git a/frontend/electron/services/environmentService.ts b/frontend/electron/services/environmentService.ts index a1f3600..b8f3d5a 100644 --- a/frontend/electron/services/environmentService.ts +++ b/frontend/electron/services/environmentService.ts @@ -4,9 +4,7 @@ import { app } from 'electron' // 获取应用根目录 export function getAppRoot(): string { - return process.env.NODE_ENV === 'development' - ? process.cwd() - : path.dirname(app.getPath('exe')) + return process.env.NODE_ENV === 'development' ? process.cwd() : path.dirname(app.getPath('exe')) } // 检查环境 @@ -20,16 +18,17 @@ export function checkEnvironment(appRoot: string) { const pythonExists = fs.existsSync(pythonPath) const gitExists = fs.existsSync(gitPath) const backendExists = fs.existsSync(backendPath) - + // 检查依赖是否已安装(简单检查是否存在site-packages目录) const sitePackagesPath = path.join(pythonPath, 'Lib', 'site-packages') - const dependenciesInstalled = fs.existsSync(sitePackagesPath) && fs.readdirSync(sitePackagesPath).length > 10 + const dependenciesInstalled = + fs.existsSync(sitePackagesPath) && fs.readdirSync(sitePackagesPath).length > 10 return { pythonExists, gitExists, backendExists, dependenciesInstalled, - isInitialized: pythonExists && gitExists && backendExists && dependenciesInstalled + isInitialized: pythonExists && gitExists && backendExists && dependenciesInstalled, } -} \ No newline at end of file +} diff --git a/frontend/electron/services/gitService.ts b/frontend/electron/services/gitService.ts index 03082fd..84c8a39 100644 --- a/frontend/electron/services/gitService.ts +++ b/frontend/electron/services/gitService.ts @@ -31,7 +31,6 @@ function copyDirSync(src: string, dest: string) { } } - // 获取Git环境变量配置 function getGitEnvironment(appRoot: string) { const gitDir = path.join(appRoot, 'environment', 'git') @@ -249,11 +248,26 @@ export async function cloneBackend( }) } await new Promise((resolve, reject) => { - const proc = spawn(gitPath, ['clone', '--progress', '--verbose','--single-branch','--depth','1','--branch', 'feature/refactor-backend', repoUrl, tmpDir], { - stdio: 'pipe', - env: gitEnv, - cwd: appRoot, - }) + const proc = spawn( + gitPath, + [ + 'clone', + '--progress', + '--verbose', + '--single-branch', + '--depth', + '1', + '--branch', + 'feature/refactor-backend', + repoUrl, + tmpDir, + ], + { + stdio: 'pipe', + env: gitEnv, + cwd: appRoot, + } + ) proc.stdout?.on('data', d => console.log('git clone:', d.toString())) proc.stderr?.on('data', d => console.log('git clone err:', d.toString())) proc.on('close', code => diff --git a/frontend/electron/services/pythonService.ts b/frontend/electron/services/pythonService.ts index 252fc89..a8be553 100644 --- a/frontend/electron/services/pythonService.ts +++ b/frontend/electron/services/pythonService.ts @@ -16,8 +16,9 @@ const pythonMirrorUrls = { official: 'https://www.python.org/ftp/python/3.12.0/python-3.12.0-embed-amd64.zip', tsinghua: 'https://mirrors.tuna.tsinghua.edu.cn/python/3.12.0/python-3.12.0-embed-amd64.zip', ustc: 'https://mirrors.ustc.edu.cn/python/3.12.0/python-3.12.0-embed-amd64.zip', - huawei: 'https://mirrors.huaweicloud.com/repository/toolkit/python/3.12.0/python-3.12.0-embed-amd64.zip', - aliyun: 'https://mirrors.aliyun.com/python-release/windows/python-3.12.0-embed-amd64.zip' + huawei: + 'https://mirrors.huaweicloud.com/repository/toolkit/python/3.12.0/python-3.12.0-embed-amd64.zip', + aliyun: 'https://mirrors.aliyun.com/python-release/windows/python-3.12.0-embed-amd64.zip', } // 检查pip是否已安装 @@ -25,20 +26,20 @@ function isPipInstalled(pythonPath: string): boolean { const scriptsPath = path.join(pythonPath, 'Scripts') const pipExePath = path.join(scriptsPath, 'pip.exe') const pip3ExePath = path.join(scriptsPath, 'pip3.exe') - + console.log(`检查pip安装状态:`) console.log(`Scripts目录: ${scriptsPath}`) console.log(`pip.exe路径: ${pipExePath}`) console.log(`pip3.exe路径: ${pip3ExePath}`) - + const scriptsExists = fs.existsSync(scriptsPath) const pipExists = fs.existsSync(pipExePath) const pip3Exists = fs.existsSync(pip3ExePath) - + console.log(`Scripts目录存在: ${scriptsExists}`) console.log(`pip.exe存在: ${pipExists}`) console.log(`pip3.exe存在: ${pip3Exists}`) - + return scriptsExists && (pipExists || pip3Exists) } @@ -62,7 +63,7 @@ async function installPip(pythonPath: string, appRoot: string): Promise { } console.log('pip未安装,开始安装...') - + const getPipPath = path.join(pythonPath, 'get-pip.py') const getPipUrl = 'http://221.236.27.82:10197/d/AUTO_MAA/get-pip.py' @@ -75,12 +76,13 @@ async function installPip(pythonPath: string, appRoot: string): Promise { try { await downloadFile(getPipUrl, getPipPath) console.log('get-pip.py下载完成') - + // 检查下载的文件大小 const stats = fs.statSync(getPipPath) console.log(`get-pip.py文件大小: ${stats.size} bytes`) - - if (stats.size < 10000) { // 如果文件小于10KB,可能是无效文件 + + if (stats.size < 10000) { + // 如果文件小于10KB,可能是无效文件 throw new Error(`get-pip.py文件大小异常: ${stats.size} bytes,可能下载失败`) } } catch (error) { @@ -94,20 +96,20 @@ async function installPip(pythonPath: string, appRoot: string): Promise { const process = spawn(pythonExe, [getPipPath], { cwd: pythonPath, - stdio: 'pipe' + stdio: 'pipe', }) - process.stdout?.on('data', (data) => { + process.stdout?.on('data', data => { const output = data.toString() console.log('pip安装输出:', output) }) - process.stderr?.on('data', (data) => { + process.stderr?.on('data', data => { const errorOutput = data.toString() console.log('pip安装错误输出:', errorOutput) }) - process.on('close', (code) => { + process.on('close', code => { console.log(`pip安装完成,退出码: ${code}`) if (code === 0) { console.log('pip安装成功') @@ -117,7 +119,7 @@ async function installPip(pythonPath: string, appRoot: string): Promise { } }) - process.on('error', (error) => { + process.on('error', error => { console.error('pip安装进程错误:', error) reject(error) }) @@ -128,20 +130,20 @@ async function installPip(pythonPath: string, appRoot: string): Promise { await new Promise((resolve, reject) => { const verifyProcess = spawn(pythonExe, ['-m', 'pip', '--version'], { cwd: pythonPath, - stdio: 'pipe' + stdio: 'pipe', }) - verifyProcess.stdout?.on('data', (data) => { + verifyProcess.stdout?.on('data', data => { const output = data.toString() console.log('pip版本信息:', output) }) - verifyProcess.stderr?.on('data', (data) => { + verifyProcess.stderr?.on('data', data => { const errorOutput = data.toString() console.log('pip版本检查错误:', errorOutput) }) - verifyProcess.on('close', (code) => { + verifyProcess.on('close', code => { if (code === 0) { console.log('pip验证成功') resolve() @@ -150,7 +152,7 @@ async function installPip(pythonPath: string, appRoot: string): Promise { } }) - verifyProcess.on('error', (error) => { + verifyProcess.on('error', error => { console.error('pip验证进程错误:', error) reject(error) }) @@ -171,11 +173,14 @@ async function installPip(pythonPath: string, appRoot: string): Promise { } // 下载Python -export async function downloadPython(appRoot: string, mirror = 'ustc'): Promise<{ success: boolean; error?: string }> { +export async function downloadPython( + appRoot: string, + mirror = 'ustc' +): Promise<{ success: boolean; error?: string }> { try { const environmentPath = path.join(appRoot, 'environment') const pythonPath = path.join(environmentPath, 'python') - + // 确保environment目录存在 if (!fs.existsSync(environmentPath)) { fs.mkdirSync(environmentPath, { recursive: true }) @@ -186,24 +191,30 @@ export async function downloadPython(appRoot: string, mirror = 'ustc'): Promise< type: 'python', progress: 0, status: 'downloading', - message: '开始下载Python...' + message: '开始下载Python...', }) } // 根据选择的镜像源获取下载链接 - const pythonUrl = pythonMirrorUrls[mirror as keyof typeof pythonMirrorUrls] || pythonMirrorUrls.ustc + const pythonUrl = + pythonMirrorUrls[mirror as keyof typeof pythonMirrorUrls] || pythonMirrorUrls.ustc const zipPath = path.join(environmentPath, 'python.zip') await downloadFile(pythonUrl, zipPath) // 检查下载的Python文件大小 const stats = fs.statSync(zipPath) - console.log(`Python压缩包大小: ${stats.size} bytes (${(stats.size / 1024 / 1024).toFixed(2)} MB)`) - + console.log( + `Python压缩包大小: ${stats.size} bytes (${(stats.size / 1024 / 1024).toFixed(2)} MB)` + ) + // Python 3.12.0嵌入式版本应该大约30MB,如果小于5MB可能是无效文件 - if (stats.size < 5 * 1024 * 1024) { // 5MB + if (stats.size < 5 * 1024 * 1024) { + // 5MB fs.unlinkSync(zipPath) // 删除无效文件 - throw new Error(`Python下载文件大小异常: ${stats.size} bytes (${(stats.size / 1024).toFixed(2)} KB),可能是镜像站返回的错误页面或无效文件。请选择一个其他可用镜像源进行下载!`) + throw new Error( + `Python下载文件大小异常: ${stats.size} bytes (${(stats.size / 1024).toFixed(2)} KB),可能是镜像站返回的错误页面或无效文件。请选择一个其他可用镜像源进行下载!` + ) } if (mainWindow) { @@ -211,19 +222,19 @@ export async function downloadPython(appRoot: string, mirror = 'ustc'): Promise< type: 'python', progress: 100, status: 'extracting', - message: '正在解压Python...' + message: '正在解压Python...', }) } // 解压Python到指定目录 console.log(`开始解压Python到: ${pythonPath}`) - + // 确保Python目录存在 if (!fs.existsSync(pythonPath)) { fs.mkdirSync(pythonPath, { recursive: true }) console.log(`创建Python目录: ${pythonPath}`) } - + const zip = new AdmZip(zipPath) zip.extractAllTo(pythonPath, true) console.log(`Python解压完成到: ${pythonPath}`) @@ -241,14 +252,13 @@ export async function downloadPython(appRoot: string, mirror = 'ustc'): Promise< console.log('已启用 site-packages 支持') } - // 安装pip if (mainWindow) { mainWindow.webContents.send('download-progress', { type: 'python', progress: 80, status: 'installing', - message: '正在安装pip...' + message: '正在安装pip...', }) } @@ -259,7 +269,7 @@ export async function downloadPython(appRoot: string, mirror = 'ustc'): Promise< type: 'python', progress: 100, status: 'completed', - message: 'Python和pip安装完成' + message: 'Python和pip安装完成', }) } @@ -271,7 +281,7 @@ export async function downloadPython(appRoot: string, mirror = 'ustc'): Promise< type: 'python', progress: 0, status: 'error', - message: `Python下载失败: ${errorMessage}` + message: `Python下载失败: ${errorMessage}`, }) } return { success: false, error: errorMessage } @@ -284,11 +294,17 @@ const pipMirrorUrls = { tsinghua: 'https://pypi.tuna.tsinghua.edu.cn/simple/', ustc: 'https://pypi.mirrors.ustc.edu.cn/simple/', aliyun: 'https://mirrors.aliyun.com/pypi/simple/', - douban: 'https://pypi.douban.com/simple/' + douban: 'https://pypi.douban.com/simple/', } // 安装Python依赖 -export async function installDependencies(appRoot: string, mirror = 'tsinghua'): Promise<{ success: boolean; error?: string }> { +export async function installDependencies( + appRoot: string, + mirror = 'tsinghua' +): Promise<{ + success: boolean + error?: string +}> { try { const pythonPath = path.join(appRoot, 'environment', 'python', 'python.exe') const backendPath = path.join(appRoot) @@ -307,17 +323,18 @@ export async function installDependencies(appRoot: string, mirror = 'tsinghua'): type: 'dependencies', progress: 0, status: 'downloading', - message: '正在安装Python依赖包...' + message: '正在安装Python依赖包...', }) } // 获取pip镜像源URL - const pipMirrorUrl = pipMirrorUrls[mirror as keyof typeof pipMirrorUrls] || pipMirrorUrls.tsinghua + const pipMirrorUrl = + pipMirrorUrls[mirror as keyof typeof pipMirrorUrls] || pipMirrorUrls.tsinghua // 使用Scripts文件夹中的pip.exe const pythonDir = path.join(appRoot, 'environment', 'python') const pipExePath = path.join(pythonDir, 'Scripts', 'pip.exe') - + console.log(`开始安装Python依赖`) console.log(`Python目录: ${pythonDir}`) console.log(`pip.exe路径: ${pipExePath}`) @@ -331,17 +348,24 @@ export async function installDependencies(appRoot: string, mirror = 'tsinghua'): // 安装依赖 - 直接使用pip.exe而不是python -m pip await new Promise((resolve, reject) => { - const process = spawn(pipExePath, [ - 'install', - '-r', requirementsPath, - '-i', pipMirrorUrl, - '--trusted-host', new URL(pipMirrorUrl).hostname - ], { - cwd: backendPath, - stdio: 'pipe' - }) + const process = spawn( + pipExePath, + [ + 'install', + '-r', + requirementsPath, + '-i', + pipMirrorUrl, + '--trusted-host', + new URL(pipMirrorUrl).hostname, + ], + { + cwd: backendPath, + stdio: 'pipe', + } + ) - process.stdout?.on('data', (data) => { + process.stdout?.on('data', data => { const output = data.toString() console.log('Pip output:', output) @@ -350,17 +374,17 @@ export async function installDependencies(appRoot: string, mirror = 'tsinghua'): type: 'dependencies', progress: 50, status: 'downloading', - message: '正在安装依赖包...' + message: '正在安装依赖包...', }) } }) - process.stderr?.on('data', (data) => { + process.stderr?.on('data', data => { const errorOutput = data.toString() console.error('Pip error:', errorOutput) }) - process.on('close', (code) => { + process.on('close', code => { console.log(`pip安装完成,退出码: ${code}`) if (code === 0) { resolve() @@ -369,7 +393,7 @@ export async function installDependencies(appRoot: string, mirror = 'tsinghua'): } }) - process.on('error', (error) => { + process.on('error', error => { console.error('pip进程错误:', error) reject(error) }) @@ -380,7 +404,7 @@ export async function installDependencies(appRoot: string, mirror = 'tsinghua'): type: 'dependencies', progress: 100, status: 'completed', - message: 'Python依赖安装完成' + message: 'Python依赖安装完成', }) } @@ -392,7 +416,7 @@ export async function installDependencies(appRoot: string, mirror = 'tsinghua'): type: 'dependencies', progress: 0, status: 'error', - message: `依赖安装失败: ${errorMessage}` + message: `依赖安装失败: ${errorMessage}`, }) } return { success: false, error: errorMessage } @@ -400,10 +424,12 @@ export async function installDependencies(appRoot: string, mirror = 'tsinghua'): } // 导出pip安装函数 -export async function installPipPackage(appRoot: string): Promise<{ success: boolean; error?: string }> { +export async function installPipPackage( + appRoot: string +): Promise<{ success: boolean; error?: string }> { try { const pythonPath = path.join(appRoot, 'environment', 'python') - + if (!fs.existsSync(pythonPath)) { throw new Error('Python环境不存在,请先安装Python') } @@ -413,7 +439,7 @@ export async function installPipPackage(appRoot: string): Promise<{ success: boo type: 'pip', progress: 0, status: 'installing', - message: '正在安装pip...' + message: '正在安装pip...', }) } @@ -424,7 +450,7 @@ export async function installPipPackage(appRoot: string): Promise<{ success: boo type: 'pip', progress: 100, status: 'completed', - message: 'pip安装完成' + message: 'pip安装完成', }) } @@ -436,7 +462,7 @@ export async function installPipPackage(appRoot: string): Promise<{ success: boo type: 'pip', progress: 0, status: 'error', - message: `pip安装失败: ${errorMessage}` + message: `pip安装失败: ${errorMessage}`, }) } return { success: false, error: errorMessage } @@ -448,7 +474,7 @@ export async function startBackend(appRoot: string): Promise<{ success: boolean; try { const pythonPath = path.join(appRoot, 'environment', 'python', 'python.exe') const backendPath = path.join(appRoot) - const mainPyPath = path.join(backendPath,'main.py') + const mainPyPath = path.join(backendPath, 'main.py') // 检查文件是否存在 if (!fs.existsSync(pythonPath)) { @@ -466,22 +492,20 @@ export async function startBackend(appRoot: string): Promise<{ success: boolean; stdio: 'pipe', env: { ...process.env, - PYTHONIOENCODING: 'utf-8' // 设置Python输出编码为UTF-8 - } + PYTHONIOENCODING: 'utf-8', // 设置Python输出编码为UTF-8 + }, }) - - // 等待后端启动 await new Promise((resolve, reject) => { const timeout = setTimeout(() => { reject(new Error('后端启动超时')) }, 30000) // 30秒超时 - backendProcess.stdout?.on('data', (data) => { + backendProcess.stdout?.on('data', data => { const output = data.toString() console.log('Backend output:', output) - + // 检查是否包含启动成功的标志 if (output.includes('Uvicorn running') || output.includes('8000')) { clearTimeout(timeout) @@ -490,7 +514,7 @@ export async function startBackend(appRoot: string): Promise<{ success: boolean; }) // ✅ 重要:也要监听 stderr - backendProcess.stderr?.on('data', (data) => { + backendProcess.stderr?.on('data', data => { const output = data.toString() console.error('Backend error:', output) // 保留原有日志 @@ -501,11 +525,11 @@ export async function startBackend(appRoot: string): Promise<{ success: boolean; } }) - backendProcess.stderr?.on('data', (data) => { + backendProcess.stderr?.on('data', data => { console.error('Backend error:', data.toString()) }) - backendProcess.on('error', (error) => { + backendProcess.on('error', error => { clearTimeout(timeout) reject(error) }) @@ -515,4 +539,4 @@ export async function startBackend(appRoot: string): Promise<{ success: boolean; } catch (error) { return { success: false, error: error instanceof Error ? error.message : String(error) } } -} \ No newline at end of file +} diff --git a/frontend/src/components/AppLayout.vue b/frontend/src/components/AppLayout.vue index b522309..76b28c0 100644 --- a/frontend/src/components/AppLayout.vue +++ b/frontend/src/components/AppLayout.vue @@ -57,7 +57,13 @@ - +
- + 所有级别 Debug Info Warn Error - + - + 清空日志 - + 导出日志 - + @@ -130,7 +134,7 @@ interface Props { backendExists: boolean dependenciesInstalled: boolean serviceStarted: boolean - + // 事件处理函数 onSkipToHome: () => void onEnterApp: () => void @@ -183,7 +187,7 @@ async function handleNextStep() { console.log('nextStep 被调用,当前步骤:', currentStep.value) isProcessing.value = true errorMessage.value = '' - + try { switch (currentStep.value) { case 0: // 主题设置 @@ -227,7 +231,7 @@ async function handleNextStep() { await startBackendService() break } - + if (currentStep.value < 6) { currentStep.value++ // 进入新步骤时自动开始测速 @@ -244,14 +248,22 @@ async function handleNextStep() { function getNextButtonText() { switch (currentStep.value) { - case 0: return '下一步' - case 1: return props.pythonInstalled ? '下一步' : '安装 Python' - case 2: return props.pipInstalled ? '下一步' : '安装 pip' - case 3: return props.gitInstalled ? '下一步' : '安装 Git' - case 4: return props.backendExists ? '更新代码' : '获取代码' - case 5: return '安装依赖' - case 6: return '启动服务' - default: return '下一步' + case 0: + return '下一步' + case 1: + return props.pythonInstalled ? '下一步' : '安装 Python' + case 2: + return props.pipInstalled ? '下一步' : '安装 pip' + case 3: + return props.gitInstalled ? '下一步' : '安装 Git' + case 4: + return props.backendExists ? '更新代码' : '获取代码' + case 5: + return '安装依赖' + case 6: + return '启动服务' + default: + return '下一步' } } @@ -368,13 +380,13 @@ async function autoStartBackendService() { logger.info('自动启动后端服务') isProcessing.value = true errorMessage.value = '' - + if (serviceStepRef.value) { serviceStepRef.value.startingService = true serviceStepRef.value.showServiceProgress = true serviceStepRef.value.serviceStatus = '正在自动启动后端服务...' } - + try { const result = await window.electronAPI.startBackend() if (result.success) { @@ -384,7 +396,7 @@ async function autoStartBackendService() { } stepStatus.value = 'finish' logger.info('后端服务自动启动成功,延迟1秒后自动进入主页') - + // 延迟1秒后自动进入主页 setTimeout(() => { handleEnterApp() @@ -413,13 +425,13 @@ async function autoStartBackendService() { // 手动启动后端服务(用户点击按钮时调用) async function startBackendService() { logger.info('手动重新启动后端服务') - + if (serviceStepRef.value) { serviceStepRef.value.startingService = true serviceStepRef.value.showServiceProgress = true serviceStepRef.value.serviceStatus = '正在重新启动后端服务...' } - + try { const result = await window.electronAPI.startBackend() if (result.success) { @@ -429,7 +441,7 @@ async function startBackendService() { } stepStatus.value = 'finish' logger.info('后端服务手动启动成功,延迟1秒后自动进入主页') - + // 延迟1秒后自动进入主页 setTimeout(() => { handleEnterApp() @@ -456,7 +468,7 @@ function handleDownloadProgress(progress: any) { // 更新全局进度条 globalProgress.value = progress.progress progressText.value = progress.message - + if (progress.status === 'error') { globalProgressStatus.value = 'exception' } else if (progress.status === 'completed') { @@ -464,7 +476,7 @@ function handleDownloadProgress(progress: any) { } else { globalProgressStatus.value = 'normal' } - + // 通知父组件 props.onProgressUpdate(progress) } @@ -472,11 +484,11 @@ function handleDownloadProgress(progress: any) { // 暴露给父组件的方法 defineExpose({ currentStep, - handleDownloadProgress + handleDownloadProgress, }) // 监听 errorMessage,一旦有内容就弹窗 -watch(errorMessage, (val) => { +watch(errorMessage, val => { if (val) { message.error(val) // 弹窗后可选:自动清空 errorMessage @@ -554,7 +566,7 @@ watch(errorMessage, (val) => { flex-direction: column; gap: 8px; } - + .step-actions { flex-direction: column; gap: 12px; diff --git a/frontend/src/components/initialization/PipStep.vue b/frontend/src/components/initialization/PipStep.vue index d23fe50..572210e 100644 --- a/frontend/src/components/initialization/PipStep.vue +++ b/frontend/src/components/initialization/PipStep.vue @@ -3,24 +3,24 @@

安装 pip 包管理器

pip 是 Python 的包管理工具,用于安装和管理 Python 包

- +
-
- - - - - - + + + + + +
@@ -44,13 +44,13 @@ async function handleForceReinstall() { if (!deleteResult.success) { throw new Error(`删除pip失败: ${deleteResult.error}`) } - + // 重新安装pip const installResult = await window.electronAPI.installPip() if (!installResult.success) { throw new Error(`重新安装pip失败: ${installResult.error}`) } - + console.log('pip强制重新安装成功') // 通知父组件更新状态 window.location.reload() // 简单的页面刷新来更新状态 @@ -63,7 +63,7 @@ async function handleForceReinstall() { } defineExpose({ - handleForceReinstall + handleForceReinstall, }) diff --git a/frontend/src/components/initialization/PythonStep.vue b/frontend/src/components/initialization/PythonStep.vue index f11bb5d..c68125d 100644 --- a/frontend/src/components/initialization/PythonStep.vue +++ b/frontend/src/components/initialization/PythonStep.vue @@ -1,42 +1,47 @@ \ No newline at end of file diff --git a/frontend/src/components/initialization/ServiceStep.vue b/frontend/src/components/initialization/ServiceStep.vue index 225fec3..7dd9997 100644 --- a/frontend/src/components/initialization/ServiceStep.vue +++ b/frontend/src/components/initialization/ServiceStep.vue @@ -24,7 +24,7 @@ defineExpose({ startingService, showServiceProgress, serviceProgress, - serviceStatus + serviceStatus, }) diff --git a/frontend/src/components/initialization/ThemeStep.vue b/frontend/src/components/initialization/ThemeStep.vue index 6208bd1..fb7aa68 100644 --- a/frontend/src/components/initialization/ThemeStep.vue +++ b/frontend/src/components/initialization/ThemeStep.vue @@ -13,8 +13,8 @@
-