424 lines
9.8 KiB
Vue
424 lines
9.8 KiB
Vue
<template>
|
||
<div class="page">
|
||
<h2>招聘信息浏览与交互模块</h2>
|
||
<p class="intro">
|
||
为理工科毕业生提供多维度的岗位检索能力,以及与企业进行高效互动的入口。
|
||
</p>
|
||
|
||
<!-- 多维度搜索 -->
|
||
<section class="card">
|
||
<h3>1. 多维度搜索</h3>
|
||
<form class="filter-bar" @submit.prevent>
|
||
<input v-model="filter.keyword" placeholder="输入岗位关键词,例如:Java、测试" />
|
||
<select v-model="filter.major">
|
||
<option value="">专业方向</option>
|
||
<option value="计算机">计算机相关</option>
|
||
<option value="机械">机械相关</option>
|
||
<option value="电子">电子信息</option>
|
||
</select>
|
||
<select v-model="filter.companyType">
|
||
<option value="">企业类型</option>
|
||
<option value="国企">国企</option>
|
||
<option value="外企">外企</option>
|
||
<option value="民企">民企</option>
|
||
</select>
|
||
<select v-model="filter.hot">
|
||
<option value="">岗位热度</option>
|
||
<option value="高">高</option>
|
||
<option value="中">中</option>
|
||
<option value="低">低</option>
|
||
</select>
|
||
</form>
|
||
</section>
|
||
|
||
<section class="layout">
|
||
<!-- 岗位列表 -->
|
||
<section class="card job-list-card">
|
||
<h3>2. 岗位列表</h3>
|
||
<div class="job-list">
|
||
<div
|
||
v-for="job in filteredJobs"
|
||
:key="job.id"
|
||
class="job-item"
|
||
:class="{ active: selectedJob && selectedJob.id === job.id }"
|
||
@click="selectJob(job)"
|
||
>
|
||
<div>
|
||
<div class="job-title-row">
|
||
<span class="job-title">{{ job.title }}</span>
|
||
<span class="job-company">{{ job.company }}</span>
|
||
</div>
|
||
<div class="job-meta">
|
||
<span>{{ job.city }}</span>
|
||
<span>{{ job.salary }}</span>
|
||
<span>{{ job.companyType }}</span>
|
||
</div>
|
||
</div>
|
||
<div class="job-actions">
|
||
<button
|
||
type="button"
|
||
@click.stop="toggleFavorite(job.id)"
|
||
:class="{ secondary: isFavorite(job.id) }"
|
||
>
|
||
{{ isFavorite(job.id) ? '已收藏' : '收藏' }}
|
||
</button>
|
||
<button
|
||
type="button"
|
||
class="primary"
|
||
@click.stop="apply(job.id)"
|
||
>
|
||
{{ isApplied(job.id) ? '已投递' : '投递简历' }}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<p v-if="!filteredJobs.length" class="empty-text">
|
||
暂无符合当前筛选条件的岗位,可以尝试调整搜索条件。
|
||
</p>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 岗位详情页 -->
|
||
<section class="card detail-card">
|
||
<h3>3. 岗位详情</h3>
|
||
<div v-if="selectedJob" class="detail">
|
||
<h4>{{ selectedJob.title }} · {{ selectedJob.company }}</h4>
|
||
<p class="detail-sub">
|
||
{{ selectedJob.city }} · {{ selectedJob.salary }} ·
|
||
{{ selectedJob.companyType }}
|
||
</p>
|
||
|
||
<h5>岗位职责</h5>
|
||
<ul>
|
||
<li v-for="(duty, index) in selectedJob.duties" :key="index">
|
||
{{ duty }}
|
||
</li>
|
||
</ul>
|
||
|
||
<h5>任职要求</h5>
|
||
<ul>
|
||
<li v-for="(req, index) in selectedJob.requirements" :key="index">
|
||
{{ req }}
|
||
</li>
|
||
</ul>
|
||
|
||
<h5>企业介绍与薪资福利</h5>
|
||
<p class="detail-desc">{{ selectedJob.companyIntro }}</p>
|
||
</div>
|
||
<p v-else class="empty-text">
|
||
在左侧列表中选择一个岗位,查看详细信息与岗位要求。
|
||
</p>
|
||
</section>
|
||
</section>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { computed, reactive, ref } from 'vue'
|
||
|
||
type JobItem = {
|
||
id: number
|
||
title: string
|
||
company: string
|
||
city: string
|
||
salary: string
|
||
companyType: string
|
||
majorTag: string
|
||
hot: '高' | '中' | '低'
|
||
duties: string[]
|
||
requirements: string[]
|
||
companyIntro: string
|
||
}
|
||
|
||
const jobs = ref<JobItem[]>([
|
||
{
|
||
id: 1,
|
||
title: 'Java 后端开发工程师',
|
||
company: '云计算科技有限公司',
|
||
city: '北京',
|
||
salary: '18-25K',
|
||
companyType: '民企',
|
||
majorTag: '计算机',
|
||
hot: '高',
|
||
duties: [
|
||
'参与后端服务的设计与开发,保证系统稳定性与性能。',
|
||
'参与需求评审,与前端及产品协作完成业务功能。',
|
||
'编写相关技术文档与单元测试。'
|
||
],
|
||
requirements: [
|
||
'计算机或相关理工科专业,本科及以上学历。',
|
||
'熟悉 Java 语言及 SpringBoot 框架。',
|
||
'掌握 MySQL、Redis 等常用中间件,具备良好的编码习惯。'
|
||
],
|
||
companyIntro: '专注云计算与大数据解决方案,为各行业提供技术服务。'
|
||
},
|
||
{
|
||
id: 2,
|
||
title: '自动化测试工程师',
|
||
company: '智能硬件科技集团',
|
||
city: '深圳',
|
||
salary: '15-20K',
|
||
companyType: '民企',
|
||
majorTag: '电子',
|
||
hot: '中',
|
||
duties: [
|
||
'参与产品测试方案设计及测试用例编写。',
|
||
'搭建和维护自动化测试框架。',
|
||
'跟踪和推动缺陷修复,保障产品质量。'
|
||
],
|
||
requirements: [
|
||
'电子信息、计算机等相关理工科专业。',
|
||
'熟悉 Python、Shell 等脚本语言。',
|
||
'了解常见自动化测试工具和方法。'
|
||
],
|
||
companyIntro: '国内领先的智能硬件设计与生产企业,产品覆盖多领域。'
|
||
},
|
||
{
|
||
id: 3,
|
||
title: '机械设计工程师',
|
||
company: '高端装备制造股份有限公司',
|
||
city: '上海',
|
||
salary: '12-18K',
|
||
companyType: '国企',
|
||
majorTag: '机械',
|
||
hot: '高',
|
||
duties: [
|
||
'负责机械部件及整机结构的方案设计与优化。',
|
||
'输出二维工程图与三维模型,并跟进生产制造。',
|
||
'参与样机装配与测试验证。'
|
||
],
|
||
requirements: [
|
||
'机械设计相关专业,本科及以上学历。',
|
||
'熟练使用 SolidWorks、CATIA 等三维设计软件。',
|
||
'具备良好的沟通协调能力和团队协作精神。'
|
||
],
|
||
companyIntro: '国有大型装备制造企业,深耕高端装备领域多年。'
|
||
}
|
||
])
|
||
|
||
const filter = reactive({
|
||
keyword: '',
|
||
major: '',
|
||
companyType: '',
|
||
hot: ''
|
||
})
|
||
|
||
const selectedJob = ref<JobItem | null>(null)
|
||
const favoriteIds = ref<number[]>([])
|
||
const appliedIds = ref<number[]>([])
|
||
|
||
const filteredJobs = computed(() =>
|
||
jobs.value.filter((job) => {
|
||
const byKeyword = filter.keyword
|
||
? job.title.includes(filter.keyword) ||
|
||
job.company.includes(filter.keyword)
|
||
: true
|
||
const byMajor = filter.major ? job.majorTag === filter.major : true
|
||
const byCompanyType = filter.companyType
|
||
? job.companyType === filter.companyType
|
||
: true
|
||
const byHot = filter.hot ? job.hot === filter.hot : true
|
||
|
||
return byKeyword && byMajor && byCompanyType && byHot
|
||
})
|
||
)
|
||
|
||
function selectJob(job: JobItem) {
|
||
selectedJob.value = job
|
||
}
|
||
|
||
function isFavorite(id: number) {
|
||
return favoriteIds.value.includes(id)
|
||
}
|
||
|
||
function toggleFavorite(id: number) {
|
||
if (isFavorite(id)) {
|
||
favoriteIds.value = favoriteIds.value.filter((v) => v !== id)
|
||
} else {
|
||
favoriteIds.value.push(id)
|
||
}
|
||
}
|
||
|
||
function isApplied(id: number) {
|
||
return appliedIds.value.includes(id)
|
||
}
|
||
|
||
function apply(id: number) {
|
||
if (!isApplied(id)) {
|
||
appliedIds.value.push(id)
|
||
alert('简历已投递(示例),可在个人中心查看投递状态。')
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.page h2 {
|
||
margin-top: 0;
|
||
margin-bottom: 8px;
|
||
font-size: 20px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.intro {
|
||
margin: 0 0 16px;
|
||
color: #4b5563;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.card {
|
||
background: #f9fafb;
|
||
border-radius: 12px;
|
||
padding: 14px 16px;
|
||
border: 1px solid #e5e7eb;
|
||
}
|
||
|
||
.filter-bar {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
margin-top: 8px;
|
||
}
|
||
|
||
.filter-bar input,
|
||
.filter-bar select {
|
||
border-radius: 999px;
|
||
border: 1px solid #d1d5db;
|
||
padding: 6px 10px;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.layout {
|
||
margin-top: 16px;
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1.4fr) minmax(0, 1.2fr);
|
||
gap: 16px;
|
||
}
|
||
|
||
@media (max-width: 900px) {
|
||
.layout {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
}
|
||
|
||
.job-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
}
|
||
|
||
.job-item {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 10px 12px;
|
||
border-radius: 10px;
|
||
background: #ffffff;
|
||
border: 1px solid #e5e7eb;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.job-item.active {
|
||
border-color: #2563eb;
|
||
box-shadow: 0 0 0 1px rgba(37, 99, 235, 0.3);
|
||
}
|
||
|
||
.job-title-row {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
align-items: baseline;
|
||
}
|
||
|
||
.job-title {
|
||
font-size: 15px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.job-company {
|
||
font-size: 13px;
|
||
color: #6b7280;
|
||
}
|
||
|
||
.job-meta {
|
||
margin-top: 4px;
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
font-size: 12px;
|
||
color: #6b7280;
|
||
}
|
||
|
||
.job-actions {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 6px;
|
||
margin-left: 10px;
|
||
}
|
||
|
||
button {
|
||
border-radius: 999px;
|
||
border: none;
|
||
padding: 5px 12px;
|
||
font-size: 12px;
|
||
cursor: pointer;
|
||
background: #2563eb;
|
||
color: #ffffff;
|
||
}
|
||
|
||
button:hover {
|
||
background: #1d4ed8;
|
||
}
|
||
|
||
.primary {
|
||
background: #f97316;
|
||
}
|
||
|
||
.primary:hover {
|
||
background: #ea580c;
|
||
}
|
||
|
||
.secondary {
|
||
background: #e5e7eb;
|
||
color: #374151;
|
||
}
|
||
|
||
.detail-card {
|
||
min-height: 260px;
|
||
}
|
||
|
||
.detail h4 {
|
||
margin: 0 0 4px;
|
||
font-size: 16px;
|
||
}
|
||
|
||
.detail-sub {
|
||
margin: 0 0 10px;
|
||
font-size: 13px;
|
||
color: #6b7280;
|
||
}
|
||
|
||
.detail h5 {
|
||
margin: 10px 0 6px;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.detail ul {
|
||
padding-left: 18px;
|
||
margin: 0;
|
||
font-size: 13px;
|
||
color: #4b5563;
|
||
}
|
||
|
||
.detail-desc {
|
||
font-size: 13px;
|
||
color: #4b5563;
|
||
margin: 0;
|
||
}
|
||
|
||
.empty-text {
|
||
margin-top: 6px;
|
||
font-size: 13px;
|
||
color: #9ca3af;
|
||
}
|
||
</style>
|
||
|