From c40fbde5b2e3afd715d53019237c895cd9045e89 Mon Sep 17 00:00:00 2001 From: geekgeekrun Date: Thu, 10 Apr 2025 02:39:34 +0800 Subject: [PATCH] add ui for resume editor --- .../runtime-file-utils.mjs | 8 +- .../flow/OPEN_SETTING_WINDOW/ipc/index.ts | 34 ++ .../ui/src/main/window/resumeEditorWindow.ts | 45 ++ .../page/MainLayout/ReadNoReplyReminder.vue | 15 + .../renderer/src/page/ResumeEditor/index.vue | 460 ++++++++++++++++++ packages/ui/src/renderer/src/router/index.ts | 7 + 6 files changed, 567 insertions(+), 2 deletions(-) create mode 100644 packages/ui/src/main/window/resumeEditorWindow.ts create mode 100644 packages/ui/src/renderer/src/page/ResumeEditor/index.vue diff --git a/packages/geek-auto-start-chat-with-boss/runtime-file-utils.mjs b/packages/geek-auto-start-chat-with-boss/runtime-file-utils.mjs index 65d8780..83c9756 100644 --- a/packages/geek-auto-start-chat-with-boss/runtime-file-utils.mjs +++ b/packages/geek-auto-start-chat-with-boss/runtime-file-utils.mjs @@ -71,8 +71,12 @@ export const readConfigFile = (fileName) => { ) } catch { fs.existsSync(joinedPath) && fs.unlinkSync(joinedPath) - ensureConfigFileExist() - o = JSON.parse(defaultConfigFileContentMap[fileName]) + if (defaultConfigFileContentMap[fileName]) { + ensureConfigFileExist() + o = JSON.parse(defaultConfigFileContentMap[fileName]) + } else { + o = null + } } return o diff --git a/packages/ui/src/main/flow/OPEN_SETTING_WINDOW/ipc/index.ts b/packages/ui/src/main/flow/OPEN_SETTING_WINDOW/ipc/index.ts index 72c03c4..1b59306 100644 --- a/packages/ui/src/main/flow/OPEN_SETTING_WINDOW/ipc/index.ts +++ b/packages/ui/src/main/flow/OPEN_SETTING_WINDOW/ipc/index.ts @@ -31,6 +31,7 @@ import { WriteStream } from 'node:fs' // eslint-disable-next-line vue/prefer-import-from-vue import { hasOwn } from '@vue/shared' import { createLlmConfigWindow, llmConfigWindow } from '../../../window/llmConfigWindow' +import { createResumeEditorWindow, resumeEditorWindow } from '../../../window/resumeEditorWindow' export default function initIpc() { ipcMain.on('open-external-link', (_, link) => { @@ -462,6 +463,39 @@ export default function initIpc() { }) ipcMain.on('close-llm-config', () => llmConfigWindow?.close()) + ipcMain.handle('resume-edit', async () => { + createResumeEditorWindow({ + parent: mainWindow!, + modal: true, + show: true + }) + const defer = Promise.withResolvers() + async function saveResumeHandler(_, resumeContent) { + await writeConfigFile('resumes.json', [ + { + name: '默认简历', + updateTime: Number(new Date()), + content: resumeContent + } + ]) + defer.resolve() + resumeEditorWindow?.close() + } + ipcMain.handle('save-resume-content', saveResumeHandler) + resumeEditorWindow?.once('closed', () => { + ipcMain.removeHandler('save-resume-content') + ipcMain.removeHandler('fetch-resume-content') + defer.reject(new Error('cancel')) + }) + + ipcMain.handle('fetch-resume-content', async () => { + const res = (await readConfigFile('resumes.json'))?.[0] + return res?.content ?? null + }) + return defer.promise + }) + ipcMain.on('close-resume-editor', () => resumeEditorWindow?.close()) + ipcMain.handle('exit-app-immediately', () => { app.exit(0) }) diff --git a/packages/ui/src/main/window/resumeEditorWindow.ts b/packages/ui/src/main/window/resumeEditorWindow.ts new file mode 100644 index 0000000..3ccb453 --- /dev/null +++ b/packages/ui/src/main/window/resumeEditorWindow.ts @@ -0,0 +1,45 @@ +import { BrowserWindow, ipcMain } from 'electron' +import path from 'path' + +export let resumeEditorWindow: BrowserWindow | null = null +export function createResumeEditorWindow( + opt?: Electron.BrowserWindowConstructorOptions +): BrowserWindow { + // Create the browser window. + if (resumeEditorWindow) { + resumeEditorWindow!.show() + } + resumeEditorWindow = new BrowserWindow({ + width: 960, + height: 720, + resizable: true, + show: false, + autoHideMenuBar: true, + // frame: false, + webPreferences: { + preload: path.join(__dirname, '../preload/index.js'), + sandbox: false + }, + ...opt + }) + + resumeEditorWindow.on('ready-to-show', () => { + resumeEditorWindow!.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']) { + resumeEditorWindow.loadURL(process.env['ELECTRON_RENDERER_URL'] + '#/resumeEditor') + } else { + resumeEditorWindow.loadURL( + 'file://' + path.join(__dirname, '../renderer/index.html') + '#/resumeEditor' + ) + } + + resumeEditorWindow!.once('closed', () => { + resumeEditorWindow = null + }) + + return resumeEditorWindow! +} diff --git a/packages/ui/src/renderer/src/page/MainLayout/ReadNoReplyReminder.vue b/packages/ui/src/renderer/src/page/MainLayout/ReadNoReplyReminder.vue index 7591df4..ba25c6f 100644 --- a/packages/ui/src/renderer/src/page/MainLayout/ReadNoReplyReminder.vue +++ b/packages/ui/src/renderer/src/page/MainLayout/ReadNoReplyReminder.vue @@ -53,6 +53,13 @@ + +
+ + 编辑简历 + +
+
携带最近 @@ -227,6 +234,14 @@ const handleClickConfigLlm = async () => { console.log(err) } } + +const handleClickEditResume = async () => { + try { + await electron.ipcRenderer.invoke('resume-edit') + } catch (err) { + console.log(err) + } +} + + diff --git a/packages/ui/src/renderer/src/router/index.ts b/packages/ui/src/renderer/src/router/index.ts index a3a1726..8b4dc97 100644 --- a/packages/ui/src/renderer/src/router/index.ts +++ b/packages/ui/src/renderer/src/router/index.ts @@ -23,6 +23,13 @@ const routes: Array = [ title: '大语言模型设置' } }, + { + path: '/resumeEditor', + component: () => import('@renderer/page/ResumeEditor/index.vue'), + meta: { + title: '简历编辑' + } + }, { path: '/main-layout', component: () => import('@renderer/page/MainLayout/index.vue'),