Files
offerpai_web/src/views/Home.vue
T
2026-05-15 19:02:11 +08:00

575 lines
25 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="home-page">
<!-- Hero 主视觉区包含顶部导航 -->
<section class="home-hero">
<!-- 底层背景色块 -->
<div class="home-hero__orb home-hero__orb--top"></div>
<div class="home-hero__orb home-hero__orb--bottom"></div>
<!-- 顶部导航栏 -->
<header class="home-nav mt32">
<div class="home-nav__inner">
<div class="home-nav__logo">
<!-- 导航栏Logo图片 -->
<img src="@/assets/images/logo.png" alt="Offer派" class="home-nav__logo-img" />
</div>
<div class="dflex-end aliite-c">
<!-- 未登录时显示登陆和立即加入按钮 -->
<div v-if="!store.state.isAuthenticated" class="fs14 color-1 mr40 fw600 cursor-po" @click="handleLoginClick">登陆</div>
<button v-if="!store.state.isAuthenticated" class="home-nav__btn" @click="router.push('/jobs')">立即加入</button>
<!-- 已登录时显示进入平台按钮 -->
<button v-else class="home-nav__btn" @click="router.push('/jobs')">进入平台</button>
</div>
</div>
</header>
<div class="home-hero__inner">
<div class="home-hero__left">
<h1 class="home-hero__title">Offer派<br/>收offer就是快!</h1>
<p class="home-hero__desc">智能匹配职位自动填写申请量身定制简历推荐内部人脉不到1分钟统统搞定</p>
<button class="home-hero__cta" @click="router.push('/jobs')">免费体验</button>
</div>
<!-- 右侧视频展示区 -->
<div class="home-hero__right">
<video
class="home-hero__video"
src="https://jsxq-image-static.oss-cn-shenzhen.aliyuncs.com/aiJob/find/open-intention-video.mp4"
autoplay
loop
muted
playsinline
></video>
</div>
</div>
</section>
<!-- Stats Section -->
<section class="home-stats">
<div class="home-stats__inner">
<div class="home-stats__header">
<h2 class="fs48">让每一次求职努力<br/>都成为看得见的成果</h2>
<div class="home-stats__divider"></div>
</div>
<div class="home-stats__cards">
<article class="stat-card">
<div class="stat-card__num">第一</div>
<p class="stat-card__label">80%大学生求职首选</p>
</article>
<article class="stat-card">
<div class="stat-card__num">3</div>
<p class="stat-card__label">面试邀约率提升</p>
</article>
<article class="stat-card">
<div class="stat-card__num">82%</div>
<p class="stat-card__label">用户成功拿到offer</p>
</article>
</div>
</div>
</section>
<!-- Jobs Showcase Section -->
<section class="home-jobs-showcase">
<div class="home-jobs-showcase__inner">
<h2>海量优质校招岗位尽在Offer派</h2>
<p class="home-jobs-showcase__sub">实时汇集海量超10000+名校校招职位</p>
<div class="home-jobs-showcase__box">
<div class="home-jobs-showcase__stats">
<div class="showcase-stat">
<div class="showcase-stat__num"><span class="accent">40</span><span class="accent">+</span></div>
<div class="showcase-stat__label">岗位总数</div>
</div>
<div class="showcase-stat">
<div class="showcase-stat__num"><span class="accent">3120</span>个岗位</div>
<div class="showcase-stat__label">今日更新</div>
</div>
</div>
<div class="home-jobs-showcase__scroll">
<div class="job-ticker" v-for="(job, i) in tickerJobs" :key="i">
<span class="job-ticker__company">{{ job.company }}·{{ job.time }}</span>
<span class="job-ticker__title">{{ job.title }}</span>
</div>
</div>
</div>
</div>
</section>
<!-- Feature 1: 个性化岗位匹配 -->
<section class="home-feature">
<div class="home-feature__inner">
<div class="home-feature__text">
<h2>个性化<br/>岗位匹配</h2>
<p>第一时间发现真正适合你的岗位精准匹配你的真实技能杜绝虚假信息</p>
<button class="home-feature__btn" @click="router.push('/jobs')">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none"><circle cx="10" cy="10" r="8" stroke="currentColor" stroke-width="2"/><circle cx="10" cy="10" r="4" stroke="currentColor" stroke-width="2"/><circle cx="10" cy="10" r="1.5" fill="currentColor"/></svg>
<span>立即匹配</span>
</button>
</div>
<div class="home-feature__visual home-feature__visual--match">
<div class="feature-match-card">
<div class="feature-match-card__header">
<div class="feature-match-card__avatar"></div>
<div class="feature-match-card__info">
<h4>求职者 Alex</h4>
<div class="feature-match-card__tags">
<span>React</span><span>Tailwind</span>
</div>
</div>
<div class="feature-match-card__score">98%</div>
</div>
<div class="feature-match-card__bars">
<div class="bar bar--full"></div>
<div class="bar bar--3q"></div>
</div>
<div class="feature-match-card__result">为您匹配了 5 个高星职位</div>
</div>
</div>
</div>
</section>
<!-- Feature 2: 一键自动网申 -->
<section class="home-feature home-feature--reverse">
<div class="home-feature__inner">
<div class="home-feature__text">
<h2>校招一键<br/>自动网申</h2>
<p>每日向数百岗位一键投递覆盖各大企业网申系统告别重复填写节省 80% 的宝贵时间</p>
<button class="home-feature__btn" @click="router.push('/jobs')">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none"><path d="M3 10l2-8h10l2 8-7 7-7-7z" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/></svg>
<span>开启自动网申</span>
</button>
</div>
<div class="home-feature__visual home-feature__visual--apply">
<div class="feature-apply-card">
<div class="feature-apply-card__header">
<span class="feature-apply-card__status">正在执行投递程序...</span>
<div class="feature-apply-card__dots">
<span class="dot dot--red"></span>
<span class="dot dot--yellow"></span>
<span class="dot dot--green"></span>
</div>
</div>
<div class="feature-apply-card__list">
<div class="apply-item">
<div class="apply-item__icon"></div>
<div class="apply-item__info">
<p class="apply-item__title">腾讯科技 - 校招投递成功</p>
<p class="apply-item__sub">耗时 0.8s · 自动识别填写完毕</p>
</div>
</div>
<div class="apply-item apply-item--active">
<div class="apply-item__icon apply-item__icon--pulse">📋</div>
<div class="apply-item__info">
<p class="apply-item__title">京东校招 - 自动填写中...</p>
<p class="apply-item__sub">进度 65%</p>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Feature 3: 岗位定制简历 -->
<section class="home-feature">
<div class="home-feature__inner">
<div class="home-feature__text">
<h2>岗位定制简历</h2>
<p>10秒内生成针对特定岗位优化的专业简历通过ATS系统突出你的核心优势</p>
<button class="home-feature__btn" @click="router.push('/jobs')">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none"><path d="M4 2h8l4 4v12H4V2z" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/><path d="M12 2v4h4" stroke="currentColor" stroke-width="2"/><path d="M4 11h8" stroke="currentColor" stroke-width="2"/></svg>
<span>优化我的简历</span>
</button>
</div>
<div class="home-feature__visual home-feature__visual--resume">
<div class="feature-resume-card">
<div class="feature-resume-card__doc--border">
<div class="feature-resume-card__doc">
<div class="doc-header">
<div class="doc-avatar"></div>
<div class="doc-lines">
<div class="doc-line doc-line--half"></div>
<div class="doc-line doc-line--third"></div>
</div>
</div>
<div class="doc-bars">
<div class="doc-bar doc-bar--1"></div>
<div class="doc-bar doc-bar--2"></div>
<div class="doc-bar doc-bar--3"></div>
</div>
</div>
</div>
<div class="feature-resume-card__badge">
<svg width="15" height="15" viewBox="0 0 15 15" fill="none"><path d="M3 2h7l3 3v8H3V2z" stroke="#4FC2C9" stroke-width="1.2"/><path d="M6 7h3" stroke="#4FC2C9" stroke-width="1.2"/></svg>
<span>ATS OPTIMIZED</span>
</div>
</div>
</div>
</div>
</section>
<!-- Feature 4: 内推人脉 -->
<section class="home-feature home-feature--reverse">
<div class="home-feature__inner">
<div class="home-feature__text">
<h2>名企内推<br/>人脉直通</h2>
<p>实时获取名企最新内推信息自动填写网申内推码简历更快到达HR</p>
<button class="home-feature__btn" @click="router.push('/jobs')">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none"><path d="M3 3h10l4 4v10H3V3z" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/><path d="M6 12l2 2 4-4" stroke="currentColor" stroke-width="2"/></svg>
<span>立即投递</span>
</button>
</div>
<div class="home-feature__visual home-feature__visual--referral">
<div class="referral-grid">
<div class="referral-card" v-for="(ref, i) in referralCards" :key="i" :class="{ 'referral-card--offset': i % 2 === 1 }">
<div class="referral-card__icon" :style="{ background: ref.color }">{{ ref.letter }}</div>
<p class="referral-card__company">{{ ref.company }}</p>
<p class="referral-card__role">{{ ref.role }}</p>
<span class="referral-card__code">内推码: {{ ref.code }}</span>
</div>
</div>
</div>
</div>
</section>
<!-- Feature 5: AI求职助手 -->
<section class="home-feature">
<div class="home-feature__inner">
<div class="home-feature__text">
<h2>24h全天候<br/>AI求职助手</h2>
<p>随时提供求职指导从岗位筛选到面试技巧你的专属职业规划顾问</p>
<button class="home-feature__btn" @click="router.push('/jobs')">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none"><path d="M2 3h12v10H6l-4 4V3z" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/></svg>
<span>立即咨询</span>
</button>
</div>
<div class="home-feature__visual home-feature__visual--ai">
<div class="feature-ai-chat">
<div class="ai-bubble ai-bubble--bot">👋 哈喽我是你的 AI 职业导师正在为你分析即将到来的面试流程</div>
<div class="ai-bubble ai-bubble--user">能帮我模拟一下明天的腾讯面试吗</div>
<div class="ai-bubble ai-bubble--bot">
<p class="ai-bubble__title">准备就绪面试官画像已生成</p>
<div class="ai-bubble__tags">
<span>项目深度与工程化能力</span>
<span>计算机网络与操作系统</span>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- 用户评价区 Testimonials Section -->
<section class="home-testimonials">
<!-- 底层背景色块 -->
<div class="home-testimonials__orb home-testimonials__orb--left"></div>
<div class="home-testimonials__orb home-testimonials__orb--right"></div>
<!-- 内容层白色容器 -->
<div class="home-testimonials__container">
<!-- 标题区 -->
<div class="home-testimonials__header">
<h2>万千毕业生的信赖之选</h2>
<p>REAL VOICES FROM THE COMMUNITY</p>
</div>
<!-- 评价卡片横向排列 -->
<div class="home-testimonials__cards">
<div class="testimonial-card" v-for="(t, i) in testimonials" :key="i">
<!-- 引号装饰 SVG -->
<svg class="testimonial-card__quote" width="48" height="48" viewBox="0 0 48 48" fill="none">
<path d="M6 6h14v36" stroke="rgba(82,202,209,0.2)" stroke-width="2"/>
<path d="M28 6h14v36" stroke="rgba(82,202,209,0.2)" stroke-width="2"/>
</svg>
<p class="testimonial-card__text">"{{ t.text }}"</p>
<div class="testimonial-card__author">
<img class="testimonial-card__avatar" :src="avatarImg" alt="用户头像" />
<div class="testimonial-card__info">
<p class="testimonial-card__name">{{ t.name }}</p>
<p class="testimonial-card__school">{{ t.school }}</p>
</div>
</div>
</div>
</div>
<!-- 创始人引言卡片可切换 -->
<div class="home-testimonials__founder">
<!-- 装饰圆环 SVG -->
<svg class="home-testimonials__founder-decor" width="455" height="455" viewBox="0 0 455 455" fill="none">
<circle cx="227.5" cy="227.5" r="189.5" stroke="#fff" stroke-width="20" opacity="0.08"/>
<circle cx="227.5" cy="227.5" r="80" stroke="#fff" stroke-width="20" opacity="0.08"/>
</svg>
<div class="home-testimonials__founder-content">
<img class="home-testimonials__founder-img" :src="avatarImg" alt="创始人头像" />
<div class="home-testimonials__founder-text">
<blockquote>"{{ founderQuotes[founderIndex].text }}"</blockquote>
<cite>
<span class="cite-name">{{ founderQuotes[founderIndex].name }}</span>
<span class="cite-role">{{ founderQuotes[founderIndex].role }}</span>
</cite>
</div>
</div>
</div>
<!-- 分页小圆点 -->
<div class="home-testimonials__dots">
<span
v-for="(_, i) in founderQuotes"
:key="i"
class="home-testimonials__dot"
:class="{ 'home-testimonials__dot--active': founderIndex === i }"
@click="founderIndex = i"
></span>
</div>
</div>
</section>
<!-- FAQ Section -->
<section class="home-faq">
<div class="home-faq__inner">
<div class="home-faq__header">
<h2>常见问题</h2>
<p>FREQUENTLY ASKED QUESTIONS</p>
</div>
<div class="home-faq__list">
<div
v-for="(faq, i) in faqs"
:key="i"
class="faq-item"
:class="{ 'faq-item--open': faqOpen === i }"
@click="faqOpen = faqOpen === i ? -1 : i"
>
<div class="faq-item__header">
<span class="faq-item__question">{{ faq.q }}</span>
<div class="faq-item__icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
<line x1="5" y1="12" x2="19" y2="12" stroke="currentColor" stroke-width="2"/>
<line v-if="faqOpen !== i" x1="12" y1="5" x2="12" y2="19" stroke="currentColor" stroke-width="2"/>
</svg>
</div>
</div>
<div class="faq-item__answer" v-show="faqOpen === i">
<p>{{ faq.a }}</p>
</div>
</div>
</div>
</div>
</section>
<!-- CTA Section -->
<section class="home-cta">
<div class="home-cta__inner">
<h2>让Offer不再遥不可及<br/>大学生一站式AI求职</h2>
<button class="home-cta__btn" @click="router.push('/jobs')">免费体验</button>
</div>
</section>
<!-- Job Search Section -->
<section class="home-job-search">
<div class="home-job-search__inner">
<h3>一键找到最适合你的工作</h3>
<div class="home-job-search__filters">
<!-- 行业选择器 -->
<IndustrySelector
:industryIds="homeIndustryIds"
:level="2"
:maxSelect="3"
:allowParentSelect="false"
:triggerStyle="filterTriggerStyle"
:displayStyle="filterDisplayStyle"
@update:industryIds="onHomeIndustryChange"
/>
<!-- 地区选择器 -->
<RegionSelector
:regionCodes="homeRegionCodes"
:level="2"
:maxSelect="3"
:triggerStyle="filterTriggerStyle"
:displayStyle="filterDisplayStyle"
@update:regionCodes="onHomeRegionChange"
/>
<!-- 岗位选择器 -->
<JobCategorySelector
:categoryIds="homeCategoryIds"
:level="3"
:maxSelect="3"
:allowParentSelect="false"
:triggerStyle="filterTriggerStyle"
:displayStyle="filterDisplayStyle"
@update:categoryIds="onHomeCategoryChange"
/>
<button class="filter-btn" @click="goSearchJobs">搜索职位</button>
</div>
</div>
</section>
<!-- Footer -->
<footer class="home-footer">
<div class="home-footer__inner">
<div class="home-footer__col">
<div class="home-footer__logo">
<!-- 网站Logo图片 -->
<img src="@/assets/images/logo.png" alt="Offer派" class="home-footer__logo-img" />
</div>
<p class="home-footer__slogan">大学生AI求职平台</p>
</div>
<div class="home-footer__col">
<h5>核心功能</h5>
<ul>
<li>智能岗位匹配</li>
<li>AI简历优化</li>
<li>AI求职助手</li>
<li>一键投递</li>
</ul>
</div>
<div class="home-footer__col">
<h5>求职资源</h5>
<ul>
<li>求职指南</li>
<li>面试技巧</li>
<li>简历模版</li>
<li>行业分析</li>
</ul>
</div>
<div class="home-footer__col">
<h5>其他信息</h5>
<ul>
<li>隐私协议</li>
<li>服务条款</li>
</ul>
</div>
</div>
<div class="home-footer__bottom">
<p>©2016-2026 - 广州油梨信息科技有限公司 版权所有</p>
</div>
</footer>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, computed } from 'vue'
import { useRouter } from 'vue-router'
import { useStore } from 'vuex'
import avatarImg from '@/assets/images/home/avatar-temporary.png'
import IndustrySelector from '@/components/tools/IndustrySelector.vue'
import RegionSelector from '@/components/tools/RegionSelector.vue'
import JobCategorySelector from '@/components/tools/JobCategorySelector.vue'
/** 路由实例 */
const router = useRouter()
/** Vuex 状态管理实例 */
const store = useStore()
/** 当前展开的 FAQ 索引,-1 表示全部收起 */
const faqOpen = ref(-1)
/** 创始人引言当前索引 — 点击小圆点可切换 */
const founderIndex = ref(0)
/** 创始人引言数据 — 支持多条切换 */
const founderQuotes = [
{ text: '很多大学生还在用传统方式找工作,海投、反复改简历,效率很低。Offer派利用AI技术让整个校招流程更丝滑,节省了80%的繁琐过程。', name: 'Stella', role: 'Offer派创始人' },
{ text: '我们的目标是让每一位大学生都能高效地找到心仪的工作,AI技术正在改变校招的游戏规则。', name: 'Stella', role: 'Offer派创始人' },
]
/** 岗位滚动展示数据 — 模拟最新发布的校招岗位 */
const tickerJobs = [
{ company: '字节跳动', time: '15分钟前', title: '前端开发工程师' },
{ company: '腾讯', time: '30分钟前', title: '后端开发工程师' },
{ company: '阿里巴巴', time: '1小时前', title: '产品经理' },
{ company: '华为', time: '2小时前', title: '算法工程师' },
{ company: '京东', time: '3小时前', title: '运营管培生' },
]
/** 内推人脉卡片数据 — letter: 公司首字母, color: 图标背景色 */
const referralCards = [
{ letter: 'b', company: '字节跳动', role: '前端工程师', code: 'r7u9xx', color: '#2563eb' },
{ letter: 'a', company: '阿里巴巴', role: '运营管培生', code: 'alicc2', color: '#ea580c' },
{ letter: 't', company: '腾讯', role: '后端开发工程师', code: 'tx9901', color: '#111827' },
{ letter: 'h', company: '华为', role: '通用软件研究员', code: 'hwl92', color: '#dc2626' },
]
/** 用户评价数据 — 展示真实用户的使用反馈 */
const testimonials = [
{ text: 'Offer派求职体验特别好!岗位信息丰富、质量高,AI岗位匹配也很精准,求职助手给的面试建议很专业,一周就拿到了Offer!', name: '李同学', school: '西安交通大学' },
{ text: '简历优化功能太强了,针对不同岗位自动调整内容,面试邀约率直接翻倍。', name: '王同学', school: '浙江大学' },
{ text: '一键投递省了我大量时间,再也不用一个个填网申表格了,效率提升太明显。', name: '张同学', school: '北京大学' },
]
/** 常见问题列表 — q: 问题, a: 答案,点击可展开/收起 */
const faqs = [
{ q: '这个平台与其他求职网站有什么不同?', a: 'Offer派专注于大学生校招场景,利用AI技术实现智能岗位匹配、一键自动网申、岗位定制简历和内推人脉直通,让求职效率提升80%以上。' },
{ q: '平台会分享我的个人信息吗?', a: '绝对不会。我们严格遵守隐私保护法规,您的个人信息仅用于岗位匹配和简历投递,不会分享给任何第三方。' },
{ q: '如何收费?', a: '基础功能完全免费,包括岗位浏览、AI匹配和求职助手。高级功能如一键批量投递、定制简历等提供会员订阅服务。' },
{ q: '平台的岗位来源是什么?', a: '我们的岗位信息来自各大企业官方校招渠道、合作高校就业中心以及企业HR直接发布,确保信息真实可靠。' },
{ q: '支持哪些企业?', a: '目前已覆盖互联网、金融、制造、快消等行业的数千家企业,包括字节跳动、腾讯、阿里巴巴、华为等头部企业。' },
]
// ==================== 底部筛选区:行业/地区/岗位选择器 ====================
/** 首页选中的行业 ID 数组 — 读写 store.jobIntention */
const homeIndustryIds = computed<number[]>(() => store.state.jobIntention.industryIds || [])
/** 首页选中的地区编码数组 — 读写 store.jobIntention */
const homeRegionCodes = computed<string[]>(() => store.state.jobIntention.regionCodes || [])
/** 首页选中的岗位 ID 数组 — 读写 store.jobIntention */
const homeCategoryIds = computed<number[]>(() => store.state.jobIntention.categoryIds || [])
/** 选择器触发按钮样式 — 匹配首页 .filter-select 的外观 */
const filterTriggerStyle = {
width: '2.35rem',
height: '0.48rem',
'border-radius': '0.24rem',
border: '1px solid #e5e7eb',
padding: '0 0.2rem',
background: '#fff',
'justify-content': 'space-between',
}
/** 选择器显示文字样式 — 匹配首页 .filter-select 内文字 */
const filterDisplayStyle = {
'font-size': '0.16rem',
'line-height': '0.24rem',
color: 'rgba(0, 0, 0, 0.45)',
'max-width': '1.8rem',
}
/** 行业选择变更回调 — 保存到 store */
function onHomeIndustryChange(ids: number[]) {
store.dispatch('saveJobIntention', {
...store.state.jobIntention,
industryIds: ids,
})
}
/** 地区选择变更回调 — 保存到 store */
function onHomeRegionChange(codes: string[]) {
store.dispatch('saveJobIntention', {
...store.state.jobIntention,
regionCodes: codes,
})
}
/** 岗位选择变更回调 — 保存到 store */
function onHomeCategoryChange(ids: number[]) {
store.dispatch('saveJobIntention', {
...store.state.jobIntention,
categoryIds: ids,
})
}
/** 点击搜索职位 — 跳转到 Jobs 页面 */
function goSearchJobs() {
router.push('/jobs')
}
onMounted(() => {
// 加载公共工具数据(行业分类、岗位分类、地区分类等)
store.dispatch('loadCommonData')
// 触发预渲染事件 — 配合 vite.config.ts 中 PrerenderPlugin 的 renderAfterDocumentEvent 设置
document.dispatchEvent(new Event('prerender-trigger'))
})
/** 点击登陆按钮 — 打开登录弹窗,登录成功后跳转到 jobs 页面 */
function handleLoginClick() {
store.dispatch('openLogin', '/jobs')
}
</script>