简历列表,首页其他4个页面
This commit is contained in:
Vendored
+5
@@ -38,6 +38,11 @@ declare module 'vue' {
|
|||||||
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
||||||
FullscreenLoading: typeof import('./src/components/FullscreenLoading.vue')['default']
|
FullscreenLoading: typeof import('./src/components/FullscreenLoading.vue')['default']
|
||||||
HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
|
HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
|
||||||
|
HomeAbout: typeof import('./src/components/HomeAbout.vue')['default']
|
||||||
|
HomeAnnouncement: typeof import('./src/components/HomeAnnouncement.vue')['default']
|
||||||
|
HomeContent: typeof import('./src/components/HomeContent.vue')['default']
|
||||||
|
HomeJobRadar: typeof import('./src/components/HomeJobRadar.vue')['default']
|
||||||
|
HomeMentor: typeof import('./src/components/HomeMentor.vue')['default']
|
||||||
IndustrySelector: typeof import('./src/components/tools/IndustrySelector.vue')['default']
|
IndustrySelector: typeof import('./src/components/tools/IndustrySelector.vue')['default']
|
||||||
JobApplyMethodDialog: typeof import('./src/components/JobApplyMethodDialog.vue')['default']
|
JobApplyMethodDialog: typeof import('./src/components/JobApplyMethodDialog.vue')['default']
|
||||||
JobCategorySelector: typeof import('./src/components/tools/JobCategorySelector.vue')['default']
|
JobCategorySelector: typeof import('./src/components/tools/JobCategorySelector.vue')['default']
|
||||||
|
|||||||
@@ -91,6 +91,60 @@ export interface AnnouncementPageData {
|
|||||||
list: AnnouncementItem[]
|
list: AnnouncementItem[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 校招公告统计数据 */
|
||||||
|
export interface AnnouncementStatistics {
|
||||||
|
/** 今日新增公告数 */
|
||||||
|
dayCount: number
|
||||||
|
/** 本月新增公告数 */
|
||||||
|
monthCount: number
|
||||||
|
/** 累计公告数 */
|
||||||
|
totalCount: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取公告最新更新时间
|
||||||
|
* GET /public/recruitAnnouncement/lastUpdateTime
|
||||||
|
* 返回毫秒时间戳(如 1786387561000)
|
||||||
|
*/
|
||||||
|
export function fetchAnnouncementLastUpdateTime() {
|
||||||
|
return request.get<any, ApiResult<number>>('/public/recruitAnnouncement/lastUpdateTime')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取公告毕业年份标签列表
|
||||||
|
* GET /public/recruitAnnouncement/year
|
||||||
|
* 返回年份数组,如 [2021, 2022, ..., 2029]
|
||||||
|
*/
|
||||||
|
export function fetchAnnouncementRecruitYearTags() {
|
||||||
|
return request.get<any, ApiResult<number[]>>('/public/recruitAnnouncement/year')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取公告学历筛选选项
|
||||||
|
* GET /public/recruitAnnouncement/education
|
||||||
|
* 返回学历字符串数组,如 ["专科","中专","博士","大专","本科","硕士","高中"]
|
||||||
|
*/
|
||||||
|
export function fetchAnnouncementEducationOptions() {
|
||||||
|
return request.get<any, ApiResult<string[]>>('/public/recruitAnnouncement/education')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取公告招聘批次筛选选项
|
||||||
|
* GET /public/recruitAnnouncement/batch
|
||||||
|
* 返回批次字符串数组
|
||||||
|
*/
|
||||||
|
export function fetchAnnouncementBatchOptions() {
|
||||||
|
return request.get<any, ApiResult<string[]>>('/public/recruitAnnouncement/batch')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取校招公告统计数据
|
||||||
|
* GET /public/recruitAnnouncement/statistics
|
||||||
|
*/
|
||||||
|
export function fetchAnnouncementStatistics() {
|
||||||
|
return request.get<any, ApiResult<AnnouncementStatistics>>('/public/recruitAnnouncement/statistics')
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取校招公告分页列表
|
* 获取校招公告分页列表
|
||||||
* POST /public/recruitAnnouncement/page
|
* POST /public/recruitAnnouncement/page
|
||||||
@@ -121,6 +175,8 @@ export interface AnnouncementDetail {
|
|||||||
title: string
|
title: string
|
||||||
/** 公司简介 */
|
/** 公司简介 */
|
||||||
companyIntro: string
|
companyIntro: string
|
||||||
|
/** 公司规模 */
|
||||||
|
companyScale: string
|
||||||
/** 面向对象 */
|
/** 面向对象 */
|
||||||
targetAudience: string
|
targetAudience: string
|
||||||
/** 专业要求 */
|
/** 专业要求 */
|
||||||
@@ -141,6 +197,10 @@ export interface AnnouncementDetail {
|
|||||||
inviteCode: string
|
inviteCode: string
|
||||||
/** 信息来源说明 */
|
/** 信息来源说明 */
|
||||||
source: string
|
source: string
|
||||||
|
/** 公告地址 */
|
||||||
|
announcementUrl: string
|
||||||
|
/** 投递地址 */
|
||||||
|
applyUrl: string
|
||||||
/** 发布时间 */
|
/** 发布时间 */
|
||||||
publishTime: InstantTime | null
|
publishTime: InstantTime | null
|
||||||
/** 清洗状态 */
|
/** 清洗状态 */
|
||||||
@@ -176,3 +236,56 @@ export function fetchAnnouncementDetail(id: string) {
|
|||||||
params: { id },
|
params: { id },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ==================== 校招公告推荐列表接口 ====================
|
||||||
|
|
||||||
|
/** 校招公告推荐请求参数 */
|
||||||
|
export interface AnnouncementRecommendParams {
|
||||||
|
/** 当前页码,从1开始 */
|
||||||
|
pageNum?: number
|
||||||
|
/** 每页条数 */
|
||||||
|
pageSize?: number
|
||||||
|
/** 关键字 */
|
||||||
|
keyword?: string
|
||||||
|
/** 公告ID(必传,字符串避免精度丢失) */
|
||||||
|
announcementId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 校招公告推荐列表项 */
|
||||||
|
export interface AnnouncementRecommendItem {
|
||||||
|
/** 公告ID */
|
||||||
|
id: number
|
||||||
|
/** 公司名称 */
|
||||||
|
companyName: string
|
||||||
|
/** 公司logo */
|
||||||
|
logoUrl: string
|
||||||
|
/** 岗位大类列表 */
|
||||||
|
categoryNames: string[]
|
||||||
|
/** 热招城市列表 */
|
||||||
|
cityNames: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 校招公告推荐分页数据 */
|
||||||
|
export interface AnnouncementRecommendPageData {
|
||||||
|
/** 当前页码 */
|
||||||
|
pageNum: number
|
||||||
|
/** 每页条数 */
|
||||||
|
pageSize: number
|
||||||
|
/** 总记录数 */
|
||||||
|
total: number
|
||||||
|
/** 数据列表 */
|
||||||
|
list: AnnouncementRecommendItem[]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取校招公告推荐列表
|
||||||
|
* POST /public/recruitAnnouncement/recommend
|
||||||
|
*/
|
||||||
|
export function fetchAnnouncementRecommend(params: AnnouncementRecommendParams) {
|
||||||
|
return request.post<any, ApiResult<AnnouncementRecommendPageData>>('/public/recruitAnnouncement/recommend', {
|
||||||
|
pageNum: params.pageNum ?? 1,
|
||||||
|
pageSize: params.pageSize ?? 100,
|
||||||
|
...params,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
+3
-3
@@ -146,7 +146,7 @@ export interface HotCityItem {
|
|||||||
* GET /job/industry/hot
|
* GET /job/industry/hot
|
||||||
*/
|
*/
|
||||||
export function fetchHotIndustries() {
|
export function fetchHotIndustries() {
|
||||||
return request.get<any, ApiResult<HotIndustryItem[]>>('/job/industry/hot')
|
return request.get<any, ApiResult<HotIndustryItem[]>>('/job/public/industry/hot')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -154,7 +154,7 @@ export function fetchHotIndustries() {
|
|||||||
* GET /job/category/hot
|
* GET /job/category/hot
|
||||||
*/
|
*/
|
||||||
export function fetchHotCategories() {
|
export function fetchHotCategories() {
|
||||||
return request.get<any, ApiResult<HotCategoryItem[]>>('/job/category/hot')
|
return request.get<any, ApiResult<HotCategoryItem[]>>('/job/public/category/hot')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -162,7 +162,7 @@ export function fetchHotCategories() {
|
|||||||
* GET /job/city/hot
|
* GET /job/city/hot
|
||||||
*/
|
*/
|
||||||
export function fetchHotCities() {
|
export function fetchHotCities() {
|
||||||
return request.get<any, ApiResult<HotCityItem[]>>('/job/city/hot')
|
return request.get<any, ApiResult<HotCityItem[]>>('/job/public/city/hot')
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 求职意向 ====================
|
// ==================== 求职意向 ====================
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 2.0 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.7 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.8 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 167 KiB |
@@ -176,6 +176,7 @@
|
|||||||
gap: 0.24rem;
|
gap: 0.24rem;
|
||||||
margin-bottom: 0.16rem;
|
margin-bottom: 0.16rem;
|
||||||
margin-left: 0.4rem;
|
margin-left: 0.4rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.agent-browser-guide-drawer__browser-link {
|
.agent-browser-guide-drawer__browser-link {
|
||||||
|
|||||||
@@ -5,12 +5,10 @@
|
|||||||
width: var(--chat-width, 3.6rem);
|
width: var(--chat-width, 3.6rem);
|
||||||
height: var(--app-height, 100vh);
|
height: var(--app-height, 100vh);
|
||||||
background: $bg-white;
|
background: $bg-white;
|
||||||
position: fixed;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
// ==================== 顶部头部区域 ====================
|
// ==================== 顶部头部区域 ====================
|
||||||
&__header {
|
&__header {
|
||||||
|
|||||||
@@ -0,0 +1,484 @@
|
|||||||
|
@use '../variables' as *;
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// 首页-关于我们Tab样式
|
||||||
|
// ========================================
|
||||||
|
.home-about {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
// ==================== Hero 区域 ====================
|
||||||
|
&__hero {
|
||||||
|
position: relative;
|
||||||
|
padding: 0.6rem 0 0.8rem;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 底部居中渐变浅色色块
|
||||||
|
&__hero-orb {
|
||||||
|
position: absolute;
|
||||||
|
bottom: -2.5rem;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 8rem;
|
||||||
|
height: 3rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: rgba(82, 202, 209, 0.15);
|
||||||
|
filter: blur(1rem);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
&__hero-inner {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
text-align: center;
|
||||||
|
max-width: 12rem;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__hero-kicker {
|
||||||
|
font-size: 0.20rem;
|
||||||
|
line-height: 0.27rem;
|
||||||
|
font-weight: 450;
|
||||||
|
color: $accent;
|
||||||
|
margin-bottom: 0.24rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__hero-title {
|
||||||
|
font-size: 0.54rem;
|
||||||
|
line-height: 0.72rem;
|
||||||
|
font-weight: 630;
|
||||||
|
color: #111111;
|
||||||
|
margin-top: 0.24rem;
|
||||||
|
margin-bottom: 0.24rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__hero-subtitle {
|
||||||
|
font-size: 0.20rem;
|
||||||
|
line-height: 0.27rem;
|
||||||
|
font-weight: 330;
|
||||||
|
color: #64748B;
|
||||||
|
margin-bottom: 0.40rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__hero-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 1.84rem;
|
||||||
|
height: 0.56rem;
|
||||||
|
background: $accent;
|
||||||
|
border-radius: 0.16rem;
|
||||||
|
border: none;
|
||||||
|
font-size: 0.16rem;
|
||||||
|
line-height: 0.21rem;
|
||||||
|
font-weight: 520;
|
||||||
|
color: #FFFFFF;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $accent-hover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 通用 kicker ====================
|
||||||
|
&__kicker {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
font-weight: 520;
|
||||||
|
color: $accent;
|
||||||
|
margin-bottom: 0.12rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 通用标题 ====================
|
||||||
|
&__section-title {
|
||||||
|
font-size: 0.48rem;
|
||||||
|
line-height: 0.64rem;
|
||||||
|
font-weight: 520;
|
||||||
|
color: #111111;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__section-subtitle {
|
||||||
|
font-size: 0.20rem;
|
||||||
|
line-height: 0.27rem;
|
||||||
|
font-weight: 330;
|
||||||
|
color: #64748B;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 产品介绍 ====================
|
||||||
|
&__intro {
|
||||||
|
padding: 0.80rem 0;
|
||||||
|
background: $bg-white;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__intro-inner {
|
||||||
|
max-width: 12rem;
|
||||||
|
margin: 0 auto;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 0.70rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__intro-img {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 5.06rem;
|
||||||
|
height: 3.68rem;
|
||||||
|
background: #F5FAFA;
|
||||||
|
border-radius: 0.22rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__intro-img-placeholder {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__intro-text {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__intro-desc {
|
||||||
|
font-size: 0.16rem;
|
||||||
|
line-height: 0.24rem;
|
||||||
|
font-weight: 380;
|
||||||
|
color: #64748B;
|
||||||
|
margin-top: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 功能亮点 ====================
|
||||||
|
&__features {
|
||||||
|
position: relative;
|
||||||
|
padding: 0.80rem 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__features-header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 0.60rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__features-grid {
|
||||||
|
max-width: 12rem;
|
||||||
|
margin: 0 auto;
|
||||||
|
display: flex;
|
||||||
|
gap: 0.16rem;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__feature-card {
|
||||||
|
width: 2.68rem;
|
||||||
|
height: 2.97rem;
|
||||||
|
background: $bg-white;
|
||||||
|
box-shadow: 0px 6px 20px rgba(0, 0, 0, 0.06);
|
||||||
|
border-radius: 0.16rem;
|
||||||
|
padding: 0.24rem 0.24rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__feature-icon {
|
||||||
|
width: 0.58rem;
|
||||||
|
height: 0.58rem;
|
||||||
|
background: #F4FBFB;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__feature-title {
|
||||||
|
font-size: 0.18rem;
|
||||||
|
line-height: 0.24rem;
|
||||||
|
font-weight: 520;
|
||||||
|
color: #111111;
|
||||||
|
margin-bottom: 0.08rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__feature-desc {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.24rem;
|
||||||
|
font-weight: 330;
|
||||||
|
color: $text-middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 为什么创立 ====================
|
||||||
|
&__why {
|
||||||
|
padding: 0.80rem 0;
|
||||||
|
max-width: 12rem;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__why-header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 0.60rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__why-content {
|
||||||
|
background: $bg-white;
|
||||||
|
box-shadow: 0px 6px 20px rgba(0, 0, 0, 0.06);
|
||||||
|
border-radius: 0.32rem;
|
||||||
|
padding: 0.40rem;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__why-block {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 0.40rem;
|
||||||
|
margin-bottom: 0.40rem;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--reverse {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__why-text {
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 0.24rem;
|
||||||
|
line-height: 0.32rem;
|
||||||
|
font-weight: 520;
|
||||||
|
color: #111111;
|
||||||
|
margin-bottom: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 0.16rem;
|
||||||
|
line-height: 0.30rem;
|
||||||
|
font-weight: 330;
|
||||||
|
color: $text-middle;
|
||||||
|
margin-bottom: 0.12rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__why-sign {
|
||||||
|
font-size: 0.16rem;
|
||||||
|
line-height: 0.30rem;
|
||||||
|
font-weight: 330;
|
||||||
|
color: $text-middle;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__why-img {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 5.44rem;
|
||||||
|
height: 2.59rem;
|
||||||
|
background: #F5FAFA;
|
||||||
|
border-radius: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 万千毕业生信赖 ====================
|
||||||
|
&__trust {
|
||||||
|
padding: 0.80rem 0;
|
||||||
|
max-width: 12rem;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__trust-header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 0.60rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__trust-dark-card {
|
||||||
|
background: #111111;
|
||||||
|
border-radius: 0.16rem;
|
||||||
|
padding: 0.28rem 0.40rem;
|
||||||
|
margin-bottom: 0.24rem;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__trust-dark-text {
|
||||||
|
max-width: 75%;
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 0.16rem;
|
||||||
|
line-height: 0.30rem;
|
||||||
|
font-weight: 330;
|
||||||
|
color: #FFFFFF;
|
||||||
|
margin-bottom: 0.10rem;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
font-weight: 520;
|
||||||
|
margin-bottom: 0.16rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__trust-dark-logo {
|
||||||
|
position: absolute;
|
||||||
|
right: 0.40rem;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
width: 1.64rem;
|
||||||
|
height: 1.64rem;
|
||||||
|
opacity: 0.1;
|
||||||
|
background: $bg-white;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__trust-cards {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.24rem;
|
||||||
|
margin-bottom: 0.24rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__trust-card {
|
||||||
|
flex: 1;
|
||||||
|
background: $bg-white;
|
||||||
|
box-shadow: 0px 20px 50px rgba(0, 0, 0, 0.05);
|
||||||
|
border-radius: 0.16rem;
|
||||||
|
padding: 0.24rem 0.28rem;
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-size: 0.18rem;
|
||||||
|
line-height: 0.24rem;
|
||||||
|
font-weight: 520;
|
||||||
|
color: #111111;
|
||||||
|
margin-bottom: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.24rem;
|
||||||
|
font-weight: 330;
|
||||||
|
color: $text-middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__trust-summary {
|
||||||
|
font-size: 0.24rem;
|
||||||
|
line-height: 0.32rem;
|
||||||
|
font-weight: 520;
|
||||||
|
color: $text-dark;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 0.40rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 价值观 ====================
|
||||||
|
&__values {
|
||||||
|
padding: 0.80rem 0;
|
||||||
|
max-width: 12rem;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__values-header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 0.60rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__values-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 0.24rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__value-card {
|
||||||
|
background: #F9FAFB;
|
||||||
|
border-radius: 0.24rem;
|
||||||
|
padding: 0.32rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__value-icon {
|
||||||
|
margin-bottom: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__value-title {
|
||||||
|
font-size: 0.24rem;
|
||||||
|
line-height: 0.32rem;
|
||||||
|
font-weight: 630;
|
||||||
|
color: #111111;
|
||||||
|
margin-bottom: 0.08rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__value-desc {
|
||||||
|
font-size: 0.18rem;
|
||||||
|
line-height: 0.24rem;
|
||||||
|
font-weight: 330;
|
||||||
|
color: $text-middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 联系我们 ====================
|
||||||
|
&__contact {
|
||||||
|
padding: 0.80rem 0;
|
||||||
|
max-width: 12rem;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__contact-header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 0.60rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__contact-grid {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.24rem;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__contact-card {
|
||||||
|
flex: 1;
|
||||||
|
max-width: 3.77rem;
|
||||||
|
background: $bg-white;
|
||||||
|
box-shadow: 0px 6px 20px rgba(0, 0, 0, 0.06);
|
||||||
|
border-radius: 0.16rem;
|
||||||
|
padding: 0.24rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__contact-icon {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 0.58rem;
|
||||||
|
height: 0.58rem;
|
||||||
|
background: #F4FBFB;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__contact-info {
|
||||||
|
h4 {
|
||||||
|
font-size: 0.18rem;
|
||||||
|
line-height: 0.24rem;
|
||||||
|
font-weight: 520;
|
||||||
|
color: #111111;
|
||||||
|
margin-bottom: 0.04rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.24rem;
|
||||||
|
font-weight: 330;
|
||||||
|
color: $text-middle;
|
||||||
|
margin-bottom: 0.08rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__contact-link {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.24rem;
|
||||||
|
font-weight: 520;
|
||||||
|
color: $accent;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $accent-hover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,387 @@
|
|||||||
|
@use '../variables' as *;
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// 首页-校招公告Tab样式
|
||||||
|
// ========================================
|
||||||
|
.home-announcement {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
// 第一部分容器
|
||||||
|
&__section {
|
||||||
|
width: 12rem;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0.6rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标题区域
|
||||||
|
&__header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 0.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
font-size: 0.36rem;
|
||||||
|
line-height: 0.48rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: $text-dark;
|
||||||
|
margin-bottom: 0.12rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__subtitle {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.2rem;
|
||||||
|
color: $text-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 筛选面板(与岗位雷达一致) ====================
|
||||||
|
&__filters {
|
||||||
|
background: $bg-white;
|
||||||
|
border: 1px solid #F0F0F0;
|
||||||
|
box-shadow: 0px 2px 6px rgba(15, 23, 42, 0.025);
|
||||||
|
border-radius: 0.14rem;
|
||||||
|
padding: 0.24rem 0.40rem;
|
||||||
|
margin-bottom: 0.32rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__filter-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 0.16rem;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__filter-label {
|
||||||
|
width: 0.28rem;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
font-weight: 450;
|
||||||
|
color: $text-light;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-right: 0.24rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__filter-chips {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.14rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__chip {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0.06rem 0.12rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: #F5F8F8;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
font-weight: 330;
|
||||||
|
color: $text-middle;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #E8F7F8;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--active {
|
||||||
|
background: $accent;
|
||||||
|
color: #FFFFFF;
|
||||||
|
font-weight: 520;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $accent-hover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 公告卡片网格 ====================
|
||||||
|
&__grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 公告卡片
|
||||||
|
&__card {
|
||||||
|
background: $bg-white;
|
||||||
|
border: 1px solid #E8F1F1;
|
||||||
|
border-radius: 0.16rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: box-shadow 0.2s, border-color 0.2s;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
|
||||||
|
border-color: #D0E8E8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 卡片主体
|
||||||
|
&__card-body {
|
||||||
|
display: flex;
|
||||||
|
padding: 0.16rem 0.20rem;
|
||||||
|
gap: 0.12rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 左侧logo容器
|
||||||
|
&__card-logo-wrap {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__card-logo {
|
||||||
|
width: 0.48rem;
|
||||||
|
height: 0.48rem;
|
||||||
|
border-radius: 0.08rem;
|
||||||
|
border: 1px solid #F4F4F4;
|
||||||
|
object-fit: cover;
|
||||||
|
|
||||||
|
&--default {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: $bg-white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 右侧内容区
|
||||||
|
&__card-content {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标题行
|
||||||
|
&__card-title-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 0.06rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__card-title {
|
||||||
|
font-size: 0.16rem;
|
||||||
|
line-height: 0.21rem;
|
||||||
|
font-weight: 520;
|
||||||
|
color: $text-dark;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 公司类型标签(蓝色)
|
||||||
|
&__card-type-tag {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0.02rem 0.08rem;
|
||||||
|
background: #ECF3FC;
|
||||||
|
border-radius: 0.04rem;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.16rem;
|
||||||
|
font-weight: 330;
|
||||||
|
color: #2672E1;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-left: 0.08rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标签行
|
||||||
|
&__card-tags {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.08rem;
|
||||||
|
margin-bottom: 0.10rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__card-tag {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0.02rem 0.08rem;
|
||||||
|
border-radius: 0.04rem;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.16rem;
|
||||||
|
font-weight: 330;
|
||||||
|
|
||||||
|
// 批次标签(青色)
|
||||||
|
&--batch {
|
||||||
|
background: #F0FAFB;
|
||||||
|
color: $accent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 学历标签(橙色)
|
||||||
|
&--edu {
|
||||||
|
background: #FAF2ED;
|
||||||
|
color: #D17E52;
|
||||||
|
font-weight: 305;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 信息行(岗位/城市)
|
||||||
|
&__card-info-line {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.04rem;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
font-weight: 380;
|
||||||
|
color: #64748B;
|
||||||
|
margin-bottom: 0.04rem;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__card-icon {
|
||||||
|
width: 0.16rem;
|
||||||
|
height: 0.16rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 卡片底部渐变条
|
||||||
|
&__card-footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0.10rem 0.20rem;
|
||||||
|
background: linear-gradient(270deg, rgba(159, 208, 81, 0.08) 0%, rgba(82, 202, 209, 0.08) 62.02%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__card-update {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
font-weight: 330;
|
||||||
|
color: #94A3B8;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__card-deadline {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
font-weight: 520;
|
||||||
|
color: $text-dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 加载中 ====================
|
||||||
|
&__loading {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0.4rem 0;
|
||||||
|
gap: 0.08rem;
|
||||||
|
color: $text-light;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__spinner {
|
||||||
|
width: 0.2rem;
|
||||||
|
height: 0.2rem;
|
||||||
|
border: 2px solid #e5e7eb;
|
||||||
|
border-top-color: $accent;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: home-announcement-spin 0.8s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 查看更多按钮 ====================
|
||||||
|
&__more {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 0.32rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__more-btn {
|
||||||
|
padding: 0.10rem 0.40rem;
|
||||||
|
border-radius: 0.08rem;
|
||||||
|
background: $text-dark;
|
||||||
|
color: #FFFFFF;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.2rem;
|
||||||
|
font-weight: 500;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 首页版统计卡片 ====================
|
||||||
|
&__stats-card {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.20rem 0.24rem;
|
||||||
|
gap: 0.40rem;
|
||||||
|
background: $bg-white;
|
||||||
|
border: 1px solid #F0F0F0;
|
||||||
|
box-shadow: 0px 2px 6px rgba(15, 23, 42, 0.025);
|
||||||
|
border-radius: 0.12rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__stats-title-wrap {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.08rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__stats-title {
|
||||||
|
font-size: 0.16rem;
|
||||||
|
line-height: 0.21rem;
|
||||||
|
font-weight: 520;
|
||||||
|
color: $text-dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__stats-date {
|
||||||
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.16rem;
|
||||||
|
font-weight: 330;
|
||||||
|
color: #64748B;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__stats-data {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.20rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__stats-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.04rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__stats-num {
|
||||||
|
font-size: 0.30rem;
|
||||||
|
line-height: 0.40rem;
|
||||||
|
font-weight: 520;
|
||||||
|
color: $accent;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__stats-label {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
font-weight: 330;
|
||||||
|
color: $text-middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__stats-divider {
|
||||||
|
width: 0;
|
||||||
|
height: 0.52rem;
|
||||||
|
border-left: 1px solid #F0F0F0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes home-announcement-spin {
|
||||||
|
to { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
@@ -0,0 +1,287 @@
|
|||||||
|
@use '../variables' as *;
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// 首页-岗位雷达Tab样式
|
||||||
|
// ========================================
|
||||||
|
.home-job-radar {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
// 第一部分容器
|
||||||
|
&__section {
|
||||||
|
width: 12rem;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0.6rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标题区域
|
||||||
|
&__header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 0.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
font-size: 0.36rem;
|
||||||
|
line-height: 0.48rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: $text-dark;
|
||||||
|
margin-bottom: 0.12rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__subtitle {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.2rem;
|
||||||
|
color: $text-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 筛选面板 ====================
|
||||||
|
&__filters {
|
||||||
|
background: $bg-white;
|
||||||
|
border: 1px solid #F0F0F0;
|
||||||
|
box-shadow: 0px 2px 6px rgba(15, 23, 42, 0.025);
|
||||||
|
border-radius: 0.14rem;
|
||||||
|
padding: 0.24rem 0.40rem;
|
||||||
|
margin-bottom: 0.32rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 筛选行
|
||||||
|
&__filter-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 0.16rem;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 筛选标签文字
|
||||||
|
&__filter-label {
|
||||||
|
width: 0.28rem;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
font-weight: 450;
|
||||||
|
color: $text-light;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-right: 0.24rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 筛选chip容器
|
||||||
|
&__filter-chips {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.14rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 筛选chip
|
||||||
|
&__chip {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0.06rem 0.12rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: #F5F8F8;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
font-weight: 330;
|
||||||
|
color: $text-middle;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #E8F7F8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选中态
|
||||||
|
&--active {
|
||||||
|
background: $accent;
|
||||||
|
color: #FFFFFF;
|
||||||
|
font-weight: 520;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $accent-hover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 岗位卡片网格 ====================
|
||||||
|
&__grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 岗位卡片
|
||||||
|
&__card {
|
||||||
|
background: $bg-white;
|
||||||
|
border: 1px solid #F0F0F0;
|
||||||
|
border-radius: 0.08rem;
|
||||||
|
padding: 0.16rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: box-shadow 0.2s, border-color 0.2s;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
height: 1.33rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
|
||||||
|
border-color: #E0E0E0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 卡片上半部分
|
||||||
|
&__card-top {
|
||||||
|
// 无需额外样式
|
||||||
|
}
|
||||||
|
|
||||||
|
// 岗位标题
|
||||||
|
&__card-title {
|
||||||
|
font-size: 0.16rem;
|
||||||
|
line-height: 0.21rem;
|
||||||
|
font-weight: 520;
|
||||||
|
color: $text-dark;
|
||||||
|
margin-bottom: 0.08rem;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标签行
|
||||||
|
&__card-tags {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.08rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单个标签
|
||||||
|
&__card-tag {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0.03rem 0.06rem;
|
||||||
|
background: #F3F4F6;
|
||||||
|
border-radius: 0.04rem;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.16rem;
|
||||||
|
font-weight: 380;
|
||||||
|
color: $text-middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 卡片下半部分
|
||||||
|
&__card-bottom {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 公司信息
|
||||||
|
&__card-company {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.04rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 公司logo
|
||||||
|
&__card-logo {
|
||||||
|
width: 0.24rem;
|
||||||
|
height: 0.24rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 1px solid #F4F4F4;
|
||||||
|
object-fit: cover;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
&--default {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: $bg-white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 公司名称
|
||||||
|
&__card-company-name {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
font-weight: 450;
|
||||||
|
color: $text-dark;
|
||||||
|
max-width: 1.69rem;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 公司类型标签
|
||||||
|
&__card-company-type {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0.03rem 0.06rem;
|
||||||
|
background: #ECFDF3;
|
||||||
|
border-radius: 0.04rem;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.16rem;
|
||||||
|
font-weight: 380;
|
||||||
|
color: #067647;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发布时间
|
||||||
|
&__card-time {
|
||||||
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.16rem;
|
||||||
|
font-weight: 330;
|
||||||
|
color: $text-light;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 加载中 ====================
|
||||||
|
&__loading {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0.4rem 0;
|
||||||
|
gap: 0.08rem;
|
||||||
|
color: $text-light;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__spinner {
|
||||||
|
width: 0.2rem;
|
||||||
|
height: 0.2rem;
|
||||||
|
border: 2px solid #e5e7eb;
|
||||||
|
border-top-color: $accent;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: spin 0.8s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 查看更多按钮 ====================
|
||||||
|
&__more {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 0.32rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__more-btn {
|
||||||
|
padding: 0.10rem 0.40rem;
|
||||||
|
border-radius: 0.08rem;
|
||||||
|
background: $text-dark;
|
||||||
|
color: #FFFFFF;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.2rem;
|
||||||
|
font-weight: 500;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
to { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
@@ -0,0 +1,310 @@
|
|||||||
|
@use '../variables' as *;
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// 首页-求职辅导Tab样式
|
||||||
|
// ========================================
|
||||||
|
.home-mentor {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
// 第一部分容器
|
||||||
|
&__section {
|
||||||
|
width: 12rem;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0.6rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标题区域
|
||||||
|
&__header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 0.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
font-size: 0.36rem;
|
||||||
|
line-height: 0.48rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: $text-dark;
|
||||||
|
margin-bottom: 0.12rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__subtitle {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.2rem;
|
||||||
|
color: $text-middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 行业分类Tab ====================
|
||||||
|
&__tabs {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.08rem;
|
||||||
|
margin-bottom: 0.32rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__tab {
|
||||||
|
padding: 0.08rem 0.20rem;
|
||||||
|
border-radius: 999px;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
font-weight: 400;
|
||||||
|
color: $text-dark;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
white-space: nowrap;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #F0FAFB;
|
||||||
|
color: $accent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选中态
|
||||||
|
&--active {
|
||||||
|
background: $accent;
|
||||||
|
color: #FFFFFF;
|
||||||
|
font-weight: 500;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $accent-hover;
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 导师列表 ====================
|
||||||
|
&__list-wrap {
|
||||||
|
height: 11rem;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__list {
|
||||||
|
// 无需额外样式
|
||||||
|
}
|
||||||
|
|
||||||
|
&__no-more {
|
||||||
|
text-align: center;
|
||||||
|
padding: 0.24rem 0;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
color: $text-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导师卡片
|
||||||
|
&__card {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0.24rem 0.32rem;
|
||||||
|
background: $bg-white;
|
||||||
|
border: 1px solid #F0F0F0;
|
||||||
|
border-radius: 0.12rem;
|
||||||
|
margin-bottom: 0.12rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: box-shadow 0.2s, border-color 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
||||||
|
border-color: #E0E8E8;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 卡片左侧 — 限制最大宽度让右侧话题纵向对齐
|
||||||
|
&__card-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.14rem;
|
||||||
|
flex: 1 1 0;
|
||||||
|
max-width: 50%;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 头像
|
||||||
|
&__avatar-wrap {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__avatar {
|
||||||
|
width: 0.56rem;
|
||||||
|
height: 0.56rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__avatar-placeholder {
|
||||||
|
width: 0.56rem;
|
||||||
|
height: 0.56rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #EDF9FA;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 0.2rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $accent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导师信息
|
||||||
|
&__card-info {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__card-name-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.10rem;
|
||||||
|
margin-bottom: 0.08rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__card-name {
|
||||||
|
font-size: 0.18rem;
|
||||||
|
line-height: 0.24rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $text-dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__card-meta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.04rem;
|
||||||
|
font-size: 0.13rem;
|
||||||
|
line-height: 0.18rem;
|
||||||
|
font-weight: 400;
|
||||||
|
color: $text-middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__card-agency-logo {
|
||||||
|
width: 0.18rem;
|
||||||
|
height: 0.18rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标签列表
|
||||||
|
&__card-labels {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.06rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__card-label {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.02rem 0.08rem;
|
||||||
|
background: #F0FAFB;
|
||||||
|
border-radius: 0.04rem;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.16rem;
|
||||||
|
font-weight: 330;
|
||||||
|
color: $accent;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 卡片右侧 — flex:1 让话题区自适应剩余空间
|
||||||
|
&__card-right {
|
||||||
|
flex: 1 1 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.12rem;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 话题列表 — 占据右侧剩余空间,自动截断
|
||||||
|
&__card-topics {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__card-topic {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: $text-middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查看详情按钮
|
||||||
|
&__detail-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.04rem;
|
||||||
|
padding: 0;
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
font-weight: 450;
|
||||||
|
color: $accent;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
transition: color 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $accent-hover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 加载中 ====================
|
||||||
|
&__loading {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0.4rem 0;
|
||||||
|
gap: 0.08rem;
|
||||||
|
color: $text-light;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__spinner {
|
||||||
|
width: 0.2rem;
|
||||||
|
height: 0.2rem;
|
||||||
|
border: 2px solid #e5e7eb;
|
||||||
|
border-top-color: $accent;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: home-mentor-spin 0.8s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 空列表
|
||||||
|
&__empty {
|
||||||
|
text-align: center;
|
||||||
|
padding: 0.4rem 0;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
color: $text-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 查看更多按钮 ====================
|
||||||
|
&__more {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 0.32rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__more-btn {
|
||||||
|
padding: 0.10rem 0.40rem;
|
||||||
|
border-radius: 0.08rem;
|
||||||
|
background: $text-dark;
|
||||||
|
color: #FFFFFF;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.2rem;
|
||||||
|
font-weight: 500;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes home-mentor-spin {
|
||||||
|
to { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
@@ -9,10 +9,8 @@
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
padding: 0.2rem 0.12rem;
|
padding: 0.2rem 0.12rem;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
// 窄版模式(window.innerWidth < 1440)
|
// 窄版模式(window.innerWidth < 1440)
|
||||||
&--narrow {
|
&--narrow {
|
||||||
|
|||||||
@@ -49,6 +49,10 @@
|
|||||||
@use './components/mentor-aside-panel.scss';
|
@use './components/mentor-aside-panel.scss';
|
||||||
@use './components/agent-browser-install-guide.scss';
|
@use './components/agent-browser-install-guide.scss';
|
||||||
@use './components/login-dialog.scss';
|
@use './components/login-dialog.scss';
|
||||||
|
@use './components/home-job-radar.scss';
|
||||||
|
@use './components/home-announcement.scss';
|
||||||
|
@use './components/home-mentor.scss';
|
||||||
|
@use './components/home-about.scss';
|
||||||
|
|
||||||
// 全局样式(优先级最高)
|
// 全局样式(优先级最高)
|
||||||
@use './auto.scss';
|
@use './auto.scss';
|
||||||
|
|||||||
@@ -6,9 +6,9 @@
|
|||||||
min-height: var(--app-height, 100vh);
|
min-height: var(--app-height, 100vh);
|
||||||
background: $bg-main;
|
background: $bg-main;
|
||||||
font-size: 0.14rem;
|
font-size: 0.14rem;
|
||||||
|
min-width: 12.8rem;
|
||||||
// 主内容区域(左侧导航栏右边的部分)
|
// 主内容区域(左侧导航栏右边的部分)
|
||||||
&__content {
|
&__content {
|
||||||
margin-left: var(--nav-width, 2.2rem);
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
height: var(--app-height, 100vh);
|
height: var(--app-height, 100vh);
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
// 主内容区(与 JobDetail 一致,通过 margin-left 避开侧边栏)
|
// 主内容区(与 JobDetail 一致,通过 margin-left 避开侧边栏)
|
||||||
&__content {
|
&__content {
|
||||||
margin-left: var(--nav-width, 2.2rem);
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: var(--app-height, 100vh);
|
height: var(--app-height, 100vh);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
@@ -473,6 +472,7 @@
|
|||||||
color: $text-middle;
|
color: $text-middle;
|
||||||
line-height: 0.16rem;
|
line-height: 0.16rem;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 校招推荐列表项 ====================
|
// ==================== 校招推荐列表项 ====================
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
.announcement-page {
|
.announcement-page {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
min-width: 12.8rem;
|
||||||
|
|
||||||
&__content {
|
&__content {
|
||||||
margin-left: var(--nav-width, 2.2rem);
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding-bottom: 0.18rem;
|
padding-bottom: 0.18rem;
|
||||||
height: var(--app-height, 100vh);
|
height: var(--app-height, 100vh);
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
// 页面标题
|
// 页面标题
|
||||||
&__title {
|
&__title {
|
||||||
font-size: 0.24rem;
|
font-size: 0.18rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: $text-dark;
|
color: $text-dark;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__subtitle {
|
&__subtitle {
|
||||||
font-size: 0.13rem;
|
font-size: 0.14rem;
|
||||||
color: $text-light;
|
color: $text-light;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,13 +9,14 @@
|
|||||||
.home-page {
|
.home-page {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
background: #fff;
|
background: radial-gradient(63.8% 19.39% at 60.25% 0%, #CEF0F2 0%, #FFFFFF 100%) no-repeat top / 100% 5rem, #fff;
|
||||||
color: #111;
|
color: #111;
|
||||||
font-family: system-ui, -apple-system, sans-serif;
|
font-family: system-ui, -apple-system, sans-serif;
|
||||||
// 全局基础行高重置,防止 1rem=100px 导致子元素继承异常行高
|
// 全局基础行高重置,防止 1rem=100px 导致子元素继承异常行高
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
font-size: 0.14rem;
|
font-size: 0.14rem;
|
||||||
|
|
||||||
|
|
||||||
// ==================== 顶部导航栏 ====================
|
// ==================== 顶部导航栏 ====================
|
||||||
.home-nav {
|
.home-nav {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
@@ -33,6 +34,8 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
background: transparent;
|
||||||
|
transition: background 0.3s, box-shadow 0.3s;
|
||||||
|
|
||||||
&--scorlled {
|
&--scorlled {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@@ -67,6 +70,47 @@
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 中间Tab导航区域
|
||||||
|
&__tabs {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.40rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单个Tab项
|
||||||
|
&__tab {
|
||||||
|
position: relative;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.2rem;
|
||||||
|
font-weight: 400;
|
||||||
|
color: $text-dark;
|
||||||
|
cursor: pointer;
|
||||||
|
padding-bottom: 0.06rem;
|
||||||
|
transition: font-weight 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $accent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选中态:加粗 + 底部下划线
|
||||||
|
&--active {
|
||||||
|
font-weight: 600;
|
||||||
|
color: $text-dark;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 0.2rem;
|
||||||
|
height: 0.02rem;
|
||||||
|
background: $accent;
|
||||||
|
border-radius: 0.01rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 导航右侧 CTA 按钮
|
// 导航右侧 CTA 按钮
|
||||||
&__btn {
|
&__btn {
|
||||||
padding: 0.1rem 0.32rem;
|
padding: 0.1rem 0.32rem;
|
||||||
@@ -85,11 +129,9 @@
|
|||||||
|
|
||||||
// ==================== Hero 主视觉区 ====================
|
// ==================== Hero 主视觉区 ====================
|
||||||
.home-hero {
|
.home-hero {
|
||||||
background: #fff;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
font-size: 0.14rem;
|
font-size: 0.14rem;
|
||||||
background: radial-gradient(34.95% 29.57% at 60.26041666666667% 0%, rgba(206, 240, 242, 1) 0%, rgba(255, 255, 255, 1) 100%);
|
|
||||||
// 背景色块 — 顶部
|
// 背景色块 — 顶部
|
||||||
&__orb {
|
&__orb {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -107,7 +149,7 @@
|
|||||||
height: 6rem;
|
height: 6rem;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
filter: blur(0.5rem);
|
filter: blur(0.5rem);
|
||||||
background: rgba(82, 202, 209, 0.24);
|
//background: rgba(82, 202, 209, 0.24);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
// ==================== 岗位详情页 ====================
|
// ==================== 岗位详情页 ====================
|
||||||
.job-detail {
|
.job-detail {
|
||||||
|
min-width: 12.8rem;
|
||||||
|
|
||||||
&__content {
|
&__content {
|
||||||
margin-left: var(--nav-width, 2.2rem);
|
|
||||||
margin-right: var(--chat-width, 3.6rem);
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: var(--app-height, 100vh);
|
height: var(--app-height, 100vh);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|||||||
@@ -4,10 +4,9 @@
|
|||||||
|
|
||||||
.jobs-page {
|
.jobs-page {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
min-width: 12.8rem;
|
||||||
|
|
||||||
&__content {
|
&__content {
|
||||||
margin-left: var(--nav-width, 2.2rem);
|
|
||||||
margin-right: var(--chat-width, 3.6rem);
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding-bottom: 0.18rem;
|
padding-bottom: 0.18rem;
|
||||||
height: var(--app-height, 100vh);
|
height: var(--app-height, 100vh);
|
||||||
@@ -15,6 +14,8 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background: $bg-main;
|
background: $bg-main;
|
||||||
font-size: 0.14rem;
|
font-size: 0.14rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 页面标题
|
// 页面标题
|
||||||
@@ -601,11 +602,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 职位列表(用 calc 减去上方头部+筛选栏大致高度,保证列表独立滚动)
|
// 职位列表(flex:1 自动占满剩余空间,保证列表独立滚动)
|
||||||
&__list {
|
&__list {
|
||||||
gap: 0;
|
gap: 0;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
height: calc(var(--app-height, 100vh) - 1.8rem);
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
padding-bottom: 0.2rem;
|
padding-bottom: 0.2rem;
|
||||||
margin: 0 0.24rem;
|
margin: 0 0.24rem;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@use '../variables' as *;
|
@use '../variables' as *;
|
||||||
/* 登录页面 — 左右分栏全屏布局 */
|
/* 登录页面 — 左右分栏全屏布局 */
|
||||||
.login-view {
|
.login-view {
|
||||||
|
min-width: 12.8rem;
|
||||||
font-size: 0.14rem;
|
font-size: 0.14rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
// ==================== 导师详情页样式 ====================
|
// ==================== 导师详情页样式 ====================
|
||||||
|
|
||||||
.mentor-detail {
|
.mentor-detail {
|
||||||
|
min-width: 12.8rem;
|
||||||
font-size: 0.14rem;
|
font-size: 0.14rem;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: var(--app-height, 100vh);
|
height: var(--app-height, 100vh);
|
||||||
@@ -14,7 +15,6 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin-left: var(--nav-width, 2.2rem);
|
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
// ==================== Mentor 导师页面样式 ====================
|
// ==================== Mentor 导师页面样式 ====================
|
||||||
|
|
||||||
.mentor-page {
|
.mentor-page {
|
||||||
|
min-width: 12.8rem;
|
||||||
font-size: 0.14rem;
|
font-size: 0.14rem;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: var(--app-height, 100vh);
|
height: var(--app-height, 100vh);
|
||||||
@@ -14,7 +15,6 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin-left: var(--nav-width, 2.2rem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 左侧主内容区
|
// 左侧主内容区
|
||||||
|
|||||||
@@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
// ==================== 个人资料页 ====================
|
// ==================== 个人资料页 ====================
|
||||||
.profile-page {
|
.profile-page {
|
||||||
|
min-width: 12.8rem;
|
||||||
|
|
||||||
&__content {
|
&__content {
|
||||||
margin-left: var(--nav-width, 2.2rem);
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding-bottom: 0.12rem;
|
padding-bottom: 0.12rem;
|
||||||
height: var(--app-height, 100vh);
|
height: var(--app-height, 100vh);
|
||||||
|
|||||||
@@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
// ==================== 简历详情页 ====================
|
// ==================== 简历详情页 ====================
|
||||||
.resume-detail {
|
.resume-detail {
|
||||||
|
min-width: 12.8rem;
|
||||||
|
|
||||||
&__content {
|
&__content {
|
||||||
margin-left: var(--nav-width, 2.2rem);
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding-bottom: 0.24rem;
|
padding-bottom: 0.24rem;
|
||||||
height: var(--app-height, 100vh);
|
height: var(--app-height, 100vh);
|
||||||
|
|||||||
+254
-209
@@ -1,9 +1,10 @@
|
|||||||
@use '../variables' as *;
|
@use '../variables' as *;
|
||||||
|
|
||||||
// ==================== 简历列表页 ====================
|
// ==================== 简历列表页(卡片视图) ====================
|
||||||
.resume-page {
|
.resume-page {
|
||||||
|
min-width: 12.8rem;
|
||||||
|
|
||||||
&__content {
|
&__content {
|
||||||
margin-left: var(--nav-width, 2.2rem);
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: var(--app-height, 100vh);
|
height: var(--app-height, 100vh);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
@@ -29,246 +30,278 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__upload-btn {
|
// 卡片网格容器
|
||||||
|
&__card-grid {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 0.24rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
flex-wrap: wrap;
|
||||||
gap: 0.06rem;
|
align-content: flex-start;
|
||||||
background: $btn-dark;
|
gap: 0.24rem;
|
||||||
color: $bg-white;
|
}
|
||||||
border: none;
|
|
||||||
border-radius: 0.08rem;
|
// ==================== 简历卡片 ====================
|
||||||
padding: 0.08rem 0.14rem;
|
&__card {
|
||||||
font-size: 0.13rem;
|
width: 2.10rem;
|
||||||
font-weight: 500;
|
height: 2.97rem;
|
||||||
|
border-radius: 0.12rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background 0.2s;
|
transition: transform 0.3s ease, filter 0.3s ease;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: $btn-dark-hover;
|
transform: translateY(-0.08rem);
|
||||||
|
filter: drop-shadow(0px 4px 12px rgba(0, 0, 0, 0.06));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从个人资料创建按钮(描边样式)
|
// hover嵌套选择器
|
||||||
&__create-btn {
|
&__card:hover &__card-more-btn {
|
||||||
display: flex;
|
opacity: 1;
|
||||||
align-items: center;
|
}
|
||||||
gap: 0.06rem;
|
&__card:hover &__card-edit-time {
|
||||||
|
opacity: 1;
|
||||||
|
height: 0.16rem;
|
||||||
|
margin-top: 0.04rem;
|
||||||
|
}
|
||||||
|
// hover时info向上扩展(absolute定位,卡片总高度不变)
|
||||||
|
&__card:hover &__card-info {
|
||||||
|
height: 0.86rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 卡片预览图区域
|
||||||
|
&__card-preview {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 0.12rem;
|
||||||
background: $bg-white;
|
background: $bg-white;
|
||||||
color: $accent;
|
overflow: hidden;
|
||||||
border: 1px solid $accent;
|
position: relative;
|
||||||
border-radius: 0.08rem;
|
|
||||||
padding: 0.08rem 0.14rem;
|
img {
|
||||||
font-size: 0.13rem;
|
width: 100%;
|
||||||
font-weight: 500;
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 0.12rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 默认标记(左上角)
|
||||||
|
&__card-default-tag {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
background: $accent;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
font-weight: 520;
|
||||||
|
padding: 0.02rem 0.08rem;
|
||||||
|
border-radius: 0.12rem 0 0.12rem 0;
|
||||||
|
z-index: 2;
|
||||||
|
line-height: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更多按钮(右上角圆形)
|
||||||
|
&__card-more-btn {
|
||||||
|
position: absolute;
|
||||||
|
top: 0.12rem;
|
||||||
|
right: 0.16rem;
|
||||||
|
width: 0.32rem;
|
||||||
|
height: 0.32rem;
|
||||||
|
background: $bg-white;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.1);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s;
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
z-index: 3;
|
||||||
|
border: none;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: rgba($accent, 0.06);
|
background: #f5f5f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:disabled {
|
svg {
|
||||||
opacity: 0.6;
|
width: 0.18rem;
|
||||||
cursor: not-allowed;
|
height: 0.18rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__upload-icon {
|
// 更多菜单弹出层
|
||||||
|
&__card-menu {
|
||||||
|
position: absolute;
|
||||||
|
top: 0.44rem;
|
||||||
|
right: 0.08rem;
|
||||||
|
width: 1.04rem;
|
||||||
|
background: $bg-white;
|
||||||
|
box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.1);
|
||||||
|
border-radius: 0.08rem;
|
||||||
|
padding: 0.06rem 0;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__card-menu-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.06rem 0.08rem;
|
||||||
|
gap: 0.04rem;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
font-weight: 380;
|
||||||
|
color: $text-middle;
|
||||||
|
transition: background 0.15s;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #f9f9f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设为默认特殊样式
|
||||||
|
&--default {
|
||||||
|
background: #EDF9FA;
|
||||||
|
border-radius: 0.04rem;
|
||||||
|
margin: 0 0.06rem;
|
||||||
|
padding: 0.06rem 0.08rem;
|
||||||
|
color: $accent;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #ddf3f5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除按钮特殊样式
|
||||||
|
&--delete {
|
||||||
|
svg {
|
||||||
|
color: $text-middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 0.16rem;
|
||||||
|
height: 0.16rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 卡片底部信息区域(absolute定位在卡片底部,hover时向上扩展,卡片总高度不变)
|
||||||
|
&__card-info {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background: $bg-white;
|
||||||
|
box-shadow: 0px -2px 12px rgba(0, 0, 0, 0.1);
|
||||||
|
border-radius: 0 0 0.12rem 0.12rem;
|
||||||
|
padding: 0.12rem;
|
||||||
|
height: 0.66rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
transition: height 0.3s ease;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 卡片信息头部(名称 + 编辑按钮)
|
||||||
|
&__card-info-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 简历名称
|
||||||
|
&__card-name {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
font-weight: 450;
|
||||||
|
color: #000;
|
||||||
|
max-width: 1.50rem;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 编辑图标按钮
|
||||||
|
&__card-edit-btn {
|
||||||
|
width: 0.20rem;
|
||||||
|
height: 0.20rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
width: 0.14rem;
|
width: 0.14rem;
|
||||||
height: 0.14rem;
|
height: 0.14rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 表格容器(超出时可滚动)
|
|
||||||
&__table-wrap {
|
|
||||||
background: $bg-white;
|
|
||||||
border-radius: 0.12rem;
|
|
||||||
margin: 0.18rem 0.17rem;
|
|
||||||
overflow-y: auto;
|
|
||||||
flex: 0 1 auto;
|
|
||||||
min-height: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__table {
|
// 目标岗位
|
||||||
width: 100%;
|
&__card-target {
|
||||||
border-collapse: collapse;
|
font-size: 0.14rem;
|
||||||
table-layout: fixed;
|
font-weight: 330;
|
||||||
}
|
|
||||||
|
|
||||||
&__th {
|
|
||||||
text-align: left;
|
|
||||||
padding: 0.14rem 0.2rem;
|
|
||||||
font-size: 0.12rem;
|
|
||||||
font-weight: 600;
|
|
||||||
color: $text-dark;
|
|
||||||
border-bottom: 1px solid $border-color;
|
|
||||||
white-space: nowrap;
|
|
||||||
width: 15%;
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
background: $bg-white;
|
|
||||||
z-index: 1;
|
|
||||||
|
|
||||||
&--action {
|
|
||||||
width: 25%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__row {
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background 0.15s;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: $theme-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:not(:last-child) {
|
|
||||||
border-bottom: 1px solid $border-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__td {
|
|
||||||
padding: 0.16rem 0.2rem;
|
|
||||||
font-size: 0.13rem;
|
|
||||||
color: $text-dark;
|
|
||||||
vertical-align: middle;
|
|
||||||
|
|
||||||
&--action {
|
|
||||||
position: relative;
|
|
||||||
text-align: center;
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity 0.15s;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--ellipsis {
|
|
||||||
max-width: 3.6rem;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__row:hover &__td--action {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 简历名称单元格
|
|
||||||
&__name-cell {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.06rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__avatar {
|
|
||||||
width: 0.3rem;
|
|
||||||
height: 0.3rem;
|
|
||||||
border-radius: 50%;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
color: $bg-white;
|
|
||||||
font-size: 0.13rem;
|
|
||||||
font-weight: 600;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__name {
|
|
||||||
font-weight: 500;
|
|
||||||
max-width: 3.6rem;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__default-tag {
|
|
||||||
font-size: 0.09rem;
|
|
||||||
color: $accent;
|
|
||||||
background: #EDF9FA;
|
|
||||||
border-radius: 0.04rem;
|
|
||||||
padding: 0.014rem 0.08rem;
|
|
||||||
padding-bottom: 0.02rem;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 编辑名称岗位图标按钮
|
|
||||||
&__edit-btn {
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
color: $text-dark;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 0.02rem;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
transition: opacity 0.2s;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__edit-icon {
|
|
||||||
font-size: 0.13rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 操作按钮容器
|
|
||||||
&__actions {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.16rem;
|
|
||||||
justify-content: flex-end;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 行内操作按钮
|
|
||||||
&__action-btn {
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
font-size: 0.12rem;
|
|
||||||
color: $text-middle;
|
color: $text-middle;
|
||||||
cursor: pointer;
|
line-height: 0.19rem;
|
||||||
padding: 0.04rem 0.08rem;
|
margin-top: 0.04rem;
|
||||||
border-radius: 0.04rem;
|
max-width: 1.80rem;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
transition: all 0.15s;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: $text-dark;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除按钮红色
|
// 最后编辑时间(hover 时显示)
|
||||||
&--delete {
|
&__card-edit-time {
|
||||||
color: #FD6464;
|
font-size: 0.12rem;
|
||||||
|
font-weight: 330;
|
||||||
&:hover {
|
|
||||||
color: #e04545;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更多按钮(已移除,保留兼容)
|
|
||||||
&__more-btn {
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
color: $text-light;
|
color: $text-light;
|
||||||
cursor: pointer;
|
line-height: 0.16rem;
|
||||||
padding: 0.04rem;
|
opacity: 0;
|
||||||
border-radius: 0.04rem;
|
height: 0;
|
||||||
|
margin-top: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: opacity 0.3s ease, height 0.3s ease, margin-top 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 新建卡片 ====================
|
||||||
|
&__card-new {
|
||||||
|
width: 2.10rem;
|
||||||
|
height: 2.97rem;
|
||||||
|
border-radius: 0.12rem;
|
||||||
|
background: $bg-white;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
transition: all 0.2s;
|
cursor: pointer;
|
||||||
|
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||||
|
gap: 0.08rem;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: $text-dark;
|
transform: translateY(-0.08rem);
|
||||||
background: $bg-main;
|
box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.06);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__more-svg {
|
svg {
|
||||||
width: 0.16rem;
|
width: 0.32rem;
|
||||||
height: 0.16rem;
|
height: 0.32rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: 0.18rem;
|
||||||
|
font-weight: 520;
|
||||||
|
color: $accent;
|
||||||
|
line-height: 0.24rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 空状态提示
|
// 空状态提示
|
||||||
@@ -278,6 +311,18 @@
|
|||||||
color: $text-light;
|
color: $text-light;
|
||||||
font-size: 0.14rem;
|
font-size: 0.14rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 加载中
|
||||||
|
&__loading-box {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.2rem 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.08rem;
|
||||||
|
color: $text-light;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 上传简历加载提示 ====================
|
// ==================== 上传简历加载提示 ====================
|
||||||
|
|||||||
@@ -0,0 +1,250 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 关于我们Tab内容 -->
|
||||||
|
<div class="home-about">
|
||||||
|
|
||||||
|
<!-- Hero 区域 -->
|
||||||
|
<section class="home-about__hero">
|
||||||
|
<div class="home-about__hero-inner">
|
||||||
|
<p class="home-about__hero-kicker">投简历神器 · 一键自动简申 · 求职助力提升</p>
|
||||||
|
<h1 class="home-about__hero-title">让每一次求职选择<br/>都更有方向</h1>
|
||||||
|
<p class="home-about__hero-subtitle">以AI提效效率,以专业经验支持判断,帮助年轻人看见机会、理解选择,更有准备地走向下一步</p>
|
||||||
|
<button class="home-about__hero-btn" @click="router.push('/jobs')">了解Offer派</button>
|
||||||
|
</div>
|
||||||
|
<!-- 底部居中渐变色块 -->
|
||||||
|
<div class="home-about__hero-orb"></div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- 产品介绍区域 -->
|
||||||
|
<section class="home-about__intro">
|
||||||
|
<div class="home-about__intro-inner">
|
||||||
|
<!-- 左侧产品图片占位 -->
|
||||||
|
<div class="home-about__intro-img">
|
||||||
|
<div class="home-about__intro-img-placeholder">
|
||||||
|
<img src="@/assets/images/home/home-about-01.png" alt="产品介绍" style="width: 100%; height: 100%; object-fit: cover; border-radius: 0.22rem;" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 右侧文字说明 -->
|
||||||
|
<div class="home-about__intro-text">
|
||||||
|
<span class="home-about__kicker">产品介绍</span>
|
||||||
|
<h2 class="home-about__section-title">用AI,让求职更清晰、更高效</h2>
|
||||||
|
<p class="home-about__intro-desc">
|
||||||
|
求职的问题,远远不只是不知道去哪里看招聘信息、该投简历,方向模糊、岗位要求说不清用什么,以及充斥着大量无用信息。
|
||||||
|
</p>
|
||||||
|
<p class="home-about__intro-desc">
|
||||||
|
Offer派(Offerpai)是志立要辅导下面向大学生的一站式就业辅导平台,帮助毕业生搜索与投递简历,找到适合自己的工作;采用先进AI技术,双科汇集海量岗位信息/平台上下配合让大学生成功投递简历。基本覆盖日均200+知名企业在线。等你的求职好运气。
|
||||||
|
</p>
|
||||||
|
<p class="home-about__intro-desc">
|
||||||
|
我们不急着做赚用户的决定,也不求速的回到的求职轨道。我们更愿意将技术成为少些信息差和搜索理操作,让每个人更关注对他们真的重要的事:了解岗位、认真复盘适合自己,以及加强真正重复投递对接。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- 产品亮点区域 -->
|
||||||
|
<section class="home-about__features">
|
||||||
|
<div class="home-about__features-header">
|
||||||
|
<span class="home-about__kicker">产品亮点</span>
|
||||||
|
<h2 class="home-about__section-title">让求职的每一步,都更简单一点</h2>
|
||||||
|
<p class="home-about__section-subtitle">找岗位搜索、自动简申、导师经验和AI理想放在一起,让求职不再碎片化</p>
|
||||||
|
</div>
|
||||||
|
<!-- 5个功能卡片 -->
|
||||||
|
<div class="home-about__features-grid">
|
||||||
|
<div class="home-about__feature-card" v-for="(feat, idx) in featureCards" :key="idx">
|
||||||
|
<div class="home-about__feature-icon">
|
||||||
|
<component :is="feat.icon" />
|
||||||
|
</div>
|
||||||
|
<h3 class="home-about__feature-title">{{ feat.title }}</h3>
|
||||||
|
<p class="home-about__feature-desc">{{ feat.desc }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- 为什么创立区域 -->
|
||||||
|
<section class="home-about__why">
|
||||||
|
<div class="home-about__why-header">
|
||||||
|
<span class="home-about__kicker">我们的初心</span>
|
||||||
|
<h2 class="home-about__section-title">为什么创立Offer派</h2>
|
||||||
|
<p class="home-about__section-subtitle">我们希望,让专业的求职服务支持离年轻人更近一点</p>
|
||||||
|
</div>
|
||||||
|
<!-- 两个内容块:左文右图 / 左图右文 -->
|
||||||
|
<div class="home-about__why-content">
|
||||||
|
<div class="home-about__why-block">
|
||||||
|
<div class="home-about__why-text">
|
||||||
|
<h3>我们希望,让好的求职服务离年轻人更近一点</h3>
|
||||||
|
<p>
|
||||||
|
团队最初在2016年成立以来,一直在帮大学生,但提供全方位服务的社会人的接入的门槛太高了。我选择什么方向?哪家特的合适推荐给我?为了轻而且自己应付更简练的记录,按录入升级面配,不同人开不清情形,有那么多的新形式把大家,搜索找一种你负面之间也能得到了。就入到城打发到实际去请投资。让到了意思每一份好资源。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="home-about__why-img">
|
||||||
|
<img src="@/assets/images/home/home-about-02.png" alt="为什么选择Offer派" style="width: 100%; height: 100%; object-fit: cover; border-radius: 0.16rem;" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="home-about__why-block home-about__why-block--reverse">
|
||||||
|
<div class="home-about__why-img">
|
||||||
|
<img src="@/assets/images/home/home-about-03.png" alt="为什么选择Offer派" style="width: 100%; height: 100%; object-fit: cover; border-radius: 0.16rem;" />
|
||||||
|
</div>
|
||||||
|
<div class="home-about__why-text">
|
||||||
|
<h3>AI 的出现,让这件事情变得真正可行</h3>
|
||||||
|
<p>
|
||||||
|
当应对AI的求职者,让AI变元素,更多利把关求职先忙完处然后大部分的力。于是做好们开了Offer派,我们让数据帮你搜匹配信息便签,目的引用布策重要做一些好交流。但是做到面,确做了另外所有内外对到不人。我们不想当自不是经验的出错的"密集完成",而是一个有着力有意思的管用同步。去看有未来方向对结。
|
||||||
|
</p>
|
||||||
|
<p class="home-about__why-sign">——Offer派团队</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- 万千毕业生的信赖之选 -->
|
||||||
|
<section class="home-about__trust">
|
||||||
|
<div class="home-about__trust-header">
|
||||||
|
<h2 class="home-about__section-title">源于见识星球,也走向更多年轻人</h2>
|
||||||
|
<p class="home-about__section-subtitle">真实求职反馈,见证每一次从迷茫到积上岸</p>
|
||||||
|
</div>
|
||||||
|
<!-- 深色卡片 -->
|
||||||
|
<div class="home-about__trust-dark-card">
|
||||||
|
<div class="home-about__trust-dark-text">
|
||||||
|
<p>Offer派是见识星球旗下的AI求职产品。</p>
|
||||||
|
<p>
|
||||||
|
见识星球创始团队专注于大学生年轻人校招生涯的多年来,求职辅导,名企求职与职业成长,通过自身招聘和辅助加盟者。为用户提供更独到的服务,专业的求职就业结合到每次经验与能力。帮企业用适配员工人选适配。让很多在先进面上入大时代。初步分析前期做到点求职规时请改变为真正知道来化,更好我们是职在服务不做到打的到角色。
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
之后我们渐渐不间断继续是指据角色。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="home-about__trust-dark-logo"></div>
|
||||||
|
</div>
|
||||||
|
<!-- 两个白色卡片 -->
|
||||||
|
<div class="home-about__trust-cards">
|
||||||
|
<div class="home-about__trust-card">
|
||||||
|
<h4>Offer 派</h4>
|
||||||
|
<p>兼有制度云层级后、一键自动简申、在立即用持行项服的技术打下一样,汇聚汇集到全面就业,合力、社作育的,也指进一步到更精准到更新更定收到先。更指连选到关Offer。</p>
|
||||||
|
</div>
|
||||||
|
<div class="home-about__trust-card">
|
||||||
|
<h4>见识星球</h4>
|
||||||
|
<p>专注于大学生专业实力指每的一个校园的到导知网的,新打5000+名企公司到得到,北大学学专的将步的改之后全入到体入到未来打的到期配到面。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 底部总结 -->
|
||||||
|
<p class="home-about__trust-summary">AI提升效率,真人提供判断。我们共同陪伴年轻人从发现机会,走到理解机会、准备机会和抓住机会。</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- 价值观区域 -->
|
||||||
|
<section class="home-about__values">
|
||||||
|
<div class="home-about__values-header">
|
||||||
|
<h2 class="home-about__section-title">每个年轻人的选择,都值得被认真对待</h2>
|
||||||
|
<p class="home-about__section-subtitle">我们用技术减少信息差距,也用真实经验达,客观心界和长期视角,帮助年轻人做出更适合自己的决定</p>
|
||||||
|
</div>
|
||||||
|
<!-- 4个价值观卡片 -->
|
||||||
|
<div class="home-about__values-grid">
|
||||||
|
<div class="home-about__value-card" v-for="(val, idx) in valueCards" :key="idx">
|
||||||
|
<div class="home-about__value-icon">
|
||||||
|
<component :is="val.icon" />
|
||||||
|
</div>
|
||||||
|
<h3 class="home-about__value-title">{{ val.title }}</h3>
|
||||||
|
<p class="home-about__value-desc">{{ val.desc }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- 联系我们区域 -->
|
||||||
|
<section class="home-about__contact">
|
||||||
|
<div class="home-about__contact-header">
|
||||||
|
<span class="home-about__kicker">期待与你一起,创建更多可能</span>
|
||||||
|
<h2 class="home-about__section-title">联系我们</h2>
|
||||||
|
<p class="home-about__section-subtitle">无论是产品建议、岗位信息纠错,还是商务合作与导师入驻,欢迎与我们联系</p>
|
||||||
|
</div>
|
||||||
|
<!-- 3个联系方式卡片 -->
|
||||||
|
<div class="home-about__contact-grid">
|
||||||
|
<div class="home-about__contact-card" v-for="(c, idx) in contactCards" :key="idx">
|
||||||
|
<div class="home-about__contact-icon">
|
||||||
|
<component :is="c.icon" />
|
||||||
|
</div>
|
||||||
|
<div class="home-about__contact-info">
|
||||||
|
<h4>{{ c.title }}</h4>
|
||||||
|
<p>{{ c.desc }}</p>
|
||||||
|
<a class="home-about__contact-link" :href="c.link" target="_blank">{{ c.linkText }} →</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- CTA区域 -->
|
||||||
|
<section class="home-cta">
|
||||||
|
<div class="home-cta__inner">
|
||||||
|
<h2>让Offer派带你找到<br/>人生第一份好工作</h2>
|
||||||
|
<button class="home-cta__btn" @click="router.push('/jobs')">免费体验</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { h } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
// ==================== 功能卡片数据 ====================
|
||||||
|
|
||||||
|
/** 火箭图标 */
|
||||||
|
const IconRocket = { render: () => h('svg', { width: '32', height: '32', viewBox: '0 0 32 32', fill: 'none' }, [h('path', { d: 'M8 24C8 24 9.5 22 12 22C14.5 22 16 24 16 24', stroke: '#52CAD1', 'stroke-width': '2', 'stroke-linecap': 'round' }), h('path', { d: 'M16 4C16 4 26 8 26 18C26 24 22 28 16 28C10 28 6 24 6 18C6 8 16 4 16 4Z', stroke: '#52CAD1', 'stroke-width': '2', fill: 'none' })]) }
|
||||||
|
|
||||||
|
/** 手指点击图标 */
|
||||||
|
const IconClick = { render: () => h('svg', { width: '32', height: '32', viewBox: '0 0 32 32', fill: 'none' }, [h('path', { d: 'M16 6V18M16 18L20 22M16 18L12 22M10 12C7 12 6 14 6 16C6 22 10 26 16 26C22 26 26 22 26 16C26 14 25 12 22 12', stroke: '#52CAD1', 'stroke-width': '2', 'stroke-linecap': 'round', 'stroke-linejoin': 'round' })]) }
|
||||||
|
|
||||||
|
/** 黑板教师图标 */
|
||||||
|
const IconTeacher = { render: () => h('svg', { width: '32', height: '32', viewBox: '0 0 32 32', fill: 'none' }, [h('rect', { x: '4', y: '6', width: '24', height: '16', rx: '2', stroke: '#52CAD1', 'stroke-width': '2', fill: 'none' }), h('path', { d: 'M12 26H20M16 22V26', stroke: '#52CAD1', 'stroke-width': '2', 'stroke-linecap': 'round' })]) }
|
||||||
|
|
||||||
|
/** 纸飞机图标 */
|
||||||
|
const IconSend = { render: () => h('svg', { width: '32', height: '32', viewBox: '0 0 32 32', fill: 'none' }, [h('path', { d: 'M6 16L26 6L20 26L16 18L6 16Z', stroke: '#52CAD1', 'stroke-width': '2', 'stroke-linejoin': 'round', fill: 'none' }), h('path', { d: 'M16 18L26 6', stroke: '#52CAD1', 'stroke-width': '2' })]) }
|
||||||
|
|
||||||
|
/** AI图标 */
|
||||||
|
const IconAI = { render: () => h('svg', { width: '32', height: '32', viewBox: '0 0 32 32', fill: 'none' }, [h('rect', { x: '6', y: '8', width: '20', height: '16', rx: '4', stroke: '#52CAD1', 'stroke-width': '2', fill: 'none' }), h('text', { x: '16', y: '20', 'text-anchor': 'middle', fill: '#52CAD1', 'font-size': '10', 'font-weight': '600' }, 'AI')]) }
|
||||||
|
|
||||||
|
/** 功能卡片列表 */
|
||||||
|
const featureCards = [
|
||||||
|
{ icon: IconRocket, title: '投简历神器', desc: '聚合数十个主流招聘网站的大学生校招信息,包含岗位分析、行业解读、精准投递帮助推荐求职。一键批量投递配合提高效率。' },
|
||||||
|
{ icon: IconClick, title: '一键自动简申', desc: '基本以自动化来填简历投递,自动获取表单,跟你配合简申计划进行1-2步。' },
|
||||||
|
{ icon: IconTeacher, title: '名企老师VI辅导', desc: 'Offer派定期邀请企业在职的一线人员,从他们自身去分享。业内包括做,关注搜索、指的的到实际Offer!' },
|
||||||
|
{ icon: IconSend, title: '内推发抖无限资', desc: '结合真实的导师在线直聊、资料指助获的从专业知识把关。' },
|
||||||
|
{ icon: IconAI, title: '全方面AI求职助手', desc: '接入当前最强AI大模型GPT-4o,智能自动对话的全方位匹配的面完整的更的线的全面的NOVA在最有最终的但能这的内的的。' },
|
||||||
|
]
|
||||||
|
|
||||||
|
// ==================== 价值观卡片数据 ====================
|
||||||
|
|
||||||
|
/** 雷达图标 */
|
||||||
|
const IconRadar = { render: () => h('svg', { width: '48', height: '48', viewBox: '0 0 48 48', fill: 'none' }, [h('circle', { cx: '24', cy: '24', r: '18', stroke: '#111', 'stroke-width': '3', fill: 'none' }), h('circle', { cx: '24', cy: '24', r: '10', stroke: '#111', 'stroke-width': '3', fill: 'none' }), h('circle', { cx: '24', cy: '24', r: '3', fill: '#111' }), h('path', { d: 'M24 6V24L36 12', stroke: '#111', 'stroke-width': '3', 'stroke-linecap': 'round' })]) }
|
||||||
|
|
||||||
|
/** 扳手图标 */
|
||||||
|
const IconWrench = { render: () => h('svg', { width: '48', height: '48', viewBox: '0 0 48 48', fill: 'none' }, [h('path', { d: 'M12 36L30 18M30 18C28 14 30 10 34 8C34 8 36 12 40 12C40 16 36 18 34 18L30 18Z', stroke: '#111', 'stroke-width': '3', 'stroke-linecap': 'round', 'stroke-linejoin': 'round', fill: 'none' }), h('path', { d: 'M12 36C10 38 10 40 12 42C14 44 16 44 18 42L12 36Z', stroke: '#111', 'stroke-width': '3', fill: 'none' })]) }
|
||||||
|
|
||||||
|
/** 路标图标 */
|
||||||
|
const IconSignpost = { render: () => h('svg', { width: '48', height: '48', viewBox: '0 0 48 48', fill: 'none' }, [h('path', { d: 'M24 8V42', stroke: '#111', 'stroke-width': '3', 'stroke-linecap': 'round' }), h('path', { d: 'M12 14H32L36 18L32 22H12V14Z', stroke: '#111', 'stroke-width': '3', fill: 'none' }), h('path', { d: 'M36 28H16L12 32L16 36H36V28Z', stroke: '#111', 'stroke-width': '3', fill: 'none' })]) }
|
||||||
|
|
||||||
|
/** 星球图标 */
|
||||||
|
const IconPlanet = { render: () => h('svg', { width: '48', height: '48', viewBox: '0 0 48 48', fill: 'none' }, [h('circle', { cx: '24', cy: '24', r: '12', stroke: '#111', 'stroke-width': '3', fill: 'none' }), h('ellipse', { cx: '24', cy: '24', rx: '20', ry: '8', stroke: '#111', 'stroke-width': '3', fill: 'none', transform: 'rotate(-30 24 24)' })]) }
|
||||||
|
|
||||||
|
const valueCards = [
|
||||||
|
{ icon: IconRadar, title: '机会不应该被信息差阻隔', desc: '我们努力让更多元宝、优质的招聘机会被年轻人及时看见。' },
|
||||||
|
{ icon: IconWrench, title: '技术应该服务真实需求', desc: '我们不会为了使用AI而使用AI,每一项功能都应该直接使切,提高用户本体验和知和用户效率互打的方面' },
|
||||||
|
{ icon: IconPlanet, title: '求职不只是获得一份工作', desc: '一份工作选着一个人未来几年的生活。我们决定后的Offer,也作进每个人长期的发展方向。' },
|
||||||
|
{ icon: IconSignpost, title: '专业建议也要尊重个人选择', desc: '我们提供信息、工具与经验,但不替用户做决定。适合自己的选择,比统一的标准效果更重要' },
|
||||||
|
]
|
||||||
|
|
||||||
|
// ==================== 联系我们卡片数据 ====================
|
||||||
|
|
||||||
|
/** 产品反馈图标 */
|
||||||
|
const IconFeedback = { render: () => h('svg', { width: '32', height: '32', viewBox: '0 0 32 32', fill: 'none' }, [h('path', { d: 'M6 8H26V22H18L12 26V22H6V8Z', stroke: '#52CAD1', 'stroke-width': '2', 'stroke-linejoin': 'round', fill: 'none' }), h('circle', { cx: '12', cy: '15', r: '1.5', fill: '#52CAD1' }), h('circle', { cx: '16', cy: '15', r: '1.5', fill: '#52CAD1' }), h('circle', { cx: '20', cy: '15', r: '1.5', fill: '#52CAD1' })]) }
|
||||||
|
|
||||||
|
/** 握手图标 */
|
||||||
|
const IconHandshake = { render: () => h('svg', { width: '32', height: '32', viewBox: '0 0 32 32', fill: 'none' }, [h('path', { d: 'M4 14L10 10L16 14L22 10L28 14', stroke: '#52CAD1', 'stroke-width': '2', 'stroke-linecap': 'round', 'stroke-linejoin': 'round' }), h('path', { d: 'M10 10V22M22 10V22', stroke: '#52CAD1', 'stroke-width': '2', 'stroke-linecap': 'round' })]) }
|
||||||
|
|
||||||
|
/** 导师入驻图标 */
|
||||||
|
const IconMentor = { render: () => h('svg', { width: '32', height: '32', viewBox: '0 0 32 32', fill: 'none' }, [h('rect', { x: '4', y: '6', width: '24', height: '16', rx: '2', stroke: '#52CAD1', 'stroke-width': '2', fill: 'none' }), h('circle', { cx: '16', cy: '13', r: '3', stroke: '#52CAD1', 'stroke-width': '2', fill: 'none' }), h('path', { d: 'M10 20C10 17 13 16 16 16C19 16 22 17 22 20', stroke: '#52CAD1', 'stroke-width': '2', 'stroke-linecap': 'round' }), h('path', { d: 'M12 26H20', stroke: '#52CAD1', 'stroke-width': '2', 'stroke-linecap': 'round' })]) }
|
||||||
|
|
||||||
|
const contactCards = [
|
||||||
|
{ icon: IconFeedback, title: '产品反馈', desc: '遇到任何问题,我们会全力解决和修正。留言反馈,欢迎告诉我们!', link: 'javascript:void(0)', linkText: '提交反馈' },
|
||||||
|
{ icon: IconHandshake, title: '商务合作', desc: '企业招聘、共赢合作、技术开发等商业合作。更进一步了解我们的服务', link: 'javascript:void(0)', linkText: '查看简历' },
|
||||||
|
{ icon: IconMentor, title: '导师入驻', desc: '如果你从来资深的行业专业导师,你可以求职领域服务更多年人。欢迎联入导师申请联系。', link: 'javascript:void(0)', linkText: '申请入驻' },
|
||||||
|
]
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,367 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 校招公告Tab内容 -->
|
||||||
|
<div class="home-announcement">
|
||||||
|
<!-- 第一部分:校招公告,一站查全 -->
|
||||||
|
<section class="home-announcement__section">
|
||||||
|
<div class="home-announcement__header">
|
||||||
|
<div class="">
|
||||||
|
<h2 class="home-announcement__title">校招公告,一站查全</h2>
|
||||||
|
<p class="home-announcement__subtitle">汇集企业官网、公众号和招聘专题页,优先看今天新动态</p>
|
||||||
|
</div>
|
||||||
|
<!-- 首页版校招动态统计卡片 -->
|
||||||
|
<div class="home-announcement__stats-card">
|
||||||
|
<!-- 标题区域 -->
|
||||||
|
<div class="home-announcement__stats-title-wrap">
|
||||||
|
<span class="home-announcement__stats-title">岗位概览</span>
|
||||||
|
<span class="home-announcement__stats-date">数据截至 {{ statsCurrentDate }}</span>
|
||||||
|
</div>
|
||||||
|
<!-- 数据区域 -->
|
||||||
|
<div class="home-announcement__stats-data">
|
||||||
|
<!-- 今日新增 -->
|
||||||
|
<div class="home-announcement__stats-item">
|
||||||
|
<span class="home-announcement__stats-num">{{ statsTodayCount }}</span>
|
||||||
|
<span class="home-announcement__stats-label">今日新增</span>
|
||||||
|
</div>
|
||||||
|
<!-- 分割线 -->
|
||||||
|
<div class="home-announcement__stats-divider"></div>
|
||||||
|
<!-- 本月新增 -->
|
||||||
|
<div class="home-announcement__stats-item">
|
||||||
|
<span class="home-announcement__stats-num">{{ statsMonthCount }}</span>
|
||||||
|
<span class="home-announcement__stats-label">本月新增</span>
|
||||||
|
</div>
|
||||||
|
<!-- 分割线 -->
|
||||||
|
<div class="home-announcement__stats-divider"></div>
|
||||||
|
<!-- 累计收录 -->
|
||||||
|
<div class="home-announcement__stats-item">
|
||||||
|
<span class="home-announcement__stats-num">{{ statsTotalCount }}</span>
|
||||||
|
<span class="home-announcement__stats-label">累计收录</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 筛选面板(与岗位雷达一致) -->
|
||||||
|
<div class="home-announcement__filters">
|
||||||
|
<!-- 行业筛选行 -->
|
||||||
|
<div class="home-announcement__filter-row">
|
||||||
|
<span class="home-announcement__filter-label">行业</span>
|
||||||
|
<div class="home-announcement__filter-chips">
|
||||||
|
<span
|
||||||
|
class="home-announcement__chip"
|
||||||
|
:class="{ 'home-announcement__chip--active': selectedIndustryName === null }"
|
||||||
|
@click="selectIndustry(null)"
|
||||||
|
>全部</span>
|
||||||
|
<span
|
||||||
|
v-for="item in hotIndustries"
|
||||||
|
:key="'ind-' + item.id"
|
||||||
|
class="home-announcement__chip"
|
||||||
|
:class="{ 'home-announcement__chip--active': selectedIndustryName === item.name }"
|
||||||
|
@click="selectIndustry(item.name)"
|
||||||
|
>{{ item.name }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 城市筛选行 -->
|
||||||
|
<div class="home-announcement__filter-row">
|
||||||
|
<span class="home-announcement__filter-label">城市</span>
|
||||||
|
<div class="home-announcement__filter-chips">
|
||||||
|
<span
|
||||||
|
class="home-announcement__chip"
|
||||||
|
:class="{ 'home-announcement__chip--active': selectedCityName === null }"
|
||||||
|
@click="selectCity(null)"
|
||||||
|
>全部</span>
|
||||||
|
<span
|
||||||
|
v-for="item in hotCities"
|
||||||
|
:key="'city-' + item.code"
|
||||||
|
class="home-announcement__chip"
|
||||||
|
:class="{ 'home-announcement__chip--active': selectedCityName === item.name }"
|
||||||
|
@click="selectCity(item.name)"
|
||||||
|
>{{ item.name }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 岗位筛选行 -->
|
||||||
|
<div class="home-announcement__filter-row">
|
||||||
|
<span class="home-announcement__filter-label">岗位</span>
|
||||||
|
<div class="home-announcement__filter-chips">
|
||||||
|
<span
|
||||||
|
class="home-announcement__chip"
|
||||||
|
:class="{ 'home-announcement__chip--active': selectedCategoryName === null }"
|
||||||
|
@click="selectCategory(null)"
|
||||||
|
>全部</span>
|
||||||
|
<span
|
||||||
|
v-for="item in hotCategories"
|
||||||
|
:key="'cat-' + item.id"
|
||||||
|
class="home-announcement__chip"
|
||||||
|
:class="{ 'home-announcement__chip--active': selectedCategoryName === item.name }"
|
||||||
|
@click="selectCategory(item.name)"
|
||||||
|
>{{ item.name }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 公告列表网格 -->
|
||||||
|
<div class="home-announcement__grid">
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in announcementList"
|
||||||
|
:key="index"
|
||||||
|
class="home-announcement__card"
|
||||||
|
@click="goToDetail(item)"
|
||||||
|
>
|
||||||
|
<!-- 卡片主体 -->
|
||||||
|
<div class="home-announcement__card-body">
|
||||||
|
<!-- 左侧公司logo -->
|
||||||
|
<div class="home-announcement__card-logo-wrap">
|
||||||
|
<img v-if="item.logoUrl" class="home-announcement__card-logo" :src="item.logoUrl" alt="" />
|
||||||
|
<div v-else class="home-announcement__card-logo home-announcement__card-logo--default">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"><rect width="24" height="24" rx="4" fill="#EDF9FA"/><g clip-path="url(#clogo3)"><path d="M5.99998 16.6667H6.66665V8.24001C6.66667 8.0301 6.73274 7.82552 6.8555 7.65526C6.97827 7.48499 7.15149 7.35767 7.35065 7.29134L12.684 5.51401C12.8343 5.46395 12.9943 5.45031 13.1509 5.47423C13.3076 5.49815 13.4562 5.55893 13.5848 5.65157C13.7133 5.74421 13.8179 5.86606 13.8901 6.00708C13.9623 6.1481 14 6.30425 14 6.46268V16.6667H14.6666V10.66C14.6667 10.6107 14.6776 10.562 14.6987 10.5175C14.7199 10.4729 14.7506 10.4336 14.7887 10.4024C14.8268 10.3711 14.8714 10.3487 14.9193 10.3368C14.9671 10.3249 15.017 10.3237 15.0653 10.3333L16.5293 10.6267C16.7559 10.672 16.9599 10.7944 17.1064 10.973C17.253 11.1517 17.3332 11.3756 17.3333 11.6067V16.6667H18C18.1768 16.6667 18.3464 16.7369 18.4714 16.8619C18.5964 16.987 18.6666 17.1565 18.6666 17.3333C18.6666 17.5102 18.5964 17.6797 18.4714 17.8047C18.3464 17.9298 18.1768 18 18 18H5.99998C5.82317 18 5.6536 17.9298 5.52858 17.8047C5.40355 17.6797 5.33331 17.5102 5.33331 17.3333C5.33331 17.1565 5.40355 16.987 5.52858 16.8619C5.6536 16.7369 5.82317 16.6667 5.99998 16.6667Z" fill="#52CAD1"/></g><defs><clipPath id="clogo3"><rect width="16" height="16" fill="white" transform="translate(4 4)"/></clipPath></defs></svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 右侧内容 -->
|
||||||
|
<div class="home-announcement__card-content">
|
||||||
|
<!-- 标题行 + 公司类型标签 -->
|
||||||
|
<div class="home-announcement__card-title-row">
|
||||||
|
<span class="home-announcement__card-title">{{ item.title }}</span>
|
||||||
|
<span v-if="getCompanyType(item)" class="home-announcement__card-type-tag">{{ getCompanyType(item) }}</span>
|
||||||
|
</div>
|
||||||
|
<!-- 标签行:批次 + 学历 -->
|
||||||
|
<div class="home-announcement__card-tags">
|
||||||
|
<span v-if="item.batchNames && item.batchNames.length" class="home-announcement__card-tag home-announcement__card-tag--batch">{{ item.batchNames[0] }}</span>
|
||||||
|
<span v-if="item.educationNames && item.educationNames.length" class="home-announcement__card-tag home-announcement__card-tag--edu">{{ item.educationNames[0] }}</span>
|
||||||
|
</div>
|
||||||
|
<!-- 岗位信息行 -->
|
||||||
|
<div class="home-announcement__card-info-line">
|
||||||
|
<svg class="home-announcement__card-icon" viewBox="0 0 16 16" fill="none">
|
||||||
|
<path d="M2.66669 12H13.3334V5.33333H2.66669V12ZM2.66669 4H13.3334V3.33333H2.66669V4ZM2.66669 12.6667C2.30002 12.6667 1.98602 12.5362 1.72469 12.2753C1.46402 12.0138 1.33335 11.6998 1.33335 11.3333V3.33333C1.33335 2.96667 1.46402 2.65289 1.72469 2.392C1.98602 2.13067 2.30002 2 2.66669 2H13.3334C13.7 2 14.014 2.13067 14.2754 2.392C14.5361 2.65289 14.6667 2.96667 14.6667 3.33333V11.3333C14.6667 11.6998 14.5361 12.0138 14.2754 12.2753C14.014 12.5362 13.7 12.6667 13.3334 12.6667H2.66669ZM4.66669 14H11.3334V13.3333H4.66669V14Z" fill="#64748B"/>
|
||||||
|
</svg>
|
||||||
|
<span>{{ formatCategories(item) }}</span>
|
||||||
|
</div>
|
||||||
|
<!-- 城市信息行 -->
|
||||||
|
<div class="home-announcement__card-info-line">
|
||||||
|
<svg class="home-announcement__card-icon" viewBox="0 0 16 16" fill="none">
|
||||||
|
<path d="M8 8.66667C8.36667 8.66667 8.68067 8.53622 8.942 8.27533C9.20289 8.01400 9.33333 7.7 9.33333 7.33333C9.33333 6.96667 9.20289 6.65289 8.942 6.392C8.68067 6.13067 8.36667 6 8 6C7.63333 6 7.31956 6.13067 7.05867 6.392C6.79733 6.65289 6.66667 6.96667 6.66667 7.33333C6.66667 7.7 6.79733 8.01400 7.05867 8.27533C7.31956 8.53622 7.63333 8.66667 8 8.66667ZM8 13.3C9.35556 12.0667 10.3751 10.9527 11.0587 9.958C11.7418 8.96378 12.0833 8.08889 12.0833 7.33333C12.0833 6.17778 11.7084 5.22222 10.9587 4.46667C10.2084 3.71111 9.2 3.33333 8 3.33333C6.8 3.33333 5.79156 3.71111 4.94133 4.46667C4.09156 5.22222 3.91667 6.17778 3.91667 7.33333C3.91667 8.08889 4.25844 8.96378 4.942 9.958C5.62511 10.9527 6.64444 12.0667 8 13.3Z" fill="#64748B"/>
|
||||||
|
</svg>
|
||||||
|
<span>{{ formatCities(item) }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 卡片底部渐变条 -->
|
||||||
|
<div class="home-announcement__card-footer">
|
||||||
|
<span class="home-announcement__card-update">{{ formatUpdateStatus(item) }}</span>
|
||||||
|
<span class="home-announcement__card-deadline">{{ formatDeadline(item) }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 加载中 -->
|
||||||
|
<div v-if="loading" class="home-announcement__loading">
|
||||||
|
<div class="home-announcement__spinner"></div>
|
||||||
|
<span>加载中...</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 查看更多按钮 -->
|
||||||
|
<div v-if="!loading && announcementList.length > 0" class="home-announcement__more">
|
||||||
|
<button class="home-announcement__more-btn" @click="router.push('/announcement')">查看更多</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- 第二部分:CTA区域 -->
|
||||||
|
<section class="home-cta">
|
||||||
|
<div class="home-cta__inner">
|
||||||
|
<h2>让Offer派带你找到<br/>人生第一份好工作</h2>
|
||||||
|
<button class="home-cta__btn" @click="router.push('/announcement')">免费体验</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, watch } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { fetchAnnouncementList, fetchAnnouncementLastUpdateTime, fetchAnnouncementStatistics } from '@/api/announcement'
|
||||||
|
import type { AnnouncementItem } from '@/api/announcement'
|
||||||
|
import { fetchHotIndustries, fetchHotCategories, fetchHotCities } from '@/api/jobs'
|
||||||
|
import type { HotIndustryItem, HotCategoryItem, HotCityItem } from '@/api/jobs'
|
||||||
|
|
||||||
|
/** 路由实例 */
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
// ==================== 统计卡片数据 ====================
|
||||||
|
|
||||||
|
/** 最新更新时间(MM.DD 格式) */
|
||||||
|
const statsCurrentDate = ref('--')
|
||||||
|
/** 今日新增 */
|
||||||
|
const statsTodayCount = ref<string | number>('--')
|
||||||
|
/** 本月新增 */
|
||||||
|
const statsMonthCount = ref<string | number>('--')
|
||||||
|
/** 累计收录 */
|
||||||
|
const statsTotalCount = ref<string | number>('--')
|
||||||
|
|
||||||
|
/** 加载统计卡片数据 */
|
||||||
|
async function loadStatsData() {
|
||||||
|
try {
|
||||||
|
const [timeRes, statsRes] = await Promise.all([
|
||||||
|
fetchAnnouncementLastUpdateTime(),
|
||||||
|
fetchAnnouncementStatistics(),
|
||||||
|
])
|
||||||
|
if (timeRes.code === '0' && timeRes.data) {
|
||||||
|
const date = new Date(Number(timeRes.data))
|
||||||
|
statsCurrentDate.value = `${String(date.getMonth() + 1).padStart(2, '0')}.${String(date.getDate()).padStart(2, '0')}`
|
||||||
|
}
|
||||||
|
if (statsRes.code === '0' && statsRes.data) {
|
||||||
|
statsTodayCount.value = statsRes.data.dayCount ?? 0
|
||||||
|
statsMonthCount.value = statsRes.data.monthCount ?? 0
|
||||||
|
statsTotalCount.value = statsRes.data.totalCount ?? 0
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('加载统计数据失败', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 筛选数据 ====================
|
||||||
|
|
||||||
|
/** 热门行业列表 */
|
||||||
|
const hotIndustries = ref<HotIndustryItem[]>([])
|
||||||
|
/** 热门城市列表 */
|
||||||
|
const hotCities = ref<HotCityItem[]>([])
|
||||||
|
/** 热门岗位列表 */
|
||||||
|
const hotCategories = ref<HotCategoryItem[]>([])
|
||||||
|
|
||||||
|
/** 当前选中的行业名称(null=全部) */
|
||||||
|
const selectedIndustryName = ref<string | null>(null)
|
||||||
|
/** 当前选中的城市名称(null=全部) */
|
||||||
|
const selectedCityName = ref<string | null>(null)
|
||||||
|
/** 当前选中的岗位名称(null=全部) */
|
||||||
|
const selectedCategoryName = ref<string | null>(null)
|
||||||
|
|
||||||
|
// ==================== 公告列表 ====================
|
||||||
|
|
||||||
|
/** 公告列表数据 */
|
||||||
|
const announcementList = ref<AnnouncementItem[]>([])
|
||||||
|
/** 加载状态 */
|
||||||
|
const loading = ref(false)
|
||||||
|
|
||||||
|
/** 选择行业 */
|
||||||
|
function selectIndustry(name: string | null) {
|
||||||
|
selectedIndustryName.value = name
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 选择城市 */
|
||||||
|
function selectCity(name: string | null) {
|
||||||
|
selectedCityName.value = name
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 选择岗位分类 */
|
||||||
|
function selectCategory(name: string | null) {
|
||||||
|
selectedCategoryName.value = name
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 加载公告列表(公告接口传名称) */
|
||||||
|
async function loadAnnouncementList() {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const params: any = {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 30,
|
||||||
|
}
|
||||||
|
if (selectedIndustryName.value !== null) {
|
||||||
|
params.industryNames = [selectedIndustryName.value]
|
||||||
|
}
|
||||||
|
if (selectedCityName.value !== null) {
|
||||||
|
params.cityNames = [selectedCityName.value]
|
||||||
|
}
|
||||||
|
if (selectedCategoryName.value !== null) {
|
||||||
|
params.categoryNames = [selectedCategoryName.value]
|
||||||
|
}
|
||||||
|
const res = await fetchAnnouncementList(params)
|
||||||
|
if (res.code === '0' && res.data) {
|
||||||
|
announcementList.value = res.data.list || []
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('加载校招公告列表失败', e)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 格式化岗位分类显示 */
|
||||||
|
function formatCategories(item: AnnouncementItem): string {
|
||||||
|
if (!item.categoryNames || item.categoryNames.length === 0) return '暂无岗位信息'
|
||||||
|
const maxShow = 3
|
||||||
|
const shown = item.categoryNames.slice(0, maxShow).join(' / ')
|
||||||
|
const totalCount = item.categoryNames.length
|
||||||
|
if (totalCount <= maxShow) return shown
|
||||||
|
return `${shown}等${totalCount}类`
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 格式化城市显示 */
|
||||||
|
function formatCities(item: AnnouncementItem): string {
|
||||||
|
if (!item.cityNames || item.cityNames.length === 0) return '全国'
|
||||||
|
const maxShow = 3
|
||||||
|
const shown = item.cityNames.slice(0, maxShow).join(' / ')
|
||||||
|
const totalCount = item.cityNames.length
|
||||||
|
if (totalCount <= maxShow) return shown
|
||||||
|
return `${shown}等${totalCount}城`
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取公司类型(从批次名中推断,暂用批次标签展示) */
|
||||||
|
function getCompanyType(_item: AnnouncementItem): string {
|
||||||
|
// 公告列表数据无公司类型字段,暂不显示
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 格式化更新状态 */
|
||||||
|
function formatUpdateStatus(item: AnnouncementItem): string {
|
||||||
|
if (!item.publishTime) return ''
|
||||||
|
const now = new Date()
|
||||||
|
const pub = new Date(item.publishTime)
|
||||||
|
const diffDays = Math.floor((now.getTime() - pub.getTime()) / (1000 * 60 * 60 * 24))
|
||||||
|
if (diffDays === 0) return '今日更新'
|
||||||
|
if (diffDays === 1) return '昨日更新'
|
||||||
|
if (diffDays <= 7) return `${diffDays}天前更新`
|
||||||
|
const month = String(pub.getMonth() + 1).padStart(2, '0')
|
||||||
|
const day = String(pub.getDate()).padStart(2, '0')
|
||||||
|
return `${month}-${day}更新`
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 格式化截止时间 */
|
||||||
|
function formatDeadline(item: AnnouncementItem): string {
|
||||||
|
if (item.applyEndDesc) return item.applyEndDesc
|
||||||
|
if (!item.applyEndTime || !item.applyEndTime.seconds) return '招满即止'
|
||||||
|
const date = new Date(item.applyEndTime.seconds * 1000)
|
||||||
|
if (isNaN(date.getTime())) return '招满即止'
|
||||||
|
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||||||
|
const day = String(date.getDate()).padStart(2, '0')
|
||||||
|
return `${month}.${day}截止`
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 跳转公告详情 */
|
||||||
|
function goToDetail(item: AnnouncementItem) {
|
||||||
|
router.push({ path: `/announcement/${item.id}`, query: { from: 'home' } })
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 加载热门筛选数据 */
|
||||||
|
async function loadHotFilters() {
|
||||||
|
try {
|
||||||
|
const [indRes, cityRes, catRes] = await Promise.all([
|
||||||
|
fetchHotIndustries(),
|
||||||
|
fetchHotCities(),
|
||||||
|
fetchHotCategories(),
|
||||||
|
])
|
||||||
|
if (indRes.code === '0' && indRes.data) hotIndustries.value = indRes.data
|
||||||
|
if (cityRes.code === '0' && cityRes.data) hotCities.value = cityRes.data
|
||||||
|
if (catRes.code === '0' && catRes.data) hotCategories.value = catRes.data
|
||||||
|
} catch (e) {
|
||||||
|
console.error('加载热门筛选数据失败', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听筛选条件变化,刷新列表
|
||||||
|
watch([selectedIndustryName, selectedCityName, selectedCategoryName], () => {
|
||||||
|
loadAnnouncementList()
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loadHotFilters()
|
||||||
|
loadAnnouncementList()
|
||||||
|
loadStatsData()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,503 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 首页Tab内容 - 从Home.vue抽取的主体内容 -->
|
||||||
|
<div class="home-content">
|
||||||
|
<!-- 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>
|
||||||
|
<div class="home-hero__inner">
|
||||||
|
<div class="home-hero__left">
|
||||||
|
<h1 class="home-hero__title">Offer派,<br/><span class="dib"></span>收offer就是快!</h1>
|
||||||
|
<p class="home-hero__desc">智能匹配职位、自动填写申请、量身定制简历、推荐内部人脉——<br/>不到1分钟,统统搞定!</p>
|
||||||
|
<button class="home-hero__cta" @click="router.push('/jobs')">免费体验</button>
|
||||||
|
</div>
|
||||||
|
<!-- 右侧视频展示区 -->
|
||||||
|
<div class="home-hero__right">
|
||||||
|
<div>
|
||||||
|
<img class="w706 h452" src="@/assets/images/home/home-top.gif" alt="">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Stats Section -->
|
||||||
|
<section class="home-stats">
|
||||||
|
<div class="home-stats__inner">
|
||||||
|
<div class="home-stats__header">
|
||||||
|
<h2 class="fs38">让每一次求职努力<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">84.5%大学生求职首选</p>
|
||||||
|
</article>
|
||||||
|
<article class="stat-card">
|
||||||
|
<div class="stat-card__num">10倍</div>
|
||||||
|
<p class="stat-card__label">面试邀约率提升</p>
|
||||||
|
</article>
|
||||||
|
<article class="stat-card">
|
||||||
|
<div class="stat-card__num">82%</div>
|
||||||
|
<p class="stat-card__label">节约82%校招求职时间</p>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Jobs Showcase Section -->
|
||||||
|
<section class="home-jobs-showcase">
|
||||||
|
<div class="home-jobs-showcase__orb home-jobs-showcase__orb--top"></div>
|
||||||
|
<div class="home-jobs-showcase__orb home-jobs-showcase__orb--bottom"></div>
|
||||||
|
<div class="home-jobs-showcase__inner">
|
||||||
|
<h2 class="fs38">海量优质校招岗位,尽在Offer派!</h2>
|
||||||
|
<p class="home-jobs-showcase__sub">实时汇集海量超10000+名校校招职位</p>
|
||||||
|
<div class="home-jobs-showcase__box prl25">
|
||||||
|
<div class="home-jobs-showcase__stats">
|
||||||
|
<div class="showcase-stat">
|
||||||
|
<div class="showcase-stat__num"><span><span class="accent">40</span><span class="accent">万</span></span><span class="fs32">+</span></div>
|
||||||
|
<div class="showcase-stat__label">岗位总数</div>
|
||||||
|
</div>
|
||||||
|
<div class="showcase-stat">
|
||||||
|
<div class="showcase-stat__num"><span class="accent">{{ dailyJobCount }}</span><span class="">个</span></div>
|
||||||
|
<div class="showcase-stat__label">今日更新</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="home-jobs-showcase__scroll">
|
||||||
|
<div class="ticker-track">
|
||||||
|
<div class="job-ticker" v-for="(job, i) in tickerJobs" :key="'a' + i">
|
||||||
|
<span class="job-ticker__company">{{ job.company }}·{{ job.time }}</span>
|
||||||
|
<span class="job-ticker__title">{{ job.title }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="job-ticker" v-for="(job, i) in tickerJobs" :key="'b' + i">
|
||||||
|
<span class="job-ticker__company">{{ job.company }}·{{ job.time }}</span>
|
||||||
|
<span class="job-ticker__title">{{ job.title }}</span>
|
||||||
|
</div>
|
||||||
|
</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>第一时间发现真正适合你的岗位,精准匹配你的真<br/>实技能,杜绝虚假信息。</p>
|
||||||
|
<button class="home-feature__btn" @click="router.push('/jobs')">
|
||||||
|
<svg width="12" height="12" viewBox="0 0 14 23" 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"><img class="wp100 hp100" src="@/assets/images/home/alex-avatar.png" alt=""></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>每日向数百岗位一键投递,覆盖各大企业网申系<br/>统。告别重复填写,节省 82% 校招求职时间。</p>
|
||||||
|
<button class="home-feature__btn" @click="router.push('/jobs')">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 20 21" fill="none"><path d="M3.33331 11.6667C3.17561 11.6673 3.021 11.623 2.88743 11.5392C2.75387 11.4554 2.64683 11.3354 2.57876 11.1931C2.51069 11.0509 2.48438 10.8922 2.50289 10.7356C2.52139 10.579 2.58396 10.4309 2.68331 10.3084L10.9333 1.80839C10.9952 1.73696 11.0795 1.68868 11.1725 1.6715C11.2654 1.65431 11.3614 1.66923 11.4447 1.71381C11.5281 1.75838 11.5938 1.82997 11.6311 1.91681C11.6684 2.00365 11.675 2.10059 11.65 2.19172L10.05 7.20839C10.0028 7.33466 9.98695 7.47049 10.0038 7.60423C10.0206 7.73797 10.0697 7.86562 10.1467 7.97624C10.2237 8.08686 10.3265 8.17715 10.446 8.23936C10.5656 8.30156 10.6985 8.33383 10.8333 8.33339L16.6666 8.33339C16.8243 8.33285 16.9789 8.37707 17.1125 8.46091C17.2461 8.54474 17.3531 8.66476 17.4212 8.80701C17.4893 8.94926 17.5156 9.1079 17.4971 9.26451C17.4785 9.42111 17.416 9.56926 17.3166 9.69172L9.06664 18.1917C9.00476 18.2632 8.92042 18.3114 8.82749 18.3286C8.73455 18.3458 8.63854 18.3309 8.5552 18.2863C8.47186 18.2417 8.40615 18.1701 8.36886 18.0833C8.33157 17.9965 8.32491 17.8995 8.34997 17.8L9.94997 12.7917C9.99715 12.6655 10.013 12.5296 9.99615 12.3959C9.9793 12.2621 9.93026 12.1345 9.85323 12.0239C9.77621 11.9132 9.6735 11.823 9.55391 11.7608C9.43433 11.6985 9.30144 11.6663 9.16664 11.6667L3.33331 11.6667Z" stroke="currentColor" stroke-width="2" stroke-linejoin="round" stroke-linecap="round"></path></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"><img class="wp100 hp100" src="@/assets/images/home/right-icon-01.png" alt=""></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"><img class="wp100 hp100" src="@/assets/images/home/load-icon-01.png" alt=""></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秒内生成针对特定岗位优化的专业简历,通过<br/>ATS系统,突出你的核心优势。</p>
|
||||||
|
<button class="home-feature__btn" @click="router.push('/jobs')">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 20 22" fill="none"><path stroke="currentColor" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" d="M10.5492 18.3334L15 18.3334C15.442 18.3334 15.8659 18.1578 16.1785 17.8453C16.4911 17.5327 16.6667 17.1088 16.6667 16.6668L16.6667 6.66675C16.6673 6.40268 16.6157 6.14109 16.5147 5.89708C16.4137 5.65307 16.2654 5.43148 16.0783 5.24509L13.0883 2.25509C12.9019 2.06802 12.6803 1.91972 12.4363 1.81874C12.1923 1.71776 11.9307 1.66611 11.6667 1.66675L4.99999 1.66675C4.55797 1.66675 4.13404 1.84235 3.82148 2.15491C3.50892 2.46747 3.33333 2.89139 3.33333 3.33342L3.33333 11.1168"></path><path stroke="rgba(82, 202, 209, 1)" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" d="M11.6667 1.66675L11.6667 5.83341C11.6667 6.05443 11.7545 6.26639 11.9107 6.42267C12.067 6.57895 12.279 6.66675 12.5 6.66675L16.6667 6.66675"></path><path d="M8.64834 10.5184C8.98019 10.1869 9.43015 10.0007 9.89922 10.001C10.3683 10.0012 10.8181 10.1878 11.1496 10.5196C11.4811 10.8515 11.6672 11.3014 11.667 11.7705C11.6668 12.2396 11.4802 12.6894 11.1483 13.0209L6.96667 17.1975C6.76865 17.3957 6.52389 17.5407 6.255 17.6192L3.86584 18.3167C3.79413 18.3376 3.71812 18.3389 3.64576 18.3203C3.5734 18.3018 3.50736 18.2642 3.45454 18.2113C3.40173 18.1585 3.36408 18.0925 3.34554 18.0201C3.327 17.9478 3.32826 17.8718 3.34917 17.8L4.04584 15.4092C4.12448 15.1406 4.2695 14.8962 4.4675 14.6984L8.64834 10.5184Z" stroke="currentColor" stroke-width="2" stroke-linejoin="round" stroke-linecap="round"></path></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">
|
||||||
|
<img class="w15 h15" src="@/assets/images/home/blue-shield-icon-01.png" alt="">
|
||||||
|
<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>实时获取名企最新内推信息,自动填写网申内推<br/>码,简历更快到达HR。</p>
|
||||||
|
<button class="home-feature__btn" @click="router.push('/jobs')">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 20 20" fill="none"><path d="M9.16667 5C11.7011 5.06529 14.1783 4.23959 16.1667 2.66667C16.2905 2.57381 16.4377 2.51727 16.5918 2.50337C16.746 2.48947 16.9009 2.51877 17.0393 2.58798C17.1778 2.65719 17.2942 2.76358 17.3755 2.89522C17.4569 3.02687 17.5 3.17857 17.5 3.33333L17.5 13.3333C17.5 13.4881 17.4569 13.6398 17.3755 13.7714C17.2942 13.9031 17.1778 14.0095 17.0393 14.0787C16.9009 14.1479 16.746 14.1772 16.5918 14.1633C16.4377 14.1494 16.2905 14.0929 16.1667 14C14.1783 12.4271 11.7011 11.6014 9.16667 11.6667L4.16667 11.6667C3.72464 11.6667 3.30072 11.4911 2.98816 11.1785C2.67559 10.866 2.5 10.442 2.5 10L2.5 6.66667C2.5 6.22464 2.67559 5.80072 2.98816 5.48816C3.30072 5.1756 3.72464 5 4.16667 5L9.16667 5Z" stroke="currentColor" stroke-width="2" stroke-linejoin="round" stroke-linecap="round"></path><path stroke="currentColor" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" d="M5 11.6665C5 13.8302 5.70178 15.9355 7 17.6665C7.26522 18.0201 7.66005 18.2539 8.09763 18.3164C8.53522 18.3789 8.97971 18.2651 9.33333 17.9998C9.68695 17.7346 9.92074 17.3398 9.98325 16.9022C10.0458 16.4646 9.93188 16.0201 9.66667 15.6665C8.80119 14.5125 8.33333 13.109 8.33333 11.6665"></path><path stroke="currentColor" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" d="M6.66669 5L6.66669 11.6667"></path></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 xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 20 20" fill="none"><path d="M18.3333 14.1667C18.3333 14.6087 18.1577 15.0326 17.8452 15.3452C17.5326 15.6577 17.1087 15.8333 16.6667 15.8333L5.69 15.8333C5.24801 15.8334 4.82416 16.0091 4.51167 16.3217L2.67667 18.1567C2.59393 18.2394 2.48851 18.2957 2.37375 18.3186C2.25898 18.3414 2.14003 18.3297 2.03193 18.2849C1.92382 18.2401 1.83142 18.1643 1.76641 18.067C1.7014 17.9697 1.66669 17.8553 1.66667 17.7383L1.66667 4.16667C1.66667 3.72464 1.84227 3.30072 2.15483 2.98816C2.46739 2.67559 2.89131 2.5 3.33334 2.5L16.6667 2.5C17.1087 2.5 17.5326 2.67559 17.8452 2.98816C18.1577 3.30072 18.3333 3.72464 18.3333 4.16667L18.3333 14.1667Z" stroke="currentColor" stroke-width="2" stroke-linejoin="round" stroke-linecap="round"></path></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>真实求职反馈,见证每一次从迷茫到上岸</p>
|
||||||
|
</div>
|
||||||
|
<div class="home-testimonials__cards">
|
||||||
|
<div class="testimonial-card" v-for="(t, i) in testimonials" :key="i">
|
||||||
|
<p class="testimonial-card__text">{{ t.text }}</p>
|
||||||
|
<div class="dflex aliite-e">
|
||||||
|
<div class="testimonial-card__author">
|
||||||
|
<img class="testimonial-card__avatar" :src="t.avatar" alt="用户头像" />
|
||||||
|
<div class="testimonial-card__info">
|
||||||
|
<p class="testimonial-card__name">{{ t.name }}</p>
|
||||||
|
<p class="testimonial-card__school">{{ t.school }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<img class="w48 h48" src="@/assets/images/home/blue-icon-768.png" alt="">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 创始人引言卡片 -->
|
||||||
|
<div class="home-testimonials__founder">
|
||||||
|
<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"/>
|
||||||
|
<path d="M240 190 L318 224 Q328 227.5 318 231 L240 265 Q227.5 270 215 265 L137 231 Q127 227.5 137 224 L215 190 Q227.5 185 240 190 Z" stroke="#fff" stroke-width="20" fill="none" opacity="0.08" transform="rotate(-45 227.5 227.5)"/>
|
||||||
|
</svg>
|
||||||
|
<div class="home-testimonials__founder-content">
|
||||||
|
<img class="home-testimonials__founder-img" :src="avatarImg" alt="创始人头像" />
|
||||||
|
<div class="home-testimonials__founder-text">
|
||||||
|
<blockquote>"很多大学生还在用传统方式找工作,海投、反复改简历,效率很低。Offer派利用AI技术让专业和岗位<span class="fw600">深度匹配</span>关联,配合<span class="fw600">自动化投递</span>,让校招求职流程更丝滑,更精准,节省了80%的繁琐过程,拿到更多Offer。"</blockquote>
|
||||||
|
<cite>
|
||||||
|
<span class="cite-name">{{ founderQuotes[founderIndex].name }}</span>
|
||||||
|
<span class="cite-role">{{ founderQuotes[founderIndex].role }}</span>
|
||||||
|
</cite>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- FAQ Section -->
|
||||||
|
<section class="home-faq">
|
||||||
|
<div class="home-faq__inner">
|
||||||
|
<div class="home-faq__header">
|
||||||
|
<h2>常见问题</h2>
|
||||||
|
<p>关于平台使用、隐私安全与岗位来源</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 }"
|
||||||
|
>
|
||||||
|
<div class="faq-item__header" @click="faqOpen === i ? null : (faqOpen = i)">
|
||||||
|
<span class="faq-item__question">{{ faq.q }}</span>
|
||||||
|
<div class="faq-item__icon" @click.stop="faqOpen = faqOpen === i ? -1 : i">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
|
||||||
|
<template v-if="faqOpen === i">
|
||||||
|
<line x1="7" y1="7" x2="17" y2="17" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<line x1="17" y1="7" x2="7" y2="17" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<line x1="5" y1="12" x2="19" y2="12" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<line x1="12" y1="5" x2="12" y2="19" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
</template>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="faq-item__answer" v-show="faqOpen === i">
|
||||||
|
<template v-if="i === faqs.length - 1">
|
||||||
|
<div class="faq-item__feedback">
|
||||||
|
<textarea
|
||||||
|
v-model="faqFeedbackText"
|
||||||
|
class="faq-item__textarea"
|
||||||
|
placeholder="请输入你的问题"
|
||||||
|
rows="4"
|
||||||
|
></textarea>
|
||||||
|
<button class="faq-item__submit" @click.stop="submitFaqFeedback">提交</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<p>{{ faq.a }}</p>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</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"
|
||||||
|
:allowParentSelectClick="true"
|
||||||
|
: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"
|
||||||
|
:allowParentSelectClick="true"
|
||||||
|
:triggerStyle="filterTriggerStyle"
|
||||||
|
:displayStyle="filterDisplayStyle"
|
||||||
|
@update:categoryIds="onHomeCategoryChange"
|
||||||
|
/>
|
||||||
|
<button class="filter-btn" @click="goSearchJobs">立即匹配</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { useStore } from 'vuex'
|
||||||
|
import avatarImg from '@/assets/images/home/avatar-temporary.png'
|
||||||
|
import studentAvatar0 from '@/assets/images/home/student-avatar-0.png'
|
||||||
|
import studentAvatar1 from '@/assets/images/home/student-avatar-1.png'
|
||||||
|
import studentAvatar2 from '@/assets/images/home/student-avatar-2.png'
|
||||||
|
import IndustrySelector from '@/components/tools/IndustrySelector.vue'
|
||||||
|
import RegionSelector from '@/components/tools/RegionSelector.vue'
|
||||||
|
import JobCategorySelector from '@/components/tools/JobCategorySelector.vue'
|
||||||
|
import { getDailyJobCount } from '@/utils/dailyJobCount'
|
||||||
|
|
||||||
|
/** 路由实例 */
|
||||||
|
const router = useRouter()
|
||||||
|
/** Vuex 状态管理实例 */
|
||||||
|
const store = useStore()
|
||||||
|
|
||||||
|
/** 今日更新岗位数量 */
|
||||||
|
const dailyJobCount = getDailyJobCount()
|
||||||
|
|
||||||
|
/** 当前展开的 FAQ 索引 */
|
||||||
|
const faqOpen = ref(-1)
|
||||||
|
|
||||||
|
/** 创始人引言当前索引 */
|
||||||
|
const founderIndex = ref(0)
|
||||||
|
|
||||||
|
/** 创始人引言数据 */
|
||||||
|
const founderQuotes = [
|
||||||
|
{ text: '"很多大学生还在用传统方式找工作,海投、反复改简历,效率很低。Offer派利用AI技术让专业和岗位深度匹配关联,配合自动化投递,让校招求职流程更丝滑,更精准,节省了80%的繁琐过程,拿到更多Offer。"', name: 'TK', role: 'Offer派创始人' },
|
||||||
|
]
|
||||||
|
|
||||||
|
/** 岗位滚动展示数据 */
|
||||||
|
const tickerJobs = [
|
||||||
|
{ company: '字节跳动', time: '15分钟前', title: '高级前端开发工程师' },
|
||||||
|
{ company: '腾讯', time: '30分钟前', title: '后端开发工程师' },
|
||||||
|
{ company: '阿里巴巴', time: '1小时前', title: '产品经理' },
|
||||||
|
{ company: '华为', time: '2小时前', title: '算法工程师' },
|
||||||
|
{ company: '京东', time: '3小时前', title: '运营管培生' },
|
||||||
|
]
|
||||||
|
|
||||||
|
/** 内推人脉卡片数据 */
|
||||||
|
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: '西安交通大学', avatar: studentAvatar0 },
|
||||||
|
{ text: '"界面设计简洁友好,用起来很舒适。AI助手帮我理清了方向,让迷茫的我建立了自信,还能帮我优化简历,真的很nice~"', name: '王同学', school: '北京大学', avatar: studentAvatar1 },
|
||||||
|
{ text: '"满分!特别是网申自动填写,不仅可以一键填写,还能快速定制简历内容,完美匹配岗位要求,毕设求职两不误,真心推荐。"', name: '张同学', school: '中国人民大学', avatar: studentAvatar2 },
|
||||||
|
]
|
||||||
|
|
||||||
|
/** 用户反馈输入内容 */
|
||||||
|
const faqFeedbackText = ref('')
|
||||||
|
|
||||||
|
/** 提交用户反馈 */
|
||||||
|
function submitFaqFeedback() {
|
||||||
|
if (!faqFeedbackText.value.trim()) return
|
||||||
|
faqFeedbackText.value = ''
|
||||||
|
faqOpen.value = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 常见问题列表 */
|
||||||
|
const faqs = [
|
||||||
|
{ q: '这个平台与其他求职平台有什么不同?', a: '不同于BOSS直聘等传统平台的"手动式"求职,Offer派如同一位经验丰富的职业导师,通过AI能力搭建智能工具,自动处理简历优化、岗位匹配、申请投递等环节,大幅度提升你的求职效率。' },
|
||||||
|
{ q: '平台如何保障我的个人信息安全?', a: 'Offer派高度重视你的隐私安全。未经你明确同意,我们绝不会将你的个人信息提供给任何第三方。你的所有数据仅用于在平台内为你提供AI智能岗位匹配、简历优化等个性化求职服务。' },
|
||||||
|
{ q: '平台可以免费使用吗?', a: 'Offer派为所有用户免费开放3天会员权益,帮你省心省力找工作。3天后,依然可以免费使用各项功能,但有使用次数限制。' },
|
||||||
|
{ q: '平台的岗位来源是什么?', a: 'Offer派的岗位来自上万家企业的官方招聘网站,同时聚合了各大主流平台的最新职位——你不需要在多个网站之间来回切换,就能一站式搜罗全网高质量的工作机会。此外,我们会持续筛查每一则新发布的职位,及时剔除虚假信息,帮你避"坑",为你提供真实靠谱的岗位信息。' },
|
||||||
|
{ q: '还有其他问题?', a: '' },
|
||||||
|
]
|
||||||
|
|
||||||
|
// ==================== 底部筛选区 ====================
|
||||||
|
|
||||||
|
/** 首页选中的行业 ID 数组 */
|
||||||
|
const homeIndustryIds = computed<number[]>(() => store.state.jobIntention.industryIds || [])
|
||||||
|
/** 首页选中的地区编码数组 */
|
||||||
|
const homeRegionCodes = computed<string[]>(() => store.state.jobIntention.regionCodes || [])
|
||||||
|
/** 首页选中的岗位 ID 数组 */
|
||||||
|
const homeCategoryIds = computed<number[]>(() => store.state.jobIntention.categoryIds || [])
|
||||||
|
|
||||||
|
/** 选择器触发按钮样式 */
|
||||||
|
const filterTriggerStyle = {
|
||||||
|
width: '2.80rem',
|
||||||
|
'max-width': 'none',
|
||||||
|
height: '0.56rem',
|
||||||
|
'border-radius': '0.16rem',
|
||||||
|
border: '1px solid #e5e7eb',
|
||||||
|
padding: '0 0.2rem',
|
||||||
|
background: '#F3F4F5',
|
||||||
|
'justify-content': 'space-between',
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 选择器显示文字样式 */
|
||||||
|
const filterDisplayStyle = {
|
||||||
|
'font-size': '0.16rem',
|
||||||
|
'line-height': '0.16rem',
|
||||||
|
color: 'rgba(0, 0, 0, 0.45)',
|
||||||
|
'max-width': '1.8rem',
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 行业选择变更回调 */
|
||||||
|
function onHomeIndustryChange(ids: number[]) {
|
||||||
|
store.dispatch('saveJobIntention', { ...store.state.jobIntention, industryIds: ids })
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 地区选择变更回调 */
|
||||||
|
function onHomeRegionChange(codes: string[]) {
|
||||||
|
store.dispatch('saveJobIntention', { ...store.state.jobIntention, regionCodes: codes })
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 岗位选择变更回调 */
|
||||||
|
function onHomeCategoryChange(ids: number[]) {
|
||||||
|
store.dispatch('saveJobIntention', { ...store.state.jobIntention, categoryIds: ids })
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 点击搜索职位 */
|
||||||
|
function goSearchJobs() {
|
||||||
|
router.push('/jobs')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,243 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 岗位雷达Tab内容 -->
|
||||||
|
<div class="home-job-radar">
|
||||||
|
<!-- 第一部分:全网优质岗位,实时精准匹配 -->
|
||||||
|
<section class="home-job-radar__section">
|
||||||
|
<div class="home-job-radar__header">
|
||||||
|
<h2 class="home-job-radar__title">全网优质岗位,实时精准匹配</h2>
|
||||||
|
<p class="home-job-radar__subtitle">实时汇聚全网企业名额信息, 综合求职意向与履历适配, 让每一次投递都是精准匹配, 更高效</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 筛选面板 -->
|
||||||
|
<div class="home-job-radar__filters">
|
||||||
|
<!-- 行业筛选行 -->
|
||||||
|
<div class="home-job-radar__filter-row">
|
||||||
|
<span class="home-job-radar__filter-label">行业</span>
|
||||||
|
<div class="home-job-radar__filter-chips">
|
||||||
|
<span
|
||||||
|
class="home-job-radar__chip"
|
||||||
|
:class="{ 'home-job-radar__chip--active': selectedIndustryId === null }"
|
||||||
|
@click="selectIndustry(null)"
|
||||||
|
>全部</span>
|
||||||
|
<span
|
||||||
|
v-for="item in hotIndustries"
|
||||||
|
:key="'ind-' + item.id"
|
||||||
|
class="home-job-radar__chip"
|
||||||
|
:class="{ 'home-job-radar__chip--active': selectedIndustryId === item.id }"
|
||||||
|
@click="selectIndustry(item.id)"
|
||||||
|
>{{ item.name }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 城市筛选行 -->
|
||||||
|
<div class="home-job-radar__filter-row">
|
||||||
|
<span class="home-job-radar__filter-label">城市</span>
|
||||||
|
<div class="home-job-radar__filter-chips">
|
||||||
|
<span
|
||||||
|
class="home-job-radar__chip"
|
||||||
|
:class="{ 'home-job-radar__chip--active': selectedCityCode === null }"
|
||||||
|
@click="selectCity(null)"
|
||||||
|
>全部</span>
|
||||||
|
<span
|
||||||
|
v-for="item in hotCities"
|
||||||
|
:key="'city-' + item.code"
|
||||||
|
class="home-job-radar__chip"
|
||||||
|
:class="{ 'home-job-radar__chip--active': selectedCityCode === item.code }"
|
||||||
|
@click="selectCity(item.code)"
|
||||||
|
>{{ item.name }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 岗位筛选行 -->
|
||||||
|
<div class="home-job-radar__filter-row">
|
||||||
|
<span class="home-job-radar__filter-label">岗位</span>
|
||||||
|
<div class="home-job-radar__filter-chips">
|
||||||
|
<span
|
||||||
|
class="home-job-radar__chip"
|
||||||
|
:class="{ 'home-job-radar__chip--active': selectedCategoryId === null }"
|
||||||
|
@click="selectCategory(null)"
|
||||||
|
>全部</span>
|
||||||
|
<span
|
||||||
|
v-for="item in hotCategories"
|
||||||
|
:key="'cat-' + item.id"
|
||||||
|
class="home-job-radar__chip"
|
||||||
|
:class="{ 'home-job-radar__chip--active': selectedCategoryId === item.id }"
|
||||||
|
@click="selectCategory(item.id)"
|
||||||
|
>{{ item.name }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 岗位列表网格 -->
|
||||||
|
<div class="home-job-radar__grid">
|
||||||
|
<div
|
||||||
|
v-for="(job, index) in jobList"
|
||||||
|
:key="index"
|
||||||
|
class="home-job-radar__card"
|
||||||
|
@click="goToDetail(job)"
|
||||||
|
>
|
||||||
|
<!-- 上半部分:岗位标题 + 标签 -->
|
||||||
|
<div class="home-job-radar__card-top">
|
||||||
|
<div class="home-job-radar__card-title">{{ job.title }}</div>
|
||||||
|
<div class="home-job-radar__card-tags">
|
||||||
|
<span v-if="job.regionName" class="home-job-radar__card-tag">{{ job.regionName }}</span>
|
||||||
|
<span v-if="formatEmploymentType(job.recruitCategory)" class="home-job-radar__card-tag">{{ formatEmploymentType(job.recruitCategory) }}</span>
|
||||||
|
<span v-if="formatEducation(job.education)" class="home-job-radar__card-tag">{{ formatEducation(job.education) }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 下半部分:公司信息 + 发布时间 -->
|
||||||
|
<div class="home-job-radar__card-bottom">
|
||||||
|
<div class="home-job-radar__card-company">
|
||||||
|
<img v-if="job.companyLogoUrl" class="home-job-radar__card-logo" :src="job.companyLogoUrl" alt="" />
|
||||||
|
<div v-else class="home-job-radar__card-logo home-job-radar__card-logo--default">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"><rect width="24" height="24" rx="12" fill="#EDF9FA"/><g clip-path="url(#clogo2)"><path d="M5.99998 16.6667H6.66665V8.24001C6.66667 8.0301 6.73274 7.82552 6.8555 7.65526C6.97827 7.48499 7.15149 7.35767 7.35065 7.29134L12.684 5.51401C12.8343 5.46395 12.9943 5.45031 13.1509 5.47423C13.3076 5.49815 13.4562 5.55893 13.5848 5.65157C13.7133 5.74421 13.8179 5.86606 13.8901 6.00708C13.9623 6.1481 14 6.30425 14 6.46268V16.6667H14.6666V10.66C14.6667 10.6107 14.6776 10.562 14.6987 10.5175C14.7199 10.4729 14.7506 10.4336 14.7887 10.4024C14.8268 10.3711 14.8714 10.3487 14.9193 10.3368C14.9671 10.3249 15.017 10.3237 15.0653 10.3333L16.5293 10.6267C16.7559 10.672 16.9599 10.7944 17.1064 10.973C17.253 11.1517 17.3332 11.3756 17.3333 11.6067V16.6667H18C18.1768 16.6667 18.3464 16.7369 18.4714 16.8619C18.5964 16.987 18.6666 17.1565 18.6666 17.3333C18.6666 17.5102 18.5964 17.6797 18.4714 17.8047C18.3464 17.9298 18.1768 18 18 18H5.99998C5.82317 18 5.6536 17.9298 5.52858 17.8047C5.40355 17.6797 5.33331 17.5102 5.33331 17.3333C5.33331 17.1565 5.40355 16.987 5.52858 16.8619C5.6536 16.7369 5.82317 16.6667 5.99998 16.6667Z" fill="#52CAD1"/></g><defs><clipPath id="clogo2"><rect width="16" height="16" fill="white" transform="translate(4 4)"/></clipPath></defs></svg>
|
||||||
|
</div>
|
||||||
|
<span class="home-job-radar__card-company-name">{{ job.companyShortName || job.companyName }}</span>
|
||||||
|
<span v-if="job.companyType" class="home-job-radar__card-company-type">{{ job.companyType }}</span>
|
||||||
|
</div>
|
||||||
|
<span class="home-job-radar__card-time">{{ formatExpireAt(job.expireAt) }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 加载中 -->
|
||||||
|
<div v-if="loading" class="home-job-radar__loading">
|
||||||
|
<div class="home-job-radar__spinner"></div>
|
||||||
|
<span>加载中...</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 查看更多按钮 -->
|
||||||
|
<div v-if="!loading && jobList.length > 0" class="home-job-radar__more">
|
||||||
|
<button class="home-job-radar__more-btn" @click="router.push('/jobs')">查看更多</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- 第二部分:CTA区域 -->
|
||||||
|
<section class="home-cta">
|
||||||
|
<div class="home-cta__inner">
|
||||||
|
<h2>让Offer派带你找到<br/>人生第一份好工作</h2>
|
||||||
|
<button class="home-cta__btn" @click="router.push('/jobs')">免费体验</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, watch } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { fetchJobList, fetchHotIndustries, fetchHotCategories, fetchHotCities } from '@/api/jobs'
|
||||||
|
import type { JobListItem, HotIndustryItem, HotCategoryItem, HotCityItem } from '@/api/jobs'
|
||||||
|
import { formatEmploymentType, formatEducation } from '@/stores/index'
|
||||||
|
|
||||||
|
/** 路由实例 */
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
// ==================== 筛选数据 ====================
|
||||||
|
|
||||||
|
/** 热门行业列表 */
|
||||||
|
const hotIndustries = ref<HotIndustryItem[]>([])
|
||||||
|
/** 热门城市列表 */
|
||||||
|
const hotCities = ref<HotCityItem[]>([])
|
||||||
|
/** 热门岗位列表 */
|
||||||
|
const hotCategories = ref<HotCategoryItem[]>([])
|
||||||
|
|
||||||
|
/** 当前选中的行业ID(null=全部) */
|
||||||
|
const selectedIndustryId = ref<number | null>(null)
|
||||||
|
/** 当前选中的城市编码(null=全部) */
|
||||||
|
const selectedCityCode = ref<string | null>(null)
|
||||||
|
/** 当前选中的岗位ID(null=全部) */
|
||||||
|
const selectedCategoryId = ref<number | null>(null)
|
||||||
|
|
||||||
|
// ==================== 岗位列表 ====================
|
||||||
|
|
||||||
|
/** 岗位列表数据 */
|
||||||
|
const jobList = ref<JobListItem[]>([])
|
||||||
|
/** 加载状态 */
|
||||||
|
const loading = ref(false)
|
||||||
|
|
||||||
|
/** 选择行业 */
|
||||||
|
function selectIndustry(id: number | null) {
|
||||||
|
selectedIndustryId.value = id
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 选择城市 */
|
||||||
|
function selectCity(code: string | null) {
|
||||||
|
selectedCityCode.value = code
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 选择岗位分类 */
|
||||||
|
function selectCategory(id: number | null) {
|
||||||
|
selectedCategoryId.value = id
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 加载岗位列表 */
|
||||||
|
async function loadJobList() {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const params: any = {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 30,
|
||||||
|
}
|
||||||
|
if (selectedIndustryId.value !== null) {
|
||||||
|
params.industryIds = [selectedIndustryId.value]
|
||||||
|
}
|
||||||
|
if (selectedCityCode.value !== null) {
|
||||||
|
params.regionCodes = [selectedCityCode.value]
|
||||||
|
}
|
||||||
|
if (selectedCategoryId.value !== null) {
|
||||||
|
params.categoryIds = [selectedCategoryId.value]
|
||||||
|
}
|
||||||
|
const res = await fetchJobList(params)
|
||||||
|
if (res.code === '0' && res.data) {
|
||||||
|
jobList.value = res.data.list || []
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('加载岗位列表失败', e)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 格式化发布时间 */
|
||||||
|
function formatExpireAt(expireAt?: string | null): string {
|
||||||
|
if (!expireAt) return ''
|
||||||
|
try {
|
||||||
|
const date = new Date(expireAt)
|
||||||
|
if (isNaN(date.getTime())) return ''
|
||||||
|
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||||||
|
const day = String(date.getDate()).padStart(2, '0')
|
||||||
|
return `${month}-${day}更新`
|
||||||
|
} catch {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 跳转到岗位详情 */
|
||||||
|
function goToDetail(job: JobListItem) {
|
||||||
|
router.push({ path: `/jobs/${job.id}`, query: { from: 'home' } })
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 加载热门筛选数据 */
|
||||||
|
async function loadHotFilters() {
|
||||||
|
try {
|
||||||
|
const [indRes, cityRes, catRes] = await Promise.all([
|
||||||
|
fetchHotIndustries(),
|
||||||
|
fetchHotCities(),
|
||||||
|
fetchHotCategories(),
|
||||||
|
])
|
||||||
|
if (indRes.code === '0' && indRes.data) hotIndustries.value = indRes.data
|
||||||
|
if (cityRes.code === '0' && cityRes.data) hotCities.value = cityRes.data
|
||||||
|
if (catRes.code === '0' && catRes.data) hotCategories.value = catRes.data
|
||||||
|
} catch (e) {
|
||||||
|
console.error('加载热门筛选数据失败', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听筛选条件变化,刷新列表
|
||||||
|
watch([selectedIndustryId, selectedCityCode, selectedCategoryId], () => {
|
||||||
|
loadJobList()
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loadHotFilters()
|
||||||
|
loadJobList()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,324 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 求职辅导Tab内容 -->
|
||||||
|
<div class="home-mentor">
|
||||||
|
<!-- 第一部分:找到真正懂行业的求职导师 -->
|
||||||
|
<section class="home-mentor__section">
|
||||||
|
<div class="home-mentor__header">
|
||||||
|
<h2 class="home-mentor__title">找到真正懂行业的求职导师</h2>
|
||||||
|
<p class="home-mentor__subtitle">连接名企在职导师,获取来自真实职场的一对一求职指导与经验分享</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 行业分类Tab -->
|
||||||
|
<div class="home-mentor__tabs">
|
||||||
|
<span
|
||||||
|
v-for="(tab, index) in industryTabs"
|
||||||
|
:key="index"
|
||||||
|
class="home-mentor__tab"
|
||||||
|
:class="{ 'home-mentor__tab--active': activeTab === index }"
|
||||||
|
@click="handleTabChange(index)"
|
||||||
|
>{{ tab }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 导师列表滚动容器 -->
|
||||||
|
<div ref="listWrapRef" class="home-mentor__list-wrap scrollbar-thin" @scroll="onListScroll">
|
||||||
|
<!-- 导师列表 -->
|
||||||
|
<div class="home-mentor__list">
|
||||||
|
<div
|
||||||
|
v-for="mentor in mentorList"
|
||||||
|
:key="mentor.id"
|
||||||
|
class="home-mentor__card"
|
||||||
|
@click="goToDetail(mentor)"
|
||||||
|
>
|
||||||
|
<!-- 左侧:头像 + 基本信息 -->
|
||||||
|
<div class="home-mentor__card-left">
|
||||||
|
<!-- 头像 -->
|
||||||
|
<div class="home-mentor__avatar-wrap">
|
||||||
|
<img
|
||||||
|
v-if="mentor.picture"
|
||||||
|
:src="toOssUrl(mentor.picture)"
|
||||||
|
class="home-mentor__avatar"
|
||||||
|
:alt="mentor.platformName"
|
||||||
|
/>
|
||||||
|
<div v-else class="home-mentor__avatar-placeholder">
|
||||||
|
{{ mentor.platformName?.charAt(0) || '师' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 导师基本信息 -->
|
||||||
|
<div class="home-mentor__card-info">
|
||||||
|
<div class="home-mentor__card-name-row">
|
||||||
|
<span class="home-mentor__card-name">{{ mentor.platformName }}</span>
|
||||||
|
<span v-if="mentor.agencyName" class="home-mentor__card-meta">
|
||||||
|
<img v-if="mentor.agencyLogo" :src="toOssUrl(mentor.agencyLogo)" class="home-mentor__card-agency-logo" alt="" />
|
||||||
|
{{ mentor.agencyName }}<template v-if="mentor.position">|{{ mentor.position }}</template>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<!-- 标签列表 -->
|
||||||
|
<div class="home-mentor__card-labels" v-if="mentor.labels && mentor.labels.length">
|
||||||
|
<span
|
||||||
|
v-for="(label, li) in mentor.labels.slice(0, 6)"
|
||||||
|
:key="li"
|
||||||
|
class="home-mentor__card-label"
|
||||||
|
>{{ label }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 右侧:话题 + 查看详情 -->
|
||||||
|
<div class="home-mentor__card-right">
|
||||||
|
<!-- 话题列表 -->
|
||||||
|
<div class="home-mentor__card-topics">
|
||||||
|
<div
|
||||||
|
v-for="(title, ti) in mentor.titles.slice(0, 3)"
|
||||||
|
:key="ti"
|
||||||
|
class="home-mentor__card-topic"
|
||||||
|
><span class="color-accent">#</span> {{ title }}</div>
|
||||||
|
</div>
|
||||||
|
<!-- 查看详情按钮 -->
|
||||||
|
<button class="home-mentor__detail-btn">
|
||||||
|
<span>查看详情</span>
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.51612 4.07575C7.38279 3.94242 7.31879 3.78686 7.32412 3.60908C7.32945 3.43131 7.39901 3.27575 7.53278 3.14241C7.66612 3.02019 7.82167 2.95619 7.99946 2.95041C8.17723 2.94464 8.33278 3.00864 8.46612 3.14241L12.8661 7.54241C12.9328 7.60908 12.9801 7.6813 13.0081 7.75908C13.0361 7.83686 13.0497 7.92019 13.0488 8.00908C13.0479 8.09797 13.0339 8.18131 13.0068 8.25908C12.9797 8.33686 12.9326 8.40908 12.8654 8.47575L8.46545 12.8757C8.34323 12.998 8.19034 13.0591 8.00679 13.0591C7.82323 13.0591 7.66501 12.998 7.53212 12.8757C7.39879 12.7424 7.33212 12.584 7.33212 12.4004C7.33212 12.2169 7.39879 12.0586 7.53212 11.9257L10.7828 8.67575H3.33279C3.1439 8.67575 2.98546 8.61175 2.85745 8.48375C2.72945 8.35575 2.66567 8.19753 2.66612 8.00908C2.66656 7.82064 2.73056 7.6622 2.85812 7.53375C2.98568 7.40531 3.1439 7.34153 3.33279 7.34242L10.7828 7.34242L7.51612 4.07575Z" fill="currentColor"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 加载中提示 -->
|
||||||
|
<div v-if="loading" class="home-mentor__loading">
|
||||||
|
<div class="home-mentor__spinner"></div>
|
||||||
|
<span>加载中...</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 加载更多中 -->
|
||||||
|
<div v-if="loadingMore" class="home-mentor__loading">
|
||||||
|
<div class="home-mentor__spinner"></div>
|
||||||
|
<span>加载中...</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 没有更多数据 -->
|
||||||
|
<div v-if="noMore && mentorList.length > 0" class="home-mentor__no-more">没有更多导师了</div>
|
||||||
|
|
||||||
|
<!-- 空列表 -->
|
||||||
|
<div v-if="!loading && mentorList.length === 0" class="home-mentor__empty">
|
||||||
|
暂无相关导师
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- 第二部分:CTA区域 -->
|
||||||
|
<section class="home-cta">
|
||||||
|
<div class="home-cta__inner">
|
||||||
|
<h2>让Offer派带你找到<br/>人生第一份好工作</h2>
|
||||||
|
<button class="home-cta__btn" @click="goToMentorPage">免费体验</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed, onMounted, nextTick } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { useStore } from 'vuex'
|
||||||
|
import { fetchMentorList } from '@/api/mentor'
|
||||||
|
import type { MentorItem, MentorListParams } from '@/api/mentor'
|
||||||
|
import { toOssUrl } from '@/utils/image'
|
||||||
|
|
||||||
|
/** 路由实例 */
|
||||||
|
const router = useRouter()
|
||||||
|
/** Vuex Store */
|
||||||
|
const store = useStore()
|
||||||
|
|
||||||
|
// ==================== 行业 Tab 数据 ====================
|
||||||
|
|
||||||
|
/** 行业 Tab 标签列表 */
|
||||||
|
const industryTabs = ['推荐', '互联网', '金融', '快消', '咨询', '央国企', '硬科技', '生涯规划', '名校导师', '心理咨询', '其他']
|
||||||
|
|
||||||
|
/** 当前选中的 Tab 索引 */
|
||||||
|
const activeTab = ref(0)
|
||||||
|
|
||||||
|
/** 生成 min~max 之间的整数数组 */
|
||||||
|
function createIntegerRange(min: number, max: number): number[] {
|
||||||
|
min = Math.floor(min)
|
||||||
|
max = Math.floor(max)
|
||||||
|
if (min > max) return []
|
||||||
|
const result: number[] = []
|
||||||
|
for (let i = min; i <= max; i++) result.push(i)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 根据当前 Tab 计算 industryIds 参数 */
|
||||||
|
const industryIds = computed<number[]>(() => {
|
||||||
|
if (activeTab.value === 0) return []
|
||||||
|
if (activeTab.value === 1) return createIntegerRange(1000, 1016)
|
||||||
|
if (activeTab.value === 2) return createIntegerRange(1131, 1139)
|
||||||
|
if (activeTab.value === 3) return createIntegerRange(1038, 1047)
|
||||||
|
if (activeTab.value === 4) return createIntegerRange(1087, 1093)
|
||||||
|
if (activeTab.value === 5) return []
|
||||||
|
if (activeTab.value === 6) return [
|
||||||
|
1012, 1014, 1017, 1018, 1019, 1020, 1021, 1022, 1023,
|
||||||
|
1074, 1078, 1079, 1084, 1085,
|
||||||
|
1095, 1097, 1098,
|
||||||
|
1119, 1120, 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, 1130,
|
||||||
|
]
|
||||||
|
if (activeTab.value === 7) return []
|
||||||
|
if (activeTab.value === 8) return []
|
||||||
|
if (activeTab.value === 9) return []
|
||||||
|
if (activeTab.value === 10) {
|
||||||
|
const all = createIntegerRange(1000, 1143)
|
||||||
|
const used = new Set([
|
||||||
|
...createIntegerRange(1000, 1016),
|
||||||
|
...createIntegerRange(1131, 1139),
|
||||||
|
...createIntegerRange(1038, 1047),
|
||||||
|
...createIntegerRange(1087, 1093),
|
||||||
|
1012, 1014, 1017, 1018, 1019, 1020, 1021, 1022, 1023,
|
||||||
|
1074, 1078, 1079, 1084, 1085,
|
||||||
|
1095, 1097, 1098,
|
||||||
|
1119, 1120, 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, 1130,
|
||||||
|
])
|
||||||
|
return all.filter(id => !used.has(id))
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
})
|
||||||
|
|
||||||
|
/** 根据当前 Tab 计算机构类型 type 参数 */
|
||||||
|
const mentorType = computed<string | null>(() => {
|
||||||
|
return activeTab.value === 5 ? '央国企' : null
|
||||||
|
})
|
||||||
|
|
||||||
|
/** 根据当前 Tab 计算身份类型 identityType 参数 */
|
||||||
|
const identityType = computed<number | null>(() => {
|
||||||
|
if (activeTab.value === 5) return 0
|
||||||
|
if (activeTab.value === 7) return 1
|
||||||
|
if (activeTab.value === 8) return 4
|
||||||
|
if (activeTab.value === 9) return 2
|
||||||
|
return null
|
||||||
|
})
|
||||||
|
|
||||||
|
// ==================== 列表数据 ====================
|
||||||
|
|
||||||
|
/** 导师列表数据 */
|
||||||
|
const mentorList = ref<MentorItem[]>([])
|
||||||
|
/** 加载状态(首次加载) */
|
||||||
|
const loading = ref(false)
|
||||||
|
/** 加载更多状态 */
|
||||||
|
const loadingMore = ref(false)
|
||||||
|
/** 当前页码 */
|
||||||
|
const pageNum = ref(1)
|
||||||
|
/** 每页条数 */
|
||||||
|
const pageSize = ref(20)
|
||||||
|
/** 是否没有更多数据 */
|
||||||
|
const noMore = ref(false)
|
||||||
|
/** 列表滚动容器 ref */
|
||||||
|
const listWrapRef = ref<HTMLElement | null>(null)
|
||||||
|
|
||||||
|
/** 构建接口请求参数 */
|
||||||
|
function buildParams(): MentorListParams {
|
||||||
|
const params: MentorListParams = {
|
||||||
|
page: pageNum.value,
|
||||||
|
pageSize: pageSize.value,
|
||||||
|
sort: 0,
|
||||||
|
}
|
||||||
|
if (industryIds.value.length) params.industryIds = industryIds.value
|
||||||
|
if (mentorType.value !== null) params.type = mentorType.value
|
||||||
|
if (identityType.value !== null) params.identityType = identityType.value
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 加载导师列表(首次加载) */
|
||||||
|
async function loadMentors() {
|
||||||
|
loading.value = true
|
||||||
|
pageNum.value = 1
|
||||||
|
noMore.value = false
|
||||||
|
mentorList.value = []
|
||||||
|
try {
|
||||||
|
const res: any = await fetchMentorList(buildParams())
|
||||||
|
const pageData = res?.data ?? res
|
||||||
|
const records = pageData?.records ?? []
|
||||||
|
mentorList.value = records
|
||||||
|
if (records.length < pageSize.value) {
|
||||||
|
noMore.value = true
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[首页导师列表] 加载失败', e)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
nextTick(() => { autoFillIfNeeded() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 加载下一页 */
|
||||||
|
async function loadNextPage() {
|
||||||
|
if (loadingMore.value || noMore.value) return
|
||||||
|
loadingMore.value = true
|
||||||
|
pageNum.value++
|
||||||
|
try {
|
||||||
|
const res: any = await fetchMentorList(buildParams())
|
||||||
|
const pageData = res?.data ?? res
|
||||||
|
const records = pageData?.records ?? []
|
||||||
|
if (records.length === 0) {
|
||||||
|
noMore.value = true
|
||||||
|
pageNum.value--
|
||||||
|
} else {
|
||||||
|
mentorList.value.push(...records)
|
||||||
|
if (records.length < pageSize.value) {
|
||||||
|
noMore.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
pageNum.value--
|
||||||
|
console.error('[首页导师列表] 加载下一页失败', e)
|
||||||
|
} finally {
|
||||||
|
loadingMore.value = false
|
||||||
|
nextTick(() => { autoFillIfNeeded() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 自动填满容器:内容不足以滚动时自动加载下一页 */
|
||||||
|
function autoFillIfNeeded() {
|
||||||
|
const el = listWrapRef.value
|
||||||
|
if (!el) return
|
||||||
|
if (el.scrollHeight <= el.clientHeight && !noMore.value && !loadingMore.value && !loading.value) {
|
||||||
|
loadNextPage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 列表滚动事件 — 触底自动加载 */
|
||||||
|
function onListScroll() {
|
||||||
|
const el = listWrapRef.value
|
||||||
|
if (!el) return
|
||||||
|
if (el.scrollHeight - el.scrollTop - el.clientHeight < 100) {
|
||||||
|
loadNextPage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 切换行业 Tab */
|
||||||
|
function handleTabChange(index: number) {
|
||||||
|
if (activeTab.value === index) return
|
||||||
|
activeTab.value = index
|
||||||
|
loadMentors()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 点击查看详情 — 需要登录验证 */
|
||||||
|
function goToDetail(mentor: MentorItem) {
|
||||||
|
if (!store.state.isAuthenticated) {
|
||||||
|
store.dispatch('openLogin', `/mentor/${mentor.id}`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
router.push({ path: `/mentor/${mentor.id}`, query: { price: String(mentor.price), from: 'home' } })
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 跳转导师页面 — 需要登录验证 */
|
||||||
|
function goToMentorPage() {
|
||||||
|
if (!store.state.isAuthenticated) {
|
||||||
|
store.dispatch('openLogin', '/mentor')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
router.push('/mentor')
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loadMentors()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -409,11 +409,11 @@ const mainMenus = computed<MenuItem[]>(() => {
|
|||||||
const showShareDialog = ref(false)
|
const showShareDialog = ref(false)
|
||||||
|
|
||||||
/** 是否为窄版导航(窗口宽度 < 1440px) */
|
/** 是否为窄版导航(窗口宽度 < 1440px) */
|
||||||
const isNarrow = ref(window.innerWidth < 1440)
|
const isNarrow = ref(window.innerWidth < 6440)
|
||||||
|
|
||||||
/** 监听窗口宽度变化,动态切换窄版/宽版 */
|
/** 监听窗口宽度变化,动态切换窄版/宽版 */
|
||||||
function handleNavResize() {
|
function handleNavResize() {
|
||||||
isNarrow.value = window.innerWidth < 1440
|
isNarrow.value = window.innerWidth < 6440
|
||||||
}
|
}
|
||||||
const showMessageDialog = ref(false)
|
const showMessageDialog = ref(false)
|
||||||
const showFeedbackDialog = ref(false)
|
const showFeedbackDialog = ref(false)
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ const remAdaptPlugin: Plugin = {
|
|||||||
docEl.style.setProperty('--app-height', '100vh')
|
docEl.style.setProperty('--app-height', '100vh')
|
||||||
docEl.style.setProperty('--chat-width', '3.6rem')
|
docEl.style.setProperty('--chat-width', '3.6rem')
|
||||||
// 根据窗口宽度设置导航栏宽度CSS变量
|
// 根据窗口宽度设置导航栏宽度CSS变量
|
||||||
const navWidth = window.innerWidth < 1440 ? '0.8rem' : '2.2rem'
|
const navWidth = window.innerWidth < 6440 ? '0.8rem' : '2.2rem'
|
||||||
docEl.style.setProperty('--nav-width', navWidth)
|
docEl.style.setProperty('--nav-width', navWidth)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+104
-26
@@ -349,7 +349,7 @@ import JobStatsOverview from '@/components/JobStatsOverview.vue'
|
|||||||
import IndustrySelector from '@/components/tools/IndustrySelector.vue'
|
import IndustrySelector from '@/components/tools/IndustrySelector.vue'
|
||||||
import JobCategorySelector from '@/components/tools/JobCategorySelector.vue'
|
import JobCategorySelector from '@/components/tools/JobCategorySelector.vue'
|
||||||
import RegionSelector from '@/components/tools/RegionSelector.vue'
|
import RegionSelector from '@/components/tools/RegionSelector.vue'
|
||||||
import { fetchAnnouncementList } from '@/api/announcement'
|
import { fetchAnnouncementList, fetchAnnouncementLastUpdateTime, fetchAnnouncementStatistics, fetchAnnouncementRecruitYearTags, fetchAnnouncementEducationOptions, fetchAnnouncementBatchOptions } from '@/api/announcement'
|
||||||
import type { AnnouncementListParams, AnnouncementItem } from '@/api/announcement'
|
import type { AnnouncementListParams, AnnouncementItem } from '@/api/announcement'
|
||||||
import { fetchHotIndustries, fetchHotCategories, fetchHotCities } from '@/api/jobs'
|
import { fetchHotIndustries, fetchHotCategories, fetchHotCities } from '@/api/jobs'
|
||||||
import type { HotIndustryItem, HotCategoryItem, HotCityItem } from '@/api/jobs'
|
import type { HotIndustryItem, HotCategoryItem, HotCityItem } from '@/api/jobs'
|
||||||
@@ -378,20 +378,41 @@ let filtersPanelObserver: ResizeObserver | null = null
|
|||||||
|
|
||||||
// ==================== 统计卡片数据 ====================
|
// ==================== 统计卡片数据 ====================
|
||||||
|
|
||||||
/** 当前日期(MM.DD 格式) */
|
/** 最新更新时间(MM.DD 格式,从后端获取) */
|
||||||
const statsCurrentDate = computed(() => {
|
const statsCurrentDate = ref('--')
|
||||||
const now = new Date()
|
|
||||||
return `${String(now.getMonth() + 1).padStart(2, '0')}.${String(now.getDate()).padStart(2, '0')}`
|
|
||||||
})
|
|
||||||
|
|
||||||
/** 今日新增公告数 */
|
/** 今日新增公告数 */
|
||||||
const statsTodayCount = ref<string | number>('128')
|
const statsTodayCount = ref<string | number>('--')
|
||||||
|
|
||||||
/** 招聘中企业数 */
|
/** 招聘中企业数(累计公告数) */
|
||||||
const statsTotalCompany = ref<string | number>('326')
|
const statsTotalCompany = ref<string | number>('--')
|
||||||
|
|
||||||
/** 近7日截止数 */
|
/** 近7日截止数(本月新增) */
|
||||||
const statsDeadline7days = ref<string | number>('42')
|
const statsDeadline7days = ref<string | number>('--')
|
||||||
|
|
||||||
|
/** 加载统计卡片数据 */
|
||||||
|
async function loadStatsData() {
|
||||||
|
try {
|
||||||
|
// 并发请求最新更新时间和统计数据
|
||||||
|
const [timeRes, statsRes] = await Promise.all([
|
||||||
|
fetchAnnouncementLastUpdateTime(),
|
||||||
|
fetchAnnouncementStatistics(),
|
||||||
|
])
|
||||||
|
// 解析最新更新时间(毫秒时间戳转 MM.DD)
|
||||||
|
if (timeRes.code === '0' && timeRes.data) {
|
||||||
|
const date = new Date(Number(timeRes.data))
|
||||||
|
statsCurrentDate.value = `${String(date.getMonth() + 1).padStart(2, '0')}.${String(date.getDate()).padStart(2, '0')}`
|
||||||
|
}
|
||||||
|
// 解析统计数据
|
||||||
|
if (statsRes.code === '0' && statsRes.data) {
|
||||||
|
statsTodayCount.value = statsRes.data.dayCount ?? 0
|
||||||
|
statsTotalCompany.value = statsRes.data.totalCount ?? 0
|
||||||
|
statsDeadline7days.value = statsRes.data.monthCount ?? 0
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('加载统计数据失败', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ==================== 热门分类数据 ====================
|
// ==================== 热门分类数据 ====================
|
||||||
|
|
||||||
@@ -467,25 +488,56 @@ const showBatchDropdown = ref(false)
|
|||||||
|
|
||||||
// ==================== 筛选选项常量 ====================
|
// ==================== 筛选选项常量 ====================
|
||||||
|
|
||||||
/** 毕业年份选项 */
|
/** 毕业年份选项(从后端接口获取) */
|
||||||
const recruitYearOptions = computed(() => {
|
const recruitYearOptions = ref<{ label: string; value: number }[]>([{ label: '全部', value: 0 }])
|
||||||
const currentYear = new Date().getFullYear()
|
|
||||||
return [
|
|
||||||
{ label: '全部', value: 0 },
|
|
||||||
{ label: `${currentYear}届`, value: currentYear },
|
|
||||||
{ label: `${currentYear + 1}届`, value: currentYear + 1 },
|
|
||||||
{ label: `${currentYear + 2}届`, value: currentYear + 2 },
|
|
||||||
]
|
|
||||||
})
|
|
||||||
|
|
||||||
/** 学历要求选项 */
|
/** 加载毕业年份标签 */
|
||||||
const educationOptions = ['不限', '大专及以上', '本科及以上', '硕士及以上', '博士及以上']
|
async function loadRecruitYearTags() {
|
||||||
|
try {
|
||||||
|
const res = await fetchAnnouncementRecruitYearTags()
|
||||||
|
if (res.code === '0' && res.data) {
|
||||||
|
recruitYearOptions.value = [
|
||||||
|
{ label: '全部', value: 0 },
|
||||||
|
...res.data.map((year: number) => ({ label: `${year}届`, value: year })),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('加载毕业年份标签失败', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 学历要求选项(从后端接口获取) */
|
||||||
|
const educationOptions = ref<string[]>(['不限'])
|
||||||
|
|
||||||
|
/** 加载学历筛选选项 */
|
||||||
|
async function loadEducationOptions() {
|
||||||
|
try {
|
||||||
|
const res = await fetchAnnouncementEducationOptions()
|
||||||
|
if (res.code === '0' && res.data) {
|
||||||
|
educationOptions.value = ['不限', ...res.data]
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('加载学历选项失败', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** 公司类型选项 */
|
/** 公司类型选项 */
|
||||||
const companyTypeOptions = ['全部', '央企', '国企', '上市企业', '外资企业', '民营企业', '事业单位']
|
const companyTypeOptions = ['全部', '央企', '国企', '上市企业', '外资企业', '民营企业', '事业单位']
|
||||||
|
|
||||||
/** 招聘批次选项 */
|
/** 招聘批次选项(从后端接口获取) */
|
||||||
const batchOptions = ['全部', '秋招正式批', '秋招提前批', '春招正式批', '春招补录', '暑期实习']
|
const batchOptions = ref<string[]>(['全部'])
|
||||||
|
|
||||||
|
/** 加载招聘批次选项 */
|
||||||
|
async function loadBatchOptions() {
|
||||||
|
try {
|
||||||
|
const res = await fetchAnnouncementBatchOptions()
|
||||||
|
if (res.code === '0' && res.data) {
|
||||||
|
batchOptions.value = ['全部', ...res.data]
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('加载招聘批次选项失败', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** 热门搜索标签 */
|
/** 热门搜索标签 */
|
||||||
const hotSearchTags = ref(['系统集成', 'AI产品经理', '广告投放', 'AI开发', '大模型'])
|
const hotSearchTags = ref(['系统集成', 'AI产品经理', '广告投放', 'AI开发', '大模型'])
|
||||||
@@ -806,7 +858,7 @@ const selectorDisplayStyle: Record<string, string> = {
|
|||||||
const pageNum = ref(1)
|
const pageNum = ref(1)
|
||||||
|
|
||||||
/** 每页条数 */
|
/** 每页条数 */
|
||||||
const pageSize = ref(10)
|
const pageSize = ref(15)
|
||||||
|
|
||||||
/** 总记录数 */
|
/** 总记录数 */
|
||||||
const total = ref(0)
|
const total = ref(0)
|
||||||
@@ -867,6 +919,8 @@ async function loadList() {
|
|||||||
console.error('加载校招公告列表失败', e)
|
console.error('加载校招公告列表失败', e)
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
|
// 首次加载后检查是否需要自动填满容器
|
||||||
|
nextTick(() => { autoFillIfNeeded() })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -892,6 +946,18 @@ async function loadNextPage() {
|
|||||||
console.error('加载下一页失败', e)
|
console.error('加载下一页失败', e)
|
||||||
} finally {
|
} finally {
|
||||||
loadingMore.value = false
|
loadingMore.value = false
|
||||||
|
// 加载下一页后继续检查是否需要填满容器
|
||||||
|
nextTick(() => { autoFillIfNeeded() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 自动填满容器:当列表内容不足以产生滚动条且还有更多数据时,自动加载下一页 */
|
||||||
|
function autoFillIfNeeded() {
|
||||||
|
const el = listRef.value
|
||||||
|
if (!el) return
|
||||||
|
// 如果容器没有滚动条(内容高度不超过可视高度)且还有更多数据未加载
|
||||||
|
if (el.scrollHeight <= el.clientHeight && !noMore.value && !loadingMore.value && !loading.value) {
|
||||||
|
loadNextPage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -969,6 +1035,18 @@ onMounted(() => {
|
|||||||
// 加载热门分类
|
// 加载热门分类
|
||||||
loadHotFilters()
|
loadHotFilters()
|
||||||
|
|
||||||
|
// 加载统计卡片数据(从后端接口获取)
|
||||||
|
loadStatsData()
|
||||||
|
|
||||||
|
// 加载毕业年份标签
|
||||||
|
loadRecruitYearTags()
|
||||||
|
|
||||||
|
// 加载学历筛选选项
|
||||||
|
loadEducationOptions()
|
||||||
|
|
||||||
|
// 加载招聘批次选项
|
||||||
|
loadBatchOptions()
|
||||||
|
|
||||||
// 监听筛选面板高度变化
|
// 监听筛选面板高度变化
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
if (filtersPanelRef.value) {
|
if (filtersPanelRef.value) {
|
||||||
|
|||||||
@@ -57,8 +57,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="announcement-detail__company-tags">
|
<div class="announcement-detail__company-tags">
|
||||||
<span v-if="detail.companyType" class="announcement-detail__tag announcement-detail__tag--type">{{ detail.companyType }}</span>
|
<span v-if="detail.companyType" class="announcement-detail__tag announcement-detail__tag--type">{{ detail.companyType }}</span>
|
||||||
<span v-if="detail.industryNames && detail.industryNames.length" class="announcement-detail__tag announcement-detail__tag--gray">{{ detail.industryNames.join('/') }}</span>
|
<span v-if="detail.categoryNames && detail.categoryNames.length" class="announcement-detail__tag announcement-detail__tag--gray">{{ detail.categoryNames.join('/') }}</span>
|
||||||
<span v-if="companyScaleText" class="announcement-detail__tag announcement-detail__tag--gray">{{ companyScaleText }}</span>
|
<span v-if="detail.companyScale" class="announcement-detail__tag announcement-detail__tag--gray">{{ detail.companyScale}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -159,10 +159,10 @@
|
|||||||
<p class="announcement-detail__section-content">{{ detail.writtenExam }}</p>
|
<p class="announcement-detail__section-content">{{ detail.writtenExam }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="detail.source" class="announcement-detail__section">
|
<!-- <div v-if="detail.source" class="announcement-detail__section">
|
||||||
<h3 class="announcement-detail__section-title">信息来源</h3>
|
<h3 class="announcement-detail__section-title">信息来源</h3>
|
||||||
<p class="announcement-detail__section-content">{{ detail.source }}</p>
|
<p class="announcement-detail__section-content">{{ detail.source }}</p>
|
||||||
</div>
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 右侧边栏 -->
|
<!-- 右侧边栏 -->
|
||||||
@@ -190,6 +190,8 @@
|
|||||||
v-for="(job, idx) in otherJobs"
|
v-for="(job, idx) in otherJobs"
|
||||||
:key="'other-' + idx"
|
:key="'other-' + idx"
|
||||||
class="announcement-detail__job-item"
|
class="announcement-detail__job-item"
|
||||||
|
style="cursor: pointer;"
|
||||||
|
@click="router.push('/jobs/' + job.id)"
|
||||||
>
|
>
|
||||||
<div class="announcement-detail__job-item-main">
|
<div class="announcement-detail__job-item-main">
|
||||||
<span class="announcement-detail__job-item-title">{{ job.title }}</span>
|
<span class="announcement-detail__job-item-title">{{ job.title }}</span>
|
||||||
@@ -231,6 +233,8 @@
|
|||||||
v-for="(rec, idx) in recommendList"
|
v-for="(rec, idx) in recommendList"
|
||||||
:key="'rec-' + idx"
|
:key="'rec-' + idx"
|
||||||
class="announcement-detail__rec-item"
|
class="announcement-detail__rec-item"
|
||||||
|
style="cursor: pointer;"
|
||||||
|
@click="router.push('/announcement/' + rec.id)"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
v-if="rec.logoUrl"
|
v-if="rec.logoUrl"
|
||||||
@@ -263,11 +267,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive, computed, onMounted } from 'vue'
|
import { ref, reactive, computed, onMounted, watch } from 'vue'
|
||||||
import { useRouter, useRoute } from 'vue-router'
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
import SideNav from '@/components/SideNav.vue'
|
import SideNav from '@/components/SideNav.vue'
|
||||||
import { fetchAnnouncementDetail } from '@/api/announcement'
|
import { fetchAnnouncementDetail, fetchAnnouncementRecommend } from '@/api/announcement'
|
||||||
import type { AnnouncementDetail } from '@/api/announcement'
|
import type { AnnouncementDetail, AnnouncementRecommendItem } from '@/api/announcement'
|
||||||
import { fetchJobList } from '@/api/jobs'
|
import { fetchJobList } from '@/api/jobs'
|
||||||
import type { JobListItem } from '@/api/jobs'
|
import type { JobListItem } from '@/api/jobs'
|
||||||
|
|
||||||
@@ -277,7 +281,7 @@ const router = useRouter()
|
|||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
/** 当前公告ID(大数字符串,避免精度丢失) */
|
/** 当前公告ID(大数字符串,避免精度丢失) */
|
||||||
const announcementId = route.params.id as string
|
let announcementId = route.params.id as string
|
||||||
|
|
||||||
// ==================== 页面状态 ====================
|
// ==================== 页面状态 ====================
|
||||||
|
|
||||||
@@ -293,6 +297,7 @@ const detail = reactive<AnnouncementDetail>({
|
|||||||
companyType: '',
|
companyType: '',
|
||||||
title: '',
|
title: '',
|
||||||
companyIntro: '',
|
companyIntro: '',
|
||||||
|
companyScale: '',
|
||||||
targetAudience: '',
|
targetAudience: '',
|
||||||
majorRequire: '',
|
majorRequire: '',
|
||||||
recruitPosition: '',
|
recruitPosition: '',
|
||||||
@@ -303,6 +308,8 @@ const detail = reactive<AnnouncementDetail>({
|
|||||||
applyEndDesc: '',
|
applyEndDesc: '',
|
||||||
inviteCode: '',
|
inviteCode: '',
|
||||||
source: '',
|
source: '',
|
||||||
|
announcementUrl: '',
|
||||||
|
applyUrl: '',
|
||||||
publishTime: null,
|
publishTime: null,
|
||||||
cleanStatus: 0,
|
cleanStatus: 0,
|
||||||
status: 0,
|
status: 0,
|
||||||
@@ -319,8 +326,6 @@ const detail = reactive<AnnouncementDetail>({
|
|||||||
|
|
||||||
// ==================== 计算属性 ====================
|
// ==================== 计算属性 ====================
|
||||||
|
|
||||||
/** 公司规模文本 */
|
|
||||||
const companyScaleText = computed(() => '')
|
|
||||||
|
|
||||||
/** 发布日期格式化文本 */
|
/** 发布日期格式化文本 */
|
||||||
const publishDateText = computed(() => {
|
const publishDateText = computed(() => {
|
||||||
@@ -363,6 +368,7 @@ const recruitCategoryMap: Record<number, string> = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface OtherJobItem {
|
interface OtherJobItem {
|
||||||
|
id: string
|
||||||
title: string
|
title: string
|
||||||
city: string
|
city: string
|
||||||
type: string
|
type: string
|
||||||
@@ -398,6 +404,7 @@ function pickRandomJobs(list: JobListItem[]): OtherJobItem[] {
|
|||||||
return picked.map(job => {
|
return picked.map(job => {
|
||||||
const style = getScoreStyle(job.matchScore ?? 0)
|
const style = getScoreStyle(job.matchScore ?? 0)
|
||||||
return {
|
return {
|
||||||
|
id: job.id,
|
||||||
title: job.title,
|
title: job.title,
|
||||||
city: job.regionName || '',
|
city: job.regionName || '',
|
||||||
type: recruitCategoryMap[job.recruitCategory ?? 3] || '',
|
type: recruitCategoryMap[job.recruitCategory ?? 3] || '',
|
||||||
@@ -418,7 +425,7 @@ async function loadCompanyJobs() {
|
|||||||
const res = await fetchJobList({
|
const res = await fetchJobList({
|
||||||
keyword: detail.companyName,
|
keyword: detail.companyName,
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 100,
|
pageSize: 30,
|
||||||
})
|
})
|
||||||
if (res.code === '0' && res.data?.list) {
|
if (res.code === '0' && res.data?.list) {
|
||||||
companyAllJobs.value = res.data.list
|
companyAllJobs.value = res.data.list
|
||||||
@@ -434,9 +441,10 @@ async function refreshOtherJobs() {
|
|||||||
await loadCompanyJobs()
|
await loadCompanyJobs()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 右侧校招推荐(静态假数据) ====================
|
// ==================== 右侧校招推荐 ====================
|
||||||
|
|
||||||
interface RecommendItem {
|
interface RecommendItem {
|
||||||
|
id: string
|
||||||
logoUrl: string
|
logoUrl: string
|
||||||
companyName: string
|
companyName: string
|
||||||
positions: string
|
positions: string
|
||||||
@@ -444,22 +452,63 @@ interface RecommendItem {
|
|||||||
cities: string
|
cities: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const recommendList = ref<RecommendItem[]>([
|
/** 推荐列表全量缓存(一次请求100条) */
|
||||||
{ logoUrl: '', companyName: '泉峰科技', positions: '产品研发/工程与制造/质量与供应链/销售与市场...', industry: '机械/制造业', cities: '上海市, 南京市' },
|
const recommendAllList = ref<AnnouncementRecommendItem[]>([])
|
||||||
{ logoUrl: '', companyName: '海天集团', positions: '技术类 产品类 设计类岗位', industry: 'IT/互联网/游戏', cities: '北京市, 杭州市' },
|
|
||||||
{ logoUrl: '', companyName: '陕西水务发展集团', positions: '水利水电工程施工设计岗 -A01, 高效节水灌溉设...', industry: '能源/化工/环保', cities: '宝鸡市, 咸阳市, 渭南市...' },
|
|
||||||
{ logoUrl: '', companyName: '陕西水务发展集团', positions: '水利水电工程施工设计岗 -A01, 高效节水灌溉设...', industry: '能源/化工/环保', cities: '宝鸡市, 咸阳市, 渭南市...' },
|
|
||||||
])
|
|
||||||
|
|
||||||
/** 换一批(校招推荐) */
|
/** 当前展示的推荐列表(随机取4条) */
|
||||||
function refreshRecommend() {
|
const recommendList = ref<RecommendItem[]>([])
|
||||||
// 静态展示暂不做切换逻辑
|
|
||||||
|
/**
|
||||||
|
* 从全量推荐列表中随机选取最多4条,转换为展示格式
|
||||||
|
*/
|
||||||
|
function pickRandomRecommend(list: AnnouncementRecommendItem[]): RecommendItem[] {
|
||||||
|
if (!list.length) return []
|
||||||
|
const shuffled = [...list].sort(() => Math.random() - 0.5)
|
||||||
|
const picked = shuffled.slice(0, 4)
|
||||||
|
return picked.map(item => ({
|
||||||
|
id: String(item.id),
|
||||||
|
logoUrl: item.logoUrl || '',
|
||||||
|
companyName: item.companyName || '',
|
||||||
|
positions: item.categoryNames?.join('/') || '',
|
||||||
|
industry: '',
|
||||||
|
cities: item.cityNames?.join(', ') || '',
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载校招推荐列表(请求100条缓存,随机展示4条)
|
||||||
|
*/
|
||||||
|
async function loadRecommendList() {
|
||||||
|
if (!announcementId) return
|
||||||
|
try {
|
||||||
|
const res = await fetchAnnouncementRecommend({
|
||||||
|
announcementId: announcementId,
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 100,
|
||||||
|
})
|
||||||
|
if (res.code === '0' && res.data?.list) {
|
||||||
|
recommendAllList.value = res.data.list
|
||||||
|
recommendList.value = pickRandomRecommend(recommendAllList.value)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('加载校招推荐列表失败', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 换一批(校招推荐)—— 重新请求接口随机展示4条 */
|
||||||
|
async function refreshRecommend() {
|
||||||
|
await loadRecommendList()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 事件处理 ====================
|
// ==================== 事件处理 ====================
|
||||||
|
|
||||||
/** 返回列表页 */
|
/** 返回列表页 */
|
||||||
function goBack() {
|
function goBack() {
|
||||||
|
// 从首页跳转过来时,直接去列表页而非回首页
|
||||||
|
if (route.query.from === 'home') {
|
||||||
|
router.push('/announcement')
|
||||||
|
return
|
||||||
|
}
|
||||||
if (window.history.length > 1) {
|
if (window.history.length > 1) {
|
||||||
router.back()
|
router.back()
|
||||||
} else {
|
} else {
|
||||||
@@ -470,14 +519,14 @@ function goBack() {
|
|||||||
/** 查看公告 */
|
/** 查看公告 */
|
||||||
function handleViewAnnouncement() {
|
function handleViewAnnouncement() {
|
||||||
if (detail.source) {
|
if (detail.source) {
|
||||||
window.open(detail.source, '_blank')
|
window.open(detail.announcementUrl, '_blank')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 投递地址 */
|
/** 投递地址 */
|
||||||
function handleApplyUrl() {
|
function handleApplyUrl() {
|
||||||
if (detail.source) {
|
if (detail.source) {
|
||||||
window.open(detail.source, '_blank')
|
window.open(detail.applyUrl, '_blank')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -490,8 +539,9 @@ async function loadDetail() {
|
|||||||
const res = await fetchAnnouncementDetail(announcementId)
|
const res = await fetchAnnouncementDetail(announcementId)
|
||||||
if (res.code === '0' && res.data) {
|
if (res.code === '0' && res.data) {
|
||||||
Object.assign(detail, res.data)
|
Object.assign(detail, res.data)
|
||||||
// 详情加载完毕后,加载企业其他岗位
|
// 详情加载完毕后,加载企业其他岗位和校招推荐
|
||||||
loadCompanyJobs()
|
loadCompanyJobs()
|
||||||
|
loadRecommendList()
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('加载校招公告详情失败', e)
|
console.error('加载校招公告详情失败', e)
|
||||||
@@ -503,4 +553,15 @@ async function loadDetail() {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadDetail()
|
loadDetail()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 监听路由参数变化(同路由组件内跳转时刷新数据)
|
||||||
|
watch(
|
||||||
|
() => route.params.id,
|
||||||
|
(newId) => {
|
||||||
|
if (newId && newId !== announcementId) {
|
||||||
|
announcementId = newId as string
|
||||||
|
loadDetail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
+59
-552
@@ -1,10 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="home-page">
|
<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 mt0">
|
<header class="home-nav mt0">
|
||||||
<div class="home-nav__inner" :class="{ 'home-nav__inner--scorlled': isScrolled }">
|
<div class="home-nav__inner" :class="{ 'home-nav__inner--scorlled': isScrolled }">
|
||||||
@@ -12,6 +7,18 @@
|
|||||||
<!-- 导航栏Logo图片 -->
|
<!-- 导航栏Logo图片 -->
|
||||||
<img src="@/assets/images/logo.png" alt="Offer派" class="home-nav__logo-img" />
|
<img src="@/assets/images/logo.png" alt="Offer派" class="home-nav__logo-img" />
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 中间Tab导航 -->
|
||||||
|
<div class="home-nav__tabs">
|
||||||
|
<div
|
||||||
|
v-for="tab in navTabs"
|
||||||
|
:key="tab.key"
|
||||||
|
class="home-nav__tab"
|
||||||
|
:class="{ 'home-nav__tab--active': activeTab === tab.key }"
|
||||||
|
@click="activeTab = tab.key"
|
||||||
|
>
|
||||||
|
<span>{{ tab.label }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="dflex-end aliite-c">
|
<div class="dflex-end aliite-c">
|
||||||
<!-- 未登录时显示登录和立即加入按钮 -->
|
<!-- 未登录时显示登录和立即加入按钮 -->
|
||||||
<div v-if="!store.state.isAuthenticated" class="fs14 color-1 mr40 fw600 cursor-po" @click="handleLoginClick">登录</div>
|
<div v-if="!store.state.isAuthenticated" class="fs14 color-1 mr40 fw600 cursor-po" @click="handleLoginClick">登录</div>
|
||||||
@@ -21,430 +28,23 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<div class="home-hero__inner">
|
|
||||||
<div class="home-hero__left">
|
|
||||||
<h1 class="home-hero__title">Offer派,<br/><span class="dib"></span>收offer就是快!</h1>
|
|
||||||
<p class="home-hero__desc">智能匹配职位、自动填写申请、量身定制简历、推荐内部人脉——<br/>不到1分钟,统统搞定!</p>
|
|
||||||
<button class="home-hero__cta" @click="router.push('/jobs')">免费体验</button>
|
|
||||||
</div>
|
|
||||||
<!-- 右侧视频展示区 -->
|
|
||||||
<div class="home-hero__right">
|
|
||||||
<!-- <div class="home-hero__right-top">-->
|
|
||||||
<!-- <div></div>-->
|
|
||||||
<!-- <div></div>-->
|
|
||||||
<!-- <div></div>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- <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>
|
|
||||||
<img class="w706 h452" src="@/assets/images/home/home-top.gif" alt="">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</section>
|
<!-- Tab内容区域 -->
|
||||||
|
<component :is="activeTabComponent" />
|
||||||
|
|
||||||
<!-- Stats Section -->
|
<!-- CTA Section(首页tab内容自带,岗位雷达自带,校招公告自带,求职辅导自带,其他tab也复用) -->
|
||||||
<section class="home-stats">
|
<section v-if="activeTab !== 'home' && activeTab !== 'jobRadar' && activeTab !== 'announcement' && activeTab !== 'mentor' && activeTab !== 'about'" class="home-cta">
|
||||||
<div class="home-stats__inner">
|
|
||||||
<div class="home-stats__header">
|
|
||||||
<h2 class="fs38">让每一次求职努力<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">84.5%大学生求职首选</p>
|
|
||||||
</article>
|
|
||||||
<article class="stat-card">
|
|
||||||
<div class="stat-card__num">10倍</div>
|
|
||||||
<p class="stat-card__label">面试邀约率提升</p>
|
|
||||||
</article>
|
|
||||||
<article class="stat-card">
|
|
||||||
<div class="stat-card__num">82%</div>
|
|
||||||
<p class="stat-card__label">节约82%校招求职时间</p>
|
|
||||||
</article>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<!-- Jobs Showcase Section -->
|
|
||||||
<section class="home-jobs-showcase">
|
|
||||||
<!-- 背景色块 — 顶部小块 -->
|
|
||||||
<div class="home-jobs-showcase__orb home-jobs-showcase__orb--top"></div>
|
|
||||||
<!-- 背景色块 — 底部全宽渐变 -->
|
|
||||||
<div class="home-jobs-showcase__orb home-jobs-showcase__orb--bottom"></div>
|
|
||||||
<div class="home-jobs-showcase__inner">
|
|
||||||
<h2 class="fs38">海量优质校招岗位,尽在Offer派!</h2>
|
|
||||||
<p class="home-jobs-showcase__sub">实时汇集海量超10000+名校校招职位</p>
|
|
||||||
<div class="home-jobs-showcase__box prl25">
|
|
||||||
<div class="home-jobs-showcase__stats">
|
|
||||||
<div class="showcase-stat">
|
|
||||||
<div class="showcase-stat__num"><span><span class="accent">40</span><span class="accent">万</span></span><span class="fs32">+</span></div>
|
|
||||||
<div class="showcase-stat__label">岗位总数</div>
|
|
||||||
</div>
|
|
||||||
<div class="showcase-stat">
|
|
||||||
<div class="showcase-stat__num"><span class="accent">{{ dailyJobCount }}</span><span class="">个</span></div>
|
|
||||||
<div class="showcase-stat__label">今日更新</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="home-jobs-showcase__scroll">
|
|
||||||
<!-- 无缝轮播:两组相同内容拼接,动画滚完第一组后无缝衔接 -->
|
|
||||||
<div class="ticker-track">
|
|
||||||
<div class="job-ticker" v-for="(job, i) in tickerJobs" :key="'a' + i">
|
|
||||||
<span class="job-ticker__company">{{ job.company }}·{{ job.time }}</span>
|
|
||||||
<span class="job-ticker__title">{{ job.title }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="job-ticker" v-for="(job, i) in tickerJobs" :key="'b' + i">
|
|
||||||
<span class="job-ticker__company">{{ job.company }}·{{ job.time }}</span>
|
|
||||||
<span class="job-ticker__title">{{ job.title }}</span>
|
|
||||||
</div>
|
|
||||||
</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>第一时间发现真正适合你的岗位,精准匹配你的真<br/>实技能,杜绝虚假信息。</p>
|
|
||||||
<button class="home-feature__btn" @click="router.push('/jobs')">
|
|
||||||
<svg width="12" height="12" viewBox="0 0 14 23" 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"><img class="wp100 hp100" src="@/assets/images/home/alex-avatar.png" alt=""></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>每日向数百岗位一键投递,覆盖各大企业网申系<br/>统。告别重复填写,节省 82% 校招求职时间。</p>
|
|
||||||
<button class="home-feature__btn" @click="router.push('/jobs')">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13" height="13" viewBox="0 0 20 21" fill="none"><path d="M3.33331 11.6667C3.17561 11.6673 3.021 11.623 2.88743 11.5392C2.75387 11.4554 2.64683 11.3354 2.57876 11.1931C2.51069 11.0509 2.48438 10.8922 2.50289 10.7356C2.52139 10.579 2.58396 10.4309 2.68331 10.3084L10.9333 1.80839C10.9952 1.73696 11.0795 1.68868 11.1725 1.6715C11.2654 1.65431 11.3614 1.66923 11.4447 1.71381C11.5281 1.75838 11.5938 1.82997 11.6311 1.91681C11.6684 2.00365 11.675 2.10059 11.65 2.19172L10.05 7.20839C10.0028 7.33466 9.98695 7.47049 10.0038 7.60423C10.0206 7.73797 10.0697 7.86562 10.1467 7.97624C10.2237 8.08686 10.3265 8.17715 10.446 8.23936C10.5656 8.30156 10.6985 8.33383 10.8333 8.33339L16.6666 8.33339C16.8243 8.33285 16.9789 8.37707 17.1125 8.46091C17.2461 8.54474 17.3531 8.66476 17.4212 8.80701C17.4893 8.94926 17.5156 9.1079 17.4971 9.26451C17.4785 9.42111 17.416 9.56926 17.3166 9.69172L9.06664 18.1917C9.00476 18.2632 8.92042 18.3114 8.82749 18.3286C8.73455 18.3458 8.63854 18.3309 8.5552 18.2863C8.47186 18.2417 8.40615 18.1701 8.36886 18.0833C8.33157 17.9965 8.32491 17.8995 8.34997 17.8084L9.94997 12.7917C9.99715 12.6655 10.013 12.5296 9.99615 12.3959C9.9793 12.2621 9.93026 12.1345 9.85323 12.0239C9.77621 11.9132 9.6735 11.823 9.55391 11.7608C9.43433 11.6985 9.30144 11.6663 9.16664 11.6667L3.33331 11.6667Z" stroke="currentColor" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" style="mix-blend-mode:normal"></path></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"><img class="wp100 hp100" src="@/assets/images/home/right-icon-01.png" alt=""></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"><img class="wp100 hp100" src="@/assets/images/home/load-icon-01.png" alt=""></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秒内生成针对特定岗位优化的专业简历,通过<br/>ATS系统,突出你的核心优势。</p>
|
|
||||||
<button class="home-feature__btn" @click="router.push('/jobs')">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14" height="14" viewBox="0 0 20 22" fill="none"><path stroke="currentColor" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" style="mix-blend-mode:normal" d="M10.5492 18.3334L15 18.3334C15.442 18.3334 15.8659 18.1578 16.1785 17.8453C16.4911 17.5327 16.6667 17.1088 16.6667 16.6668L16.6667 6.66675C16.6673 6.40268 16.6157 6.14109 16.5147 5.89708C16.4137 5.65307 16.2654 5.43148 16.0783 5.24509L13.0883 2.25509C12.9019 2.06802 12.6803 1.91972 12.4363 1.81874C12.1923 1.71776 11.9307 1.66611 11.6667 1.66675L4.99999 1.66675C4.55797 1.66675 4.13404 1.84235 3.82148 2.15491C3.50892 2.46747 3.33333 2.89139 3.33333 3.33342L3.33333 11.1168"></path><path stroke="rgba(82, 202, 209, 1)" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" style="mix-blend-mode:normal" d="M11.6667 1.66675L11.6667 5.83341C11.6667 6.05443 11.7545 6.26639 11.9107 6.42267C12.067 6.57895 12.279 6.66675 12.5 6.66675L16.6667 6.66675"></path><path d="M8.64834 10.5184C8.98019 10.1869 9.43015 10.0007 9.89922 10.001C10.3683 10.0012 10.8181 10.1878 11.1496 10.5196C11.4811 10.8515 11.6672 11.3014 11.667 11.7705C11.6668 12.2396 11.4802 12.6894 11.1483 13.0209L6.96667 17.1975C6.76865 17.3957 6.52389 17.5407 6.255 17.6192L3.86584 18.3167C3.79413 18.3376 3.71812 18.3389 3.64576 18.3203C3.5734 18.3018 3.50736 18.2642 3.45454 18.2113C3.40173 18.1585 3.36408 18.0925 3.34554 18.0201C3.327 17.9478 3.32826 17.8718 3.34917 17.8L4.04584 15.4092C4.12448 15.1406 4.2695 14.8962 4.4675 14.6984L8.64834 10.5184Z" stroke="currentColor" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" style="mix-blend-mode:normal"></path></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">
|
|
||||||
<img class="w15 h15" src="@/assets/images/home/blue-shield-icon-01.png" alt="">
|
|
||||||
<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>实时获取名企最新内推信息,自动填写网申内推<br/>码,简历更快到达HR。</p>
|
|
||||||
<button class="home-feature__btn" @click="router.push('/jobs')">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13" height="13" viewBox="0 0 20 20" fill="none"><path d="M9.16667 5C11.7011 5.06529 14.1783 4.23959 16.1667 2.66667C16.2905 2.57381 16.4377 2.51727 16.5918 2.50337C16.746 2.48947 16.9009 2.51877 17.0393 2.58798C17.1778 2.65719 17.2942 2.76358 17.3755 2.89522C17.4569 3.02687 17.5 3.17857 17.5 3.33333L17.5 13.3333C17.5 13.4881 17.4569 13.6398 17.3755 13.7714C17.2942 13.9031 17.1778 14.0095 17.0393 14.0787C16.9009 14.1479 16.746 14.1772 16.5918 14.1633C16.4377 14.1494 16.2905 14.0929 16.1667 14C14.1783 12.4271 11.7011 11.6014 9.16667 11.6667L4.16667 11.6667C3.72464 11.6667 3.30072 11.4911 2.98816 11.1785C2.67559 10.866 2.5 10.442 2.5 10L2.5 6.66667C2.5 6.22464 2.67559 5.80072 2.98816 5.48816C3.30072 5.1756 3.72464 5 4.16667 5L9.16667 5Z" stroke="currentColor" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" style="mix-blend-mode:normal"></path><path stroke="currentColor" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" style="mix-blend-mode:normal" d="M5 11.6665C5 13.8302 5.70178 15.9355 7 17.6665C7.26522 18.0201 7.66005 18.2539 8.09763 18.3164C8.53522 18.3789 8.97971 18.2651 9.33333 17.9998C9.68695 17.7346 9.92074 17.3398 9.98325 16.9022C10.0458 16.4646 9.93188 16.0201 9.66667 15.6665C8.80119 14.5125 8.33333 13.109 8.33333 11.6665"></path><path stroke="currentColor" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" style="mix-blend-mode:normal" d="M6.66669 5L6.66669 11.6667"></path></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 xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13" height="13" viewBox="0 0 20 20" fill="none"><path d="M18.3333 14.1667C18.3333 14.6087 18.1577 15.0326 17.8452 15.3452C17.5326 15.6577 17.1087 15.8333 16.6667 15.8333L5.69 15.8333C5.24801 15.8334 4.82416 16.0091 4.51167 16.3217L2.67667 18.1567C2.59393 18.2394 2.48851 18.2957 2.37375 18.3186C2.25898 18.3414 2.14003 18.3297 2.03193 18.2849C1.92382 18.2401 1.83142 18.1643 1.76641 18.067C1.7014 17.9697 1.66669 17.8553 1.66667 17.7383L1.66667 4.16667C1.66667 3.72464 1.84227 3.30072 2.15483 2.98816C2.46739 2.67559 2.89131 2.5 3.33334 2.5L16.6667 2.5C17.1087 2.5 17.5326 2.67559 17.8452 2.98816C18.1577 3.30072 18.3333 3.72464 18.3333 4.16667L18.3333 14.1667Z" stroke="currentColor" stroke-width="2" stroke-linejoin="round" stroke-linecap="round" style="mix-blend-mode:normal"></path></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>真实求职反馈,见证每一次从迷茫到上岸</p>
|
|
||||||
</div>
|
|
||||||
<!-- 评价卡片横向排列 -->
|
|
||||||
<div class="home-testimonials__cards">
|
|
||||||
<div class="testimonial-card" v-for="(t, i) in testimonials" :key="i">
|
|
||||||
<!-- 引号装饰 SVG -->
|
|
||||||
|
|
||||||
<p class="testimonial-card__text">{{ t.text }}</p>
|
|
||||||
<div class="dflex aliite-e">
|
|
||||||
<div class="testimonial-card__author">
|
|
||||||
<img class="testimonial-card__avatar" :src="t.avatar" alt="用户头像" />
|
|
||||||
<div class="testimonial-card__info">
|
|
||||||
<p class="testimonial-card__name">{{ t.name }}</p>
|
|
||||||
<p class="testimonial-card__school">{{ t.school }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<img class="w48 h48" src="@/assets/images/home/blue-icon-768.png" alt="">
|
|
||||||
</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"/>
|
|
||||||
<path d="M240 190 L318 224 Q328 227.5 318 231 L240 265 Q227.5 270 215 265 L137 231 Q127 227.5 137 224 L215 190 Q227.5 185 240 190 Z" stroke="#fff" stroke-width="20" fill="none" opacity="0.08" transform="rotate(-45 227.5 227.5)"/>
|
|
||||||
</svg>
|
|
||||||
<div class="home-testimonials__founder-content">
|
|
||||||
<img class="home-testimonials__founder-img" :src="avatarImg" alt="创始人头像" />
|
|
||||||
<div class="home-testimonials__founder-text">
|
|
||||||
<blockquote>“很多大学生还在用传统方式找工作,海投、反复改简历,效率很低。Offer派利用AI技术让专业和岗位<span class="fw600">深度匹配</span>关联,配合<span class="fw600">自动化投递</span>,让校招求职流程更丝滑,更精准,节省了80%的繁琐过程,拿到更多Offer。”</blockquote>
|
|
||||||
<cite>
|
|
||||||
<span class="cite-name">{{ founderQuotes[founderIndex].name }}</span>
|
|
||||||
<span class="cite-role">{{ founderQuotes[founderIndex].role }}</span>
|
|
||||||
</cite>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- 分页小圆点 -->
|
|
||||||
<div v-if="false" 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>关于平台使用、隐私安全与岗位来源</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 }"
|
|
||||||
>
|
|
||||||
<div class="faq-item__header" @click="faqOpen === i ? null : (faqOpen = i)">
|
|
||||||
<span class="faq-item__question">{{ faq.q }}</span>
|
|
||||||
<div class="faq-item__icon" @click.stop="faqOpen = faqOpen === i ? -1 : i">
|
|
||||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
|
|
||||||
<template v-if="faqOpen === i">
|
|
||||||
<line x1="7" y1="7" x2="17" y2="17" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
|
||||||
<line x1="17" y1="7" x2="7" y2="17" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<line x1="5" y1="12" x2="19" y2="12" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
|
||||||
<line x1="12" y1="5" x2="12" y2="19" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
|
||||||
</template>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="faq-item__answer" v-show="faqOpen === i">
|
|
||||||
<!-- 最后一项"还有其他问题"显示文本输入框+提交按钮 -->
|
|
||||||
<template v-if="i === faqs.length - 1">
|
|
||||||
<div class="faq-item__feedback">
|
|
||||||
<textarea
|
|
||||||
v-model="faqFeedbackText"
|
|
||||||
class="faq-item__textarea"
|
|
||||||
placeholder="请输入你的问题"
|
|
||||||
rows="4"
|
|
||||||
></textarea>
|
|
||||||
<button class="faq-item__submit" @click.stop="submitFaqFeedback">提交</button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<p>{{ faq.a }}</p>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<!-- CTA Section -->
|
|
||||||
<section class="home-cta">
|
|
||||||
<div class="home-cta__inner">
|
<div class="home-cta__inner">
|
||||||
<h2>让Offer派带你找到<br/>人生第一份好工作</h2>
|
<h2>让Offer派带你找到<br/>人生第一份好工作</h2>
|
||||||
<button class="home-cta__btn" @click="router.push('/jobs')">免费体验</button>
|
<button class="home-cta__btn" @click="router.push('/jobs')">免费体验</button>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</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"
|
|
||||||
:allowParentSelectClick="true"
|
|
||||||
: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"
|
|
||||||
:allowParentSelectClick="true"
|
|
||||||
:triggerStyle="filterTriggerStyle"
|
|
||||||
:displayStyle="filterDisplayStyle"
|
|
||||||
@update:categoryIds="onHomeCategoryChange"
|
|
||||||
/>
|
|
||||||
<button class="filter-btn" @click="goSearchJobs">立即匹配</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
<footer class="home-footer">
|
<footer class="home-footer">
|
||||||
<div class="home-footer__inner">
|
<div class="home-footer__inner">
|
||||||
<div class="home-footer__col">
|
<div class="home-footer__col">
|
||||||
<div class="home-footer__logo">
|
<div class="home-footer__logo">
|
||||||
<!-- 网站Logo图片 -->
|
|
||||||
<img src="@/assets/images/logo.png" alt="Offer派" class="home-footer__logo-img" />
|
<img src="@/assets/images/logo.png" alt="Offer派" class="home-footer__logo-img" />
|
||||||
</div>
|
</div>
|
||||||
<p class="home-footer__slogan">大学生AI求职平台</p>
|
<p class="home-footer__slogan">大学生AI求职平台</p>
|
||||||
@@ -466,7 +66,6 @@
|
|||||||
<li><a href="https://www.jianshixingqiu.com/internship" target="_blank">名企实习</a></li>
|
<li><a href="https://www.jianshixingqiu.com/internship" target="_blank">名企实习</a></li>
|
||||||
<li><a href="https://www.jianshixingqiu.com/biunique" target="_blank">名企导师1V1</a></li>
|
<li><a href="https://www.jianshixingqiu.com/biunique" target="_blank">名企导师1V1</a></li>
|
||||||
<li><a href="https://www.jianshixingqiu.com/directTrain" target="_blank">Offer直通车</a></li>
|
<li><a href="https://www.jianshixingqiu.com/directTrain" target="_blank">Offer直通车</a></li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="home-footer__col">
|
<div class="home-footer__col">
|
||||||
@@ -492,15 +91,12 @@
|
|||||||
import { ref, onMounted, onUnmounted, computed } from 'vue'
|
import { ref, onMounted, onUnmounted, computed } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { useStore } from 'vuex'
|
import { useStore } from 'vuex'
|
||||||
import avatarImg from '@/assets/images/home/avatar-temporary.png'
|
|
||||||
import studentAvatar0 from '@/assets/images/home/student-avatar-0.png'
|
|
||||||
import studentAvatar1 from '@/assets/images/home/student-avatar-1.png'
|
|
||||||
import studentAvatar2 from '@/assets/images/home/student-avatar-2.png'
|
|
||||||
import IndustrySelector from '@/components/tools/IndustrySelector.vue'
|
|
||||||
import RegionSelector from '@/components/tools/RegionSelector.vue'
|
|
||||||
import JobCategorySelector from '@/components/tools/JobCategorySelector.vue'
|
|
||||||
import AgreementPreviewDialog from '@/components/tools/AgreementPreviewDialog.vue'
|
import AgreementPreviewDialog from '@/components/tools/AgreementPreviewDialog.vue'
|
||||||
import { getDailyJobCount } from '@/utils/dailyJobCount'
|
import HomeContent from '@/components/HomeContent.vue'
|
||||||
|
import HomeJobRadar from '@/components/HomeJobRadar.vue'
|
||||||
|
import HomeAnnouncement from '@/components/HomeAnnouncement.vue'
|
||||||
|
import HomeMentor from '@/components/HomeMentor.vue'
|
||||||
|
import HomeAbout from '@/components/HomeAbout.vue'
|
||||||
|
|
||||||
/** 路由实例 */
|
/** 路由实例 */
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@@ -510,133 +106,46 @@ const store = useStore()
|
|||||||
// 声明友盟统计 _czc 对象
|
// 声明友盟统计 _czc 对象
|
||||||
const _czc: any[] = (window as any)._czc || [];
|
const _czc: any[] = (window as any)._czc || [];
|
||||||
(window as any)._czc = _czc;
|
(window as any)._czc = _czc;
|
||||||
// 绑定 siteid,请用您的 siteid 替换下方 "XXXXXXXX" 部分
|
|
||||||
_czc.push(["_setAccount", "1281490571"]);
|
_czc.push(["_setAccount", "1281490571"]);
|
||||||
|
|
||||||
/** 页面是否已向下滚动超过 20px — 用于导航栏背景切换 */
|
// ==================== Tab导航 ====================
|
||||||
|
|
||||||
|
/** 导航Tab列表 */
|
||||||
|
const navTabs = [
|
||||||
|
{ key: 'home', label: '首页' },
|
||||||
|
{ key: 'jobRadar', label: '岗位雷达' },
|
||||||
|
{ key: 'announcement', label: '校招公告' },
|
||||||
|
{ key: 'mentor', label: '求职辅导' },
|
||||||
|
{ key: 'about', label: '关于我们' },
|
||||||
|
]
|
||||||
|
|
||||||
|
/** 当前激活的Tab */
|
||||||
|
const activeTab = ref('home')
|
||||||
|
|
||||||
|
/** 当前激活Tab对应的组件 */
|
||||||
|
const activeTabComponent = computed(() => {
|
||||||
|
switch (activeTab.value) {
|
||||||
|
case 'home':
|
||||||
|
return HomeContent
|
||||||
|
case 'jobRadar':
|
||||||
|
return HomeJobRadar
|
||||||
|
case 'announcement':
|
||||||
|
return HomeAnnouncement
|
||||||
|
case 'mentor':
|
||||||
|
return HomeMentor
|
||||||
|
case 'about':
|
||||||
|
return HomeAbout
|
||||||
|
default:
|
||||||
|
return HomeContent
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// ==================== 页面滚动 ====================
|
||||||
|
|
||||||
|
/** 页面是否已向下滚动超过 20px */
|
||||||
const isScrolled = ref(false)
|
const isScrolled = ref(false)
|
||||||
|
|
||||||
/** 今日更新岗位数量 — 每日确定性变化(使用公共哈希工具) */
|
|
||||||
const dailyJobCount = getDailyJobCount()
|
|
||||||
|
|
||||||
/** 当前展开的 FAQ 索引,-1 表示全部收起 */
|
|
||||||
const faqOpen = ref(-1)
|
|
||||||
|
|
||||||
/** 创始人引言当前索引 — 点击小圆点可切换 */
|
|
||||||
const founderIndex = ref(0)
|
|
||||||
|
|
||||||
/** 创始人引言数据 — 支持多条切换 */
|
|
||||||
const founderQuotes = [
|
|
||||||
{ text: '“很多大学生还在用传统方式找工作,海投、反复改简历,效率很低。Offer派利用AI技术让专业和岗位深度匹配关联,配合自动化投递,让校招求职流程更丝滑,更精准,节省了80%的繁琐过程,拿到更多Offer。”', name: 'TK', 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: '西安交通大学', avatar: studentAvatar0 },
|
|
||||||
{ text: '“界面设计简洁友好,用起来很舒适。AI助手帮我理清了方向,让迷茫的我建立了自信,还能帮我优化简历,真的很nice~”', name: '王同学', school: '北京大学', avatar: studentAvatar1 },
|
|
||||||
{ text: '“满分!特别是网申自动填写,不仅可以一键填写,还能快速定制简历内容,完美匹配岗位要求,毕设求职两不误,真心推荐。”', name: '张同学', school: '中国人民大学', avatar: studentAvatar2 },
|
|
||||||
]
|
|
||||||
|
|
||||||
/** 用户反馈输入内容 */
|
|
||||||
const faqFeedbackText = ref('')
|
|
||||||
|
|
||||||
/** 提交用户反馈 */
|
|
||||||
function submitFaqFeedback() {
|
|
||||||
if (!faqFeedbackText.value.trim()) return
|
|
||||||
// TODO: 对接后端反馈接口
|
|
||||||
faqFeedbackText.value = ''
|
|
||||||
faqOpen.value = -1
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 常见问题列表 — q: 问题, a: 答案,点击可展开/收起 */
|
|
||||||
const faqs = [
|
|
||||||
{ q: '这个平台与其他求职平台有什么不同?', a: '不同于BOSS直聘等传统平台的“手动式”求职,Offer派如同一位经验丰富的职业导师,通过AI能力搭建智能工具,自动处理简历优化、岗位匹配、申请投递等环节,大幅度提升你的求职效率。' },
|
|
||||||
{ q: '平台如何保障我的个人信息安全?', a: 'Offer派高度重视你的隐私安全。未经你明确同意,我们绝不会将你的个人信息提供给任何第三方。你的所有数据仅用于在平台内为你提供AI智能岗位匹配、简历优化等个性化求职服务。' },
|
|
||||||
{ q: '平台可以免费使用吗?', a: 'Offer派为所有用户免费开放3天会员权益,帮你省心省力找工作。3天后,依然可以免费使用各项功能,但有使用次数限制。如果你需要不受限制地使用所有功能,更快更高效地获得Offer,建议您升级为付费会员,让求职效率翻倍。' },
|
|
||||||
{ q: '平台的岗位来源是什么?', a: 'Offer派的岗位来自上万家企业的官方招聘网站,同时聚合了各大主流平台的最新职位——你不需要在多个网站之间来回切换,就能一站式搜罗全网高质量的工作机会。此外,我们会持续筛查每一则新发布的职位,及时剔除虚假信息,帮你避“坑”,为你提供真实靠谱的岗位信息。' },
|
|
||||||
{ 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.80rem',
|
|
||||||
'max-width': 'none',
|
|
||||||
height: '0.56rem',
|
|
||||||
'border-radius': '0.16rem',
|
|
||||||
border: '1px solid #e5e7eb',
|
|
||||||
padding: '0 0.2rem',
|
|
||||||
background: '#F3F4F5',
|
|
||||||
'justify-content': 'space-between',
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 选择器显示文字样式 — 匹配首页 .filter-select 内文字 */
|
|
||||||
const filterDisplayStyle = {
|
|
||||||
'font-size': '0.16rem',
|
|
||||||
'line-height': '0.16rem',
|
|
||||||
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(() => {
|
onMounted(() => {
|
||||||
// 监听页面滚动,超过 20px 时导航栏显示背景
|
|
||||||
const isScaleMode = () => {
|
const isScaleMode = () => {
|
||||||
return !!document.body.style.transform && document.body.style.transform.includes('scale')
|
return !!document.body.style.transform && document.body.style.transform.includes('scale')
|
||||||
}
|
}
|
||||||
@@ -652,13 +161,11 @@ onMounted(() => {
|
|||||||
if (isScaleMode()) {
|
if (isScaleMode()) {
|
||||||
const el = document.querySelector('.home-nav__inner') as HTMLElement | null
|
const el = document.querySelector('.home-nav__inner') as HTMLElement | null
|
||||||
if (el && isScrolled.value) {
|
if (el && isScrolled.value) {
|
||||||
// fixed 在 transform 容器内退化为 absolute,手动同步 top
|
|
||||||
el.style.top = (document.body.scrollTop + 20) + 'px'
|
el.style.top = (document.body.scrollTop + 20) + 'px'
|
||||||
} else if (el && !isScrolled.value) {
|
} else if (el && !isScrolled.value) {
|
||||||
el.style.top = ''
|
el.style.top = ''
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 非 scale 模式:清除内联 top,让 CSS 控制
|
|
||||||
const el = document.querySelector('.home-nav__inner') as HTMLElement | null
|
const el = document.querySelector('.home-nav__inner') as HTMLElement | null
|
||||||
if (el && el.style.top) {
|
if (el && el.style.top) {
|
||||||
el.style.top = ''
|
el.style.top = ''
|
||||||
@@ -677,18 +184,18 @@ onMounted(() => {
|
|||||||
document.body.removeEventListener('scroll', handleScroll)
|
document.body.removeEventListener('scroll', handleScroll)
|
||||||
})
|
})
|
||||||
|
|
||||||
// 检测 URL 中的邀请码参数 invite_code,存入全局状态
|
// 检测 URL 中的邀请码参数
|
||||||
const urlParams = new URLSearchParams(window.location.search)
|
const urlParams = new URLSearchParams(window.location.search)
|
||||||
const inviteCode = urlParams.get('invite_code')
|
const inviteCode = urlParams.get('invite_code')
|
||||||
if (inviteCode && inviteCode.length === 10) {
|
if (inviteCode && inviteCode.length === 10) {
|
||||||
store.commit('SET_INVITE_CODE', inviteCode)
|
store.commit('SET_INVITE_CODE', inviteCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载公共工具数据(行业分类、岗位分类、地区分类等)
|
// 加载公共工具数据
|
||||||
store.dispatch('loadCommonData')
|
store.dispatch('loadCommonData')
|
||||||
})
|
})
|
||||||
|
|
||||||
/** 点击登录按钮 — 打开登录弹窗,登录成功后跳转到 jobs 页面 */
|
/** 点击登录按钮 */
|
||||||
function handleLoginClick() {
|
function handleLoginClick() {
|
||||||
store.dispatch('openLogin', '/jobs')
|
store.dispatch('openLogin', '/jobs')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -452,6 +452,11 @@ onMounted(() => {
|
|||||||
|
|
||||||
/** 返回职位列表页 */
|
/** 返回职位列表页 */
|
||||||
function goBack() {
|
function goBack() {
|
||||||
|
// 从首页跳转过来时,直接去列表页而非回首页
|
||||||
|
if (route.query.from === 'home') {
|
||||||
|
router.push('/jobs')
|
||||||
|
return
|
||||||
|
}
|
||||||
if (window.history.length > 1) {
|
if (window.history.length > 1) {
|
||||||
router.back()
|
router.back()
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+19
-1
@@ -1624,6 +1624,8 @@ async function loadJobList() {
|
|||||||
console.error('加载岗位列表失败', e)
|
console.error('加载岗位列表失败', e)
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
|
// 登录状态下,首次加载后检查是否需要自动填满容器
|
||||||
|
nextTick(() => { autoFillIfNeeded() })
|
||||||
}
|
}
|
||||||
// 加载完列表后查询筛选数量
|
// 加载完列表后查询筛选数量
|
||||||
loadFilterJobCount()
|
loadFilterJobCount()
|
||||||
@@ -1657,6 +1659,22 @@ async function loadNextPage() {
|
|||||||
console.error('加载下一页失败', e)
|
console.error('加载下一页失败', e)
|
||||||
} finally {
|
} finally {
|
||||||
loadingMore.value = false
|
loadingMore.value = false
|
||||||
|
// 加载下一页后继续检查是否需要填满容器
|
||||||
|
nextTick(() => { autoFillIfNeeded() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 自动填满容器:登录状态下,当推荐列表内容不足以产生滚动条且还有更多数据时,自动加载下一页 */
|
||||||
|
function autoFillIfNeeded() {
|
||||||
|
// 未登录时不自动补全,只展示一页
|
||||||
|
if (!isAuthenticated.value) return
|
||||||
|
// 仅推荐Tab生效,收藏和已投递不处理
|
||||||
|
if (!isRecommendTab.value) return
|
||||||
|
const el = jobListRef.value
|
||||||
|
if (!el) return
|
||||||
|
// 如果容器没有滚动条(内容高度不超过可视高度)且还有更多数据未加载
|
||||||
|
if (el.scrollHeight <= el.clientHeight && !noMore.value && !loadingMore.value && !loading.value) {
|
||||||
|
loadNextPage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1712,7 +1730,7 @@ const filterCountLoading = ref(false)
|
|||||||
|
|
||||||
/** 是否显示筛选数量与深度匹配提示条(数量 < 2000 时显示) */
|
/** 是否显示筛选数量与深度匹配提示条(数量 < 2000 时显示) */
|
||||||
const showFilterCountBar = computed(() => {
|
const showFilterCountBar = computed(() => {
|
||||||
return filterJobCount.value !== null && filterJobCount.value < 2000 && isRecommendTab.value
|
return filterJobCount.value !== null && filterJobCount.value < 5000 && isRecommendTab.value
|
||||||
})
|
})
|
||||||
|
|
||||||
/** 是否正在进行深度匹配查询 */
|
/** 是否正在进行深度匹配查询 */
|
||||||
|
|||||||
@@ -218,6 +218,11 @@ async function loadDetail() {
|
|||||||
|
|
||||||
/** 返回导师列表页 */
|
/** 返回导师列表页 */
|
||||||
function goBack() {
|
function goBack() {
|
||||||
|
// 从首页跳转过来时,直接去列表页而非回首页
|
||||||
|
if (route.query.from === 'home') {
|
||||||
|
router.push('/mentor')
|
||||||
|
return
|
||||||
|
}
|
||||||
if (window.history.length > 1) {
|
if (window.history.length > 1) {
|
||||||
router.back()
|
router.back()
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+204
-140
@@ -2,89 +2,111 @@
|
|||||||
<div class="resume-page dflex">
|
<div class="resume-page dflex">
|
||||||
<SideNav />
|
<SideNav />
|
||||||
<div class="resume-page__content">
|
<div class="resume-page__content">
|
||||||
<!-- 页面标题 + 上传按钮 -->
|
<!-- 页面标题 -->
|
||||||
<div class="resume-page__header">
|
<div class="resume-page__header">
|
||||||
<h2 class="resume-page__title">我的简历</h2>
|
<h2 class="resume-page__title">简历管理</h2>
|
||||||
<div class="dflex-end">
|
</div>
|
||||||
<!-- 从个人资料创建按钮 -->
|
|
||||||
<button class="resume-page__create-btn mr16" :disabled="creatingFromProfile" @click="handleCreateFromProfile">
|
<!-- 简历卡片网格 -->
|
||||||
<svg viewBox="0 0 16 16" fill="none" class="resume-page__upload-icon">
|
<div ref="gridRef" class="resume-page__card-grid scrollbar-thin" @scroll="onGridScroll">
|
||||||
<path d="M8 3v10M3 8h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
<!-- 简历卡片列表 -->
|
||||||
|
<div
|
||||||
|
v-for="item in resumeList"
|
||||||
|
:key="item.id"
|
||||||
|
class="resume-page__card"
|
||||||
|
@click="goDetail(item.id)"
|
||||||
|
>
|
||||||
|
<!-- 预览图区域 -->
|
||||||
|
<div class="resume-page__card-preview">
|
||||||
|
<!-- 默认标记 -->
|
||||||
|
<span v-if="item.isDefault" class="resume-page__card-default-tag">默认</span>
|
||||||
|
<!-- 更多按钮(右上角) -->
|
||||||
|
<button
|
||||||
|
class="resume-page__card-more-btn"
|
||||||
|
@click.stop="toggleMenu(item.id)"
|
||||||
|
>
|
||||||
|
<svg viewBox="0 0 24 24" fill="none">
|
||||||
|
<circle cx="6" cy="12" r="2" fill="#52CAD1"/>
|
||||||
|
<circle cx="12" cy="12" r="2" fill="#52CAD1"/>
|
||||||
|
<circle cx="18" cy="12" r="2" fill="#52CAD1"/>
|
||||||
</svg>
|
</svg>
|
||||||
从个人资料创建
|
|
||||||
</button>
|
</button>
|
||||||
<button class="resume-page__upload-btn" @click="handleUpload">
|
<!-- 更多菜单 -->
|
||||||
<svg viewBox="0 0 16 16" fill="none" class="resume-page__upload-icon">
|
<div v-if="activeMenuId === item.id" class="resume-page__card-menu" @click.stop>
|
||||||
<path d="M8 3v10M3 8h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
<!-- 设为默认 -->
|
||||||
|
<div
|
||||||
|
v-if="!item.isDefault"
|
||||||
|
class="resume-page__card-menu-item resume-page__card-menu-item--default"
|
||||||
|
@click.stop="handleSetDefault(item.id)"
|
||||||
|
>
|
||||||
|
<svg viewBox="0 0 16 16" fill="none">
|
||||||
|
<path d="M8 1.5L9.79 5.12L13.8 5.71L10.9 8.53L11.58 12.52L8 10.63L4.42 12.52L5.1 8.53L2.2 5.71L6.21 5.12L8 1.5Z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round" fill="none"/>
|
||||||
|
</svg>
|
||||||
|
<span>设为默认</span>
|
||||||
|
</div>
|
||||||
|
<!-- 导出简历 -->
|
||||||
|
<div
|
||||||
|
class="resume-page__card-menu-item"
|
||||||
|
@click.stop="handleExport(item)"
|
||||||
|
>
|
||||||
|
<svg viewBox="0 0 16 16" fill="none">
|
||||||
|
<path d="M8 2v8M8 2L5 5M8 2l3 3" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M2 10v3a1 1 0 001 1h10a1 1 0 001-1v-3" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
<span>导出简历</span>
|
||||||
|
</div>
|
||||||
|
<!-- 删除简历 -->
|
||||||
|
<div
|
||||||
|
class="resume-page__card-menu-item resume-page__card-menu-item--delete"
|
||||||
|
@click.stop="handleDelete(item.id, item.isDefault)"
|
||||||
|
>
|
||||||
|
<svg viewBox="0 0 16 16" fill="none">
|
||||||
|
<path d="M3 4h10M5.5 4V3a1 1 0 011-1h3a1 1 0 011 1v1M6.5 7v4M9.5 7v4" stroke="#EF4444" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M4 4l.7 8.5a1 1 0 001 .9h4.6a1 1 0 001-.9L12 4" stroke="#EF4444" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
<span style="color: #6A7282;">删除简历</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 预览图片 -->
|
||||||
|
<img src="@/assets/images/resume-list-img01.png" alt="简历预览" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 底部信息区域 -->
|
||||||
|
<div class="resume-page__card-info">
|
||||||
|
<!-- 名称 + 编辑按钮 -->
|
||||||
|
<div class="resume-page__card-info-header">
|
||||||
|
<span class="resume-page__card-name">{{ item.name }}</span>
|
||||||
|
<!-- 编辑按钮(笔图标) -->
|
||||||
|
<button class="resume-page__card-edit-btn" @click.stop="handleEditName(item)">
|
||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M4.16667 17.5H15.8333C16.75 17.5 17.5 16.75 17.5 15.8333V9.16667H15.8333V15.8333H4.16667V4.16667H10.8333V2.5H4.16667C3.25 2.5 2.5 3.25 2.5 4.16667V15.8333C2.5 16.75 3.25 17.5 4.16667 17.5Z" fill="#52CAD1"/>
|
||||||
|
<path d="M6.83334 10.6662V12.3329C6.83334 12.7912 7.20834 13.1662 7.66668 13.1662H9.33334C9.55834 13.1662 9.76668 13.0746 9.92501 12.9246L15.3 7.54956L12.4583 4.7079L7.08334 10.0829C7.00611 10.1608 6.945 10.2531 6.90353 10.3546C6.86206 10.4562 6.84104 10.5649 6.84168 10.6746L6.83334 10.6662ZM17.2583 5.59123C17.3356 5.51413 17.3969 5.42256 17.4387 5.32175C17.4805 5.22094 17.502 5.11287 17.502 5.00373C17.502 4.89459 17.4805 4.78652 17.4387 4.68571C17.3969 4.5849 17.3356 4.49332 17.2583 4.41623L15.5917 2.74956C15.5146 2.67231 15.423 2.61102 15.3222 2.5692C15.2214 2.52738 15.1133 2.50586 15.0042 2.50586C14.895 2.50586 14.787 2.52738 14.6862 2.5692C14.5853 2.61102 14.4938 2.67231 14.4167 2.74956L13.0417 4.12456L15.8833 6.96623L17.2583 5.59123Z" fill="#52CAD1"/>
|
||||||
</svg>
|
</svg>
|
||||||
上传简历
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 目标岗位 -->
|
||||||
|
<div class="resume-page__card-target">{{ item.targetJob || '' }}</div>
|
||||||
|
<!-- 最后编辑时间(hover时显示) -->
|
||||||
|
<div class="resume-page__card-edit-time">最后编辑于:{{ item.updatedAtDate }}</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 简历表格 -->
|
<!-- 新建卡片(始终在最后) -->
|
||||||
<div class="resume-page__table-wrap">
|
<div class="resume-page__card-new" @click="handleUpload">
|
||||||
<!-- 空状态提示 -->
|
<svg viewBox="0 0 32 32" fill="none">
|
||||||
<div v-if="resumeList.length === 0" class="resume-page__empty">
|
<circle cx="16" cy="16" r="16" fill="#52CAD1"/>
|
||||||
<p>暂无简历,请点击上方按钮上传简历</p>
|
<path d="M16 10v12M10 16h12" stroke="#fff" stroke-width="2.5" stroke-linecap="round"/>
|
||||||
</div>
|
|
||||||
<table v-else class="resume-page__table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="resume-page__th">简历</th>
|
|
||||||
<th class="resume-page__th">目标岗位</th>
|
|
||||||
<th class="resume-page__th">最近修改</th>
|
|
||||||
<th class="resume-page__th resume-page__th--action"></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr
|
|
||||||
v-for="item in resumeList"
|
|
||||||
:key="item.id"
|
|
||||||
class="resume-page__row"
|
|
||||||
@click="goDetail(item.id)"
|
|
||||||
>
|
|
||||||
<td class="resume-page__td">
|
|
||||||
<div class="resume-page__name-cell">
|
|
||||||
<span class="resume-page__name">{{ item.name }}</span>
|
|
||||||
<span v-if="item.isDefault" class="resume-page__default-tag">默认</span>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td class="resume-page__td resume-page__td--ellipsis">{{ item.targetJob }}</td>
|
|
||||||
<td class="resume-page__td">{{ item.updatedAt }}</td>
|
|
||||||
<!-- 操作按钮列 -->
|
|
||||||
<td class="resume-page__td resume-page__td--action">
|
|
||||||
<div class="resume-page__actions">
|
|
||||||
<button
|
|
||||||
class="resume-page__action-btn"
|
|
||||||
@click.stop="handleEditName(item)"
|
|
||||||
>
|
|
||||||
<svg width="12" height="12" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.0523 1.82016C11.7781 1.54295 11.4366 1.34358 11.062 1.24212C10.6875 1.14065 10.2931 1.14065 9.91851 1.24212C9.54396 1.34358 9.2024 1.54295 8.92822 1.82016L8.29348 2.46298C8.2617 2.4886 8.23269 2.51753 8.20693 2.54932L1.90565 8.92043C1.82508 9.00168 1.77008 9.10517 1.74754 9.21793L1.16589 12.1346C1.14691 12.2288 1.1513 12.3264 1.17863 12.4185C1.20598 12.5107 1.25544 12.5945 1.32261 12.6627C1.38979 12.7308 1.47258 12.7811 1.56364 12.809C1.65458 12.837 1.75127 12.8417 1.84449 12.8229L4.7343 12.2396C4.84585 12.2168 4.94823 12.1612 5.02859 12.0797L12.0523 4.97947C12.3265 4.70229 12.5237 4.35703 12.6241 3.97838C12.7245 3.59974 12.7245 3.20105 12.6241 2.8224C12.5237 2.44375 12.3265 2.09849 12.0523 1.82133" fill="currentColor"/>
|
|
||||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.3353 11.1303L2.46814 11.5083L2.84319 9.62298L8.65699 3.74536L10.1491 5.25385L4.3353 11.1303ZM9.7439 2.64628C9.8742 2.51131 10.0376 2.41368 10.2174 2.36336C10.3972 2.31304 10.587 2.31183 10.7675 2.35985C10.9479 2.40787 11.1125 2.5034 11.2445 2.63669C11.3765 2.76999 11.4711 2.93629 11.5187 3.11863C11.5664 3.30096 11.5653 3.4928 11.5157 3.67459C11.466 3.85638 11.3696 4.0216 11.2362 4.15341L10.9661 4.42871L9.47384 2.91925L9.7439 2.64628Z" fill="white"/>
|
|
||||||
</svg>
|
</svg>
|
||||||
<span class="fs12 color-middle ml3 color-dark-ho">修改简历信息</span>
|
<span>新建</span>
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
v-if="!item.isDefault"
|
|
||||||
class="resume-page__action-btn"
|
|
||||||
@click.stop="handleSetDefault(item.id)"
|
|
||||||
>设为默认</button>
|
|
||||||
<button
|
|
||||||
class="resume-page__action-btn"
|
|
||||||
@click.stop="handleExport(item)"
|
|
||||||
>导出</button>
|
|
||||||
<button
|
|
||||||
class="resume-page__action-btn resume-page__action-btn--delete"
|
|
||||||
@click.stop="handleDelete(item.id, item.isDefault)"
|
|
||||||
>删除</button>
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
|
||||||
</tr>
|
<!-- 加载中 -->
|
||||||
</tbody>
|
<div v-if="loadingMore" class="resume-page__loading-box">
|
||||||
</table>
|
<span>加载中...</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 编辑简历名称弹窗 -->
|
<!-- 编辑简历名称弹窗 -->
|
||||||
<ResumeEditNameDialog
|
<ResumeEditNameDialog
|
||||||
v-model="editNameVisible"
|
v-model="editNameVisible"
|
||||||
@@ -106,8 +128,10 @@
|
|||||||
v-model="uploadDialogVisible"
|
v-model="uploadDialogVisible"
|
||||||
@confirm="handleUploadConfirm"
|
@confirm="handleUploadConfirm"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 全屏加载遮罩 -->
|
<!-- 全屏加载遮罩 -->
|
||||||
<FullscreenLoading :visible="fullLoading" :text="fullLoadingText" title="Nova 正在帮您努力处理~" />
|
<FullscreenLoading :visible="fullLoading" :text="fullLoadingText" title="Nova 正在帮您努力处理~" />
|
||||||
|
|
||||||
<!-- 简历解析步骤进度遮罩 -->
|
<!-- 简历解析步骤进度遮罩 -->
|
||||||
<StepProgressOverlay
|
<StepProgressOverlay
|
||||||
v-if="showUploadProgress"
|
v-if="showUploadProgress"
|
||||||
@@ -123,19 +147,17 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { EditPen } from '@element-plus/icons-vue'
|
|
||||||
import SideNav from '@/components/SideNav.vue'
|
import SideNav from '@/components/SideNav.vue'
|
||||||
import ResumeEditNameDialog from '@/components/ResumeEditNameDialog.vue'
|
import ResumeEditNameDialog from '@/components/ResumeEditNameDialog.vue'
|
||||||
import ResumeExportDialog from '@/components/ResumeExportDialog.vue'
|
import ResumeExportDialog from '@/components/ResumeExportDialog.vue'
|
||||||
import ResumeUploadDialog from '@/components/ResumeUploadDialog.vue'
|
import ResumeUploadDialog from '@/components/ResumeUploadDialog.vue'
|
||||||
import { uploadResume } from '@/utils/aiRequest'
|
import { uploadResume } from '@/utils/aiRequest'
|
||||||
import {
|
import {
|
||||||
fetchResumeList, deleteResume, setDefaultResume, createResumeFromProfile, type ResumeListItem,
|
fetchResumeList, deleteResume, setDefaultResume, type ResumeListItem,
|
||||||
} from '@/api/resume'
|
} from '@/api/resume'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
// 命令式调用的组件,按需引入插件不会自动加载其样式,需手动引入
|
|
||||||
import 'element-plus/es/components/message-box/style/css'
|
import 'element-plus/es/components/message-box/style/css'
|
||||||
import FullscreenLoading from '@/components/FullscreenLoading.vue'
|
import FullscreenLoading from '@/components/FullscreenLoading.vue'
|
||||||
import StepProgressOverlay from '@/components/StepProgressOverlay.vue'
|
import StepProgressOverlay from '@/components/StepProgressOverlay.vue'
|
||||||
@@ -145,7 +167,6 @@ const router = useRouter()
|
|||||||
// 声明友盟统计 _czc 对象
|
// 声明友盟统计 _czc 对象
|
||||||
const _czc: any[] = (window as any)._czc || [];
|
const _czc: any[] = (window as any)._czc || [];
|
||||||
(window as any)._czc = _czc;
|
(window as any)._czc = _czc;
|
||||||
// 绑定 siteid,请用您的 siteid 替换下方 "XXXXXXXX" 部分
|
|
||||||
_czc.push(["_setAccount", "1281490571"]);
|
_czc.push(["_setAccount", "1281490571"]);
|
||||||
|
|
||||||
// ==================== 全屏加载状态 ====================
|
// ==================== 全屏加载状态 ====================
|
||||||
@@ -154,62 +175,44 @@ const fullLoading = ref(false)
|
|||||||
/** 全屏加载文案 */
|
/** 全屏加载文案 */
|
||||||
const fullLoadingText = ref('')
|
const fullLoadingText = ref('')
|
||||||
|
|
||||||
// ==================== 头像颜色池 ====================
|
|
||||||
|
|
||||||
/** 头像背景色列表,按索引循环取色 */
|
|
||||||
const avatarColors = ['#1A1A2E', '#4FC2C9', '#F2994A', '#6C5CE7', '#E17055', '#00B894', '#FDCB6E']
|
|
||||||
|
|
||||||
// ==================== 类型定义 ====================
|
// ==================== 类型定义 ====================
|
||||||
|
|
||||||
/** 简历列表项(前端展示用) */
|
/** 简历列表项(前端展示用) */
|
||||||
interface ResumeItem {
|
interface ResumeItem {
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
avatarLetter: string
|
|
||||||
avatarColor: string
|
|
||||||
isDefault: boolean
|
isDefault: boolean
|
||||||
targetJob: string
|
targetJob: string
|
||||||
updatedAt: string
|
updatedAt: string
|
||||||
createdAt: string
|
updatedAtDate: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 工具方法 ====================
|
// ==================== 工具方法 ====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将毫秒时间戳转为友好的相对时间文案
|
* 将毫秒时间戳转为日期格式 YYYY-MM-DD
|
||||||
* @param timestamp 后端返回的毫秒级时间戳
|
|
||||||
*/
|
*/
|
||||||
function formatTime(timestamp?: number): string {
|
function formatDate(timestamp?: number): string {
|
||||||
if (!timestamp) return '-'
|
if (!timestamp) return ''
|
||||||
const date = new Date(timestamp)
|
const date = new Date(timestamp)
|
||||||
const now = Date.now()
|
const y = date.getFullYear()
|
||||||
const diff = now - date.getTime()
|
const m = String(date.getMonth() + 1).padStart(2, '0')
|
||||||
const minutes = Math.floor(diff / 60000)
|
const d = String(date.getDate()).padStart(2, '0')
|
||||||
if (minutes < 1) return '刚刚'
|
return `${y}-${m}-${d}`
|
||||||
if (minutes < 60) return `${minutes}分钟前`
|
|
||||||
const hours = Math.floor(minutes / 60)
|
|
||||||
if (hours < 24) return `${hours}小时前`
|
|
||||||
const days = Math.floor(hours / 24)
|
|
||||||
if (days < 30) return `${days}天前`
|
|
||||||
const months = Math.floor(days / 30)
|
|
||||||
if (months < 12) return `${months}个月前`
|
|
||||||
return `${Math.floor(months / 12)}年前`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将后端简历数据转为前端展示结构
|
* 将后端简历数据转为前端展示结构
|
||||||
*/
|
*/
|
||||||
function mapResumeItem(item: ResumeListItem, index: number): ResumeItem {
|
function mapResumeItem(item: ResumeListItem): ResumeItem {
|
||||||
const name = item.resumeName || '未命名简历'
|
const name = item.resumeName || '未命名简历'
|
||||||
return {
|
return {
|
||||||
id: String(item.id ?? ''),
|
id: String(item.id ?? ''),
|
||||||
name,
|
name,
|
||||||
avatarLetter: name.charAt(0) || '?',
|
|
||||||
avatarColor: avatarColors[index % avatarColors.length],
|
|
||||||
isDefault: item.isDefault === 1,
|
isDefault: item.isDefault === 1,
|
||||||
targetJob: item.targetPosition || '',
|
targetJob: item.targetPosition || '',
|
||||||
updatedAt: formatTime(item.updateTime),
|
updatedAt: String(item.updateTime || ''),
|
||||||
createdAt: formatTime(item.createTime),
|
updatedAtDate: formatDate(item.updateTime),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,50 +220,101 @@ function mapResumeItem(item: ResumeListItem, index: number): ResumeItem {
|
|||||||
|
|
||||||
/** 简历列表 */
|
/** 简历列表 */
|
||||||
const resumeList = ref<ResumeItem[]>([])
|
const resumeList = ref<ResumeItem[]>([])
|
||||||
|
/** 当前页码 */
|
||||||
|
const pageNum = ref(1)
|
||||||
|
/** 每页条数 */
|
||||||
|
const pageSize = ref(20)
|
||||||
|
/** 是否加载更多中 */
|
||||||
|
const loadingMore = ref(false)
|
||||||
|
/** 是否无更多数据 */
|
||||||
|
const hasNoMoreData = ref(false)
|
||||||
|
/** 首次加载中 */
|
||||||
|
const loading = ref(false)
|
||||||
|
/** 网格容器ref */
|
||||||
|
const gridRef = ref<HTMLElement | null>(null)
|
||||||
|
|
||||||
/** 加载简历列表 */
|
/** 加载简历列表(首页) */
|
||||||
async function loadResumeList() {
|
async function loadResumeList() {
|
||||||
|
loading.value = true
|
||||||
|
pageNum.value = 1
|
||||||
|
hasNoMoreData.value = false
|
||||||
try {
|
try {
|
||||||
const res = await fetchResumeList()
|
const res = await fetchResumeList(pageSize.value)
|
||||||
if (res.code === '0' && res.data) {
|
if (res.code === '0' && res.data) {
|
||||||
resumeList.value = res.data.map(mapResumeItem)
|
resumeList.value = res.data.map(mapResumeItem)
|
||||||
|
// 如果返回数量少于 pageSize,说明没有更多了
|
||||||
|
if (res.data.length < pageSize.value) {
|
||||||
|
hasNoMoreData.value = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('获取简历列表失败', e)
|
console.error('获取简历列表失败', e)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
// 首次加载后检查是否需要自动填满容器
|
||||||
|
nextTick(() => { autoFillIfNeeded() })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 生命周期 ====================
|
/** 加载下一页 */
|
||||||
|
async function loadNextPage() {
|
||||||
onMounted(() => {
|
if (loadingMore.value || hasNoMoreData.value) return
|
||||||
loadResumeList()
|
loadingMore.value = true
|
||||||
})
|
pageNum.value++
|
||||||
|
|
||||||
// ==================== 从个人资料创建简历 ====================
|
|
||||||
|
|
||||||
/** 防抖锁:防止多次点击 */
|
|
||||||
const creatingFromProfile = ref(false)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从个人资料创建简历(带防抖)
|
|
||||||
*/
|
|
||||||
async function handleCreateFromProfile() {
|
|
||||||
if (creatingFromProfile.value) return
|
|
||||||
creatingFromProfile.value = true
|
|
||||||
try {
|
try {
|
||||||
const res = await createResumeFromProfile()
|
const res = await fetchResumeList(pageSize.value)
|
||||||
if (res.code === '0') {
|
if (res.code === '0' && res.data) {
|
||||||
ElMessage.success('创建成功')
|
if (res.data.length === 0) {
|
||||||
await loadResumeList()
|
hasNoMoreData.value = true
|
||||||
|
pageNum.value--
|
||||||
|
} else {
|
||||||
|
resumeList.value.push(...res.data.map(mapResumeItem))
|
||||||
|
if (res.data.length < pageSize.value) {
|
||||||
|
hasNoMoreData.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('从个人资料创建简历失败', e)
|
pageNum.value--
|
||||||
|
console.error('加载下一页失败', e)
|
||||||
} finally {
|
} finally {
|
||||||
creatingFromProfile.value = false
|
loadingMore.value = false
|
||||||
|
nextTick(() => { autoFillIfNeeded() })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 页面状态 ====================
|
/** 自动填满容器:当列表内容不足以产生滚动条且还有更多数据时,自动加载下一页 */
|
||||||
|
function autoFillIfNeeded() {
|
||||||
|
const el = gridRef.value
|
||||||
|
if (!el) return
|
||||||
|
if (el.scrollHeight <= el.clientHeight && !hasNoMoreData.value && !loadingMore.value && !loading.value) {
|
||||||
|
loadNextPage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 网格滚动事件 — 触底自动加载 */
|
||||||
|
function onGridScroll() {
|
||||||
|
const el = gridRef.value
|
||||||
|
if (!el) return
|
||||||
|
if (el.scrollHeight - el.scrollTop - el.clientHeight < 100) {
|
||||||
|
loadNextPage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 卡片菜单状态 ====================
|
||||||
|
|
||||||
|
/** 当前展开菜单的简历ID */
|
||||||
|
const activeMenuId = ref<string>('')
|
||||||
|
|
||||||
|
/** 切换菜单 */
|
||||||
|
function toggleMenu(id: string) {
|
||||||
|
activeMenuId.value = activeMenuId.value === id ? '' : id
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 点击页面其他区域关闭菜单 */
|
||||||
|
function closeMenuOnClickOutside() {
|
||||||
|
activeMenuId.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
// ==================== 编辑简历名称弹窗状态 ====================
|
// ==================== 编辑简历名称弹窗状态 ====================
|
||||||
|
|
||||||
@@ -279,7 +333,7 @@ const editTargetPosition = ref('')
|
|||||||
const exportDialogVisible = ref(false)
|
const exportDialogVisible = ref(false)
|
||||||
/** 当前导出的简历 ID */
|
/** 当前导出的简历 ID */
|
||||||
const exportResumeId = ref('')
|
const exportResumeId = ref('')
|
||||||
/** 当前导出的简历名称(用于文件名) */
|
/** 当前导出的简历名称 */
|
||||||
const exportResumeName = ref('')
|
const exportResumeName = ref('')
|
||||||
|
|
||||||
// ==================== 上传简历弹窗状态 ====================
|
// ==================== 上传简历弹窗状态 ====================
|
||||||
@@ -299,6 +353,7 @@ function handleEditName(item: ResumeItem) {
|
|||||||
|
|
||||||
/** 设为默认简历 */
|
/** 设为默认简历 */
|
||||||
async function handleSetDefault(id: string) {
|
async function handleSetDefault(id: string) {
|
||||||
|
activeMenuId.value = ''
|
||||||
try {
|
try {
|
||||||
const res = await setDefaultResume(id)
|
const res = await setDefaultResume(id)
|
||||||
if (res.code === '0') {
|
if (res.code === '0') {
|
||||||
@@ -314,6 +369,7 @@ async function handleSetDefault(id: string) {
|
|||||||
|
|
||||||
/** 导出简历 */
|
/** 导出简历 */
|
||||||
function handleExport(item: ResumeItem) {
|
function handleExport(item: ResumeItem) {
|
||||||
|
activeMenuId.value = ''
|
||||||
exportResumeId.value = item.id
|
exportResumeId.value = item.id
|
||||||
exportResumeName.value = item.name || '简历'
|
exportResumeName.value = item.name || '简历'
|
||||||
exportDialogVisible.value = true
|
exportDialogVisible.value = true
|
||||||
@@ -321,6 +377,7 @@ function handleExport(item: ResumeItem) {
|
|||||||
|
|
||||||
/** 删除简历 */
|
/** 删除简历 */
|
||||||
async function handleDelete(id: string, isDefault: boolean) {
|
async function handleDelete(id: string, isDefault: boolean) {
|
||||||
|
activeMenuId.value = ''
|
||||||
try {
|
try {
|
||||||
await ElMessageBox.confirm('确定要删除这份简历吗?', '提示', {
|
await ElMessageBox.confirm('确定要删除这份简历吗?', '提示', {
|
||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
@@ -328,7 +385,7 @@ async function handleDelete(id: string, isDefault: boolean) {
|
|||||||
type: 'warning',
|
type: 'warning',
|
||||||
})
|
})
|
||||||
|
|
||||||
if(resumeList.value.length<=1||isDefault){
|
if (resumeList.value.length <= 1 || isDefault) {
|
||||||
ElMessage.warning('默认简历不可删除')
|
ElMessage.warning('默认简历不可删除')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -352,9 +409,8 @@ function handleUpload() {
|
|||||||
uploadDialogVisible.value = true
|
uploadDialogVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 上传弹窗确认回调 — 接收 File 对象,调用接口上传 */
|
/** 上传弹窗确认回调 */
|
||||||
async function handleUploadConfirm(file: File) {
|
async function handleUploadConfirm(file: File) {
|
||||||
// 显示步骤进度遮罩
|
|
||||||
showUploadProgress.value = true
|
showUploadProgress.value = true
|
||||||
uploadProgressDone.value = false
|
uploadProgressDone.value = false
|
||||||
pendingResumeId.value = ''
|
pendingResumeId.value = ''
|
||||||
@@ -362,11 +418,8 @@ async function handleUploadConfirm(file: File) {
|
|||||||
try {
|
try {
|
||||||
const res = await uploadResume(file)
|
const res = await uploadResume(file)
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
// 上传成功,刷新列表
|
|
||||||
loadResumeList()
|
loadResumeList()
|
||||||
// 缓存简历ID,等进度走完后跳转
|
|
||||||
pendingResumeId.value = res.data.resumeId
|
pendingResumeId.value = res.data.resumeId
|
||||||
// 通知进度组件接口已完成
|
|
||||||
uploadProgressDone.value = true
|
uploadProgressDone.value = true
|
||||||
} else {
|
} else {
|
||||||
showUploadProgress.value = false
|
showUploadProgress.value = false
|
||||||
@@ -390,9 +443,9 @@ const uploadProgressTitle = '正在解析简历'
|
|||||||
const uploadProgressSubtitle = '正在识别教育背景、工作经历与技能关键词'
|
const uploadProgressSubtitle = '正在识别教育背景、工作经历与技能关键词'
|
||||||
/** 4个步骤名称 */
|
/** 4个步骤名称 */
|
||||||
const uploadProgressSteps = ['教育背景解析...', '工作经历解析...', '技能特长解析...', '个人资料最终确认']
|
const uploadProgressSteps = ['教育背景解析...', '工作经历解析...', '技能特长解析...', '个人资料最终确认']
|
||||||
/** 每步时长4600毫秒 */
|
/** 每步时长 */
|
||||||
const uploadProgressDurations = [4200, 4200, 4200, 4200]
|
const uploadProgressDurations = [4200, 4200, 4200, 4200]
|
||||||
/** 缓存的简历ID(等进度走完后跳转) */
|
/** 缓存的简历ID */
|
||||||
const pendingResumeId = ref('')
|
const pendingResumeId = ref('')
|
||||||
|
|
||||||
/** 解析进度走完后跳转详情页 */
|
/** 解析进度走完后跳转详情页 */
|
||||||
@@ -413,4 +466,15 @@ function handleUploadProgressClose() {
|
|||||||
function goDetail(id: string) {
|
function goDetail(id: string) {
|
||||||
router.push(`/resume/${id}`)
|
router.push(`/resume/${id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== 生命周期 ====================
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loadResumeList()
|
||||||
|
document.addEventListener('click', closeMenuOnClickOutside)
|
||||||
|
})
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
document.removeEventListener('click', closeMenuOnClickOutside)
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user