add browserDownloadProgress relevant logic

This commit is contained in:
geekgeekrun
2026-02-07 23:34:50 +08:00
parent ebf512c86a
commit 3f2b709097
17 changed files with 328 additions and 225 deletions

View File

@@ -0,0 +1,4 @@
import path from 'node:path'
import os from 'node:os'
export const cacheDir = path.join(os.homedir(), '.geekgeekrun', 'cache')

View File

@@ -0,0 +1,28 @@
import { ipcMain } from 'electron'
import {
createBrowserDownloadProgressWindow,
browserDownloadProgressWindow
} from '../window/browserDownloadProgressWindow'
export async function openBrowserDownloadWindow({ windowOption } = {}) {
return new Promise((resolve, reject) => {
createBrowserDownloadProgressWindow({ ...windowOption })
let processDone = false
let pathOfDownloadedBrowser = null
function handler(_, executablePath) {
pathOfDownloadedBrowser = executablePath
processDone = true
browserDownloadProgressWindow.close()
}
ipcMain.once('browser-download-done', handler)
browserDownloadProgressWindow.once('closed', () => {
ipcMain.off('browser-download-done', handler)
if (processDone) {
resolve(pathOfDownloadedBrowser)
} else {
reject(new Error('USER_CANCELLED_CONFIG_BROWSER'))
}
})
})
}

View File

@@ -9,7 +9,7 @@ export enum DOWNLOAD_ERROR_EXIT_CODE {
DOWNLOAD_ERROR = 80
}
export const checkAndDownloadDependenciesForInit = async () => {
export const downloadDependenciesForInit = async () => {
process.on('disconnect', () => app.exit())
process.on('uncaughtException', () => app.exit(DOWNLOAD_ERROR_EXIT_CODE.DOWNLOAD_ERROR))
app.dock?.hide()
@@ -50,7 +50,7 @@ export const checkAndDownloadDependenciesForInit = async () => {
timeoutTimer = setTimeout(() => {
// will encounter this when network disconnected when downloading
promiseWithResolver.reject(new Error('PROGRESS_NOT_CHANGED_TOO_LONG'))
}, 5 * 1000)
}, 10 * 1000)
} else {
clearTimeout(throttleProgressTimer)
throttleProgressTimer = null
@@ -73,7 +73,7 @@ export const checkAndDownloadDependenciesForInit = async () => {
)
throttleProgressTimer = setTimeout(() => {
throttleProgressTimer = null
}, 2500)
}, 500)
}
}
})
@@ -94,11 +94,13 @@ export const checkAndDownloadDependenciesForInit = async () => {
pipe,
JSON.stringify({
type: 'PUPPETEER_DOWNLOAD_ENCOUNTER_ERROR',
...err instanceof Error ? {
name: err.name,
message: err.message,
stack: err.stack
} : null
...(err instanceof Error
? {
name: err.name,
message: err.message,
stack: err.stack
}
: null)
}) + '\r\n'
)
await sleep(1000)

View File

