仓库初始化+岗位相关页面
This commit is contained in:
@@ -0,0 +1,553 @@
|
||||
<template>
|
||||
<div class="jobs-page dflex">
|
||||
<SideNav />
|
||||
<div class="jobs-page__content">
|
||||
<!-- 页面标题 + Tab 切换 -->
|
||||
<JobPageHeader v-model:activeTab="activeTab" />
|
||||
<!-- 筛选条件 -->
|
||||
<div class="jobs-page__filters-bar">
|
||||
<div class="jobs-page__filters">
|
||||
<div class="jobs-page__filter-group">
|
||||
<!-- 筛选条件按钮列表(行业单独用组件) -->
|
||||
<template v-for="filter in filters" :key="filter.label">
|
||||
<!-- 城市筛选:使用地区选择组件(选到市级) -->
|
||||
<RegionSelector
|
||||
v-if="filter.key === 'city'"
|
||||
:regionCodes="selectedRegionCodes"
|
||||
:level="2"
|
||||
:maxSelect="3"
|
||||
@update:regionCodes="onRegionChange"
|
||||
/>
|
||||
<!-- 行业筛选:使用行业选择组件 -->
|
||||
<IndustrySelector
|
||||
v-else-if="filter.key === 'industry'"
|
||||
:industryIds="selectedIndustryIds"
|
||||
:maxSelect="3"
|
||||
@update:industryIds="onIndustryChange"
|
||||
/>
|
||||
<!-- 岗位筛选:使用岗位选择组件 -->
|
||||
<JobCategorySelector
|
||||
v-else-if="filter.key === 'position'"
|
||||
:categoryIds="selectedCategoryIds"
|
||||
:maxSelect="3"
|
||||
@update:categoryIds="onCategoryChange"
|
||||
/>
|
||||
<!-- 其他筛选条件 -->
|
||||
<div
|
||||
v-else
|
||||
class="jobs-page__filter-item"
|
||||
@click="handleFilterClick(filter)"
|
||||
>
|
||||
<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"/>
|
||||
</svg>
|
||||
<!-- 工作类型下拉菜单 -->
|
||||
<div
|
||||
v-if="filter.key === 'jobType' && showJobTypeDropdown"
|
||||
class="jobs-page__filter-dropdown"
|
||||
@click.stop
|
||||
>
|
||||
<div
|
||||
class="jobs-page__filter-dropdown-item"
|
||||
v-for="option in jobTypeOptions"
|
||||
:key="option.value"
|
||||
:class="{ 'jobs-page__filter-dropdown-item--active': filter.selected === option.label }"
|
||||
@click.stop="selectJobType(filter, option)"
|
||||
>
|
||||
{{ option.label }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="jobs-page__search-box">
|
||||
<svg class="jobs-page__search-svg" viewBox="0 0 16 16" fill="none">
|
||||
<circle cx="7" cy="7" r="5.5" stroke="currentColor" stroke-width="1.2"/>
|
||||
<path d="M11 11L14 14" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
<input
|
||||
v-model="searchText"
|
||||
class="jobs-page__search-input"
|
||||
placeholder="搜索职位、公司或关键词"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 职位列表 -->
|
||||
<div ref="jobListRef" class="jobs-page__list pr5" @scroll="onListScroll">
|
||||
<div
|
||||
v-for="(job, index) in jobList"
|
||||
:key="index"
|
||||
class="jobs-page__job-card"
|
||||
:class="{ 'jobs-page__job-card--selected--none': selectedIndex === index }"
|
||||
@click="goToDetail(job)"
|
||||
>
|
||||
<div class="jobs-page__job-main">
|
||||
<!-- 左侧:公司图标 + 职位信息 -->
|
||||
<div class="jobs-page__job-left">
|
||||
<div class="jobs-page__job-icon">
|
||||
<svg viewBox="0 0 24 24" fill="none" class="jobs-page__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"/>
|
||||
<rect x="10" y="11" width="4" height="4" rx="0.5" stroke="currentColor" stroke-width="1"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="jobs-page__job-info">
|
||||
<div class="jobs-page__job-title-row">
|
||||
<span class="jobs-page__job-name">{{ job.title }}</span>
|
||||
<button class="jobs-page__job-more" aria-label="更多操作" @click.stop="toggleMenu(index)">
|
||||
<svg viewBox="0 0 16 16" fill="currentColor" class="jobs-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>
|
||||
<div class="jobs-page__job-meta pt5">
|
||||
<span>{{ job.regionName }}</span>
|
||||
<span class="jobs-page__job-dot">·</span>
|
||||
<span>{{ job.companyShortName || job.companyName }}</span>
|
||||
<span class="jobs-page__job-dot">·</span>
|
||||
<span>{{ job.categoryName }}</span>
|
||||
</div>
|
||||
<!-- 提示信息 -->
|
||||
<div v-if="(job as any).tip" class="jobs-page__job-tip">
|
||||
<svg viewBox="0 0 14 14" fill="none" class="jobs-page__tip-svg">
|
||||
<circle cx="7" cy="7" r="6" stroke="currentColor" stroke-width="1"/>
|
||||
<path d="M7 6.5V10" stroke="currentColor" stroke-width="1" stroke-linecap="round"/>
|
||||
<circle cx="7" cy="4.5" r="0.5" fill="currentColor"/>
|
||||
</svg>
|
||||
{{ (job as any).tip }}
|
||||
</div>
|
||||
|
||||
<!-- 底部操作栏 -->
|
||||
<div class="jobs-page__job-actions pt20">
|
||||
<div class="dflex fgrow2 aliite-c flex-warp" >
|
||||
<!-- 标签 -->
|
||||
<div class="jobs-page__job-tags mt10">
|
||||
<span v-for="(tag, ti) in job.tags" :key="ti" class="jobs-page__job-tag">{{ tag }}</span>
|
||||
</div>
|
||||
<div class="dflex-end mt10">
|
||||
<div class="jobs-page__job-action-left">
|
||||
<button class="jobs-page__action-icon-btn" aria-label="不感兴趣" @click.stop="openDislikeDialog(job)">
|
||||
<svg viewBox="0 0 16 16" fill="none" class="jobs-page__action-svg">
|
||||
<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="{ 'jobs-page__action-icon-btn--liked': job.isFavorite }" aria-label="收藏">
|
||||
<svg viewBox="0 0 16 16" :fill="job.isFavorite ? 'currentColor' : 'none'" class="jobs-page__action-svg">
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div class="jobs-page__job-action-right ">
|
||||
<button class="jobs-page__job-helper">
|
||||
<svg viewBox="0 0 14 14" fill="none" class="jobs-page__helper-svg">
|
||||
<circle cx="7" cy="7" r="6" stroke="currentColor" stroke-width="1"/>
|
||||
<path d="M5.5 5.5a1.5 1.5 0 113 0c0 .8-.7 1-1.5 1.5V9" stroke="currentColor" stroke-width="1" stroke-linecap="round"/>
|
||||
<circle cx="7" cy="11" r="0.5" fill="currentColor"/>
|
||||
</svg>
|
||||
问助手
|
||||
</button>
|
||||
<button class="jobs-page__job-apply-btn" :class="{ 'jobs-page__job-apply-btn--active': job.applied }">
|
||||
自动投递
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 弹出菜单 -->
|
||||
<div v-if="job.showMenu" class="jobs-page__job-popup" @click.stop>
|
||||
<div
|
||||
class="jobs-page__job-popup-item"
|
||||
v-for="action in popupActions"
|
||||
:key="action"
|
||||
@click="handlePopupAction(action, job)"
|
||||
>{{ action }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 右侧:匹配度 -->
|
||||
<div class="jobs-page__job-match" :class="matchClass(job.matchScore)">
|
||||
<div class="jobs-page__match-ring">
|
||||
<svg viewBox="0 0 80 80" class="jobs-page__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="job.matchScore >= 80 ? '#4FC2C9' : '#BFBFBF'"
|
||||
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="jobs-page__match-score">{{ job.matchScore }}%</div>
|
||||
</div>
|
||||
<div class="jobs-page__match-label">匹配值</div>
|
||||
<div class="jobs-page__match-level">{{ matchLevelText(job.matchScore) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 加载更多提示 -->
|
||||
<div v-if="loadingMore" class="jobs-page__loading-more">加载中...</div>
|
||||
<div v-else-if="noMore && jobList.length > 0" class="jobs-page__loading-more">没有更多了</div>
|
||||
</div>
|
||||
</div>
|
||||
<AiChat />
|
||||
|
||||
<!-- 职位不感兴趣反馈弹窗 -->
|
||||
<JobDislikeDialog ref="dislikeDialogRef" v-model="showDislikeDialog" :job-id="dislikeJobId" />
|
||||
|
||||
<!-- 职位问题反馈弹窗 -->
|
||||
<JobFeedbackDialog ref="feedbackDialogRef" v-model="showFeedbackDialog" :job-id="feedbackJobId" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, onMounted, onBeforeUnmount, nextTick, computed } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { useStore } from 'vuex'
|
||||
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 IndustrySelector from '@/components/tools/IndustrySelector.vue'
|
||||
import JobCategorySelector from '@/components/tools/JobCategorySelector.vue'
|
||||
import RegionSelector from '@/components/tools/RegionSelector.vue'
|
||||
import { fetchJobList } from '@/api/jobs'
|
||||
import type { JobListItem, JobListParams } from '@/api/jobs'
|
||||
|
||||
// ==================== 路由相关 ====================
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const store = useStore()
|
||||
|
||||
// ==================== 页面状态 ====================
|
||||
|
||||
/** 当前激活的 Tab,从 URL query 参数读取,默认"推荐" */
|
||||
const activeTab = ref((route.query.tab as string) || 'recommend')
|
||||
|
||||
/** 搜索框输入内容 */
|
||||
const searchText = ref('')
|
||||
|
||||
/** 当前选中的职位卡片索引 */
|
||||
const selectedIndex = ref(0)
|
||||
|
||||
/** 不感兴趣弹窗的显示状态 */
|
||||
const showDislikeDialog = ref(false)
|
||||
|
||||
/** 当前操作的职位 ID(用于提交不感兴趣反馈) */
|
||||
const dislikeJobId = ref<string | null>(null)
|
||||
|
||||
/** 问题反馈弹窗的显示状态 */
|
||||
const showFeedbackDialog = ref(false)
|
||||
|
||||
/** 当前操作的职位 ID(用于提交问题反馈) */
|
||||
const feedbackJobId = ref<string | null>(null)
|
||||
|
||||
// ==================== 常量数据 ====================
|
||||
|
||||
/** 筛选条件项类型 */
|
||||
interface FilterItem {
|
||||
label: string
|
||||
key: string
|
||||
selected: string
|
||||
}
|
||||
|
||||
/** 筛选条件列表 */
|
||||
const filters = ref<FilterItem[]>([
|
||||
{ label: '城市', key: 'city', selected: '' },
|
||||
{ label: '岗位', key: 'position', selected: '' },
|
||||
{ label: '行业', key: 'industry', selected: '' },
|
||||
{ label: '工作类型', key: 'jobType', selected: '' },
|
||||
])
|
||||
|
||||
/** 工作类型选项映射:label → 接口参数 employmentType(0=全职 1=实习) */
|
||||
const jobTypeOptions: { label: string; value: number }[] = [
|
||||
{ label: '全职', value: 0 },
|
||||
{ label: '实习', value: 1 },
|
||||
]
|
||||
|
||||
/** 工作类型下拉菜单是否显示 */
|
||||
const showJobTypeDropdown = ref(false)
|
||||
|
||||
/** 当前选中的工作类型(integer,对应接口参数 employmentType,null 表示未选) */
|
||||
const selectedEmploymentType = ref<number | null>(null)
|
||||
|
||||
/** 选中的行业 id 数组(integer,对应接口参数 industryIds) */
|
||||
const selectedIndustryIds = ref<number[]>([])
|
||||
|
||||
/** 选中的岗位 id 数组(integer,对应接口参数 categoryIds) */
|
||||
const selectedCategoryIds = ref<number[]>([])
|
||||
|
||||
/** 选中的地区编码数组(string,对应接口参数 regionCodes) */
|
||||
const selectedRegionCodes = ref<string[]>([])
|
||||
|
||||
/** 行业选择变更回调 */
|
||||
function onIndustryChange(ids: number[]) {
|
||||
selectedIndustryIds.value = ids
|
||||
}
|
||||
|
||||
/** 岗位选择变更回调 */
|
||||
function onCategoryChange(ids: number[]) {
|
||||
selectedCategoryIds.value = ids
|
||||
}
|
||||
|
||||
/** 地区选择变更回调 */
|
||||
function onRegionChange(codes: string[]) {
|
||||
selectedRegionCodes.value = codes
|
||||
}
|
||||
|
||||
/** 点击筛选条件按钮 — 仅工作类型展开下拉 */
|
||||
function handleFilterClick(filter: FilterItem) {
|
||||
if (filter.key === 'jobType') {
|
||||
showJobTypeDropdown.value = !showJobTypeDropdown.value
|
||||
}
|
||||
}
|
||||
|
||||
/** 选中工作类型选项 */
|
||||
function selectJobType(filter: FilterItem, option: { label: string; value: number }) {
|
||||
filter.selected = option.label
|
||||
selectedEmploymentType.value = option.value
|
||||
showJobTypeDropdown.value = false
|
||||
}
|
||||
|
||||
/** 点击页面其他区域时关闭下拉菜单 */
|
||||
function closeDropdownOnClickOutside(e: MouseEvent) {
|
||||
const target = e.target as HTMLElement
|
||||
if (!target.closest('.jobs-page__filter-item')) {
|
||||
showJobTypeDropdown.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
document.addEventListener('click', closeDropdownOnClickOutside)
|
||||
// 进入 Jobs 页时加载公共工具数据(行业分类等)
|
||||
store.dispatch('loadCommonData')
|
||||
|
||||
// 尝试从缓存恢复列表数据(从详情页返回时不重新请求)
|
||||
const cache = store.state.jobListCache
|
||||
if (cache && cache.list.length > 0) {
|
||||
jobList.value = cache.list
|
||||
pageNum.value = cache.pageNum
|
||||
total.value = cache.total
|
||||
savedScrollTop = cache.scrollTop
|
||||
// 清除缓存,避免下次非详情页返回时误用
|
||||
store.commit('SET_JOB_LIST_CACHE', null)
|
||||
// 等 DOM 渲染完成后恢复滚动位置
|
||||
nextTick(() => {
|
||||
if (jobListRef.value) {
|
||||
jobListRef.value.scrollTop = savedScrollTop
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// 没有缓存,正常加载
|
||||
loadJobList()
|
||||
}
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
document.removeEventListener('click', closeDropdownOnClickOutside)
|
||||
})
|
||||
|
||||
/** 弹出菜单操作项 */
|
||||
const popupActions = ['从列表中移除', '已投递', '复制链接', '问题反馈']
|
||||
|
||||
// ==================== 职位列表项(扩展接口字段,增加前端交互状态) ====================
|
||||
|
||||
/** 职位列表项类型(在接口返回基础上扩展前端交互字段) */
|
||||
interface JobItem extends JobListItem {
|
||||
/** 是否已投递 */
|
||||
applied: boolean
|
||||
/** 是否显示弹出菜单 */
|
||||
showMenu: boolean
|
||||
}
|
||||
|
||||
// ==================== 分页与加载状态 ====================
|
||||
|
||||
/** 当前页码 */
|
||||
const pageNum = ref(1)
|
||||
|
||||
/** 每页条数 */
|
||||
const pageSize = ref(15)
|
||||
|
||||
/** 总记录数 */
|
||||
const total = ref(0)
|
||||
|
||||
/** 是否正在加载(首次加载) */
|
||||
const loading = ref(false)
|
||||
|
||||
/** 是否正在加载下一页 */
|
||||
const loadingMore = ref(false)
|
||||
|
||||
/** 是否已加载全部数据 */
|
||||
const noMore = computed(() => jobList.value.length >= total.value && total.value > 0)
|
||||
|
||||
/** 职位列表数据 */
|
||||
const jobList = ref<JobItem[]>([])
|
||||
|
||||
/** 列表容器 ref,用于监听滚动和恢复滚动位置 */
|
||||
const jobListRef = ref<HTMLElement | null>(null)
|
||||
|
||||
/** 记录离开页面前的滚动位置 */
|
||||
let savedScrollTop = 0
|
||||
// ==================== 加载岗位列表 ====================
|
||||
|
||||
/** 组装请求参数 */
|
||||
function buildParams(): JobListParams {
|
||||
const params: JobListParams = {
|
||||
pageNum: pageNum.value,
|
||||
pageSize: pageSize.value,
|
||||
}
|
||||
// 地区筛选
|
||||
if (selectedRegionCodes.value.length) {
|
||||
params.regionCodes = selectedRegionCodes.value
|
||||
}
|
||||
// 岗位类型筛选
|
||||
if (selectedCategoryIds.value.length) {
|
||||
params.categoryIds = selectedCategoryIds.value
|
||||
}
|
||||
// 行业筛选
|
||||
if (selectedIndustryIds.value.length) {
|
||||
params.industryIds = selectedIndustryIds.value
|
||||
}
|
||||
// 工作类型筛选
|
||||
if (selectedEmploymentType.value !== null) {
|
||||
params.employmentType = selectedEmploymentType.value
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
/** 加载岗位列表数据(首次加载,替换列表) */
|
||||
async function loadJobList() {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await fetchJobList(buildParams())
|
||||
if (res.code === '0' && res.data) {
|
||||
// 将接口数据映射为前端 JobItem,补充交互状态字段
|
||||
jobList.value = res.data.list.map((item) => ({
|
||||
...item,
|
||||
applied: false,
|
||||
showMenu: false,
|
||||
}))
|
||||
total.value = Number(res.data.total)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('加载岗位列表失败', e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 加载下一页数据(追加到列表末尾) */
|
||||
async function loadNextPage() {
|
||||
if (loadingMore.value || noMore.value) return
|
||||
loadingMore.value = true
|
||||
pageNum.value++
|
||||
try {
|
||||
const res = await fetchJobList(buildParams())
|
||||
if (res.code === '0' && res.data) {
|
||||
const newItems = res.data.list.map((item) => ({
|
||||
...item,
|
||||
applied: false,
|
||||
showMenu: false,
|
||||
}))
|
||||
jobList.value.push(...newItems)
|
||||
total.value = Number(res.data.total)
|
||||
}
|
||||
} catch (e) {
|
||||
// 加载失败时回退页码
|
||||
pageNum.value--
|
||||
console.error('加载下一页失败', e)
|
||||
} finally {
|
||||
loadingMore.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 列表滚动事件 — 滚动到底部时自动加载下一页 */
|
||||
function onListScroll() {
|
||||
const el = jobListRef.value
|
||||
if (!el) return
|
||||
// 距离底部小于 100px 时触发加载
|
||||
const threshold = 100
|
||||
if (el.scrollHeight - el.scrollTop - el.clientHeight < threshold) {
|
||||
loadNextPage()
|
||||
}
|
||||
}
|
||||
|
||||
/** 筛选条件变化时重置到第一页并重新加载 */
|
||||
function reloadFirstPage() {
|
||||
pageNum.value = 1
|
||||
// 筛选条件变化时清除缓存
|
||||
store.commit('SET_JOB_LIST_CACHE', null)
|
||||
loadJobList()
|
||||
}
|
||||
|
||||
// 监听筛选条件变化,自动重新加载
|
||||
watch(
|
||||
[selectedRegionCodes, selectedCategoryIds, selectedIndustryIds, selectedEmploymentType],
|
||||
() => reloadFirstPage(),
|
||||
)
|
||||
|
||||
// ==================== 事件处理 ====================
|
||||
|
||||
/** 切换职位卡片的弹出菜单(同时关闭其他已打开的菜单) */
|
||||
function toggleMenu(index: number) {
|
||||
jobList.value.forEach((j, i) => {
|
||||
j.showMenu = i === index ? !j.showMenu : false
|
||||
})
|
||||
}
|
||||
|
||||
/** 处理弹出菜单操作项点击 — 问题反馈打开反馈弹窗,其他直接关闭菜单 */
|
||||
function handlePopupAction(action: string, job: JobItem) {
|
||||
job.showMenu = false
|
||||
if (action === '问题反馈') {
|
||||
openFeedbackDialog(job)
|
||||
}
|
||||
}
|
||||
|
||||
/** 根据匹配分数返回对应的 CSS 类名 */
|
||||
function matchClass(score: number) {
|
||||
return score >= 80 ? 'jobs-page__job-match--high' : 'jobs-page__job-match--low'
|
||||
}
|
||||
|
||||
/** 根据匹配分数返回匹配等级文案 */
|
||||
function matchLevelText(score: number) {
|
||||
if (score >= 80) return '匹配'
|
||||
if (score >= 60) return '一般匹配'
|
||||
return '匹配度偏低'
|
||||
}
|
||||
|
||||
/** 跳转到岗位详情页 — 先缓存当前列表和滚动位置 */
|
||||
function goToDetail(job: JobItem) {
|
||||
// 保存当前列表状态到 store,返回时恢复
|
||||
store.commit('SET_JOB_LIST_CACHE', {
|
||||
list: jobList.value,
|
||||
pageNum: pageNum.value,
|
||||
total: total.value,
|
||||
scrollTop: jobListRef.value?.scrollTop ?? 0,
|
||||
})
|
||||
router.push(`/jobs/${job.id}`)
|
||||
}
|
||||
|
||||
/** 不感兴趣弹窗和问题反馈弹窗的组件引用 */
|
||||
const dislikeDialogRef = ref<InstanceType<typeof JobDislikeDialog> | null>(null)
|
||||
const feedbackDialogRef = ref<InstanceType<typeof JobFeedbackDialog> | null>(null)
|
||||
|
||||
/** 打开不感兴趣弹窗 — 记录当前职位 ID 并重置表单 */
|
||||
function openDislikeDialog(job: JobItem) {
|
||||
dislikeJobId.value = job.id
|
||||
dislikeDialogRef.value?.resetForm()
|
||||
showDislikeDialog.value = true
|
||||
}
|
||||
|
||||
/** 打开问题反馈弹窗 — 记录当前职位 ID 并重置表单 */
|
||||
function openFeedbackDialog(job: JobItem) {
|
||||
feedbackJobId.value = job.id
|
||||
feedbackDialogRef.value?.resetForm()
|
||||
showFeedbackDialog.value = true
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user