Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0631cce83d | ||
|
|
351190a6d8 | ||
|
|
d556170969 | ||
|
|
1e103627f8 | ||
|
|
8b9ebd6ddc | ||
|
|
5abd6d27d6 | ||
|
|
bb7a8c55b2 | ||
|
|
a0f01dd697 | ||
|
|
58a027296a | ||
|
|
010a80be81 |
@@ -31,16 +31,18 @@ declare module 'vue' {
|
|||||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||||
ElIcon: typeof import('element-plus/es')['ElIcon']
|
ElIcon: typeof import('element-plus/es')['ElIcon']
|
||||||
ElInput: typeof import('element-plus/es')['ElInput']
|
ElInput: typeof import('element-plus/es')['ElInput']
|
||||||
ElOption: typeof import('element-plus/es')['ElOption']
|
|
||||||
ElRadio: typeof import('element-plus/es')['ElRadio']
|
ElRadio: typeof import('element-plus/es')['ElRadio']
|
||||||
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
|
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
|
||||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
|
||||||
ElSkeleton: typeof import('element-plus/es')['ElSkeleton']
|
ElSkeleton: typeof import('element-plus/es')['ElSkeleton']
|
||||||
ElSkeletonItem: typeof import('element-plus/es')['ElSkeletonItem']
|
ElSkeletonItem: typeof import('element-plus/es')['ElSkeletonItem']
|
||||||
ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
|
||||||
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']
|
||||||
@@ -51,6 +53,7 @@ declare module 'vue' {
|
|||||||
JobResumeCustomDialog: typeof import('./src/components/JobResumeCustomDialog.vue')['default']
|
JobResumeCustomDialog: typeof import('./src/components/JobResumeCustomDialog.vue')['default']
|
||||||
JobResumeCustomEditPanel: typeof import('./src/components/JobResumeCustomEditPanel.vue')['default']
|
JobResumeCustomEditPanel: typeof import('./src/components/JobResumeCustomEditPanel.vue')['default']
|
||||||
JobResumeTemplate: typeof import('./src/components/JobResumeTemplate.vue')['default']
|
JobResumeTemplate: typeof import('./src/components/JobResumeTemplate.vue')['default']
|
||||||
|
JobStatsOverview: typeof import('./src/components/JobStatsOverview.vue')['default']
|
||||||
LoginDialog: typeof import('./src/components/LoginDialog.vue')['default']
|
LoginDialog: typeof import('./src/components/LoginDialog.vue')['default']
|
||||||
MemberAccessDialog: typeof import('./src/components/MemberAccessDialog.vue')['default']
|
MemberAccessDialog: typeof import('./src/components/MemberAccessDialog.vue')['default']
|
||||||
MemberDialog: typeof import('./src/components/MemberDialog.vue')['default']
|
MemberDialog: typeof import('./src/components/MemberDialog.vue')['default']
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
google-site-verification: google18c40aea647ea1cd.html
|
||||||
@@ -1,12 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-config-provider :locale="zhCn">
|
<el-config-provider :locale="zhCn">
|
||||||
<RouterView />
|
<RouterView />
|
||||||
|
<!-- 全局登录弹窗 -->
|
||||||
|
<LoginDialog />
|
||||||
</el-config-provider>
|
</el-config-provider>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { RouterView } from 'vue-router'
|
import { RouterView } from 'vue-router'
|
||||||
import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
||||||
|
import LoginDialog from '@/components/LoginDialog.vue'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|||||||
@@ -301,9 +301,7 @@ export interface OptimizeResumeParams {
|
|||||||
*/
|
*/
|
||||||
export function optimizeAgentResume(params: OptimizeResumeParams) {
|
export function optimizeAgentResume(params: OptimizeResumeParams) {
|
||||||
return aiService.post('/job-agent/optimize-resume', params, {
|
return aiService.post('/job-agent/optimize-resume', params, {
|
||||||
headers: {
|
|
||||||
Token: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjIwMzUyNTM4OTg5MTk4NzA0NjUsInV1SWQiOiI2MmQ5MDE2NTcyNzY0ZmNjODNjZTIyYjRjODA5ZmU5MiJ9.eE-Q5rio5J5kxkS-XPYdmk-1Tgvg6kj6NGoKWMFNU14',
|
|
||||||
},
|
|
||||||
}).then(res => res.data)
|
}).then(res => res.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,291 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
import type { ApiResult } from '@/api/auth'
|
||||||
|
|
||||||
|
// ==================== 校招公告列表接口 ====================
|
||||||
|
|
||||||
|
/** Instant 时间结构(Java Instant 序列化格式) */
|
||||||
|
export interface InstantTime {
|
||||||
|
/** 从 1970-01-01T00:00:00Z 起的秒数 */
|
||||||
|
seconds: number
|
||||||
|
/** 纳秒偏移(0 ~ 999999999) */
|
||||||
|
nanos?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 校招公告列表请求参数 */
|
||||||
|
export interface AnnouncementListParams {
|
||||||
|
/** 当前页码,从1开始 */
|
||||||
|
pageNum?: number
|
||||||
|
/** 每页条数 */
|
||||||
|
pageSize?: number
|
||||||
|
/** 关键字 */
|
||||||
|
keyword?: string
|
||||||
|
/** 发布时间起(不含) */
|
||||||
|
publishTimeStart?: InstantTime | null
|
||||||
|
/** 发布时间止(含) */
|
||||||
|
publishTimeEnd?: InstantTime | null
|
||||||
|
/** 投递截止时间起(不含) */
|
||||||
|
applyEndTimeStart?: InstantTime | null
|
||||||
|
/** 投递截止时间止(含) */
|
||||||
|
applyEndTimeEnd?: InstantTime | null
|
||||||
|
/** 公司类型列表 */
|
||||||
|
companyTypes?: string[]
|
||||||
|
/** 学历要求列表 */
|
||||||
|
educationNames?: string[]
|
||||||
|
/** 招聘届数列表 */
|
||||||
|
recruitYears?: number[]
|
||||||
|
/** 批次列表 */
|
||||||
|
batchNames?: string[]
|
||||||
|
/** 岗位大类列表 */
|
||||||
|
categoryNames?: string[]
|
||||||
|
/** 热招城市列表 */
|
||||||
|
cityNames?: string[]
|
||||||
|
/** 行业列表 */
|
||||||
|
industryNames?: string[]
|
||||||
|
/** 标签列表 */
|
||||||
|
tagNames?: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 校招公告列表项 */
|
||||||
|
export interface AnnouncementItem {
|
||||||
|
/** 公告ID */
|
||||||
|
id: number
|
||||||
|
/** 公司ID */
|
||||||
|
companyId: number
|
||||||
|
/** 公司名称 */
|
||||||
|
companyName: string
|
||||||
|
/** 公司logo */
|
||||||
|
logoUrl: string
|
||||||
|
/** 公告标题 */
|
||||||
|
title: string
|
||||||
|
/** 专业要求 */
|
||||||
|
majorRequire: string
|
||||||
|
/** 发布时间(毫秒时间戳) */
|
||||||
|
publishTime: number | null
|
||||||
|
/** 投递结束时间 */
|
||||||
|
applyEndTime: InstantTime | null
|
||||||
|
/** 投递截止描述 */
|
||||||
|
applyEndDesc: string
|
||||||
|
/** 行业列表 */
|
||||||
|
industryNames: string[]
|
||||||
|
/** 岗位大类列表 */
|
||||||
|
categoryNames: string[]
|
||||||
|
/** 热招城市列表 */
|
||||||
|
cityNames: string[]
|
||||||
|
/** 学历要求列表 */
|
||||||
|
educationNames: string[]
|
||||||
|
/** 招聘届数列表 */
|
||||||
|
recruitYears: number[]
|
||||||
|
/** 批次列表 */
|
||||||
|
batchNames: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 校招公告分页数据 */
|
||||||
|
export interface AnnouncementPageData {
|
||||||
|
/** 当前页码 */
|
||||||
|
pageNum: number
|
||||||
|
/** 每页条数 */
|
||||||
|
pageSize: number
|
||||||
|
/** 总记录数 */
|
||||||
|
total: number
|
||||||
|
/** 数据列表 */
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
export function fetchAnnouncementList(params: AnnouncementListParams = {}) {
|
||||||
|
return request.post<any, ApiResult<AnnouncementPageData>>('/public/recruitAnnouncement/page', {
|
||||||
|
pageNum: params.pageNum ?? 1,
|
||||||
|
pageSize: params.pageSize ?? 10,
|
||||||
|
...params,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 校招公告详情接口 ====================
|
||||||
|
|
||||||
|
/** 校招公告详情数据 */
|
||||||
|
export interface AnnouncementDetail {
|
||||||
|
/** 公告ID */
|
||||||
|
id: number
|
||||||
|
/** 公司ID */
|
||||||
|
companyId: number
|
||||||
|
/** 公司名称 */
|
||||||
|
companyName: string
|
||||||
|
/** 公司logo */
|
||||||
|
logoUrl: string
|
||||||
|
/** 公司类型 */
|
||||||
|
companyType: string
|
||||||
|
/** 公告标题 */
|
||||||
|
title: string
|
||||||
|
/** 公司简介 */
|
||||||
|
companyIntro: string
|
||||||
|
/** 公司规模 */
|
||||||
|
companyScale: string
|
||||||
|
/** 面向对象 */
|
||||||
|
targetAudience: string
|
||||||
|
/** 专业要求 */
|
||||||
|
majorRequire: string
|
||||||
|
/** 招聘岗位 */
|
||||||
|
recruitPosition: string
|
||||||
|
/** 备注 */
|
||||||
|
remark: string
|
||||||
|
/** 是否笔试 */
|
||||||
|
writtenExam: string
|
||||||
|
/** 投递开始时间 */
|
||||||
|
applyStartTime: InstantTime | null
|
||||||
|
/** 投递结束时间 */
|
||||||
|
applyEndTime: InstantTime | null
|
||||||
|
/** 投递截止描述 */
|
||||||
|
applyEndDesc: string
|
||||||
|
/** 专属内推码 */
|
||||||
|
inviteCode: string
|
||||||
|
/** 信息来源说明 */
|
||||||
|
source: string
|
||||||
|
/** 公告地址 */
|
||||||
|
announcementUrl: string
|
||||||
|
/** 投递地址 */
|
||||||
|
applyUrl: string
|
||||||
|
/** 发布时间 */
|
||||||
|
publishTime: InstantTime | null
|
||||||
|
/** 清洗状态 */
|
||||||
|
cleanStatus: number
|
||||||
|
/** 状态 */
|
||||||
|
status: number
|
||||||
|
/** 创建时间 */
|
||||||
|
createTime: InstantTime | null
|
||||||
|
/** 更新时间 */
|
||||||
|
updateTime: InstantTime | null
|
||||||
|
/** 行业列表 */
|
||||||
|
industryNames: string[]
|
||||||
|
/** 岗位大类列表 */
|
||||||
|
categoryNames: string[]
|
||||||
|
/** 热招城市列表 */
|
||||||
|
cityNames: string[]
|
||||||
|
/** 学历要求列表 */
|
||||||
|
educationNames: string[]
|
||||||
|
/** 招聘届数列表 */
|
||||||
|
recruitYears: number[]
|
||||||
|
/** 批次列表 */
|
||||||
|
batchNames: string[]
|
||||||
|
/** 标签列表 */
|
||||||
|
tagNames: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取校招公告详情
|
||||||
|
* GET /public/recruitAnnouncement/detail
|
||||||
|
*/
|
||||||
|
export function fetchAnnouncementDetail(id: string) {
|
||||||
|
return request.get<any, ApiResult<AnnouncementDetail>>('/public/recruitAnnouncement/detail', {
|
||||||
|
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,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -54,6 +54,19 @@ export async function smsLogin(mobileNumber: string, code: string, inviteCode?:
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 超级管理员登录
|
||||||
|
* POST /public/login/superAdminLogin
|
||||||
|
* Body: { mobileNumber, password }
|
||||||
|
* 返回结构与 smsLogin 一致
|
||||||
|
*/
|
||||||
|
export function superAdminLogin(mobileNumber: string, password: string) {
|
||||||
|
return request.post<any, ApiResult<LoginData>>('/public/login/superAdminLogin', {
|
||||||
|
mobileNumber,
|
||||||
|
password,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查登录状态
|
* 检查登录状态
|
||||||
* GET /public/checkLogin
|
* GET /public/checkLogin
|
||||||
|
|||||||
@@ -33,12 +33,16 @@ export interface JobListItem {
|
|||||||
id: string
|
id: string
|
||||||
/** 岗位标题 */
|
/** 岗位标题 */
|
||||||
title: string
|
title: string
|
||||||
|
/** 薪资描述 */
|
||||||
|
salary?: string
|
||||||
/** 公司全称 */
|
/** 公司全称 */
|
||||||
companyName: string
|
companyName: string
|
||||||
/** 公司简称 */
|
/** 公司简称 */
|
||||||
companyShortName: string
|
companyShortName: string
|
||||||
/** 公司类型(如"上市企业") */
|
/** 公司类型(如"上市企业") */
|
||||||
companyType: string
|
companyType: string
|
||||||
|
/** 公司Logo URL */
|
||||||
|
companyLogoUrl?: string
|
||||||
/** 公司标签列表(如 ["新能源汽车", "乘用车制造", "10000人以上"]) */
|
/** 公司标签列表(如 ["新能源汽车", "乘用车制造", "10000人以上"]) */
|
||||||
companyTags: string[]
|
companyTags: string[]
|
||||||
/** 地区名称 */
|
/** 地区名称 */
|
||||||
@@ -51,13 +55,19 @@ export interface JobListItem {
|
|||||||
sourceUrl: string
|
sourceUrl: string
|
||||||
/** 是否已收藏 */
|
/** 是否已收藏 */
|
||||||
isFavorite: boolean
|
isFavorite: boolean
|
||||||
|
/** 投递状态(null=未投递,0=已投递 1=面试中 2=有Offer 3=未通过 4=已结束) */
|
||||||
|
applicationStatus?: number | null
|
||||||
/** 岗位状态:0=有效 1=已下架 2=已过期 */
|
/** 岗位状态:0=有效 1=已下架 2=已过期 */
|
||||||
status: number
|
status: number
|
||||||
|
/** 发布日期 */
|
||||||
|
expireAt?: string | null
|
||||||
|
/** 脚本名字 */
|
||||||
|
pyname?: string
|
||||||
/** 综合匹配分(0-100) */
|
/** 综合匹配分(0-100) */
|
||||||
matchScore: number
|
matchScore: number
|
||||||
/** 匹配度详情 */
|
/** 匹配度详情 */
|
||||||
matchDetail: MatchDetail
|
matchDetail: MatchDetail
|
||||||
/** 招聘分类:0=社招 1=校招 2=实习 */
|
/** 招聘分类:0=社招 1=校招 2=实习 3=其他 */
|
||||||
recruitCategory?: number
|
recruitCategory?: number
|
||||||
/** 学历要求 0=不限 1=大专 2=本科 3=硕士 4=博士 */
|
/** 学历要求 0=不限 1=大专 2=本科 3=硕士 4=博士 */
|
||||||
education?: number
|
education?: number
|
||||||
@@ -97,12 +107,62 @@ export interface JobListParams {
|
|||||||
statusFilter?: number[]
|
statusFilter?: number[]
|
||||||
/** 搜索关键词 */
|
/** 搜索关键词 */
|
||||||
keyword?: string
|
keyword?: string
|
||||||
/** 招聘分类 0=校招 1=实习 2=社招 3=其他 */
|
/** 招聘分类 0=社招 1=校招 2=实习 3=其他 */
|
||||||
recruitCategory?: number
|
recruitCategory?: number
|
||||||
/** 排除岗位ID列表(用于推荐时排除已推荐过的) */
|
/** 排除岗位ID列表(用于推荐时排除已推荐过的) */
|
||||||
excludeJobIds?: number[]
|
excludeJobIds?: number[]
|
||||||
/** 公司类型列表(上市企业、独角兽、国企等,可多选) */
|
/** 公司类型列表(上市企业、独角兽、国企等,可多选) */
|
||||||
companyTypes?: string[]
|
companyTypes?: string[]
|
||||||
|
/** 学历要求列表 0=不限 1=大专 2=本科 3=硕士 4=博士(可多选) */
|
||||||
|
educations?: number[]
|
||||||
|
/** 发布开始时间(ISO 8601格式,如 "2026-08-10T21:00:00Z") */
|
||||||
|
publishStartTime?: string
|
||||||
|
/** 发布截止时间(ISO 8601格式,如 "2026-08-11T21:00:00Z") */
|
||||||
|
publishEndTime?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 热门推荐接口 ====================
|
||||||
|
|
||||||
|
/** 热门行业项 */
|
||||||
|
export interface HotIndustryItem {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 热门岗位项 */
|
||||||
|
export interface HotCategoryItem {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 热门城市项 */
|
||||||
|
export interface HotCityItem {
|
||||||
|
code: string
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取热门推荐行业
|
||||||
|
* GET /job/industry/hot
|
||||||
|
*/
|
||||||
|
export function fetchHotIndustries() {
|
||||||
|
return request.get<any, ApiResult<HotIndustryItem[]>>('/job/public/industry/hot')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取热门推荐岗位
|
||||||
|
* GET /job/category/hot
|
||||||
|
*/
|
||||||
|
export function fetchHotCategories() {
|
||||||
|
return request.get<any, ApiResult<HotCategoryItem[]>>('/job/public/category/hot')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取热门推荐城市
|
||||||
|
* GET /job/city/hot
|
||||||
|
*/
|
||||||
|
export function fetchHotCities() {
|
||||||
|
return request.get<any, ApiResult<HotCityItem[]>>('/job/public/city/hot')
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 求职意向 ====================
|
// ==================== 求职意向 ====================
|
||||||
@@ -149,7 +209,33 @@ export function saveJobIntention(data: JobIntention) {
|
|||||||
* @param params 岗位列表查询参数
|
* @param params 岗位列表查询参数
|
||||||
*/
|
*/
|
||||||
export function fetchJobList(params: JobListParams = {}) {
|
export function fetchJobList(params: JobListParams = {}) {
|
||||||
return request.post<any, ApiResult<JobPageData>>('/job/list', {
|
return request.post<any, ApiResult<JobPageData>>('/public/job/list', {
|
||||||
|
pageNum: params.pageNum ?? 1,
|
||||||
|
pageSize: params.pageSize ?? 15,
|
||||||
|
...params,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取筛选岗位数量
|
||||||
|
* POST /job/list/count
|
||||||
|
* @param params 与岗位列表相同的筛选参数
|
||||||
|
*/
|
||||||
|
export function fetchJobListCount(params: JobListParams = {}) {
|
||||||
|
return request.post<any, ApiResult<number>>('/job/list/count', {
|
||||||
|
pageNum: params.pageNum ?? 1,
|
||||||
|
pageSize: params.pageSize ?? 10,
|
||||||
|
...params,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 深度匹配岗位列表
|
||||||
|
* POST /job/list/match
|
||||||
|
* @param params 与岗位列表相同的筛选参数
|
||||||
|
*/
|
||||||
|
export function fetchJobListMatch(params: JobListParams = {}) {
|
||||||
|
return request.post<any, ApiResult<JobPageData>>('/job/list/match', {
|
||||||
pageNum: params.pageNum ?? 1,
|
pageNum: params.pageNum ?? 1,
|
||||||
pageSize: params.pageSize ?? 15,
|
pageSize: params.pageSize ?? 15,
|
||||||
...params,
|
...params,
|
||||||
|
|||||||
|
After Width: | Height: | Size: 458 KiB |
|
After Width: | Height: | Size: 504 KiB |
|
After Width: | Height: | Size: 448 KiB |
|
After Width: | Height: | Size: 524 KiB |
|
After Width: | Height: | Size: 2.0 MiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 1.8 MiB |
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 167 KiB |
|
Before Width: | Height: | Size: 2.3 MiB |
|
Before Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 462 KiB |
|
Before Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 177 KiB |
|
Before Width: | Height: | Size: 246 KiB |
|
Before Width: | Height: | Size: 114 KiB |
|
Before Width: | Height: | Size: 168 KiB |
|
Before Width: | Height: | Size: 221 KiB |
|
Before Width: | Height: | Size: 485 KiB |
|
Before Width: | Height: | Size: 232 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 127 KiB |
|
Before Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 92 KiB |
|
Before Width: | Height: | Size: 390 KiB |
|
Before Width: | Height: | Size: 114 KiB |
|
Before Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 408 KiB |
|
Before Width: | Height: | Size: 177 KiB |
|
Before Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 247 KiB |
|
Before Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 83 KiB |
|
Before Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 1.8 MiB |
@@ -450,6 +450,9 @@ body:not(#_) {
|
|||||||
.flex-warp{
|
.flex-warp{
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
.flex0{
|
||||||
|
flex: 0;
|
||||||
|
}
|
||||||
.flex1{
|
.flex1{
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,67 @@
|
|||||||
// Agent浏览器插件安装步骤指引组件样式
|
// Agent浏览器插件安装步骤指引组件样式
|
||||||
@use '../variables' as *;
|
@use '../variables' as *;
|
||||||
|
|
||||||
|
/* 组件最外层容器 */
|
||||||
|
.agent-browser-guide {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tab切换栏 */
|
||||||
|
.agent-browser-guide__tabs {
|
||||||
|
display: flex;
|
||||||
|
border-bottom: 1px solid #F0F0F0;
|
||||||
|
margin-bottom: 0.16rem;
|
||||||
|
padding: 0 0.32rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 单个Tab */
|
||||||
|
.agent-browser-guide__tab {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.06rem;
|
||||||
|
padding: 0.14rem 0.24rem;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
font-weight: 450;
|
||||||
|
color: $text-middle;
|
||||||
|
cursor: pointer;
|
||||||
|
border-bottom: 2px solid transparent;
|
||||||
|
transition: color 0.2s, border-color 0.2s;
|
||||||
|
flex: 1;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $accent;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--active {
|
||||||
|
color: $accent;
|
||||||
|
font-weight: 600;
|
||||||
|
border-bottom-color: $accent;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 链接样式 */
|
||||||
|
.agent-browser-guide__link {
|
||||||
|
color: $accent;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* URL截断文本 */
|
||||||
|
.agent-browser-guide__url-text {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
max-width: 2.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
/* 步骤内容区域 */
|
/* 步骤内容区域 */
|
||||||
.agent-browser-guide-drawer__body {
|
.agent-browser-guide-drawer__body {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
@@ -74,6 +135,11 @@
|
|||||||
border-radius: 0.12rem;
|
border-radius: 0.12rem;
|
||||||
height: 0.44rem;
|
height: 0.44rem;
|
||||||
margin-left: 0.4rem;
|
margin-left: 0.4rem;
|
||||||
|
|
||||||
|
&--wide {
|
||||||
|
width: auto;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.agent-browser-guide-drawer__download-name {
|
.agent-browser-guide-drawer__download-name {
|
||||||
@@ -96,6 +162,7 @@
|
|||||||
font-weight: 620;
|
font-weight: 620;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background 0.2s;
|
transition: background 0.2s;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: $accent-hover;
|
background: $accent-hover;
|
||||||
@@ -109,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); }
|
||||||
|
}
|
||||||
@@ -56,15 +56,11 @@
|
|||||||
|
|
||||||
// ==================== 下拉面板 ====================
|
// ==================== 下拉面板 ====================
|
||||||
&__panel {
|
&__panel {
|
||||||
position: absolute;
|
|
||||||
top: calc(100% + 0.06rem);
|
|
||||||
left: 0;
|
|
||||||
width: 3.6rem;
|
width: 3.6rem;
|
||||||
background: $bg-white;
|
background: $bg-white;
|
||||||
border: 1px solid $border-color;
|
border: 1px solid $border-color;
|
||||||
border-radius: 0.1rem;
|
border-radius: 0.1rem;
|
||||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
||||||
z-index: 100;
|
|
||||||
padding: 0.1rem;
|
padding: 0.1rem;
|
||||||
|
|
||||||
// 只显示一栏时缩窄面板
|
// 只显示一栏时缩窄面板
|
||||||
|
|||||||
@@ -57,15 +57,11 @@
|
|||||||
|
|
||||||
// ==================== 下拉面板 ====================
|
// ==================== 下拉面板 ====================
|
||||||
&__panel {
|
&__panel {
|
||||||
position: absolute;
|
|
||||||
top: calc(100% + 0.06rem);
|
|
||||||
left: 0;
|
|
||||||
width: 4.8rem;
|
width: 4.8rem;
|
||||||
background: $bg-white;
|
background: $bg-white;
|
||||||
border: 1px solid $border-color;
|
border: 1px solid $border-color;
|
||||||
border-radius: 0.1rem;
|
border-radius: 0.1rem;
|
||||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
||||||
z-index: 100;
|
|
||||||
padding: 0.1rem;
|
padding: 0.1rem;
|
||||||
|
|
||||||
// 只显示一栏时缩窄面板
|
// 只显示一栏时缩窄面板
|
||||||
|
|||||||
@@ -1,86 +1,5 @@
|
|||||||
@use '../variables' as *;
|
@use '../variables' as *;
|
||||||
|
|
||||||
/* ==================== 岗位统计卡片 ==================== */
|
|
||||||
.job-stats-cards {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.16rem;
|
|
||||||
margin-left: auto;
|
|
||||||
filter: drop-shadow(0px 2px 10px rgba(0, 221, 179, 0.16));
|
|
||||||
|
|
||||||
/* 全网实时岗位卡片 */
|
|
||||||
&__count-card {
|
|
||||||
position: relative;
|
|
||||||
height: 0.43rem;
|
|
||||||
background: #0A171C;
|
|
||||||
border: 1px solid #1C4C55;
|
|
||||||
border-radius: 0.05rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 状态指示圆点 */
|
|
||||||
&__dot {
|
|
||||||
//position: absolute;
|
|
||||||
width: 0.08rem;
|
|
||||||
height: 0.08rem;
|
|
||||||
background: #2FE9F4;
|
|
||||||
border-radius: 50%;
|
|
||||||
box-shadow: 0px 0px 4px rgba(47, 233, 244, 0.75);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 岗位数字 */
|
|
||||||
&__count-num {
|
|
||||||
|
|
||||||
font-family: 'MiSans';
|
|
||||||
font-weight: 630;
|
|
||||||
font-size: 0.16rem;
|
|
||||||
line-height: 0.21rem;
|
|
||||||
color: #F4FFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 岗位标签文字 */
|
|
||||||
&__count-label {
|
|
||||||
font-family: 'MiSans';
|
|
||||||
font-weight: 330;
|
|
||||||
font-size: 0.10rem;
|
|
||||||
line-height: 0.13rem;
|
|
||||||
color: #8AA8AF;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 可投率卡片 */
|
|
||||||
&__match-card {
|
|
||||||
position: relative;
|
|
||||||
width: 0.52rem;
|
|
||||||
height: 0.42rem;
|
|
||||||
background: #08161B;
|
|
||||||
border: 1px solid #20626D;
|
|
||||||
border-radius: 0.05rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 可投率数字 */
|
|
||||||
&__match-num {
|
|
||||||
position: absolute;
|
|
||||||
left: 0.08rem;
|
|
||||||
top: 0.04rem;
|
|
||||||
font-family: 'MiSans';
|
|
||||||
font-weight: 630;
|
|
||||||
font-size: 0.16rem;
|
|
||||||
line-height: 0.21rem;
|
|
||||||
color: #2FE9F4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 可投率标签文字 */
|
|
||||||
&__match-label {
|
|
||||||
position: absolute;
|
|
||||||
left: 0.08rem;
|
|
||||||
top: 0.245rem;
|
|
||||||
font-family: 'MiSans';
|
|
||||||
font-weight: 620;
|
|
||||||
font-size: 0.10rem;
|
|
||||||
line-height: 0.13rem;
|
|
||||||
color: #8FB7BE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.job-page-header {
|
.job-page-header {
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1398,9 +1398,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 立即去投递按钮
|
// 下载专属简历按钮
|
||||||
&__submit-btn {
|
&__submit-btn {
|
||||||
flex: 1;
|
width: 100%;
|
||||||
height: 0.48rem;
|
height: 0.48rem;
|
||||||
background: $btn-dark;
|
background: $btn-dark;
|
||||||
color: $bg-white;
|
color: $bg-white;
|
||||||
@@ -1415,6 +1415,20 @@
|
|||||||
background: $btn-dark-hover;
|
background: $btn-dark-hover;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 下载专属简历按钮包裹(含下拉菜单定位)
|
||||||
|
&__submit-wrap {
|
||||||
|
position: relative;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
.job-resume-custom-dialog__top-download-menu {
|
||||||
|
top: auto;
|
||||||
|
bottom: 100%;
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0.06rem;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 右侧滑入动画
|
// 右侧滑入动画
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
@use '../variables' as *;
|
||||||
|
|
||||||
|
.job-stats-overview {
|
||||||
|
/* 固定宽度卡片 */
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
|
width: 3.25rem;
|
||||||
|
padding: 0.24rem 0.20rem;
|
||||||
|
background: linear-gradient(180deg, #EDF9FA 0%, #FFFFFF 20.63%);
|
||||||
|
border: 1px solid #F0F0F0;
|
||||||
|
box-shadow: 0 0.02rem 0.06rem rgba(15, 23, 42, 0.025);
|
||||||
|
border-radius: 0.12rem;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 1.8rem;
|
||||||
|
|
||||||
|
/* 右上角装饰图片 */
|
||||||
|
&__icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 0.10rem;
|
||||||
|
right: 0.10rem;
|
||||||
|
width: 0.86rem;
|
||||||
|
height: 0.72rem;
|
||||||
|
object-fit: contain;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 内容纵向居中容器 */
|
||||||
|
&__inner {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.32rem;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 标题区域 */
|
||||||
|
&__header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 0.04rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.18rem;
|
||||||
|
line-height: 0.24rem;
|
||||||
|
color: #1A1A1A;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__date {
|
||||||
|
font-weight: 330;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
color: #64748B;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 数据指标行 */
|
||||||
|
&__metrics {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.20rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 单个指标 */
|
||||||
|
&__metric-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.04rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__metric-num {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.30rem;
|
||||||
|
line-height: 0.40rem;
|
||||||
|
color: $accent;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__metric-label {
|
||||||
|
font-weight: 330;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
color: #6A7282;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 竖线分隔 */
|
||||||
|
&__divider {
|
||||||
|
width: 0;
|
||||||
|
height: 0.52rem;
|
||||||
|
border-left: 1px solid #F0F0F0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,376 @@
|
|||||||
|
@use '../variables' as *;
|
||||||
|
|
||||||
|
/* 登录弹窗遮罩层 */
|
||||||
|
.login-dialog-overlay {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100vw;
|
||||||
|
height: var(--app-height, 100vh);
|
||||||
|
background: rgba(0, 0, 0, 0.45);
|
||||||
|
z-index: 2050;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 弹窗底座盒子 */
|
||||||
|
.login-dialog-box {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
position: relative;
|
||||||
|
width: 5.6rem;
|
||||||
|
min-height: 4.57rem;
|
||||||
|
background: radial-gradient(58.14% 30.59% at 100% 0%, #D2F2F3 0%, #FFFFFF 100%);
|
||||||
|
border: 1px solid #F0F0F0;
|
||||||
|
border-radius: 0.32rem;
|
||||||
|
padding: 0.48rem 0.6rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 关闭按钮 */
|
||||||
|
.login-dialog-box__close {
|
||||||
|
position: absolute;
|
||||||
|
top: 0.2rem;
|
||||||
|
right: 0.24rem;
|
||||||
|
width: 0.32rem;
|
||||||
|
height: 0.32rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 50%;
|
||||||
|
transition: background 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 0.2rem;
|
||||||
|
height: 0.2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Logo 行 */
|
||||||
|
.login-dialog-box__logo-row {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 0.4rem;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 1.6rem;
|
||||||
|
height: 0.4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 表单包裹 */
|
||||||
|
.login-dialog-box__form-wrap {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.24rem;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 标题 */
|
||||||
|
.login-dialog-box__heading {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.05rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-box__title {
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 0.24rem;
|
||||||
|
line-height: 0.22rem;
|
||||||
|
color: #18181A;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-box__subtitle {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
margin-top: 0.08rem;
|
||||||
|
margin-bottom: 0.08rem;
|
||||||
|
color: #616367;
|
||||||
|
|
||||||
|
> span:nth-child(2) {
|
||||||
|
color: $accent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 手机号输入行 */
|
||||||
|
.login-dialog-box__phone-row {
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 0.56rem;
|
||||||
|
background: #FFFFFF;
|
||||||
|
border: 1px solid #C8C9CD;
|
||||||
|
box-shadow: 0 0.08rem 0.20rem rgba(15, 83, 87, 0.05);
|
||||||
|
border-radius: 0.12rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-box__phone-icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 0.18rem;
|
||||||
|
height: 0.18rem;
|
||||||
|
margin-left: 0.16rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 0.18rem;
|
||||||
|
height: 0.18rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-box__country-label {
|
||||||
|
margin-left: 0.06rem;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.15rem;
|
||||||
|
color: #202124;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-box__country-chevron {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 0.20rem;
|
||||||
|
height: 0.20rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 0.20rem;
|
||||||
|
height: 0.20rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-box__input-divider {
|
||||||
|
width: 1px;
|
||||||
|
height: 0.30rem;
|
||||||
|
background: #E7F2F3;
|
||||||
|
margin: 0 0.16rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-box__phone-input {
|
||||||
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.15rem;
|
||||||
|
color: #202124;
|
||||||
|
outline: none;
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
color: #939599;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 发送验证码按钮 */
|
||||||
|
.login-dialog-box__send-btn {
|
||||||
|
width: 100%;
|
||||||
|
height: 0.43rem;
|
||||||
|
background: linear-gradient(90deg, #4FC2C9 0%, #42A8B3 100%);
|
||||||
|
box-shadow: 0 0.16rem 0.30rem rgba(15, 83, 87, 0.15);
|
||||||
|
border-radius: 0.12rem;
|
||||||
|
border: none;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.15rem;
|
||||||
|
color: #FFFFFF;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:disabled):hover {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* OTP 验证码输入 */
|
||||||
|
.login-dialog-box__otp-wrap {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 0.1rem;
|
||||||
|
width: 100%;
|
||||||
|
cursor: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-box__otp-hidden-input {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
opacity: 0;
|
||||||
|
z-index: 2;
|
||||||
|
font-size: 0.16rem;
|
||||||
|
caret-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-box__otp-box {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 0.56rem;
|
||||||
|
height: 0.56rem;
|
||||||
|
background: #FAFBFC;
|
||||||
|
border: 1px solid #E2E8F0;
|
||||||
|
border-radius: 0.12rem;
|
||||||
|
transition: border-color 0.2s, background 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-box__otp-box--active {
|
||||||
|
background: #F3FFFD;
|
||||||
|
border: 1px solid $accent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-box__otp-box--filled {
|
||||||
|
background: #F3FFFD;
|
||||||
|
border: 2px solid $accent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-box__otp-digit {
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 0.24rem;
|
||||||
|
line-height: 0.29rem;
|
||||||
|
color: #132034;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 闪烁光标 */
|
||||||
|
.login-dialog-box__otp-cursor {
|
||||||
|
display: inline-block;
|
||||||
|
width: 2px;
|
||||||
|
height: 0.28rem;
|
||||||
|
background: $accent;
|
||||||
|
border-radius: 1px;
|
||||||
|
animation: login-dialog-otp-blink 1s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes login-dialog-otp-blink {
|
||||||
|
0%, 100% { opacity: 1; }
|
||||||
|
50% { opacity: 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 验证码状态提示 */
|
||||||
|
.login-dialog-box__sms-status {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 0.13rem;
|
||||||
|
line-height: 0.16rem;
|
||||||
|
color: #64748B;
|
||||||
|
text-align: left;
|
||||||
|
margin-top: -0.14rem;
|
||||||
|
margin-bottom: -0.06rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-box__sms-status--error {
|
||||||
|
color: #EF4444;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 状态按钮(步骤二) */
|
||||||
|
.login-dialog-box__status-btn {
|
||||||
|
width: 100%;
|
||||||
|
height: 0.43rem;
|
||||||
|
background: linear-gradient(90deg, $btn-dark 0%, $btn-dark-hover 100%);
|
||||||
|
border-radius: 0.12rem;
|
||||||
|
border: none;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
color: #FFFFFF;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.08rem;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
opacity: 0.7;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:disabled):hover {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 登录中转圈动画 */
|
||||||
|
.login-dialog-box__spinner {
|
||||||
|
display: inline-block;
|
||||||
|
width: 0.18rem;
|
||||||
|
height: 0.18rem;
|
||||||
|
border: 2px solid rgba(255, 255, 255, 0.3);
|
||||||
|
border-top-color: #FFFFFF;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: login-dialog-spin 0.7s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes login-dialog-spin {
|
||||||
|
to { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 协议勾选 */
|
||||||
|
.login-dialog-box__agreement {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.06rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-box__checkbox {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 0.18rem;
|
||||||
|
height: 0.18rem;
|
||||||
|
background: #FFFFFF;
|
||||||
|
border: 1.5px solid #CBD5E1;
|
||||||
|
border-radius: 0.04rem;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transition: all 0.2s;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-box__checkbox--checked {
|
||||||
|
background: #4FC2C9;
|
||||||
|
border-color: #4FC2C9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-box__check-icon {
|
||||||
|
font-size: 0.11rem;
|
||||||
|
color: #FFFFFF;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-box__agreement-text {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.15rem;
|
||||||
|
color: #616367;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-box__agreement-link {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.15rem;
|
||||||
|
color: #42A8B3;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// 会员弹窗样式(新版)
|
// 会员弹窗样式 — 新版黑金左右布局
|
||||||
@use '../variables' as *;
|
@use '../variables' as *;
|
||||||
|
|
||||||
// 遮罩层
|
// 遮罩层
|
||||||
@@ -10,82 +10,163 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
font-size: 0.14rem;
|
||||||
// 扫码支付弹窗的遮罩层级更高
|
|
||||||
&--qrcode {
|
|
||||||
z-index: 2400;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 弹窗主体
|
// 弹窗主体 — 左右布局
|
||||||
.member-dialog {
|
.member-dialog {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
width: 6.49rem;
|
||||||
align-items: flex-start;
|
height: 4rem;
|
||||||
padding: 0.24rem 0.32rem;
|
border-radius: 0.16rem;
|
||||||
gap: 0.24rem;
|
box-shadow: 0 0.025rem 0.05rem rgba(60, 38, 13, 0.22);
|
||||||
width: 4.8rem;
|
border: 0.00625rem solid #D9B873;
|
||||||
background: linear-gradient(180deg, #EDF9FA 0%, #FFFFFF 20.63%);
|
|
||||||
border: 1px solid #F0F0F0;
|
|
||||||
box-shadow: 0 0 0.16rem rgba(0, 0, 0, 0.05);
|
|
||||||
border-radius: 0.12rem;
|
|
||||||
font-size: 0.14rem;
|
font-size: 0.14rem;
|
||||||
|
|
||||||
// 扫码支付弹窗变体
|
// ==================== 左侧黑金权益栏 ====================
|
||||||
&--qrcode {
|
&__left {
|
||||||
|
position: relative;
|
||||||
|
width: 2rem;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(180deg, #0F001E 0%, #1A0B09 18.09%, #452206 66.19%, #2C1500 100%);
|
||||||
|
padding: 0.24rem 0.20rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border-radius: 0.16rem 0 0 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 装饰线条背景
|
||||||
|
&__left-deco {
|
||||||
|
position: absolute;
|
||||||
|
width: 4.47rem;
|
||||||
|
height: 2.39rem;
|
||||||
|
left: -0.52rem;
|
||||||
|
top: -0.75rem;
|
||||||
|
background: radial-gradient(ellipse at center, rgba(255, 230, 175, 0.08) 0%, transparent 70%);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__left-title {
|
||||||
|
position: relative;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.16rem;
|
||||||
|
line-height: 0.21rem;
|
||||||
|
color: #FFE9A6;
|
||||||
|
margin: 0 0 0.06rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__left-subtitle {
|
||||||
|
position: relative;
|
||||||
|
font-weight: 330;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.16rem;
|
||||||
|
color: #F4E5CC;
|
||||||
|
margin: 0 0 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 左栏权益卡片 ====================
|
||||||
|
&__benefits {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__benefit-card {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 1.56rem;
|
||||||
|
height: 0.6rem;
|
||||||
|
border: 0.00625rem solid #9C6D2D;
|
||||||
|
border-radius: 0.08rem;
|
||||||
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
padding: 0 0.12rem;
|
||||||
|
gap: 0.12rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__benefit-icon {
|
||||||
|
width: 0.32rem;
|
||||||
|
height: 0.32rem;
|
||||||
|
background: #4C3517;
|
||||||
|
border: 0.00625rem solid #D5A64A;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 0.16rem;
|
||||||
|
height: 0.16rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__benefit-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.04rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__benefit-name {
|
||||||
|
font-weight: 450;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
color: #FFE6AF;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__benefit-desc {
|
||||||
|
font-weight: 330;
|
||||||
|
font-size: 0.1rem;
|
||||||
|
line-height: 0.13rem;
|
||||||
|
color: #F4E5CC;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 左右分割金边 ====================
|
||||||
|
&__divider {
|
||||||
|
width: 0.01rem;
|
||||||
|
height: 100%;
|
||||||
|
background: #D6B15B;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 右侧内容区 ====================
|
||||||
|
&__right {
|
||||||
|
flex: 1;
|
||||||
|
background: linear-gradient(179.38deg, #FCEDD8 0.54%, #FEFBF5 19.09%);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 0.2rem 0.24rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
|
border-radius: 0 0.16rem 0.16rem 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 顶部标题行 ====================
|
// ==================== 顶部标题行 ====================
|
||||||
&__header {
|
&__header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: flex-start;
|
align-items: center;
|
||||||
width: 100%;
|
margin-bottom: 0.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__header-left {
|
&__title {
|
||||||
display: flex;
|
font-weight: 600;
|
||||||
flex-direction: column;
|
font-size: 0.18rem;
|
||||||
gap: 0.04rem;
|
line-height: 0.24rem;
|
||||||
|
color: #1F160F;
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__header-right {
|
&__header-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.16rem;
|
gap: 0.16rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__title {
|
// 联系客服
|
||||||
font-weight: 620;
|
|
||||||
font-size: 0.18rem;
|
|
||||||
line-height: 0.24rem;
|
|
||||||
color: $text-dark;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__subtitle {
|
|
||||||
font-weight: 330;
|
|
||||||
font-size: 0.12rem;
|
|
||||||
line-height: 0.16rem;
|
|
||||||
color: $text-middle;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__contact {
|
|
||||||
font-weight: 330;
|
|
||||||
font-size: 0.12rem;
|
|
||||||
line-height: 0.16rem;
|
|
||||||
color: $text-light;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: $text-middle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 联系客服外层包装(用于定位二维码弹出框)
|
|
||||||
&__contact-wrap {
|
&__contact-wrap {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
@@ -96,7 +177,18 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 联系客服二维码弹出框
|
&__contact {
|
||||||
|
font-weight: 330;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.16rem;
|
||||||
|
color: #2F343B;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #1F160F;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&__contact-qr {
|
&__contact-qr {
|
||||||
display: none;
|
display: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -122,7 +214,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 二维码弹出框底部箭头
|
|
||||||
&__contact-qr-arrow {
|
&__contact-qr-arrow {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: -0.07rem;
|
bottom: -0.07rem;
|
||||||
@@ -133,7 +224,6 @@
|
|||||||
border-left: 0.08rem solid transparent;
|
border-left: 0.08rem solid transparent;
|
||||||
border-right: 0.08rem solid transparent;
|
border-right: 0.08rem solid transparent;
|
||||||
border-top: 0.08rem solid $bg-white;
|
border-top: 0.08rem solid $bg-white;
|
||||||
filter: drop-shadow(0 0.02rem 0.02rem rgba(0, 0, 0, 0.05));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__close {
|
&__close {
|
||||||
@@ -143,355 +233,378 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-size: 0.14rem;
|
font-size: 0.14rem;
|
||||||
color: $text-middle;
|
color: #2F343B;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: $text-dark;
|
color: #1F160F;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 套餐选择区域 ====================
|
// ==================== 套餐选择区域 ====================
|
||||||
&__plans {
|
&__plans {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 0.13rem;
|
gap: 0.2rem;
|
||||||
width: 100%;
|
margin-bottom: 0.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__plan-card {
|
&__plan-card {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
width: 1.2rem;
|
||||||
|
height: 1.4rem;
|
||||||
|
background: #FFFDF8;
|
||||||
|
border: 1px solid #E7C991;
|
||||||
|
border-radius: 0.08rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 0.12rem 0.16rem;
|
gap: 0.08rem;
|
||||||
gap: 0.04rem;
|
|
||||||
width: 1.3rem;
|
|
||||||
height: 1.01rem;
|
|
||||||
background: $bg-white;
|
|
||||||
border: 1px solid #F0F0F0;
|
|
||||||
border-radius: 0.08rem;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: border-color 0.2s;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
transition: border-color 0.2s, box-shadow 0.2s;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
border-color: $accent;
|
border-color: #B77D24;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 选中状态 — 粗边框
|
// 选中态
|
||||||
&--active {
|
&--active {
|
||||||
border: 3px solid $accent;
|
background: linear-gradient(180deg, #FFF4D8 0%, #FDF9F1 100%);
|
||||||
|
border: 2px solid #B77D24;
|
||||||
|
box-shadow: 0 0.04rem 0.08rem rgba(183, 125, 36, 0.2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__plan-recommend {
|
// 推荐角标
|
||||||
|
&__plan-badge {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -0.1rem;
|
top: -0.12rem;
|
||||||
left: 10%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
background: $accent;
|
background: #C28A2F;
|
||||||
color: $bg-white;
|
border: 0.00625rem solid #F0D091;
|
||||||
font-size: 0.1rem;
|
border-radius: 0.075rem;
|
||||||
padding: 0.02rem 0.08rem;
|
padding: 0.04rem 0.12rem;
|
||||||
border-radius: 0.08rem;
|
font-weight: 600;
|
||||||
font-weight: 620;
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.16rem;
|
||||||
|
color: #FFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__plan-name {
|
&__plan-name {
|
||||||
font-weight: 450;
|
font-weight: 600;
|
||||||
font-size: 0.14rem;
|
font-size: 0.14rem;
|
||||||
line-height: 0.19rem;
|
line-height: 0.19rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: $text-dark;
|
color: #1F160F;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__plan-price {
|
&__plan-price {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-end;
|
align-items: baseline;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 0.04rem;
|
|
||||||
padding: 0.04rem 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__plan-price-symbol {
|
&__plan-price-symbol {
|
||||||
font-weight: 450;
|
font-weight: 600;
|
||||||
font-size: 0.14rem;
|
font-size: 0.14rem;
|
||||||
line-height: 0.19rem;
|
color: #1F160F;
|
||||||
color: $text-dark;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__plan-price-num {
|
&__plan-price-num {
|
||||||
font-weight: 630;
|
font-weight: 600;
|
||||||
font-size: 0.24rem;
|
font-size: 0.28rem;
|
||||||
line-height: 0.18rem;
|
line-height: 0.37rem;
|
||||||
color: $text-dark;
|
color: #1F160F;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__plan-original-price {
|
&__plan-original {
|
||||||
font-weight: 330;
|
font-weight: 330;
|
||||||
font-size: 0.12rem;
|
font-size: 0.12rem;
|
||||||
line-height: 0.16rem;
|
line-height: 0.16rem;
|
||||||
text-decoration: line-through;
|
text-decoration: line-through;
|
||||||
color: $text-light;
|
color: #7A7D82;
|
||||||
|
margin-left: 0.04rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__plan-daily {
|
&__plan-tag {
|
||||||
font-weight: 330;
|
font-weight: 330;
|
||||||
font-size: 0.12rem;
|
font-size: 0.12rem;
|
||||||
line-height: 0.16rem;
|
line-height: 0.16rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: $accent;
|
color: #3B2A1E;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 会员权益区域 ====================
|
// ==================== 支付方式选择(步骤一) ====================
|
||||||
&__benefits {
|
&__step-pay {
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__benefits-title {
|
|
||||||
font-weight: 450;
|
|
||||||
font-size: 0.14rem;
|
|
||||||
line-height: 0.19rem;
|
|
||||||
color: $text-dark;
|
|
||||||
margin: 0 0 0.16rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__benefits-cards {
|
|
||||||
display: flex;
|
|
||||||
gap: 0.13rem;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__benefit-card {
|
|
||||||
box-sizing: border-box;
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 0.12rem 0.16rem;
|
|
||||||
gap: 0.1rem;
|
|
||||||
background: $bg-white;
|
|
||||||
border: 1px solid #AEE6EA;
|
|
||||||
border-radius: 0.08rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__benefit-icon {
|
&__payment-section {
|
||||||
width: 0.4rem;
|
margin-bottom: 0.16rem;
|
||||||
height: 0.4rem;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
background: #EDF9FA;
|
|
||||||
border-radius: 50%;
|
|
||||||
flex-shrink: 0;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
width: 0.24rem;
|
|
||||||
height: 0.24rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__benefit-info {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 0.04rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__benefit-name {
|
|
||||||
font-weight: 450;
|
|
||||||
font-size: 0.14rem;
|
|
||||||
line-height: 0.19rem;
|
|
||||||
color: $accent;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__benefit-desc {
|
|
||||||
font-weight: 330;
|
|
||||||
font-size: 0.12rem;
|
|
||||||
line-height: 0.16rem;
|
|
||||||
color: $text-middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==================== 支付方式选择 ====================
|
|
||||||
&__payment {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__payment-label {
|
&__payment-label {
|
||||||
font-weight: 450;
|
font-weight: 450;
|
||||||
font-size: 0.14rem;
|
font-size: 0.14rem;
|
||||||
line-height: 0.19rem;
|
line-height: 0.19rem;
|
||||||
color: $text-dark;
|
color: #1F160F;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0.08rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__payment-methods {
|
&__payment-methods {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
|
||||||
gap: 0.24rem;
|
gap: 0.24rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__payment-item {
|
&__payment-item {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 1.88rem;
|
||||||
|
height: 0.58rem;
|
||||||
|
background: #FFFDF8;
|
||||||
|
border: 1px solid #E7C991;
|
||||||
|
border-radius: 0.08rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0.04rem 0.08rem;
|
padding: 0 0.2rem;
|
||||||
gap: 0.06rem;
|
gap: 0.12rem;
|
||||||
border-radius: 0.04rem;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background 0.2s;
|
position: relative;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
width: 0.16rem;
|
width: 0.32rem;
|
||||||
height: 0.16rem;
|
height: 0.32rem;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 微信选中态
|
// 选中态
|
||||||
&--wechat-active {
|
&--active {
|
||||||
background: #EBFEF4;
|
border-color: #B77D24;
|
||||||
}
|
|
||||||
|
|
||||||
// 支付宝选中态
|
|
||||||
&--alipay-active {
|
|
||||||
background: #EBF3FF;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__payment-text {
|
&__payment-text {
|
||||||
font-weight: 620;
|
font-weight: 600;
|
||||||
|
font-size: 0.13rem;
|
||||||
|
line-height: 0.17rem;
|
||||||
|
color: #1F160F;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选中圆圈
|
||||||
|
&__payment-radio {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 0.14rem;
|
||||||
|
height: 0.14rem;
|
||||||
|
background: #FFFDF8;
|
||||||
|
border: 1px solid #E7C991;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-left: auto;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.member-dialog__payment-item--active & {
|
||||||
|
border-color: #C28A2F;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__payment-radio-inner {
|
||||||
|
width: 0.08rem;
|
||||||
|
height: 0.08rem;
|
||||||
|
background: #C28A2F;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 底部栏(步骤一/步骤二共用) ====================
|
||||||
|
&__bottom-bar {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 0.66rem;
|
||||||
|
background: #FCF4E8;
|
||||||
|
border-top: 1px solid #E9D4B1;
|
||||||
|
border-radius: 0 0 0.16rem 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 0.24rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
&--qrcode {
|
||||||
|
height: 1.7rem;
|
||||||
|
padding: 0.2rem 0.24rem;
|
||||||
|
gap: 0.24rem;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__footer-price {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 0.04rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__footer-price-label {
|
||||||
|
font-weight: 330;
|
||||||
font-size: 0.12rem;
|
font-size: 0.12rem;
|
||||||
line-height: 0.18rem;
|
line-height: 0.16rem;
|
||||||
|
color: #1F160F;
|
||||||
&--wechat {
|
margin-right: 0.08rem;
|
||||||
color: #07C160;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&--alipay {
|
&__footer-price-symbol {
|
||||||
color: #1677FF;
|
font-weight: 600;
|
||||||
}
|
font-size: 0.14rem;
|
||||||
|
color: #1F160F;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 购买按钮 ====================
|
&__footer-price-num {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.24rem;
|
||||||
|
line-height: 0.32rem;
|
||||||
|
color: #1F160F;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 购买会员按钮
|
||||||
&__buy-btn {
|
&__buy-btn {
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0.08rem 0.12rem;
|
padding: 0.08rem 0.24rem;
|
||||||
height: 0.35rem;
|
height: 0.33rem;
|
||||||
background: #AEE6EA;
|
background: #C88E35;
|
||||||
|
border: 1px solid #F0D091;
|
||||||
|
box-shadow: 0 0.02rem 0.05rem rgba(154, 104, 32, 0.18);
|
||||||
border-radius: 0.08rem;
|
border-radius: 0.08rem;
|
||||||
border: none;
|
font-weight: 600;
|
||||||
font-weight: 450;
|
font-size: 0.13rem;
|
||||||
font-size: 0.14rem;
|
line-height: 0.15rem;
|
||||||
line-height: 0.19rem;
|
color: #FFFFFF;
|
||||||
color: $bg-white;
|
|
||||||
cursor: default;
|
|
||||||
opacity: 0.4;
|
|
||||||
transition: background 0.2s, opacity 0.2s;
|
|
||||||
|
|
||||||
// 选择了支付方式后变为主题色、不透明、可点击
|
|
||||||
&--active {
|
|
||||||
background: $accent;
|
|
||||||
opacity: 1;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
border: 1px solid #F0D091;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: $accent-hover;
|
opacity: 0.9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 扫码支付弹窗内容 ====================
|
// ==================== 扫码支付区域(底部栏内) ====================
|
||||||
&__qrcode-content {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.16rem;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__qrcode-image {
|
&__qrcode-box {
|
||||||
width: 2.1rem;
|
|
||||||
height: 2.1rem;
|
width: 1.2rem;
|
||||||
|
height: 1.2rem;
|
||||||
|
border: 2px solid #B77D24;
|
||||||
|
border-radius: 0.0rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
background: #FFFFFF;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__payment-iframe {
|
&__qrcode-iframe {
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 0.08rem;
|
border-radius: 0.04rem;
|
||||||
|
}
|
||||||
|
.qrcode-zhifubao{
|
||||||
|
transform: scale(0.52);
|
||||||
|
width: 2.2rem !important;
|
||||||
|
height: 2.2rem !important;
|
||||||
|
padding-top: 0.1rem;
|
||||||
|
padding-left: 0.1rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.qrcode-wechat{
|
||||||
|
transform: scale(0.66);
|
||||||
|
width: 1.6rem !important;
|
||||||
|
height: 1.6rem !important;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__wechat-qr-iframe {
|
&__qrcode-info {
|
||||||
width: 2.2rem;
|
display: flex;
|
||||||
height: 2.2rem;
|
flex-direction: column;
|
||||||
border: none;
|
gap: 0.12rem;
|
||||||
border-radius: 0.08rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__qrcode-price-row {
|
&__qrcode-price-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-end;
|
align-items: center;
|
||||||
gap: 0.08rem;
|
gap: 0.04rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__qrcode-price {
|
&__qrcode-price-symbol {
|
||||||
font-weight: 630;
|
font-weight: 600;
|
||||||
|
font-size: 0.18rem;
|
||||||
|
color: #1F160F;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__qrcode-price-num {
|
||||||
font-size: 0.32rem;
|
font-size: 0.32rem;
|
||||||
line-height: 0.25rem;
|
font-weight: 600;
|
||||||
color: $text-dark;
|
line-height: 0.37rem;
|
||||||
|
color: #1F160F;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__qrcode-tip {
|
&__qrcode-tip {
|
||||||
font-weight: 330;
|
font-weight: 330;
|
||||||
font-size: 0.14rem;
|
font-size: 0.14rem;
|
||||||
line-height: 0.1rem;
|
line-height: 0.19rem;
|
||||||
color: $text-dark;
|
color: #1F160F;
|
||||||
|
margin-left: 0.08rem;
|
||||||
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__qrcode-agreement {
|
&__qrcode-agreement {
|
||||||
font-weight: 330;
|
font-weight: 330;
|
||||||
font-size: 0.14rem;
|
font-size: 0.12rem;
|
||||||
line-height: 0.19rem;
|
line-height: 0.16rem;
|
||||||
color: $text-light;
|
color: #3B2A1E;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: $text-light;
|
color: #A86718;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: $accent;
|
color: #A86718;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 已支付成功按钮
|
// 我已支付成功按钮
|
||||||
&__paid-btn {
|
&__paid-btn {
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0.08rem 0.12rem;
|
padding: 0.08rem 0.24rem;
|
||||||
height: 0.35rem;
|
height: 0.33rem;
|
||||||
background: $accent;
|
width: fit-content;
|
||||||
|
background: #C88E35;
|
||||||
|
border: 1px solid #F0D091;
|
||||||
|
box-shadow: 0 0.02rem 0.05rem rgba(154, 104, 32, 0.18);
|
||||||
border-radius: 0.08rem;
|
border-radius: 0.08rem;
|
||||||
border: none;
|
font-weight: 600;
|
||||||
font-weight: 450;
|
font-size: 0.13rem;
|
||||||
font-size: 0.14rem;
|
line-height: 0.15rem;
|
||||||
line-height: 0.19rem;
|
color: #FFFFFF;
|
||||||
color: $bg-white;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background 0.2s;
|
transition: opacity 0.2s;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: $accent-hover;
|
opacity: 0.9;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -349,4 +349,14 @@
|
|||||||
color: #64748B;
|
color: #64748B;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 个人概述文本
|
||||||
|
&__summary-text {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
line-height: 1.7;
|
||||||
|
color: #374151;
|
||||||
|
padding: 0 0.14rem 0.12rem;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,15 +55,11 @@
|
|||||||
|
|
||||||
// ==================== 下拉面板 ====================
|
// ==================== 下拉面板 ====================
|
||||||
&__panel {
|
&__panel {
|
||||||
position: absolute;
|
|
||||||
top: calc(100% + 0.06rem);
|
|
||||||
left: 0;
|
|
||||||
width: 4.2rem;
|
width: 4.2rem;
|
||||||
background: $bg-white;
|
background: $bg-white;
|
||||||
border: 1px solid $border-color;
|
border: 1px solid $border-color;
|
||||||
border-radius: 0.1rem;
|
border-radius: 0.1rem;
|
||||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
||||||
z-index: 100;
|
|
||||||
padding: 0.1rem;
|
padding: 0.1rem;
|
||||||
|
|
||||||
// level=2 时只有两栏,面板收窄
|
// level=2 时只有两栏,面板收窄
|
||||||
|
|||||||
@@ -9,9 +9,15 @@
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
padding: 0.2rem 0.12rem;
|
padding: 0.2rem 0.12rem;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
position: fixed;
|
z-index: 100;
|
||||||
left: 0;
|
flex-shrink: 0;
|
||||||
top: 0;
|
|
||||||
|
// 窄版模式(window.innerWidth < 1440)
|
||||||
|
&--narrow {
|
||||||
|
width: 0.8rem;
|
||||||
|
padding: 0.16rem 0.10rem;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
&__header {
|
&__header {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -21,6 +27,12 @@
|
|||||||
margin-bottom: 0.2rem;
|
margin-bottom: 0.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 窄版header居中
|
||||||
|
&--narrow &__header {
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0.1rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
&__avatar {
|
&__avatar {
|
||||||
width: 0.36rem;
|
width: 0.36rem;
|
||||||
height: 0.36rem;
|
height: 0.36rem;
|
||||||
@@ -43,6 +55,12 @@
|
|||||||
width: 1.32rem;
|
width: 1.32rem;
|
||||||
height: 0.34rem;
|
height: 0.34rem;
|
||||||
display: block;
|
display: block;
|
||||||
|
|
||||||
|
// 窄版logo
|
||||||
|
&--narrow {
|
||||||
|
width: 0.46rem;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__menu {
|
&__menu {
|
||||||
@@ -52,7 +70,13 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 窄版菜单宽度撑满
|
||||||
|
&--narrow &__menu {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
&__item {
|
&__item {
|
||||||
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.04rem;
|
gap: 0.04rem;
|
||||||
@@ -79,18 +103,45 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 窄版导航项:纵向居中排列
|
||||||
|
&--narrow &__item {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.04rem;
|
||||||
|
padding: 0.1rem 0.06rem;
|
||||||
|
}
|
||||||
|
|
||||||
&__item-icon {
|
&__item-icon {
|
||||||
width: 0.2rem;
|
width: 0.2rem;
|
||||||
height: 0.2rem;
|
height: 0.2rem;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
font-size: 0.16rem;
|
font-size: 0.16rem;
|
||||||
|
|
||||||
|
// 内部SVG/img统一撑满容器
|
||||||
|
svg, img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 窄版图标放大,防止scale缩放后图标过小
|
||||||
|
&--narrow &__item-icon {
|
||||||
|
width: 0.24rem;
|
||||||
|
height: 0.24rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__item-label {
|
&__item-label {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 窄版label字号缩小
|
||||||
|
&--narrow &__item-label {
|
||||||
|
font-size: 0.11rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
&__badge {
|
&__badge {
|
||||||
background: #e85635;
|
background: #e85635;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
@@ -118,6 +169,39 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
color: #FFFFFF;
|
color: #FFFFFF;
|
||||||
flex: none;
|
flex: none;
|
||||||
|
|
||||||
|
// 窄版角标样式(右上角定位)
|
||||||
|
&--corner {
|
||||||
|
position: absolute;
|
||||||
|
top: -0.07rem;
|
||||||
|
right: -0.05rem;
|
||||||
|
min-width: auto;
|
||||||
|
padding: 0.02rem 0.04rem;
|
||||||
|
height: 0.17rem;
|
||||||
|
font-size: 0.10rem;
|
||||||
|
line-height: 0.12rem;
|
||||||
|
border-radius: 0.03rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 公测群二维码弹出层(hover索引5时显示)
|
||||||
|
&__qrcode-popup {
|
||||||
|
position: absolute;
|
||||||
|
top: calc(100% + 0.08rem);
|
||||||
|
left: 0;
|
||||||
|
padding: 0.08rem;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 0.08rem;
|
||||||
|
box-shadow: 0 0.02rem 0.12rem rgba(0, 0, 0, 0.08);
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__qrcode-img {
|
||||||
|
display: block;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
max-width: 1.6rem;
|
||||||
|
border-radius: 0.04rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__footer {
|
&__footer {
|
||||||
@@ -126,6 +210,48 @@
|
|||||||
gap: 0.04rem;
|
gap: 0.04rem;
|
||||||
padding-top: 0.12rem;
|
padding-top: 0.12rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 窄版footer居中
|
||||||
|
&--narrow &__footer {
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 窄版邀请图片卡片 ====================
|
||||||
|
.side-nav__referral-card-narrow {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 0.12rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.side-nav__referral-card-narrow-img {
|
||||||
|
width: 0.56rem;
|
||||||
|
height: 0.85rem;
|
||||||
|
display: block;
|
||||||
|
border-radius: 0.06rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 窄版用户信息 ====================
|
||||||
|
.side-nav__user-info-narrow {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.06rem;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0.08rem 0;
|
||||||
|
border-radius: 0.08rem;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.side-nav__user-avatar-narrow {
|
||||||
|
width: 0.26rem;
|
||||||
|
height: 0.26rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.side-nav__dialog-overlay {
|
.side-nav__dialog-overlay {
|
||||||
@@ -478,84 +604,120 @@
|
|||||||
|
|
||||||
// ==================== 邀请会员卡片 ====================
|
// ==================== 邀请会员卡片 ====================
|
||||||
.side-nav__referral-card {
|
.side-nav__referral-card {
|
||||||
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: linear-gradient(128.17deg, #52CAD1 0%, #82D79B 100%);
|
height: 2.21rem;
|
||||||
|
background: linear-gradient(90deg, #DFF5F6 0%, #FBFDF7 100%);
|
||||||
|
box-shadow: 0px 0px 0.08rem rgba(0, 0, 0, 0.06);
|
||||||
border-radius: 0.08rem;
|
border-radius: 0.08rem;
|
||||||
padding: 0.16rem;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
margin-top: 0.12rem;
|
margin-top: 0.12rem;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 顶部区域:标题在左上,礼物图片定位在右下角
|
||||||
|
.side-nav__referral-top {
|
||||||
|
position: relative;
|
||||||
|
padding: 0.2rem 0.16rem 0.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.side-nav__referral-top-text {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.side-nav__referral-title {
|
.side-nav__referral-title {
|
||||||
font-size: 0.16rem;
|
font-size: 0.18rem;
|
||||||
font-weight: 630;
|
font-weight: 630;
|
||||||
color: #FFFFFF;
|
color: #1A1A1A;
|
||||||
line-height: 0.21rem;
|
line-height: 0.24rem;
|
||||||
|
|
||||||
|
&--accent {
|
||||||
|
background: linear-gradient(128.17deg, #52CAD1 0%, #82D79B 100%);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.side-nav__referral-subtitle {
|
.side-nav__referral-subtitle {
|
||||||
font-size: 0.10rem;
|
font-size: 0.14rem;
|
||||||
font-weight: 330;
|
font-weight: 330;
|
||||||
color: #EAFBFC;
|
color: #6A7282;
|
||||||
line-height: 0.13rem;
|
line-height: 0.19rem;
|
||||||
margin-top: 0.04rem;
|
margin-top: 0.08rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 礼物图片:absolute定位在顶部区域的右下角,底部被毛玻璃面板遮住
|
||||||
|
.side-nav__referral-gift {
|
||||||
|
position: absolute;
|
||||||
|
right: 0.10rem;
|
||||||
|
bottom: 0.02rem;
|
||||||
|
width: 0.68rem;
|
||||||
|
height: 0.68rem;
|
||||||
|
mix-blend-mode: darken;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 白色毛玻璃面板(覆盖在礼物底部之上)
|
||||||
.side-nav__referral-panel {
|
.side-nav__referral-panel {
|
||||||
background: #FFFFFF;
|
position: absolute;
|
||||||
box-shadow: 0px 0.02rem 0.06rem rgba(26, 26, 26, 0.05);
|
left: 0;
|
||||||
border-radius: 0.06rem;
|
bottom: 0;
|
||||||
padding: 0.10rem 0.08rem;
|
width: 100%;
|
||||||
margin-top: 0.10rem;
|
height: 1.38rem;
|
||||||
|
background: rgba(255, 255, 255, 0.4);
|
||||||
|
border: 1px solid #FFFFFF;
|
||||||
|
border-bottom: none;
|
||||||
|
backdrop-filter: blur(3px);
|
||||||
|
border-radius: 0.08rem 0.08rem 0 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0.16rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.side-nav__referral-row {
|
.side-nav__referral-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
gap: 0.08rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.side-nav__referral-label {
|
.side-nav__referral-label {
|
||||||
font-size: 0.10rem;
|
font-size: 0.14rem;
|
||||||
font-weight: 330;
|
font-weight: 330;
|
||||||
color: #6B7280;
|
color: #6A7282;
|
||||||
line-height: 0.13rem;
|
line-height: 0.19rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.side-nav__referral-value {
|
.side-nav__referral-value {
|
||||||
font-size: 0.10rem;
|
font-size: 0.14rem;
|
||||||
font-weight: 620;
|
font-weight: 450;
|
||||||
color: #52CAD1;
|
line-height: 0.19rem;
|
||||||
line-height: 0.13rem;
|
background: linear-gradient(128.17deg, #52CAD1 0%, #82D79B 100%);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
}
|
}
|
||||||
|
|
||||||
.side-nav__referral-track {
|
.side-nav__referral-track {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 0.02rem;
|
height: 0.06rem;
|
||||||
background: #D7F1F3;
|
background: #EDF9FA;
|
||||||
border-radius: 9999px;
|
border-radius: 0.06rem;
|
||||||
margin-top: 0.06rem;
|
margin-top: 0.1rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.side-nav__referral-fill {
|
.side-nav__referral-fill {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: #52CAD1;
|
background: #52CAD1;
|
||||||
border-radius: 9999px;
|
border-radius: 0.06rem;
|
||||||
}
|
|
||||||
|
|
||||||
.side-nav__referral-divider {
|
|
||||||
width: 100%;
|
|
||||||
border-top: 0.01rem solid #8C8C8C;
|
|
||||||
margin-top: 0.08rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.side-nav__referral-tip {
|
.side-nav__referral-tip {
|
||||||
font-size: 0.10rem;
|
font-size: 0.12rem;
|
||||||
font-weight: 330;
|
font-weight: 330;
|
||||||
color: #1A1A1A;
|
color: #6A7282;
|
||||||
line-height: 0.13rem;
|
line-height: 0.16rem;
|
||||||
margin-top: 0.08rem;
|
margin-top: 0.06rem;
|
||||||
|
|
||||||
strong {
|
strong {
|
||||||
font-weight: 630;
|
font-weight: 630;
|
||||||
@@ -563,16 +725,22 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.side-nav__referral-action {
|
.side-nav__referral-action {
|
||||||
font-size: 0.11rem;
|
display: flex;
|
||||||
font-weight: 620;
|
align-items: center;
|
||||||
color: #52CAD1;
|
justify-content: center;
|
||||||
line-height: 0.15rem;
|
width: 100%;
|
||||||
text-align: center;
|
height: 0.40rem;
|
||||||
margin-top: 0.08rem;
|
background: linear-gradient(90deg, #36C1C9 16.99%, #AFE9D0 100%);
|
||||||
|
box-shadow: inset 0px 0px 0.06rem rgba(255, 255, 255, 0.5);
|
||||||
|
border-radius: 0.08rem;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #FFFFFF;
|
||||||
|
margin-top: 0.12rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
opacity: 0.8;
|
opacity: 0.9;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -680,12 +848,13 @@
|
|||||||
bottom: calc(100% + 0.08rem);
|
bottom: calc(100% + 0.08rem);
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
min-width: 1.65rem;
|
||||||
background: #FFFFFF;
|
background: #FFFFFF;
|
||||||
border: 1px solid #F0F0F0;
|
border: 1px solid #F0F0F0;
|
||||||
box-shadow: 0px 0.02rem 0.08rem rgba(0, 0, 0, 0.04);
|
box-shadow: 0px 0.02rem 0.08rem rgba(0, 0, 0, 0.04);
|
||||||
border-radius: 0.08rem;
|
border-radius: 0.08rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
z-index: 100;
|
z-index: 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.side-nav__account-popup-header {
|
.side-nav__account-popup-header {
|
||||||
|
|||||||
@@ -12,12 +12,15 @@
|
|||||||
@use './pages/login.scss';
|
@use './pages/login.scss';
|
||||||
@use './pages/mentor.scss';
|
@use './pages/mentor.scss';
|
||||||
@use './pages/mentor-detail.scss';
|
@use './pages/mentor-detail.scss';
|
||||||
|
@use './pages/announcement.scss';
|
||||||
|
@use './pages/announcement-detail.scss';
|
||||||
|
|
||||||
// 组件样式
|
// 组件样式
|
||||||
@use './components/hello-world.scss';
|
@use './components/hello-world.scss';
|
||||||
@use './components/side-nav.scss';
|
@use './components/side-nav.scss';
|
||||||
@use './components/ai-chat.scss';
|
@use './components/ai-chat.scss';
|
||||||
@use './components/job-page-header.scss';
|
@use './components/job-page-header.scss';
|
||||||
|
@use './components/job-stats-overview.scss';
|
||||||
@use './components/job-goal-dialog.scss';
|
@use './components/job-goal-dialog.scss';
|
||||||
@use './components/settings-dialog.scss';
|
@use './components/settings-dialog.scss';
|
||||||
@use './components/member-dialog.scss';
|
@use './components/member-dialog.scss';
|
||||||
@@ -45,6 +48,11 @@
|
|||||||
@use './components/step-progress-overlay.scss';
|
@use './components/step-progress-overlay.scss';
|
||||||
@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/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: 2.2rem;
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
height: var(--app-height, 100vh);
|
height: var(--app-height, 100vh);
|
||||||
@@ -677,6 +677,78 @@
|
|||||||
margin-bottom: 0.16rem;
|
margin-bottom: 0.16rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 第2步投递偏好开关容器
|
||||||
|
&__step2-pref-switches {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.12rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第2步开关项
|
||||||
|
&__step2-switch-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0.2rem 0.24rem;
|
||||||
|
background: #F9FAFB;
|
||||||
|
border-radius: 0.12rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第2步开关文字区
|
||||||
|
&__step2-switch-text {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.04rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第2步开关标签
|
||||||
|
&__step2-switch-label {
|
||||||
|
font-size: 0.15rem;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 0.21rem;
|
||||||
|
color: #1A1A1A;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第2步开关描述
|
||||||
|
&__step2-switch-desc {
|
||||||
|
font-size: 0.13rem;
|
||||||
|
font-weight: 330;
|
||||||
|
line-height: 0.18rem;
|
||||||
|
color: $text-middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第2步自定义开关
|
||||||
|
&__step2-toggle {
|
||||||
|
position: relative;
|
||||||
|
width: 0.44rem;
|
||||||
|
height: 0.24rem;
|
||||||
|
background: #E5E7EB;
|
||||||
|
border-radius: 0.12rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
&--on {
|
||||||
|
background: $accent;
|
||||||
|
|
||||||
|
.agent-page__step2-toggle-dot {
|
||||||
|
left: 0.22rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第2步开关圆点
|
||||||
|
&__step2-toggle-dot {
|
||||||
|
position: absolute;
|
||||||
|
width: 0.18rem;
|
||||||
|
height: 0.18rem;
|
||||||
|
left: 0.04rem;
|
||||||
|
top: 0.03rem;
|
||||||
|
background: #FFFFFF;
|
||||||
|
border-radius: 50%;
|
||||||
|
transition: left 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
// 第2步功能说明区域 — 全宽
|
// 第2步功能说明区域 — 全宽
|
||||||
&__step2-faq {
|
&__step2-faq {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -744,13 +816,14 @@
|
|||||||
padding: 0.12rem 0.16rem;
|
padding: 0.12rem 0.16rem;
|
||||||
min-width: 1.6rem;
|
min-width: 1.6rem;
|
||||||
height: 0.43rem;
|
height: 0.43rem;
|
||||||
background: #F3F4F6;
|
background: #fff;
|
||||||
border-radius: 0.12rem;
|
border-radius: 0.12rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
transition: border-color 0.2s ease;
|
transition: border-color 0.2s ease;
|
||||||
width: 1.6rem;
|
width: 100%;
|
||||||
|
border: 1px solid #F0F0F0;
|
||||||
|
|
||||||
&:hover { border-color: darken($border-color, 10%); }
|
&:hover { border-color: darken($border-color, 10%); }
|
||||||
}
|
}
|
||||||
@@ -1928,7 +2001,7 @@
|
|||||||
.agent-page__install-dialog-title {
|
.agent-page__install-dialog-title {
|
||||||
position: relative;
|
position: relative;
|
||||||
font-size: 0.18rem;
|
font-size: 0.18rem;
|
||||||
font-weight: 520;
|
font-weight: 600;
|
||||||
color: $text-dark;
|
color: $text-dark;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin: 0 0 0.2rem 0;
|
margin: 0 0 0.2rem 0;
|
||||||
|
|||||||
@@ -0,0 +1,532 @@
|
|||||||
|
@use '../variables' as *;
|
||||||
|
|
||||||
|
// ==================== 校招公告详情页 ====================
|
||||||
|
|
||||||
|
.announcement-detail {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
width: 100%;
|
||||||
|
height: var(--app-height, 100vh);
|
||||||
|
overflow: hidden;
|
||||||
|
min-width: 12.8rem;
|
||||||
|
|
||||||
|
// 主内容区(与 JobDetail 一致,通过 margin-left 避开侧边栏)
|
||||||
|
&__content {
|
||||||
|
flex: 1;
|
||||||
|
height: var(--app-height, 100vh);
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
background: $bg-main;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页面标题
|
||||||
|
&__page-title {
|
||||||
|
font-size: 0.18rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $text-dark;
|
||||||
|
line-height: 0.24rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__page-subtitle {
|
||||||
|
font-size: 0.12rem;
|
||||||
|
color: $text-middle;
|
||||||
|
line-height: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回按钮行
|
||||||
|
&__back-row {
|
||||||
|
padding: 0 0.24rem;
|
||||||
|
margin-bottom: 0.12rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__back-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.04rem;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
color: $text-middle;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $accent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__back-icon {
|
||||||
|
width: 0.16rem;
|
||||||
|
height: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 主体内容可滚动区域
|
||||||
|
&__body {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 0 0.24rem 0.24rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 两列布局(公司卡片下方)
|
||||||
|
&__layout {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.12rem;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 左侧主详情
|
||||||
|
&__left {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
background: #fff;
|
||||||
|
padding: 0.24rem 0.32rem;
|
||||||
|
border-radius: 0.08rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 右侧边栏
|
||||||
|
&__right {
|
||||||
|
width: 4.24rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 顶部公司信息卡片(独占一行) ====================
|
||||||
|
|
||||||
|
.announcement-detail__company-card {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.24rem 0.32rem;
|
||||||
|
background: $bg-white;
|
||||||
|
border: 1px solid #F0F0F0;
|
||||||
|
box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.04);
|
||||||
|
border-radius: 0.08rem;
|
||||||
|
margin-bottom: 0.12rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__company-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__company-logo {
|
||||||
|
width: 0.66rem;
|
||||||
|
height: 0.66rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
&--default {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: #EDF9FA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__company-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.12rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__company-name-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__company-name {
|
||||||
|
font-size: 0.24rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $text-dark;
|
||||||
|
line-height: 0.32rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__company-tags {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 0.12rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__tag {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0.03rem 0.06rem;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.16rem;
|
||||||
|
border-radius: 0.04rem;
|
||||||
|
|
||||||
|
&--type {
|
||||||
|
background: #FEF3F2;
|
||||||
|
color: #B42318;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--gray {
|
||||||
|
background: #F3F4F6;
|
||||||
|
color: $text-middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__company-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__btn-outline {
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0.08rem 0.16rem;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
font-weight: 450;
|
||||||
|
color: $accent;
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid $accent;
|
||||||
|
border-radius: 0.08rem;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #EDF9FA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__btn-primary {
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0.08rem 0.16rem;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
font-weight: 450;
|
||||||
|
color: #FFFFFF;
|
||||||
|
background: $accent;
|
||||||
|
border: 1px solid $accent;
|
||||||
|
border-radius: 0.08rem;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $accent-hover;
|
||||||
|
border-color: $accent-hover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 岗位速览卡片 ====================
|
||||||
|
|
||||||
|
.announcement-detail__overview-card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 0.16rem 0.24rem;
|
||||||
|
gap: 0.16rem;
|
||||||
|
background: linear-gradient(180deg, #EDF9FA 0%, #FFFFFF 20.63%);
|
||||||
|
border: 1px solid #AEE6EA;
|
||||||
|
border-radius: 0.08rem;
|
||||||
|
margin-bottom: 0.24rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__overview-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__overview-title-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
gap: 0.12rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__overview-title {
|
||||||
|
font-size: 0.16rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $text-dark;
|
||||||
|
line-height: 0.21rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__overview-date {
|
||||||
|
font-size: 0.12rem;
|
||||||
|
font-weight: 330;
|
||||||
|
color: $text-middle;
|
||||||
|
line-height: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__overview-deadline {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
font-weight: 380;
|
||||||
|
color: $text-dark;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__overview-body {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.24rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__overview-fields {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 每行两个字段横排,align-items: stretch 保证同行等高
|
||||||
|
.announcement-detail__overview-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: stretch;
|
||||||
|
gap: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__overview-direction {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.04rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__overview-field {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.04rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__overview-label {
|
||||||
|
font-size: 0.12rem;
|
||||||
|
font-weight: 330;
|
||||||
|
color: $text-middle;
|
||||||
|
line-height: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__overview-value {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
font-weight: 380;
|
||||||
|
color: $text-dark;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 公告标题 ====================
|
||||||
|
|
||||||
|
.announcement-detail__main-title {
|
||||||
|
font-size: 0.24rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $text-dark;
|
||||||
|
line-height: 0.32rem;
|
||||||
|
margin-bottom: 0.24rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 详情正文段落 ====================
|
||||||
|
|
||||||
|
.announcement-detail__section {
|
||||||
|
margin-bottom: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__section-title {
|
||||||
|
font-size: 0.18rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $accent;
|
||||||
|
line-height: 0.24rem;
|
||||||
|
margin-bottom: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__section-content {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
font-weight: 330;
|
||||||
|
color: $text-dark;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 右侧边栏卡片 ====================
|
||||||
|
|
||||||
|
.announcement-detail__aside-card {
|
||||||
|
background: $bg-white;
|
||||||
|
border: 1px solid #F0F0F0;
|
||||||
|
box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.04);
|
||||||
|
border-radius: 0.08rem;
|
||||||
|
padding: 0.24rem 0.32rem;
|
||||||
|
margin-bottom: 0.12rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__aside-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 0.24rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__aside-title {
|
||||||
|
font-size: 0.18rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $accent;
|
||||||
|
line-height: 0.24rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__aside-more {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.04rem;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
font-weight: 450;
|
||||||
|
color: $text-middle;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 0.19rem;
|
||||||
|
height: 0.19rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $accent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__aside-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 企业其他岗位列表项 ====================
|
||||||
|
|
||||||
|
.announcement-detail__job-item {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding-bottom: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__job-item-main {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__job-item-title {
|
||||||
|
font-size: 0.16rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $text-dark;
|
||||||
|
line-height: 0.21rem;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0.08rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
max-width: 2.56rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__job-item-tags {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.08rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__job-item-score {
|
||||||
|
text-align: right;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__job-item-score-num {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.22rem;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 0.29rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__job-item-score-label {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
font-weight: 450;
|
||||||
|
line-height: 0.16rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__job-divider {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 0;
|
||||||
|
border-bottom: 1px solid #F0F0F0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 通用灰色chip ====================
|
||||||
|
|
||||||
|
.announcement-detail__chip {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0.03rem 0.06rem;
|
||||||
|
background: #F3F4F6;
|
||||||
|
border-radius: 0.04rem;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
font-weight: 380;
|
||||||
|
color: $text-middle;
|
||||||
|
line-height: 0.16rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 校招推荐列表项 ====================
|
||||||
|
|
||||||
|
.announcement-detail__rec-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 0.1rem;
|
||||||
|
position: relative;
|
||||||
|
padding-bottom: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__rec-logo {
|
||||||
|
width: 0.4rem;
|
||||||
|
height: 0.4rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
&--default {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: #EDF9FA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__rec-info {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.04rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__rec-company {
|
||||||
|
font-size: 0.16rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #111827;
|
||||||
|
line-height: 0.21rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__rec-positions {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
font-weight: 330;
|
||||||
|
color: $text-middle;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement-detail__rec-tags {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 0.04rem;
|
||||||
|
}
|
||||||
@@ -0,0 +1,555 @@
|
|||||||
|
// 校招公告页面样式
|
||||||
|
@use '../variables' as *;
|
||||||
|
|
||||||
|
.announcement-page {
|
||||||
|
display: flex;
|
||||||
|
min-width: 12.8rem;
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
flex: 1;
|
||||||
|
padding-bottom: 0.18rem;
|
||||||
|
height: var(--app-height, 100vh);
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
background: $bg-main;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页面标题
|
||||||
|
&__title {
|
||||||
|
font-size: 0.18rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: $text-dark;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__subtitle {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
color: $text-light;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 筛选条件外层
|
||||||
|
&__filters-bar {
|
||||||
|
border-radius: 0.12rem;
|
||||||
|
margin: 0 0.24rem 0.12rem 0.24rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 筛选面板 + 统计卡片横向排列
|
||||||
|
&__filters-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 0.12rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 筛选面板
|
||||||
|
&__filters-panel {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
background: $bg-white;
|
||||||
|
border: 1px solid #F0F0F0;
|
||||||
|
box-shadow: 0px 2px 6px rgba(15, 23, 42, 0.025);
|
||||||
|
border-radius: 0.12rem;
|
||||||
|
padding: 0.12rem 0.16rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.12rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 筛选行
|
||||||
|
&__filter-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.08rem 0.16rem;
|
||||||
|
background: $bg-white;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__filter-row-inner {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.16rem;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 筛选行标题
|
||||||
|
&__filter-row-label {
|
||||||
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.16rem;
|
||||||
|
font-weight: 380;
|
||||||
|
color: $text-middle;
|
||||||
|
flex-shrink: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// chip组外层
|
||||||
|
&__filter-chips-wrap {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 0.08rem;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
|
||||||
|
> .industry-selector,
|
||||||
|
> .job-category-selector,
|
||||||
|
> .region-selector {
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-left: auto;
|
||||||
|
align-self: flex-end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// chip组
|
||||||
|
&__filter-chips {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
align-content: center;
|
||||||
|
gap: 0.08rem;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 筛选chip
|
||||||
|
&__filter-chip {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.04rem 0.08rem;
|
||||||
|
background: #F3F4F6;
|
||||||
|
border-radius: 0.04rem;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.16rem;
|
||||||
|
font-weight: 330;
|
||||||
|
color: $text-dark;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
user-select: none;
|
||||||
|
transition: all 0.15s;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #E8F8F9;
|
||||||
|
color: $accent;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--active {
|
||||||
|
background: #F4FBFB;
|
||||||
|
border-color: $accent;
|
||||||
|
color: $accent;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--active-solid {
|
||||||
|
background: $accent;
|
||||||
|
color: #FFFFFF;
|
||||||
|
font-weight: 600;
|
||||||
|
border-color: $accent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 底部筛选行
|
||||||
|
&__filter-row--bottom {}
|
||||||
|
|
||||||
|
// 下拉按钮组容器
|
||||||
|
&__filter-dropdowns {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.08rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下拉按钮项
|
||||||
|
&__dropdown-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.02rem;
|
||||||
|
padding: 0.04rem 0.08rem;
|
||||||
|
border: 1px solid #F0F0F0;
|
||||||
|
border-radius: 0.04rem;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.16rem;
|
||||||
|
font-weight: 330;
|
||||||
|
color: $text-dark;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
position: relative;
|
||||||
|
user-select: none;
|
||||||
|
transition: all 0.15s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: $accent;
|
||||||
|
color: $accent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-range-separator {
|
||||||
|
padding-bottom: 0.03rem !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__dropdown-arrow {
|
||||||
|
width: 0.12rem;
|
||||||
|
height: 0.12rem;
|
||||||
|
color: $text-middle;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下拉菜单面板
|
||||||
|
&__filter-dropdown {
|
||||||
|
position: absolute;
|
||||||
|
top: calc(100% + 0.06rem);
|
||||||
|
left: 0;
|
||||||
|
background: $bg-white;
|
||||||
|
border: 1px solid #E8E8E8;
|
||||||
|
border-radius: 0.08rem;
|
||||||
|
padding: 0.04rem 0;
|
||||||
|
box-shadow: 0 0.04rem 0.12rem rgba(0, 0, 0, 0.08);
|
||||||
|
z-index: 20;
|
||||||
|
min-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下拉菜单选项
|
||||||
|
&__filter-dropdown-item {
|
||||||
|
padding: 0.06rem 0.16rem;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
color: $text-dark;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
transition: all 0.15s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $theme-color;
|
||||||
|
color: $accent-hover;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--active {
|
||||||
|
color: $accent;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清空筛选按钮
|
||||||
|
&__clear-filters {
|
||||||
|
font-size: 0.12rem;
|
||||||
|
color: $text-middle;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $accent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索框
|
||||||
|
&__search-box {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background: $bg-white;
|
||||||
|
border-radius: 0.08rem;
|
||||||
|
padding: 0.10rem 0.14rem;
|
||||||
|
border: 1px solid #F0F0F0;
|
||||||
|
|
||||||
|
&:focus-within {
|
||||||
|
border-color: $accent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__search-svg {
|
||||||
|
width: 0.14rem;
|
||||||
|
height: 0.14rem;
|
||||||
|
color: $text-light;
|
||||||
|
margin-right: 0.08rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__search-input {
|
||||||
|
flex: 1;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
color: $text-dark;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
color: $text-light;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 热门搜索标签
|
||||||
|
&__hot-search-label {
|
||||||
|
font-size: 0.12rem;
|
||||||
|
color: $text-middle;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-right: 0.07rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__hot-search-tag {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 0.24rem;
|
||||||
|
padding: 0 0.1rem;
|
||||||
|
border-radius: 0.04rem;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
color: $accent;
|
||||||
|
background: $bg-white;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
user-select: none;
|
||||||
|
transition: all 0.15s;
|
||||||
|
margin-right: 0.07rem;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&--active {
|
||||||
|
background: $accent;
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 列表区域
|
||||||
|
&__list {
|
||||||
|
overflow-y: auto;
|
||||||
|
height: calc(var(--app-height, 100vh) - 3.4rem);
|
||||||
|
padding: 0 0.24rem 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 表头
|
||||||
|
&__table-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.10rem 0.12rem;
|
||||||
|
background: #F4FBFB;
|
||||||
|
border-radius: 0.08rem 0.08rem 0 0;
|
||||||
|
border-bottom: 1px solid #F0F0F0;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $text-dark;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 5;
|
||||||
|
gap: 0.2rem;
|
||||||
|
>span{
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 表格行
|
||||||
|
&__table-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.12rem;
|
||||||
|
background: $bg-white;
|
||||||
|
border-bottom: 1px solid #F6F6F6;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
color: $text-dark;
|
||||||
|
transition: background 0.15s;
|
||||||
|
gap: 0.2rem;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $theme-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
>span{
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
>div{
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 表头列宽
|
||||||
|
&__th, &__td {
|
||||||
|
flex-shrink: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__th--time, &__td--time { min-width: 0.7rem; }
|
||||||
|
&__th--company, &__td--company { width: 1.8rem; flex-shrink: 1; }
|
||||||
|
&__th--title, &__td--title { width: 1.8rem; flex: 1; min-width: 1rem; }
|
||||||
|
&__th--position, &__td--position { width: 1.5rem; }
|
||||||
|
&__th--target, &__td--target { width: 1.2rem; }
|
||||||
|
&__th--major, &__td--major { width: 1.6rem; }
|
||||||
|
&__th--batch, &__td--batch { width: 1rem; }
|
||||||
|
&__th--deadline, &__td--deadline { width: 0.9rem; }
|
||||||
|
|
||||||
|
// 公司信息列
|
||||||
|
&__td--company {
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__company-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.08rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__company-logo {
|
||||||
|
width: 0.32rem;
|
||||||
|
height: 0.32rem;
|
||||||
|
border-radius: 0.06rem;
|
||||||
|
border: 1px solid #F4F4F4;
|
||||||
|
flex-shrink: 0;
|
||||||
|
object-fit: cover;
|
||||||
|
|
||||||
|
&--default {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: $bg-white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__company-text {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__company-name {
|
||||||
|
font-size: 0.13rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: $text-dark;
|
||||||
|
display: block;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__company-tags {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.04rem;
|
||||||
|
margin-top: 0.02rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__company-tag {
|
||||||
|
font-size: 0.11rem;
|
||||||
|
padding: 0.01rem 0.04rem;
|
||||||
|
border-radius: 0.02rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
&--industry {
|
||||||
|
background: #EDF9FA;
|
||||||
|
color: $accent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 多行单元格
|
||||||
|
&__td--position, &__td--target {
|
||||||
|
white-space: normal;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.02rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__cell-line {
|
||||||
|
font-size: 0.12rem;
|
||||||
|
color: $text-dark;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__cell-sub {
|
||||||
|
font-size: 0.11rem;
|
||||||
|
color: $text-light;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__recruit-year {
|
||||||
|
font-size: 0.12rem;
|
||||||
|
color: #175CD3;
|
||||||
|
background: #EFF8FF;
|
||||||
|
padding: 0 0.08rem;
|
||||||
|
border-radius: 0.04rem;
|
||||||
|
display: inline-block;
|
||||||
|
align-self: flex-start;
|
||||||
|
height: 0.24rem;
|
||||||
|
line-height: 0.24rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 空状态
|
||||||
|
&__empty {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
color: $text-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__empty-img {
|
||||||
|
width: 1.24rem;
|
||||||
|
height: 1.3rem;
|
||||||
|
display: block;
|
||||||
|
margin: 1rem auto 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__empty-title {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
color: $text-light;
|
||||||
|
margin-bottom: 0.08rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__empty-subtitle {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
color: $text-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__empty-link {
|
||||||
|
color: $accent;
|
||||||
|
text-decoration: underline;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 0.75;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载状态
|
||||||
|
&__loading-box {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.08rem;
|
||||||
|
padding: 0.24rem 0;
|
||||||
|
font-size: 0.13rem;
|
||||||
|
color: $text-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__loading-spinner {
|
||||||
|
width: 0.18rem;
|
||||||
|
height: 0.18rem;
|
||||||
|
border: 2px solid rgba(0, 0, 0, 0.1);
|
||||||
|
border-top-color: $accent;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: announcement-spin 0.6s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes announcement-spin {
|
||||||
|
to { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
&__loading-more {
|
||||||
|
text-align: center;
|
||||||
|
padding: 0.16rem 0;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
color: $text-light;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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: 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;
|
||||||
|
|||||||
@@ -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: 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: 2.2rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 左侧主内容区
|
// 左侧主内容区
|
||||||
|
|||||||
@@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
// ==================== 个人资料页 ====================
|
// ==================== 个人资料页 ====================
|
||||||
.profile-page {
|
.profile-page {
|
||||||
|
min-width: 12.8rem;
|
||||||
|
|
||||||
&__content {
|
&__content {
|
||||||
margin-left: 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: 2.2rem;
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding-bottom: 0.24rem;
|
padding-bottom: 0.24rem;
|
||||||
height: var(--app-height, 100vh);
|
height: var(--app-height, 100vh);
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
@use '../variables' as *;
|
@use '../variables' as *;
|
||||||
|
|
||||||
// ==================== 简历列表页 ====================
|
// ==================== 简历列表页(卡片视图) ====================
|
||||||
.resume-page {
|
.resume-page {
|
||||||
|
min-width: 12.8rem;
|
||||||
|
|
||||||
&__content {
|
&__content {
|
||||||
margin-left: 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 上传简历加载提示 ====================
|
// ==================== 上传简历加载提示 ====================
|
||||||
|
|||||||
@@ -1,6 +1,99 @@
|
|||||||
<!-- Agent页面 - 浏览器插件安装步骤指引组件 -->
|
<!-- Agent页面 - 浏览器插件安装步骤指引组件(双Tab切换) -->
|
||||||
<template>
|
<template>
|
||||||
<div class="agent-browser-guide-drawer__body">
|
<div class="agent-browser-guide">
|
||||||
|
<!-- 顶部Tab切换 -->
|
||||||
|
<div class="agent-browser-guide__tabs">
|
||||||
|
<div
|
||||||
|
class="agent-browser-guide__tab"
|
||||||
|
:class="{ 'agent-browser-guide__tab--active': activeTab === 'edge' }"
|
||||||
|
@click="activeTab = 'edge'"
|
||||||
|
>
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip_tab_edge)">
|
||||||
|
<path d="M14.4375 11.9059C14.225 12.0184 14.0062 12.1184 13.7812 12.1996C13.0625 12.4684 12.3062 12.6059 11.5375 12.6059C8.5812 12.6059 6.0062 10.5746 6.0062 7.96211C6.01245 7.24961 6.4062 6.59336 7.0312 6.25586C4.3562 6.36836 3.6687 9.15586 3.6687 10.7871C3.6687 15.4059 7.92495 15.8746 8.8437 15.8746C9.33745 15.8746 10.0812 15.7309 10.5312 15.5871L10.6125 15.5621C12.3375 14.9684 13.8 13.8059 14.775 12.2621C14.85 12.1434 14.8125 11.9934 14.7 11.9184C14.6187 11.8684 14.5187 11.8621 14.4375 11.9059Z" fill="#0C59A4"/>
|
||||||
|
<path d="M9.51875 9.30625C9.46875 9.36875 9.3125 9.4625 9.3125 9.6625C9.3125 9.825 9.41875 9.98125 9.60625 10.1125C10.5062 10.7375 12.2 10.6562 12.2063 10.6562C12.875 10.6562 13.525 10.475 14.1 10.1375C15.275 9.45 16 8.19375 16 6.83125C16.0187 5.43125 15.5 4.5 15.2937 4.0875C13.9688 1.49375 11.1062 0 8 0C3.625 0 0.0625 3.5125 0 7.8875C0.03125 5.60625 2.3 3.7625 5 3.7625C5.21875 3.7625 6.46875 3.78125 7.625 4.39375C8.64375 4.93125 9.18125 5.575 9.55 6.21875C9.9375 6.8875 10.0063 7.725 10.0063 8.0625C10.0063 8.39375 9.8375 8.89375 9.51875 9.30625Z" fill="#35C1F1"/>
|
||||||
|
</g>
|
||||||
|
<defs><clipPath id="clip_tab_edge"><rect width="16" height="16" fill="white"/></clipPath></defs>
|
||||||
|
</svg>
|
||||||
|
<span>Edge商店下载</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="agent-browser-guide__tab"
|
||||||
|
:class="{ 'agent-browser-guide__tab--active': activeTab === 'manual' }"
|
||||||
|
@click="activeTab = 'manual'"
|
||||||
|
>
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip_tab_chrome)">
|
||||||
|
<path d="M8 12.45C10.46 12.45 12.45 10.46 12.45 8C12.45 5.54 10.46 3.55 8 3.55C5.54 3.55 3.55 5.54 3.55 8C3.55 10.46 5.54 12.45 8 12.45" fill="white"/>
|
||||||
|
<path d="M2.24 5.81C1.91 5.24 1.52 4.63 1.07 4C0.37 5.22 0 6.6 0 8C0 9.41 0.37 10.78 1.07 12C1.77 13.22 2.78 14.23 4 14.93C5.22 15.63 6.6 16 8 16C8.74 14.97 9.24 14.22 9.5 13.77C10.01 12.89 10.66 11.63 11.46 10V10C11.11 10.61 10.61 11.11 10 11.46C9.39 11.82 8.7 12 8 12C7.3 12 6.61 11.82 6 11.46C5.39 11.11 4.89 10.61 4.54 10C3.44 7.97 2.68 6.57 2.24 5.81Z" fill="#229342"/>
|
||||||
|
<path d="M8 16C9.05 16 10.09 15.79 11.06 15.39C12.03 14.99 12.91 14.4 13.66 13.66C14.4 12.91 14.99 12.03 15.39 11.06C15.79 10.09 16 9.05 16 8C16 6.6 15.63 5.22 14.93 4C13.41 3.85 12.29 3.78 11.57 3.78C10.75 3.78 9.56 3.85 8 4L8 4C8.7 4 9.39 4.19 10 4.54C10.61 4.89 11.11 5.39 11.46 6C11.82 6.61 12 7.3 12 8C12 8.7 11.82 9.39 11.46 10L8 16Z" fill="#FBC116"/>
|
||||||
|
<path d="M8 11.17C9.75 11.17 11.17 9.75 11.17 8C11.17 6.25 9.75 4.83 8 4.83C6.25 4.83 4.83 6.25 4.83 8C4.83 9.75 6.25 11.17 8 11.17Z" fill="#1A73E8"/>
|
||||||
|
<path d="M8 4H14.93C14.23 2.78 13.22 1.77 12 1.07C10.78 0.37 9.4 0 8 0C6.6 0 5.22 0.37 4 1.07C2.78 1.77 1.77 2.78 1.07 4L4.54 10L4.54 10C4.19 9.39 4 8.7 4 8C4 7.3 4.18 6.61 4.54 6C4.89 5.39 5.39 4.89 6 4.54C6.61 4.18 7.3 4 8 4Z" fill="#E33B2E"/>
|
||||||
|
</g>
|
||||||
|
<defs><clipPath id="clip_tab_chrome"><rect width="16" height="16" fill="white"/></clipPath></defs>
|
||||||
|
</svg>
|
||||||
|
<span>Chrome/Edge手动安装</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Tab1: Edge商店下载(3步) -->
|
||||||
|
<div v-if="activeTab === 'edge'" class="agent-browser-guide-drawer__body">
|
||||||
|
<!-- 步骤1:点击链接跳转商店 -->
|
||||||
|
<div class="agent-browser-guide-drawer__card">
|
||||||
|
<div class="mr100">
|
||||||
|
<div class="agent-browser-guide-drawer__step-row mr0">
|
||||||
|
<span class="agent-browser-guide-drawer__step-num">1</span>
|
||||||
|
<div class="agent-browser-guide-drawer__step-info">
|
||||||
|
<h4 class="agent-browser-guide-drawer__step-title">点击下方链接跳转商店,获取插件</h4>
|
||||||
|
<p class="agent-browser-guide-drawer__step-desc">打开 Edge 扩展商店中的「<a class="agent-browser-guide__link" :href="edgeStoreUrl" target="_blank">Offer派智能投递助手</a>」页面,点击右上角「获取」。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 商店链接 + 跳转按钮 -->
|
||||||
|
<div class="agent-browser-guide-drawer__download-box agent-browser-guide-drawer__download-box--wide">
|
||||||
|
<span class="agent-browser-guide-drawer__download-name agent-browser-guide__url-text">{{ edgeStoreUrlDisplay }}</span>
|
||||||
|
<button class="agent-browser-guide-drawer__download-btn" @click="openEdgeStore">
|
||||||
|
<svg viewBox="0 0 16 16" fill="none" width="14" height="14"><path d="M6 3h7v7M13 3L3 13" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||||
|
<span>跳转下载</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 步骤1示意图 -->
|
||||||
|
<img src="@/assets/images/agent-setting/edge-step1.png" alt="Edge商店获取插件" class="agent-browser-guide-drawer__step-img" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 步骤2:添加扩展 -->
|
||||||
|
<div class="agent-browser-guide-drawer__card">
|
||||||
|
<div>
|
||||||
|
<div class="agent-browser-guide-drawer__step-row">
|
||||||
|
<span class="agent-browser-guide-drawer__step-num">2</span>
|
||||||
|
<div class="agent-browser-guide-drawer__step-info">
|
||||||
|
<h4 class="agent-browser-guide-drawer__step-title">添加扩展</h4>
|
||||||
|
<p class="agent-browser-guide-drawer__step-desc">在浏览器弹出的确认窗口中,点击「添加扩展」,等待插件自动安装完成。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 步骤2示意图 -->
|
||||||
|
<img src="@/assets/images/agent-setting/edge-step2.png" alt="添加扩展" class="agent-browser-guide-drawer__step-img" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 步骤3:固定插件 -->
|
||||||
|
<div class="agent-browser-guide-drawer__card">
|
||||||
|
<div>
|
||||||
|
<div class="agent-browser-guide-drawer__step-row">
|
||||||
|
<span class="agent-browser-guide-drawer__step-num">3</span>
|
||||||
|
<div class="agent-browser-guide-drawer__step-info">
|
||||||
|
<h4 class="agent-browser-guide-drawer__step-title">固定插件</h4>
|
||||||
|
<p class="agent-browser-guide-drawer__step-desc">点击浏览器右上角的「扩展」图标,找到「Offer派智能投递助手」,点击右侧的固钉图标,将插件固定到工具栏,方便后续使用。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 步骤3示意图 -->
|
||||||
|
<img src="@/assets/images/agent-setting/edge-step3.png" alt="固定插件" class="agent-browser-guide-drawer__step-img" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Tab2: Chrome/Edge手动安装(4步,保留原内容) -->
|
||||||
|
<div v-if="activeTab === 'manual'" class="agent-browser-guide-drawer__body">
|
||||||
<!-- 步骤1:下载插件包 -->
|
<!-- 步骤1:下载插件包 -->
|
||||||
<div class="agent-browser-guide-drawer__card">
|
<div class="agent-browser-guide-drawer__card">
|
||||||
<div class="mr100">
|
<div class="mr100">
|
||||||
@@ -8,7 +101,7 @@
|
|||||||
<span class="agent-browser-guide-drawer__step-num">1</span>
|
<span class="agent-browser-guide-drawer__step-num">1</span>
|
||||||
<div class="agent-browser-guide-drawer__step-info">
|
<div class="agent-browser-guide-drawer__step-info">
|
||||||
<h4 class="agent-browser-guide-drawer__step-title">下载并解压插件压缩包</h4>
|
<h4 class="agent-browser-guide-drawer__step-title">下载并解压插件压缩包</h4>
|
||||||
<p class="agent-browser-guide-drawer__step-desc">下载 Offer派自动投递助手安装包,并将下载好的插件压缩包解压</p>
|
<p class="agent-browser-guide-drawer__step-desc">下载 Offer派智能投递助手安装包,并将下载好的插件压缩包解压</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="agent-browser-guide-drawer__download-box w263">
|
<div class="agent-browser-guide-drawer__download-box w263">
|
||||||
@@ -25,7 +118,6 @@
|
|||||||
|
|
||||||
<!-- 步骤2:打开扩展管理页面 -->
|
<!-- 步骤2:打开扩展管理页面 -->
|
||||||
<div class="agent-browser-guide-drawer__card">
|
<div class="agent-browser-guide-drawer__card">
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class="agent-browser-guide-drawer__step-row">
|
<div class="agent-browser-guide-drawer__step-row">
|
||||||
<span class="agent-browser-guide-drawer__step-num">2</span>
|
<span class="agent-browser-guide-drawer__step-num">2</span>
|
||||||
@@ -38,18 +130,14 @@
|
|||||||
<div class="agent-browser-guide-drawer__browser-links">
|
<div class="agent-browser-guide-drawer__browser-links">
|
||||||
<div class="agent-browser-guide-drawer__browser-link" @click="copyToClipboard('chrome://extensions')">
|
<div class="agent-browser-guide-drawer__browser-link" @click="copyToClipboard('chrome://extensions')">
|
||||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<g clip-path="url(#clip0_guide_chrome)">
|
<g clip-path="url(#clip0_guide_chrome2)">
|
||||||
<path d="M8.00027 12.4507C10.4587 12.4507 12.4516 10.4577 12.4516 7.99929C12.4516 5.54085 10.4587 3.54785 8.00027 3.54785C5.54183 3.54785 3.54883 5.54085 3.54883 7.99929C3.54883 10.4577 5.54177 12.4507 8.0002 12.4507" fill="white"/>
|
<path d="M8 12.45C10.46 12.45 12.45 10.46 12.45 8C12.45 5.54 10.46 3.55 8 3.55C5.54 3.55 3.55 5.54 3.55 8C3.55 10.46 5.54 12.45 8 12.45" fill="white"/>
|
||||||
<path d="M2.24303 5.81204C1.91094 5.23683 1.52061 4.63314 1.07203 4.00098C0.369757 5.21706 2.38548e-05 6.59661 1.15428e-09 8.0009C-2.38525e-05 9.4052 0.369663 10.7848 1.07189 12.0009C1.77412 13.217 2.78414 14.2268 4.0004 14.9288C5.21666 15.6307 6.59629 16.0001 8.00059 15.9998C8.73688 14.9671 9.2368 14.2225 9.50034 13.766C10.0065 12.8893 10.6612 11.6341 11.4643 10.0004V9.99941C11.1134 10.6077 10.6086 11.113 10.0005 11.4643C9.39241 11.8156 8.70256 12.0006 8.0003 12.0007C7.29804 12.0008 6.60813 11.816 5.99995 11.4649C5.39178 11.1138 4.88677 10.6087 4.53571 10.0005C3.44496 7.96623 2.68073 6.57004 2.24303 5.81204Z" fill="#229342"/>
|
<path d="M2.24 5.81C1.91 5.24 1.52 4.63 1.07 4C0.37 5.22 0 6.6 0 8C0 9.41 0.37 10.78 1.07 12C1.77 13.22 2.78 14.23 4 14.93C5.22 15.63 6.6 16 8 16C8.74 14.97 9.24 14.22 9.5 13.77C10.01 12.89 10.66 11.63 11.46 10V10C11.11 10.61 10.61 11.11 10 11.46C9.39 11.82 8.7 12 8 12C7.3 12 6.61 11.82 6 11.46C5.39 11.11 4.89 10.61 4.54 10C3.44 7.97 2.68 6.57 2.24 5.81Z" fill="#229342"/>
|
||||||
<path d="M8.00046 16.0002C9.05106 16.0004 10.0914 15.7936 11.0621 15.3916C12.0327 14.9896 12.9147 14.4003 13.6575 13.6574C14.4004 12.9145 14.9896 12.0325 15.3915 11.0619C15.7935 10.0912 16.0002 9.05084 16 8.00024C15.9997 6.59593 15.6297 5.21644 14.9273 4.00043C13.4118 3.85105 12.2933 3.77637 11.5719 3.77637C10.7539 3.77637 9.56323 3.85105 7.9999 4.00043L7.99902 4.00105C8.7013 4.00071 9.39128 4.18529 9.99958 4.53623C10.6079 4.88717 11.113 5.39211 11.4643 6.00024C11.8155 6.60838 12.0004 7.29828 12.0004 8.00056C12.0004 8.70284 11.8155 9.39274 11.4642 10.0009L8.00046 16.0002Z" fill="#FBC116"/>
|
<path d="M8 16C9.05 16 10.09 15.79 11.06 15.39C12.03 14.99 12.91 14.4 13.66 13.66C14.4 12.91 14.99 12.03 15.39 11.06C15.79 10.09 16 9.05 16 8C16 6.6 15.63 5.22 14.93 4C13.41 3.85 12.29 3.78 11.57 3.78C10.75 3.78 9.56 3.85 8 4L8 4C8.7 4 9.39 4.19 10 4.54C10.61 4.89 11.11 5.39 11.46 6C11.82 6.61 12 7.3 12 8C12 8.7 11.82 9.39 11.46 10L8 16Z" fill="#FBC116"/>
|
||||||
<path d="M8.00013 11.1677C9.74913 11.1677 11.1669 9.74992 11.1669 8.00086C11.1669 6.2518 9.74913 4.83398 8.00006 4.83398C6.25113 4.83398 4.83325 6.25186 4.83325 8.00086C4.83325 9.74986 6.25113 11.1677 8.00013 11.1677Z" fill="#1A73E8"/>
|
<path d="M8 11.17C9.75 11.17 11.17 9.75 11.17 8C11.17 6.25 9.75 4.83 8 4.83C6.25 4.83 4.83 6.25 4.83 8C4.83 9.75 6.25 11.17 8 11.17Z" fill="#1A73E8"/>
|
||||||
<path d="M8.00027 4.00027H14.9276C14.2256 2.78399 13.2158 1.77397 11.9997 1.07176C10.7835 0.369547 9.40396 -9.50021e-05 7.99965 1.83149e-08C6.59534 9.50388e-05 5.21581 0.369924 3.99978 1.0723C2.78374 1.77467 1.77406 2.78484 1.07227 4.00121L4.53595 10.0006L4.53689 10.0011C4.18549 9.39306 4.00037 8.70322 4.00017 8.00095C3.99996 7.29868 4.18467 6.60873 4.53571 6.0005C4.88676 5.39226 5.39177 4.88718 5.99995 4.53605C6.60814 4.18491 7.29806 4.0001 8.00033 4.00021L8.00027 4.00027Z" fill="#E33B2E"/>
|
<path d="M8 4H14.93C14.23 2.78 13.22 1.77 12 1.07C10.78 0.37 9.4 0 8 0C6.6 0 5.22 0.37 4 1.07C2.78 1.77 1.77 2.78 1.07 4L4.54 10L4.54 10C4.19 9.39 4 8.7 4 8C4 7.3 4.18 6.61 4.54 6C4.89 5.39 5.39 4.89 6 4.54C6.61 4.18 7.3 4 8 4Z" fill="#E33B2E"/>
|
||||||
</g>
|
</g>
|
||||||
<defs>
|
<defs><clipPath id="clip0_guide_chrome2"><rect width="16" height="16" fill="white"/></clipPath></defs>
|
||||||
<clipPath id="clip0_guide_chrome">
|
|
||||||
<rect width="16" height="16" fill="white"/>
|
|
||||||
</clipPath>
|
|
||||||
</defs>
|
|
||||||
</svg>
|
</svg>
|
||||||
<span>Chrome浏览器:chrome://extensions</span>
|
<span>Chrome浏览器:chrome://extensions</span>
|
||||||
<span class="agent-browser-guide-drawer__copy-btn">
|
<span class="agent-browser-guide-drawer__copy-btn">
|
||||||
@@ -59,50 +147,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="agent-browser-guide-drawer__browser-link" @click="copyToClipboard('edge://extensions')">
|
<div class="agent-browser-guide-drawer__browser-link" @click="copyToClipboard('edge://extensions')">
|
||||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<g clip-path="url(#clip0_guide_edge)">
|
<g clip-path="url(#clip0_guide_edge2)">
|
||||||
<path d="M14.4375 11.9059C14.225 12.0184 14.0062 12.1184 13.7812 12.1996C13.0625 12.4684 12.3062 12.6059 11.5375 12.6059C8.5812 12.6059 6.0062 10.5746 6.0062 7.96211C6.01245 7.24961 6.4062 6.59336 7.0312 6.25586C4.3562 6.36836 3.6687 9.15586 3.6687 10.7871C3.6687 15.4059 7.92495 15.8746 8.8437 15.8746C9.33745 15.8746 10.0812 15.7309 10.5312 15.5871L10.6125 15.5621C12.3375 14.9684 13.8 13.8059 14.775 12.2621C14.85 12.1434 14.8125 11.9934 14.7 11.9184C14.6187 11.8684 14.5187 11.8621 14.4375 11.9059Z" fill="url(#paint0_linear_guide_edge)"/>
|
<path d="M14.4375 11.9059C14.225 12.0184 14.0062 12.1184 13.7812 12.1996C13.0625 12.4684 12.3062 12.6059 11.5375 12.6059C8.5812 12.6059 6.0062 10.5746 6.0062 7.96211C6.01245 7.24961 6.4062 6.59336 7.0312 6.25586C4.3562 6.36836 3.6687 9.15586 3.6687 10.7871C3.6687 15.4059 7.92495 15.8746 8.8437 15.8746C9.33745 15.8746 10.0812 15.7309 10.5312 15.5871L10.6125 15.5621C12.3375 14.9684 13.8 13.8059 14.775 12.2621C14.85 12.1434 14.8125 11.9934 14.7 11.9184C14.6187 11.8684 14.5187 11.8621 14.4375 11.9059Z" fill="#0C59A4"/>
|
||||||
<path opacity="0.35" d="M14.4375 11.9059C14.225 12.0184 14.0062 12.1184 13.7812 12.1996C13.0625 12.4684 12.3062 12.6059 11.5375 12.6059C8.5812 12.6059 6.0062 10.5746 6.0062 7.96211C6.01245 7.24961 6.4062 6.59336 7.0312 6.25586C4.3562 6.36836 3.6687 9.15586 3.6687 10.7871C3.6687 15.4059 7.92495 15.8746 8.8437 15.8746C9.33745 15.8746 10.0812 15.7309 10.5312 15.5871L10.6125 15.5621C12.3375 14.9684 13.8 13.8059 14.775 12.2621C14.85 12.1434 14.8125 11.9934 14.7 11.9184C14.6187 11.8684 14.5187 11.8621 14.4375 11.9059Z" fill="url(#paint1_radial_guide_edge)"/>
|
<path d="M9.51875 9.30625C9.46875 9.36875 9.3125 9.4625 9.3125 9.6625C9.3125 9.825 9.41875 9.98125 9.60625 10.1125C10.5062 10.7375 12.2 10.6562 12.2063 10.6562C12.875 10.6562 13.525 10.475 14.1 10.1375C15.275 9.45 16 8.19375 16 6.83125C16.0187 5.43125 15.5 4.5 15.2937 4.0875C13.9688 1.49375 11.1062 0 8 0C3.625 0 0.0625 3.5125 0 7.8875C0.03125 5.60625 2.3 3.7625 5 3.7625C5.21875 3.7625 6.46875 3.78125 7.625 4.39375C8.64375 4.93125 9.18125 5.575 9.55 6.21875C9.9375 6.8875 10.0063 7.725 10.0063 8.0625C10.0063 8.39375 9.8375 8.89375 9.51875 9.30625Z" fill="#35C1F1"/>
|
||||||
<path d="M6.60629 15.0877C6.05004 14.7439 5.56879 14.2877 5.18754 13.7564C3.54379 11.5064 4.03754 8.3502 6.28754 6.70645C6.52504 6.5377 6.76879 6.38145 7.03129 6.25645C7.22504 6.1627 7.55629 6.0002 8.00004 6.00645C8.63129 6.0127 9.22504 6.3127 9.60629 6.81895C9.85629 7.15645 10 7.5627 10.0063 7.9877C10.0063 7.9752 11.5375 3.0127 5.00629 3.0127C2.26254 3.0127 0.00628588 5.61895 0.00628588 7.9002C-0.00621412 9.10645 0.256286 10.3064 0.762536 11.4002C2.48754 15.0752 6.68754 16.8752 10.5375 15.5939C9.21879 16.0064 7.78129 15.8252 6.60629 15.0877Z" fill="url(#paint2_linear_guide_edge)"/>
|
|
||||||
<path opacity="0.41" d="M6.60629 15.0877C6.05004 14.7439 5.56879 14.2877 5.18754 13.7564C3.54379 11.5064 4.03754 8.3502 6.28754 6.70645C6.52504 6.5377 6.76879 6.38145 7.03129 6.25645C7.22504 6.1627 7.55629 6.0002 8.00004 6.00645C8.63129 6.0127 9.22504 6.3127 9.60629 6.81895C9.85629 7.15645 10 7.5627 10.0063 7.9877C10.0063 7.9752 11.5375 3.0127 5.00629 3.0127C2.26254 3.0127 0.00628588 5.61895 0.00628588 7.9002C-0.00621412 9.10645 0.256286 10.3064 0.762536 11.4002C2.48754 15.0752 6.68754 16.8752 10.5375 15.5939C9.21879 16.0064 7.78129 15.8252 6.60629 15.0877Z" fill="url(#paint3_radial_guide_edge)"/>
|
|
||||||
<path d="M9.51875 9.30625C9.46875 9.36875 9.3125 9.4625 9.3125 9.6625C9.3125 9.825 9.41875 9.98125 9.60625 10.1125C10.5062 10.7375 12.2 10.6562 12.2063 10.6562C12.875 10.6562 13.525 10.475 14.1 10.1375C15.275 9.45 16 8.19375 16 6.83125C16.0187 5.43125 15.5 4.5 15.2937 4.0875C13.9688 1.49375 11.1062 0 8 0C3.625 0 0.0625 3.5125 0 7.8875C0.03125 5.60625 2.3 3.7625 5 3.7625C5.21875 3.7625 6.46875 3.78125 7.625 4.39375C8.64375 4.93125 9.18125 5.575 9.55 6.21875C9.9375 6.8875 10.0063 7.725 10.0063 8.0625C10.0063 8.39375 9.8375 8.89375 9.51875 9.30625Z" fill="url(#paint4_radial_guide_edge)"/>
|
|
||||||
<path d="M9.51875 9.30625C9.46875 9.36875 9.3125 9.4625 9.3125 9.6625C9.3125 9.825 9.41875 9.98125 9.60625 10.1125C10.5062 10.7375 12.2 10.6562 12.2063 10.6562C12.875 10.6562 13.525 10.475 14.1 10.1375C15.275 9.45 16 8.19375 16 6.83125C16.0187 5.43125 15.5 4.5 15.2937 4.0875C13.9688 1.49375 11.1062 0 8 0C3.625 0 0.0625 3.5125 0 7.8875C0.03125 5.60625 2.3 3.7625 5 3.7625C5.21875 3.7625 6.46875 3.78125 7.625 4.39375C8.64375 4.93125 9.18125 5.575 9.55 6.21875C9.9375 6.8875 10.0063 7.725 10.0063 8.0625C10.0063 8.39375 9.8375 8.89375 9.51875 9.30625Z" fill="url(#paint5_radial_guide_edge)"/>
|
|
||||||
</g>
|
</g>
|
||||||
<defs>
|
<defs><clipPath id="clip0_guide_edge2"><rect width="16" height="16" fill="white"/></clipPath></defs>
|
||||||
<linearGradient id="paint0_linear_guide_edge" x1="3.66895" y1="11.0634" x2="14.8116" y2="11.0634" gradientUnits="userSpaceOnUse">
|
|
||||||
<stop stop-color="#0C59A4"/>
|
|
||||||
<stop offset="1" stop-color="#114A8B"/>
|
|
||||||
</linearGradient>
|
|
||||||
<radialGradient id="paint1_radial_guide_edge" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(9.82444 11.1519) scale(5.96065 5.662)">
|
|
||||||
<stop offset="0.72" stop-opacity="0"/>
|
|
||||||
<stop offset="0.95" stop-opacity="0.53"/>
|
|
||||||
<stop offset="1"/>
|
|
||||||
</radialGradient>
|
|
||||||
<linearGradient id="paint2_linear_guide_edge" x1="9.54822" y1="6.23432" x2="2.58741" y2="13.8163" gradientUnits="userSpaceOnUse">
|
|
||||||
<stop stop-color="#1B9DE2"/>
|
|
||||||
<stop offset="0.16" stop-color="#1595DF"/>
|
|
||||||
<stop offset="0.67" stop-color="#0680D7"/>
|
|
||||||
<stop offset="1" stop-color="#0078D4"/>
|
|
||||||
</linearGradient>
|
|
||||||
<radialGradient id="paint3_radial_guide_edge" cx="0" cy="0" r="1" gradientTransform="matrix(1.34287 -8.86118 7.162 1.0743 4.41307 12.4383)" gradientUnits="userSpaceOnUse">
|
|
||||||
<stop offset="0.76" stop-opacity="0"/>
|
|
||||||
<stop offset="0.95" stop-opacity="0.5"/>
|
|
||||||
<stop offset="1"/>
|
|
||||||
</radialGradient>
|
|
||||||
<radialGradient id="paint4_radial_guide_edge" cx="0" cy="0" r="1" gradientTransform="matrix(-0.506075 12.6493 -26.9472 -1.0119 1.61573 2.96205)" gradientUnits="userSpaceOnUse">
|
|
||||||
<stop stop-color="#35C1F1"/>
|
|
||||||
<stop offset="0.11" stop-color="#34C1ED"/>
|
|
||||||
<stop offset="0.23" stop-color="#2FC2DF"/>
|
|
||||||
<stop offset="0.31" stop-color="#2BC3D2"/>
|
|
||||||
<stop offset="0.67" stop-color="#36C752"/>
|
|
||||||
</radialGradient>
|
|
||||||
<radialGradient id="paint5_radial_guide_edge" cx="0" cy="0" r="1" gradientTransform="matrix(1.70345 5.83918 -4.74533 1.39926 15.0038 4.83786)" gradientUnits="userSpaceOnUse">
|
|
||||||
<stop stop-color="#66EB6E"/>
|
|
||||||
<stop offset="1" stop-color="#66EB6E" stop-opacity="0"/>
|
|
||||||
</radialGradient>
|
|
||||||
<clipPath id="clip0_guide_edge">
|
|
||||||
<rect width="16" height="16" fill="white"/>
|
|
||||||
</clipPath>
|
|
||||||
</defs>
|
|
||||||
</svg>
|
</svg>
|
||||||
<span>Edge浏览器:edge://extensions</span>
|
<span>Edge浏览器:edge://extensions</span>
|
||||||
<span class="agent-browser-guide-drawer__copy-btn">
|
<span class="agent-browser-guide-drawer__copy-btn">
|
||||||
@@ -111,7 +160,6 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!-- 步骤2示意图 -->
|
<!-- 步骤2示意图 -->
|
||||||
<img src="@/assets/images/agent-setting/2-1.png" alt="输入扩展地址" class="agent-browser-guide-drawer__step-img" />
|
<img src="@/assets/images/agent-setting/2-1.png" alt="输入扩展地址" class="agent-browser-guide-drawer__step-img" />
|
||||||
@@ -131,28 +179,47 @@
|
|||||||
<img src="@/assets/images/agent-setting/3-1.png" alt="打开开发者模式" class="agent-browser-guide-drawer__step-img max-w602" />
|
<img src="@/assets/images/agent-setting/3-1.png" alt="打开开发者模式" class="agent-browser-guide-drawer__step-img max-w602" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 步骤4:将CRX安装包拖入安装 -->
|
<!-- 步骤4:加载未打包的扩展程序 -->
|
||||||
<div class="agent-browser-guide-drawer__card">
|
<div class="agent-browser-guide-drawer__card">
|
||||||
<div class="agent-browser-guide-drawer__step-row">
|
<div class="agent-browser-guide-drawer__step-row">
|
||||||
<span class="agent-browser-guide-drawer__step-num">4</span>
|
<span class="agent-browser-guide-drawer__step-num">4</span>
|
||||||
<div class="agent-browser-guide-drawer__step-info">
|
<div class="agent-browser-guide-drawer__step-info dflex flex-warp">
|
||||||
|
<div>
|
||||||
<h4 class="agent-browser-guide-drawer__step-title">点击加载未打包的扩展程序</h4>
|
<h4 class="agent-browser-guide-drawer__step-title">点击加载未打包的扩展程序</h4>
|
||||||
<p class="agent-browser-guide-drawer__step-desc">点击"加载未打包的扩展程序",选择解压后的插件文件夹,完成安装</p>
|
<p class="agent-browser-guide-drawer__step-desc">点击「加载未打包的扩展程序」,选择直接包含 static 文件夹的「Offer派智能投递助手」文件夹</p>
|
||||||
|
</div>
|
||||||
|
<img src="@/assets/images/agent-setting/4-1.png" alt="加载扩展" class="agent-browser-guide-drawer__step-img" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 步骤4示意图 -->
|
<!-- 步骤4示意图 -->
|
||||||
<img src="@/assets/images/agent-setting/4-1.png" alt="拖入安装" class="agent-browser-guide-drawer__step-img" />
|
|
||||||
|
<img src="@/assets/images/agent-setting/4-2.png" alt="加载扩展" class="agent-browser-guide-drawer__step-img" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
|
||||||
/** 插件下载地址 */
|
/** 当前激活的Tab */
|
||||||
|
const activeTab = ref<'edge' | 'manual'>('edge')
|
||||||
|
|
||||||
|
/** Edge扩展商店地址 */
|
||||||
|
const edgeStoreUrl = 'https://microsoftedge.microsoft.com/addons/detail/offer派智能投递助手/jianshixingqiu'
|
||||||
|
/** Edge商店地址展示文本(截断显示) */
|
||||||
|
const edgeStoreUrlDisplay = 'https://microsoftedge.microsoft.com/addons/detai...'
|
||||||
|
|
||||||
|
/** 插件zip下载地址 */
|
||||||
const extensionDownloadUrl = 'https://offerpie.oss-cn-guangzhou.aliyuncs.com/extension/Offer派智能投递助手.zip'
|
const extensionDownloadUrl = 'https://offerpie.oss-cn-guangzhou.aliyuncs.com/extension/Offer派智能投递助手.zip'
|
||||||
|
|
||||||
/** 下载插件 */
|
/** 跳转Edge商店 */
|
||||||
|
function openEdgeStore() {
|
||||||
|
window.open(edgeStoreUrl, '_blank')
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 下载插件zip包 */
|
||||||
function downloadExtension() {
|
function downloadExtension() {
|
||||||
window.open(extensionDownloadUrl, '_blank')
|
window.open(extensionDownloadUrl, '_blank')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,9 +43,28 @@
|
|||||||
<span class="agent-page__intro-avatar-name">Nova</span>
|
<span class="agent-page__intro-avatar-name">Nova</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- 标题 -->
|
<!-- 标题 -->
|
||||||
<h2 class="agent-page__intro-title">请先确认你的个人资料是否无误</h2>
|
<h2 class="agent-page__intro-title">请先选择并确认你的投递简历</h2>
|
||||||
<!-- 描述 -->
|
<!-- 描述 -->
|
||||||
<p class="agent-page__intro-desc">请仔细对你的资料评估(包括个人信息、教育背景、工作履历及技能),确保资料齐全</p>
|
<p class="agent-page__intro-desc">请选择智能投递使用的简历,并仔细核对简历内容,确保各项信息准确、完整。</p>
|
||||||
|
<div class="agent-page__step2-filters">
|
||||||
|
<!-- 自定义简历下拉 -->
|
||||||
|
<div class="agent-page__step2-resume-dropdown" @click.stop="showResumeDropdown = !showResumeDropdown">
|
||||||
|
<span class="agent-page__step2-resume-dropdown-text">{{ selectedResumeName || '请选择简历' }}</span>
|
||||||
|
<svg class="agent-page__step2-resume-dropdown-arrow" viewBox="0 0 12 12" fill="none">
|
||||||
|
<path d="M3 4.5L6 7.5L9 4.5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
<!-- 下拉菜单 -->
|
||||||
|
<div v-if="showResumeDropdown" class="agent-page__step2-resume-menu" @click.stop>
|
||||||
|
<div
|
||||||
|
v-for="r in resumeList"
|
||||||
|
:key="r.id"
|
||||||
|
class="agent-page__step2-resume-menu-item"
|
||||||
|
:class="{ 'agent-page__step2-resume-menu-item--active': selectedResumeId === r.id }"
|
||||||
|
@click.stop="selectResume(r)"
|
||||||
|
>{{ r.resumeName }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!-- 按钮 -->
|
<!-- 按钮 -->
|
||||||
<button class="agent-page__intro-gradient-btn" @click="handleNext">下一步</button>
|
<button class="agent-page__intro-gradient-btn" @click="handleNext">下一步</button>
|
||||||
|
|
||||||
@@ -54,7 +73,7 @@
|
|||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- ========== 第2步:确认目标 ========== -->
|
<!-- ========== 第2步:配置投递方案 ========== -->
|
||||||
<template v-if="currentStep === 2">
|
<template v-if="currentStep === 2">
|
||||||
<!-- 左侧:求职偏好 + 简历选择 -->
|
<!-- 左侧:求职偏好 + 简历选择 -->
|
||||||
<div class="agent-page__right">
|
<div class="agent-page__right">
|
||||||
@@ -113,25 +132,28 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 简历选择区域 -->
|
<!-- 投递偏好区域 -->
|
||||||
<div class="agent-page__step2-section">
|
<div class="agent-page__step2-section">
|
||||||
<h3 class="agent-page__step2-section-title">简历选择</h3>
|
<h3 class="agent-page__step2-section-title">投递偏好</h3>
|
||||||
<div class="agent-page__step2-filters">
|
<div class="agent-page__step2-pref-switches">
|
||||||
<!-- 自定义简历下拉 -->
|
<!-- 开启简历针对性优化 -->
|
||||||
<div class="agent-page__step2-resume-dropdown" @click.stop="showResumeDropdown = !showResumeDropdown">
|
<div class="agent-page__step2-switch-item">
|
||||||
<span class="agent-page__step2-resume-dropdown-text">{{ selectedResumeName || '请选择简历' }}</span>
|
<div class="agent-page__step2-switch-text">
|
||||||
<svg class="agent-page__step2-resume-dropdown-arrow" viewBox="0 0 12 12" fill="none">
|
<span class="agent-page__step2-switch-label">开启简历针对性优化</span>
|
||||||
<path d="M3 4.5L6 7.5L9 4.5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
|
<span class="agent-page__step2-switch-desc">结合岗位要求,自动优化简历表达</span>
|
||||||
</svg>
|
</div>
|
||||||
<!-- 下拉菜单 -->
|
<div class="agent-page__step2-toggle" :class="{ 'agent-page__step2-toggle--on': autoOptimizeSwitch }" @click="toggleOptimize">
|
||||||
<div v-if="showResumeDropdown" class="agent-page__step2-resume-menu" @click.stop>
|
<div class="agent-page__step2-toggle-dot"></div>
|
||||||
<div
|
</div>
|
||||||
v-for="r in resumeList"
|
</div>
|
||||||
:key="r.id"
|
<!-- 开启深度人岗匹配分析 -->
|
||||||
class="agent-page__step2-resume-menu-item"
|
<div class="agent-page__step2-switch-item">
|
||||||
:class="{ 'agent-page__step2-resume-menu-item--active': selectedResumeId === r.id }"
|
<div class="agent-page__step2-switch-text">
|
||||||
@click.stop="selectResume(r)"
|
<span class="agent-page__step2-switch-label">开启深度人岗匹配分析</span>
|
||||||
>{{ r.resumeName }}</div>
|
<span class="agent-page__step2-switch-desc">分析你的匹配优势与差距</span>
|
||||||
|
</div>
|
||||||
|
<div class="agent-page__step2-toggle" :class="{ 'agent-page__step2-toggle--on': autoMatchAnalysisSwitch }" @click="toggleMatchAnalysis">
|
||||||
|
<div class="agent-page__step2-toggle-dot"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -176,9 +198,9 @@
|
|||||||
<span class="agent-page__intro-avatar-name">Nova</span>
|
<span class="agent-page__intro-avatar-name">Nova</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- 标题 -->
|
<!-- 标题 -->
|
||||||
<h2 class="agent-page__intro-title">安装浏览器自动投递插件</h2>
|
<h2 class="agent-page__intro-title">请按左侧步骤安装浏览器插件</h2>
|
||||||
<!-- 描述 -->
|
<!-- 描述 -->
|
||||||
<p class="agent-page__intro-desc">按照左侧步骤完成插件安装,即可开启自动投递功能</p>
|
<p class="agent-page__intro-desc">只需4步,完成 Chrome / Edge 插件安装</p>
|
||||||
<!-- 按钮:在线显示下一步,离线显示安装确认按钮 -->
|
<!-- 按钮:在线显示下一步,离线显示安装确认按钮 -->
|
||||||
<button v-if="plugIsOnline" class="agent-page__intro-gradient-btn" @click="handleNext">下一步</button>
|
<button v-if="plugIsOnline" class="agent-page__intro-gradient-btn" @click="handleNext">下一步</button>
|
||||||
<button v-else class="agent-page__intro-gradient-btn" @click="handleInstallConfirm">
|
<button v-else class="agent-page__intro-gradient-btn" @click="handleInstallConfirm">
|
||||||
@@ -234,7 +256,7 @@
|
|||||||
</Teleport>
|
</Teleport>
|
||||||
</div>
|
</div>
|
||||||
<!-- 功能说明 — 独立区块,仅第2步显示 -->
|
<!-- 功能说明 — 独立区块,仅第2步显示 -->
|
||||||
<div v-if="currentStep === 2" class="agent-page__step2-faq mrl24 mt16">
|
<div v-if="currentStep === 2||currentStep === 3" class="agent-page__step2-faq mrl24 mt16">
|
||||||
<h3 class="agent-page__step2-faq-title">功能说明</h3>
|
<h3 class="agent-page__step2-faq-title">功能说明</h3>
|
||||||
<div class="agent-page__step2-faq-item">
|
<div class="agent-page__step2-faq-item">
|
||||||
<div class="agent-page__step2-faq-item-title">为什么要选择求职偏好?</div>
|
<div class="agent-page__step2-faq-item-title">为什么要选择求职偏好?</div>
|
||||||
@@ -267,11 +289,19 @@ import RegionSelector from '@/components/tools/RegionSelector.vue'
|
|||||||
import JobCategorySelector from '@/components/tools/JobCategorySelector.vue'
|
import JobCategorySelector from '@/components/tools/JobCategorySelector.vue'
|
||||||
import IndustrySelector from '@/components/tools/IndustrySelector.vue'
|
import IndustrySelector from '@/components/tools/IndustrySelector.vue'
|
||||||
import AgentBrowserInstallGuide from '@/components/AgentBrowserInstallGuide.vue'
|
import AgentBrowserInstallGuide from '@/components/AgentBrowserInstallGuide.vue'
|
||||||
import { saveProfile, saveEducation, saveWork, saveInternship, saveProject, saveCompetition, fetchProfile, fetchEducation, fetchWork, fetchInternship, fetchProject, fetchCompetition } from '@/api/profile'
|
import { saveProfile, fetchProfile } from '@/api/profile'
|
||||||
import type { SaveEducationItem, SaveWorkItem, SaveProjectItem, SaveCompetitionItem } from '@/api/profile'
|
import {
|
||||||
import { fetchResumeList, setDefaultResume } from '@/api/resume'
|
fetchResumeList, setDefaultResume, fetchResumeMain, saveResumeMain,
|
||||||
|
fetchResumeEducation, fetchResumeWork, fetchResumeInternship, fetchResumeProject, fetchResumeCompetition,
|
||||||
|
addResumeEducation, updateResumeEducation, deleteResumeEducation,
|
||||||
|
addResumeWork, updateResumeWork, deleteResumeWork,
|
||||||
|
addResumeInternship, updateResumeInternship, deleteResumeInternship,
|
||||||
|
addResumeProject, updateResumeProject, deleteResumeProject,
|
||||||
|
addResumeCompetition, updateResumeCompetition, deleteResumeCompetition,
|
||||||
|
} from '@/api/resume'
|
||||||
import type { ResumeListItem } from '@/api/resume'
|
import type { ResumeListItem } from '@/api/resume'
|
||||||
import type { AgentConfig } from '@/api/agent'
|
import type { AgentConfig } from '@/api/agent'
|
||||||
|
import { fetchAgentConfig, saveAgentConfig } from '@/api/agent'
|
||||||
|
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
|
|
||||||
@@ -309,6 +339,10 @@ const editModule = ref('info')
|
|||||||
const editInitialData = ref<Record<string, any>>({})
|
const editInitialData = ref<Record<string, any>>({})
|
||||||
|
|
||||||
// ==================== 个人档案数据 ====================
|
// ==================== 个人档案数据 ====================
|
||||||
|
|
||||||
|
/** 默认简历 ID(从简历列表中确定) */
|
||||||
|
const defaultResumeId = ref('')
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
// 恢复刷新前保存的步骤号
|
// 恢复刷新前保存的步骤号
|
||||||
const savedStep = sessionStorage.getItem('wizardStep')
|
const savedStep = sessionStorage.getItem('wizardStep')
|
||||||
@@ -337,92 +371,160 @@ onMounted(async () => {
|
|||||||
|
|
||||||
if (!store.state.regions.length) store.dispatch('loadCommonData')
|
if (!store.state.regions.length) store.dispatch('loadCommonData')
|
||||||
store.dispatch('loadJobIntention')
|
store.dispatch('loadJobIntention')
|
||||||
|
// 个人信息仍从 /user/profile 获取
|
||||||
await loadProfile()
|
await loadProfile()
|
||||||
await loadEducation()
|
// 其他数据(技能、证书、个人概述、5大经历)从默认简历获取
|
||||||
await loadWork()
|
await loadDefaultResumeData()
|
||||||
await loadInternship()
|
//加载简历列表
|
||||||
await loadProject()
|
loadResumeList()
|
||||||
await loadCompetition()
|
// 加载投递偏好开关状态
|
||||||
|
loadPreferenceSwitches()
|
||||||
})
|
})
|
||||||
|
|
||||||
// ==================== 通信桥接:插件在线状态从 store 全局获取 ====================
|
// ==================== 通信桥接:插件在线状态从 store 全局获取 ====================
|
||||||
/** 插件是否在线(从 vuex 全局状态读取) */
|
/** 插件是否在线(从 vuex 全局状态读取) */
|
||||||
const plugIsOnline = computed(() => store.state.plugIsOnline)
|
const plugIsOnline = computed(() => store.state.plugIsOnline)
|
||||||
|
|
||||||
|
/** 加载个人资料主表 — 仅取 name/email/mobileNumber/regionCode/wechatNumber/portfolioUrl */
|
||||||
async function loadProfile() {
|
async function loadProfile() {
|
||||||
try {
|
try {
|
||||||
const res = await fetchProfile()
|
const res = await fetchProfile()
|
||||||
if (res.code === '0' && res.data) {
|
if (res.code === '0' && res.data) {
|
||||||
const d = res.data
|
const d = res.data
|
||||||
profile.value.name = d.name || ''; profile.value.phone = d.mobileNumber || ''
|
profile.value.name = d.name || ''
|
||||||
profile.value.email = d.email || ''; profile.value.idNumber = d.idCard || ''
|
profile.value.phone = d.mobileNumber || ''
|
||||||
profile.value.regionCode = d.regionCode || ''; profile.value.wechat = d.wechatNumber || ''
|
profile.value.email = d.email || ''
|
||||||
profile.value.skills = d.skills || []; profile.value.certificates = d.certificates || []
|
profile.value.regionCode = d.regionCode || ''
|
||||||
|
profile.value.wechat = d.wechatNumber || ''
|
||||||
profile.value.portfolioUrl = d.portfolioUrl || ''
|
profile.value.portfolioUrl = d.portfolioUrl || ''
|
||||||
}
|
}
|
||||||
} catch { console.error('[AgentSetupWizard] 加载个人资料失败') }
|
} catch { console.error('[AgentSetupWizard] 加载个人资料失败') }
|
||||||
}
|
}
|
||||||
async function loadEducation() {
|
|
||||||
|
/**
|
||||||
|
* 确定默认简历并加载简历主表 + 5大经历
|
||||||
|
* 规则:优先 isDefault===1 的简历,否则取 createTime 最新的
|
||||||
|
*/
|
||||||
|
async function loadDefaultResumeData() {
|
||||||
try {
|
try {
|
||||||
const res = await fetchEducation()
|
const listRes = await fetchResumeList()
|
||||||
if (res.code === '0' && res.data) {
|
if (listRes.code !== '0' || !listRes.data || listRes.data.length === 0) {
|
||||||
profile.value.education = res.data.map(item => ({ school: item.school || '', major: item.major || '', studyType: item.studyType ?? 0, degree: item.degree ?? 2, startDate: item.startDate || '', endDate: item.endDate || '', description: (item.description || []).map(d => ({ id: d.id || '', text: d.text || '' })) }))
|
console.warn('[AgentSetupWizard] 无简历数据')
|
||||||
|
return
|
||||||
}
|
}
|
||||||
} catch { console.error('[AgentSetupWizard] 加载教育经历失败') }
|
const list = listRes.data
|
||||||
|
// 确定默认简历
|
||||||
|
let target = list.find(r => r.isDefault === 1)
|
||||||
|
if (!target) {
|
||||||
|
// 按 createTime 降序取第一个
|
||||||
|
target = [...list].sort((a, b) => (b.createTime || 0) - (a.createTime || 0))[0]
|
||||||
}
|
}
|
||||||
async function loadWork() {
|
if (!target || !target.id) return
|
||||||
try {
|
defaultResumeId.value = target.id
|
||||||
const res = await fetchWork()
|
|
||||||
if (res.code === '0' && res.data) {
|
// 并发加载简历主表 + 5大经历
|
||||||
profile.value.works = res.data.map(item => ({ companyName: item.companyName || '', position: item.position || '', startDate: item.startDate || '', endDate: item.endDate || '', description: (item.description || []).map(d => ({ id: d.id || '', text: d.text || '' })) }))
|
const [mainRes, eduRes, workRes, internRes, projRes, compRes] = await Promise.all([
|
||||||
|
fetchResumeMain(defaultResumeId.value),
|
||||||
|
fetchResumeEducation(defaultResumeId.value),
|
||||||
|
fetchResumeWork(defaultResumeId.value),
|
||||||
|
fetchResumeInternship(defaultResumeId.value),
|
||||||
|
fetchResumeProject(defaultResumeId.value),
|
||||||
|
fetchResumeCompetition(defaultResumeId.value),
|
||||||
|
])
|
||||||
|
|
||||||
|
// 从简历主表获取技能、证书、个人概述
|
||||||
|
if (mainRes.code === '0' && mainRes.data) {
|
||||||
|
profile.value.skills = mainRes.data.skills || []
|
||||||
|
profile.value.certificates = mainRes.data.certificates || []
|
||||||
|
profile.value.summary = mainRes.data.summary || ''
|
||||||
}
|
}
|
||||||
} catch { console.error('[AgentSetupWizard] 加载工作经历失败') }
|
// 教育经历
|
||||||
|
if (eduRes.code === '0' && eduRes.data) {
|
||||||
|
profile.value.education = eduRes.data.map(item => ({
|
||||||
|
id: item.id || '',
|
||||||
|
school: item.school || '', major: item.major || '',
|
||||||
|
studyType: item.studyType || '',
|
||||||
|
degree: item.degree || '',
|
||||||
|
startDate: item.startDate || '', endDate: item.endDate || '',
|
||||||
|
description: (item.description || []).map(d => ({ id: d.id || '', text: d.text || '' })),
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
async function loadInternship() {
|
// 工作经历
|
||||||
try {
|
if (workRes.code === '0' && workRes.data) {
|
||||||
const res = await fetchInternship()
|
profile.value.works = workRes.data.map(item => ({
|
||||||
if (res.code === '0' && res.data) {
|
id: item.id || '',
|
||||||
profile.value.internships = res.data.map(item => ({ companyName: item.companyName || '', position: item.position || '', startDate: item.startDate || '', endDate: item.endDate || '', description: (item.description || []).map(d => ({ id: d.id || '', text: d.text || '' })) }))
|
companyName: item.companyName || '', position: item.position || '',
|
||||||
|
startDate: item.startDate || '', endDate: item.endDate || '',
|
||||||
|
description: (item.description || []).map(d => ({ id: d.id || '', text: d.text || '' })),
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
} catch { console.error('[AgentSetupWizard] 加载实习经历失败') }
|
// 实习经历
|
||||||
|
if (internRes.code === '0' && internRes.data) {
|
||||||
|
profile.value.internships = internRes.data.map(item => ({
|
||||||
|
id: item.id || '',
|
||||||
|
companyName: item.companyName || '', position: item.position || '',
|
||||||
|
startDate: item.startDate || '', endDate: item.endDate || '',
|
||||||
|
description: (item.description || []).map(d => ({ id: d.id || '', text: d.text || '' })),
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
async function loadProject() {
|
// 项目经历
|
||||||
try {
|
if (projRes.code === '0' && projRes.data) {
|
||||||
const res = await fetchProject()
|
profile.value.projects = projRes.data.map(item => ({
|
||||||
if (res.code === '0' && res.data) {
|
id: item.id || '',
|
||||||
profile.value.projects = res.data.map(item => ({ projectName: item.projectName || '', companyName: item.companyName || '', role: item.role || '', startDate: item.startDate || '', endDate: item.endDate || '', description: (item.description || []).map(d => ({ id: d.id || '', text: d.text || '' })) }))
|
projectName: item.projectName || '', companyName: item.companyName || '',
|
||||||
|
role: item.role || '', startDate: item.startDate || '', endDate: item.endDate || '',
|
||||||
|
description: (item.description || []).map(d => ({ id: d.id || '', text: d.text || '' })),
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
} catch { console.error('[AgentSetupWizard] 加载项目经历失败') }
|
// 竞赛经历
|
||||||
|
if (compRes.code === '0' && compRes.data) {
|
||||||
|
profile.value.competitions = compRes.data.map(item => ({
|
||||||
|
id: item.id || '',
|
||||||
|
competitionName: item.competitionName || '', award: item.award || '',
|
||||||
|
awardDate: item.awardDate || '',
|
||||||
|
description: (item.description || []).map(d => ({ id: d.id || '', text: d.text || '' })),
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
async function loadCompetition() {
|
} catch { console.error('[AgentSetupWizard] 加载默认简历数据失败') }
|
||||||
try {
|
|
||||||
const res = await fetchCompetition()
|
|
||||||
if (res.code === '0' && res.data) {
|
|
||||||
profile.value.competitions = res.data.map(item => ({ competitionName: item.competitionName || '', award: item.award || '', awardDate: item.awardDate || '', description: (item.description || []).map(d => ({ id: d.id || '', text: d.text || '' })) }))
|
|
||||||
}
|
|
||||||
} catch { console.error('[AgentSetupWizard] 加载竞赛经历失败') }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const profile = ref({
|
const profile = ref({
|
||||||
name: '', phone: '', email: '', idNumber: '', regionCode: '', portfolioUrl: '', wechat: '',
|
name: '', phone: '', email: '', idNumber: '', regionCode: '', portfolioUrl: '', wechat: '',
|
||||||
skills: [] as string[], certificates: [] as string[],
|
skills: [] as string[], certificates: [] as string[], summary: '',
|
||||||
education: [] as Array<{ school: string; major: string; studyType: number; degree: number; startDate: string; endDate: string; description: Array<{ id: string; text: string }> }>,
|
education: [] as Array<{ id: string; school: string; major: string; studyType: string | number; degree: string | number; startDate: string; endDate: string; description: Array<{ id: string; text: string }> }>,
|
||||||
works: [] as Array<{ companyName: string; position: string; startDate: string; endDate: string; description: Array<{ id: string; text: string }> }>,
|
works: [] as Array<{ id: string; companyName: string; position: string; startDate: string; endDate: string; description: Array<{ id: string; text: string }> }>,
|
||||||
internships: [] as Array<{ companyName: string; position: string; startDate: string; endDate: string; description: Array<{ id: string; text: string }> }>,
|
internships: [] as Array<{ id: string; companyName: string; position: string; startDate: string; endDate: string; description: Array<{ id: string; text: string }> }>,
|
||||||
projects: [] as Array<{ projectName: string; companyName: string; role: string; startDate: string; endDate: string; description: Array<{ id: string; text: string }> }>,
|
projects: [] as Array<{ id: string; projectName: string; companyName: string; role: string; startDate: string; endDate: string; description: Array<{ id: string; text: string }> }>,
|
||||||
competitions: [] as Array<{ competitionName: string; award: string; awardDate: string; description: Array<{ id: string; text: string }> }>,
|
competitions: [] as Array<{ id: string; competitionName: string; award: string; awardDate: string; description: Array<{ id: string; text: string }> }>,
|
||||||
})
|
})
|
||||||
|
|
||||||
// ==================== 编辑抽屉事件处理 ====================
|
// ==================== 编辑抽屉事件处理 ====================
|
||||||
function handleEdit(section: string) {
|
function handleEdit(section: string) {
|
||||||
editModule.value = section
|
editModule.value = section
|
||||||
if (section === 'info') { editInitialData.value = { name: profile.value.name, email: profile.value.email, phone: profile.value.phone, location: profile.value.regionCode, wechat: profile.value.wechat } }
|
if (section === 'info') { editInitialData.value = { name: profile.value.name, email: profile.value.email, phone: profile.value.phone, location: profile.value.regionCode, wechat: profile.value.wechat } }
|
||||||
else if (section === 'education') { editInitialData.value = { education: profile.value.education.map(edu => ({ ...edu, description: edu.description.map(d => ({ ...d })) })) } }
|
else if (section === 'education') {
|
||||||
else if (section === 'work') { editInitialData.value = { works: profile.value.works.map(exp => ({ ...exp, description: exp.description.map(d => ({ ...d })) })) } }
|
// 记录当前教育经历ID快照,用于保存时做diff
|
||||||
else if (section === 'internship') { editInitialData.value = { internships: (profile.value.internships || []).map(exp => ({ ...exp, description: exp.description.map(d => ({ ...d })) })) } }
|
editSnapshotEducationIds.value = profile.value.education.map(e => e.id).filter(Boolean)
|
||||||
else if (section === 'project') { editInitialData.value = { projects: (profile.value.projects || []).map(proj => ({ ...proj, description: proj.description.map(d => ({ ...d })) })) } }
|
editInitialData.value = { education: profile.value.education.map(edu => ({ ...edu, description: edu.description.map(d => ({ ...d })) })) }
|
||||||
else if (section === 'competition') { editInitialData.value = { competitions: profile.value.competitions.map(comp => ({ ...comp, description: comp.description.map(d => ({ ...d })) })) } }
|
}
|
||||||
|
else if (section === 'work') {
|
||||||
|
editSnapshotWorkIds.value = profile.value.works.map(w => w.id).filter(Boolean)
|
||||||
|
editInitialData.value = { works: profile.value.works.map(exp => ({ ...exp, description: exp.description.map(d => ({ ...d })) })) }
|
||||||
|
}
|
||||||
|
else if (section === 'internship') {
|
||||||
|
editSnapshotInternshipIds.value = profile.value.internships.map(i => i.id).filter(Boolean)
|
||||||
|
editInitialData.value = { internships: (profile.value.internships || []).map(exp => ({ ...exp, description: exp.description.map(d => ({ ...d })) })) }
|
||||||
|
}
|
||||||
|
else if (section === 'project') {
|
||||||
|
editSnapshotProjectIds.value = profile.value.projects.map(p => p.id).filter(Boolean)
|
||||||
|
editInitialData.value = { projects: (profile.value.projects || []).map(proj => ({ ...proj, description: proj.description.map(d => ({ ...d })) })) }
|
||||||
|
}
|
||||||
|
else if (section === 'competition') {
|
||||||
|
editSnapshotCompetitionIds.value = profile.value.competitions.map(c => c.id).filter(Boolean)
|
||||||
|
editInitialData.value = { competitions: profile.value.competitions.map(comp => ({ ...comp, description: comp.description.map(d => ({ ...d })) })) }
|
||||||
|
}
|
||||||
else if (section === 'portfolio') { editInitialData.value = { portfolioUrl: profile.value.portfolioUrl } }
|
else if (section === 'portfolio') { editInitialData.value = { portfolioUrl: profile.value.portfolioUrl } }
|
||||||
|
else if (section === 'summary') { editInitialData.value = { summary: profile.value.summary || '' } }
|
||||||
else if (section === 'skills') { editInitialData.value = { skills: [...profile.value.skills] } }
|
else if (section === 'skills') { editInitialData.value = { skills: [...profile.value.skills] } }
|
||||||
else if (section === 'certificate') { editInitialData.value = { certificates: [...(profile.value.certificates || [])] } }
|
else if (section === 'certificate') { editInitialData.value = { certificates: [...(profile.value.certificates || [])] } }
|
||||||
else { editInitialData.value = {} }
|
else { editInitialData.value = {} }
|
||||||
@@ -432,58 +534,226 @@ function handleEdit(section: string) {
|
|||||||
/** 保存中的加载状态 */
|
/** 保存中的加载状态 */
|
||||||
const saving = ref(false)
|
const saving = ref(false)
|
||||||
|
|
||||||
/** 保存编辑数据 — 调用接口持久化 */
|
/** 保存编辑数据 — 个人信息走 profile 接口,其余走简历接口 */
|
||||||
async function handleSaveEdit(data: Record<string, any>) {
|
async function handleSaveEdit(data: Record<string, any>) {
|
||||||
if (editModule.value === 'info') {
|
if (editModule.value === 'info') {
|
||||||
try { saving.value = true; await saveProfile({ name: data.name, email: data.email, mobileNumber: data.phone, regionCode: data.location, wechatNumber: data.wechat }); profile.value.name = data.name; profile.value.email = data.email; profile.value.phone = data.phone; profile.value.wechat = data.wechat; profile.value.regionCode = data.location || ''; ElMessage.success('个人信息保存成功') } catch { ElMessage.error('个人信息保存失败,请重试') } finally { saving.value = false }
|
// 个人信息 — 保存到 /user/profile
|
||||||
|
try {
|
||||||
|
saving.value = true
|
||||||
|
await saveProfile({ name: data.name, email: data.email, mobileNumber: data.phone, regionCode: data.location, wechatNumber: data.wechat })
|
||||||
|
profile.value.name = data.name; profile.value.email = data.email
|
||||||
|
profile.value.phone = data.phone; profile.value.wechat = data.wechat
|
||||||
|
profile.value.regionCode = data.location || ''
|
||||||
|
ElMessage.success('个人信息保存成功')
|
||||||
|
} catch { ElMessage.error('个人信息保存失败,请重试') } finally { saving.value = false }
|
||||||
} else if (editModule.value === 'education') {
|
} else if (editModule.value === 'education') {
|
||||||
try { saving.value = true; const payload: SaveEducationItem[] = data.education.map((edu: any) => ({ school: edu.school, major: edu.major, degree: edu.degree, studyType: edu.studyType, startDate: edu.startDate, endDate: edu.endDate, description: edu.description.map((d: any) => ({ id: d.id, text: d.text })) })); await saveEducation(payload); profile.value.education = data.education.map((edu: any) => ({ school: edu.school, major: edu.major, studyType: edu.studyType, degree: edu.degree, startDate: edu.startDate, endDate: edu.endDate, description: edu.description.map((d: any) => ({ ...d })) })); ElMessage.success('教育经历保存成功') } catch { ElMessage.error('教育经历保存失败,请重试') } finally { saving.value = false }
|
// 教育经历 — diff增删改(简历接口)
|
||||||
|
if (!defaultResumeId.value) { ElMessage.error('未找到默认简历'); return }
|
||||||
|
try {
|
||||||
|
saving.value = true
|
||||||
|
const oldIds = new Set(editSnapshotEducationIds.value)
|
||||||
|
const newItems: any[] = data.education
|
||||||
|
const newIds = new Set(newItems.filter((e: any) => e.id).map((e: any) => e.id))
|
||||||
|
const deletedIds = editSnapshotEducationIds.value.filter(id => !newIds.has(id))
|
||||||
|
const addPromises: Promise<any>[] = []
|
||||||
|
const updatePromises: Promise<any>[] = []
|
||||||
|
const deletePromises = deletedIds.map(id => deleteResumeEducation(id))
|
||||||
|
for (const edu of newItems) {
|
||||||
|
const itemData = { school: edu.school, major: edu.major, degree: edu.degree, studyType: edu.studyType, startDate: edu.startDate, endDate: edu.endDate, description: edu.description }
|
||||||
|
if (edu.id && oldIds.has(edu.id)) {
|
||||||
|
updatePromises.push(updateResumeEducation({ ...itemData, id: edu.id }))
|
||||||
|
} else {
|
||||||
|
addPromises.push(addResumeEducation(defaultResumeId.value, itemData))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await Promise.all([...addPromises, ...updatePromises, ...deletePromises])
|
||||||
|
// 重新加载教育经历以获取最新ID
|
||||||
|
const eduRes = await fetchResumeEducation(defaultResumeId.value)
|
||||||
|
if (eduRes.code === '0' && eduRes.data) {
|
||||||
|
profile.value.education = eduRes.data.map(item => ({ id: item.id || '', school: item.school || '', major: item.major || '', studyType: item.studyType || '', degree: item.degree || '', startDate: item.startDate || '', endDate: item.endDate || '', description: (item.description || []).map(d => ({ id: d.id || '', text: d.text || '' })) }))
|
||||||
|
}
|
||||||
|
ElMessage.success('教育经历保存成功')
|
||||||
|
} catch { ElMessage.error('教育经历保存失败,请重试') } finally { saving.value = false }
|
||||||
} else if (editModule.value === 'work') {
|
} else if (editModule.value === 'work') {
|
||||||
try { saving.value = true; const payload: SaveWorkItem[] = data.works.map((w: any) => ({ companyName: w.companyName, position: w.position, startDate: w.startDate, endDate: w.endDate || '', description: w.description.map((d: any) => ({ id: d.id, text: d.text })) })); await saveWork(payload); profile.value.works = data.works.map((w: any) => ({ companyName: w.companyName, position: w.position, startDate: w.startDate, endDate: w.endDate, description: w.description.map((d: any) => ({ ...d })) })); ElMessage.success('工作经历保存成功') } catch { ElMessage.error('工作经历保存失败,请重试') } finally { saving.value = false }
|
// 工作经历 — diff增删改(简历接口)
|
||||||
|
if (!defaultResumeId.value) { ElMessage.error('未找到默认简历'); return }
|
||||||
|
try {
|
||||||
|
saving.value = true
|
||||||
|
const oldIds = new Set(editSnapshotWorkIds.value)
|
||||||
|
const newItems: any[] = data.works
|
||||||
|
const newIds = new Set(newItems.filter((w: any) => w.id).map((w: any) => w.id))
|
||||||
|
const deletedIds = editSnapshotWorkIds.value.filter(id => !newIds.has(id))
|
||||||
|
const addPromises: Promise<any>[] = []
|
||||||
|
const updatePromises: Promise<any>[] = []
|
||||||
|
const deletePromises = deletedIds.map(id => deleteResumeWork(id))
|
||||||
|
for (const w of newItems) {
|
||||||
|
const itemData = { companyName: w.companyName, position: w.position, startDate: w.startDate, endDate: w.endDate || '', description: w.description }
|
||||||
|
if (w.id && oldIds.has(w.id)) {
|
||||||
|
updatePromises.push(updateResumeWork({ ...itemData, id: w.id }))
|
||||||
|
} else {
|
||||||
|
addPromises.push(addResumeWork(defaultResumeId.value, itemData))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await Promise.all([...addPromises, ...updatePromises, ...deletePromises])
|
||||||
|
const workRes = await fetchResumeWork(defaultResumeId.value)
|
||||||
|
if (workRes.code === '0' && workRes.data) {
|
||||||
|
profile.value.works = workRes.data.map(item => ({ id: item.id || '', companyName: item.companyName || '', position: item.position || '', startDate: item.startDate || '', endDate: item.endDate || '', description: (item.description || []).map(d => ({ id: d.id || '', text: d.text || '' })) }))
|
||||||
|
}
|
||||||
|
ElMessage.success('工作经历保存成功')
|
||||||
|
} catch { ElMessage.error('工作经历保存失败,请重试') } finally { saving.value = false }
|
||||||
} else if (editModule.value === 'internship') {
|
} else if (editModule.value === 'internship') {
|
||||||
try { saving.value = true; const payload: SaveWorkItem[] = data.internships.map((i: any) => ({ companyName: i.companyName, position: i.position, startDate: i.startDate, endDate: i.endDate || '', description: i.description.map((d: any) => ({ id: d.id, text: d.text })) })); await saveInternship(payload); profile.value.internships = data.internships.map((i: any) => ({ companyName: i.companyName, position: i.position, startDate: i.startDate, endDate: i.endDate, description: i.description.map((d: any) => ({ ...d })) })); ElMessage.success('实习经历保存成功') } catch { ElMessage.error('实习经历保存失败,请重试') } finally { saving.value = false }
|
// 实习经历 — diff增删改(简历接口)
|
||||||
|
if (!defaultResumeId.value) { ElMessage.error('未找到默认简历'); return }
|
||||||
|
try {
|
||||||
|
saving.value = true
|
||||||
|
const oldIds = new Set(editSnapshotInternshipIds.value)
|
||||||
|
const newItems: any[] = data.internships
|
||||||
|
const newIds = new Set(newItems.filter((i: any) => i.id).map((i: any) => i.id))
|
||||||
|
const deletedIds = editSnapshotInternshipIds.value.filter(id => !newIds.has(id))
|
||||||
|
const addPromises: Promise<any>[] = []
|
||||||
|
const updatePromises: Promise<any>[] = []
|
||||||
|
const deletePromises = deletedIds.map(id => deleteResumeInternship(id))
|
||||||
|
for (const i of newItems) {
|
||||||
|
const itemData = { companyName: i.companyName, position: i.position, startDate: i.startDate, endDate: i.endDate || '', description: i.description }
|
||||||
|
if (i.id && oldIds.has(i.id)) {
|
||||||
|
updatePromises.push(updateResumeInternship({ ...itemData, id: i.id }))
|
||||||
|
} else {
|
||||||
|
addPromises.push(addResumeInternship(defaultResumeId.value, itemData))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await Promise.all([...addPromises, ...updatePromises, ...deletePromises])
|
||||||
|
const internRes = await fetchResumeInternship(defaultResumeId.value)
|
||||||
|
if (internRes.code === '0' && internRes.data) {
|
||||||
|
profile.value.internships = internRes.data.map(item => ({ id: item.id || '', companyName: item.companyName || '', position: item.position || '', startDate: item.startDate || '', endDate: item.endDate || '', description: (item.description || []).map(d => ({ id: d.id || '', text: d.text || '' })) }))
|
||||||
|
}
|
||||||
|
ElMessage.success('实习经历保存成功')
|
||||||
|
} catch { ElMessage.error('实习经历保存失败,请重试') } finally { saving.value = false }
|
||||||
} else if (editModule.value === 'project') {
|
} else if (editModule.value === 'project') {
|
||||||
try { saving.value = true; const payload: SaveProjectItem[] = data.projects.map((p: any) => ({ projectName: p.projectName, companyName: p.companyName || '', role: p.role || '', startDate: p.startDate, endDate: p.endDate || '', description: p.description.map((d: any) => ({ id: d.id, text: d.text })) })); await saveProject(payload); profile.value.projects = data.projects.map((p: any) => ({ projectName: p.projectName, companyName: p.companyName, role: p.role, startDate: p.startDate, endDate: p.endDate, description: p.description.map((d: any) => ({ ...d })) })); ElMessage.success('项目经历保存成功') } catch { ElMessage.error('项目经历保存失败,请重试') } finally { saving.value = false }
|
// 项目经历 — diff增删改(简历接口)
|
||||||
|
if (!defaultResumeId.value) { ElMessage.error('未找到默认简历'); return }
|
||||||
|
try {
|
||||||
|
saving.value = true
|
||||||
|
const oldIds = new Set(editSnapshotProjectIds.value)
|
||||||
|
const newItems: any[] = data.projects
|
||||||
|
const newIds = new Set(newItems.filter((p: any) => p.id).map((p: any) => p.id))
|
||||||
|
const deletedIds = editSnapshotProjectIds.value.filter(id => !newIds.has(id))
|
||||||
|
const addPromises: Promise<any>[] = []
|
||||||
|
const updatePromises: Promise<any>[] = []
|
||||||
|
const deletePromises = deletedIds.map(id => deleteResumeProject(id))
|
||||||
|
for (const p of newItems) {
|
||||||
|
const itemData = { projectName: p.projectName, companyName: p.companyName || '', role: p.role || '', startDate: p.startDate, endDate: p.endDate || '', description: p.description }
|
||||||
|
if (p.id && oldIds.has(p.id)) {
|
||||||
|
updatePromises.push(updateResumeProject({ ...itemData, id: p.id }))
|
||||||
|
} else {
|
||||||
|
addPromises.push(addResumeProject(defaultResumeId.value, itemData))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await Promise.all([...addPromises, ...updatePromises, ...deletePromises])
|
||||||
|
const projRes = await fetchResumeProject(defaultResumeId.value)
|
||||||
|
if (projRes.code === '0' && projRes.data) {
|
||||||
|
profile.value.projects = projRes.data.map(item => ({ id: item.id || '', projectName: item.projectName || '', companyName: item.companyName || '', role: item.role || '', startDate: item.startDate || '', endDate: item.endDate || '', description: (item.description || []).map(d => ({ id: d.id || '', text: d.text || '' })) }))
|
||||||
|
}
|
||||||
|
ElMessage.success('项目经历保存成功')
|
||||||
|
} catch { ElMessage.error('项目经历保存失败,请重试') } finally { saving.value = false }
|
||||||
} else if (editModule.value === 'competition') {
|
} else if (editModule.value === 'competition') {
|
||||||
try { saving.value = true; const payload: SaveCompetitionItem[] = data.competitions.map((c: any) => ({ competitionName: c.competitionName, award: c.award || '', awardDate: c.awardDate || '', description: c.description.map((d: any) => ({ id: d.id, text: d.text })) })); await saveCompetition(payload); profile.value.competitions = data.competitions.map((c: any) => ({ competitionName: c.competitionName, award: c.award, awardDate: c.awardDate, description: c.description.map((d: any) => ({ ...d })) })); ElMessage.success('竞赛经历保存成功') } catch { ElMessage.error('竞赛经历保存失败,请重试') } finally { saving.value = false }
|
// 竞赛经历 — diff增删改(简历接口)
|
||||||
|
if (!defaultResumeId.value) { ElMessage.error('未找到默认简历'); return }
|
||||||
|
try {
|
||||||
|
saving.value = true
|
||||||
|
const oldIds = new Set(editSnapshotCompetitionIds.value)
|
||||||
|
const newItems: any[] = data.competitions
|
||||||
|
const newIds = new Set(newItems.filter((c: any) => c.id).map((c: any) => c.id))
|
||||||
|
const deletedIds = editSnapshotCompetitionIds.value.filter(id => !newIds.has(id))
|
||||||
|
const addPromises: Promise<any>[] = []
|
||||||
|
const updatePromises: Promise<any>[] = []
|
||||||
|
const deletePromises = deletedIds.map(id => deleteResumeCompetition(id))
|
||||||
|
for (const c of newItems) {
|
||||||
|
const itemData = { competitionName: c.competitionName, award: c.award || '', awardDate: c.awardDate || '', description: c.description }
|
||||||
|
if (c.id && oldIds.has(c.id)) {
|
||||||
|
updatePromises.push(updateResumeCompetition({ ...itemData, id: c.id }))
|
||||||
|
} else {
|
||||||
|
addPromises.push(addResumeCompetition(defaultResumeId.value, itemData))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await Promise.all([...addPromises, ...updatePromises, ...deletePromises])
|
||||||
|
const compRes = await fetchResumeCompetition(defaultResumeId.value)
|
||||||
|
if (compRes.code === '0' && compRes.data) {
|
||||||
|
profile.value.competitions = compRes.data.map(item => ({ id: item.id || '', competitionName: item.competitionName || '', award: item.award || '', awardDate: item.awardDate || '', description: (item.description || []).map(d => ({ id: d.id || '', text: d.text || '' })) }))
|
||||||
|
}
|
||||||
|
ElMessage.success('竞赛经历保存成功')
|
||||||
|
} catch { ElMessage.error('竞赛经历保存失败,请重试') } finally { saving.value = false }
|
||||||
|
} else if (editModule.value === 'summary') {
|
||||||
|
// 个人概述 — 保存到简历主表
|
||||||
|
if (!defaultResumeId.value) { ElMessage.error('未找到默认简历'); return }
|
||||||
|
try {
|
||||||
|
saving.value = true
|
||||||
|
await saveResumeMain({ resumeId: defaultResumeId.value, skills: profile.value.skills, certificates: profile.value.certificates, summary: data.summary })
|
||||||
|
profile.value.summary = data.summary
|
||||||
|
ElMessage.success('个人概述保存成功')
|
||||||
|
} catch { ElMessage.error('个人概述保存失败,请重试') } finally { saving.value = false }
|
||||||
} else if (editModule.value === 'portfolio') {
|
} else if (editModule.value === 'portfolio') {
|
||||||
try { saving.value = true; await saveProfile({ name: profile.value.name, email: profile.value.email, mobileNumber: profile.value.phone, regionCode: profile.value.regionCode, wechatNumber: profile.value.wechat, skills: profile.value.skills, certificates: profile.value.certificates, portfolioUrl: data.portfolioUrl }); profile.value.portfolioUrl = data.portfolioUrl; ElMessage.success('作品集保存成功') } catch { ElMessage.error('作品集保存失败,请重试') } finally { saving.value = false }
|
// 作品集链接 — 保存到 /user/profile
|
||||||
|
try {
|
||||||
|
saving.value = true
|
||||||
|
await saveProfile({ name: profile.value.name, email: profile.value.email, mobileNumber: profile.value.phone, regionCode: profile.value.regionCode, wechatNumber: profile.value.wechat, portfolioUrl: data.portfolioUrl })
|
||||||
|
profile.value.portfolioUrl = data.portfolioUrl
|
||||||
|
ElMessage.success('作品集保存成功')
|
||||||
|
} catch { ElMessage.error('作品集保存失败,请重试') } finally { saving.value = false }
|
||||||
} else if (editModule.value === 'skills') {
|
} else if (editModule.value === 'skills') {
|
||||||
try { saving.value = true; await saveProfile({ name: profile.value.name, email: profile.value.email, mobileNumber: profile.value.phone, regionCode: profile.value.regionCode, wechatNumber: profile.value.wechat, skills: [...data.skills], certificates: profile.value.certificates }); profile.value.skills = [...data.skills]; ElMessage.success('技能保存成功') } catch { ElMessage.error('技能保存失败,请重试') } finally { saving.value = false }
|
// 技能 — 保存到简历主表
|
||||||
|
if (!defaultResumeId.value) { ElMessage.error('未找到默认简历'); return }
|
||||||
|
try {
|
||||||
|
saving.value = true
|
||||||
|
await saveResumeMain({ resumeId: defaultResumeId.value, skills: [...data.skills], certificates: profile.value.certificates, summary: profile.value.summary })
|
||||||
|
profile.value.skills = [...data.skills]
|
||||||
|
ElMessage.success('技能保存成功')
|
||||||
|
} catch { ElMessage.error('技能保存失败,请重试') } finally { saving.value = false }
|
||||||
} else if (editModule.value === 'certificate') {
|
} else if (editModule.value === 'certificate') {
|
||||||
try { saving.value = true; await saveProfile({ name: profile.value.name, email: profile.value.email, mobileNumber: profile.value.phone, regionCode: profile.value.regionCode, wechatNumber: profile.value.wechat, skills: profile.value.skills, certificates: [...data.certificates] }); profile.value.certificates = [...data.certificates]; ElMessage.success('证书保存成功') } catch { ElMessage.error('证书保存失败,请重试') } finally { saving.value = false }
|
// 证书 — 保存到简历主表
|
||||||
|
if (!defaultResumeId.value) { ElMessage.error('未找到默认简历'); return }
|
||||||
|
try {
|
||||||
|
saving.value = true
|
||||||
|
await saveResumeMain({ resumeId: defaultResumeId.value, skills: profile.value.skills, certificates: [...data.certificates], summary: profile.value.summary })
|
||||||
|
profile.value.certificates = [...data.certificates]
|
||||||
|
ElMessage.success('证书保存成功')
|
||||||
|
} catch { ElMessage.error('证书保存失败,请重试') } finally { saving.value = false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 编辑抽屉打开时的经历ID快照 — 用于保存时做增删改diff */
|
||||||
|
const editSnapshotEducationIds = ref<string[]>([])
|
||||||
|
const editSnapshotWorkIds = ref<string[]>([])
|
||||||
|
const editSnapshotInternshipIds = ref<string[]>([])
|
||||||
|
const editSnapshotProjectIds = ref<string[]>([])
|
||||||
|
const editSnapshotCompetitionIds = ref<string[]>([])
|
||||||
|
|
||||||
/** 内联保存处理(个人信息/技能/证书模块从组件内直接保存) */
|
/** 内联保存处理(个人信息/技能/证书模块从组件内直接保存) */
|
||||||
async function handleInlineSave(section: string, data: Record<string, any>) {
|
async function handleInlineSave(section: string, data: Record<string, any>) {
|
||||||
editModule.value = section
|
editModule.value = section
|
||||||
await handleSaveEdit(data)
|
await handleSaveEdit(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 单条经历更新 — 替换到完整列表后整体保存 */
|
/** 单条经历更新 — 调用简历单条编辑接口 */
|
||||||
async function handleExpUpdate(moduleType: string, index: number, data: Record<string, any>) {
|
async function handleExpUpdate(moduleType: string, index: number, data: Record<string, any>) {
|
||||||
|
if (!defaultResumeId.value) { ElMessage.error('未找到默认简历'); return }
|
||||||
try {
|
try {
|
||||||
|
const record = (profile.value as any)[moduleType === 'work' ? 'works' : moduleType === 'internship' ? 'internships' : moduleType === 'project' ? 'projects' : moduleType === 'competition' ? 'competitions' : 'education'][index]
|
||||||
|
const recordId = record?.id
|
||||||
if (moduleType === 'education') {
|
if (moduleType === 'education') {
|
||||||
const list = profile.value.education.map((item, i) => i === index ? data : item) as any[]
|
await updateResumeEducation({ id: recordId, school: data.school, major: data.major, degree: data.degree, studyType: data.studyType, startDate: data.startDate, endDate: data.endDate, description: data.description })
|
||||||
await saveEducation(list)
|
profile.value.education[index] = { id: recordId, ...data } as any
|
||||||
profile.value.education = list
|
|
||||||
} else if (moduleType === 'work') {
|
} else if (moduleType === 'work') {
|
||||||
const list = profile.value.works.map((item, i) => i === index ? data : item) as any[]
|
await updateResumeWork({ id: recordId, companyName: data.companyName, position: data.position, startDate: data.startDate, endDate: data.endDate, description: data.description })
|
||||||
await saveWork(list)
|
profile.value.works[index] = { id: recordId, ...data } as any
|
||||||
profile.value.works = list
|
|
||||||
} else if (moduleType === 'internship') {
|
} else if (moduleType === 'internship') {
|
||||||
const list = profile.value.internships.map((item, i) => i === index ? data : item) as any[]
|
await updateResumeInternship({ id: recordId, companyName: data.companyName, position: data.position, startDate: data.startDate, endDate: data.endDate, description: data.description })
|
||||||
await saveInternship(list)
|
profile.value.internships[index] = { id: recordId, ...data } as any
|
||||||
profile.value.internships = list
|
|
||||||
} else if (moduleType === 'project') {
|
} else if (moduleType === 'project') {
|
||||||
const list = profile.value.projects.map((item, i) => i === index ? data : item) as any[]
|
await updateResumeProject({ id: recordId, projectName: data.projectName, companyName: data.companyName, role: data.role, startDate: data.startDate, endDate: data.endDate, description: data.description })
|
||||||
await saveProject(list)
|
profile.value.projects[index] = { id: recordId, ...data } as any
|
||||||
profile.value.projects = list
|
|
||||||
} else if (moduleType === 'competition') {
|
} else if (moduleType === 'competition') {
|
||||||
const list = profile.value.competitions.map((item, i) => i === index ? data : item) as any[]
|
await updateResumeCompetition({ id: recordId, competitionName: data.competitionName, award: data.award, awardDate: data.awardDate, description: data.description })
|
||||||
await saveCompetition(list)
|
profile.value.competitions[index] = { id: recordId, ...data } as any
|
||||||
profile.value.competitions = list
|
|
||||||
}
|
}
|
||||||
ElMessage.success('保存成功')
|
ElMessage.success('保存成功')
|
||||||
} catch {
|
} catch {
|
||||||
@@ -491,29 +761,31 @@ async function handleExpUpdate(moduleType: string, index: number, data: Record<s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 新增经历 */
|
/** 新增经历 — 调用简历单条添加接口 */
|
||||||
async function handleExpAdd(moduleType: string, data: Record<string, any>) {
|
async function handleExpAdd(moduleType: string, data: Record<string, any>) {
|
||||||
|
if (!defaultResumeId.value) { ElMessage.error('未找到默认简历'); return }
|
||||||
try {
|
try {
|
||||||
|
let newId = ''
|
||||||
if (moduleType === 'education') {
|
if (moduleType === 'education') {
|
||||||
const list = [...profile.value.education, data] as any[]
|
const res = await addResumeEducation(defaultResumeId.value, { school: data.school, major: data.major, degree: data.degree, studyType: data.studyType, startDate: data.startDate, endDate: data.endDate, description: data.description })
|
||||||
await saveEducation(list)
|
newId = res.data || ''
|
||||||
profile.value.education = list
|
profile.value.education.push({ id: newId, ...data } as any)
|
||||||
} else if (moduleType === 'work') {
|
} else if (moduleType === 'work') {
|
||||||
const list = [...profile.value.works, data] as any[]
|
const res = await addResumeWork(defaultResumeId.value, { companyName: data.companyName, position: data.position, startDate: data.startDate, endDate: data.endDate, description: data.description })
|
||||||
await saveWork(list)
|
newId = res.data || ''
|
||||||
profile.value.works = list
|
profile.value.works.push({ id: newId, ...data } as any)
|
||||||
} else if (moduleType === 'internship') {
|
} else if (moduleType === 'internship') {
|
||||||
const list = [...profile.value.internships, data] as any[]
|
const res = await addResumeInternship(defaultResumeId.value, { companyName: data.companyName, position: data.position, startDate: data.startDate, endDate: data.endDate, description: data.description })
|
||||||
await saveInternship(list)
|
newId = res.data || ''
|
||||||
profile.value.internships = list
|
profile.value.internships.push({ id: newId, ...data } as any)
|
||||||
} else if (moduleType === 'project') {
|
} else if (moduleType === 'project') {
|
||||||
const list = [...profile.value.projects, data] as any[]
|
const res = await addResumeProject(defaultResumeId.value, { projectName: data.projectName, companyName: data.companyName, role: data.role, startDate: data.startDate, endDate: data.endDate, description: data.description })
|
||||||
await saveProject(list)
|
newId = res.data || ''
|
||||||
profile.value.projects = list
|
profile.value.projects.push({ id: newId, ...data } as any)
|
||||||
} else if (moduleType === 'competition') {
|
} else if (moduleType === 'competition') {
|
||||||
const list = [...profile.value.competitions, data] as any[]
|
const res = await addResumeCompetition(defaultResumeId.value, { competitionName: data.competitionName, award: data.award, awardDate: data.awardDate, description: data.description })
|
||||||
await saveCompetition(list)
|
newId = res.data || ''
|
||||||
profile.value.competitions = list
|
profile.value.competitions.push({ id: newId, ...data } as any)
|
||||||
}
|
}
|
||||||
ElMessage.success('添加成功')
|
ElMessage.success('添加成功')
|
||||||
} catch {
|
} catch {
|
||||||
@@ -521,7 +793,7 @@ async function handleExpAdd(moduleType: string, data: Record<string, any>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 删除单条经历 — 确认后从列表移除并全量保存 */
|
/** 删除单条经历 — 调用简历单条删除接口 */
|
||||||
async function handleExpDelete(moduleType: string, index: number) {
|
async function handleExpDelete(moduleType: string, index: number) {
|
||||||
try {
|
try {
|
||||||
await ElMessageBox.confirm('确定要删除这条经历吗?', '提示', {
|
await ElMessageBox.confirm('确定要删除这条经历吗?', '提示', {
|
||||||
@@ -532,27 +804,28 @@ async function handleExpDelete(moduleType: string, index: number) {
|
|||||||
} catch {
|
} catch {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (!defaultResumeId.value) { ElMessage.error('未找到默认简历'); return }
|
||||||
try {
|
try {
|
||||||
if (moduleType === 'education') {
|
if (moduleType === 'education') {
|
||||||
const list = profile.value.education.filter((_, i) => i !== index) as any[]
|
const id = profile.value.education[index]?.id
|
||||||
await saveEducation(list)
|
if (id) await deleteResumeEducation(id)
|
||||||
profile.value.education = list
|
profile.value.education.splice(index, 1)
|
||||||
} else if (moduleType === 'work') {
|
} else if (moduleType === 'work') {
|
||||||
const list = profile.value.works.filter((_, i) => i !== index) as any[]
|
const id = profile.value.works[index]?.id
|
||||||
await saveWork(list)
|
if (id) await deleteResumeWork(id)
|
||||||
profile.value.works = list
|
profile.value.works.splice(index, 1)
|
||||||
} else if (moduleType === 'internship') {
|
} else if (moduleType === 'internship') {
|
||||||
const list = profile.value.internships.filter((_, i) => i !== index) as any[]
|
const id = profile.value.internships[index]?.id
|
||||||
await saveInternship(list)
|
if (id) await deleteResumeInternship(id)
|
||||||
profile.value.internships = list
|
profile.value.internships.splice(index, 1)
|
||||||
} else if (moduleType === 'project') {
|
} else if (moduleType === 'project') {
|
||||||
const list = profile.value.projects.filter((_, i) => i !== index) as any[]
|
const id = profile.value.projects[index]?.id
|
||||||
await saveProject(list)
|
if (id) await deleteResumeProject(id)
|
||||||
profile.value.projects = list
|
profile.value.projects.splice(index, 1)
|
||||||
} else if (moduleType === 'competition') {
|
} else if (moduleType === 'competition') {
|
||||||
const list = profile.value.competitions.filter((_, i) => i !== index) as any[]
|
const id = profile.value.competitions[index]?.id
|
||||||
await saveCompetition(list)
|
if (id) await deleteResumeCompetition(id)
|
||||||
profile.value.competitions = list
|
profile.value.competitions.splice(index, 1)
|
||||||
}
|
}
|
||||||
ElMessage.success('删除成功')
|
ElMessage.success('删除成功')
|
||||||
} catch {
|
} catch {
|
||||||
@@ -581,6 +854,11 @@ const selectedResumeName = computed(() => {
|
|||||||
function selectResume(r: { id?: string; resumeName?: string }) {
|
function selectResume(r: { id?: string; resumeName?: string }) {
|
||||||
selectedResumeId.value = r.id || ''
|
selectedResumeId.value = r.id || ''
|
||||||
showResumeDropdown.value = false
|
showResumeDropdown.value = false
|
||||||
|
|
||||||
|
// 个人信息仍从 /user/profile 获取
|
||||||
|
loadProfile()
|
||||||
|
// 其他数据(技能、证书、个人概述、5大经历)从默认简历获取
|
||||||
|
loadDefaultResumeData()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 选中招聘分类 */
|
/** 选中招聘分类 */
|
||||||
@@ -639,13 +917,50 @@ const autoOptimizeSwitch = ref(true)
|
|||||||
/** 岗位匹配分析开关 */
|
/** 岗位匹配分析开关 */
|
||||||
const autoMatchAnalysisSwitch = ref(true)
|
const autoMatchAnalysisSwitch = ref(true)
|
||||||
|
|
||||||
|
/** 切换简历针对性优化开关 */
|
||||||
|
function toggleOptimize() {
|
||||||
|
autoOptimizeSwitch.value = !autoOptimizeSwitch.value
|
||||||
|
savePreferenceSwitches()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 切换深度人岗匹配分析开关 */
|
||||||
|
function toggleMatchAnalysis() {
|
||||||
|
autoMatchAnalysisSwitch.value = !autoMatchAnalysisSwitch.value
|
||||||
|
savePreferenceSwitches()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 保存投递偏好开关到接口 */
|
||||||
|
async function savePreferenceSwitches() {
|
||||||
|
try {
|
||||||
|
await saveAgentConfig({
|
||||||
|
autoOptimizeResume: autoOptimizeSwitch.value ? 1 : 0,
|
||||||
|
acceptDeptTransfer: autoMatchAnalysisSwitch.value ? '是' : '否',
|
||||||
|
})
|
||||||
|
} catch { /* 静默 */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 加载投递偏好开关状态 */
|
||||||
|
async function loadPreferenceSwitches() {
|
||||||
|
try {
|
||||||
|
const res = await fetchAgentConfig()
|
||||||
|
if (res.code === '0' && res.data) {
|
||||||
|
if (res.data.autoOptimizeResume !== undefined) autoOptimizeSwitch.value = res.data.autoOptimizeResume === 1
|
||||||
|
autoMatchAnalysisSwitch.value = res.data.acceptDeptTransfer === '是'
|
||||||
|
}
|
||||||
|
} catch { /* 静默 */ }
|
||||||
|
}
|
||||||
|
|
||||||
/** 加载简历列表 */
|
/** 加载简历列表 */
|
||||||
async function loadResumeList() {
|
async function loadResumeList() {
|
||||||
try {
|
try {
|
||||||
const res = await fetchResumeList()
|
const res = await fetchResumeList()
|
||||||
if (res.code === '0' && res.data) {
|
if (res.code === '0' && res.data) {
|
||||||
resumeList.value = res.data
|
resumeList.value = res.data
|
||||||
const defaultResume = res.data.find(r => r.isDefault === 1)
|
let defaultResume = res.data.find(r => r.isDefault === 1)
|
||||||
|
if(!defaultResume){
|
||||||
|
// 按 createTime 降序取第一个
|
||||||
|
defaultResume = [...resumeList.value].sort((a, b) => (b.createTime || 0) - (a.createTime || 0))[0]
|
||||||
|
}
|
||||||
if (defaultResume && defaultResume.id) {
|
if (defaultResume && defaultResume.id) {
|
||||||
selectedResumeId.value = defaultResume.id
|
selectedResumeId.value = defaultResume.id
|
||||||
} else if (res.data.length > 0 && res.data[0].id) {
|
} else if (res.data.length > 0 && res.data[0].id) {
|
||||||
@@ -656,7 +971,7 @@ async function loadResumeList() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** 进入第2步时加载简历列表 */
|
/** 进入第2步时加载简历列表 */
|
||||||
watch(currentStep, (val) => { if (val === 2) loadResumeList() })
|
// watch(currentStep, (val) => { if (val === 1) loadResumeList() })
|
||||||
|
|
||||||
/** 选择简历后设为默认简历 */
|
/** 选择简历后设为默认简历 */
|
||||||
watch(selectedResumeId, async (newId, oldId) => {
|
watch(selectedResumeId, async (newId, oldId) => {
|
||||||
|
|||||||
@@ -152,11 +152,11 @@ function switchTab(tab: 'pending' | 'completed') {
|
|||||||
activeTab.value = tab
|
activeTab.value = tab
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 加载待投递列表(pageSize=300) */
|
/** 加载待投递列表(pageSize=200) */
|
||||||
async function loadPendingList() {
|
async function loadPendingList() {
|
||||||
pendingLoading.value = true
|
pendingLoading.value = true
|
||||||
try {
|
try {
|
||||||
const res = await fetchAgentTaskList({ pageNum: 1, pageSize: 300, tab: 1 })
|
const res = await fetchAgentTaskList({ pageNum: 1, pageSize: 200, tab: 1 })
|
||||||
if (res.code === '0' && res.data) {
|
if (res.code === '0' && res.data) {
|
||||||
pendingList.value = res.data.list || []
|
pendingList.value = res.data.list || []
|
||||||
}
|
}
|
||||||
@@ -167,11 +167,11 @@ async function loadPendingList() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 加载已完成列表(pageSize=300) */
|
/** 加载已完成列表(pageSize=200) */
|
||||||
async function loadCompletedList() {
|
async function loadCompletedList() {
|
||||||
completedLoading.value = true
|
completedLoading.value = true
|
||||||
try {
|
try {
|
||||||
const res = await fetchAgentTaskList({ pageNum: 1, pageSize: 300, tab: 2 })
|
const res = await fetchAgentTaskList({ pageNum: 1, pageSize: 200, tab: 2 })
|
||||||
if (res.code === '0' && res.data) {
|
if (res.code === '0' && res.data) {
|
||||||
completedList.value = res.data.list || []
|
completedList.value = res.data.list || []
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -17,22 +17,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 岗位统计卡片区域 -->
|
|
||||||
<div class="job-stats-cards">
|
|
||||||
<!-- 全网实时岗位卡片 -->
|
|
||||||
<div class="job-stats-cards__count-card prl10 dflex-center aliite-c">
|
|
||||||
<span class="job-stats-cards__dot"></span>
|
|
||||||
<div class="ml8">
|
|
||||||
<div class="job-stats-cards__count-num">{{ formattedJobCount }}</div>
|
|
||||||
<div class="job-stats-cards__count-label">全网实时岗位</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- 可投率卡片 -->
|
|
||||||
<div class="job-stats-cards__match-card">
|
|
||||||
<span class="job-stats-cards__match-num">92%</span>
|
|
||||||
<span class="job-stats-cards__match-label">可投率</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -41,7 +26,7 @@
|
|||||||
import { ref, computed, onMounted } from 'vue'
|
import { ref, computed, onMounted } from 'vue'
|
||||||
import { useRouter, useRoute } from 'vue-router'
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
import { useStore } from 'vuex'
|
import { useStore } from 'vuex'
|
||||||
import { fetchFavoriteCount, fetchApplyCount, fetchJobCount } from '@/api/jobs'
|
import { fetchFavoriteCount, fetchApplyCount } from '@/api/jobs'
|
||||||
|
|
||||||
// ==================== Props & Emits ====================
|
// ==================== Props & Emits ====================
|
||||||
|
|
||||||
@@ -66,32 +51,12 @@ const isAuthenticated = computed(() => store.state.isAuthenticated)
|
|||||||
|
|
||||||
// ==================== 收藏 & 投递统计 ====================
|
// ==================== 收藏 & 投递统计 ====================
|
||||||
|
|
||||||
/** 全网岗位总数 */
|
|
||||||
const jobCount = ref(0)
|
|
||||||
|
|
||||||
/** 格式化岗位总数(每3位加逗号) */
|
|
||||||
const formattedJobCount = computed(() => {
|
|
||||||
return jobCount.value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
|
||||||
})
|
|
||||||
|
|
||||||
/** 收藏总数 */
|
/** 收藏总数 */
|
||||||
const favoriteTotal = ref(0)
|
const favoriteTotal = ref(0)
|
||||||
|
|
||||||
/** 投递总数 */
|
/** 投递总数 */
|
||||||
const applyTotal = ref(0)
|
const applyTotal = ref(0)
|
||||||
|
|
||||||
/** 加载岗位总数 */
|
|
||||||
async function loadJobCount() {
|
|
||||||
try {
|
|
||||||
const res = await fetchJobCount()
|
|
||||||
if (res.code === '0' && res.data !== undefined) {
|
|
||||||
jobCount.value = Number(res.data)
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error('加载岗位总数失败', e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 加载收藏统计 */
|
/** 加载收藏统计 */
|
||||||
async function loadFavoriteCount() {
|
async function loadFavoriteCount() {
|
||||||
try {
|
try {
|
||||||
@@ -118,8 +83,6 @@ async function loadApplyCount() {
|
|||||||
|
|
||||||
/** 组件挂载时请求收藏和投递统计 */
|
/** 组件挂载时请求收藏和投递统计 */
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 岗位总数不需要登录态
|
|
||||||
loadJobCount()
|
|
||||||
if (isAuthenticated.value) {
|
if (isAuthenticated.value) {
|
||||||
loadFavoriteCount()
|
loadFavoriteCount()
|
||||||
loadApplyCount()
|
loadApplyCount()
|
||||||
|
|||||||
@@ -12,21 +12,7 @@
|
|||||||
</button>
|
</button>
|
||||||
<h2 class="job-resume-custom-dialog__drawer-title">生成你的岗位专属简历</h2>
|
<h2 class="job-resume-custom-dialog__drawer-title">生成你的岗位专属简历</h2>
|
||||||
</div>
|
</div>
|
||||||
<!-- 下载简历按钮(步骤三显示,位于步骤指示器上方) -->
|
|
||||||
<div v-if="currentStep === 4" class="job-resume-custom-dialog__top-download mt10 ml12">
|
|
||||||
<button class="job-resume-custom-dialog__top-download-btn" @click="toggleDownloadMenu">
|
|
||||||
<svg viewBox="0 0 16 16" fill="none" class="job-resume-custom-dialog__top-download-icon">
|
|
||||||
<path d="M8 2v8M8 10l-3-3M8 10l3-3" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
||||||
<path d="M3 12h10" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/>
|
|
||||||
</svg>
|
|
||||||
下载简历
|
|
||||||
</button>
|
|
||||||
<!-- 下载下拉菜单 -->
|
|
||||||
<div v-if="showDownloadMenu" class="job-resume-custom-dialog__top-download-menu">
|
|
||||||
<button class="job-resume-custom-dialog__top-download-option" @click="handleDownload('pdf')">下载PDF</button>
|
|
||||||
<button class="job-resume-custom-dialog__top-download-option" @click="handleDownload('word')">下载Word</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- 步骤指示器 -->
|
<!-- 步骤指示器 -->
|
||||||
<div class="job-resume-custom-dialog__steps pt10">
|
<div class="job-resume-custom-dialog__steps pt10">
|
||||||
<div class="job-resume-custom-dialog__step" :class="{ 'job-resume-custom-dialog__step--active': currentStep === 2 }">
|
<div class="job-resume-custom-dialog__step" :class="{ 'job-resume-custom-dialog__step--active': currentStep === 2 }">
|
||||||
@@ -222,7 +208,7 @@
|
|||||||
</svg>
|
</svg>
|
||||||
<span class="job-resume-custom-dialog__match-score">{{ cachedOptimizedScore.toFixed(1) }}</span>
|
<span class="job-resume-custom-dialog__match-score">{{ cachedOptimizedScore.toFixed(1) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="job-resume-custom-dialog__match-label job-resume-custom-dialog__match-label--high">{{ cachedOptimizedScore >= 9 ? '非常匹配' : cachedOptimizedScore >= 6 ? '高匹配度' : '低匹配度' }}</span>
|
<span class="job-resume-custom-dialog__match-label job-resume-custom-dialog__match-label--high">{{ cachedOptimizedScore >= 9 ? '非常匹配' : cachedOptimizedScore >= 6 ? '高匹配度' : '低竞争力' }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 改写说明(卡片外面平铺) -->
|
<!-- 改写说明(卡片外面平铺) -->
|
||||||
@@ -327,8 +313,15 @@
|
|||||||
<div v-if="currentStep === 4" class="job-resume-custom-dialog__preview-footer mt10 pt30">
|
<div v-if="currentStep === 4" class="job-resume-custom-dialog__preview-footer mt10 pt30">
|
||||||
<!-- 左侧:上一步按钮 -->
|
<!-- 左侧:上一步按钮 -->
|
||||||
<button class="job-resume-custom-dialog__footer-prev-btn" @click="goToStep(3)">上一步</button>
|
<button class="job-resume-custom-dialog__footer-prev-btn" @click="goToStep(3)">上一步</button>
|
||||||
<!-- 右侧:立即去投递按钮 -->
|
<!-- 右侧:下载专属简历按钮 -->
|
||||||
<button class="job-resume-custom-dialog__submit-btn" @click="handleSubmit">立即去投递</button>
|
<div class="job-resume-custom-dialog__submit-wrap">
|
||||||
|
<button class="job-resume-custom-dialog__submit-btn" @click="toggleDownloadMenu">下载专属简历</button>
|
||||||
|
<!-- 下载下拉菜单 -->
|
||||||
|
<div v-if="showDownloadMenu" class="job-resume-custom-dialog__top-download-menu">
|
||||||
|
<button class="job-resume-custom-dialog__top-download-option" @click="handleDownload('pdf')">下载PDF</button>
|
||||||
|
<button class="job-resume-custom-dialog__top-download-option" @click="handleDownload('word')">下载Word</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -482,7 +475,7 @@ const missingSkills = computed(() => props.jobInfo.missingSkills || [])
|
|||||||
const matchLevelText = computed(() => {
|
const matchLevelText = computed(() => {
|
||||||
const score = props.jobInfo.matchScore
|
const score = props.jobInfo.matchScore
|
||||||
if (score >= 6) return '高匹配度'
|
if (score >= 6) return '高匹配度'
|
||||||
return '低匹配度'
|
return '低竞争力'
|
||||||
})
|
})
|
||||||
|
|
||||||
/** 是否为低匹配度(低于6分) */
|
/** 是否为低匹配度(低于6分) */
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 岗位概览统计卡片 -->
|
||||||
|
<div class="job-stats-overview" :style="{ height: cardHeight }">
|
||||||
|
<!-- 右上角装饰图片 -->
|
||||||
|
<img class="job-stats-overview__icon" src="@/assets/images/job-count-card-icon01.png" alt="" />
|
||||||
|
<!-- 内容居中容器 -->
|
||||||
|
<div class="job-stats-overview__inner">
|
||||||
|
<!-- 标题区域 -->
|
||||||
|
<div class="job-stats-overview__header">
|
||||||
|
<div class="job-stats-overview__title">{{ title }}</div>
|
||||||
|
<div class="job-stats-overview__date">{{ subtitle }}</div>
|
||||||
|
</div>
|
||||||
|
<!-- 数据指标区域 -->
|
||||||
|
<div class="job-stats-overview__metrics">
|
||||||
|
<!-- 今日新增 -->
|
||||||
|
<div class="job-stats-overview__metric-item">
|
||||||
|
<div class="job-stats-overview__metric-num">{{ todayCount }}</div>
|
||||||
|
<div class="job-stats-overview__metric-label">{{ todayLabel }}</div>
|
||||||
|
</div>
|
||||||
|
<!-- 分隔线 -->
|
||||||
|
<div class="job-stats-overview__divider"></div>
|
||||||
|
<!-- 累计收录 -->
|
||||||
|
<div class="job-stats-overview__metric-item">
|
||||||
|
<div class="job-stats-overview__metric-num">{{ totalCount }}</div>
|
||||||
|
<div class="job-stats-overview__metric-label">{{ totalLabel }}</div>
|
||||||
|
</div>
|
||||||
|
<!-- 分隔线 -->
|
||||||
|
<div class="job-stats-overview__divider"></div>
|
||||||
|
<!-- 可投率 -->
|
||||||
|
<div class="job-stats-overview__metric-item">
|
||||||
|
<div class="job-stats-overview__metric-num">{{ rateValue }}</div>
|
||||||
|
<div class="job-stats-overview__metric-label">{{ rateLabel }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
/** 岗位概览统计卡片 - 所有展示数据由父组件传入 */
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
/** 卡片标题,如"岗位概览" */
|
||||||
|
title: string
|
||||||
|
/** 副标题,如"数据截至 07.28" */
|
||||||
|
subtitle: string
|
||||||
|
/** 今日新增数字 */
|
||||||
|
todayCount: string | number
|
||||||
|
/** 今日新增标签 */
|
||||||
|
todayLabel: string
|
||||||
|
/** 累计收录数字 */
|
||||||
|
totalCount: string | number
|
||||||
|
/** 累计收录标签 */
|
||||||
|
totalLabel: string
|
||||||
|
/** 可投率数字 */
|
||||||
|
rateValue: string | number
|
||||||
|
/** 可投率标签 */
|
||||||
|
rateLabel: string
|
||||||
|
/** 卡片高度(从父级传入,与筛选面板同步) */
|
||||||
|
cardHeight?: string
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
@@ -1,152 +1,282 @@
|
|||||||
<template>
|
<template>
|
||||||
<!--
|
<!-- 登录弹窗 — 使用登录页 step1&2 的样式,弹窗形式 -->
|
||||||
⚠️ 该弹窗登录组件已搁置,登录功能已改为独立页面 /login (src/views/Login.vue)。
|
<Teleport to="body">
|
||||||
如需恢复弹窗登录,重新在 App.vue 中引用此组件即可。
|
<div v-if="visible" class="login-dialog-overlay" @click.self="handleClose">
|
||||||
-->
|
<div class="login-dialog-box">
|
||||||
<el-dialog
|
<!-- 关闭按钮 -->
|
||||||
v-model="visible"
|
<div class="login-dialog-box__close" @click="handleClose">
|
||||||
width="480px"
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
:show-close="true"
|
<path d="M5 5L15 15M15 5L5 15" stroke="#999" stroke-width="1.8" stroke-linecap="round"/>
|
||||||
:close-on-click-modal="false"
|
</svg>
|
||||||
:close-on-press-escape="true"
|
|
||||||
class="login-dialog"
|
|
||||||
@close="handleClose"
|
|
||||||
>
|
|
||||||
<div class="login-page">
|
|
||||||
<h1 class="login-title">欢迎使用Offer派</h1>
|
|
||||||
|
|
||||||
<div class="login-form">
|
|
||||||
<el-input
|
|
||||||
v-model="phone"
|
|
||||||
placeholder="输入手机号"
|
|
||||||
size="large"
|
|
||||||
class="login-input mt20"
|
|
||||||
/>
|
|
||||||
<div class="code-row mt12 mb12">
|
|
||||||
<el-input
|
|
||||||
v-model="code"
|
|
||||||
placeholder="输入验证码"
|
|
||||||
size="large"
|
|
||||||
class="login-input"
|
|
||||||
/>
|
|
||||||
<el-button
|
|
||||||
class="send-code-btn"
|
|
||||||
:disabled="countdown > 0"
|
|
||||||
@click="sendCode"
|
|
||||||
>
|
|
||||||
{{ countdown > 0 ? countdownText : '发送验证码' }}
|
|
||||||
</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-button
|
<!-- Logo -->
|
||||||
type="primary"
|
<div class="login-dialog-box__logo-row">
|
||||||
size="large"
|
<img src="@/assets/images/logo.png" alt="">
|
||||||
class="login-btn h50 border-ra20"
|
</div>
|
||||||
@click="handleLogin"
|
|
||||||
>
|
|
||||||
登录
|
|
||||||
</el-button>
|
|
||||||
|
|
||||||
|
<div class="login-dialog-box__form-wrap">
|
||||||
|
<!-- 步骤一:输入手机号发送验证码 -->
|
||||||
|
<template v-if="step === 1">
|
||||||
|
<div class="login-dialog-box__heading">
|
||||||
|
<h2 class="login-dialog-box__title">手机号登录/注册</h2>
|
||||||
|
<p class="login-dialog-box__subtitle">未注册用户验证后将自动注册并登录</p>
|
||||||
|
</div>
|
||||||
|
<!-- 手机号输入组 -->
|
||||||
|
<div class="login-dialog-box__phone-row">
|
||||||
|
<!-- 手机图标 -->
|
||||||
|
<div class="login-dialog-box__phone-icon">
|
||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="4.5" y="2" width="9" height="14" rx="1.5" stroke="#0F6B66" stroke-width="1.5"/>
|
||||||
|
<line x1="9" y1="2" x2="9" y2="3.5" stroke="#0F6B66" stroke-width="1.5" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<!-- 国家码标签 -->
|
||||||
|
<span class="login-dialog-box__country-label">中国 +86</span>
|
||||||
|
<!-- 下拉箭头 -->
|
||||||
|
<div class="login-dialog-box__country-chevron">
|
||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M6 8L10 12L14 8" stroke="#6F8586" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<!-- 分隔线 -->
|
||||||
|
<div class="login-dialog-box__input-divider"></div>
|
||||||
|
<!-- 手机号输入框 -->
|
||||||
|
<input v-model="phone" type="tel" class="login-dialog-box__phone-input" placeholder="请输入手机号码" maxlength="11" />
|
||||||
|
</div>
|
||||||
|
<!-- 发送验证码按钮 -->
|
||||||
|
<button class="login-dialog-box__send-btn" :disabled="!canSend" @click="handleSendCode">发送验证码</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 步骤二:输入验证码登录 -->
|
||||||
|
<template v-if="step === 2">
|
||||||
|
<div class="login-dialog-box__heading">
|
||||||
|
<h2 class="login-dialog-box__title">请输入验证码</h2>
|
||||||
|
<p class="login-dialog-box__subtitle dflex"><span class="dib">短信验证码已发送至 +86{{ phone }} </span><span class="fw600 ml5 dib cursor-po mlauto" @click="handleChangePhone">修改手机号</span></p>
|
||||||
|
</div>
|
||||||
|
<!-- OTP 输入框 -->
|
||||||
|
<div class="login-dialog-box__otp-wrap" @click="focusOtpInput">
|
||||||
|
<input ref="otpInputRef" v-model="otpValue" type="text" inputmode="numeric" class="login-dialog-box__otp-hidden-input" maxlength="6" :disabled="isLoggingIn" @input="handleOtpInput" />
|
||||||
|
<div v-for="(_, idx) in 6" :key="idx" class="login-dialog-box__otp-box" :class="{ 'login-dialog-box__otp-box--active': idx === otpValue.length && !isLoggingIn, 'login-dialog-box__otp-box--filled': idx < otpValue.length }">
|
||||||
|
<span v-if="idx < otpValue.length" class="login-dialog-box__otp-digit">{{ otpValue[idx] }}</span>
|
||||||
|
<span v-else-if="idx === otpValue.length && !isLoggingIn" class="login-dialog-box__otp-cursor"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
<!-- 状态提示 -->
|
||||||
|
<p v-if="smsStatusMsg" class="login-dialog-box__sms-status" :class="{ 'login-dialog-box__sms-status--error': smsStatusIsError }">{{ smsStatusMsg }}</p>
|
||||||
|
<!-- 重新发送 / 登录中按钮 -->
|
||||||
|
<button class="login-dialog-box__status-btn" :disabled="isLoggingIn || countdown > 0" @click="handleResendCode">
|
||||||
|
<template v-if="isLoggingIn"><span class="login-dialog-box__spinner"></span><span>登录中</span></template>
|
||||||
|
<template v-else-if="countdown > 0">{{ countdown }} 秒后可继续发送</template>
|
||||||
|
<template v-else>再次发送验证码</template>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 协议勾选(步骤一二通用) -->
|
||||||
|
<div class="login-dialog-box__agreement">
|
||||||
|
<div class="login-dialog-box__checkbox" :class="{ 'login-dialog-box__checkbox--checked': agreedTerms }" @click="agreedTerms = !agreedTerms">
|
||||||
|
<span v-if="agreedTerms" class="login-dialog-box__check-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="0.13rem" height="0.13rem"><path stroke="currentColor" fill="currentColor" d="M77.248 415.04a64 64 0 0 1 90.496 0l226.304 226.304L846.528 188.8a64 64 0 1 1 90.56 90.496l-543.04 543.04-316.8-316.8a64 64 0 0 1 0-90.496"></path></svg></span>
|
||||||
|
</div>
|
||||||
|
<span class="login-dialog-box__agreement-text">登录即表示同意</span>
|
||||||
|
<span class="login-dialog-box__agreement-link" @click="openAgreement('ae8065i3')">《用户协议》</span>
|
||||||
|
<span class="login-dialog-box__agreement-text">与</span>
|
||||||
|
<span class="login-dialog-box__agreement-link" @click="openAgreement('hf8375i8')">《隐私政策》</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Teleport>
|
||||||
|
|
||||||
|
<!-- 协议预览弹窗 -->
|
||||||
|
<AgreementPreviewDialog v-model="showAgreementDialog" :code="agreementCode" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed, nextTick, watch } from 'vue'
|
||||||
import { useStore } from 'vuex'
|
import { useStore } from 'vuex'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { sendSmsCode, smsLogin } from '@/api/auth'
|
import { sendSmsCode, smsLogin } from '@/api/auth'
|
||||||
|
import AgreementPreviewDialog from '@/components/tools/AgreementPreviewDialog.vue'
|
||||||
|
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
|
// ==================== 弹窗显隐控制 ====================
|
||||||
|
/** 弹窗可见性,绑定 store.state.showLogin */
|
||||||
|
const visible = computed(() => store.state.showLogin)
|
||||||
|
|
||||||
|
// ==================== 登录步骤 ====================
|
||||||
|
/** 当前步骤:1=输入手机号 2=输入验证码 */
|
||||||
|
const step = ref(1)
|
||||||
|
/** 手机号 */
|
||||||
const phone = ref('')
|
const phone = ref('')
|
||||||
const code = ref('')
|
/** OTP 验证码值 */
|
||||||
|
const otpValue = ref('')
|
||||||
|
/** 是否已勾选协议 */
|
||||||
|
const agreedTerms = ref(true)
|
||||||
|
/** 倒计时秒数 */
|
||||||
const countdown = ref(0)
|
const countdown = ref(0)
|
||||||
let timer: ReturnType<typeof setInterval> | null = null
|
let countdownTimer: ReturnType<typeof setInterval> | null = null
|
||||||
|
/** 是否正在登录中 */
|
||||||
|
const isLoggingIn = ref(false)
|
||||||
|
/** 验证码状态提示文字 */
|
||||||
|
const smsStatusMsg = ref('')
|
||||||
|
/** 是否为错误样式 */
|
||||||
|
const smsStatusIsError = ref(false)
|
||||||
|
/** OTP 输入框引用 */
|
||||||
|
const otpInputRef = ref<HTMLInputElement | null>(null)
|
||||||
|
/** 协议弹窗状态 */
|
||||||
|
const showAgreementDialog = ref(false)
|
||||||
|
const agreementCode = ref('')
|
||||||
|
|
||||||
/** 倒计时显示文本,格式 m:ss */
|
/** 发送按钮是否可用(手机号11位 + 勾选协议) */
|
||||||
const countdownText = computed(() => {
|
const canSend = computed(() => phone.value.length === 11 && agreedTerms.value)
|
||||||
const m = Math.floor(countdown.value / 60)
|
|
||||||
const s = countdown.value % 60
|
|
||||||
return `${m}:${s.toString().padStart(2, '0')}`
|
|
||||||
})
|
|
||||||
|
|
||||||
const visible = computed({
|
// ==================== 弹窗打开时重置状态 ====================
|
||||||
get: () => store.state.showLogin,
|
watch(visible, (val) => {
|
||||||
set: (val: boolean) => {
|
if (val) {
|
||||||
if (!val) store.dispatch('closeLogin')
|
step.value = 1
|
||||||
},
|
phone.value = ''
|
||||||
})
|
otpValue.value = ''
|
||||||
|
countdown.value = 0
|
||||||
//发送验证码
|
smsStatusMsg.value = ''
|
||||||
async function sendCode() {
|
smsStatusIsError.value = false
|
||||||
if (!phone.value) {
|
isLoggingIn.value = false
|
||||||
ElMessage.warning('请输入手机号')
|
if (countdownTimer) { clearInterval(countdownTimer); countdownTimer = null }
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// ==================== 方法 ====================
|
||||||
|
|
||||||
|
/** 关闭弹窗 */
|
||||||
|
function handleClose() {
|
||||||
|
store.dispatch('closeLogin')
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 打开协议预览 */
|
||||||
|
function openAgreement(code: string) {
|
||||||
|
agreementCode.value = code
|
||||||
|
showAgreementDialog.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 聚焦 OTP 隐藏输入框 */
|
||||||
|
function focusOtpInput() {
|
||||||
|
otpInputRef.value?.focus()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 修改手机号 — 回到步骤一 */
|
||||||
|
function handleChangePhone() {
|
||||||
|
step.value = 1
|
||||||
|
phone.value = ''
|
||||||
|
otpValue.value = ''
|
||||||
|
countdown.value = 0
|
||||||
|
smsStatusMsg.value = ''
|
||||||
|
smsStatusIsError.value = false
|
||||||
|
isLoggingIn.value = false
|
||||||
|
if (countdownTimer) { clearInterval(countdownTimer); countdownTimer = null }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 开始60秒倒计时 */
|
||||||
|
function startCountdown() {
|
||||||
|
countdown.value = 60
|
||||||
|
countdownTimer = setInterval(() => {
|
||||||
|
countdown.value--
|
||||||
|
if (countdown.value <= 0 && countdownTimer) { clearInterval(countdownTimer); countdownTimer = null }
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 步骤一:发送验证码 */
|
||||||
|
async function handleSendCode() {
|
||||||
|
if (!phone.value) { ElMessage.warning('请输入手机号'); return }
|
||||||
|
if (!agreedTerms.value) { ElMessage.warning('请先同意用户协议与隐私政策'); return }
|
||||||
try {
|
try {
|
||||||
const res = await sendSmsCode(phone.value)
|
const res = await sendSmsCode(phone.value)
|
||||||
if (res.code === '0' && res.data === true) {
|
if (res.code === '0') {
|
||||||
ElMessage.success('验证码已发送')
|
smsStatusMsg.value = '验证码发送成功,请输入'
|
||||||
countdown.value = 60
|
smsStatusIsError.value = false
|
||||||
timer = setInterval(() => {
|
step.value = 2
|
||||||
countdown.value--
|
startCountdown()
|
||||||
if (countdown.value <= 0 && timer) {
|
nextTick(() => focusOtpInput())
|
||||||
clearInterval(timer)
|
} else if (res.msg && res.msg.includes('请勿重复发送')) {
|
||||||
timer = null
|
smsStatusMsg.value = '验证码还在有效期内,请输入'
|
||||||
}
|
smsStatusIsError.value = false
|
||||||
}, 1000)
|
step.value = 2
|
||||||
|
startCountdown()
|
||||||
|
nextTick(() => focusOtpInput())
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error(res.msg || '验证码发送失败')
|
smsStatusMsg.value = res.msg || '验证码发送失败'
|
||||||
|
smsStatusIsError.value = true
|
||||||
}
|
}
|
||||||
} catch {
|
} catch (err: any) {
|
||||||
// 错误已在 request 拦截器中统一处理
|
const msg = err?.response?.data?.msg || '验证码发送失败'
|
||||||
|
smsStatusMsg.value = msg
|
||||||
|
smsStatusIsError.value = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** OTP 输入处理 — 6位自动登录 */
|
||||||
* 登录流程:
|
function handleOtpInput() {
|
||||||
* 1. 调 smsLogin 接口,后端成功会 Set-Cookie: Token=xxx
|
otpValue.value = otpValue.value.replace(/\D/g, '').slice(0, 6)
|
||||||
* 2. Cookie 自动保持登录状态,不再存 localStorage
|
if (otpValue.value.length === 6) { handleLogin() }
|
||||||
* 3. 关闭弹窗,跳转到登录前想去的页面
|
|
||||||
*/
|
|
||||||
async function handleLogin() {
|
|
||||||
if (!phone.value || !code.value) {
|
|
||||||
ElMessage.warning('请输入手机号和验证码')
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 步骤二:再次发送验证码 */
|
||||||
|
async function handleResendCode() {
|
||||||
|
if (isLoggingIn.value || countdown.value > 0) return
|
||||||
try {
|
try {
|
||||||
const res = await smsLogin(phone.value, code.value)
|
const res = await sendSmsCode(phone.value)
|
||||||
|
if (res.code === '0') {
|
||||||
|
smsStatusMsg.value = '验证码发送成功,请输入'
|
||||||
|
smsStatusIsError.value = false
|
||||||
|
otpValue.value = ''
|
||||||
|
startCountdown()
|
||||||
|
nextTick(() => focusOtpInput())
|
||||||
|
} else if (res.msg && res.msg.includes('请勿重复发送')) {
|
||||||
|
smsStatusMsg.value = '验证码还在有效期内,请输入'
|
||||||
|
smsStatusIsError.value = false
|
||||||
|
} else {
|
||||||
|
smsStatusMsg.value = res.msg || '验证码发送失败'
|
||||||
|
smsStatusIsError.value = true
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
const msg = err?.response?.data?.msg || '验证码发送失败'
|
||||||
|
smsStatusMsg.value = msg
|
||||||
|
smsStatusIsError.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 登录接口调用 */
|
||||||
|
async function handleLogin() {
|
||||||
|
isLoggingIn.value = true
|
||||||
|
try {
|
||||||
|
const res = await smsLogin(phone.value, otpValue.value)
|
||||||
if (res.code !== '0') {
|
if (res.code !== '0') {
|
||||||
ElMessage.error(res.msg || '登录失败')
|
smsStatusMsg.value = '验证码有误,请重新输入'
|
||||||
|
smsStatusIsError.value = true
|
||||||
|
otpValue.value = ''
|
||||||
|
isLoggingIn.value = false
|
||||||
|
nextTick(() => focusOtpInput())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 登录成功,Cookie Token 已由后端 Set-Cookie 写入
|
// 登录成功
|
||||||
ElMessage.success(`欢迎回来,${res.data?.nick || ''}`)
|
ElMessage.success(`欢迎回来,${res.data?.nick || ''}`)
|
||||||
|
if (countdownTimer) { clearInterval(countdownTimer); countdownTimer = null }
|
||||||
// 清除验证码倒计时,登录成功后解除发送限制
|
|
||||||
if (timer) {
|
|
||||||
clearInterval(timer)
|
|
||||||
timer = null
|
|
||||||
}
|
|
||||||
countdown.value = 0
|
countdown.value = 0
|
||||||
|
|
||||||
store.commit('SET_AUTHENTICATED', true)
|
store.commit('SET_AUTHENTICATED', true)
|
||||||
|
|
||||||
|
// 关闭弹窗并跳转
|
||||||
const redirect = store.state.loginRedirect
|
const redirect = store.state.loginRedirect
|
||||||
store.dispatch('closeLogin')
|
store.dispatch('closeLogin')
|
||||||
if (redirect) {
|
if (redirect) {
|
||||||
router.push(redirect)
|
router.push(redirect)
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// 错误已在 request 拦截器中统一处理
|
smsStatusMsg.value = '验证码有误,请重新输入'
|
||||||
|
smsStatusIsError.value = true
|
||||||
|
otpValue.value = ''
|
||||||
|
isLoggingIn.value = false
|
||||||
|
nextTick(() => focusOtpInput())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleClose() {
|
|
||||||
store.dispatch('closeLogin')
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -3,17 +3,84 @@
|
|||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<!-- 遮罩层 — 点击关闭弹窗 -->
|
<!-- 遮罩层 — 点击关闭弹窗 -->
|
||||||
<div v-if="modelValue" class="member-dialog-overlay" @click="$emit('update:modelValue', false)">
|
<div v-if="modelValue" class="member-dialog-overlay" @click="$emit('update:modelValue', false)">
|
||||||
<!-- 弹窗主体 — 阻止点击冒泡 -->
|
<!-- 弹窗主体 — 左右布局 -->
|
||||||
<div class="member-dialog" @click.stop>
|
<div class="member-dialog" @click.stop>
|
||||||
|
|
||||||
|
<!-- 左侧黑金权益栏 -->
|
||||||
|
<div class="member-dialog__left">
|
||||||
|
<!-- 装饰线条背景 -->
|
||||||
|
<div class="member-dialog__left-deco"></div>
|
||||||
|
<!-- 左栏标题 -->
|
||||||
|
<h2 class="member-dialog__left-title">Offer派会员专享权益</h2>
|
||||||
|
<p class="member-dialog__left-subtitle">解锁更多功能,让求职更高效</p>
|
||||||
|
<!-- 权益卡片列表 -->
|
||||||
|
<div class="member-dialog__benefits">
|
||||||
|
<div class="member-dialog__benefit-card">
|
||||||
|
<div class="member-dialog__benefit-icon">
|
||||||
|
<svg width="14" height="15" viewBox="0 0 13 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M4.67492 2.29867C5.07359 1.132 6.68559 1.09667 7.15825 2.19267L7.19825 2.29933L7.73625 3.87267C7.85955 4.23349 8.05879 4.56367 8.32054 4.84095C8.58229 5.11822 8.90046 5.33614 9.25359 5.48L9.39825 5.534L10.9716 6.07133C12.1383 6.47 12.1736 8.082 11.0783 8.55467L10.9716 8.59467L9.39825 9.13267C9.03731 9.25588 8.70699 9.45508 8.4296 9.71684C8.1522 9.97859 7.93418 10.2968 7.79025 10.65L7.73625 10.794L7.19892 12.368C6.80025 13.5347 5.18825 13.57 4.71625 12.4747L4.67492 12.368L4.13759 10.7947C4.01437 10.4337 3.81517 10.1034 3.55341 9.82601C3.29166 9.54862 2.97345 9.3306 2.62025 9.18667L2.47625 9.13267L0.902919 8.59533C-0.264415 8.19667 -0.299748 6.58467 0.796252 6.11267L0.902919 6.07133L2.47625 5.534C2.83707 5.4107 3.16726 5.21146 3.44453 4.94971C3.72181 4.68796 3.93973 4.36979 4.08359 4.01667L4.13759 3.87267L4.67492 2.29867ZM11.2703 1.20458e-07C11.395 -1.57315e-07 11.5172 0.0349855 11.623 0.100981C11.7288 0.166977 11.814 0.261335 11.8689 0.373333L11.9009 0.451333L12.1343 1.13533L12.8189 1.36867C12.9439 1.41113 13.0535 1.48974 13.1337 1.59454C13.214 1.69934 13.2613 1.82561 13.2698 1.95735C13.2782 2.08908 13.2473 2.22035 13.1811 2.33453C13.1148 2.4487 13.0161 2.54063 12.8976 2.59867L12.8189 2.63067L12.1349 2.864L11.9016 3.54867C11.859 3.67362 11.7804 3.78313 11.6755 3.86333C11.5707 3.94352 11.4444 3.99079 11.3127 3.99915C11.1809 4.0075 11.0497 3.97656 10.9356 3.91025C10.8214 3.84394 10.7296 3.74524 10.6716 3.62667L10.6396 3.54867L10.4063 2.86467L9.72159 2.63133C9.5966 2.58887 9.48703 2.51026 9.40677 2.40546C9.3265 2.30066 9.27916 2.17439 9.27073 2.04265C9.26231 1.91092 9.29318 1.77965 9.35944 1.66548C9.4257 1.5513 9.52436 1.45937 9.64292 1.40133L9.72159 1.36933L10.4056 1.136L10.6389 0.451333C10.6839 0.319617 10.7689 0.205272 10.8821 0.124333C10.9954 0.0433927 11.1311 -8.35209e-05 11.2703 1.20458e-07Z" fill="#FFE2A1"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class="member-dialog__benefit-info">
|
||||||
|
<span class="member-dialog__benefit-name">AI智能投递</span>
|
||||||
|
<span class="member-dialog__benefit-desc">会员专享</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="member-dialog__benefit-card">
|
||||||
|
<div class="member-dialog__benefit-icon">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_2639_2062)">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.49998 1.66667C9.49998 1.62246 9.48242 1.58007 9.45116 1.54882C9.41991 1.51756 9.37752 1.5 9.33331 1.5H4.66665C4.18042 1.5 3.7141 1.69315 3.37028 2.03697C3.02647 2.38079 2.83331 2.8471 2.83331 3.33333V12.6667C2.83331 13.1529 3.02647 13.6192 3.37028 13.963C3.7141 14.3068 4.18042 14.5 4.66665 14.5H11.3333C11.8195 14.5 12.2859 14.3068 12.6297 13.963C12.9735 13.6192 13.1666 13.1529 13.1666 12.6667V6.098C13.1666 6.0538 13.1491 6.0114 13.1178 5.98015C13.0866 5.94889 13.0442 5.93133 13 5.93133H9.99998C9.86737 5.93133 9.74019 5.87865 9.64643 5.78489C9.55266 5.69112 9.49998 5.56394 9.49998 5.43133V1.66667ZM9.99998 8.16667C10.1326 8.16667 10.2598 8.21935 10.3535 8.31311C10.4473 8.40688 10.5 8.53406 10.5 8.66667C10.5 8.79927 10.4473 8.92645 10.3535 9.02022C10.2598 9.11399 10.1326 9.16667 9.99998 9.16667H5.99998C5.86737 9.16667 5.74019 9.11399 5.64643 9.02022C5.55266 8.92645 5.49998 8.79927 5.49998 8.66667C5.49998 8.53406 5.55266 8.40688 5.64643 8.31311C5.74019 8.21935 5.86737 8.16667 5.99998 8.16667H9.99998ZM9.99998 10.8333C10.1326 10.8333 10.2598 10.886 10.3535 10.9798C10.4473 11.0735 10.5 11.2007 10.5 11.3333C10.5 11.4659 10.4473 11.5931 10.3535 11.6869C10.2598 11.7807 10.1326 11.8333 9.99998 11.8333H5.99998C5.86737 11.8333 5.74019 11.7807 5.64643 11.6869C5.55266 11.5931 5.49998 11.4659 5.49998 11.3333C5.49998 11.2007 5.55266 11.0735 5.64643 10.9798C5.74019 10.886 5.86737 10.8333 5.99998 10.8333H9.99998Z" fill="#FFE2A1"/>
|
||||||
|
<path d="M10.5 1.88272C10.5 1.76005 10.6287 1.68205 10.724 1.75872C10.8049 1.82405 10.8767 1.90005 10.9393 1.98672L12.948 4.78472C12.9933 4.84872 12.944 4.93139 12.8653 4.93139H10.6667C10.6225 4.93139 10.5801 4.91383 10.5488 4.88257C10.5176 4.85131 10.5 4.80892 10.5 4.76472V1.88272Z" fill="#FFE2A1"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_2639_2062">
|
||||||
|
<rect width="16" height="16" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class="member-dialog__benefit-info">
|
||||||
|
<span class="member-dialog__benefit-name">AI优化简历</span>
|
||||||
|
<span class="member-dialog__benefit-desc">享受无限次数</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="member-dialog__benefit-card">
|
||||||
|
<div class="member-dialog__benefit-icon">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M8.655 1.64404C8.70394 1.5974 8.76182 1.56116 8.82516 1.53753C8.8885 1.5139 8.95597 1.50335 9.0235 1.50654C11.9815 1.64504 14.355 4.01854 14.4935 6.97654C14.4967 7.04411 14.4861 7.11162 14.4624 7.17499C14.4388 7.23835 14.4025 7.29626 14.3558 7.3452C14.3091 7.39414 14.253 7.4331 14.1908 7.45971C14.1286 7.48632 14.0616 7.50004 13.994 7.50004H9C8.86739 7.50004 8.74021 7.44736 8.64645 7.35359C8.55268 7.25982 8.5 7.13264 8.5 7.00004V2.00604C8.49999 1.93835 8.51372 1.87136 8.54036 1.80913C8.567 1.74691 8.60601 1.69074 8.655 1.64404ZM7.345 3.14404C7.39399 3.19074 7.43299 3.24691 7.45964 3.30913C7.48628 3.37136 7.50001 3.43835 7.5 3.50604V7.25004C7.5 7.58156 7.6317 7.8995 7.86612 8.13392C8.10054 8.36834 8.41848 8.50004 8.75 8.50004H12.494C12.5617 8.49996 12.6287 8.51363 12.6909 8.54021C12.7532 8.5668 12.8094 8.60574 12.8561 8.65469C12.9029 8.70364 12.9392 8.76157 12.9629 8.82497C12.9866 8.88837 12.9972 8.95593 12.994 9.02354C12.85 12.0725 10.3335 14.5 7.25 14.5C4.0745 14.5 1.5 11.9255 1.5 8.75004C1.5 5.66604 3.9275 3.14954 6.9765 3.00654C7.04403 3.00335 7.1115 3.0139 7.17484 3.03753C7.23818 3.06116 7.29606 3.0974 7.345 3.14404Z" fill="#FFE2A1"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class="member-dialog__benefit-info">
|
||||||
|
<span class="member-dialog__benefit-name">海量岗位数据</span>
|
||||||
|
<span class="member-dialog__benefit-desc">全网实时更新</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="member-dialog__benefit-card">
|
||||||
|
<div class="member-dialog__benefit-icon">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M12 2C11.4696 2 10.9609 2.21071 10.5858 2.58579C10.2107 2.96086 10 3.46957 10 4C10 4.53043 10.2107 5.03914 10.5858 5.41421C10.9609 5.78929 11.4696 6 12 6C12.5304 6 13.0391 5.78929 13.4142 5.41421C13.7893 5.03914 14 4.53043 14 4C14 3.46957 13.7893 2.96086 13.4142 2.58579C13.0391 2.21071 12.5304 2 12 2Z" fill="#FFE2A1"/>
|
||||||
|
<path d="M3.33333 2.66663C2.6 2.66663 2 3.26663 2 3.99996V12.6666C2 13.4 2.6 14 3.33333 14H12C12.7333 14 13.3333 13.4 13.3333 12.6666V6.67329C12.9267 6.87329 12.48 6.99996 12 6.99996C10.3467 6.99996 9 5.65329 9 3.99996C9 3.51996 9.12667 3.07329 9.32667 2.66663H3.33333Z" fill="#FFE2A1"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class="member-dialog__benefit-info">
|
||||||
|
<span class="member-dialog__benefit-name">校招公告速递</span>
|
||||||
|
<span class="member-dialog__benefit-desc">名企动态抢先看</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 左右分割金边 -->
|
||||||
|
<div class="member-dialog__divider"></div>
|
||||||
|
|
||||||
|
<!-- 右侧内容区 -->
|
||||||
|
<div class="member-dialog__right">
|
||||||
<!-- 顶部标题行 -->
|
<!-- 顶部标题行 -->
|
||||||
<div class="member-dialog__header">
|
<div class="member-dialog__header">
|
||||||
<div class="member-dialog__header-left">
|
|
||||||
<h2 class="member-dialog__title">会员中心</h2>
|
<h2 class="member-dialog__title">会员中心</h2>
|
||||||
<p class="member-dialog__subtitle">解锁更多求职功能,让投递更高效</p>
|
<div class="member-dialog__header-actions">
|
||||||
</div>
|
<!-- 联系客服 -->
|
||||||
<div class="member-dialog__header-right">
|
|
||||||
<!-- 联系客服(hover显示二维码) -->
|
|
||||||
<span class="member-dialog__contact-wrap">
|
<span class="member-dialog__contact-wrap">
|
||||||
<span class="member-dialog__contact">联系客服</span>
|
<span class="member-dialog__contact">联系客服</span>
|
||||||
<div class="member-dialog__contact-qr">
|
<div class="member-dialog__contact-qr">
|
||||||
@@ -21,6 +88,7 @@
|
|||||||
<div class="member-dialog__contact-qr-arrow"></div>
|
<div class="member-dialog__contact-qr-arrow"></div>
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
|
<!-- 关闭按钮 -->
|
||||||
<span class="member-dialog__close" @click="$emit('update:modelValue', false)">✕</span>
|
<span class="member-dialog__close" @click="$emit('update:modelValue', false)">✕</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -34,150 +102,129 @@
|
|||||||
:class="{ 'member-dialog__plan-card--active': selectedPlan === plan.key }"
|
:class="{ 'member-dialog__plan-card--active': selectedPlan === plan.key }"
|
||||||
@click="selectedPlan = plan.key"
|
@click="selectedPlan = plan.key"
|
||||||
>
|
>
|
||||||
<!-- 推荐标签 -->
|
<!-- 推荐角标 -->
|
||||||
<div v-if="plan.recommend" class="member-dialog__plan-recommend"><svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<div v-if="plan.recommend" class="member-dialog__plan-badge">超值推荐</div>
|
||||||
<g clip-path="url(#clip0_180_2594)">
|
|
||||||
<path d="M0.872709 4.61946C0.867714 4.56192 0.874732 4.50398 0.893317 4.44931C0.911903 4.39464 0.94165 4.34442 0.980672 4.30186C1.01969 4.25929 1.06714 4.2253 1.11999 4.20204C1.17285 4.17878 1.22996 4.16676 1.28771 4.16675H2.08333C2.19384 4.16675 2.29982 4.21065 2.37796 4.28879C2.4561 4.36693 2.5 4.47291 2.5 4.58341V8.54175C2.5 8.65225 2.4561 8.75823 2.37796 8.83637C2.29982 8.91451 2.19384 8.95841 2.08333 8.95841H1.63208C1.5278 8.95844 1.42729 8.91936 1.35042 8.84889C1.27355 8.77842 1.2259 8.68168 1.21688 8.57779L0.872709 4.61946ZM3.75 4.45321C3.75 4.27904 3.85833 4.1232 4.01563 4.04904C4.35917 3.88696 4.94438 3.56133 5.20833 3.12112C5.54854 2.55362 5.61271 1.52841 5.62313 1.29362C5.62458 1.26071 5.62375 1.22779 5.62813 1.19529C5.68458 0.788414 6.46979 1.26362 6.77083 1.76612C6.93438 2.03862 6.95521 2.39675 6.93813 2.67654C6.91958 2.97571 6.83188 3.26466 6.74583 3.55175L6.5625 4.16362H8.82438C8.88875 4.16362 8.95225 4.17853 9.0099 4.20719C9.06754 4.23585 9.11776 4.27748 9.15662 4.32881C9.19547 4.38014 9.22191 4.43977 9.23384 4.50303C9.24578 4.56629 9.2429 4.63145 9.22542 4.69341L8.10667 8.65508C8.08197 8.74245 8.02941 8.81937 7.95698 8.87413C7.88455 8.92888 7.79622 8.95848 7.70542 8.95841H4.16667C4.05616 8.95841 3.95018 8.91451 3.87204 8.83637C3.7939 8.75823 3.75 8.65225 3.75 8.54175V4.45321Z" fill="white" stroke="white" stroke-width="0.833333" stroke-linecap="round" stroke-linejoin="round"/>
|
|
||||||
</g>
|
|
||||||
<defs>
|
|
||||||
<clipPath id="clip0_180_2594">
|
|
||||||
<rect width="10" height="10" fill="white"/>
|
|
||||||
</clipPath>
|
|
||||||
</defs>
|
|
||||||
</svg>
|
|
||||||
推荐</div>
|
|
||||||
<!-- 套餐名称 -->
|
<!-- 套餐名称 -->
|
||||||
<div class="member-dialog__plan-name">{{ plan.name }}</div>
|
<div class="member-dialog__plan-name">{{ plan.name }}</div>
|
||||||
<!-- 价格行 -->
|
<!-- 价格行 -->
|
||||||
<div class="member-dialog__plan-price">
|
<div class="member-dialog__plan-price">
|
||||||
<span class="member-dialog__plan-price-symbol">¥</span>
|
<span class="member-dialog__plan-price-symbol">¥</span>
|
||||||
<span class="member-dialog__plan-price-num">{{ plan.priceInt }}</span>
|
<span class="member-dialog__plan-price-num">{{ plan.priceInt }}</span>
|
||||||
<span v-if="plan.originalPrice" class="member-dialog__plan-original-price">{{ plan.originalPrice }}</span>
|
<span v-if="plan.originalPrice" class="member-dialog__plan-original">{{ plan.originalPrice }}</span>
|
||||||
</div>
|
|
||||||
<!-- 标签描述(接口tag字段) -->
|
|
||||||
<div class="member-dialog__plan-daily mt4">{{ plan.tag }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 会员权益区域 -->
|
|
||||||
<div class="member-dialog__benefits">
|
|
||||||
<h3 class="member-dialog__benefits-title">会员权益</h3>
|
|
||||||
<div class="member-dialog__benefits-cards">
|
|
||||||
<div class="member-dialog__benefit-card">
|
|
||||||
<div class="member-dialog__benefit-icon">
|
|
||||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
|
|
||||||
<rect width="24" height="24" rx="12" fill="#EDF9FA"/>
|
|
||||||
<path d="M7 8h7v2H7V8zm0 3h10v2H7v-2zm0 3h5v2H7v-2z" fill="#52CAD1"/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<div class="member-dialog__benefit-info">
|
|
||||||
<span class="member-dialog__benefit-name">AI优化简历</span>
|
|
||||||
<span class="member-dialog__benefit-desc">享受无限次数</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="member-dialog__benefit-card">
|
|
||||||
<div class="member-dialog__benefit-icon">
|
|
||||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
|
|
||||||
<rect width="24" height="24" rx="12" fill="#EDF9FA"/>
|
|
||||||
<path d="M12 7l1.5 3 3.5.5-2.5 2.5.5 3.5L12 15l-3 1.5.5-3.5L7 10.5l3.5-.5L12 7z" fill="#52CAD1"/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<div class="member-dialog__benefit-info">
|
|
||||||
<span class="member-dialog__benefit-name">AI+投递助手</span>
|
|
||||||
<span class="member-dialog__benefit-desc">会员专享</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 标签描述 -->
|
||||||
|
<div class="member-dialog__plan-tag">{{ plan.tag }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 步骤一:选择支付方式 + 底部应付金额购买按钮(未创建订单时显示) -->
|
||||||
|
<div v-if="!showQrCode" class="member-dialog__step-pay">
|
||||||
<!-- 支付方式选择 -->
|
<!-- 支付方式选择 -->
|
||||||
<div class="member-dialog__payment">
|
<div class="member-dialog__payment-section">
|
||||||
<span class="member-dialog__payment-label">选择支付方式</span>
|
<span class="member-dialog__payment-label">选择支付方式</span>
|
||||||
<div class="member-dialog__payment-methods">
|
<div class="member-dialog__payment-methods">
|
||||||
|
<!-- 微信支付 -->
|
||||||
<div
|
<div
|
||||||
class="member-dialog__payment-item"
|
class="member-dialog__payment-item"
|
||||||
:class="{ 'member-dialog__payment-item--wechat-active': selectedPayment === 'wechat' }"
|
:class="{ 'member-dialog__payment-item--active': selectedPayment === 'wechat' }"
|
||||||
@click="selectedPayment = 'wechat'"
|
@click="selectedPayment = 'wechat'"
|
||||||
>
|
>
|
||||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
|
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M14 8c0 3.3-2.7 6-6 6s-6-2.7-6-6 2.7-6 6-6 6 2.7 6 6z" fill="#07C160"/>
|
<g clip-path="url(#clip0_2639_1996)">
|
||||||
<path d="M5.5 6.5c.5-.3 1.2-.1 1.5.4l.5 1 1.5-2c.3-.5 1-.6 1.5-.3.5.3.6 1 .3 1.5l-2.5 3.5c-.2.3-.5.4-.8.4-.3 0-.6-.1-.8-.4L5.2 8c-.3-.5-.2-1.2.3-1.5z" fill="white"/>
|
<path d="M20.8249 10.8533C21.3364 10.8533 21.8348 10.8933 22.32 10.96C21.4282 7 17.3364 4 12.4184 4C6.8446 4 2.32001 7.84 2.32001 12.5733C2.32001 15.3067 3.8282 17.72 6.17574 19.2933L4.85116 22L8.47083 20.4133C9.2446 20.6933 10.0577 20.92 10.9233 21.04C10.8053 20.52 10.7397 19.9867 10.7397 19.4267C10.7266 14.7067 15.2512 10.8533 20.8249 10.8533ZM15.7757 7.85333C15.9411 7.85333 16.1048 7.88644 16.2576 7.95077C16.4103 8.01509 16.5491 8.10938 16.666 8.22824C16.7829 8.3471 16.8757 8.4882 16.9389 8.6435C17.0022 8.7988 17.0348 8.96524 17.0348 9.13333C17.0348 9.30143 17.0022 9.46787 16.9389 9.62317C16.8757 9.77847 16.7829 9.91957 16.666 10.0384C16.5491 10.1573 16.4103 10.2516 16.2576 10.3159C16.1048 10.3802 15.9411 10.4133 15.7757 10.4133C15.4418 10.4133 15.1216 10.2785 14.8855 10.0384C14.6494 9.79838 14.5167 9.47281 14.5167 9.13333C14.5167 8.79386 14.6494 8.46828 14.8855 8.22824C15.1216 7.98819 15.4418 7.85333 15.7757 7.85333ZM9.04788 10.4267C8.71396 10.4267 8.39373 10.2918 8.15762 10.0518C7.92151 9.81172 7.78886 9.48614 7.78886 9.14667C7.78886 8.80719 7.92151 8.48162 8.15762 8.24157C8.39373 8.00152 8.71396 7.86667 9.04788 7.86667C9.38179 7.86667 9.70202 8.00152 9.93814 8.24157C10.1742 8.48162 10.3069 8.80719 10.3069 9.14667C10.3069 9.48614 10.1742 9.81172 9.93814 10.0518C9.70202 10.2918 9.38179 10.4267 9.04788 10.4267Z" fill="#07C160"/>
|
||||||
|
<path d="M29 19.6638C29 15.9818 25.1942 13 20.5 13C15.8058 13 12 15.9818 12 19.6638C12 23.3457 15.8058 26.3276 20.5 26.3276C21.2691 26.3276 22.0117 26.2239 22.7145 26.0683L27.3027 28L25.7114 24.8885C27.7005 23.6698 29 21.8029 29 19.6638ZM17.9407 19.2489C17.6889 19.2489 17.4428 19.1759 17.2335 19.0392C17.0241 18.9024 16.861 18.708 16.7646 18.4806C16.6683 18.2532 16.643 18.0029 16.6922 17.7615C16.7413 17.5201 16.8625 17.2983 17.0406 17.1243C17.2186 16.9502 17.4454 16.8317 17.6924 16.7836C17.9393 16.7356 18.1953 16.7603 18.4279 16.8545C18.6605 16.9487 18.8593 17.1082 18.9992 17.3129C19.1391 17.5175 19.2137 17.7582 19.2137 18.0043C19.227 18.6914 18.6435 19.2489 17.9407 19.2489ZM23.046 19.2489C22.7084 19.2489 22.3846 19.1178 22.1459 18.8844C21.9071 18.651 21.773 18.3344 21.773 18.0043C21.773 17.6742 21.9071 17.3577 22.1459 17.1243C22.3846 16.8909 22.7084 16.7597 23.046 16.7597C23.3836 16.7597 23.7074 16.8909 23.9462 17.1243C24.1849 17.3577 24.319 17.6742 24.319 18.0043C24.319 18.3344 24.1849 18.651 23.9462 18.8844C23.7074 19.1178 23.3836 19.2489 23.046 19.2489Z" fill="#07C160"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_2639_1996">
|
||||||
|
<rect width="32" height="32" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
<span class="member-dialog__payment-text member-dialog__payment-text--wechat">微信支付</span>
|
<span class="member-dialog__payment-text">微信支付</span>
|
||||||
|
<!-- 选中圆圈 -->
|
||||||
|
<div class="member-dialog__payment-radio">
|
||||||
|
<div v-if="selectedPayment === 'wechat'" class="member-dialog__payment-radio-inner"></div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 支付宝支付 -->
|
||||||
<div
|
<div
|
||||||
class="member-dialog__payment-item"
|
class="member-dialog__payment-item"
|
||||||
:class="{ 'member-dialog__payment-item--alipay-active': selectedPayment === 'alipay' }"
|
:class="{ 'member-dialog__payment-item--active': selectedPayment === 'alipay' }"
|
||||||
@click="selectedPayment = 'alipay'"
|
@click="selectedPayment = 'alipay'"
|
||||||
>
|
>
|
||||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
|
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<rect width="16" height="16" rx="3" fill="#1677FF"/>
|
<g clip-path="url(#clip0_2639_2002)">
|
||||||
<text x="4" y="12" fill="white" font-size="10" font-weight="bold">支</text>
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.4127 4.03125C17.5281 4.03125 17.6226 4.12374 17.6226 4.23954V7.82858H25.2414C25.3583 7.82858 25.4488 7.92605 25.4492 8.0431C25.4496 8.79249 25.2601 9.75641 24.8287 9.75641H17.623V12.2974H22.8164C23.0565 12.2974 23.2477 12.5015 23.2303 12.7419L23.2267 12.7891C23.2051 15.6153 22.2698 18.4489 20.7417 20.9244L21.0142 21.0439C23.4297 22.0928 26.0812 22.9505 29.3624 23.0535C29.7298 23.0652 30.0163 23.3761 29.9993 23.7449L29.9929 23.8687C29.8888 25.7353 29.3682 28.0312 27.4979 28.0312C27.2227 28.0312 26.9576 28.014 26.7016 27.9808C24.2628 27.6909 21.8177 26.1933 19.3166 24.526L18.775 24.1633L18.3641 23.8868C17.6939 24.5493 16.9634 25.1524 16.1769 25.6805C15.9834 25.8062 15.779 25.9218 15.5652 26.0275C13.5181 27.2551 11.1213 27.9891 8.45844 27.9895C4.76459 27.9895 2.05466 25.5465 2.00081 22.4783L2 22.3858L2.00081 22.3325C2.05288 19.2583 4.65006 16.8441 8.34497 16.7956L8.45841 16.7949C11.6748 16.7949 14.2916 17.8455 16.9109 19.0864L16.9248 19.0984L16.978 18.9897C17.6426 17.6065 18.1167 16.0147 18.3135 14.2254L8.16359 14.2252C8.10869 14.2252 8.05603 14.2033 8.01716 14.1645C7.97829 14.1256 7.95638 14.0728 7.95622 14.0178C7.95497 13.333 8.14369 12.2974 8.57666 12.2974H13.6419V9.75641H5.99781C5.88084 9.75641 5.79044 9.65934 5.79044 9.54188C5.79 8.83332 5.97956 7.82858 6.41087 7.82858H13.6419V5.79663L13.6428 5.73444C13.6712 4.76532 14.3841 4.03125 17.4127 4.03125ZM8.028 19.3837C5.69156 19.3837 3.76147 20.6349 3.71934 22.3791L3.71875 22.4185L3.72122 22.5201C3.72714 22.6636 3.74369 22.8064 3.77072 22.9475C4.40375 25.9708 10.6506 27.0115 15.1562 21.801L14.9053 21.6531C12.6859 20.3584 10.4044 19.3837 8.028 19.3837Z" fill="#1677FF"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_2639_2002">
|
||||||
|
<rect width="32" height="32" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
<span class="member-dialog__payment-text member-dialog__payment-text--alipay">支付宝支付</span>
|
<span class="member-dialog__payment-text">支付宝支付</span>
|
||||||
|
<!-- 选中圆圈 -->
|
||||||
|
<div class="member-dialog__payment-radio">
|
||||||
|
<div v-if="selectedPayment === 'alipay'" class="member-dialog__payment-radio-inner"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 购买按钮 -->
|
<!-- 底部栏:步骤一显示应付金额+购买按钮,步骤二显示二维码+已支付 -->
|
||||||
|
<div class="member-dialog__bottom-bar" :class="{ 'member-dialog__bottom-bar--qrcode': showQrCode }">
|
||||||
|
<!-- 步骤一:应付金额 + 购买按钮 -->
|
||||||
|
<template v-if="!showQrCode">
|
||||||
|
<div class="member-dialog__footer-price">
|
||||||
|
<span class="member-dialog__footer-price-label">应付金额</span>
|
||||||
|
<span class="member-dialog__footer-price-symbol">¥</span>
|
||||||
|
<span class="member-dialog__footer-price-num">{{ currentPlan.priceInt }}</span>
|
||||||
|
</div>
|
||||||
<button
|
<button
|
||||||
class="member-dialog__buy-btn"
|
class="member-dialog__buy-btn"
|
||||||
:class="{ 'member-dialog__buy-btn--active': selectedPayment }"
|
:disabled="!selectedPayment"
|
||||||
@click="handleBuy"
|
@click="handleBuy"
|
||||||
>购买会员</button>
|
>购买会员</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
</div>
|
<!-- 步骤二:扫码支付区域 -->
|
||||||
</div>
|
<template v-else>
|
||||||
|
<!-- 二维码 -->
|
||||||
<!-- ==================== 扫码支付弹窗 ==================== -->
|
<div class="member-dialog__qrcode-box">
|
||||||
<div v-if="showQrCode" class="member-dialog-overlay member-dialog-overlay--qrcode" @click="handleCloseQrCode">
|
<!-- 支付宝:iframe 渲染 -->
|
||||||
<div class="member-dialog member-dialog--qrcode" @click.stop>
|
|
||||||
|
|
||||||
<!-- 顶部标题行 -->
|
|
||||||
<div class="member-dialog__header">
|
|
||||||
<div class="member-dialog__header-left">
|
|
||||||
<h2 class="member-dialog__title">扫码支付</h2>
|
|
||||||
</div>
|
|
||||||
<div class="member-dialog__header-right">
|
|
||||||
<span class="member-dialog__close" @click="handleCloseQrCode">✕</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 二维码区域 -->
|
|
||||||
<div class="member-dialog__qrcode-content">
|
|
||||||
<!-- 支付宝:iframe 渲染支付表单 -->
|
|
||||||
<div v-if="selectedPayment === 'alipay' && paymentFormHtml" class="member-dialog__qrcode-image">
|
|
||||||
<iframe
|
<iframe
|
||||||
|
v-if="selectedPayment === 'alipay' && paymentFormHtml"
|
||||||
:srcdoc="paymentFormHtml"
|
:srcdoc="paymentFormHtml"
|
||||||
frameborder="0"
|
frameborder="0"
|
||||||
class="member-dialog__payment-iframe"
|
class="member-dialog__qrcode-iframe qrcode-zhifubao"
|
||||||
scrolling="auto"
|
scrolling="auto"
|
||||||
></iframe>
|
></iframe>
|
||||||
</div>
|
<!-- 微信:qrcode.js 渲染 -->
|
||||||
<!-- 微信:使用 qrcode.js 渲染二维码 -->
|
|
||||||
<div v-if="selectedPayment === 'wechat' && wechatCodeUrl" class="member-dialog__qrcode-image">
|
|
||||||
<iframe
|
<iframe
|
||||||
|
v-if="selectedPayment === 'wechat' && wechatCodeUrl"
|
||||||
:srcdoc="wechatQrHtml"
|
:srcdoc="wechatQrHtml"
|
||||||
frameborder="0"
|
frameborder="0"
|
||||||
class="member-dialog__wechat-qr-iframe"
|
class="member-dialog__qrcode-iframe qrcode-wechat"
|
||||||
scrolling="no"
|
scrolling="no"
|
||||||
></iframe>
|
></iframe>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 右侧信息 -->
|
||||||
<!-- 金额和提示 -->
|
<div class="member-dialog__qrcode-info">
|
||||||
<div class="member-dialog__qrcode-price-row">
|
<div class="member-dialog__qrcode-price-row">
|
||||||
<span class="member-dialog__qrcode-price">¥{{ currentPlan.priceInt }}</span>
|
<span class="member-dialog__qrcode-price-num">¥{{ currentPlan.priceInt }}</span>
|
||||||
<span class="member-dialog__qrcode-tip">扫码完成支付</span>
|
<span class="member-dialog__qrcode-tip">扫码完成支付</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 协议提示 -->
|
|
||||||
<p class="member-dialog__qrcode-agreement">
|
<p class="member-dialog__qrcode-agreement">
|
||||||
开通即代表同意 <a href="javascript:;" @click.prevent="openMemberAgreement">《会员服务协议》</a>
|
开通即代表同意 <a href="javascript:;" @click.prevent="openMemberAgreement">《会员服务协议》</a>
|
||||||
</p>
|
</p>
|
||||||
|
<!-- 已支付成功按钮 -->
|
||||||
|
<button class="member-dialog__paid-btn" @click="handleConfirmPaid">我已支付成功</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 已支付成功按钮 -->
|
|
||||||
<button class="member-dialog__paid-btn" @click="handleConfirmPaid">已支付成功</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -203,19 +250,14 @@ const store = useStore()
|
|||||||
|
|
||||||
// ==================== 类型定义 ====================
|
// ==================== 类型定义 ====================
|
||||||
|
|
||||||
/** 套餐项类型(包含后端完整数据 + 前端展示字段) */
|
/** 套餐项类型 */
|
||||||
interface PlanItem {
|
interface PlanItem {
|
||||||
key: string
|
key: string
|
||||||
name: string
|
name: string
|
||||||
/** 整数价格(元),用于显示 */
|
|
||||||
priceInt: string
|
priceInt: string
|
||||||
/** 划线价(元) */
|
|
||||||
originalPrice: string
|
originalPrice: string
|
||||||
/** 标签描述(接口tag字段,如"轻量体验"、"低至¥0.56/天") */
|
|
||||||
tag: string
|
tag: string
|
||||||
/** 是否推荐 */
|
|
||||||
recommend?: boolean
|
recommend?: boolean
|
||||||
/** 后端原始数据,下单时使用 */
|
|
||||||
raw: MemberProduct
|
raw: MemberProduct
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,22 +266,22 @@ interface PlanItem {
|
|||||||
/** 当前选中的套餐 key */
|
/** 当前选中的套餐 key */
|
||||||
const selectedPlan = ref('')
|
const selectedPlan = ref('')
|
||||||
|
|
||||||
/** 当前选中的支付方式(wechat / alipay),默认不选 */
|
/** 当前选中的支付方式 */
|
||||||
const selectedPayment = ref('')
|
const selectedPayment = ref('')
|
||||||
|
|
||||||
/** 是否显示扫码支付弹窗 */
|
/** 是否显示扫码支付区域 */
|
||||||
const showQrCode = ref(false)
|
const showQrCode = ref(false)
|
||||||
|
|
||||||
/** 支付宝表单 HTML(用于 iframe 渲染) */
|
/** 支付宝表单 HTML */
|
||||||
const paymentFormHtml = ref('')
|
const paymentFormHtml = ref('')
|
||||||
|
|
||||||
/** 微信支付 code_url(用于生成二维码) */
|
/** 微信支付 code_url */
|
||||||
const wechatCodeUrl = ref('')
|
const wechatCodeUrl = ref('')
|
||||||
|
|
||||||
/** 微信二维码 iframe 的 srcdoc HTML */
|
/** 微信二维码 iframe srcdoc */
|
||||||
const wechatQrHtml = computed(() => {
|
const wechatQrHtml = computed(() => {
|
||||||
if (!wechatCodeUrl.value) return ''
|
if (!wechatCodeUrl.value) return ''
|
||||||
return `<!DOCTYPE html><html><head><meta charset="UTF-8"><script src="https://cdn.jsdelivr.net/npm/qrcodejs@1.0.0/qrcode.min.js"><\/script><style>body{display:flex;align-items:center;justify-content:center;margin:0;height:100%;}</style></head><body><div id="qrcode"></div><script>new QRCode(document.getElementById("qrcode"),{text:"${wechatCodeUrl.value}",width:210,height:210,colorDark:"#000000",colorLight:"#ffffff",correctLevel:QRCode.CorrectLevel.H});<\/script></body></html>`
|
return `<!DOCTYPE html><html><head><meta charset="UTF-8"><script src="https://cdn.jsdelivr.net/npm/qrcodejs@1.0.0/qrcode.min.js"><\/script><style>body{display:flex;align-items:center;justify-content:center;margin:0;height:100%;}</style></head><body><div id="qrcode"></div><script>new QRCode(document.getElementById("qrcode"),{text:"${wechatCodeUrl.value}",width:160,height:160,colorDark:"#000000",colorLight:"#ffffff",correctLevel:QRCode.CorrectLevel.H});<\/script></body></html>`
|
||||||
})
|
})
|
||||||
|
|
||||||
/** 当前订单ID */
|
/** 当前订单ID */
|
||||||
@@ -248,12 +290,12 @@ const orderId = ref('')
|
|||||||
/** 是否正在创建订单 */
|
/** 是否正在创建订单 */
|
||||||
const creatingOrder = ref(false)
|
const creatingOrder = ref(false)
|
||||||
|
|
||||||
/** 协议预览弹窗显示状态 */
|
/** 协议预览弹窗 */
|
||||||
const showAgreementDialog = ref(false)
|
const showAgreementDialog = ref(false)
|
||||||
|
|
||||||
// ==================== 监听 ====================
|
// ==================== 监听 ====================
|
||||||
|
|
||||||
/** 监听弹窗开关 — 打开时锁定背景滚动,关闭时恢复并重置状态 */
|
/** 监听弹窗开关 */
|
||||||
watch(() => props.modelValue, (val) => {
|
watch(() => props.modelValue, (val) => {
|
||||||
document.body.style.overflow = val ? 'hidden' : ''
|
document.body.style.overflow = val ? 'hidden' : ''
|
||||||
if (!val) {
|
if (!val) {
|
||||||
@@ -274,18 +316,14 @@ const currentPlan = computed(() => {
|
|||||||
|
|
||||||
// ==================== 数据 ====================
|
// ==================== 数据 ====================
|
||||||
|
|
||||||
/** 套餐列表(从接口获取) */
|
/** 套餐列表 */
|
||||||
const plans = ref<PlanItem[]>([])
|
const plans = ref<PlanItem[]>([])
|
||||||
|
|
||||||
/** 将后端商品数据转换为前端套餐项 */
|
/** 后端商品数据转换 */
|
||||||
function mapProductToPlan(product: MemberProduct): PlanItem {
|
function mapProductToPlan(product: MemberProduct): PlanItem {
|
||||||
// 分转元,直接除以100不四舍五入
|
|
||||||
const priceYuan = product.price / 100
|
const priceYuan = product.price / 100
|
||||||
const originalPriceYuan = product.originalPrice ? product.originalPrice / 100 : 0
|
const originalPriceYuan = product.originalPrice ? product.originalPrice / 100 : 0
|
||||||
// 直接使用接口返回的 productName 作为套餐名称
|
|
||||||
const name = product.productName
|
const name = product.productName
|
||||||
|
|
||||||
// 价格显示:如果是整数就不显示小数,否则保留实际小数
|
|
||||||
const priceDisplay = Number.isInteger(priceYuan) ? String(priceYuan) : priceYuan.toFixed(2)
|
const priceDisplay = Number.isInteger(priceYuan) ? String(priceYuan) : priceYuan.toFixed(2)
|
||||||
const originalDisplay = originalPriceYuan > priceYuan
|
const originalDisplay = originalPriceYuan > priceYuan
|
||||||
? `¥${Number.isInteger(originalPriceYuan) ? originalPriceYuan : originalPriceYuan.toFixed(2)}`
|
? `¥${Number.isInteger(originalPriceYuan) ? originalPriceYuan : originalPriceYuan.toFixed(2)}`
|
||||||
@@ -309,7 +347,6 @@ async function loadMemberProducts() {
|
|||||||
if (res.data && res.data.length) {
|
if (res.data && res.data.length) {
|
||||||
const sorted = [...res.data].sort((a, b) => a.sortOrder - b.sortOrder)
|
const sorted = [...res.data].sort((a, b) => a.sortOrder - b.sortOrder)
|
||||||
plans.value = sorted.map(mapProductToPlan)
|
plans.value = sorted.map(mapProductToPlan)
|
||||||
// 默认选中推荐套餐(季卡),若无则选第一个
|
|
||||||
const featured = plans.value.find(p => p.recommend)
|
const featured = plans.value.find(p => p.recommend)
|
||||||
selectedPlan.value = featured ? featured.key : plans.value[0].key
|
selectedPlan.value = featured ? featured.key : plans.value[0].key
|
||||||
}
|
}
|
||||||
@@ -318,7 +355,6 @@ async function loadMemberProducts() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 组件挂载时加载商品列表 */
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadMemberProducts()
|
loadMemberProducts()
|
||||||
})
|
})
|
||||||
@@ -352,8 +388,6 @@ async function handleBuy() {
|
|||||||
wechatCodeUrl.value = ''
|
wechatCodeUrl.value = ''
|
||||||
}
|
}
|
||||||
showQrCode.value = true
|
showQrCode.value = true
|
||||||
// 【注释掉自动轮询,后续如需恢复取消注释即可】
|
|
||||||
// confirmPaymentPolling()
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('创建订单失败', e)
|
console.error('创建订单失败', e)
|
||||||
@@ -362,67 +396,18 @@ async function handleBuy() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// /** 轮询计时器 */
|
/** 点击"我已支付成功"按钮 */
|
||||||
// let pollTimer: ReturnType<typeof setInterval> | null = null
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * 自动轮询查询订单支付状态(已关闭,保留逻辑防止后续要用)
|
|
||||||
// * 支付成功后自动关闭弹窗并刷新会员状态
|
|
||||||
// */
|
|
||||||
// async function confirmPaymentPolling() {
|
|
||||||
// const startTime = Date.now()
|
|
||||||
// const timeout = 5 * 60 * 1000 // 5分钟超时
|
|
||||||
// const interval = 500
|
|
||||||
//
|
|
||||||
// if (pollTimer) {
|
|
||||||
// clearInterval(pollTimer)
|
|
||||||
// pollTimer = null
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// pollTimer = setInterval(async () => {
|
|
||||||
// try {
|
|
||||||
// const res = await fetchOrderDetail(orderId.value)
|
|
||||||
// const status = res.data?.status
|
|
||||||
//
|
|
||||||
// if (status === 1) {
|
|
||||||
// clearInterval(pollTimer!)
|
|
||||||
// pollTimer = null
|
|
||||||
// showQrCode.value = false
|
|
||||||
// ElMessage.success('开通成功')
|
|
||||||
// emit('update:modelValue', false)
|
|
||||||
// store.dispatch('loadMemberStatus')
|
|
||||||
// } else if (status === 2 || status === 3) {
|
|
||||||
// clearInterval(pollTimer!)
|
|
||||||
// pollTimer = null
|
|
||||||
// showQrCode.value = false
|
|
||||||
// ElMessage.error('支付未成功,请重新下单')
|
|
||||||
// } else if (Date.now() - startTime >= timeout) {
|
|
||||||
// clearInterval(pollTimer!)
|
|
||||||
// pollTimer = null
|
|
||||||
// showQrCode.value = false
|
|
||||||
// ElMessage.error('支付超时,请重新下单')
|
|
||||||
// }
|
|
||||||
// } catch (e) {
|
|
||||||
// console.error('查询订单状态失败', e)
|
|
||||||
// }
|
|
||||||
// }, interval)
|
|
||||||
// }
|
|
||||||
|
|
||||||
/** 点击"已支付成功"按钮 — 手动查询一次订单状态 */
|
|
||||||
async function handleConfirmPaid() {
|
async function handleConfirmPaid() {
|
||||||
if (!orderId.value) return
|
if (!orderId.value) return
|
||||||
try {
|
try {
|
||||||
const res = await fetchOrderDetail(orderId.value)
|
const res = await fetchOrderDetail(orderId.value)
|
||||||
const status = res.data?.status
|
const status = res.data?.status
|
||||||
if (status === 1) {
|
if (status === 1) {
|
||||||
// 支付成功 — 关闭弹窗,刷新会员状态
|
|
||||||
showQrCode.value = false
|
showQrCode.value = false
|
||||||
ElMessage.success('开通成功')
|
ElMessage.success('开通成功')
|
||||||
emit('update:modelValue', false)
|
emit('update:modelValue', false)
|
||||||
// 刷新 vuex 中的会员状态
|
|
||||||
store.dispatch('loadMemberStatus')
|
store.dispatch('loadMemberStatus')
|
||||||
} else {
|
} else {
|
||||||
// 未支付成功
|
|
||||||
ElMessage.warning('未查询到支付订单,请再次确认')
|
ElMessage.warning('未查询到支付订单,请再次确认')
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -431,11 +416,6 @@ async function handleConfirmPaid() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 关闭扫码支付弹窗 */
|
|
||||||
function handleCloseQrCode() {
|
|
||||||
showQrCode.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 打开会员服务协议 */
|
/** 打开会员服务协议 */
|
||||||
function openMemberAgreement() {
|
function openMemberAgreement() {
|
||||||
showAgreementDialog.value = true
|
showAgreementDialog.value = true
|
||||||
|
|||||||