@@ -1,5 +1,3 @@
import * as path from 'node:path'
import * as os from 'node:os'
import * as fs from 'node:fs'
import type { InstalledBrowser } from '@puppeteer/browsers'
import {
@@ -10,6 +8,7 @@ import {
} from '../browser-history'
import gtag from '../../../../utils/gtag'
import { EXPECT_CHROMIUM_BUILD_ID } from '../../../../../common/constant'
import { cacheDir } from '../../../../constant'
const getPuppeteerManagerModule = async () => {
const puppeteerManager = await import('@puppeteer/browsers')
@@ -17,7 +16,6 @@ const getPuppeteerManagerModule = async () => {
return puppeteerManager
}
const cacheDir = path.join(os.homedir(), '.geekgeekrun', 'cache')
const getExpectCachedPuppeteerExecutable = async (): Promise<BrowserInfo> => {
const puppeteerManager = await getPuppeteerManagerModule()

View File

@@ -6,7 +6,7 @@ import {
getPublicDbFilePath
} from '@geekgeekrun/geek-auto-start-chat-with-boss/runtime-file-utils.mjs'
// import { pipeWriteRegardlessError } from '../utils/pipe'
import { getAnyAvailablePuppeteerExecutable } from '../CHECK_AND_DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable'
import { getAnyAvailablePuppeteerExecutable } from '../DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable'
import { sleep } from '@geekgeekrun/utils/sleep.mjs'
import { AUTO_CHAT_ERROR_EXIT_CODE } from '../../../common/enums/auto-start-chat'
import attachListenerForKillSelfOnParentExited from '../../utils/attachListenerForKillSelfOnParentExited'

View File

@@ -12,7 +12,7 @@ import {
import { ChildProcess } from 'child_process'
import * as JSONStream from 'JSONStream'
import { checkCookieListFormat } from '../../../../common/utils/cookie'
import { getAnyAvailablePuppeteerExecutable } from '../../../flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable/index'
import { getAnyAvailablePuppeteerExecutable } from '../../DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable/index'
import { AUTO_CHAT_ERROR_EXIT_CODE } from '../../../../common/enums/auto-start-chat'
import { mainWindow } from '../../../window/mainWindow'
import {

View File

@@ -34,7 +34,7 @@ import cheerio from 'cheerio'
import { connectToDaemon, sendToDaemon } from '../OPEN_SETTING_WINDOW/connect-to-daemon'
// import { pushCurrentPageScreenshot, SCREENSHOT_INTERVAL_MS } from '../../utils/screenshot'
import { checkShouldExit } from '../../utils/worker'
import { getAnyAvailablePuppeteerExecutable } from '../CHECK_AND_DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable'
import { getAnyAvailablePuppeteerExecutable } from '../DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable'
import minimist from 'minimist'
import { checkCookieListFormat } from '../../../common/utils/cookie'
import { loginWithCookieAssistant } from '../../features/login-with-cookie-assistant'

View File

@@ -1,7 +1,7 @@
import minimist from 'minimist'
import { runCommon } from './features/run-common';
import { launchDaemon } from './flow/OPEN_SETTING_WINDOW/launch-daemon';
import { app } from 'electron';
import { runCommon } from './features/run-common'
import { launchDaemon } from './flow/OPEN_SETTING_WINDOW/launch-daemon'
import { app } from 'electron'
// 捕获未处理的 EPIPE 错误
process.on('uncaughtException', (err) => {
@@ -9,13 +9,13 @@ process.on('uncaughtException', (err) => {
return
}
throw err
});
})
const isUiDev = process.env.NODE_ENV === 'development'
const commandlineArgs = minimist(isUiDev ? process.argv.slice(2) : process.argv.slice(1))
console.log(commandlineArgs)
const runMode = commandlineArgs['mode'];
const runMode = commandlineArgs['mode']
;(async () => {
switch (runMode) {
@@ -27,11 +27,9 @@ const runMode = commandlineArgs['mode'];
waitForProcessHandShakeAndRunAutoChat()
break
}
case 'checkAndDownloadDependenciesForInit': {
const { checkAndDownloadDependenciesForInit } = await import(
'./flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/index'
)
checkAndDownloadDependenciesForInit()
case 'downloadDependenciesForInit': {
const { downloadDependenciesForInit } = await import('./flow/DOWNLOAD_DEPENDENCIES/index')
downloadDependenciesForInit()
break
}
case 'launchBossZhipinLoginPageWithPreloadExtension': {

View File

@@ -1,13 +1,11 @@
import { ChildProcess } from 'child_process'
import { BrowserWindow, ipcMain } from 'electron'
import path from 'path'
import { getAnyAvailablePuppeteerExecutable } from '../flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable'
import * as childProcess from 'node:child_process'
import * as JSONStream from 'JSONStream'
import { getAnyAvailablePuppeteerExecutable } from '../flow/DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable'
import {
getLastUsedAndAvailableBrowser,
saveLastUsedAndAvailableBrowserInfo
} from '../flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/utils/browser-history'
} from '../flow/DOWNLOAD_DEPENDENCIES/utils/browser-history'
import { openBrowserDownloadWindow } from '../features/open-browser-download-window'
export let browserAssistantWindow: BrowserWindow | null = null
@@ -83,67 +81,15 @@ export function createBrowserAssistantWindow(
}
)
let subProcessOfCheckAndDownloadDependencies: ChildProcess | null = null
registerHandleWithWindow(browserAssistantWindow, 'setup-dependencies', async () => {
if (subProcessOfCheckAndDownloadDependencies) {
return
}
subProcessOfCheckAndDownloadDependencies = childProcess.spawn(
process.argv[0],
[process.argv[1], `--mode=checkAndDownloadDependenciesForInit`],
{
stdio: [null, null, null, 'pipe', 'ipc']
registerHandleWithWindow(browserAssistantWindow, 'download-browser-with-downloader', async () => {
return await openBrowserDownloadWindow({
windowOption: {
parent: browserAssistantWindow!,
modal: true,
show: true
}
)
return new Promise((resolve, reject) => {
subProcessOfCheckAndDownloadDependencies!.stdio[3]!.pipe(JSONStream.parse()).on(
'data',
(raw) => {
const data = raw
switch (data.type) {
case 'NEED_RESETUP_DEPENDENCIES':
case 'PUPPETEER_DOWNLOAD_PROGRESS': {
browserAssistantWindow?.webContents.send(data.type, data)
break
}
case 'PUPPETEER_DOWNLOAD_ENCOUNTER_ERROR': {
console.error(data)
break
}
default: {
return
}
}
}
)
subProcessOfCheckAndDownloadDependencies!.once('exit', (exitCode) => {
switch (exitCode) {
case 0: {
resolve(exitCode)
break
}
default: {
reject('PUPPETEER_DOWNLOAD_ENCOUNTER_ERROR')
break
}
}
subProcessOfCheckAndDownloadDependencies = null
})
})
})
const killHandler = async () => {
try {
subProcessOfCheckAndDownloadDependencies?.kill()
} catch {
//
} finally {
subProcessOfCheckAndDownloadDependencies = null
}
}
browserAssistantWindow.once('closed', () => {
killHandler()
})
return browserAssistantWindow!
}

View File

@@ -0,0 +1,124 @@
import { ChildProcess } from 'child_process'
import { BrowserWindow, ipcMain } from 'electron'
import path from 'path'
import * as childProcess from 'node:child_process'
import * as JSONStream from 'JSONStream'
import * as fs from 'node:fs'
import { cacheDir } from '../constant'
import { EXPECT_CHROMIUM_BUILD_ID } from '../../common/constant'
import * as puppeteerManager from '@puppeteer/browsers'
export let browserDownloadProgressWindow: BrowserWindow | null = null
const registerHandleWithWindow = (
win: BrowserWindow,
...args: Parameters<typeof ipcMain.handle>
) => {
const [channel, handler] = args
ipcMain.handle(channel, handler)
win.once('closed', () => ipcMain.removeHandler(channel))
}
export function createBrowserDownloadProgressWindow(
opt?: Electron.BrowserWindowConstructorOptions
): BrowserWindow {
// Create the browser window.
if (browserDownloadProgressWindow) {
browserDownloadProgressWindow!.close()
}
browserDownloadProgressWindow = new BrowserWindow({
width: 600,
height: 200,
resizable: false,
show: false,
autoHideMenuBar: true,
webPreferences: {
preload: path.join(__dirname, '../preload/index.js'),
sandbox: false
},
...opt
})
browserDownloadProgressWindow.on('ready-to-show', () => {
browserDownloadProgressWindow!.show()
})
// HMR for renderer base on electron-vite cli.
// Load the remote URL for development or the local html file for production.
if (process.env.NODE_ENV === 'development' && process.env['ELECTRON_RENDERER_URL']) {
browserDownloadProgressWindow.loadURL(
process.env['ELECTRON_RENDERER_URL'] + '#/browserDownloadProgress'
)
} else {
browserDownloadProgressWindow.loadURL(
'file://' + path.join(__dirname, '../renderer/index.html') + '#/browserDownloadProgress'
)
}
let subProcessOfCheckAndDownloadDependencies: ChildProcess | null = null
registerHandleWithWindow(browserDownloadProgressWindow, 'setup-dependencies', async () => {
if (subProcessOfCheckAndDownloadDependencies) {
return
}
subProcessOfCheckAndDownloadDependencies = childProcess.spawn(
process.argv[0],
[process.argv[1], `--mode=downloadDependenciesForInit`],
{
stdio: [null, null, null, 'pipe', 'ipc']
}
)
return new Promise((resolve, reject) => {
subProcessOfCheckAndDownloadDependencies!.stdio[3]!.pipe(JSONStream.parse()).on(
'data',
(raw) => {
const data = raw
switch (data.type) {
case 'NEED_RESETUP_DEPENDENCIES':
case 'PUPPETEER_DOWNLOAD_PROGRESS': {
browserDownloadProgressWindow?.webContents.send(data.type, data)
break
}
case 'PUPPETEER_DOWNLOAD_ENCOUNTER_ERROR': {
console.error(data)
break
}
default: {
return
}
}
}
)
subProcessOfCheckAndDownloadDependencies!.once('exit', (exitCode) => {
const executablePath = puppeteerManager.computeExecutablePath({
browser: puppeteerManager.Browser.CHROME,
cacheDir,
buildId: EXPECT_CHROMIUM_BUILD_ID
})
if (exitCode === 0 && fs.existsSync(executablePath)) {
resolve(executablePath)
} else {
reject('PUPPETEER_DOWNLOAD_ENCOUNTER_ERROR')
}
subProcessOfCheckAndDownloadDependencies = null
})
})
})
const killHandler = async () => {
try {
subProcessOfCheckAndDownloadDependencies?.kill()
} catch {
//
} finally {
subProcessOfCheckAndDownloadDependencies = null
}
}
browserDownloadProgressWindow.once('closed', () => {
killHandler()
})
browserDownloadProgressWindow.once('closed', () => {
browserDownloadProgressWindow = null
})
return browserDownloadProgressWindow!
}

View File

@@ -1,7 +1,7 @@
import { ChildProcess } from 'child_process'
import { BrowserWindow, ipcMain } from 'electron'
import path from 'path'
import { getAnyAvailablePuppeteerExecutable } from '../flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable'
import { getAnyAvailablePuppeteerExecutable } from '../flow/DOWNLOAD_DEPENDENCIES/utils/puppeteer-executable'
import * as childProcess from 'node:child_process'
import * as JSONStream from 'JSONStream'

View File

@@ -32,11 +32,11 @@
<li>
方案一通过本程序下载 Google Chrome for Testing
{{ EXPECT_CHROMIUM_BUILD_ID }} -
<a href="javascript:;">点击此处</a
>即可下载这个浏览器本程序独占不会影响到当前 Google Chrome
<a href="javascript:;" @click="handleClickLaunchBrowserDownloader">点击此处</a
>即可下载这个浏览器仅供本程序使用不会影响到当前 Google Chrome
安装本程序开发过程中主要是使用这个浏览器测试的<span color-orange
>可以保证兼容性</span
>网络波动有一定概率下载失败如多次尝试后确实不能下载成功请尝试方案二<span
>网络波动有一定概率下载失败如多次尝试后确实不能下载成功请尝试方案二<span
color-orange
>推荐</span
>
@@ -54,7 +54,7 @@
>浏览器升级后某些功能不兼容导致本程序不能正确运行</span
>的问题您可以<a href="javascript:;" @click="handleFeedbackClick"
>提交 Issue</a
>来反馈新版本浏览器不能正常运行的问题同时请再尝试方
>来反馈新版本浏览器不能正常运行的问题同时请再尝试方
</li>
</ul>
</div>
@@ -142,13 +142,19 @@ async function autoDetectPuppeteerExecutable() {
noSave: true
})
if (!result) {
ElMessage.warning({
ElMessage({
message: '未检测到可用浏览器的可执行文件',
type: 'warning'
type: 'warning',
grouping: true
})
return
}
formData.value.browserPath = result.executablePath
ElMessage({
message: '已找到可用浏览器,可执行文件路径已填入输入框',
type: 'success',
grouping: true
})
}
async function browserExecutableFile() {
@@ -177,7 +183,9 @@ function handleCancel() {
gtagRenderer('cancel_clicked')
window.close()
}
const formRef = ref()
async function handleSave() {
await formRef.value.validate()
await ipcRenderer.invoke('save-last-used-and-available-browser-info', {
executablePath: formData.value.browserPath,
browser: ''
@@ -188,6 +196,18 @@ const handleFeedbackClick = () => {
gtagRenderer('goto_feedback_for_ba_clicked')
electron.ipcRenderer.send('send-feed-back-to-github-issue')
}
const handleClickLaunchBrowserDownloader = async () => {
gtagRenderer('launch_browser_downloader_clicked')
const downloadedBrowserPath = await electron.ipcRenderer.invoke('download-browser-with-downloader')
if (downloadedBrowserPath) {
formData.value.browserPath = downloadedBrowserPath
ElMessage({
message: '浏览器下载成功,可执行文件路径已填入输入框',
type: 'success',
grouping: true
})
}
}
</script>
<style lang="scss" scoped>

View File

@@ -1,107 +0,0 @@
<template>
<div class="flex flex-col flex-items-start flex-justify-start" v-if="!dependenciesStatus.puppeteerExecutableAvailable">
<div mb14px>正在下载兼容的浏览器</div>
<el-progress
:percentage="browserDownloadPercentage"
:format="(n) => `${n.toFixed(1)}%`"
:stroke-width="10"
class="w400px"
/>
</div>
</template>
<script lang="ts" setup>
import { ref, onUnmounted, PropType, h } from 'vue'
import { ElMessageBox } from 'element-plus'
import { gtagRenderer } from '@renderer/utils/gtag'
import { sleep } from '@geekgeekrun/utils/sleep.mjs'
import FailMessage from './FailMessage.vue'
const props = defineProps({
dependenciesStatus: {
type: Object as PropType<Record<string, boolean>>,
default: () => ({})
},
processWaitee: Object
})
const browserDownloadPercentage = ref(0)
const handleBrowserDownloadProgress = (ev, { downloadedBytes, totalBytes }) => {
browserDownloadPercentage.value = (downloadedBytes / totalBytes) * 100
}
electron.ipcRenderer.on('PUPPETEER_DOWNLOAD_PROGRESS', handleBrowserDownloadProgress)
onUnmounted(() =>
electron.ipcRenderer.removeListener('PUPPETEER_DOWNLOAD_PROGRESS', handleBrowserDownloadProgress)
)
const downloadProcessExitCode = ref(0)
const processDownloadBrowser = async () => {
downloadProcessExitCode.value = 0
browserDownloadPercentage.value = 0
let restRetriedTime = 2
while (restRetriedTime > 0) {
try {
try {
await electron.ipcRenderer.invoke('setup-dependencies')
browserDownloadPercentage.value = 100
} catch (err) {
downloadProcessExitCode.value = 1
throw err
}
break
} catch (err) {
restRetriedTime--
if (restRetriedTime === 0) {
throw err
}
await sleep(5000)
}
}
}
const promiseList: Array<Promise<void>> = []
const processTasks = async () => {
if (!props.dependenciesStatus.puppeteerExecutableAvailable) {
gtagRenderer('start_download_puppeteer')
const p = processDownloadBrowser()
promiseList.push(p)
p.then(() => {
gtagRenderer('puppeteer_download_success')
props.dependenciesStatus.puppeteerExecutableAvailable = true
})
}
while (promiseList.length) {
const p = promiseList.shift()!
try {
p.then(() => {
if (!promiseList.length) {
props.processWaitee?.resolve?.()
}
})
await p
} catch {
gtagRenderer('encounter_error_when_download_deps')
await ElMessageBox.confirm(h(FailMessage), {
closeOnClickModal: false,
closeOnPressEscape: false,
showClose: false,
type: 'error',
cancelButtonText: '退出程序',
confirmButtonText: '重试'
})
.then(() => {
gtagRenderer('start_retry_download_deps')
processTasks()
})
.catch(() => {
gtagRenderer('cancel_download_deps_and_exit')
promiseList.length = 0
electron.ipcRenderer.invoke('exit-app-immediately')
})
}
}
}
processTasks()
</script>

View File

@@ -1,7 +1,7 @@
<template>
<div>
<p>核心组件下载失败请重试</p>
<br />
<p>浏览器下载失败请重试或使用其他方式下载</p>
<!-- <br />
<br />
<p>
<b text-orange>提示</b>由于网络颠簸如果多次重试仍然失败&nbsp;<el-button
@@ -12,23 +12,23 @@
>点击此处</el-button
>&nbsp;下载最新版本 Google Chrome
浏览器安装完毕后重新打开本程序程序会自动检测该浏览器并使用它
</p>
</p> -->
</div>
</template>
<script lang="ts" setup>
import { gtagRenderer } from '@renderer/utils/gtag'
import debounce from 'lodash/debounce'
const { ipcRenderer } = electron
// import { gtagRenderer } from '@renderer/utils/gtag'
// import debounce from 'lodash/debounce'
// const { ipcRenderer } = electron
const handleOpenChromeDownloadPage = debounce(
async () => {
gtagRenderer('open_chrome_download_page_clicked')
ipcRenderer.send('open-external-link', 'https://www.google.cn/chrome/')
},
1000,
{ leading: true, trailing: false }
)
// const handleOpenChromeDownloadPage = debounce(
// async () => {
// gtagRenderer('open_chrome_download_page_clicked')
// ipcRenderer.send('open-external-link', 'https://www.google.cn/chrome/')
// },
// 1000,
// { leading: true, trailing: false }
// )
</script>
<style scoped></style>

View File

@@ -0,0 +1,92 @@
<template>
<!-- flex-items- -->
<div class="flex flex-col flex-justify-center w500px h-full ml-auto mr-auto">
<div font-size-14px>正在下载 Google Chrome for Testing {{ EXPECT_CHROMIUM_BUILD_ID }}</div>
<el-progress
:percentage="browserDownloadPercentage"
:format="(n) => `${n.toFixed(1)}%`"
:stroke-width="10"
class="w500px"
mt10px
/>
<div mt10px>
<el-button @click="handleCancelDownload">取消下载</el-button>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, onUnmounted, h } from 'vue'
import { ElMessageBox } from 'element-plus'
import { gtagRenderer } from '@renderer/utils/gtag'
import { sleep } from '@geekgeekrun/utils/sleep.mjs'
import FailMessage from './FailMessage.vue'
import { EXPECT_CHROMIUM_BUILD_ID } from '../../../../common/constant'
const browserDownloadPercentage = ref(0)
const handleBrowserDownloadProgress = (ev, { downloadedBytes, totalBytes }) => {
browserDownloadPercentage.value = (downloadedBytes / totalBytes) * 100
}
electron.ipcRenderer.on('PUPPETEER_DOWNLOAD_PROGRESS', handleBrowserDownloadProgress)
onUnmounted(() =>
electron.ipcRenderer.removeListener('PUPPETEER_DOWNLOAD_PROGRESS', handleBrowserDownloadProgress)
)
const downloadProcessExitCode = ref(0)
let executablePath
const processDownloadBrowser = async () => {
downloadProcessExitCode.value = 0
browserDownloadPercentage.value = 0
let restRetriedTime = 2
while (restRetriedTime > 0) {
try {
try {
executablePath = await electron.ipcRenderer.invoke('setup-dependencies')
browserDownloadPercentage.value = 100
} catch (err) {
downloadProcessExitCode.value = 1
throw err
}
break
} catch (err) {
restRetriedTime--
if (restRetriedTime === 0) {
throw err
}
await sleep(5000)
}
}
}
const processTasks = async () => {
try {
await processDownloadBrowser()
electron.ipcRenderer.send('browser-download-done', executablePath)
} catch (err) {
gtagRenderer('encounter_error_when_download_deps')
await ElMessageBox.confirm(h(FailMessage), {
closeOnClickModal: false,
closeOnPressEscape: false,
showClose: false,
type: 'error',
cancelButtonText: '取消',
confirmButtonText: '重试'
})
.then(() => {
gtagRenderer('start_retry_download_deps')
processTasks()
})
.catch(() => {
gtagRenderer('cancel_download_deps_from_err_dialog')
window.close()
})
}
}
processTasks()
function handleCancelDownload() {
gtagRenderer('cancel_download_deps_from_cancel_btn')
window.close()
}
</script>

View File

@@ -22,16 +22,14 @@ const routes: Array<RouteRecordRaw> = [
component: () => import('@renderer/page/BrowserAssistant/index.vue'),
meta: {
title: '浏览器助手'
},
children: [
{
path: '/downloadingDependencies',
component: () => import('@renderer/page/BrowserAssistant/page/DownloadingDependencies.vue'),
meta: {
title: '正在下载核心组件'
}
}
]
}
},
{
path: '/browserDownloadProgress',
component: () => import('@renderer/page/BrowserDownloadProgress/index.vue'),
meta: {
title: '正在下载浏览器'
}
},
{
path: '/llmConfig',