mirror of
https://github.com/geekgeekrun/geekgeekrun.git
synced 2026-09-05 15:38:46 +08:00
add ui for resume editor
This commit is contained in:
@@ -71,8 +71,12 @@ export const readConfigFile = (fileName) => {
|
|||||||
)
|
)
|
||||||
} catch {
|
} catch {
|
||||||
fs.existsSync(joinedPath) && fs.unlinkSync(joinedPath)
|
fs.existsSync(joinedPath) && fs.unlinkSync(joinedPath)
|
||||||
ensureConfigFileExist()
|
if (defaultConfigFileContentMap[fileName]) {
|
||||||
o = JSON.parse(defaultConfigFileContentMap[fileName])
|
ensureConfigFileExist()
|
||||||
|
o = JSON.parse(defaultConfigFileContentMap[fileName])
|
||||||
|
} else {
|
||||||
|
o = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return o
|
return o
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import { WriteStream } from 'node:fs'
|
|||||||
// eslint-disable-next-line vue/prefer-import-from-vue
|
// eslint-disable-next-line vue/prefer-import-from-vue
|
||||||
import { hasOwn } from '@vue/shared'
|
import { hasOwn } from '@vue/shared'
|
||||||
import { createLlmConfigWindow, llmConfigWindow } from '../../../window/llmConfigWindow'
|
import { createLlmConfigWindow, llmConfigWindow } from '../../../window/llmConfigWindow'
|
||||||
|
import { createResumeEditorWindow, resumeEditorWindow } from '../../../window/resumeEditorWindow'
|
||||||
|
|
||||||
export default function initIpc() {
|
export default function initIpc() {
|
||||||
ipcMain.on('open-external-link', (_, link) => {
|
ipcMain.on('open-external-link', (_, link) => {
|
||||||
@@ -462,6 +463,39 @@ export default function initIpc() {
|
|||||||
})
|
})
|
||||||
ipcMain.on('close-llm-config', () => llmConfigWindow?.close())
|
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', () => {
|
ipcMain.handle('exit-app-immediately', () => {
|
||||||
app.exit(0)
|
app.exit(0)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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!
|
||||||
|
}
|
||||||
@@ -53,6 +53,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<div class="flex flex-items-center">
|
||||||
|
<el-button size="small" type="primary" @click="handleClickEditResume">
|
||||||
|
编辑简历
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item prop="recentMessageQuantityForLlm">
|
<el-form-item prop="recentMessageQuantityForLlm">
|
||||||
<div>
|
<div>
|
||||||
携带最近
|
携带最近
|
||||||
@@ -227,6 +234,14 @@ const handleClickConfigLlm = async () => {
|
|||||||
console.log(err)
|
console.log(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleClickEditResume = async () => {
|
||||||
|
try {
|
||||||
|
await electron.ipcRenderer.invoke('resume-edit')
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
@@ -0,0 +1,460 @@
|
|||||||
|
<template>
|
||||||
|
<div class="resume-editor-page">
|
||||||
|
<div class="main-wrapper">
|
||||||
|
<main>
|
||||||
|
<div class="mt1em mb1em flex flex-items-center flex-justify-between">
|
||||||
|
<span>简历编辑器</span>
|
||||||
|
</div>
|
||||||
|
<el-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="formContent"
|
||||||
|
:rules="formRules"
|
||||||
|
label-position="top"
|
||||||
|
class="resume-editor-form"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
:style="{
|
||||||
|
display: 'grid',
|
||||||
|
gridTemplateColumns: '1fr 1fr 1fr',
|
||||||
|
gap: '10px'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<el-form-item prop="providerCompleteApiUrl" label="姓名">
|
||||||
|
<el-input v-model="formContent.name" font-size-12px></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item prop="providerCompleteApiUrl" label="性别">
|
||||||
|
<el-input v-model="formContent.gender" font-size-12px></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item prop="providerCompleteApiUrl" label="年龄">
|
||||||
|
<el-input-number
|
||||||
|
v-model="formContent.age"
|
||||||
|
w-full
|
||||||
|
font-size-12px
|
||||||
|
:min="0"
|
||||||
|
:max="200"
|
||||||
|
:precision="0"
|
||||||
|
:step="1"
|
||||||
|
></el-input-number>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item prop="providerCompleteApiUrl" label="学历">
|
||||||
|
<el-input v-model="formContent.degree" font-size-12px></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item prop="providerCompleteApiUrl" label="工作年限">
|
||||||
|
<el-input v-model="formContent.workYearDesc" font-size-12px></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item prop="providerCompleteApiUrl" label="期望职位">
|
||||||
|
<el-input v-model="formContent.expectJob" font-size-12px></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-form-item prop="providerCompleteApiUrl" label="个人优势">
|
||||||
|
<el-input
|
||||||
|
v-model="formContent.userDescription"
|
||||||
|
type="textarea"
|
||||||
|
:autosize="{
|
||||||
|
minRows: 6,
|
||||||
|
maxRows: 8
|
||||||
|
}"
|
||||||
|
font-size-12px
|
||||||
|
></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<div class="el-form-item__label">
|
||||||
|
工作经历
|
||||||
|
<el-button size="small" :icon="Plus" @click="addWorkExp">新增一条</el-button>
|
||||||
|
</div>
|
||||||
|
<div v-for="(exp, index) in formContent.geekWorkExpList" :key="index">
|
||||||
|
<div
|
||||||
|
:style="{
|
||||||
|
display: 'flex',
|
||||||
|
gap: '12px'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
:style="{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
gap: '10px',
|
||||||
|
height: 'fit-content',
|
||||||
|
marginTop: '10px'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
:disabled="index <= 0"
|
||||||
|
style="margin: 0"
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
:icon="ArrowUp"
|
||||||
|
@click="moveWorkExpUp(index)"
|
||||||
|
/>
|
||||||
|
<el-button
|
||||||
|
:disabled="index >= formContent.geekWorkExpList.length - 1"
|
||||||
|
style="margin: 0"
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
:icon="ArrowDown"
|
||||||
|
@click="moveWorkExpDown(index)"
|
||||||
|
/>
|
||||||
|
<el-button
|
||||||
|
:disabled="1 >= formContent.geekWorkExpList.length"
|
||||||
|
style="margin: 0"
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
:icon="Delete"
|
||||||
|
@click="removeWorkExp(index)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
:style="{
|
||||||
|
display: 'grid',
|
||||||
|
gridTemplateColumns: '1fr 1.25fr 1fr',
|
||||||
|
gap: '10px',
|
||||||
|
width: '100%'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<el-form-item label="公司名称" style="margin-bottom: 18px">
|
||||||
|
<el-input v-model="exp.company" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="任职时间" style="margin-bottom: 18px">
|
||||||
|
<div
|
||||||
|
:style="{
|
||||||
|
display: 'grid',
|
||||||
|
gridTemplateColumns: '1fr 1fr'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<el-date-picker
|
||||||
|
v-model="exp.startYearMon"
|
||||||
|
:style="{ '--el-date-editor-width': 'auto' }"
|
||||||
|
type="month"
|
||||||
|
placeholder="开始月份"
|
||||||
|
/>
|
||||||
|
<el-date-picker
|
||||||
|
v-model="exp.endYearMon"
|
||||||
|
:style="{ '--el-date-editor-width': 'auto' }"
|
||||||
|
type="month"
|
||||||
|
placeholder="结束月份"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="职务" style="margin-bottom: 18px">
|
||||||
|
<el-input v-model="exp.positionName" />
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
<el-form-item label="工作业绩">
|
||||||
|
<el-input
|
||||||
|
v-model="exp.performance"
|
||||||
|
type="textarea"
|
||||||
|
:autosize="{
|
||||||
|
minRows: 6,
|
||||||
|
maxRows: 8
|
||||||
|
}"
|
||||||
|
font-size-12px
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="index !== formContent.geekWorkExpList.length - 1"
|
||||||
|
class="mt20px mb20px h1px"
|
||||||
|
style="background-color: #dcdcdc"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<div class="el-form-item__label">
|
||||||
|
项目经历
|
||||||
|
<el-button size="small" :icon="Plus" @click="addProjExp">新增一条</el-button>
|
||||||
|
</div>
|
||||||
|
<div v-for="(proj, index) in formContent.geekProjExpList" :key="index">
|
||||||
|
<div
|
||||||
|
:style="{
|
||||||
|
display: 'flex',
|
||||||
|
gap: '12px'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
:style="{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
gap: '10px',
|
||||||
|
height: 'fit-content',
|
||||||
|
marginTop: '10px'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
:disabled="index <= 0"
|
||||||
|
style="margin: 0"
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
:icon="ArrowUp"
|
||||||
|
@click="moveProjExpUp(index)"
|
||||||
|
/>
|
||||||
|
<el-button
|
||||||
|
:disabled="index >= formContent.geekProjExpList.length - 1"
|
||||||
|
style="margin: 0"
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
:icon="ArrowDown"
|
||||||
|
@click="moveProjExpDown(index)"
|
||||||
|
/>
|
||||||
|
<el-button
|
||||||
|
:disabled="1 >= formContent.geekProjExpList.length"
|
||||||
|
style="margin: 0"
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
:icon="Delete"
|
||||||
|
@click="removeProjExp(index)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
:style="{
|
||||||
|
display: 'grid',
|
||||||
|
gridTemplateColumns: '1fr 1fr 1.25fr',
|
||||||
|
gap: '10px',
|
||||||
|
width: '100%'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<el-form-item label="项目名称" style="margin-bottom: 18px">
|
||||||
|
<el-input v-model="proj.name" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="项目角色" style="margin-bottom: 18px">
|
||||||
|
<el-input v-model="proj.roleName" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="项目时间" style="margin-bottom: 18px">
|
||||||
|
<div
|
||||||
|
:style="{
|
||||||
|
display: 'grid',
|
||||||
|
gridTemplateColumns: '1fr 1fr'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<el-date-picker
|
||||||
|
v-model="proj.startYearMon"
|
||||||
|
:style="{ '--el-date-editor-width': 'auto' }"
|
||||||
|
type="month"
|
||||||
|
placeholder="开始月份"
|
||||||
|
/>
|
||||||
|
<el-date-picker
|
||||||
|
v-model="proj.endYearMon"
|
||||||
|
:style="{ '--el-date-editor-width': 'auto' }"
|
||||||
|
type="month"
|
||||||
|
placeholder="结束月份"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
<el-form-item label="项目业绩">
|
||||||
|
<el-input
|
||||||
|
v-model="proj.performance"
|
||||||
|
type="textarea"
|
||||||
|
:autosize="{
|
||||||
|
minRows: 6,
|
||||||
|
maxRows: 8
|
||||||
|
}"
|
||||||
|
font-size-12px
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="index !== formContent.geekProjExpList.length - 1"
|
||||||
|
class="mt20px mb20px h1px"
|
||||||
|
style="background-color: #dcdcdc"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
<footer flex pt10px pb10px pr20px flex-justify-between>
|
||||||
|
<div>
|
||||||
|
<!-- <el-button type="text" @click="handleTestAvailability">测试可用性</el-button> -->
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<el-button @click="handleCancel">取消</el-button>
|
||||||
|
<el-button type="primary" @click="handleSubmit">确定</el-button>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ElForm, ElButton } from 'element-plus'
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
import { ArrowUp, ArrowDown, Delete, Plus } from '@element-plus/icons-vue'
|
||||||
|
|
||||||
|
interface ResumeContent {
|
||||||
|
name: string
|
||||||
|
gender: string
|
||||||
|
age: string
|
||||||
|
degree: string
|
||||||
|
workYearDesc: string
|
||||||
|
expectJob: string
|
||||||
|
userDescription: string
|
||||||
|
geekWorkExpList: Array<{
|
||||||
|
company: string
|
||||||
|
positionName: string
|
||||||
|
startYearMon: string | null
|
||||||
|
endYearMon: string | null
|
||||||
|
performance: string
|
||||||
|
}>
|
||||||
|
geekProjExpList: Array<{
|
||||||
|
name: string
|
||||||
|
startYearMon: string
|
||||||
|
endYearMon: string
|
||||||
|
roleName: string
|
||||||
|
projectDescription: string
|
||||||
|
performance: string
|
||||||
|
}>
|
||||||
|
}
|
||||||
|
|
||||||
|
const formRef = ref<InstanceType<typeof ElForm>>()
|
||||||
|
|
||||||
|
const getEmptyFormContent = () => {
|
||||||
|
const o: any = {
|
||||||
|
age: '',
|
||||||
|
degree: '',
|
||||||
|
expectJob: '',
|
||||||
|
gender: '',
|
||||||
|
name: '',
|
||||||
|
userDescription: '',
|
||||||
|
workYearDesc: '',
|
||||||
|
geekWorkExpList: [],
|
||||||
|
geekProjExpList: []
|
||||||
|
}
|
||||||
|
o.geekProjExpList = [getNewProjExpItem()]
|
||||||
|
o.geekWorkExpList = [getNewWorkExpItem()]
|
||||||
|
|
||||||
|
return o as ResumeContent
|
||||||
|
}
|
||||||
|
const formContent = ref<ResumeContent>(getEmptyFormContent())
|
||||||
|
|
||||||
|
const formRules = {}
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
electron.ipcRenderer.send('close-resume-editor')
|
||||||
|
}
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
electron.ipcRenderer.invoke('save-resume-content', JSON.parse(JSON.stringify(formContent.value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
try {
|
||||||
|
const savedFileContent = await electron.ipcRenderer.invoke('fetch-resume-content')
|
||||||
|
if (!savedFileContent) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for (const k of Object.keys(formContent.value)) {
|
||||||
|
formContent.value[k] = savedFileContent[k]
|
||||||
|
}
|
||||||
|
if (!formContent.value.geekProjExpList?.length) {
|
||||||
|
formContent.value.geekProjExpList = [getNewProjExpItem()]
|
||||||
|
}
|
||||||
|
if (!formContent.value.geekWorkExpList?.length) {
|
||||||
|
formContent.value.geekWorkExpList = [getNewWorkExpItem()]
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
formContent.value = getEmptyFormContent()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// function handlePresetClick(selected: (typeof llmPresetList)[number]) {}
|
||||||
|
|
||||||
|
// #region edit work exp list
|
||||||
|
function getNewWorkExpItem() {
|
||||||
|
return {
|
||||||
|
company: '',
|
||||||
|
endYearMon: '',
|
||||||
|
positionName: '',
|
||||||
|
startYearMon: '',
|
||||||
|
performance: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function addWorkExp() {
|
||||||
|
formContent.value.geekWorkExpList.push(getNewWorkExpItem())
|
||||||
|
}
|
||||||
|
function moveWorkExpUp(index) {
|
||||||
|
;[formContent.value.geekWorkExpList[index], formContent.value.geekWorkExpList[index - 1]] = [
|
||||||
|
formContent.value.geekWorkExpList[index - 1],
|
||||||
|
formContent.value.geekWorkExpList[index]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
function moveWorkExpDown(index) {
|
||||||
|
;[formContent.value.geekWorkExpList[index], formContent.value.geekWorkExpList[index + 1]] = [
|
||||||
|
formContent.value.geekWorkExpList[index + 1],
|
||||||
|
formContent.value.geekWorkExpList[index]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeWorkExp(index) {
|
||||||
|
formContent.value.geekWorkExpList.splice(index, 1)
|
||||||
|
}
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region edit proj list
|
||||||
|
function getNewProjExpItem() {
|
||||||
|
return {
|
||||||
|
name: '',
|
||||||
|
endYearMon: '',
|
||||||
|
roleName: '',
|
||||||
|
startYearMon: '',
|
||||||
|
performance: '',
|
||||||
|
projectDescription: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function addProjExp() {
|
||||||
|
formContent.value.geekProjExpList.push(getNewProjExpItem())
|
||||||
|
}
|
||||||
|
function moveProjExpUp(index) {
|
||||||
|
;[formContent.value.geekProjExpList[index], formContent.value.geekProjExpList[index - 1]] = [
|
||||||
|
formContent.value.geekProjExpList[index - 1],
|
||||||
|
formContent.value.geekProjExpList[index]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
function moveProjExpDown(index) {
|
||||||
|
;[formContent.value.geekProjExpList[index], formContent.value.geekProjExpList[index + 1]] = [
|
||||||
|
formContent.value.geekProjExpList[index + 1],
|
||||||
|
formContent.value.geekProjExpList[index]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeProjExp(index) {
|
||||||
|
formContent.value.geekProjExpList.splice(index, 1)
|
||||||
|
}
|
||||||
|
// #endregion
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.resume-editor-page {
|
||||||
|
margin: 0 auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100vh;
|
||||||
|
.main-wrapper {
|
||||||
|
overflow: auto;
|
||||||
|
main {
|
||||||
|
margin: 0 auto;
|
||||||
|
max-width: 768px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
footer {
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.resume-editor-form.el-form {
|
||||||
|
.el-form-item__error--inline {
|
||||||
|
margin-left: 0;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -23,6 +23,13 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
title: '大语言模型设置'
|
title: '大语言模型设置'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/resumeEditor',
|
||||||
|
component: () => import('@renderer/page/ResumeEditor/index.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '简历编辑'
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/main-layout',
|
path: '/main-layout',
|
||||||
component: () => import('@renderer/page/MainLayout/index.vue'),
|
component: () => import('@renderer/page/MainLayout/index.vue'),
|
||||||
|
|||||||
Reference in New Issue
Block a user