115 lines
3.3 KiB
Vue
115 lines
3.3 KiB
Vue
<template>
|
||
<!-- 导出简历格式选择弹窗 -->
|
||
<el-dialog
|
||
v-model="visible"
|
||
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="visible = 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" mode="export" />
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, computed, nextTick } from 'vue'
|
||
import JobResumeTemplate from '@/components/JobResumeTemplate.vue'
|
||
import type { ResumeTemplateData } from '@/components/JobResumeTemplate.vue'
|
||
import { exportResumePdf, exportResumeWord, loadResumeTemplateData } from '@/utils/resumeExport'
|
||
import { ElMessage } from 'element-plus'
|
||
|
||
// ==================== Props & Emits ====================
|
||
|
||
const props = defineProps<{
|
||
/** 控制弹窗显示/隐藏(v-model) */
|
||
modelValue: boolean
|
||
/** 要导出的简历 ID */
|
||
resumeId: string
|
||
/** 导出文件名(不含扩展名) */
|
||
resumeName?: string
|
||
}>()
|
||
|
||
const emit = defineEmits<{
|
||
(e: 'update:modelValue', value: boolean): void
|
||
}>()
|
||
|
||
// ==================== 弹窗显隐双向绑定 ====================
|
||
|
||
/** 弹窗可见状态 */
|
||
const visible = computed({
|
||
get: () => props.modelValue,
|
||
set: (val: boolean) => emit('update:modelValue', val),
|
||
})
|
||
|
||
// ==================== 导出相关状态 ====================
|
||
|
||
/** 导出格式:pdf 或 word */
|
||
const exportFormat = ref<'pdf' | 'word'>('pdf')
|
||
|
||
/** 导出中状态 */
|
||
const exporting = ref(false)
|
||
|
||
/** 导出用的简历模板数据 */
|
||
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(props.resumeId)
|
||
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 = props.resumeName || '简历'
|
||
|
||
if (exportFormat.value === 'pdf') {
|
||
await exportResumePdf(element, fileName)
|
||
} else {
|
||
exportResumeWord(element, fileName)
|
||
}
|
||
|
||
ElMessage.success('导出成功')
|
||
visible.value = false
|
||
} catch (err) {
|
||
console.error('[导出简历] 失败', err)
|
||
ElMessage.error('导出失败,请稍后重试')
|
||
} finally {
|
||
exporting.value = false
|
||
// 清理隐藏模板数据
|
||
exportTemplateData.value = null
|
||
}
|
||
}
|
||
</script>
|