登陆页左侧新广告特效

This commit is contained in:
2026-06-28 19:23:54 +08:00
parent 0888d9fa31
commit 0aebde7bd3
15 changed files with 452 additions and 133 deletions
+131 -39
View File
@@ -135,10 +135,17 @@
<div class="resume-detail__card" :class="{ 'resume-detail__card-hover': editModule !== 'info' || !showEditDrawer }">
<!-- 展示模式 -->
<template v-if="editModule !== 'info' || !showEditDrawer">
<div class="resume-detail__card-header">
<div>
<div class="resume-detail__card-header color-6">
<div class="dflex-start aliite-c">
<h3 class="resume-detail__user-name">{{ resumeMain.name || '未填写姓名' }}</h3>
<p class="resume-detail__user-title">{{ resumeMain.targetPosition || '' }}</p>
<span v-if="resumeMain.city" class="ml10 dflex-start aliite-c fs13">
<svg viewBox="0 0 16 16" fill="none" class="resume-detail__contact-icon">
<circle cx="8" cy="6.5" r="2.5" stroke="currentColor" stroke-width="1.2"/>
<path d="M8 14s-5-4-5-7.5a5 5 0 0110 0C13 10 8 14 8 14z" stroke="currentColor" stroke-width="1.2"/>
</svg>
{{ resumeMain.city }}
</span>
</div>
<!-- 编辑按钮 hover时才显示品牌色图标+文字 -->
<button class="resume-detail__edit-btn-inline" @click="openEditDrawer('info')" aria-label="编辑个人信息">
@@ -162,20 +169,10 @@
</svg>
{{ resumeMain.mobileNumber }}
</span>
<!-- 所在城市 -->
<span v-if="resumeMain.city" class="resume-detail__contact-item">
<svg viewBox="0 0 16 16" fill="none" class="resume-detail__contact-icon">
<circle cx="8" cy="6.5" r="2.5" stroke="currentColor" stroke-width="1.2"/>
<path d="M8 14s-5-4-5-7.5a5 5 0 0110 0C13 10 8 14 8 14z" stroke="currentColor" stroke-width="1.2"/>
</svg>
{{ resumeMain.city }}
</span>
<!-- 微信号 -->
<span v-if="resumeMain.wechatNumber" class="resume-detail__contact-item">
<svg viewBox="0 0 16 16" fill="none" class="resume-detail__contact-icon">
<path d="M2 8a6 6 0 1112 0 6 6 0 01-12 0z" stroke="currentColor" stroke-width="1.2"/>
<path d="M5.5 7.5c.5-1 1.5-1.5 2.5-1.5s2 .5 2.5 1.5M6 10s.8 1 2 1 2-1 2-1" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/>
</svg>
<el-icon class="fs14 color-9"><ChatLineRound /></el-icon>
{{ resumeMain.wechatNumber }}
</span>
<!-- 作品集链接 -->
@@ -250,7 +247,7 @@
@save="handleExpAdd('education', $event)"
@cancel="expAddingModule = ''"
/>
<div v-for="edu in educationList" :key="edu.id" class="resume-detail__exp-item">
<div v-for="edu in educationList" :key="edu.id" class="resume-detail__exp-item" @click.stop="startEditExp('education', edu)">
<!-- 展示模式 -->
<template v-if="expEditingId !== edu.id">
<div class="resume-detail__exp-row">
@@ -262,11 +259,18 @@
建议使用AI润色修复 &gt;&gt;
<span class="resume-detail__fix-tooltip">{{ getIssueByRecord('education', edu.id!)!.finding }}</span>
</span>
<!-- 编辑按钮 hover时显示 -->
<button class="resume-detail__edit-btn-inline resume-detail__exp-edit-btn" @click="startEditExp('education', edu)" aria-label="编辑">
<el-icon><EditPen /></el-icon>
<span>编辑</span>
</button>
<div class="mlauto dflex-end">
<!-- 编辑按钮 hover时显示 -->
<button class="resume-detail__edit-btn-inline resume-detail__exp-edit-btn" @click="startEditExp('education', edu)" aria-label="编辑">
<el-icon><EditPen /></el-icon>
<span>编辑</span>
</button>
<!-- 删除按钮 -->
<button class="resume-detail__edit-btn-inline resume-detail__exp-edit-btn" @click.stop="handleExpDelete('education', edu.id!)" aria-label="删除">
<el-icon><DeleteFilled /></el-icon>
<span>删除</span>
</button>
</div>
</div>
<div v-if="edu.description?.length" class="resume-detail__desc-list">
<p v-for="p in edu.description" :key="p.id" class="resume-detail__desc-item">{{ p.text }}</p>
@@ -293,7 +297,7 @@
</button>
</div>
<ResumeExpInlineEdit v-if="expAddingModule === 'work'" :module-type="'work'" @save="handleExpAdd('work', $event)" @cancel="expAddingModule = ''" />
<div v-for="exp in workList" :key="exp.id" class="resume-detail__exp-item">
<div v-for="exp in workList" :key="exp.id" class="resume-detail__exp-item" @click.stop="startEditExp('work', exp)">
<template v-if="expEditingId !== exp.id">
<div class="resume-detail__exp-row">
<span class="resume-detail__exp-name">{{ exp.companyName }}</span>
@@ -304,9 +308,14 @@
建议使用AI润色修复 &gt;&gt;
<span class="resume-detail__fix-tooltip">{{ getIssueByRecord('work', exp.id!)!.finding }}</span>
</span>
<button class="resume-detail__edit-btn-inline resume-detail__exp-edit-btn" @click="startEditExp('work', exp)" aria-label="编辑">
<el-icon><EditPen /></el-icon><span>编辑</span>
</button>
<div class="mlauto dflex-end">
<button class="resume-detail__edit-btn-inline resume-detail__exp-edit-btn" @click="startEditExp('work', exp)" aria-label="编辑">
<el-icon><EditPen /></el-icon><span>编辑</span>
</button>
<button class="resume-detail__edit-btn-inline resume-detail__exp-edit-btn" @click.stop="handleExpDelete('work', exp.id!)" aria-label="删除">
<el-icon><DeleteFilled /></el-icon><span>删除</span>
</button>
</div>
</div>
<ul v-if="exp.description?.length" class="resume-detail__desc-list pl16">
<li v-for="p in exp.description" :key="p.id" class="resume-detail__desc-item">{{ p.text }}</li>
@@ -325,7 +334,7 @@
</button>
</div>
<ResumeExpInlineEdit v-if="expAddingModule === 'internship'" :module-type="'internship'" @save="handleExpAdd('internship', $event)" @cancel="expAddingModule = ''" />
<div v-for="intern in internshipList" :key="intern.id" class="resume-detail__exp-item">
<div v-for="intern in internshipList" :key="intern.id" class="resume-detail__exp-item" @click.stop="startEditExp('internship', intern)">
<template v-if="expEditingId !== intern.id">
<div class="resume-detail__exp-row">
<span class="resume-detail__exp-name">{{ intern.companyName }}</span>
@@ -336,9 +345,14 @@
建议使用AI润色修复 &gt;&gt;
<span class="resume-detail__fix-tooltip">{{ getIssueByRecord('internship', intern.id!)!.finding }}</span>
</span>
<button class="resume-detail__edit-btn-inline resume-detail__exp-edit-btn" @click="startEditExp('internship', intern)" aria-label="编辑">
<el-icon><EditPen /></el-icon><span>编辑</span>
</button>
<div class="mlauto dflex-end">
<button class="resume-detail__edit-btn-inline resume-detail__exp-edit-btn" @click="startEditExp('internship', intern)" aria-label="编辑">
<el-icon><EditPen /></el-icon><span>编辑</span>
</button>
<button class="resume-detail__edit-btn-inline resume-detail__exp-edit-btn" @click.stop="handleExpDelete('internship', intern.id!)" aria-label="删除">
<el-icon><DeleteFilled /></el-icon><span>删除</span>
</button>
</div>
</div>
<div v-if="intern.description?.length" class="resume-detail__desc-list">
<p v-for="p in intern.description" :key="p.id" class="resume-detail__desc-item">{{ p.text }}</p>
@@ -357,7 +371,7 @@
</button>
</div>
<ResumeExpInlineEdit v-if="expAddingModule === 'project'" :module-type="'project'" @save="handleExpAdd('project', $event)" @cancel="expAddingModule = ''" />
<div v-for="proj in projectList" :key="proj.id" class="resume-detail__exp-item">
<div v-for="proj in projectList" :key="proj.id" class="resume-detail__exp-item" @click.stop="startEditExp('project', proj)">
<template v-if="expEditingId !== proj.id">
<div class="resume-detail__exp-row">
<span class="resume-detail__exp-name">{{ proj.projectName }}</span>
@@ -368,9 +382,14 @@
建议使用AI润色修复 &gt;&gt;
<span class="resume-detail__fix-tooltip">{{ getIssueByRecord('project', proj.id!)!.finding }}</span>
</span>
<button class="resume-detail__edit-btn-inline resume-detail__exp-edit-btn" @click="startEditExp('project', proj)" aria-label="编辑">
<el-icon><EditPen /></el-icon><span>编辑</span>
</button>
<div class="mlauto dflex-end">
<button class="resume-detail__edit-btn-inline resume-detail__exp-edit-btn" @click="startEditExp('project', proj)" aria-label="编辑">
<el-icon><EditPen /></el-icon><span>编辑</span>
</button>
<button class="resume-detail__edit-btn-inline resume-detail__exp-edit-btn" @click.stop="handleExpDelete('project', proj.id!)" aria-label="删除">
<el-icon><DeleteFilled /></el-icon><span>删除</span>
</button>
</div>
</div>
<div v-if="proj.description?.length" class="resume-detail__desc-list">
<p v-for="p in proj.description" :key="p.id" class="resume-detail__desc-item">{{ p.text }}</p>
@@ -389,7 +408,7 @@
</button>
</div>
<ResumeExpInlineEdit v-if="expAddingModule === 'competition'" :module-type="'competition'" @save="handleExpAdd('competition', $event)" @cancel="expAddingModule = ''" />
<div v-for="comp in competitionList" :key="comp.id" class="resume-detail__exp-item">
<div v-for="comp in competitionList" :key="comp.id" class="resume-detail__exp-item" @click.stop="startEditExp('competition', comp)">
<template v-if="expEditingId !== comp.id">
<div class="resume-detail__exp-row">
<span class="resume-detail__exp-name">{{ comp.competitionName }}</span>
@@ -400,9 +419,14 @@
建议使用AI润色修复 &gt;&gt;
<span class="resume-detail__fix-tooltip">{{ getIssueByRecord('competition', comp.id!)!.finding }}</span>
</span>
<button class="resume-detail__edit-btn-inline resume-detail__exp-edit-btn" @click="startEditExp('competition', comp)" aria-label="编辑">
<el-icon><EditPen /></el-icon><span>编辑</span>
</button>
<div class="mlauto dflex-end">
<button class="resume-detail__edit-btn-inline resume-detail__exp-edit-btn" @click="startEditExp('competition', comp)" aria-label="编辑">
<el-icon><EditPen /></el-icon><span>编辑</span>
</button>
<button class="resume-detail__edit-btn-inline resume-detail__exp-edit-btn" @click.stop="handleExpDelete('competition', comp.id!)" aria-label="删除">
<el-icon><DeleteFilled /></el-icon><span>删除</span>
</button>
</div>
</div>
<div v-if="comp.description?.length" class="resume-detail__desc-list">
<p v-for="p in comp.description" :key="p.id" class="resume-detail__desc-item">{{ p.text }}</p>
@@ -480,8 +504,9 @@
</template>
<script setup lang="ts">
import { ref, reactive, computed, onMounted } from 'vue'
import { ref, reactive, computed, onMounted, watch } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useStore } from 'vuex'
import SideNav from '@/components/SideNav.vue'
import ProfileEditDrawer from '@/components/ProfileEditDrawer.vue'
import ResumeExpInlineEdit from '@/components/ResumeExpInlineEdit.vue'
@@ -531,7 +556,11 @@ import {
type DiagnosisIssue,
type DescriptionParagraph,
} from '@/api/resume'
import {ArrowLeft, EditPen, Plus} from "@element-plus/icons-vue";
import {ArrowLeft, EditPen, Plus, DeleteFilled, ChatLineRound} from "@element-plus/icons-vue";
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus'
// ==================== Store 实例 ====================
const store = useStore()
// ==================== 诊断数据相关 ====================
@@ -748,6 +777,23 @@ const competitionList = ref<ResumeCompetition[]>([])
// ==================== 数据加载 ====================
/** 根据城市名称从地区树中反查城市编码(用于后端未返回 regionCode 时的 fallback */
function resolveRegionCodeByName(cityName: string): string {
if (!cityName) return ''
const regions = store.state.regions || []
for (const province of regions) {
for (const city of province.children) {
if (city.name === cityName) return city.code
if (city.children) {
for (const district of city.children) {
if (district.name === cityName) return district.code
}
}
}
}
return ''
}
/** 加载所有简历详情数据 */
async function loadResumeDetail() {
const [mainRes, eduRes, workRes, internRes, projRes, compRes] = await Promise.all([
@@ -761,6 +807,10 @@ async function loadResumeDetail() {
if (mainRes.code === '0' && mainRes.data) {
resumeMain.value = mainRes.data
// 如果后端未返回 regionCode 但有 city 名称,尝试从地区树反查编码
if (!resumeMain.value.regionCode && resumeMain.value.city) {
resumeMain.value.regionCode = resolveRegionCodeByName(resumeMain.value.city)
}
}
if (eduRes.code === '0' && eduRes.data) {
educationList.value = eduRes.data
@@ -779,12 +829,26 @@ async function loadResumeDetail() {
}
}
// ==================== 地区数据反查 ====================
/** 当 store 中地区树数据加载完毕后,如果 resumeMain 缺少 regionCode 则尝试反查 */
watch(
() => store.state.regions,
(regions) => {
if (regions?.length && resumeMain.value.city && !resumeMain.value.regionCode) {
resumeMain.value.regionCode = resolveRegionCodeByName(resumeMain.value.city)
}
}
)
// ==================== 生命周期 ====================
onMounted(() => {
loadResumeDetail()
// 加载诊断报告
loadDiagnosis()
// 确保地区分类数据可用(页面刷新后 store 可能为空)
store.dispatch('loadCommonData')
})
// ==================== 计算属性 ====================
@@ -1286,6 +1350,32 @@ async function handleExpUpdate(moduleType: string, recordId: string, data: Recor
}
}
/** 删除单条经历 */
async function handleExpDelete(moduleType: string, recordId: string) {
try {
await ElMessageBox.confirm('确定要删除这条经历吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
const deleteMap: Record<string, (id: string) => Promise<any>> = {
education: deleteResumeEducation,
work: deleteResumeWork,
internship: deleteResumeInternship,
project: deleteResumeProject,
competition: deleteResumeCompetition,
}
const deleteFn = deleteMap[moduleType]
if (deleteFn) {
await deleteFn(recordId)
await loadResumeDetail()
ElMessage.success('删除成功')
}
} catch {
}
}
/** 保存新增的经历 */
async function handleExpAdd(moduleType: string, data: Record<string, any>) {
try {
@@ -1343,7 +1433,7 @@ function openEditDrawer(section: string) {
name: resumeMain.value.name || '',
email: resumeMain.value.email || '',
phone: resumeMain.value.mobileNumber || '',
location: '',
location: resumeMain.value.regionCode || '',
wechat: resumeMain.value.wechatNumber || '',
portfolioUrl: resumeMain.value.portfolioUrl || '',
}
@@ -1446,6 +1536,7 @@ async function handleSaveEdit(data: Record<string, any>) {
email: data.email,
mobileNumber: data.phone,
city: data.locationName || data.location || '',
regionCode: data.location || '',
wechatNumber: data.wechat,
portfolioUrl: data.portfolioUrl,
})
@@ -1453,6 +1544,7 @@ async function handleSaveEdit(data: Record<string, any>) {
resumeMain.value.email = data.email
resumeMain.value.mobileNumber = data.phone
resumeMain.value.city = data.locationName || data.location || ''
resumeMain.value.regionCode = data.location || ''
resumeMain.value.wechatNumber = data.wechat
resumeMain.value.portfolioUrl = data.portfolioUrl
} else if (editModule.value === 'summary') {