177 lines
5.6 KiB
Vue
177 lines
5.6 KiB
Vue
<template>
|
|
<!-- 求职偏好设置弹窗 -->
|
|
<div v-if="visible" class="job-goal-dialog__overlay" @click.self="handleClose">
|
|
<div class="job-goal-dialog">
|
|
<!-- 头部区域 -->
|
|
<div class="job-goal-dialog__header">
|
|
<span class="job-goal-dialog__title">求职偏好</span>
|
|
<!-- 关闭按钮 -->
|
|
<svg class="job-goal-dialog__close-btn" @click="handleClose" width="24" height="24" viewBox="0 0 24 24" fill="none">
|
|
<path d="M6 6L18 18M18 6L6 18" stroke="#6A7282" stroke-width="1.5" stroke-linecap="round"/>
|
|
</svg>
|
|
</div>
|
|
|
|
<!-- 岗位选择模块 -->
|
|
<div class="job-goal-dialog__section">
|
|
<div class="job-goal-dialog__label">岗位</div>
|
|
<JobCategorySelector
|
|
:categoryIds="selectedCategoryIds"
|
|
:maxSelect="3"
|
|
:level="3"
|
|
:allowParentSelect="false"
|
|
:triggerStyle="selectorTriggerStyle"
|
|
:displayStyle="selectorDisplayStyle"
|
|
@update:categoryIds="onCategoryChange"
|
|
/>
|
|
</div>
|
|
|
|
<!-- 行业选择模块 -->
|
|
<div class="job-goal-dialog__section">
|
|
<div class="job-goal-dialog__label">行业</div>
|
|
<IndustrySelector
|
|
:industryIds="selectedIndustryIds"
|
|
:maxSelect="3"
|
|
:level="2"
|
|
:allowParentSelect="false"
|
|
:triggerStyle="selectorTriggerStyle"
|
|
:displayStyle="selectorDisplayStyle"
|
|
@update:industryIds="onIndustryChange"
|
|
/>
|
|
</div>
|
|
|
|
<!-- 城市选择模块 -->
|
|
<div class="job-goal-dialog__section">
|
|
<div class="job-goal-dialog__label">城市</div>
|
|
<RegionSelector
|
|
:regionCodes="selectedRegionCodes"
|
|
:level="2"
|
|
:maxSelect="3"
|
|
:triggerStyle="selectorTriggerStyle"
|
|
:displayStyle="selectorDisplayStyle"
|
|
@update:regionCodes="onRegionChange"
|
|
/>
|
|
</div>
|
|
|
|
<!-- 招聘类型选择模块 -->
|
|
<div class="job-goal-dialog__section">
|
|
<div class="job-goal-dialog__label">招聘类型</div>
|
|
<!-- 招聘类型按钮组 -->
|
|
<div class="job-goal-dialog__type-group">
|
|
<button
|
|
v-for="t in jobTypes"
|
|
:key="t"
|
|
class="job-goal-dialog__type-btn"
|
|
:class="{ 'job-goal-dialog__type-btn--active': selectedJobType === t }"
|
|
@click="selectedJobType = t"
|
|
>
|
|
{{ t }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 保存按钮 -->
|
|
<button class="job-goal-dialog__save-btn" @click="handleSave">保存</button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, watch } from 'vue'
|
|
import { useStore } from 'vuex'
|
|
import { JOB_TYPE_OPTIONS, formatEmploymentType } from '@/stores/index'
|
|
import RegionSelector from './tools/RegionSelector.vue'
|
|
import IndustrySelector from './tools/IndustrySelector.vue'
|
|
import JobCategorySelector from './tools/JobCategorySelector.vue'
|
|
|
|
/** 组件属性:控制弹窗显示/隐藏 */
|
|
const props = defineProps<{ modelValue: boolean }>()
|
|
|
|
/** 组件事件:更新弹窗状态 */
|
|
const emit = defineEmits<{
|
|
(e: 'update:modelValue', val: boolean): void
|
|
}>()
|
|
|
|
const store = useStore()
|
|
|
|
/** 弹窗可见状态 */
|
|
const visible = ref(props.modelValue)
|
|
/** 监听外部传入的 modelValue 同步弹窗状态 */
|
|
watch(() => props.modelValue, (v) => { visible.value = v })
|
|
/** 监听弹窗状态变化并通知父组件 */
|
|
watch(visible, (v) => { emit('update:modelValue', v) })
|
|
|
|
/** 本地编辑副本 — 打开弹窗时从 store 拷贝,保存时写回 store */
|
|
const selectedCategoryIds = ref<number[]>([])
|
|
const selectedIndustryIds = ref<number[]>([])
|
|
const selectedRegionCodes = ref<string[]>([])
|
|
const selectedJobType = ref('全部')
|
|
|
|
/** 招聘类型选项列表 */
|
|
const jobTypes = JOB_TYPE_OPTIONS.map(item => item.label)
|
|
|
|
/** 弹窗打开时从 store 同步数据到本地编辑副本 */
|
|
watch(() => props.modelValue, (v) => {
|
|
if (v) {
|
|
const intention = store.state.jobIntention
|
|
selectedCategoryIds.value = [...(intention.categoryIds || [])]
|
|
selectedIndustryIds.value = [...(intention.industryIds || [])]
|
|
selectedRegionCodes.value = [...(intention.regionCodes || [])]
|
|
selectedJobType.value = formatEmploymentType(intention.recruitCategory) || '全部'
|
|
}
|
|
})
|
|
|
|
/** 选择器触发按钮的自定义样式 */
|
|
const selectorTriggerStyle: Record<string, string> = {
|
|
width: '100%',
|
|
'box-sizing': 'border-box',
|
|
padding: '0.08rem 0.16rem',
|
|
'font-size': '0.14rem',
|
|
color: '#1A1A1A',
|
|
background: '#F3F4F6',
|
|
border: 'none',
|
|
'border-radius': '0.08rem',
|
|
'max-width': 'none',
|
|
'justify-content': 'space-between',
|
|
}
|
|
|
|
/** 选择器显示文字的自定义样式 */
|
|
const selectorDisplayStyle: Record<string, string> = {
|
|
'max-width': 'none',
|
|
}
|
|
|
|
/** 岗位选择变更回调 */
|
|
function onCategoryChange(ids: number[]) {
|
|
selectedCategoryIds.value = ids
|
|
}
|
|
|
|
/** 行业选择变更回调 */
|
|
function onIndustryChange(ids: number[]) {
|
|
selectedIndustryIds.value = ids
|
|
}
|
|
|
|
/** 地区选择变更回调 */
|
|
function onRegionChange(codes: string[]) {
|
|
selectedRegionCodes.value = codes
|
|
}
|
|
|
|
/** 保存表单数据 */
|
|
async function handleSave() {
|
|
try {
|
|
await store.dispatch('saveJobIntention', {
|
|
categoryIds: [...selectedCategoryIds.value],
|
|
industryIds: [...selectedIndustryIds.value],
|
|
regionCodes: [...selectedRegionCodes.value],
|
|
recruitCategory: JOB_TYPE_OPTIONS.find(o => o.label === selectedJobType.value)?.value ?? 0,
|
|
})
|
|
visible.value = false
|
|
} catch (e) {
|
|
console.error('保存求职意向失败', e)
|
|
}
|
|
}
|
|
|
|
/** 关闭弹窗 */
|
|
function handleClose() {
|
|
visible.value = false
|
|
}
|
|
</script>
|