4个mvp补丁

This commit is contained in:
2026-07-24 18:15:31 +08:00
parent a0f01dd697
commit bb7a8c55b2
43 changed files with 207 additions and 35 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 462 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 246 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 485 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 232 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 390 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 408 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 247 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

@@ -1398,9 +1398,9 @@
} }
} }
// 立即去投递按钮 // 下载专属简历按钮
&__submit-btn { &__submit-btn {
flex: 1; width: 100%;
height: 0.48rem; height: 0.48rem;
background: $btn-dark; background: $btn-dark;
color: $bg-white; color: $bg-white;
@@ -1415,6 +1415,20 @@
background: $btn-dark-hover; background: $btn-dark-hover;
} }
} }
// 下载专属简历按钮包裹(含下拉菜单定位)
&__submit-wrap {
position: relative;
flex: 1;
.job-resume-custom-dialog__top-download-menu {
top: auto;
bottom: 100%;
margin-top: 0;
margin-bottom: 0.06rem;
width: 100%;
}
}
} }
// 右侧滑入动画 // 右侧滑入动画
@@ -53,6 +53,7 @@
} }
&__item { &__item {
position: relative;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.04rem; gap: 0.04rem;
@@ -120,6 +121,26 @@
flex: none; flex: none;
} }
// 公测群二维码弹出层(hover索引5时显示)
&__qrcode-popup {
position: absolute;
top: calc(100% + 0.08rem);
left: 0;
padding: 0.08rem;
background: #fff;
border-radius: 0.08rem;
box-shadow: 0 0.02rem 0.12rem rgba(0, 0, 0, 0.08);
z-index: 100;
}
&__qrcode-img {
display: block;
width: auto;
height: auto;
max-width: 1.6rem;
border-radius: 0.04rem;
}
&__footer { &__footer {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
+65 -2
View File
@@ -168,11 +168,34 @@
&__ai-tip-text { &__ai-tip-text {
font-size: 0.12rem; font-size: 0.12rem;
line-height: 0.16rem; line-height: 0.16rem;
color: $accent; color: $text-light;
vertical-align: text-top; vertical-align: text-top;
margin-left: 0.03rem; margin-left: 0.03rem;
} }
// AI 推荐的可点击岗位/行业关键词
&__ai-tip-keyword {
color: $accent;
text-decoration: underline;
cursor: pointer;
transition: opacity 0.2s;
&:hover {
opacity: 0.75;
}
}
// 关键词之间的顿号(无下划线,text-light 色)
&__ai-tip-comma {
color: $text-light;
text-decoration: none;
}
// ";行业:" 分隔符保持 text-light 色
&__ai-tip-separator {
color: $text-light;
}
// 筛选条件 // 筛选条件
&__filters { &__filters {
display: flex; display: flex;
@@ -185,6 +208,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.08rem; gap: 0.08rem;
flex-wrap: wrap;
} }
&__filter-item { &__filter-item {
@@ -777,7 +801,46 @@
// 暂无数据提示 // 暂无数据提示
&__empty { &__empty {
text-align: center; text-align: center;
padding: 1rem 0; font-size: 0.14rem;
color: $text-light;
}
// 空状态图片
&__empty-img {
width: 1.24rem;
height: 1.3rem;
display: block;
margin: 1.6rem auto 0.2rem;
}
// 空状态主标题
&__empty-title {
font-size: 0.14rem;
color: $text-light;
margin-bottom: 0.08rem;
}
// 空状态副标题
&__empty-subtitle {
font-size: 0.14rem;
color: $text-light;
}
// "减少筛选条件" 可点击链接
&__empty-link {
color: $accent;
text-decoration: underline;
cursor: pointer;
&:hover {
opacity: 0.75;
}
}
// 列表结果较少时的底部提示
&__few-results {
text-align: center;
padding: 0.12rem 0;
font-size: 0.14rem; font-size: 0.14rem;
color: $text-light; color: $text-light;
} }
+10 -17
View File
@@ -12,21 +12,7 @@
</button> </button>
<h2 class="job-resume-custom-dialog__drawer-title">生成你的岗位专属简历</h2> <h2 class="job-resume-custom-dialog__drawer-title">生成你的岗位专属简历</h2>
</div> </div>
<!-- 下载简历按钮步骤三显示位于步骤指示器上方 -->
<div v-if="currentStep === 4" class="job-resume-custom-dialog__top-download mt10 ml12">
<button class="job-resume-custom-dialog__top-download-btn" @click="toggleDownloadMenu">
<svg viewBox="0 0 16 16" fill="none" class="job-resume-custom-dialog__top-download-icon">
<path d="M8 2v8M8 10l-3-3M8 10l3-3" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3 12h10" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/>
</svg>
下载简历
</button>
<!-- 下载下拉菜单 -->
<div v-if="showDownloadMenu" class="job-resume-custom-dialog__top-download-menu">
<button class="job-resume-custom-dialog__top-download-option" @click="handleDownload('pdf')">下载PDF</button>
<button class="job-resume-custom-dialog__top-download-option" @click="handleDownload('word')">下载Word</button>
</div>
</div>
<!-- 步骤指示器 --> <!-- 步骤指示器 -->
<div class="job-resume-custom-dialog__steps pt10"> <div class="job-resume-custom-dialog__steps pt10">
<div class="job-resume-custom-dialog__step" :class="{ 'job-resume-custom-dialog__step--active': currentStep === 2 }"> <div class="job-resume-custom-dialog__step" :class="{ 'job-resume-custom-dialog__step--active': currentStep === 2 }">
@@ -327,8 +313,15 @@
<div v-if="currentStep === 4" class="job-resume-custom-dialog__preview-footer mt10 pt30"> <div v-if="currentStep === 4" class="job-resume-custom-dialog__preview-footer mt10 pt30">
<!-- 左侧上一步按钮 --> <!-- 左侧上一步按钮 -->
<button class="job-resume-custom-dialog__footer-prev-btn" @click="goToStep(3)">上一步</button> <button class="job-resume-custom-dialog__footer-prev-btn" @click="goToStep(3)">上一步</button>
<!-- 右侧立即去投递按钮 --> <!-- 右侧下载专属简历按钮 -->
<button class="job-resume-custom-dialog__submit-btn" @click="handleSubmit">立即去投递</button> <div class="job-resume-custom-dialog__submit-wrap">
<button class="job-resume-custom-dialog__submit-btn" @click="toggleDownloadMenu">下载专属简历</button>
<!-- 下载下拉菜单 -->
<div v-if="showDownloadMenu" class="job-resume-custom-dialog__top-download-menu">
<button class="job-resume-custom-dialog__top-download-option" @click="handleDownload('pdf')">下载PDF</button>
<button class="job-resume-custom-dialog__top-download-option" @click="handleDownload('word')">下载Word</button>
</div>
</div>
</div> </div>
</div> </div>
+7
View File
@@ -28,6 +28,13 @@
<!-- 索引0的时候显示"全网"小标签 --> <!-- 索引0的时候显示"全网"小标签 -->
<span v-if="index === 0" class="side-nav__tag-quanwang mt2 ml8">全网</span> <span v-if="index === 0" class="side-nav__tag-quanwang mt2 ml8">全网</span>
<!-- 索引5的时候显示"公测群"小标签 -->
<span v-if="index === 5" class="side-nav__tag-quanwang mt2 ml8">公测群</span>
<!-- 索引5 hover时显示公测群二维码 -->
<div v-if="index === 5 && hoverIndex === 5" class="side-nav__qrcode-popup">
<img src="@/assets/images/home/mobile-qcCode.png" alt="公测群二维码" class="side-nav__qrcode-img" />
</div>
<span v-if="item.badge" class="side-nav__badge">{{ item.badge }}</span> <span v-if="item.badge" class="side-nav__badge">{{ item.badge }}</span>
</a> </a>
</nav> </nav>
+88 -14
View File
@@ -144,7 +144,7 @@
<div class="jobs-page__ai-tip-content"> <div class="jobs-page__ai-tip-content">
<img class="jobs-page__ai-tip-logo" src="@/assets/images/logo-offerpai-2.png" alt="Nova" /> <img class="jobs-page__ai-tip-logo" src="@/assets/images/logo-offerpai-2.png" alt="Nova" />
<span class="jobs-page__ai-tip-text"> <span class="jobs-page__ai-tip-text">
Nova根据你的个人背景建议的<template v-if="aiCategoryNames">岗位:{{ aiCategoryNames }}</template><template v-if="aiIndustryNames">行业{{ aiIndustryNames }}</template> Nova根据你的个人背景建议的<template v-if="aiCategoryItems.length">岗位:<template v-for="(item, idx) in aiCategoryItems" :key="'cat-' + item.id"><span class="jobs-page__ai-tip-keyword" @click="handleAddCategory(item.id)">{{ item.name }}</span><span v-if="idx < aiCategoryItems.length - 1" class="jobs-page__ai-tip-comma">、</span></template></template><template v-if="aiIndustryItems.length"><span class="jobs-page__ai-tip-separator">;行业:</span><template v-for="(item, idx) in aiIndustryItems" :key="'ind-' + item.id"><span class="jobs-page__ai-tip-keyword" @click="handleAddIndustry(item.id)">{{ item.name }}</span><span v-if="idx < aiIndustryItems.length - 1" class="jobs-page__ai-tip-comma"></span></template></template>
</span> </span>
</div> </div>
</div> </div>
@@ -292,7 +292,16 @@
<span>加载中...</span> <span>加载中...</span>
</div> </div>
<!-- 暂无数据提示 --> <!-- 暂无数据提示 -->
<div v-if="!loading && jobList.length === 0" class="jobs-page__empty">暂无数据</div> <div v-if="!loading && jobList.length === 0" class="jobs-page__empty">
<img class="jobs-page__empty-img" src="@/assets/images/list-empty.png" alt="暂无数据" />
<p class="jobs-page__empty-title">符合条件的岗位较少</p>
<p class="jobs-page__empty-subtitle">试试 <span class="jobs-page__empty-link" @click="clearAllFilters">减少筛选条件</span> 或调整您意向的关键词哦~</p>
</div>
<!-- 列表结果少于5条时的提示 -->
<div v-if="!loading && jobList.length > 0 && jobList.length < 5 && hasActiveFilters" class="jobs-page__few-results">
<p class="jobs-page__empty-title">符合条件的岗位较少</p>
<p class="jobs-page__empty-subtitle">试试 <span class="jobs-page__empty-link" @click="clearAllFilters">减少筛选条件</span> 或调整您意向的关键词哦~</p>
</div>
<!-- 加载更多提示 --> <!-- 加载更多提示 -->
<div v-if="loadingMore" class="jobs-page__loading-box"> <div v-if="loadingMore" class="jobs-page__loading-box">
<div class="jobs-page__loading-spinner"></div> <div class="jobs-page__loading-spinner"></div>
@@ -700,11 +709,11 @@ function resolveFullCategoryName(id: string): string {
return '' return ''
} }
/** AI 推荐的行业名称ID 转文字,基于完整行业树 */ /** AI 推荐的行业列表ID + 名称,用于提示条展示和点击 */
const aiIndustryNames = computed<string>(() => { const aiIndustryItems = computed<{ id: string; name: string }[]>(() => {
if (!aiIndustryIds.value.length || !fullIndustryTree.value.length) return '' if (!aiIndustryIds.value.length || !fullIndustryTree.value.length) return []
const idSet = new Set(aiIndustryIds.value.map(String)) const idSet = new Set(aiIndustryIds.value.map(String))
const names: string[] = [] const items: { id: string; name: string }[] = []
for (const id of aiIndustryIds.value) { for (const id of aiIndustryIds.value) {
// 如果该 ID 是一级父节点且子节点也在列表中,跳过父级避免重复 // 如果该 ID 是一级父节点且子节点也在列表中,跳过父级避免重复
const parent = fullIndustryTree.value.find(p => String(p.id) === id) const parent = fullIndustryTree.value.find(p => String(p.id) === id)
@@ -712,16 +721,16 @@ const aiIndustryNames = computed<string>(() => {
continue continue
} }
const name = resolveFullIndustryName(id) const name = resolveFullIndustryName(id)
if (name) names.push(name) if (name) items.push({ id, name })
} }
return names.join('、') return items
}) })
/** AI 推荐的岗位名称ID 转文字,基于完整岗位树 */ /** AI 推荐的岗位列表ID + 名称,用于提示条展示和点击 */
const aiCategoryNames = computed<string>(() => { const aiCategoryItems = computed<{ id: string; name: string }[]>(() => {
if (!aiCategoryIds.value.length || !fullJobCategoryTree.value.length) return '' if (!aiCategoryIds.value.length || !fullJobCategoryTree.value.length) return []
const idSet = new Set(aiCategoryIds.value.map(String)) const idSet = new Set(aiCategoryIds.value.map(String))
const names: string[] = [] const items: { id: string; name: string }[] = []
for (const id of aiCategoryIds.value) { for (const id of aiCategoryIds.value) {
// 如果该 ID 是一级父节点且下级子节点也在列表中,跳过 // 如果该 ID 是一级父节点且下级子节点也在列表中,跳过
const lv1 = fullJobCategoryTree.value.find(p => String(p.id) === id) const lv1 = fullJobCategoryTree.value.find(p => String(p.id) === id)
@@ -739,11 +748,17 @@ const aiCategoryNames = computed<string>(() => {
} }
if (isParentWithChild) continue if (isParentWithChild) continue
const name = resolveFullCategoryName(id) const name = resolveFullCategoryName(id)
if (name) names.push(name) if (name) items.push({ id, name })
} }
return names.join('、') return items
}) })
/** AI 推荐的行业名称(兼容旧逻辑,拼接字符串用于条件判断) */
const aiIndustryNames = computed<string>(() => aiIndustryItems.value.map(i => i.name).join('、'))
/** AI 推荐的岗位名称(兼容旧逻辑,拼接字符串用于条件判断) */
const aiCategoryNames = computed<string>(() => aiCategoryItems.value.map(i => i.name).join('、'))
/** 是否显示 AI 推荐提示条 */ /** 是否显示 AI 推荐提示条 */
const showAiRecommendTip = computed(() => { const showAiRecommendTip = computed(() => {
return isRecommendTab.value && (aiIndustryNames.value || aiCategoryNames.value) return isRecommendTab.value && (aiIndustryNames.value || aiCategoryNames.value)
@@ -765,6 +780,36 @@ function onCategoryChange(ids: number[]) {
}) })
} }
/** 点击 AI 推荐岗位词 — 将该岗位 ID 添加到筛选器(去重,最多3个) */
function handleAddCategory(id: string) {
const numId = Number(id)
const current = selectedCategoryIds.value
if (current.includes(numId)) return // 已存在,不重复添加
if (current.length >= 3) {
ElMessage.warning('最多选择3个分类,请先去掉一个再添加')
return
}
store.dispatch('saveJobIntention', {
...store.state.jobIntention,
categoryIds: [...current, numId],
})
}
/** 点击 AI 推荐行业词 — 将该行业 ID 添加到筛选器(去重,最多3个) */
function handleAddIndustry(id: string) {
const numId = Number(id)
const current = selectedIndustryIds.value
if (current.includes(numId)) return // 已存在,不重复添加
if (current.length >= 3) {
ElMessage.warning('最多选择3个分类,请先去掉一个再添加')
return
}
store.dispatch('saveJobIntention', {
...store.state.jobIntention,
industryIds: [...current, numId],
})
}
/** 地区选择变更回调 */ /** 地区选择变更回调 */
function onRegionChange(codes: string[]) { function onRegionChange(codes: string[]) {
store.dispatch('saveJobIntention', { store.dispatch('saveJobIntention', {
@@ -1192,6 +1237,35 @@ function reloadFirstPage() {
loadCurrentTab() loadCurrentTab()
} }
/** 是否有任何筛选条件或搜索关键词处于激活状态 */
const hasActiveFilters = computed(() => {
return selectedCategoryIds.value.length > 0
|| selectedIndustryIds.value.length > 0
|| selectedRegionCodes.value.length > 0
|| selectedEmploymentType.value !== null
|| selectedCompanyTypes.value.length > 0
|| keyword.value.trim() !== ''
})
/** 清空所有筛选条件和搜索关键词,重新查询 */
function clearAllFilters() {
// 清空搜索关键词
keyword.value = ''
// 清空公司类型(本地状态 + 缓存)
selectedCompanyTypes.value = []
saveCachedCompanyTypes([])
// 清空筛选按钮的显示文字
filters.value.forEach(f => { f.selected = '' })
// 清空 store 中的分类筛选条件
store.dispatch('saveJobIntention', {
...store.state.jobIntention,
categoryIds: [],
industryIds: [],
regionCodes: [],
recruitCategory: null,
})
}
/** 根据当前 Tab 加载对应列表 */ /** 根据当前 Tab 加载对应列表 */
function loadCurrentTab() { function loadCurrentTab() {
if (isRecommendTab.value) { if (isRecommendTab.value) {