wuzhen updat
This commit is contained in:
1 parent
3e4642c624
commit
e4e4679da9
173 files changed
+37924
-325
No files matched your search
@@ -0,0 +1,461 @@
|
||||
<template>
|
||||
<div class="poster-preview">
|
||||
<!-- 海报画布容器 -->
|
||||
<div
|
||||
ref="posterRef"
|
||||
class="poster-canvas"
|
||||
:style="canvasStyle"
|
||||
>
|
||||
<!-- 企业信息叠加 -->
|
||||
<div class="info-overlay">
|
||||
<!-- 顶部企业标题 -->
|
||||
<div class="company-header">
|
||||
<h1 class="company-name">{{ posterData.enterpriseName }}</h1>
|
||||
<div class="company-tagline">诚聘英才 · 共创未来</div>
|
||||
</div>
|
||||
|
||||
<!-- 中间内容区域 - 根据海报类型显示不同内容 -->
|
||||
|
||||
<!-- 企业海报:展示企业文化和优势 -->
|
||||
<div v-if="posterData.posterType === '1'" class="position-info">
|
||||
<div class="position-title">加入我们 · 共创辉煌</div>
|
||||
<div v-if="enterpriseDetail" class="position-details">
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<div class="detail-item" v-if="enterpriseDetail.mainBusiness">
|
||||
<span class="icon">🏢</span>
|
||||
<span>{{ enterpriseDetail.mainBusiness }}</span>
|
||||
</div>
|
||||
<div class="detail-item" v-if="enterpriseDetail.enterpriseScale">
|
||||
<span class="icon">👥</span>
|
||||
<span>{{ getScaleLabel(enterpriseDetail.enterpriseScale) }}</span>
|
||||
</div>
|
||||
<div class="detail-item" v-if="enterpriseDetail.address">
|
||||
<span class="icon">📍</span>
|
||||
<span>{{ enterpriseDetail.address }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 岗位海报:展示具体岗位信息 -->
|
||||
<div v-else-if="posterData.posterType === '2'" class="position-info">
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<div class="position-title">
|
||||
{{ posterData.positionName || positionDetail?.positionName || '招聘岗位' }}
|
||||
</div>
|
||||
<div v-if="positionDetail && Object.keys(positionDetail).length > 0" class="position-details">
|
||||
<div class="position-details-grid">
|
||||
<div class="detail-item" v-if="positionDetail.workAddress">
|
||||
<span class="icon">📍</span>
|
||||
<span>{{ positionDetail.workAddress }}</span>
|
||||
</div>
|
||||
<div class="detail-item" v-if="positionDetail.salary">
|
||||
<span class="icon">💰</span>
|
||||
<span>{{ positionDetail.salary }}</span>
|
||||
</div>
|
||||
<div class="detail-item" v-if="positionDetail.workTime">
|
||||
<span class="icon">⏰</span>
|
||||
<span>{{ positionDetail.workTime }}</span>
|
||||
</div>
|
||||
<div class="detail-item" v-if="positionDetail.requiredSkills">
|
||||
<span class="icon">🎯</span>
|
||||
<span>{{ positionDetail.requiredSkills }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 如果没有岗位详情,显示提示 -->
|
||||
<div v-else class="position-details">
|
||||
<div class="detail-item">
|
||||
<span class="icon">💼</span>
|
||||
<span>岗位详情加载中或暂无数据</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部联系信息 - 根据海报类型显示不同内容 -->
|
||||
<div class="company-footer">
|
||||
<div v-if="enterpriseDetail" class="company-info">
|
||||
|
||||
<!-- 企业海报:重点显示联系方式 -->
|
||||
<template v-if="posterData.posterType === '1'">
|
||||
<div class="info-row" v-if="enterpriseDetail.contactPhone">
|
||||
<span class="label">📞 联系电话:</span>
|
||||
<span class="value">{{ enterpriseDetail.contactPhone }}</span>
|
||||
</div>
|
||||
<div class="info-row" v-if="enterpriseDetail.email">
|
||||
<span class="label">📧 电子邮箱:</span>
|
||||
<span class="value">{{ enterpriseDetail.email }}</span>
|
||||
</div>
|
||||
<div class="info-row" v-if="enterpriseDetail.address">
|
||||
<span class="label">🏢 公司地址:</span>
|
||||
<span class="value">{{ enterpriseDetail.address }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 岗位海报:显示企业背景信息 -->
|
||||
<template v-else-if="posterData.posterType === '2'">
|
||||
<div class="info-row" v-if="enterpriseDetail.mainBusiness">
|
||||
<span class="label">主营业务:</span>
|
||||
<span class="value">{{ enterpriseDetail.mainBusiness }}</span>
|
||||
</div>
|
||||
<div class="info-row" v-if="enterpriseDetail.enterpriseScale">
|
||||
<span class="label">企业规模:</span>
|
||||
<span class="value">{{ getScaleLabel(enterpriseDetail.enterpriseScale) }}</span>
|
||||
</div>
|
||||
<div class="info-row" v-if="enterpriseDetail.contactPhone">
|
||||
<span class="label">联系电话:</span>
|
||||
<span class="value">{{ enterpriseDetail.contactPhone }}</span>
|
||||
</div>
|
||||
<div class="info-row" v-if="enterpriseDetail.email">
|
||||
<span class="label">电子邮箱:</span>
|
||||
<span class="value">{{ enterpriseDetail.email }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div class="action-buttons">
|
||||
<el-button type="primary" icon="Download" @click="exportToPDF" :loading="exporting">
|
||||
导出PDF
|
||||
</el-button>
|
||||
<el-button icon="Picture" @click="exportToImage" :loading="exporting">
|
||||
导出图片
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import html2canvas from 'html2canvas'
|
||||
import jsPDF from 'jspdf'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
// 定义接口
|
||||
interface PosterData {
|
||||
posterPath: string
|
||||
enterpriseName: string
|
||||
positionName?: string
|
||||
posterType: string
|
||||
}
|
||||
|
||||
interface EnterpriseDetail {
|
||||
mainBusiness?: string
|
||||
enterpriseScale?: string
|
||||
contactPhone?: string
|
||||
email?: string
|
||||
address?: string
|
||||
}
|
||||
|
||||
interface PositionDetail {
|
||||
positionName?: string
|
||||
workAddress?: string
|
||||
salary?: string
|
||||
workTime?: string
|
||||
requiredSkills?: string
|
||||
}
|
||||
|
||||
// Props定义
|
||||
const props = defineProps<{
|
||||
posterData: PosterData
|
||||
enterpriseDetail?: EnterpriseDetail
|
||||
positionDetail?: PositionDetail
|
||||
}>()
|
||||
|
||||
// 响应式数据
|
||||
const posterRef = ref<HTMLElement>()
|
||||
const exporting = ref(false)
|
||||
|
||||
// 计算样式
|
||||
const canvasStyle = computed(() => ({
|
||||
backgroundImage: `url(${props.posterData.posterPath})`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'center',
|
||||
backgroundRepeat: 'no-repeat'
|
||||
}))
|
||||
|
||||
// 企业规模字典
|
||||
const scaleDict = {
|
||||
'1': '50人以下',
|
||||
'2': '50-200人',
|
||||
'3': '200-500人',
|
||||
'4': '500-1000人',
|
||||
'5': '1000人以上'
|
||||
}
|
||||
|
||||
// 获取规模标签
|
||||
const getScaleLabel = (value: string) => {
|
||||
return scaleDict[value as keyof typeof scaleDict] || value
|
||||
}
|
||||
|
||||
// 导出为PDF
|
||||
const exportToPDF = async () => {
|
||||
if (!posterRef.value) return
|
||||
|
||||
try {
|
||||
exporting.value = true
|
||||
|
||||
const canvas = await html2canvas(posterRef.value, {
|
||||
backgroundColor: null,
|
||||
scale: 2,
|
||||
useCORS: true,
|
||||
allowTaint: true,
|
||||
foreignObjectRendering: false
|
||||
})
|
||||
|
||||
const imgData = canvas.toDataURL('image/png')
|
||||
const pdf = new jsPDF({
|
||||
orientation: 'portrait',
|
||||
unit: 'mm',
|
||||
format: 'a4'
|
||||
})
|
||||
|
||||
const imgWidth = 190
|
||||
const imgHeight = (canvas.height * imgWidth) / canvas.width
|
||||
|
||||
pdf.addImage(imgData, 'PNG', 10, 10, imgWidth, imgHeight)
|
||||
|
||||
const fileName = `${props.posterData.enterpriseName}_招聘海报_${new Date().getTime()}.pdf`
|
||||
pdf.save(fileName)
|
||||
|
||||
ElMessage.success('PDF导出成功')
|
||||
} catch (error) {
|
||||
console.error('PDF导出失败:', error)
|
||||
ElMessage.error('PDF导出失败,请重试')
|
||||
} finally {
|
||||
exporting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 导出为图片
|
||||
const exportToImage = async () => {
|
||||
if (!posterRef.value) return
|
||||
|
||||
try {
|
||||
exporting.value = true
|
||||
|
||||
const canvas = await html2canvas(posterRef.value, {
|
||||
backgroundColor: null,
|
||||
scale: 2,
|
||||
useCORS: true,
|
||||
allowTaint: true
|
||||
})
|
||||
|
||||
const link = document.createElement('a')
|
||||
link.download = `${props.posterData.enterpriseName}_招聘海报_${new Date().getTime()}.png`
|
||||
link.href = canvas.toDataURL('image/png')
|
||||
link.click()
|
||||
|
||||
ElMessage.success('图片导出成功')
|
||||
} catch (error) {
|
||||
console.error('图片导出失败:', error)
|
||||
ElMessage.error('图片导出失败,请重试')
|
||||
} finally {
|
||||
exporting.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.poster-preview {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.poster-canvas {
|
||||
position: relative;
|
||||
width: 600px;
|
||||
height: 800px;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
}
|
||||
|
||||
.info-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding: 40px;
|
||||
color: white;
|
||||
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);
|
||||
background: linear-gradient(
|
||||
180deg,
|
||||
rgba(0, 0, 0, 0.3) 0%,
|
||||
rgba(0, 0, 0, 0.1) 50%,
|
||||
rgba(0, 0, 0, 0.4) 100%
|
||||
);
|
||||
}
|
||||
|
||||
.company-header {
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.company-name {
|
||||
font-size: 48px;
|
||||
font-weight: 700;
|
||||
margin: 0 0 10px 0;
|
||||
letter-spacing: 2px;
|
||||
background: linear-gradient(135deg, #ffd700, #ffed4e);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
text-shadow: none;
|
||||
filter: drop-shadow(2px 2px 4px rgba(0, 0, 0, 0.8));
|
||||
}
|
||||
|
||||
.company-tagline {
|
||||
font-size: 18px;
|
||||
font-weight: 300;
|
||||
letter-spacing: 4px;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.position-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.position-title {
|
||||
font-size: 36px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 30px;
|
||||
background: linear-gradient(135deg, #ff6b6b, #ffd93d);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
text-shadow: none;
|
||||
filter: drop-shadow(2px 2px 4px rgba(0, 0, 0, 0.8));
|
||||
}
|
||||
|
||||
.position-details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
font-size: 14px;
|
||||
max-width: 500px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.position-details-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 10px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.detail-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
padding: 8px 15px;
|
||||
border-radius: 20px;
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
font-size: 14px;
|
||||
min-height: 36px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 16px;
|
||||
margin-right: 3px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.company-footer {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.company-info {
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
padding: 25px;
|
||||
border-radius: 15px;
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.info-row {
|
||||
display: flex;
|
||||
margin-bottom: 12px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.info-row:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-weight: 600;
|
||||
min-width: 80px;
|
||||
color: #ffd700;
|
||||
}
|
||||
|
||||
.value {
|
||||
flex: 1;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.poster-canvas {
|
||||
width: 90vw;
|
||||
height: calc(90vw * 4 / 3);
|
||||
max-width: 450px;
|
||||
max-height: 600px;
|
||||
}
|
||||
|
||||
.info-overlay {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.company-name {
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
.position-title {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.detail-item {
|
||||
font-size: 14px;
|
||||
padding: 8px 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user