mirror of
https://github.com/geekgeekrun/geekgeekrun.git
synced 2026-09-07 08:27:13 +08:00
add browser assistant entry on ui
This commit is contained in:
@@ -1 +1,2 @@
|
|||||||
export const SINGLE_ITEM_DEFAULT_SERVE_WEIGHT = 1
|
export const SINGLE_ITEM_DEFAULT_SERVE_WEIGHT = 1
|
||||||
|
export const EXPECT_CHROMIUM_BUILD_ID = '139.0.7258.154'
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { ipcMain } from 'electron'
|
||||||
|
import {
|
||||||
|
createBrowserAssistantWindow,
|
||||||
|
browserAssistantWindow
|
||||||
|
} from '../window/browserAssistantWindow'
|
||||||
|
|
||||||
|
export async function configWithBrowserAssistant({ windowOption } = {}) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
createBrowserAssistantWindow({ ...windowOption })
|
||||||
|
|
||||||
|
let processDone = false
|
||||||
|
function handler() {
|
||||||
|
processDone = true
|
||||||
|
browserAssistantWindow.close()
|
||||||
|
}
|
||||||
|
ipcMain.once('browser-config-saved', handler)
|
||||||
|
browserAssistantWindow.once('closed', () => {
|
||||||
|
ipcMain.off('browser-config-saved', handler)
|
||||||
|
if (processDone) {
|
||||||
|
resolve(true)
|
||||||
|
} else {
|
||||||
|
reject(new Error('USER_CANCELLED_CONFIG_BROWSER'))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -6,11 +6,13 @@ export async function loginWithCookieAssistant({ windowOption } = {}) {
|
|||||||
createCookieAssistantWindow({ ...windowOption })
|
createCookieAssistantWindow({ ...windowOption })
|
||||||
|
|
||||||
let processDone = false
|
let processDone = false
|
||||||
ipcMain.once('cookie-saved', function handler() {
|
function handler() {
|
||||||
processDone = true
|
processDone = true
|
||||||
cookieAssistantWindow.close()
|
cookieAssistantWindow.close()
|
||||||
})
|
}
|
||||||
|
ipcMain.once('cookie-saved', handler)
|
||||||
cookieAssistantWindow.once('closed', () => {
|
cookieAssistantWindow.once('closed', () => {
|
||||||
|
ipcMain.off('cookie-saved', handler)
|
||||||
if (processDone) {
|
if (processDone) {
|
||||||
resolve(true)
|
resolve(true)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -40,13 +40,6 @@ export const getLastUsedAndAvailableBrowser = async (): Promise<BrowserInfo | nu
|
|||||||
await removeLastUsedAndAvailableBrowserPath()
|
await removeLastUsedAndAvailableBrowserPath()
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
// blacklist browser
|
|
||||||
if (path.includes(`Microsoft\\Edge\\Application\\msedge.exe`)) {
|
|
||||||
await removeLastUsedAndAvailableBrowserPath()
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
executablePath: path,
|
executablePath: path,
|
||||||
browser
|
browser
|
||||||
|
|||||||
+21
-14
@@ -9,6 +9,7 @@ import {
|
|||||||
removeLastUsedAndAvailableBrowserPath
|
removeLastUsedAndAvailableBrowserPath
|
||||||
} from '../browser-history'
|
} from '../browser-history'
|
||||||
import gtag from '../../../../utils/gtag'
|
import gtag from '../../../../utils/gtag'
|
||||||
|
import { EXPECT_CHROMIUM_BUILD_ID } from '../../../../../common/constant'
|
||||||
|
|
||||||
const getPuppeteerManagerModule = async () => {
|
const getPuppeteerManagerModule = async () => {
|
||||||
const puppeteerManager = await import('@puppeteer/browsers')
|
const puppeteerManager = await import('@puppeteer/browsers')
|
||||||
@@ -16,7 +17,6 @@ const getPuppeteerManagerModule = async () => {
|
|||||||
return puppeteerManager
|
return puppeteerManager
|
||||||
}
|
}
|
||||||
|
|
||||||
const EXPECT_CHROMIUM_BUILD_ID = '139.0.7258.154'
|
|
||||||
const cacheDir = path.join(os.homedir(), '.geekgeekrun', 'cache')
|
const cacheDir = path.join(os.homedir(), '.geekgeekrun', 'cache')
|
||||||
|
|
||||||
const getExpectCachedPuppeteerExecutable = async (): Promise<BrowserInfo> => {
|
const getExpectCachedPuppeteerExecutable = async (): Promise<BrowserInfo> => {
|
||||||
@@ -97,29 +97,36 @@ export const checkAndDownloadPuppeteerExecutable = async (
|
|||||||
return installedBrowser
|
return installedBrowser
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getAnyAvailablePuppeteerExecutable = async (): Promise<BrowserInfo | null> => {
|
export const getAnyAvailablePuppeteerExecutable = async ({
|
||||||
const lastUsedOne = await getLastUsedAndAvailableBrowser()
|
ignoreCached = false,
|
||||||
if (lastUsedOne) {
|
noSave = false
|
||||||
return lastUsedOne
|
}: {
|
||||||
|
ignoreCached?: boolean
|
||||||
|
noSave?: boolean
|
||||||
|
} = {}): Promise<BrowserInfo | null> => {
|
||||||
|
if (!ignoreCached) {
|
||||||
|
const lastUsedOne = await getLastUsedAndAvailableBrowser()
|
||||||
|
if (lastUsedOne) {
|
||||||
|
return lastUsedOne
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// find existed browser - the fallback one
|
||||||
|
if (await checkCachedPuppeteerExecutable()) {
|
||||||
|
const cachedOne = await getExpectCachedPuppeteerExecutable()
|
||||||
|
!noSave && (await saveLastUsedAndAvailableBrowserInfo(cachedOne))
|
||||||
|
|
||||||
|
return cachedOne
|
||||||
}
|
}
|
||||||
// find existed browser - the one maybe actively installed by user or ship with os like Edge on windows
|
// find existed browser - the one maybe actively installed by user or ship with os like Edge on windows
|
||||||
try {
|
try {
|
||||||
const existedOne = await findAndLocateUserInstalledChromiumExecutableSync()
|
const existedOne = await findAndLocateUserInstalledChromiumExecutableSync()
|
||||||
await saveLastUsedAndAvailableBrowserInfo(existedOne)
|
!noSave && (await saveLastUsedAndAvailableBrowserInfo(existedOne))
|
||||||
// save its path
|
// save its path
|
||||||
return existedOne
|
return existedOne
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
console.log('no existed browser path found')
|
console.log('no existed browser path found')
|
||||||
}
|
}
|
||||||
// find existed browser - the fallback one
|
|
||||||
if (await checkCachedPuppeteerExecutable()) {
|
|
||||||
const cachedOne = await getExpectCachedPuppeteerExecutable()
|
|
||||||
await saveLastUsedAndAvailableBrowserInfo(cachedOne)
|
|
||||||
|
|
||||||
return cachedOne
|
|
||||||
}
|
|
||||||
|
|
||||||
// if no one available, then return null and remove last used browser
|
// if no one available, then return null and remove last used browser
|
||||||
await removeLastUsedAndAvailableBrowserPath()
|
await removeLastUsedAndAvailableBrowserPath()
|
||||||
return null
|
return null
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ import gtag from '../../../utils/gtag'
|
|||||||
import { daemonEE, sendToDaemon } from '../connect-to-daemon'
|
import { daemonEE, sendToDaemon } from '../connect-to-daemon'
|
||||||
import { runCommon } from '../../../features/run-common'
|
import { runCommon } from '../../../features/run-common'
|
||||||
import { loginWithCookieAssistant } from '../../../features/login-with-cookie-assistant'
|
import { loginWithCookieAssistant } from '../../../features/login-with-cookie-assistant'
|
||||||
|
import { configWithBrowserAssistant } from '../../../features/config-with-browser-assistant'
|
||||||
|
|
||||||
export default function initIpc() {
|
export default function initIpc() {
|
||||||
ipcMain.handle('fetch-config-file-content', async () => {
|
ipcMain.handle('fetch-config-file-content', async () => {
|
||||||
@@ -246,64 +247,6 @@ export default function initIpc() {
|
|||||||
return { runRecordId }
|
return { runRecordId }
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcMain.handle('check-dependencies', async () => {
|
|
||||||
const [anyAvailablePuppeteerExecutable] = await Promise.all([
|
|
||||||
getAnyAvailablePuppeteerExecutable()
|
|
||||||
])
|
|
||||||
return {
|
|
||||||
puppeteerExecutableAvailable: !!anyAvailablePuppeteerExecutable
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
let subProcessOfCheckAndDownloadDependencies: ChildProcess | null = null
|
|
||||||
ipcMain.handle('setup-dependencies', async () => {
|
|
||||||
if (subProcessOfCheckAndDownloadDependencies) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
subProcessOfCheckAndDownloadDependencies = childProcess.spawn(
|
|
||||||
process.argv[0],
|
|
||||||
[process.argv[1], `--mode=checkAndDownloadDependenciesForInit`],
|
|
||||||
{
|
|
||||||
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': {
|
|
||||||
mainWindow?.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
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
ipcMain.handle('stop-geek-auto-start-chat-with-boss', async () => {
|
ipcMain.handle('stop-geek-auto-start-chat-with-boss', async () => {
|
||||||
mainWindow?.webContents.send('geek-auto-start-chat-with-boss-stopping')
|
mainWindow?.webContents.send('geek-auto-start-chat-with-boss-stopping')
|
||||||
const p = new Promise((resolve) => {
|
const p = new Promise((resolve) => {
|
||||||
@@ -613,6 +556,15 @@ export default function initIpc() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
ipcMain.handle('config-with-browser-assistant', async () => {
|
||||||
|
return await configWithBrowserAssistant({
|
||||||
|
windowOption: {
|
||||||
|
parent: mainWindow!,
|
||||||
|
modal: true,
|
||||||
|
show: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
ipcMain.handle('exit-app-immediately', () => {
|
ipcMain.handle('exit-app-immediately', () => {
|
||||||
app.exit(0)
|
app.exit(0)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { BrowserWindow, ipcMain, shell } from 'electron'
|
import { BrowserWindow, dialog, ipcMain, shell } from 'electron'
|
||||||
import gtag from './gtag'
|
import gtag from './gtag'
|
||||||
import buildInfo from '../../common/build-info.json'
|
import buildInfo from '../../common/build-info.json'
|
||||||
import os from 'node:os'
|
import os from 'node:os'
|
||||||
@@ -71,4 +71,18 @@ export default function initPublicIpc() {
|
|||||||
ensureStorageFileExist()
|
ensureStorageFileExist()
|
||||||
return await writeStorageFile(payload.fileName, JSON.parse(payload.data))
|
return await writeStorageFile(payload.fileName, JSON.parse(payload.data))
|
||||||
})
|
})
|
||||||
|
ipcMain.handle('get-os-platform', () => {
|
||||||
|
return os.platform()
|
||||||
|
})
|
||||||
|
ipcMain.handle('choose-file', (ev, { fileChooserConfig }) => {
|
||||||
|
if (!fileChooserConfig) {
|
||||||
|
fileChooserConfig = {}
|
||||||
|
}
|
||||||
|
const win = BrowserWindow.fromWebContents(ev.sender)
|
||||||
|
if (!win) {
|
||||||
|
return dialog.showOpenDialog(fileChooserConfig)
|
||||||
|
} else {
|
||||||
|
return dialog.showOpenDialog(win, fileChooserConfig)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,149 @@
|
|||||||
|
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 {
|
||||||
|
getLastUsedAndAvailableBrowser,
|
||||||
|
saveLastUsedAndAvailableBrowserInfo
|
||||||
|
} from '../flow/CHECK_AND_DOWNLOAD_DEPENDENCIES/utils/browser-history'
|
||||||
|
|
||||||
|
export let browserAssistantWindow: 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 createBrowserAssistantWindow(
|
||||||
|
opt?: Electron.BrowserWindowConstructorOptions
|
||||||
|
): BrowserWindow {
|
||||||
|
// Create the browser window.
|
||||||
|
if (browserAssistantWindow) {
|
||||||
|
browserAssistantWindow!.close()
|
||||||
|
}
|
||||||
|
browserAssistantWindow = new BrowserWindow({
|
||||||
|
width: 800,
|
||||||
|
minWidth: 800,
|
||||||
|
height: 400,
|
||||||
|
resizable: true,
|
||||||
|
show: false,
|
||||||
|
autoHideMenuBar: true,
|
||||||
|
webPreferences: {
|
||||||
|
preload: path.join(__dirname, '../preload/index.js'),
|
||||||
|
sandbox: false
|
||||||
|
},
|
||||||
|
...opt
|
||||||
|
})
|
||||||
|
|
||||||
|
browserAssistantWindow.on('ready-to-show', () => {
|
||||||
|
browserAssistantWindow!.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']) {
|
||||||
|
browserAssistantWindow.loadURL(process.env['ELECTRON_RENDERER_URL'] + '#/browserAssistant')
|
||||||
|
} else {
|
||||||
|
browserAssistantWindow.loadURL(
|
||||||
|
'file://' + path.join(__dirname, '../renderer/index.html') + '#/browserAssistant'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
browserAssistantWindow!.once('closed', () => {
|
||||||
|
browserAssistantWindow = null
|
||||||
|
})
|
||||||
|
|
||||||
|
registerHandleWithWindow(
|
||||||
|
browserAssistantWindow,
|
||||||
|
'get-any-available-puppeteer-executable',
|
||||||
|
async (_, { ignoreCached, noSave } = {}) => {
|
||||||
|
return await getAnyAvailablePuppeteerExecutable({ ignoreCached, noSave })
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
registerHandleWithWindow(
|
||||||
|
browserAssistantWindow,
|
||||||
|
'get-last-used-and-available-browser',
|
||||||
|
async () => {
|
||||||
|
return await getLastUsedAndAvailableBrowser()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
registerHandleWithWindow(
|
||||||
|
browserAssistantWindow,
|
||||||
|
'save-last-used-and-available-browser-info',
|
||||||
|
async (_, payload) => {
|
||||||
|
return await saveLastUsedAndAvailableBrowserInfo(payload)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
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']
|
||||||
|
}
|
||||||
|
)
|
||||||
|
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!
|
||||||
|
}
|
||||||
@@ -27,25 +27,7 @@ const router = useRouter()
|
|||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
gtagRenderer('bootstrap_mounted')
|
gtagRenderer('bootstrap_mounted')
|
||||||
// checkDependenciesResult.value = await electron.ipcRenderer.invoke('check-dependencies')
|
|
||||||
// downloadProcessWaitee.value = Promise.withResolvers()
|
|
||||||
|
|
||||||
// if (Object.values(checkDependenciesResult.value).includes(false)) {
|
|
||||||
// gtagRenderer('dependencies_need_download')
|
|
||||||
// router.replace('/downloadingDependencies')
|
|
||||||
// } else {
|
|
||||||
// downloadProcessWaitee.value!.resolve()
|
|
||||||
// }
|
|
||||||
|
|
||||||
// downloadProcessWaitee.value!.promise.then(async () => {
|
|
||||||
// const isCookieFileValid = await electron.ipcRenderer.invoke('check-boss-zhipin-cookie-file')
|
|
||||||
// if (!isCookieFileValid) {
|
|
||||||
// gtagRenderer('found_cookie_invalid_when_bootstrap')
|
|
||||||
// router.replace('/cookieAssistant')
|
|
||||||
// } else {
|
|
||||||
await sleep(2000)
|
await sleep(2000)
|
||||||
router.replace('/main-layout')
|
router.replace('/main-layout')
|
||||||
// }
|
|
||||||
// })
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,58 +1,200 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="h-screen flex flex-col flex-items-center flex-justify-center">
|
<div class="h-screen of-hidden flex flex-col flex-items-center flex-justify-between">
|
||||||
<div>
|
<div flex-1 of-hidden w-full>
|
||||||
<img
|
<el-form ref="formRef" :model="formData" :rules="rules" flex flex-col of-hidden h-full>
|
||||||
class="block"
|
<div class="bg-#f6f6f6" flex-0>
|
||||||
:class="{
|
<el-form-item
|
||||||
'animate__animated animate__bounce animate__repeat-3':
|
class="w-80%"
|
||||||
Object.values(checkDependenciesResult).includes(false)
|
label="浏览器可执行文件路径"
|
||||||
}"
|
prop="browserPath"
|
||||||
:width="256"
|
pt50px
|
||||||
src="@renderer/../../../resources/icon.png"
|
pb50px
|
||||||
/>
|
ml-auto
|
||||||
|
mr-auto
|
||||||
|
mb-0
|
||||||
|
>
|
||||||
|
<div flex flex-1>
|
||||||
|
<el-input v-model="formData.browserPath" />
|
||||||
|
<el-button type="primary" @click="autoDetectPuppeteerExecutable">自动检测</el-button>
|
||||||
|
<el-button :style="{ marginLeft: 0 }" @click="browserExecutableFile">浏览</el-button>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
<div flex-1 of-auto font-size-14px line-height-1.5em>
|
||||||
|
<div mt10px ml-auto mr-auto class="w-80%">
|
||||||
|
<div>常见问题</div>
|
||||||
|
<div>
|
||||||
|
<details>
|
||||||
|
<summary>不能自动检测到浏览器?</summary>
|
||||||
|
<div ml12px class="color-#666">
|
||||||
|
请尝试如下方案之一来处理:
|
||||||
|
<ul pl1em m0>
|
||||||
|
<li>
|
||||||
|
方案一:通过本程序下载 Google Chrome for Testing
|
||||||
|
{{ EXPECT_CHROMIUM_BUILD_ID }} -
|
||||||
|
<a href="javascript:;">点击此处</a
|
||||||
|
>即可下载;这个浏览器由本程序独占,不会影响到当前的 Google Chrome
|
||||||
|
安装。本程序开发过程中主要是使用这个浏览器测试的,<span color-orange
|
||||||
|
>可以保证兼容性</span
|
||||||
|
>。但网络波动,有一定概率下载失败。如多次尝试后确实不能下载成功,请尝试方案二。<span
|
||||||
|
color-orange
|
||||||
|
>(推荐)</span
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
方案二:手动安装 Google Chrome 最新版本 -
|
||||||
|
<a href="javascript:;" @click="handleOpenChromeDownloadPage">点击此处</a>打开
|
||||||
|
Google Chrome
|
||||||
|
官方网站,找到浏览器下载页面来下载安装程序。下载完毕后,执行安装程序。安装完成后,点击上方<a
|
||||||
|
href="javascript:;"
|
||||||
|
@click="autoDetectPuppeteerExecutable"
|
||||||
|
>自动检测</a
|
||||||
|
>按钮再次尝试。目前(2026.2.7)已知 Chrome 最新版本为 144.0.7559.133
|
||||||
|
,多数情况下本程序都可以正常工作,但由于浏览器会自动升级,版本不固定,可能存在<span color-orange
|
||||||
|
>浏览器升级后某些功能不兼容导致本程序不能正确运行</span
|
||||||
|
>的问题。您可以<a href="javascript:;" @click="handleFeedbackClick"
|
||||||
|
>提交 Issue</a
|
||||||
|
>来反馈新版本浏览器不能正常运行的问题,同时请再尝试方法一。
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
<div mt24px>愿你薪想事成</div>
|
<div class="bg-#f8f8f8 pb10px pt10px w-full flex-0">
|
||||||
<div class="h60px mt14px">
|
<div
|
||||||
|
:style="{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'end',
|
||||||
|
width: '80%',
|
||||||
|
margin: '0 auto',
|
||||||
|
paddingLeft: '',
|
||||||
|
paddingRight: ''
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<el-button @click="handleCancel">取消</el-button>
|
||||||
|
<el-button type="primary" @click="handleSave">确定</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- <div class="h60px mt14px">
|
||||||
<RouterView
|
<RouterView
|
||||||
class="h100%"
|
class="h100%"
|
||||||
:dependencies-status="checkDependenciesResult"
|
:dependencies-status="checkDependenciesResult"
|
||||||
:process-waitee="downloadProcessWaitee"
|
:process-waitee="downloadProcessWaitee"
|
||||||
></RouterView>
|
></RouterView>
|
||||||
</div>
|
</div> -->
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { onMounted, ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { sleep } from '@geekgeekrun/utils/sleep.mjs'
|
import debounce from 'lodash/debounce'
|
||||||
import { gtagRenderer } from '@renderer/utils/gtag'
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { gtagRenderer as baseGtagRenderer } from '@renderer/utils/gtag'
|
||||||
|
import { EXPECT_CHROMIUM_BUILD_ID } from '../../../../common/constant'
|
||||||
|
|
||||||
const router = useRouter()
|
const { ipcRenderer } = electron
|
||||||
|
useRouter()
|
||||||
|
// const checkDependenciesResult = ref({})
|
||||||
|
// const downloadProcessWaitee = ref(null)
|
||||||
|
|
||||||
const checkDependenciesResult = ref({})
|
const gtagRenderer = (name, params?: object) => {
|
||||||
const downloadProcessWaitee = ref(null)
|
return baseGtagRenderer(name, {
|
||||||
|
scene: 'cookie-assistant',
|
||||||
|
...params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
const handleOpenChromeDownloadPage = debounce(
|
||||||
checkDependenciesResult.value = await electron.ipcRenderer.invoke('check-dependencies')
|
async () => {
|
||||||
downloadProcessWaitee.value = Promise.withResolvers()
|
gtagRenderer('open_chrome_download_page_clicked')
|
||||||
|
ipcRenderer.send('open-external-link', 'https://www.google.cn/chrome/')
|
||||||
|
},
|
||||||
|
1000,
|
||||||
|
{ leading: true, trailing: false }
|
||||||
|
)
|
||||||
|
|
||||||
if (Object.values(checkDependenciesResult.value).includes(false)) {
|
const formData = ref({
|
||||||
gtagRenderer('dependencies_need_download')
|
browserPath: ''
|
||||||
router.replace('/downloadingDependencies')
|
})
|
||||||
} else {
|
|
||||||
downloadProcessWaitee.value!.resolve()
|
const rules = {
|
||||||
|
browserPath: {
|
||||||
|
validator: (_, value, callback) => {
|
||||||
|
if (!value?.trim()) {
|
||||||
|
callback(new Error('请输入浏览器可执行文件路径'))
|
||||||
|
}
|
||||||
|
// TODO: 检查文件是否存在
|
||||||
|
else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
downloadProcessWaitee.value!.promise.then(async () => {
|
async function autoDetectPuppeteerExecutable() {
|
||||||
const isCookieFileValid = await electron.ipcRenderer.invoke('check-boss-zhipin-cookie-file')
|
const result = await ipcRenderer.invoke('get-any-available-puppeteer-executable', {
|
||||||
if (!isCookieFileValid) {
|
ignoreCached: true,
|
||||||
gtagRenderer('found_cookie_invalid_when_bootstrap')
|
noSave: true
|
||||||
router.replace('/cookieAssistant')
|
})
|
||||||
} else {
|
if (!result) {
|
||||||
await sleep(1000)
|
ElMessage.warning({
|
||||||
router.replace('/main-layout')
|
message: '未检测到可用浏览器的可执行文件',
|
||||||
|
type: 'warning'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
formData.value.browserPath = result.executablePath
|
||||||
|
}
|
||||||
|
|
||||||
|
async function browserExecutableFile() {
|
||||||
|
const chooseResult = await ipcRenderer.invoke('choose-file', {
|
||||||
|
fileChooserConfig: {
|
||||||
|
properties: ['openFile', 'treatPackageAsDirectory'],
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
name: '可执行文件',
|
||||||
|
extensions: (await ipcRenderer.invoke('get-os-platform')) === 'win32' ? ['exe'] : ['']
|
||||||
|
},
|
||||||
|
{ name: '所有文件', extensions: ['*'] }
|
||||||
|
]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
if (chooseResult.canceled || !chooseResult.filePaths?.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
formData.value.browserPath = chooseResult.filePaths[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
ipcRenderer.invoke('get-last-used-and-available-browser').then((res) => {
|
||||||
|
formData.value.browserPath = res?.executablePath ?? ''
|
||||||
})
|
})
|
||||||
|
function handleCancel() {
|
||||||
|
gtagRenderer('cancel_clicked')
|
||||||
|
window.close()
|
||||||
|
}
|
||||||
|
async function handleSave() {
|
||||||
|
await ipcRenderer.invoke('save-last-used-and-available-browser-info', {
|
||||||
|
executablePath: formData.value.browserPath,
|
||||||
|
browser: ''
|
||||||
|
})
|
||||||
|
await ipcRenderer.send('browser-config-saved')
|
||||||
|
}
|
||||||
|
const handleFeedbackClick = () => {
|
||||||
|
gtagRenderer('goto_feedback_for_ba_clicked')
|
||||||
|
electron.ipcRenderer.send('send-feed-back-to-github-issue')
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
a:link,
|
||||||
|
a:visited,
|
||||||
|
a:hover,
|
||||||
|
a:active {
|
||||||
|
color: #409eff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -10,16 +10,27 @@
|
|||||||
<div class="form-wrap geek-auto-start-run-with-boss">
|
<div class="form-wrap geek-auto-start-run-with-boss">
|
||||||
<el-form ref="formRef" :model="formContent" label-position="top" :rules="formRules">
|
<el-form ref="formRef" :model="formContent" label-position="top" :rules="formRules">
|
||||||
<el-card class="config-section">
|
<el-card class="config-section">
|
||||||
<el-form-item>
|
<div flex>
|
||||||
<div>
|
<el-form-item>
|
||||||
<div font-size-16px>BOSS直聘 Cookie</div>
|
<div>
|
||||||
<el-button size="small" type="primary" @click="handleClickLaunchLogin"
|
<div font-size-14px>BOSS直聘 Cookie</div>
|
||||||
>编辑Cookie</el-button
|
<el-button size="small" type="primary" @click="handleClickLaunchLogin"
|
||||||
>
|
>编辑Cookie</el-button
|
||||||
</div>
|
>
|
||||||
</el-form-item>
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
<div w1px class="bg-#dee1e8" ml16px mr16px />
|
||||||
|
<el-form-item>
|
||||||
|
<div>
|
||||||
|
<div font-size-14px>浏览器</div>
|
||||||
|
<el-button size="small" type="primary" @click="handleClickBrowserSetting"
|
||||||
|
>编辑浏览器设置</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div font-size-16px>
|
<div font-size-14px>
|
||||||
摸鱼模式
|
摸鱼模式
|
||||||
<el-tooltip
|
<el-tooltip
|
||||||
effect="light"
|
effect="light"
|
||||||
@@ -51,7 +62,7 @@
|
|||||||
启用摸鱼模式
|
启用摸鱼模式
|
||||||
</el-checkbox>
|
</el-checkbox>
|
||||||
</div>
|
</div>
|
||||||
<div pl-1.5em font-size-14px>
|
<div pl-1.5em font-size-12px>
|
||||||
<div
|
<div
|
||||||
:style="{
|
:style="{
|
||||||
color: formContent.isSageTimeEnabled ? '' : '#aaa'
|
color: formContent.isSageTimeEnabled ? '' : '#aaa'
|
||||||
@@ -1602,6 +1613,20 @@ const handleClickLaunchLogin = async () => {
|
|||||||
//
|
//
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleClickBrowserSetting = async () => {
|
||||||
|
gtagRenderer('browser_setting_clicked')
|
||||||
|
try {
|
||||||
|
await electron.ipcRenderer.invoke('config-with-browser-assistant')
|
||||||
|
ElMessage({
|
||||||
|
type: 'success',
|
||||||
|
message: '浏览器设置保存成功'
|
||||||
|
})
|
||||||
|
} catch {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const expectCompanyTemplateList = [
|
const expectCompanyTemplateList = [
|
||||||
{
|
{
|
||||||
name: '默认值',
|
name: '默认值',
|
||||||
|
|||||||
@@ -7,11 +7,19 @@
|
|||||||
:model="formContent.autoReminder"
|
:model="formContent.autoReminder"
|
||||||
label-position="top"
|
label-position="top"
|
||||||
>
|
>
|
||||||
<el-form-item label="BOSS直聘 Cookie">
|
<div flex>
|
||||||
<el-button size="small" type="primary" @click="handleClickLaunchLogin"
|
<el-form-item label="BOSS直聘 Cookie">
|
||||||
>编辑Cookie</el-button
|
<el-button size="small" type="primary" @click="handleClickLaunchLogin"
|
||||||
>
|
>编辑Cookie</el-button
|
||||||
</el-form-item>
|
>
|
||||||
|
</el-form-item>
|
||||||
|
<div w1px class="bg-#dee1e8" ml16px mr16px />
|
||||||
|
<el-form-item label="浏览器">
|
||||||
|
<el-button size="small" type="primary" @click="handleClickBrowserSetting"
|
||||||
|
>编辑浏览器设置</el-button
|
||||||
|
>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<div>
|
<div>
|
||||||
<el-checkbox v-if="!expectJobTypeRegExpStr?.trim()" :model-value="false" disabled>
|
<el-checkbox v-if="!expectJobTypeRegExpStr?.trim()" :model-value="false" disabled>
|
||||||
@@ -538,6 +546,18 @@ const handleClickLaunchLogin = async () => {
|
|||||||
//
|
//
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const handleClickBrowserSetting = async () => {
|
||||||
|
gtagRenderer('browser_setting_clicked')
|
||||||
|
try {
|
||||||
|
await electron.ipcRenderer.invoke('config-with-browser-assistant')
|
||||||
|
ElMessage({
|
||||||
|
type: 'success',
|
||||||
|
message: '浏览器设置保存成功'
|
||||||
|
})
|
||||||
|
} catch {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const currentStamp = ref(new Date())
|
const currentStamp = ref(new Date())
|
||||||
let timer = 0
|
let timer = 0
|
||||||
|
|||||||
@@ -146,7 +146,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, onUnmounted } from 'vue'
|
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { TopRight, QuestionFilled } from '@element-plus/icons-vue'
|
import { TopRight, QuestionFilled } from '@element-plus/icons-vue'
|
||||||
import useBuildInfo from '@renderer/hooks/useBuildInfo'
|
import useBuildInfo from '@renderer/hooks/useBuildInfo'
|
||||||
@@ -154,23 +153,7 @@ import { debounce } from 'lodash'
|
|||||||
import { gtagRenderer } from '@renderer/utils/gtag'
|
import { gtagRenderer } from '@renderer/utils/gtag'
|
||||||
import { useUpdateStore, useTaskManagerStore } from '../../store/index'
|
import { useUpdateStore, useTaskManagerStore } from '../../store/index'
|
||||||
|
|
||||||
const router = useRouter()
|
useRouter()
|
||||||
const unmountedCbs: Array<InstanceType<typeof Function>> = []
|
|
||||||
onUnmounted(() => {
|
|
||||||
while (unmountedCbs.length) {
|
|
||||||
const fn = unmountedCbs.shift()!
|
|
||||||
try {
|
|
||||||
fn()
|
|
||||||
} catch {}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
;(async () => {
|
|
||||||
const checkDependenciesResult = await electron.ipcRenderer.invoke('check-dependencies')
|
|
||||||
if (Object.values(checkDependenciesResult).includes(false)) {
|
|
||||||
router.replace('/')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
|
|
||||||
const { buildInfo } = useBuildInfo()
|
const { buildInfo } = useBuildInfo()
|
||||||
const handleFeedbackClick = () => {
|
const handleFeedbackClick = () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user