新版交互调整

This commit is contained in:
2026-06-24 19:03:41 +08:00
parent 065553f53e
commit 8143a89dab
37 changed files with 4929 additions and 4409 deletions
+417 -909
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -449,7 +449,7 @@ function fillJobData(data: JobDetailData) {
job.title = data.jobTitle || ''
job.location = data.regionName || ''
job.experience = formatExperience(data.minExperience)
job.type = formatEmploymentType(data.employmentType)
job.type = formatEmploymentType(data.recruitCategory)
job.education = formatEducation(data.education)
job.salary = data.salary || ''
job.matchScore = data.matchScore ?? 0
+71 -19
View File
@@ -10,7 +10,7 @@
@save="handleSaveEdit"
/>
<!-- 欢迎上传简历弹窗无个人资料时自动弹出 -->
<!-- 欢迎上传简历弹窗无个人资料主表记录时自动弹出 -->
<ResumeUploadDialog v-model="showWelcomeDialog" @confirm="handleWelcomeUpload" />
<!-- 页面标题 -->
@@ -27,27 +27,12 @@
<ProfilePageContent
:profile="profile"
@edit="handleEdit"
@save="handleInlineSave"
@exp-update="handleExpUpdate"
@exp-add="handleExpAdd"
/>
<!-- 右侧入口 -->
<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>
@@ -658,4 +643,71 @@ function goToJobs() {
function goToResume() {
router.push('/resume')
}
/** 内联保存处理(个人信息/技能/证书模块从组件内直接保存) */
async function handleInlineSave(section: string, data: Record<string, any>) {
// 复用已有的 handleSaveEdit 逻辑
editModule.value = section
await handleSaveEdit(data)
}
/** 单条经历更新 — 将编辑后的数据替换到完整列表中再整体保存 */
async function handleExpUpdate(moduleType: string, index: number, data: Record<string, any>) {
try {
if (moduleType === 'education') {
const list = profile.value.education.map((item, i) => i === index ? data : item) as any[]
await saveEducation(list)
await loadEducation()
} else if (moduleType === 'work') {
const list = profile.value.works.map((item, i) => i === index ? data : item) as any[]
await saveWork(list)
await loadWork()
} else if (moduleType === 'internship') {
const list = profile.value.internships.map((item, i) => i === index ? data : item) as any[]
await saveInternship(list)
await loadInternship()
} else if (moduleType === 'project') {
const list = profile.value.projects.map((item, i) => i === index ? data : item) as any[]
await saveProject(list)
await loadProject()
} else if (moduleType === 'competition') {
const list = profile.value.competitions.map((item, i) => i === index ? data : item) as any[]
await saveCompetition(list)
await loadCompetition()
}
ElMessage.success('保存成功')
} catch {
ElMessage.error('保存失败')
}
}
/** 新增经历 */
async function handleExpAdd(moduleType: string, data: Record<string, any>) {
try {
if (moduleType === 'education') {
const list = [...profile.value.education, data] as any[]
await saveEducation(list)
await loadEducation()
} else if (moduleType === 'work') {
const list = [...profile.value.works, data] as any[]
await saveWork(list)
await loadWork()
} else if (moduleType === 'internship') {
const list = [...profile.value.internships, data] as any[]
await saveInternship(list)
await loadInternship()
} else if (moduleType === 'project') {
const list = [...profile.value.projects, data] as any[]
await saveProject(list)
await loadProject()
} else if (moduleType === 'competition') {
const list = [...profile.value.competitions, data] as any[]
await saveCompetition(list)
await loadCompetition()
}
ElMessage.success('添加成功')
} catch {
ElMessage.error('添加失败')
}
}
</script>
+73 -79
View File
@@ -25,7 +25,6 @@
<th class="resume-page__th">简历</th>
<th class="resume-page__th">目标岗位</th>
<th class="resume-page__th">最近修改</th>
<th class="resume-page__th">创建时间</th>
<th class="resume-page__th resume-page__th--action"></th>
</tr>
</thead>
@@ -38,38 +37,39 @@
>
<td class="resume-page__td">
<div class="resume-page__name-cell">
<span class="resume-page__avatar" :style="{ background: item.avatarColor }">
{{ item.avatarLetter }}
</span>
<!-- <span class="resume-page__avatar" :style="{ background: item.avatarColor }">-->
<!-- {{ item.avatarLetter }}-->
<!-- </span>-->
<span class="resume-page__name">{{ item.name }}</span>
<span v-if="item.isDefault" class="resume-page__default-tag">默认</span>
<!-- 编辑名称岗位图标 -->
<button
class="resume-page__edit-btn"
aria-label="编辑名称岗位"
@click.stop="handleEditName(item)"
>
<el-icon class="resume-page__edit-icon"><EditPen /></el-icon>
</button>
</div>
</td>
<td class="resume-page__td">{{ item.targetJob }}</td>
<td class="resume-page__td">{{ item.updatedAt }}</td>
<td class="resume-page__td">{{ item.createdAt }}</td>
<!-- 操作按钮列 -->
<td class="resume-page__td resume-page__td--action">
<button
class="resume-page__more-btn"
aria-label="更多操作"
@click.stop="toggleMenu(item.id)"
>
<svg viewBox="0 0 16 16" fill="currentColor" class="resume-page__more-svg">
<circle cx="3" cy="8" r="1.5"/>
<circle cx="8" cy="8" r="1.5"/>
<circle cx="13" cy="8" r="1.5"/>
</svg>
</button>
<!-- 弹出菜单 -->
<div v-if="activeMenuId === item.id" class="resume-page__popup" @click.stop>
<div
v-for="action in popupActions"
:key="action"
class="resume-page__popup-item"
@click="handleAction(action, item.id)"
>
{{ action }}
</div>
<div class="resume-page__actions">
<button
v-if="!item.isDefault"
class="resume-page__action-btn"
@click.stop="handleSetDefault(item.id)"
>设为默认</button>
<button
class="resume-page__action-btn"
@click.stop="handleExport(item)"
>导出</button>
<button
class="resume-page__action-btn resume-page__action-btn--delete"
@click.stop="handleDelete(item.id)"
>删除</button>
</div>
</td>
</tr>
@@ -104,13 +104,14 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { EditPen } from '@element-plus/icons-vue'
import SideNav from '@/components/SideNav.vue'
import ResumeEditNameDialog from '@/components/ResumeEditNameDialog.vue'
import ResumeExportDialog from '@/components/ResumeExportDialog.vue'
import ResumeUploadDialog from '@/components/ResumeUploadDialog.vue'
import { uploadResume } from '@/utils/aiRequest'
import {
fetchResumeList, deleteResume, type ResumeListItem,
fetchResumeList, deleteResume, setDefaultResume, type ResumeListItem,
} from '@/api/resume'
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus'
// 命令式调用的组件,按需引入插件不会自动加载其样式,需手动引入
@@ -203,9 +204,6 @@ onMounted(() => {
// ==================== 页面状态 ====================
/** 当前打开弹出菜单的简历 ID */
const activeMenuId = ref<string | null>(null)
// ==================== 编辑简历名称弹窗状态 ====================
/** 编辑弹窗是否可见 */
@@ -231,61 +229,57 @@ const exportResumeName = ref('')
/** 上传弹窗是否可见 */
const uploadDialogVisible = ref(false)
/** 弹出菜单操作项 */
const popupActions = ['设为默认简历', '编辑名称岗位', '导出简历', '删除']
// ==================== 事件处理 ====================
/** 切换弹出菜单的显示/隐藏 */
function toggleMenu(id: string) {
activeMenuId.value = activeMenuId.value === id ? null : id
/** 点击编辑图标 — 打开编辑名称岗位弹窗 */
function handleEditName(item: ResumeItem) {
editResumeId.value = item.id
editResumeName.value = item.name
editTargetPosition.value = item.targetJob
editNameVisible.value = true
}
/** 弹出菜单操作点击 */
async function handleAction(action: string, id: string) {
activeMenuId.value = null
if (action === '删除') {
// 二次确认删除
try {
await ElMessageBox.confirm('确定要删除这份简历吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
// 调用删除接口
const res = await deleteResume(id)
if (res.code === '0') {
ElMessage.success('删除成功')
// 刷新列表
loadResumeList()
} else {
ElMessage.error(res.msg || '删除失败')
}
} catch (error) {
// 用户取消删除或接口报错
if (error !== 'cancel') {
ElMessage.error('删除失败,请稍后重试')
}
/** 设为默认简历 */
async function handleSetDefault(id: string) {
try {
const res = await setDefaultResume(id)
if (res.code === '0') {
ElMessage.success('已设为默认简历')
loadResumeList()
} else {
ElMessage.error(res.msg || '设置失败')
}
} else if (action === '编辑名称岗位') {
// 找到当前简历数据,打开编辑弹窗
const target = resumeList.value.find(r => r.id === id)
if (target) {
editResumeId.value = id
editResumeName.value = target.name
editTargetPosition.value = target.targetJob
editNameVisible.value = true
} catch {
ElMessage.error('设置失败,请稍后重试')
}
}
/** 导出简历 */
function handleExport(item: ResumeItem) {
exportResumeId.value = item.id
exportResumeName.value = item.name || '简历'
exportDialogVisible.value = true
}
/** 删除简历 */
async function handleDelete(id: string) {
try {
await ElMessageBox.confirm('确定要删除这份简历吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
const res = await deleteResume(id)
if (res.code === '0') {
ElMessage.success('删除成功')
loadResumeList()
} else {
ElMessage.error(res.msg || '删除失败')
}
} catch (error) {
if (error !== 'cancel') {
ElMessage.error('删除失败,请稍后重试')
}
} else if (action === '导出简历') {
// 打开导出格式选择弹窗
exportResumeId.value = id
const target = resumeList.value.find(r => r.id === id)
exportResumeName.value = target?.name || '简历'
exportDialogVisible.value = true
} else {
console.log(action, id)
}
}
+644 -285
View File
File diff suppressed because it is too large Load Diff