AI助手和Nova助手
This commit is contained in:
+131
-8
@@ -73,15 +73,53 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 编辑简历名称弹窗 -->
|
||||
<ResumeEditNameDialog
|
||||
v-model="editNameVisible"
|
||||
:resume-id="editResumeId"
|
||||
:resume-name="editResumeName"
|
||||
:target-position="editTargetPosition"
|
||||
@saved="loadResumeList"
|
||||
/>
|
||||
|
||||
<!-- 导出简历格式选择弹窗 -->
|
||||
<el-dialog
|
||||
v-model="exportDialogVisible"
|
||||
title="导出简历"
|
||||
width="3.6rem"
|
||||
:close-on-click-modal="false"
|
||||
class="resume-export-dialog"
|
||||
>
|
||||
<!-- 格式选择 -->
|
||||
<el-radio-group v-model="exportFormat" class="resume-export-dialog__radio-group">
|
||||
<el-radio value="pdf">PDF 简历</el-radio>
|
||||
<el-radio value="word">Word 简历</el-radio>
|
||||
</el-radio-group>
|
||||
<template #footer>
|
||||
<el-button @click="exportDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="exporting" @click="doExport">下载</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 隐藏的简历模板,用于导出时渲染DOM -->
|
||||
<div v-if="exportTemplateData" style="position:absolute;left:-9999px;top:0;">
|
||||
<JobResumeTemplate ref="exportTemplateRef" :resume-data="exportTemplateData" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { ref, onMounted, nextTick } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import SideNav from '@/components/SideNav.vue'
|
||||
import ResumeEditNameDialog from '@/components/ResumeEditNameDialog.vue'
|
||||
import JobResumeTemplate from '@/components/JobResumeTemplate.vue'
|
||||
import type { ResumeTemplateData } from '@/components/JobResumeTemplate.vue'
|
||||
import { exportResumePdf, exportResumeWord, loadResumeTemplateData } from '@/utils/resumeExport'
|
||||
import { uploadResume } from '@/utils/aiRequest'
|
||||
import { fetchResumeList, deleteResume, type ResumeListItem } from '@/api/resume'
|
||||
import {
|
||||
fetchResumeList, deleteResume, type ResumeListItem,
|
||||
} from '@/api/resume'
|
||||
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus'
|
||||
// ElLoading.service() 是命令式调用,按需引入插件不会自动加载其样式,需手动引入
|
||||
import 'element-plus/es/components/loading/style/css'
|
||||
@@ -110,12 +148,12 @@ interface ResumeItem {
|
||||
// ==================== 工具方法 ====================
|
||||
|
||||
/**
|
||||
* 将 Instant 时间戳转为友好的相对时间文案
|
||||
* @param instant 后端返回的 Instant 对象
|
||||
* 将毫秒时间戳转为友好的相对时间文案
|
||||
* @param timestamp 后端返回的毫秒级时间戳
|
||||
*/
|
||||
function formatTime(instant?: { seconds?: number; nanos?: number }): string {
|
||||
if (!instant?.seconds) return '-'
|
||||
const date = new Date(instant.seconds * 1000)
|
||||
function formatTime(timestamp?: number): string {
|
||||
if (!timestamp) return '-'
|
||||
const date = new Date(timestamp)
|
||||
const now = Date.now()
|
||||
const diff = now - date.getTime()
|
||||
const minutes = Math.floor(diff / 60000)
|
||||
@@ -175,8 +213,78 @@ onMounted(() => {
|
||||
/** 当前打开弹出菜单的简历 ID */
|
||||
const activeMenuId = ref<string | null>(null)
|
||||
|
||||
// ==================== 编辑简历名称弹窗状态 ====================
|
||||
|
||||
/** 编辑弹窗是否可见 */
|
||||
const editNameVisible = ref(false)
|
||||
/** 当前编辑的简历 ID */
|
||||
const editResumeId = ref('')
|
||||
/** 当前编辑的简历名称 */
|
||||
const editResumeName = ref('')
|
||||
/** 当前编辑的目标岗位 */
|
||||
const editTargetPosition = ref('')
|
||||
|
||||
// ==================== 导出简历弹窗状态 ====================
|
||||
|
||||
/** 导出弹窗是否可见 */
|
||||
const exportDialogVisible = ref(false)
|
||||
/** 导出格式:pdf 或 word */
|
||||
const exportFormat = ref<'pdf' | 'word'>('pdf')
|
||||
/** 导出中状态 */
|
||||
const exporting = ref(false)
|
||||
/** 当前导出的简历 ID */
|
||||
const exportResumeId = ref('')
|
||||
/** 当前导出的简历名称(用于文件名) */
|
||||
const exportResumeName = ref('')
|
||||
/** 导出用的简历模板数据 */
|
||||
const exportTemplateData = ref<ResumeTemplateData | null>(null)
|
||||
/** 导出用的简历模板组件引用 */
|
||||
const exportTemplateRef = ref<InstanceType<typeof JobResumeTemplate> | null>(null)
|
||||
|
||||
/** 执行导出下载 */
|
||||
async function doExport() {
|
||||
exporting.value = true
|
||||
try {
|
||||
// 1. 加载简历完整数据
|
||||
const data = await loadResumeTemplateData(exportResumeId.value)
|
||||
if (!data) {
|
||||
ElMessage.error('获取简历数据失败')
|
||||
return
|
||||
}
|
||||
|
||||
// 2. 设置模板数据,等待DOM渲染
|
||||
exportTemplateData.value = data
|
||||
await nextTick()
|
||||
|
||||
// 3. 获取渲染后的DOM
|
||||
const element = exportTemplateRef.value?.resumeRef
|
||||
if (!element) {
|
||||
ElMessage.error('简历模板渲染失败')
|
||||
return
|
||||
}
|
||||
|
||||
const fileName = exportResumeName.value || '简历'
|
||||
|
||||
if (exportFormat.value === 'pdf') {
|
||||
await exportResumePdf(element, fileName)
|
||||
} else {
|
||||
exportResumeWord(element, fileName)
|
||||
}
|
||||
|
||||
ElMessage.success('导出成功')
|
||||
exportDialogVisible.value = false
|
||||
} catch (err) {
|
||||
console.error('[导出简历] 失败', err)
|
||||
ElMessage.error('导出失败,请稍后重试')
|
||||
} finally {
|
||||
exporting.value = false
|
||||
// 清理隐藏模板数据
|
||||
exportTemplateData.value = null
|
||||
}
|
||||
}
|
||||
|
||||
/** 弹出菜单操作项 */
|
||||
const popupActions = ['设为默认简历', '编辑', '导出简历', '删除']
|
||||
const popupActions = ['设为默认简历', '编辑名称岗位', '导出简历', '删除']
|
||||
|
||||
// ==================== 事件处理 ====================
|
||||
|
||||
@@ -213,6 +321,21 @@ async function handleAction(action: string, id: string) {
|
||||
ElMessage.error('删除失败,请稍后重试')
|
||||
}
|
||||
}
|
||||
} else if (action === '编辑名称岗位') {
|
||||
// 找到当前简历数据,打开编辑弹窗
|
||||
const target = resumeList.value.find(r => r.id === id)
|
||||
if (target) {
|
||||
editResumeId.value = id
|
||||
editResumeName.value = target.name
|
||||
editTargetPosition.value = target.targetJob
|
||||
editNameVisible.value = true
|
||||
}
|
||||
} else if (action === '导出简历') {
|
||||
// 打开导出格式选择弹窗
|
||||
exportResumeId.value = id
|
||||
const target = resumeList.value.find(r => r.id === id)
|
||||
exportResumeName.value = target?.name || '简历'
|
||||
exportDialogVisible.value = true
|
||||
} else {
|
||||
console.log(action, id)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user