仓库初始化+岗位相关页面

This commit is contained in:
2026-03-24 21:06:00 +08:00
commit 0468339d23
113 changed files with 18644 additions and 0 deletions
+579
View File
@@ -0,0 +1,579 @@
<template>
<div class="profile-page dflex">
<SideNav />
<div class="profile-page__content">
<!-- 个人资料编辑抽屉 -->
<ProfileEditDrawer
v-model="showEditDrawer"
:module="editModule"
:initial-data="editInitialData"
@save="handleSaveEdit"
/>
<!-- 页面标题 -->
<div class="profile-page__header">
<h2 class="profile-page__title">个人资料 <span class="profile-page__title-tip"></span></h2>
<p class="profile-page__subtitle">
设定个人资料以匹配岗位需求包括教育背景实习经历等大部分信息可以从简历中自动获取也可以手动修改
</p>
</div>
<!-- 主体区域左侧详情 + 右侧入口 -->
<div class="profile-page__body">
<!-- 个人资料内容组件 -->
<ProfilePageContent
:profile="profile"
@edit="handleEdit"
/>
<!-- 右侧入口 -->
<div class="profile-page__sidebar">
<!-- 提示卡片 -->
<div class="profile-page__tip-card">
<p class="profile-page__tip-text">
非常棒你的个人资料已经被完善了自动填写信息也已变换现在可以轻松开始投递简历啦
</p>
<button class="profile-page__tip-btn" @click="goToJobs">去投递</button>
</div>
<!-- 管理简历入口 -->
<div class="profile-page__nav-entry" @click="goToResume">
<span class="profile-page__nav-entry-icon">📄</span>
<span class="profile-page__nav-entry-text">管理我的简历</span>
<svg viewBox="0 0 16 16" fill="none" class="profile-page__nav-arrow">
<path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { useStore } from 'vuex'
import SideNav from '@/components/SideNav.vue'
import ProfileEditDrawer from '@/components/ProfileEditDrawer.vue'
import ProfilePageContent from '@/components/ProfilePageContent.vue'
import { saveProfile, fetchProfile, fetchEducation, saveEducation, fetchWork, saveWork, fetchInternship, saveInternship, fetchProject, saveProject, fetchCompetition, saveCompetition } from '@/api/profile'
import type { SaveEducationItem, SaveWorkItem, SaveProjectItem, SaveCompetitionItem } from '@/api/profile'
const router = useRouter()
const store = useStore()
/** 页面挂载时加载公共分类数据和个人资料 */
onMounted(async () => {
if (!store.state.regions.length) {
store.dispatch('loadCommonData')
}
// 请求个人资料主表数据,填充非数组字段
await loadProfile()
// 请求教育经历数据
await loadEducation()
// 请求工作经历数据
await loadWork()
// 请求实习经历数据
await loadInternship()
// 请求项目经历数据
await loadProject()
// 请求竞赛经历数据
await loadCompetition()
})
/** 加载个人资料主表数据 */
async function loadProfile() {
try {
const res = await fetchProfile()
if (res.code === '0' && res.data) {
const d = res.data
profile.value.name = d.name || ''
profile.value.phone = d.mobileNumber || ''
profile.value.email = d.email || ''
profile.value.idNumber = d.idCard || ''
profile.value.regionCode = d.regionCode || ''
profile.value.wechat = d.wechatNumber || ''
profile.value.skills = d.skills || []
profile.value.certificates = d.certificates || []
}
} catch {
console.error('[Profile] 加载个人资料失败')
}
}
/** 加载教育经历数据 */
async function loadEducation() {
try {
const res = await fetchEducation()
if (res.code === '0' && res.data) {
profile.value.education = res.data.map(item => ({
school: item.school || '',
major: item.major || '',
studyType: item.studyType ?? 0,
degree: item.degree ?? 2,
startDate: item.startDate || '',
endDate: item.endDate || '',
description: (item.description || []).map(d => ({
id: d.id || '',
text: d.text || '',
})),
}))
}
} catch {
console.error('[Profile] 加载教育经历失败')
}
}
/** 加载工作经历数据 */
async function loadWork() {
try {
const res = await fetchWork()
if (res.code === '0' && res.data) {
profile.value.works = res.data.map(item => ({
companyName: item.companyName || '',
position: item.position || '',
startDate: item.startDate || '',
endDate: item.endDate || '',
description: (item.description || []).map(d => ({
id: d.id || '',
text: d.text || '',
})),
}))
}
} catch {
console.error('[Profile] 加载工作经历失败')
}
}
/** 加载实习经历数据 */
async function loadInternship() {
try {
const res = await fetchInternship()
if (res.code === '0' && res.data) {
profile.value.internships = res.data.map(item => ({
companyName: item.companyName || '',
position: item.position || '',
startDate: item.startDate || '',
endDate: item.endDate || '',
description: (item.description || []).map(d => ({
id: d.id || '',
text: d.text || '',
})),
}))
}
} catch {
console.error('[Profile] 加载实习经历失败')
}
}
/** 加载项目经历数据 */
async function loadProject() {
try {
const res = await fetchProject()
if (res.code === '0' && res.data) {
profile.value.projects = res.data.map(item => ({
projectName: item.projectName || '',
companyName: item.companyName || '',
role: item.role || '',
startDate: item.startDate || '',
endDate: item.endDate || '',
description: (item.description || []).map(d => ({
id: d.id || '',
text: d.text || '',
})),
}))
}
} catch {
console.error('[Profile] 加载项目经历失败')
}
}
/** 加载竞赛经历数据 */
async function loadCompetition() {
try {
const res = await fetchCompetition()
if (res.code === '0' && res.data) {
profile.value.competitions = res.data.map(item => ({
competitionName: item.competitionName || '',
award: item.award || '',
awardDate: item.awardDate || '',
description: (item.description || []).map(d => ({
id: d.id || '',
text: d.text || '',
})),
}))
}
} catch {
console.error('[Profile] 加载竞赛经历失败')
}
}
/** 编辑抽屉的显示状态 */
const showEditDrawer = ref(false)
/** 当前编辑的模块名称 */
const editModule = ref('info')
/** 当前编辑模块的初始数据 */
const editInitialData = ref<Record<string, any>>({})
/** 保存中的加载状态 */
const saving = ref(false)
// ==================== 个人资料数据(非数组字段由接口填充,数组字段暂用模拟数据) ====================
const profile = ref({
/** 真实姓名 — 接口字段 name */
name: '',
/** 手机号码 — 接口字段 mobileNumber */
phone: '',
/** 邮箱 — 接口字段 email */
email: '',
/** 身份证号 — 接口字段 idCard */
idNumber: '',
/** 所在城市编码 — 接口字段 regionCode */
regionCode: '',
/** 微信号 — 接口字段 wechatNumber */
wechat: '',
/** 技能标签列表 — 接口字段 skills */
skills: [] as string[],
/** 证书标签列表 — 接口字段 certificates */
certificates: [] as string[],
/** 教育经历 — 对应数据库 bg_user_profile_education */
education: [] as Array<{
school: string
major: string
studyType: number
degree: number
startDate: string
endDate: string
description: Array<{ id: string; text: string }>
}>,
/** 工作经历 — 对应数据库 bg_user_profile_work */
works: [] as Array<{
companyName: string
position: string
startDate: string
endDate: string
description: Array<{ id: string; text: string }>
}>,
internships: [] as Array<{
companyName: string
position: string
startDate: string
endDate: string
description: Array<{ id: string; text: string }>
}>,
projects: [] as Array<{
projectName: string
companyName: string
role: string
startDate: string
endDate: string
description: Array<{ id: string; text: string }>
}>,
/** 竞赛经历 — 对应数据库 bg_user_profile_competition */
competitions: [] as Array<{
competitionName: string
award: string
awardDate: string
description: Array<{ id: string; text: string }>
}>,
})
// ==================== 事件处理 ====================
/** 打开编辑抽屉 — 根据模块名设置初始数据 */
function handleEdit(section: string) {
editModule.value = section
// 根据模块名提取对应的初始数据
if (section === 'info') {
editInitialData.value = {
name: profile.value.name,
email: profile.value.email,
phone: profile.value.phone,
/** 城市编码 — 传给编辑抽屉的 RegionSelector */
location: profile.value.regionCode,
wechat: profile.value.wechat,
}
} else if (section === 'education') {
editInitialData.value = {
education: profile.value.education.map(edu => ({
school: edu.school,
major: edu.major,
studyType: edu.studyType,
degree: edu.degree,
startDate: edu.startDate,
endDate: edu.endDate,
description: edu.description.map(d => ({ ...d })),
})),
}
} else if (section === 'work') {
editInitialData.value = {
works: profile.value.works.map(exp => ({
companyName: exp.companyName,
position: exp.position,
startDate: exp.startDate,
endDate: exp.endDate,
description: exp.description.map(d => ({ ...d })),
})),
}
} else if (section === 'internship') {
editInitialData.value = {
internships: profile.value.internships.map(exp => ({
companyName: exp.companyName,
position: exp.position,
startDate: exp.startDate,
endDate: exp.endDate,
description: exp.description.map(d => ({ ...d })),
})),
}
} else if (section === 'project') {
editInitialData.value = {
projects: profile.value.projects.map(proj => ({
projectName: proj.projectName,
companyName: proj.companyName,
role: proj.role,
startDate: proj.startDate,
endDate: proj.endDate,
description: proj.description.map(d => ({ ...d })),
})),
}
} else if (section === 'competition') {
editInitialData.value = {
competitions: profile.value.competitions.map(comp => ({
competitionName: comp.competitionName,
award: comp.award,
awardDate: comp.awardDate,
description: comp.description.map(d => ({ ...d })),
})),
}
} else if (section === 'skills') {
editInitialData.value = {
skills: [...profile.value.skills],
}
} else if (section === 'certificate') {
editInitialData.value = {
certificates: [...profile.value.certificates],
}
} else {
editInitialData.value = {}
}
showEditDrawer.value = true
}
/** 保存编辑数据 — 将抽屉返回的数据合并到 profile,并调用对应接口持久化 */
async function handleSaveEdit(data: Record<string, any>) {
if (editModule.value === 'info') {
// ---- 基本信息:调用主表接口保存 ----
try {
saving.value = true
await saveProfile({
name: data.name,
email: data.email,
mobileNumber: data.phone,
regionCode: data.location,
wechatNumber: data.wechat,
})
// 接口成功后更新本地数据
profile.value.name = data.name
profile.value.email = data.email
profile.value.phone = data.phone
profile.value.wechat = data.wechat
/** 将城市编码存入 regionCode,先直接显示编码,后续联调获取接口再做名称转换 */
profile.value.regionCode = data.location || ''
ElMessage.success('个人信息保存成功')
} catch {
ElMessage.error('个人信息保存失败,请重试')
} finally {
saving.value = false
}
} else if (editModule.value === 'education') {
// ---- 教育经历:调用教育经历接口保存 ----
try {
saving.value = true
const payload: SaveEducationItem[] = data.education.map((edu: any) => ({
school: edu.school,
major: edu.major,
degree: edu.degree,
studyType: edu.studyType,
startDate: edu.startDate,
endDate: edu.endDate,
description: edu.description.map((d: any) => ({ id: d.id, text: d.text })),
}))
await saveEducation(payload)
// 接口成功后更新本地数据
profile.value.education = data.education.map((edu: any) => ({
school: edu.school,
major: edu.major,
studyType: edu.studyType,
degree: edu.degree,
startDate: edu.startDate,
endDate: edu.endDate,
description: edu.description.map((d: any) => ({ ...d })),
}))
ElMessage.success('教育经历保存成功')
} catch {
ElMessage.error('教育经历保存失败,请重试')
} finally {
saving.value = false
}
} else if (editModule.value === 'work') {
// ---- 工作经历:调用工作经历接口保存 ----
try {
saving.value = true
const payload: SaveWorkItem[] = data.works.map((work: any) => ({
companyName: work.companyName,
position: work.position,
startDate: work.startDate,
endDate: work.endDate || '',
description: work.description.map((d: any) => ({ id: d.id, text: d.text })),
}))
await saveWork(payload)
// 接口成功后更新本地数据
profile.value.works = data.works.map((work: any) => ({
companyName: work.companyName,
position: work.position,
startDate: work.startDate,
endDate: work.endDate,
description: work.description.map((d: any) => ({ ...d })),
}))
ElMessage.success('工作经历保存成功')
} catch {
ElMessage.error('工作经历保存失败,请重试')
} finally {
saving.value = false
}
} else if (editModule.value === 'internship') {
// ---- 实习经历:调用实习经历接口保存 ----
try {
saving.value = true
const payload: SaveWorkItem[] = data.internships.map((intern: any) => ({
companyName: intern.companyName,
position: intern.position,
startDate: intern.startDate,
endDate: intern.endDate || '',
description: intern.description.map((d: any) => ({ id: d.id, text: d.text })),
}))
await saveInternship(payload)
// 接口成功后更新本地数据
profile.value.internships = data.internships.map((intern: any) => ({
companyName: intern.companyName,
position: intern.position,
startDate: intern.startDate,
endDate: intern.endDate,
description: intern.description.map((d: any) => ({ ...d })),
}))
ElMessage.success('实习经历保存成功')
} catch {
ElMessage.error('实习经历保存失败,请重试')
} finally {
saving.value = false
}
} else if (editModule.value === 'project') {
// ---- 项目经历:调用项目经历接口保存 ----
try {
saving.value = true
const payload: SaveProjectItem[] = data.projects.map((proj: any) => ({
projectName: proj.projectName,
companyName: proj.companyName || '',
role: proj.role || '',
startDate: proj.startDate,
endDate: proj.endDate || '',
description: proj.description.map((d: any) => ({ id: d.id, text: d.text })),
}))
await saveProject(payload)
// 接口成功后更新本地数据
profile.value.projects = data.projects.map((proj: any) => ({
projectName: proj.projectName,
companyName: proj.companyName,
role: proj.role,
startDate: proj.startDate,
endDate: proj.endDate,
description: proj.description.map((d: any) => ({ ...d })),
}))
ElMessage.success('项目经历保存成功')
} catch {
ElMessage.error('项目经历保存失败,请重试')
} finally {
saving.value = false
}
} else if (editModule.value === 'competition') {
// ---- 竞赛经历:调用竞赛经历接口保存 ----
try {
saving.value = true
const payload: SaveCompetitionItem[] = data.competitions.map((comp: any) => ({
competitionName: comp.competitionName,
award: comp.award || '',
awardDate: comp.awardDate || '',
description: comp.description.map((d: any) => ({ id: d.id, text: d.text })),
}))
await saveCompetition(payload)
// 接口成功后更新本地数据
profile.value.competitions = data.competitions.map((comp: any) => ({
competitionName: comp.competitionName,
award: comp.award,
awardDate: comp.awardDate,
description: comp.description.map((d: any) => ({ ...d })),
}))
ElMessage.success('竞赛经历保存成功')
} catch {
ElMessage.error('竞赛经历保存失败,请重试')
} finally {
saving.value = false
}
} else if (editModule.value === 'skills') {
// ---- 技能:调用主表接口保存,需要传递完整的个人信息数据 ----
try {
saving.value = true
await saveProfile({
name: profile.value.name,
email: profile.value.email,
mobileNumber: profile.value.phone,
idCard: profile.value.idNumber,
regionCode: profile.value.regionCode,
wechatNumber: profile.value.wechat,
skills: [...data.skills],
certificates: profile.value.certificates,
})
profile.value.skills = [...data.skills]
ElMessage.success('技能保存成功')
} catch {
ElMessage.error('技能保存失败,请重试')
} finally {
saving.value = false
}
} else if (editModule.value === 'certificate') {
// ---- 证书:调用主表接口保存,需要传递完整的个人信息数据 ----
try {
saving.value = true
await saveProfile({
name: profile.value.name,
email: profile.value.email,
mobileNumber: profile.value.phone,
idCard: profile.value.idNumber,
regionCode: profile.value.regionCode,
wechatNumber: profile.value.wechat,
skills: profile.value.skills,
certificates: [...data.certificates],
})
profile.value.certificates = [...data.certificates]
ElMessage.success('证书保存成功')
} catch {
ElMessage.error('证书保存失败,请重试')
} finally {
saving.value = false
}
}
}
function goToJobs() {
router.push('/jobs')
}
function goToResume() {
router.push('/resume')
}
</script>