fix(admin): 修复简历附件下载问题,完善简历信息展示
This commit is contained in:
parent
fbcd98dc46
commit
1ec8734401
|
|
@ -22,11 +22,18 @@ class Resume(models.Model):
|
|||
|
||||
def to_snapshot(self):
|
||||
"""序列化为投递快照,与主表解耦"""
|
||||
attachment_url = None
|
||||
if self.attachment:
|
||||
# 返回相对 URL,前端会处理
|
||||
attachment_url = self.attachment.url
|
||||
|
||||
return {
|
||||
'name': self.name,
|
||||
'gender': self.gender,
|
||||
'birthday': str(self.birthday) if self.birthday else None,
|
||||
'education': self.education,
|
||||
'experience': self.experience,
|
||||
'attachment_url': self.attachment.url if self.attachment else None,
|
||||
'email': self.user.email,
|
||||
'phone': self.user.phone,
|
||||
'attachment_url': attachment_url,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,16 +25,70 @@
|
|||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-dialog v-model="resumeVisible" title="简历详情" width="600px">
|
||||
<div v-if="currentResume">
|
||||
<p><strong>姓名:</strong>{{ currentResume.name }}</p>
|
||||
<p><strong>性别:</strong>{{ currentResume.gender }}</p>
|
||||
<el-divider>教育经历</el-divider>
|
||||
<div v-for="(e, i) in currentResume.education" :key="i">{{ e.school }} · {{ e.degree }} · {{ e.major }}</div>
|
||||
<el-divider>工作经历</el-divider>
|
||||
<div v-for="(e, i) in currentResume.experience" :key="i">{{ e.company }} · {{ e.position }} · {{ e.duration }}</div>
|
||||
<div v-if="currentResume.attachment_url" style="margin-top:16px">
|
||||
<a :href="currentResume.attachment_url" target="_blank">下载简历附件</a>
|
||||
<el-dialog v-model="resumeVisible" title="简历详情" width="700px">
|
||||
<div v-if="currentResume" class="resume-detail">
|
||||
<!-- 基本信息 -->
|
||||
<div class="section">
|
||||
<div class="section-title">基本信息</div>
|
||||
<div class="info-grid">
|
||||
<div class="info-item">
|
||||
<span class="label">姓名:</span>
|
||||
<span class="value">{{ currentResume.name || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">性别:</span>
|
||||
<span class="value">{{ getGenderLabel(currentResume.gender) }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">邮箱:</span>
|
||||
<span class="value">{{ currentResume.email || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">手机:</span>
|
||||
<span class="value">{{ currentResume.phone || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">生日:</span>
|
||||
<span class="value">{{ currentResume.birthday || '-' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 教育经历 -->
|
||||
<div class="section">
|
||||
<div class="section-title">教育经历</div>
|
||||
<div v-if="currentResume.education?.length" class="list-items">
|
||||
<div v-for="(e, i) in currentResume.education" :key="i" class="list-item">
|
||||
<div class="item-header">{{ e.school }}</div>
|
||||
<div class="item-detail">{{ e.degree }} · {{ e.major }}</div>
|
||||
<div class="item-detail">{{ e.start_year }} - {{ e.end_year }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else style="color: #999; font-size: 12px;">暂无教育经历</div>
|
||||
</div>
|
||||
|
||||
<!-- 工作经历 -->
|
||||
<div class="section">
|
||||
<div class="section-title">工作经历</div>
|
||||
<div v-if="currentResume.experience?.length" class="list-items">
|
||||
<div v-for="(e, i) in currentResume.experience" :key="i" class="list-item">
|
||||
<div class="item-header">{{ e.company }} - {{ e.position }}</div>
|
||||
<div class="item-detail">{{ e.duration }}</div>
|
||||
<div class="item-detail" v-if="e.description">{{ e.description }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else style="color: #999; font-size: 12px;">暂无工作经历</div>
|
||||
</div>
|
||||
|
||||
<!-- 附件 -->
|
||||
<div class="section" v-if="currentResume.attachment_url">
|
||||
<div class="section-title">附件</div>
|
||||
<div style="margin-top: 8px;">
|
||||
<el-button type="primary" @click="downloadAttachment">
|
||||
<el-icon><Download /></el-icon>
|
||||
下载简历附件
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
|
@ -44,12 +98,20 @@
|
|||
import { ref, onMounted } from 'vue'
|
||||
import { getManageApplications, updateApplicationStatus } from '@/api/applications'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { Download } from '@element-plus/icons-vue'
|
||||
|
||||
const applications = ref([])
|
||||
const loading = ref(false)
|
||||
const resumeVisible = ref(false)
|
||||
const currentResume = ref(null)
|
||||
|
||||
const genderMap = {
|
||||
'male': '男',
|
||||
'female': '女',
|
||||
'other': '其他',
|
||||
'': '-'
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
loading.value = true
|
||||
const { data } = await getManageApplications()
|
||||
|
|
@ -68,4 +130,87 @@ function viewResume(row) {
|
|||
currentResume.value = row.resume_snapshot
|
||||
resumeVisible.value = true
|
||||
}
|
||||
|
||||
function getGenderLabel(gender) {
|
||||
return genderMap[gender] || '-'
|
||||
}
|
||||
|
||||
function downloadAttachment() {
|
||||
if (!currentResume.value?.attachment_url) {
|
||||
ElMessage.warning('附件不可用')
|
||||
return
|
||||
}
|
||||
const link = document.createElement('a')
|
||||
link.href = currentResume.value.attachment_url
|
||||
link.download = `${currentResume.value.name}_resume`
|
||||
link.style.display = 'none'
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
ElMessage.success('下载已启动')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.section {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #1a1a2e;
|
||||
margin-bottom: 12px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.info-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 12px 16px;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.info-item .label {
|
||||
color: #666;
|
||||
min-width: 50px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.info-item .value {
|
||||
color: #333;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.list-items {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.list-item {
|
||||
padding: 12px;
|
||||
background: #f9f9f9;
|
||||
border-radius: 4px;
|
||||
border-left: 3px solid #409eff;
|
||||
}
|
||||
|
||||
.item-header {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: #1a1a2e;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.item-detail {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@ export default defineConfig({
|
|||
},
|
||||
server: {
|
||||
proxy: {
|
||||
'/api': { target: 'http://127.0.0.1:8000', changeOrigin: true }
|
||||
'/api': { target: 'http://127.0.0.1:8000', changeOrigin: true },
|
||||
'/media': { target: 'http://127.0.0.1:8000', changeOrigin: true }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in New Issue