导师相关接口换offer派接口,职位列表和职位详情,Nova聊天侧边栏UI重写
This commit is contained in:
+109
-291
@@ -4,275 +4,128 @@
|
||||
<div class="job-detail__content">
|
||||
<!-- 页面标题 + Tab 切换 -->
|
||||
<JobPageHeader :activeTab="''" />
|
||||
<div class="bg-white p20 border-ra20">
|
||||
<div class="bg-main p20 border-ra20">
|
||||
<!-- 顶部操作栏 -->
|
||||
<div class="job-detail__toolbar">
|
||||
<button class="job-detail__close-btn" @click="goBack" aria-label="关闭">
|
||||
<svg viewBox="0 0 16 16" fill="none" class="job-detail__close-icon">
|
||||
<path d="M12 4L4 12M4 4l8 8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
||||
</svg>
|
||||
</button>
|
||||
<div class="job-detail__toolbar-right">
|
||||
<button class="job-detail__tool-btn" aria-label="编辑" @click="openDislikeDialog">
|
||||
<svg viewBox="0 0 16 16" fill="none" class="job-detail__tool-icon">
|
||||
<path d="M11.5 2.5l2 2L5 13H3v-2l8.5-8.5z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
</button>
|
||||
<button class="jobs-page__action-icon-btn" :class="{ 'job-detail__tool-btn--liked': job.isFavorite }" aria-label="收藏" @click="toggleFavorite">
|
||||
<svg viewBox="0 0 16 16" :fill="job.isFavorite ? 'currentColor' : 'none'" class="job-detail__tool-icon">
|
||||
<path d="M8 13.7l-1.1-1C3.6 9.8 1.5 7.9 1.5 5.7 1.5 3.9 2.9 2.5 4.7 2.5c1 0 2 .5 2.6 1.2h1.4c.6-.7 1.6-1.2 2.6-1.2 1.8 0 3.2 1.4 3.2 3.2 0 2.2-2.1 4.1-5.4 6.9L8 13.7z" stroke="currentColor" stroke-width="1"/>
|
||||
</svg>
|
||||
</button>
|
||||
<button class="job-detail__apply-btn" @click="handleApply">去投递</button>
|
||||
<!-- 主内容卡片 -->
|
||||
<div class="job-detail__main-card">
|
||||
<!-- 返回按钮 -->
|
||||
<div class="job-detail__back-row">
|
||||
<button class="job-detail__back-btn" @click="goBack">
|
||||
<svg viewBox="0 0 16 16" fill="none" class="job-detail__back-icon">
|
||||
<path d="M10 12L6 8l4-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
<span>返回</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 内容区域(可滚动) -->
|
||||
<div class="job-detail__body scrollbar-thin">
|
||||
<!-- 岗位基本信息区 -->
|
||||
<div class="job-detail__header-section">
|
||||
<!-- 左侧:岗位信息 -->
|
||||
<div class="job-detail__basic-info">
|
||||
<!-- 岗位标题 + 收藏 -->
|
||||
<div class="job-detail__title-row">
|
||||
<h1 class="job-detail__job-title">{{ job.title }}</h1>
|
||||
<button class="job-detail__fav-btn" :class="{ 'job-detail__fav-btn--active': job.isFavorite }" aria-label="收藏" @click="toggleFavorite">
|
||||
<svg viewBox="0 0 16 16" class="job-detail__fav-icon">
|
||||
<path d="M8 13.7l-1.1-1C3.6 9.8 1.5 7.9 1.5 5.7 1.5 3.9 2.9 2.5 4.7 2.5c1 0 2 .5 2.6 1.2h1.4c.6-.7 1.6-1.2 2.6-1.2 1.8 0 3.2 1.4 3.2 3.2 0 2.2-2.1 4.1-5.4 6.9L8 13.7z" stroke="currentColor" stroke-width="1" fill="none"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<!-- 岗位 meta 信息 -->
|
||||
<div class="job-detail__meta-row">
|
||||
<span>{{ job.location }}</span>
|
||||
<span class="job-detail__meta-dot">·</span>
|
||||
<span>{{ job.experience }}</span>
|
||||
<span class="job-detail__meta-dot">·</span>
|
||||
<span>{{ job.education }}</span>
|
||||
<span class="job-detail__meta-dot">·</span>
|
||||
<span>{{ job.salary }}</span>
|
||||
</div>
|
||||
<!-- 操作按钮 -->
|
||||
<div class="job-detail__action-btns">
|
||||
<button class="job-detail__nova-btn" @click="handleAskNova">问Nova</button>
|
||||
<button class="job-detail__apply-btn" @click="handleApply">去投递</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧:匹配度卡片 -->
|
||||
<div class="job-detail__match-card">
|
||||
<div class="job-detail__match-top">
|
||||
<span class="job-detail__match-score">{{ job.matchScore }}%</span>
|
||||
<span class="job-detail__match-label">高匹配度</span>
|
||||
</div>
|
||||
<div class="job-detail__match-list">
|
||||
<div class="job-detail__match-row" v-for="m in matchItems" :key="m.label">
|
||||
<span class="job-detail__match-row-label">{{ m.label }}</span>
|
||||
<span class="job-detail__match-row-score">{{ m.score }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 内容区域(可滚动) -->
|
||||
<div class="job-detail__body">
|
||||
<!-- 导航 Tab:岗位详情 / 公司概况 -->
|
||||
<div class="job-detail__nav-tabs">
|
||||
<div
|
||||
class="job-detail__nav-tab"
|
||||
:class="{ 'job-detail__nav-tab--active': activeSection === 'job' }"
|
||||
@click="activeSection = 'job'"
|
||||
>岗位详情</div>
|
||||
<div
|
||||
class="job-detail__nav-tab"
|
||||
:class="{ 'job-detail__nav-tab--active': activeSection === 'company' }"
|
||||
@click="scrollToCompany"
|
||||
>公司概况</div>
|
||||
<div class="job-detail__nav-tab-right">
|
||||
<span class="job-detail__link-btn" @click="handleFeedback">问题反馈</span>
|
||||
<span class="job-detail__link-btn" @click="handleReport">原链接</span>
|
||||
</div>
|
||||
<!-- 优化简历提示条 -->
|
||||
<div class="job-detail__optimize-bar">
|
||||
<span class="job-detail__optimize-text">优化简历大幅提升面试成功率</span>
|
||||
<button class="job-detail__optimize-btn" @click="handleGenerateResume">生成岗位专属简历</button>
|
||||
</div>
|
||||
|
||||
<!-- 岗位职责 -->
|
||||
<div class="job-detail__section">
|
||||
<h3 class="job-detail__section-title">岗位职责</h3>
|
||||
<div class="job-detail__section-list">
|
||||
<div class="job-detail__section-item" v-for="(item, i) in job.responsibilities" :key="i">{{ item }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 岗位详情内容 -->
|
||||
<template v-if="activeSection === 'job'">
|
||||
<!-- 公司 & 职位头部 -->
|
||||
<div class="job-detail__card">
|
||||
<div class="job-detail__card-top">
|
||||
<div class="job-detail__card-left">
|
||||
<div class="job-detail__company-row">
|
||||
<div class="job-detail__company-icon">
|
||||
<img v-if="job.companyLogoUrl" :src="job.companyLogoUrl" :alt="job.company" class="job-detail__company-logo-img" />
|
||||
<svg v-else viewBox="0 0 24 24" fill="none" class="job-detail__company-svg">
|
||||
<rect x="3" y="7" width="18" height="14" rx="2" stroke="currentColor" stroke-width="1.5"/>
|
||||
<path d="M7 7V5a2 2 0 012-2h6a2 2 0 012 2v2" stroke="currentColor" stroke-width="1.5"/>
|
||||
<path d="M3 13h18" stroke="currentColor" stroke-width="1.5"/>
|
||||
</svg>
|
||||
</div>
|
||||
<span class="job-detail__company-name">{{ job.company }}</span>
|
||||
</div>
|
||||
<h3 class="job-detail__job-title">{{ job.title }}</h3>
|
||||
<div class="job-detail__job-meta">
|
||||
<span class="job-detail__meta-item">
|
||||
<svg viewBox="0 0 16 16" fill="none" class="job-detail__meta-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>
|
||||
{{ job.location }}
|
||||
</span>
|
||||
<span class="job-detail__meta-item">
|
||||
<svg viewBox="0 0 16 16" fill="none" class="job-detail__meta-icon">
|
||||
<rect x="2" y="3" width="12" height="11" rx="1.5" stroke="currentColor" stroke-width="1.2"/>
|
||||
<path d="M2 6.5h12" stroke="currentColor" stroke-width="1.2"/>
|
||||
</svg>
|
||||
{{ job.experience }}
|
||||
</span>
|
||||
<span class="job-detail__meta-item">
|
||||
<svg viewBox="0 0 16 16" fill="none" class="job-detail__meta-icon">
|
||||
<rect x="2" y="2" width="12" height="12" rx="2" stroke="currentColor" stroke-width="1.2"/>
|
||||
<path d="M5 8h6M8 5v6" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ job.type }}
|
||||
</span>
|
||||
<span v-if="job.education" class="job-detail__meta-item">
|
||||
<svg viewBox="0 0 16 16" fill="none" class="job-detail__meta-icon">
|
||||
<path d="M8 2L1 6l7 4 7-4-7-4z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/>
|
||||
<path d="M3 7.5v4l5 3 5-3v-4" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
{{ job.education }}
|
||||
</span>
|
||||
<span v-if="job.salary" class="job-detail__meta-item">
|
||||
<svg viewBox="0 0 16 16" fill="none" class="job-detail__meta-icon">
|
||||
<path d="M8 1v14M4 4h8M3 8h10M5 12h6" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
{{ job.salary }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 匹配度环 -->
|
||||
<div class="job-detail__match-area">
|
||||
<div class="job-detail__match-ring">
|
||||
<svg viewBox="0 0 80 80" class="job-detail__ring-svg">
|
||||
<circle cx="40" cy="40" r="34" stroke-width="5" stroke="#E8E8E8" fill="none" opacity="0.3"/>
|
||||
<circle cx="40" cy="40" r="34" stroke-width="5" fill="none"
|
||||
stroke="#4FC2C9"
|
||||
stroke-linecap="round"
|
||||
:stroke-dasharray="2 * Math.PI * 34"
|
||||
:stroke-dashoffset="2 * Math.PI * 34 * (1 - job.matchScore / 100)"
|
||||
transform="rotate(-90 40 40)"
|
||||
/>
|
||||
</svg>
|
||||
<div class="job-detail__match-score">{{ job.matchScore }}%</div>
|
||||
</div>
|
||||
<div class="job-detail__match-label">岗位匹配值</div>
|
||||
<div class="job-detail__match-details">
|
||||
<div class="job-detail__match-item" v-for="m in matchItems" :key="m.label">
|
||||
<div class="job-detail__match-mini-ring">
|
||||
<svg viewBox="0 0 40 40" class="job-detail__mini-ring-svg">
|
||||
<circle cx="20" cy="20" r="16" stroke-width="3" stroke="#E8E8E8" fill="none" opacity="0.3"/>
|
||||
<circle cx="20" cy="20" r="16" stroke-width="3" fill="none"
|
||||
stroke="#BFBFBF"
|
||||
stroke-linecap="round"
|
||||
:stroke-dasharray="2 * Math.PI * 16"
|
||||
:stroke-dashoffset="2 * Math.PI * 16 * (1 - m.score / 100)"
|
||||
transform="rotate(-90 20 20)"
|
||||
/>
|
||||
</svg>
|
||||
<span class="job-detail__mini-score">{{ m.score }}%</span>
|
||||
</div>
|
||||
<span class="job-detail__match-item-label">{{ m.label }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 优化简历提示 -->
|
||||
<div class="job-detail__optimize-bar">
|
||||
<span>优化简历大幅提升面试成功率!</span>
|
||||
<button class="job-detail__optimize-btn" @click="handleGenerateResume">生成岗位专属简历</button>
|
||||
</div>
|
||||
|
||||
<!-- 岗位描述 -->
|
||||
<div class="job-detail__card">
|
||||
<p class="job-detail__desc-text">{{ job.companyInfo.summary }}</p>
|
||||
<div class="job-detail__tag-list">
|
||||
<span v-for="tag in job.companyInfo.tags" :key="tag" class="job-detail__tag">{{ tag }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 岗位职责 -->
|
||||
<div class="job-detail__card">
|
||||
<h3 class="job-detail__section-title">岗位职责</h3>
|
||||
<ol class="job-detail__list">
|
||||
<li v-for="(item, i) in job.responsibilities" :key="i">{{ item }}</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<!-- 任职要求 -->
|
||||
<div class="job-detail__card">
|
||||
<div class="job-detail__section-header">
|
||||
<h3 class="job-detail__section-title">任职要求</h3>
|
||||
<span class="job-detail__skill-hint">
|
||||
|
||||
<!-- 深色为你拥有的技能-->
|
||||
</span>
|
||||
</div>
|
||||
<div class="job-detail__skill-tags">
|
||||
|
||||
<!-- 先不加点击选中 @click="skill.matched = !skill.matched"-->
|
||||
<!-- 任职要求 -->
|
||||
<div class="job-detail__section">
|
||||
<h3 class="job-detail__section-title">任职要求</h3>
|
||||
<!-- 技能标签 -->
|
||||
<div class="job-detail__skill-tags">
|
||||
<span
|
||||
v-for="skill in job.requiredSkills"
|
||||
:key="skill.name"
|
||||
class="job-detail__skill-tag cursor-po"
|
||||
class="job-detail__skill-tag"
|
||||
:class="{ 'job-detail__skill-tag--matched': skill.matched }"
|
||||
>{{ skill.name }}</span>
|
||||
</div>
|
||||
<!-- 要求列表 -->
|
||||
<div class="job-detail__section-list">
|
||||
<div class="job-detail__section-item" v-for="(item, i) in job.requirements" :key="i">{{ item }}</div>
|
||||
</div>
|
||||
<!-- 加分项 -->
|
||||
<div v-if="job.bonus" class="job-detail__bonus-item">加分项:{{ job.bonus }}</div>
|
||||
</div>
|
||||
|
||||
>
|
||||
{{ skill.name }}
|
||||
<svg v-if="skill.matched" viewBox="0 0 12 12" fill="none" class="job-detail__skill-close">
|
||||
<path d="M9 3L3 9M3 3l6 6" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
</span>
|
||||
<!-- 公司概况 -->
|
||||
<div class="job-detail__section">
|
||||
<h3 class="job-detail__section-title">公司概况</h3>
|
||||
<div class="job-detail__company-block">
|
||||
<!-- 公司 logo + 名称 + 标签 -->
|
||||
<div class="job-detail__company-head">
|
||||
<div class="job-detail__company-logo">
|
||||
<img v-if="job.companyLogoUrl" :src="job.companyLogoUrl" :alt="job.company" class="job-detail__company-logo-img" />
|
||||
<svg v-else viewBox="0 0 32 32" fill="none" class="job-detail__company-svg">
|
||||
<rect x="4" y="8" width="24" height="18" rx="3" stroke="currentColor" stroke-width="1.5"/>
|
||||
<path d="M10 8V6a3 3 0 013-3h6a3 3 0 013 3v2" stroke="currentColor" stroke-width="1.5"/>
|
||||
</svg>
|
||||
</div>
|
||||
<ol class="job-detail__list">
|
||||
<li v-for="(item, i) in job.requirements" :key="i">{{ item }}</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<!-- 加分项 -->
|
||||
<div class="job-detail__card">
|
||||
<h3 class="job-detail__section-title">加分项</h3>
|
||||
<p class="job-detail__desc-text">{{ job.bonus }}</p>
|
||||
</div>
|
||||
|
||||
<!-- 公司概况 -->
|
||||
<div ref="companySectionRef" class="job-detail__card">
|
||||
<h3 class="job-detail__section-title">公司概况</h3>
|
||||
<div class="job-detail__company-info">
|
||||
<div class="job-detail__company-info-left">
|
||||
<div class="job-detail__company-header">
|
||||
<div class="job-detail__company-logo">
|
||||
<img v-if="job.companyLogoUrl" :src="job.companyLogoUrl" :alt="job.company" class="job-detail__company-logo-img" />
|
||||
<svg v-else viewBox="0 0 24 24" fill="none" class="job-detail__company-svg">
|
||||
<rect x="3" y="7" width="18" height="14" rx="2" stroke="currentColor" stroke-width="1.5"/>
|
||||
<path d="M7 7V5a2 2 0 012-2h6a2 2 0 012 2v2" stroke="currentColor" stroke-width="1.5"/>
|
||||
</svg>
|
||||
</div>
|
||||
<span class="job-detail__company-info-name">{{ job.company }}</span>
|
||||
</div>
|
||||
<p class="job-detail__company-desc">{{ job.companyInfo.description }}</p>
|
||||
</div>
|
||||
<div class="job-detail__company-info-right pr50">
|
||||
<div class="job-detail__company-meta-item">
|
||||
<span class="job-detail__meta-label">成立时间:</span>
|
||||
<span>{{ job.companyInfo.founded }}</span>
|
||||
</div>
|
||||
<div class="job-detail__company-meta-item">
|
||||
<span class="job-detail__meta-label">公司地址:</span>
|
||||
<span>{{ job.companyInfo.address }}</span>
|
||||
</div>
|
||||
<div class="job-detail__company-meta-item">
|
||||
<span class="job-detail__meta-label">企业规模:</span>
|
||||
<span>{{ job.companyInfo.size }}</span>
|
||||
</div>
|
||||
<div class="job-detail__company-meta-item">
|
||||
<span class="job-detail__meta-label">官网:</span>
|
||||
<a :href="job.companyInfo.website" target="_blank" class="job-detail__company-link">{{ job.companyInfo.website }}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="job-detail__company-name-info">
|
||||
<span class="job-detail__company-name">{{ job.company }}</span>
|
||||
<span class="job-detail__company-sub">{{ job.companyInfo.industryName }}{{ job.companyInfo.size ? ' · ' + job.companyInfo.size : '' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 融资 -->
|
||||
<div class="job-detail__card">
|
||||
<h3 class="job-detail__section-title">融资</h3>
|
||||
<p class="job-detail__desc-text">
|
||||
<span class="job-detail__funding-label">当前融资阶段:</span>{{ job.companyInfo.fundingStage }}
|
||||
<span class="job-detail__funding-label" style="margin-left: 0.3rem;">最新估值:</span>{{ job.companyInfo.valuation }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 最新动态 -->
|
||||
<div class="job-detail__card" v-if="job.companyInfo.news.length">
|
||||
<h3 class="job-detail__section-title">最新动态</h3>
|
||||
<div class="job-detail__news-list">
|
||||
<div v-for="(news, i) in job.companyInfo.news" :key="i" class="job-detail__news-item">
|
||||
<p class="job-detail__news-desc">{{ news }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 公司概况 Tab 已移除,点击直接滚动到岗位详情中的公司概况部分 -->
|
||||
<!-- 公司描述 -->
|
||||
<p class="job-detail__company-desc">{{ job.companyInfo.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<AiChat :job-id="jobId" />
|
||||
|
||||
<!-- 职位不感兴趣反馈弹窗 -->
|
||||
<JobDislikeDialog ref="dislikeDialogRef" v-model="showDislikeDialog" :job-id="jobId" />
|
||||
|
||||
<!-- 职位问题反馈弹窗 -->
|
||||
<JobFeedbackDialog ref="feedbackDialogRef" v-model="showFeedbackDialog" :job-id="jobId" />
|
||||
<AiChat ref="aiChatRef" :job-id="jobId" />
|
||||
|
||||
<!-- 岗位专属简历定制弹窗 -->
|
||||
<JobResumeCustomDialog v-model="showResumeCustomDialog" :job-info="resumeCustomJobInfo" :job-id="jobId" @skip="handleSkipToApply" />
|
||||
@@ -287,15 +140,13 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed, nextTick, onMounted } from 'vue'
|
||||
import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { useStore } from 'vuex'
|
||||
import { formatEmploymentType } from '@/stores/index'
|
||||
import SideNav from '@/components/SideNav.vue'
|
||||
import AiChat from '@/components/AiChat.vue'
|
||||
import JobPageHeader from '@/components/JobPageHeader.vue'
|
||||
import JobDislikeDialog from '@/components/JobDislikeDialog.vue'
|
||||
import JobFeedbackDialog from '@/components/JobFeedbackDialog.vue'
|
||||
import JobResumeCustomDialog from '@/components/JobResumeCustomDialog.vue'
|
||||
import MemberAccessDialog from '@/components/MemberAccessDialog.vue'
|
||||
import FullscreenLoading from '@/components/FullscreenLoading.vue'
|
||||
@@ -349,23 +200,11 @@ function splitNumberedText(text: string | undefined): string[] {
|
||||
|
||||
// ==================== 页面状态 ====================
|
||||
|
||||
/** 当前激活的内容区 Tab:job-岗位详情 / company-公司概况 */
|
||||
const activeSection = ref<'job' | 'company'>('job')
|
||||
|
||||
/** 公司概况卡片 ref,用于滚动定位 */
|
||||
const companySectionRef = ref<HTMLElement | null>(null)
|
||||
/** 当前激活的内容区 Tab(保留兼容性但不再使用) */
|
||||
|
||||
/** 是否正在加载 */
|
||||
const loading = ref(false)
|
||||
|
||||
/** 点击公司概况 tab 时,确保显示岗位详情内容并滚动到公司概况卡片 */
|
||||
function scrollToCompany() {
|
||||
activeSection.value = 'job'
|
||||
nextTick(() => {
|
||||
companySectionRef.value?.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
||||
})
|
||||
}
|
||||
|
||||
// ==================== 岗位详情数据 ====================
|
||||
|
||||
/** 匹配度维度列表(岗位匹配环下方的子维度) */
|
||||
@@ -525,24 +364,8 @@ onMounted(() => {
|
||||
|
||||
// ==================== 事件处理 ====================
|
||||
|
||||
/** 不感兴趣弹窗状态 */
|
||||
const showDislikeDialog = ref(false)
|
||||
const dislikeDialogRef = ref<InstanceType<typeof JobDislikeDialog> | null>(null)
|
||||
|
||||
/** 问题反馈弹窗状态 */
|
||||
const showFeedbackDialog = ref(false)
|
||||
const feedbackDialogRef = ref<InstanceType<typeof JobFeedbackDialog> | null>(null)
|
||||
|
||||
/** 打开不感兴趣弹窗 */
|
||||
function openDislikeDialog() {
|
||||
dislikeDialogRef.value?.resetForm()
|
||||
showDislikeDialog.value = true
|
||||
}
|
||||
|
||||
/** 返回职位列表页 */
|
||||
function goBack() {
|
||||
// 使用 back() 回退,保证 Jobs 页能正确恢复缓存
|
||||
// 如果没有历史记录(直接访问详情页),则 push 到列表页
|
||||
if (window.history.length > 1) {
|
||||
router.back()
|
||||
} else {
|
||||
@@ -550,17 +373,12 @@ function goBack() {
|
||||
}
|
||||
}
|
||||
|
||||
/** 问题反馈 */
|
||||
function handleFeedback() {
|
||||
feedbackDialogRef.value?.resetForm()
|
||||
showFeedbackDialog.value = true
|
||||
}
|
||||
/** AiChat 组件引用 */
|
||||
const aiChatRef = ref<InstanceType<typeof AiChat> | null>(null)
|
||||
|
||||
/** 跳转到原链接 */
|
||||
function handleReport() {
|
||||
if (job.sourceUrl) {
|
||||
window.open(job.sourceUrl, '_blank')
|
||||
}
|
||||
/** 问 Nova — 触发 AI 聊天,推送提示消息 */
|
||||
function handleAskNova() {
|
||||
aiChatRef.value?.triggerAsk()
|
||||
}
|
||||
|
||||
// ==================== 岗位专属简历定制弹窗 ====================
|
||||
|
||||
+40
-24
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="jobs-page dflex">
|
||||
<div class="jobs-page">
|
||||
<SideNav />
|
||||
<div class="jobs-page__content">
|
||||
|
||||
@@ -16,25 +16,7 @@
|
||||
|
||||
<!-- 页面标题 + Tab 切换 -->
|
||||
<JobPageHeader v-model:activeTab="activeTab" :favoriteCount="favoriteTotal" :applyCount="applyTotal" />
|
||||
<!-- 收藏统计栏 -->
|
||||
<div v-if="activeTab === 'collected'" class="jobs-page__filters-bar">
|
||||
<div class="jobs-page__fav-stats">
|
||||
<span class="jobs-page__fav-stats-item">有效({{ favoriteValidCount }})</span>
|
||||
<span class="jobs-page__fav-stats-item">失效({{ favoriteInvalidCount }})</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 投递状态筛选栏 -->
|
||||
<div v-if="activeTab === 'applied'" class="jobs-page__filters-bar">
|
||||
<div class="jobs-page__fav-stats">
|
||||
<span
|
||||
v-for="tab in applyStatusTabs"
|
||||
:key="tab.status"
|
||||
class="jobs-page__fav-stats-item"
|
||||
:class="{ 'jobs-page__fav-stats-item--active': applyStatusFilter === tab.status }"
|
||||
@click="switchApplyStatus(tab.status)"
|
||||
>{{ tab.label }}({{ tab.count }})</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 筛选条件 -->
|
||||
<div v-if="isRecommendTab" class="jobs-page__filters-bar">
|
||||
<div class="jobs-page__filters">
|
||||
@@ -47,6 +29,9 @@
|
||||
:regionCodes="selectedRegionCodes"
|
||||
:level="2"
|
||||
:maxSelect="3"
|
||||
:triggerStyle="selectorTriggerStyle"
|
||||
:hoverStyle="selectorHoverStyle"
|
||||
:displayStyle="selectorDisplayStyle"
|
||||
@update:regionCodes="onRegionChange"
|
||||
/>
|
||||
<!-- 岗位筛选:使用岗位选择组件 -->
|
||||
@@ -56,6 +41,9 @@
|
||||
:maxSelect="3"
|
||||
:level="3"
|
||||
:allowParentSelect="true"
|
||||
:triggerStyle="selectorTriggerStyle"
|
||||
:hoverStyle="selectorHoverStyle"
|
||||
:displayStyle="selectorDisplayStyle"
|
||||
@update:categoryIds="onCategoryChange"
|
||||
/>
|
||||
<!-- 行业筛选:使用行业选择组件 -->
|
||||
@@ -65,6 +53,9 @@
|
||||
:maxSelect="3"
|
||||
:level="2"
|
||||
:allowParentSelect="true"
|
||||
:triggerStyle="selectorTriggerStyle"
|
||||
:hoverStyle="selectorHoverStyle"
|
||||
:displayStyle="selectorDisplayStyle"
|
||||
@update:industryIds="onIndustryChange"
|
||||
/>
|
||||
<!-- 其他筛选条件 -->
|
||||
@@ -75,7 +66,7 @@
|
||||
>
|
||||
<span>{{ filter.selected || filter.label }}</span>
|
||||
<svg class="jobs-page__filter-arrow-icon" viewBox="0 0 12 12" fill="none">
|
||||
<path d="M3 4.5L6 7.5L9 4.5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M3 4.5L6 7.5L9 4.5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
<!-- 工作类型下拉菜单 -->
|
||||
<div
|
||||
@@ -112,7 +103,7 @@
|
||||
</div>
|
||||
|
||||
<!-- 职位列表 -->
|
||||
<div ref="jobListRef" class="jobs-page__list pr5" :style="restoring ? { visibility: 'hidden' } : {}" @scroll="onListScroll">
|
||||
<div ref="jobListRef" class="jobs-page__list pr5 scrollbar-thin" :style="restoring ? { visibility: 'hidden' } : {}" @scroll="onListScroll">
|
||||
<div
|
||||
v-for="(job, index) in jobList"
|
||||
:key="index"
|
||||
@@ -151,7 +142,7 @@
|
||||
</svg>
|
||||
{{ job.regionName }}
|
||||
</span>
|
||||
<span class="jobs-page__meta-edu">本科</span>
|
||||
<span v-if="formatEducation(job.education)" class="jobs-page__meta-edu">{{ formatEducation(job.education) }}</span>
|
||||
<span v-if="formatEmploymentType(job.recruitCategory)" class="jobs-page__meta-recruit">{{ formatEmploymentType(job.recruitCategory) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -267,7 +258,7 @@
|
||||
import { ref, watch, onMounted, onBeforeUnmount, nextTick, computed } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { useStore } from 'vuex'
|
||||
import { JOB_TYPE_OPTIONS, formatEmploymentType } from '@/stores/index'
|
||||
import { JOB_TYPE_OPTIONS, formatEmploymentType, formatEducation } from '@/stores/index'
|
||||
import SideNav from '@/components/SideNav.vue'
|
||||
import AiChat from '@/components/AiChat.vue'
|
||||
import JobPageHeader from '@/components/JobPageHeader.vue'
|
||||
@@ -340,6 +331,31 @@ function askAssistant(job: JobItem) {
|
||||
currentAskJobId.value = job.id
|
||||
}
|
||||
|
||||
/** 选择器触发按钮的自定义样式,适配弹窗内布局(参考 ProfileEditDrawer 中 regionTriggerStyle) */
|
||||
const selectorTriggerStyle: Record<string, string> = {
|
||||
width: '100%',
|
||||
'box-sizing': 'border-box',
|
||||
padding: '0.08rem 0.12rem',
|
||||
'font-size': '0.13rem',
|
||||
color: '#666',
|
||||
background: '#fff',
|
||||
border: '1px solid transparent',
|
||||
'border-radius': '0.08rem',
|
||||
'max-width': 'none',
|
||||
'justify-content': 'space-between',
|
||||
}
|
||||
|
||||
/** 选择器显示文字的自定义样式,覆盖默认 max-width: 1.6rem */
|
||||
const selectorDisplayStyle: Record<string, string> = {
|
||||
'max-width': 'none',
|
||||
}
|
||||
|
||||
/** 选择器触发按钮 hover 时的样式 */
|
||||
const selectorHoverStyle: Record<string, string> = {
|
||||
background: '#12C7BE',
|
||||
color: '#fff',
|
||||
}
|
||||
|
||||
// ==================== 收藏统计 ====================
|
||||
|
||||
/** 收藏总数(用于 Tab 标签显示) */
|
||||
|
||||
@@ -100,7 +100,10 @@
|
||||
<button
|
||||
class="mentor-page__detail-btn"
|
||||
@click="goToDetail(mentor)"
|
||||
>查看详情 →</button>
|
||||
><span>查看详情</span> <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.51612 4.07575C7.38279 3.94242 7.31879 3.78686 7.32412 3.60908C7.32945 3.43131 7.39901 3.27575 7.53278 3.14241C7.66612 3.02019 7.82167 2.95619 7.99946 2.95041C8.17723 2.94464 8.33278 3.00864 8.46612 3.14241L12.8661 7.54241C12.9328 7.60908 12.9801 7.6813 13.0081 7.75908C13.0361 7.83686 13.0497 7.92019 13.0488 8.00908C13.0479 8.09797 13.0339 8.18131 13.0068 8.25908C12.9797 8.33686 12.9326 8.40908 12.8654 8.47575L8.46545 12.8757C8.34323 12.998 8.19034 13.0591 8.00679 13.0591C7.82323 13.0591 7.66501 12.998 7.53212 12.8757C7.39879 12.7424 7.33212 12.584 7.33212 12.4004C7.33212 12.2169 7.39879 12.0586 7.53212 11.9257L10.7828 8.67575H3.33279C3.1439 8.67575 2.98546 8.61175 2.85745 8.48375C2.72945 8.35575 2.66567 8.19753 2.66612 8.00908C2.66656 7.82064 2.73056 7.6622 2.85812 7.53375C2.98568 7.40531 3.1439 7.34153 3.33279 7.34242L10.7828 7.34242L7.51612 4.07575Z" fill="#52CAD1"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -426,12 +426,14 @@ async function handleSaveEdit(data: Record<string, any>) {
|
||||
mobileNumber: data.phone,
|
||||
regionCode: data.location,
|
||||
wechatNumber: data.wechat,
|
||||
portfolioUrl: data.portfolioUrl,
|
||||
})
|
||||
// 接口成功后更新本地数据
|
||||
profile.value.name = data.name
|
||||
profile.value.email = data.email
|
||||
profile.value.phone = data.phone
|
||||
profile.value.wechat = data.wechat
|
||||
profile.value.portfolioUrl = data.portfolioUrl || ''
|
||||
/** 将城市编码存入 regionCode,先直接显示编码,后续联调获取接口再做名称转换 */
|
||||
profile.value.regionCode = data.location || ''
|
||||
ElMessage.success('个人信息保存成功')
|
||||
|
||||
Reference in New Issue
Block a user