个人资料教育经历学历类型保存bug,和岗位为列表页查询条件添加公司类型分类
This commit is contained in:
+2
-1
@@ -101,7 +101,8 @@ export interface JobListParams {
|
|||||||
recruitCategory?: number
|
recruitCategory?: number
|
||||||
/** 排除岗位ID列表(用于推荐时排除已推荐过的) */
|
/** 排除岗位ID列表(用于推荐时排除已推荐过的) */
|
||||||
excludeJobIds?: number[]
|
excludeJobIds?: number[]
|
||||||
|
/** 公司类型列表(上市企业、独角兽、国企等,可多选) */
|
||||||
|
companyTypes?: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 求职意向 ====================
|
// ==================== 求职意向 ====================
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
<div class="profile-edit-inline__fields-row">
|
<div class="profile-edit-inline__fields-row">
|
||||||
<div class="profile-edit-inline__field-item"><label class="profile-edit-inline__label">学校</label><input class="profile-edit-inline__input" placeholder="请输入学校名称" v-model="form.school" /></div>
|
<div class="profile-edit-inline__field-item"><label class="profile-edit-inline__label">学校</label><input class="profile-edit-inline__input" placeholder="请输入学校名称" v-model="form.school" /></div>
|
||||||
<div class="profile-edit-inline__field-item"><label class="profile-edit-inline__label">专业</label><input class="profile-edit-inline__input" placeholder="请输入专业名称" v-model="form.major" /></div>
|
<div class="profile-edit-inline__field-item"><label class="profile-edit-inline__label">专业</label><input class="profile-edit-inline__input" placeholder="请输入专业名称" v-model="form.major" /></div>
|
||||||
<div class="profile-edit-inline__field-item"><label class="profile-edit-inline__label">学历</label><select class="profile-edit-inline__input" v-model="form.degree"><option value="大专">大专</option><option value="本科">本科</option><option value="硕士">硕士</option><option value="博士">博士</option></select></div>
|
<div class="profile-edit-inline__field-item"><label class="profile-edit-inline__label">学历</label><select class="profile-edit-inline__input" v-model="form.degree"><option :value="1">大专</option><option :value="2">本科</option><option :value="3">硕士</option><option :value="4">博士</option></select></div>
|
||||||
<div class="profile-edit-inline__field-item"><label class="profile-edit-inline__label">学历类型</label><select class="profile-edit-inline__input" v-model="form.studyType"><option value="全日制">全日制</option><option value="非全日制">非全日制</option></select></div>
|
<div class="profile-edit-inline__field-item"><label class="profile-edit-inline__label">学历类型</label><select class="profile-edit-inline__input" v-model="form.studyType"><option :value="0">全日制</option><option :value="1">非全日制</option></select></div>
|
||||||
<div class="profile-edit-inline__field-item"><label class="profile-edit-inline__label">就读时间</label>
|
<div class="profile-edit-inline__field-item"><label class="profile-edit-inline__label">就读时间</label>
|
||||||
<div class="profile-edit-inline__date-range">
|
<div class="profile-edit-inline__date-range">
|
||||||
<el-date-picker v-model="form.startDate" type="month" placeholder="开始" format="YYYY-MM" value-format="YYYY-MM" class="profile-edit-inline__date-picker" :teleported="true" popper-class="profile-drawer-date-popper" />
|
<el-date-picker v-model="form.startDate" type="month" placeholder="开始" format="YYYY-MM" value-format="YYYY-MM" class="profile-edit-inline__date-picker" :teleported="true" popper-class="profile-drawer-date-popper" />
|
||||||
@@ -180,6 +180,17 @@ function initForm() {
|
|||||||
aiPolishResult.value = ''
|
aiPolishResult.value = ''
|
||||||
if (props.initialData) {
|
if (props.initialData) {
|
||||||
form.value = { ...props.initialData }
|
form.value = { ...props.initialData }
|
||||||
|
// 教育经历:确保 degree 和 studyType 为整数(兼容旧数据可能是中文字符串)
|
||||||
|
if (props.moduleType === 'education') {
|
||||||
|
const degreeMap: Record<string, number> = { '大专': 1, '本科': 2, '硕士': 3, '博士': 4 }
|
||||||
|
const studyTypeMap: Record<string, number> = { '全日制': 0, '非全日制': 1 }
|
||||||
|
if (typeof form.value.degree === 'string') {
|
||||||
|
form.value.degree = degreeMap[form.value.degree] ?? (Number(form.value.degree) || null)
|
||||||
|
}
|
||||||
|
if (typeof form.value.studyType === 'string') {
|
||||||
|
form.value.studyType = studyTypeMap[form.value.studyType] ?? (Number(form.value.studyType) || null)
|
||||||
|
}
|
||||||
|
}
|
||||||
// 将 description 数组拼接为文本
|
// 将 description 数组拼接为文本
|
||||||
if (props.initialData.description?.length) {
|
if (props.initialData.description?.length) {
|
||||||
descriptionText.value = props.initialData.description.map((d: DescriptionParagraph) => d.text).join('\n')
|
descriptionText.value = props.initialData.description.map((d: DescriptionParagraph) => d.text).join('\n')
|
||||||
|
|||||||
+124
-3
@@ -63,9 +63,9 @@
|
|||||||
:displayStyle="selectorDisplayStyle"
|
:displayStyle="selectorDisplayStyle"
|
||||||
@update:industryIds="onIndustryChange"
|
@update:industryIds="onIndustryChange"
|
||||||
/>
|
/>
|
||||||
<!-- 其他筛选条件 -->
|
<!-- 招聘分类筛选条件 -->
|
||||||
<div
|
<div
|
||||||
v-else
|
v-else-if="filter.key === 'jobType'"
|
||||||
class="jobs-page__filter-item"
|
class="jobs-page__filter-item"
|
||||||
@click="handleFilterClick(filter)"
|
@click="handleFilterClick(filter)"
|
||||||
>
|
>
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
<svg class="jobs-page__filter-arrow-icon" viewBox="0 0 12 12" fill="none">
|
<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>
|
</svg>
|
||||||
<!-- 工作类型下拉菜单 -->
|
<!-- 招聘分类下拉菜单 -->
|
||||||
<div
|
<div
|
||||||
v-if="filter.key === 'jobType' && showJobTypeDropdown"
|
v-if="filter.key === 'jobType' && showJobTypeDropdown"
|
||||||
class="jobs-page__filter-dropdown"
|
class="jobs-page__filter-dropdown"
|
||||||
@@ -90,6 +90,34 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 公司类型筛选条件 -->
|
||||||
|
<div
|
||||||
|
v-else-if="filter.key === 'companyType'"
|
||||||
|
class="jobs-page__filter-item"
|
||||||
|
@click.stop="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="showCompanyTypeDropdown"
|
||||||
|
class="jobs-page__filter-dropdown"
|
||||||
|
@click.stop
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="jobs-page__filter-dropdown-item"
|
||||||
|
v-for="option in companyTypeOptions"
|
||||||
|
:key="option.label"
|
||||||
|
:class="{ 'jobs-page__filter-dropdown-item--active': filter.selected === option.label || (!filter.selected && !option.value.length) }"
|
||||||
|
@click.stop="selectCompanyType(filter, option)"
|
||||||
|
>
|
||||||
|
{{ option.label }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="jobs-page__search-box">
|
<div class="jobs-page__search-box">
|
||||||
@@ -578,6 +606,7 @@ const filters = ref<FilterItem[]>([
|
|||||||
{ label: '岗位', key: 'position', selected: '' },
|
{ label: '岗位', key: 'position', selected: '' },
|
||||||
{ label: '行业', key: 'industry', selected: '' },
|
{ label: '行业', key: 'industry', selected: '' },
|
||||||
{ label: '招聘分类', key: 'jobType', selected: '' },
|
{ label: '招聘分类', key: 'jobType', selected: '' },
|
||||||
|
{ label: '公司类型', key: 'companyType', selected: '' },
|
||||||
])
|
])
|
||||||
|
|
||||||
/** 招聘分类选项映射:从全局 store 常量统一引入 */
|
/** 招聘分类选项映射:从全局 store 常量统一引入 */
|
||||||
@@ -586,6 +615,54 @@ const jobTypeOptions = JOB_TYPE_OPTIONS
|
|||||||
/** 招聘分类下拉菜单是否显示 */
|
/** 招聘分类下拉菜单是否显示 */
|
||||||
const showJobTypeDropdown = ref(false)
|
const showJobTypeDropdown = ref(false)
|
||||||
|
|
||||||
|
/** 公司类型选项(label=显示文字,value=传给接口的字符串数组) */
|
||||||
|
const companyTypeOptions: { label: string; value: string[] }[] = [
|
||||||
|
{ label: '全部', value: [] },
|
||||||
|
{ label: '央国企', value: ['央企', '国企'] },
|
||||||
|
{ label: '独角兽', value: ['独角兽'] },
|
||||||
|
{ label: '事业单位', value: ['事业单位'] },
|
||||||
|
{ label: '上市企业', value: ['上市企业'] },
|
||||||
|
{ label: '外资企业', value: ['外资企业'] },
|
||||||
|
{ label: '合资企业', value: ['合资企业'] },
|
||||||
|
{ label: '民营企业', value: ['民营企业'] },
|
||||||
|
]
|
||||||
|
|
||||||
|
/** 公司类型下拉菜单是否显示 */
|
||||||
|
const showCompanyTypeDropdown = ref(false)
|
||||||
|
|
||||||
|
/** localStorage 缓存 key(带用户 ID 隔离不同用户) */
|
||||||
|
const COMPANY_TYPE_CACHE_KEY = 'offerpai_jobs_company_type_filter_'
|
||||||
|
|
||||||
|
/** 获取当前用户的公司类型缓存 key */
|
||||||
|
function getCompanyTypeCacheKey(): string {
|
||||||
|
const userId = store.state.userInfo?.id || 'anonymous'
|
||||||
|
return COMPANY_TYPE_CACHE_KEY + userId
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 从 localStorage 读取缓存的公司类型筛选 */
|
||||||
|
function loadCachedCompanyTypes(): string[] {
|
||||||
|
try {
|
||||||
|
const cached = localStorage.getItem(getCompanyTypeCacheKey())
|
||||||
|
if (!cached || cached === 'null') return []
|
||||||
|
return JSON.parse(cached) as string[]
|
||||||
|
} catch {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 保存公司类型筛选到 localStorage */
|
||||||
|
function saveCachedCompanyTypes(types: string[]) {
|
||||||
|
const key = getCompanyTypeCacheKey()
|
||||||
|
if (types.length === 0) {
|
||||||
|
localStorage.setItem(key, 'null')
|
||||||
|
} else {
|
||||||
|
localStorage.setItem(key, JSON.stringify(types))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 当前选中的公司类型(传给接口的字符串数组),onMounted 中从缓存恢复 */
|
||||||
|
const selectedCompanyTypes = ref<string[]>([])
|
||||||
|
|
||||||
/** 当前选中的招聘分类 — 直接读 store.jobIntention.recruitCategory */
|
/** 当前选中的招聘分类 — 直接读 store.jobIntention.recruitCategory */
|
||||||
const selectedEmploymentType = computed<number | null>(
|
const selectedEmploymentType = computed<number | null>(
|
||||||
() => store.state.jobIntention.recruitCategory ?? null,
|
() => store.state.jobIntention.recruitCategory ?? null,
|
||||||
@@ -738,6 +815,10 @@ function onRegionChange(codes: string[]) {
|
|||||||
function handleFilterClick(filter: FilterItem) {
|
function handleFilterClick(filter: FilterItem) {
|
||||||
if (filter.key === 'jobType') {
|
if (filter.key === 'jobType') {
|
||||||
showJobTypeDropdown.value = !showJobTypeDropdown.value
|
showJobTypeDropdown.value = !showJobTypeDropdown.value
|
||||||
|
showCompanyTypeDropdown.value = false
|
||||||
|
} else if (filter.key === 'companyType') {
|
||||||
|
showCompanyTypeDropdown.value = !showCompanyTypeDropdown.value
|
||||||
|
showJobTypeDropdown.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -751,6 +832,15 @@ function selectJobType(filter: FilterItem, option: { label: string; value: numbe
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 选中公司类型选项 */
|
||||||
|
function selectCompanyType(filter: FilterItem, option: { label: string; value: string[] }) {
|
||||||
|
filter.selected = option.value.length ? option.label : ''
|
||||||
|
showCompanyTypeDropdown.value = false
|
||||||
|
selectedCompanyTypes.value = option.value
|
||||||
|
saveCachedCompanyTypes(option.value)
|
||||||
|
reloadFirstPage()
|
||||||
|
}
|
||||||
|
|
||||||
/** 监听 store 中 recruitCategory 变化,同步招聘分类筛选按钮的显示文字 */
|
/** 监听 store 中 recruitCategory 变化,同步招聘分类筛选按钮的显示文字 */
|
||||||
watch(selectedEmploymentType, (val) => {
|
watch(selectedEmploymentType, (val) => {
|
||||||
const jobTypeFilter = filters.value.find(f => f.key === 'jobType')
|
const jobTypeFilter = filters.value.find(f => f.key === 'jobType')
|
||||||
@@ -765,6 +855,7 @@ function closeDropdownOnClickOutside(e: MouseEvent) {
|
|||||||
const target = e.target as HTMLElement
|
const target = e.target as HTMLElement
|
||||||
if (!target.closest('.jobs-page__filter-item')) {
|
if (!target.closest('.jobs-page__filter-item')) {
|
||||||
showJobTypeDropdown.value = false
|
showJobTypeDropdown.value = false
|
||||||
|
showCompanyTypeDropdown.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -973,6 +1064,32 @@ async function handleApplyMethodAction() {
|
|||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
document.addEventListener('click', closeDropdownOnClickOutside)
|
document.addEventListener('click', closeDropdownOnClickOutside)
|
||||||
|
|
||||||
|
// 从缓存恢复公司类型筛选按钮的显示文字
|
||||||
|
// 需要等 userInfo 加载后再读取(刷新时 userInfo 可能还没有)
|
||||||
|
const restoreCompanyTypeFilter = () => {
|
||||||
|
const cached = loadCachedCompanyTypes()
|
||||||
|
if (cached.length) {
|
||||||
|
selectedCompanyTypes.value = cached
|
||||||
|
const matched = companyTypeOptions.find(o => JSON.stringify(o.value) === JSON.stringify(cached))
|
||||||
|
const companyTypeFilter = filters.value.find(f => f.key === 'companyType')
|
||||||
|
if (companyTypeFilter && matched) {
|
||||||
|
companyTypeFilter.selected = matched.label
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (store.state.userInfo?.id) {
|
||||||
|
restoreCompanyTypeFilter()
|
||||||
|
} else {
|
||||||
|
// userInfo 还没加载,监听变化后恢复
|
||||||
|
const unwatch = watch(() => store.state.userInfo, (info) => {
|
||||||
|
if (info?.id) {
|
||||||
|
restoreCompanyTypeFilter()
|
||||||
|
unwatch()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 窗口 resize 时更新尖角位置
|
// 窗口 resize 时更新尖角位置
|
||||||
window.addEventListener('resize', updateAiTipArrowPosition)
|
window.addEventListener('resize', updateAiTipArrowPosition)
|
||||||
|
|
||||||
@@ -1161,6 +1278,10 @@ function buildParams(): JobListParams {
|
|||||||
if (keyword.value.trim()) {
|
if (keyword.value.trim()) {
|
||||||
params.keyword = keyword.value.trim()
|
params.keyword = keyword.value.trim()
|
||||||
}
|
}
|
||||||
|
// 公司类型筛选
|
||||||
|
if (selectedCompanyTypes.value.length) {
|
||||||
|
params.companyTypes = selectedCompanyTypes.value
|
||||||
|
}
|
||||||
return params
|
return params
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -296,7 +296,7 @@
|
|||||||
<template v-if="expEditingId !== edu.id">
|
<template v-if="expEditingId !== edu.id">
|
||||||
<div class="resume-detail__exp-row">
|
<div class="resume-detail__exp-row">
|
||||||
<span class="resume-detail__exp-name">{{ edu.school }}</span>
|
<span class="resume-detail__exp-name">{{ edu.school }}</span>
|
||||||
<span v-if="edu.major || edu.degree" class="resume-detail__exp-role">{{ edu.major }}{{ edu.degree ? '·' + edu.degree : '' }}</span>
|
<span v-if="edu.major || edu.degree" class="resume-detail__exp-role">{{ edu.major }}{{ edu.degree ? '·' + (EDUCATION_MAP[Number(edu.degree)] || edu.degree) : '' }}</span>
|
||||||
<span v-if="hasDiagnosis && getIssueByRecord('education', edu.id!) && getIssueByRecord('education', edu.id!)!.status === 0" class="resume-detail__fix-tag">
|
<span v-if="hasDiagnosis && getIssueByRecord('education', edu.id!) && getIssueByRecord('education', edu.id!)!.status === 0" class="resume-detail__fix-tag">
|
||||||
<svg viewBox="0 0 16 16" class="resume-detail__fix-tag-icon"><circle cx="8" cy="8" r="7" fill="#FF8D0B"/><text x="8" y="12" text-anchor="middle" font-size="11" fill="#fff" font-weight="bold">!</text></svg>
|
<svg viewBox="0 0 16 16" class="resume-detail__fix-tag-icon"><circle cx="8" cy="8" r="7" fill="#FF8D0B"/><text x="8" y="12" text-anchor="middle" font-size="11" fill="#fff" font-weight="bold">!</text></svg>
|
||||||
建议使用AI润色修复
|
建议使用AI润色修复
|
||||||
@@ -633,6 +633,7 @@ import {
|
|||||||
} from '@/api/resume'
|
} from '@/api/resume'
|
||||||
import {ArrowLeft, EditPen, Plus, DeleteFilled, ChatLineRound} from "@element-plus/icons-vue";
|
import {ArrowLeft, EditPen, Plus, DeleteFilled, ChatLineRound} from "@element-plus/icons-vue";
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
|
import { EDUCATION_MAP } from '@/stores/index'
|
||||||
import FullscreenLoading from '@/components/FullscreenLoading.vue'
|
import FullscreenLoading from '@/components/FullscreenLoading.vue'
|
||||||
import StepProgressOverlay from '@/components/StepProgressOverlay.vue'
|
import StepProgressOverlay from '@/components/StepProgressOverlay.vue'
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user