生成定制简历部分默认优化选项全选
This commit is contained in:
+14
-2
@@ -435,6 +435,16 @@ export interface SkillGapResume {
|
|||||||
targetPosition: string
|
targetPosition: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 技能差距分析 — 差距项 */
|
||||||
|
export interface SkillGapItem {
|
||||||
|
/** 关键词 */
|
||||||
|
keyword: string
|
||||||
|
/** 差距标题 */
|
||||||
|
title: string
|
||||||
|
/** 差距描述 */
|
||||||
|
description: string
|
||||||
|
}
|
||||||
|
|
||||||
/** 技能差距分析返回数据 */
|
/** 技能差距分析返回数据 */
|
||||||
export interface SkillGapData {
|
export interface SkillGapData {
|
||||||
/** 匹配度分数 */
|
/** 匹配度分数 */
|
||||||
@@ -443,8 +453,10 @@ export interface SkillGapData {
|
|||||||
job: SkillGapJob
|
job: SkillGapJob
|
||||||
/** 简历信息 */
|
/** 简历信息 */
|
||||||
resume: SkillGapResume
|
resume: SkillGapResume
|
||||||
/** 缺少的技能列表 */
|
/** 缺少的技能列表(兼容旧版) */
|
||||||
missingSkills: string[]
|
missingSkills?: string[]
|
||||||
|
/** 差距分析列表(新版) */
|
||||||
|
gaps?: SkillGapItem[]
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -232,7 +232,7 @@
|
|||||||
background: $btn-dark;
|
background: $btn-dark;
|
||||||
color: $bg-white;
|
color: $bg-white;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 0.24rem;
|
border-radius: 0.08rem;
|
||||||
font-size: 0.15rem;
|
font-size: 0.15rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -274,7 +274,6 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 0.5rem;
|
|
||||||
margin-bottom: 0.02rem;
|
margin-bottom: 0.02rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,34 +281,44 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.08rem;
|
gap: 0.08rem;
|
||||||
font-size: 0.13rem;
|
font-size: 0.14rem;
|
||||||
color: $text-light;
|
font-weight: 600;
|
||||||
|
color: $text-middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__step--active {
|
&__step--active {
|
||||||
color: $text-dark;
|
color: $text-dark;
|
||||||
font-weight: 600;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__step-num {
|
&__step-num {
|
||||||
width: 0.22rem;
|
width: 0.32rem;
|
||||||
height: 0.22rem;
|
height: 0.32rem;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: $bg-main;
|
background: $bg-main;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-size: 0.11rem;
|
font-size: 0.14rem;
|
||||||
font-weight: 600;
|
font-weight: 450;
|
||||||
|
color: $text-middle;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__step--active &__step-num {
|
&__step--active &__step-num {
|
||||||
background: $text-dark;
|
background: $accent;
|
||||||
color: $bg-white;
|
color: $bg-white;
|
||||||
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 差距分析头部 ====================
|
// 步骤之间的连接横线
|
||||||
|
&__step-line {
|
||||||
|
width: 0.935rem;
|
||||||
|
height: 0.02rem;
|
||||||
|
background: #E5E7EB;
|
||||||
|
margin: 0 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 差距分析头部(新版) ====================
|
||||||
&__gap-header {
|
&__gap-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
@@ -323,28 +332,24 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__gap-title {
|
&__gap-title {
|
||||||
font-size: 0.2rem;
|
font-size: 0.24rem;
|
||||||
font-weight: 700;
|
font-weight: 630;
|
||||||
color: $text-dark;
|
color: $text-dark;
|
||||||
margin: 0 0 0.1rem 0;
|
margin: 0 0 0.08rem 0;
|
||||||
line-height: 1.3;
|
line-height: 0.32rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__gap-warn {
|
// 匹配度高亮文字(品牌色)
|
||||||
display: flex;
|
&__gap-title-highlight {
|
||||||
align-items: flex-start;
|
color: #FE6D52;
|
||||||
gap: 0.06rem;
|
|
||||||
font-size: 0.12rem;
|
|
||||||
color: $text-middle;
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__warn-icon {
|
&__gap-subtitle {
|
||||||
width: 0.14rem;
|
font-size: 0.14rem;
|
||||||
height: 0.14rem;
|
font-weight: 330;
|
||||||
flex-shrink: 0;
|
|
||||||
margin-top: 0.02rem;
|
|
||||||
color: $text-middle;
|
color: $text-middle;
|
||||||
|
margin: 0;
|
||||||
|
line-height: 0.19rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__gap-score-area {
|
&__gap-score-area {
|
||||||
@@ -355,170 +360,184 @@
|
|||||||
margin-left: 0.2rem;
|
margin-left: 0.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 对比卡片表格 ====================
|
// 匹配度分数圆环
|
||||||
&__gap-table {
|
&__score-circle {
|
||||||
margin-bottom: 0.36rem;
|
position: relative;
|
||||||
|
width: 0.72rem;
|
||||||
|
height: 0.72rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__score-svg {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__score-num {
|
||||||
|
font-size: 0.24rem;
|
||||||
|
font-weight: 630;
|
||||||
|
color: $accent;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 匹配度标签(底部黑底白字)
|
||||||
|
&__score-tag {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
font-weight: 330;
|
||||||
|
color: $bg-white;
|
||||||
|
background: $text-dark;
|
||||||
|
border-radius: 0.04rem;
|
||||||
|
padding: 0.02rem 0.08rem;
|
||||||
|
margin-top: -0.1rem;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 通用区域标题 ====================
|
||||||
|
&__section {
|
||||||
|
margin-bottom: 0.28rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__section-title {
|
||||||
|
font-size: 0.18rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $text-dark;
|
||||||
|
margin: 0 0 0.16rem 0;
|
||||||
|
line-height: 0.24rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 简历选择下拉框 ====================
|
||||||
|
&__resume-select-box {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0.12rem 0.16rem;
|
||||||
|
background: $bg-main;
|
||||||
|
border-radius: 0.12rem;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
width: 1.6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__resume-select-name {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $text-middle;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__resume-select-arrow {
|
||||||
|
width: 0.14rem;
|
||||||
|
height: 0.14rem;
|
||||||
|
color: $text-middle;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-left: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 岗位概览卡片 ====================
|
||||||
|
&__overview-card {
|
||||||
|
border: 1px solid #F0F0F0;
|
||||||
|
border-radius: 0.12rem;
|
||||||
|
padding: 0.16rem 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__overview-title {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $text-dark;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
margin-bottom: 0.04rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__overview-sub {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
font-weight: 400;
|
||||||
|
color: $text-middle;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
margin-bottom: 0.08rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__overview-tags {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.04rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__overview-tag {
|
||||||
|
font-size: 0.12rem;
|
||||||
|
font-weight: 400;
|
||||||
|
color: $text-middle;
|
||||||
|
background: $bg-main;
|
||||||
|
border-radius: 0.04rem;
|
||||||
|
padding: 0.04rem 0.06rem;
|
||||||
|
line-height: 0.18rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 差距分析列表 ====================
|
||||||
|
&__gap-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.06rem;
|
gap: 0.13rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__gap-row {
|
&__gap-item {
|
||||||
display: flex;
|
|
||||||
gap: 0.06rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__gap-cell {
|
|
||||||
flex: 1;
|
|
||||||
padding: 0.18rem 0.16rem;
|
|
||||||
font-size: 0.13rem;
|
|
||||||
color: $text-dark;
|
|
||||||
background: $bg-main;
|
|
||||||
border-radius: 0.08rem;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
min-height: 0.6rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__gap-cell--label {
|
|
||||||
flex: 0 0 1.2rem;
|
|
||||||
font-weight: 600;
|
|
||||||
justify-content: flex-start;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__gap-cell-title {
|
|
||||||
font-size: 0.18rem;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 关键词列横跨两列
|
|
||||||
&__gap-cell--keywords {
|
|
||||||
flex: 2.06;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 概览行岗位信息
|
|
||||||
&__gap-job-info {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
padding: 0.16rem 0.2rem;
|
||||||
|
border: 1px solid #F0F0F0;
|
||||||
|
border-radius: 0.12rem;
|
||||||
gap: 0.12rem;
|
gap: 0.12rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__gap-company-icon {
|
// 序号圆圈
|
||||||
width: 0.36rem;
|
&__gap-item-num {
|
||||||
height: 0.36rem;
|
width: 0.32rem;
|
||||||
border-radius: 0.06rem;
|
height: 0.32rem;
|
||||||
background: $bg-white;
|
border-radius: 50%;
|
||||||
|
background: $accent;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
|
||||||
|
|
||||||
&__gap-company-logo {
|
span {
|
||||||
width: 100%;
|
font-size: 0.14rem;
|
||||||
height: 100%;
|
font-weight: 600;
|
||||||
border-radius: 0.06rem;
|
color: $bg-white;
|
||||||
object-fit: cover;
|
line-height: 0.19rem;
|
||||||
}
|
|
||||||
|
|
||||||
&__gap-company-svg {
|
|
||||||
width: 0.2rem;
|
|
||||||
height: 0.2rem;
|
|
||||||
color: $text-dark;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__gap-job-text {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 0.04rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__gap-job-title {
|
|
||||||
font-size: 0.14rem;
|
|
||||||
font-weight: 600;
|
|
||||||
color: $text-dark;
|
|
||||||
line-height: 1.2;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__gap-job-sub {
|
|
||||||
font-size: 0.11rem;
|
|
||||||
color: $text-light;
|
|
||||||
line-height: 1.2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 岗位名称/简历目标值
|
|
||||||
&__gap-value {
|
|
||||||
font-size: 0.14rem;
|
|
||||||
font-weight: 500;
|
|
||||||
color: $text-dark;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==================== 简历选择器 ====================
|
|
||||||
&__resume-selector {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
width: 100%;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__resume-info {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__resume-file-icon {
|
|
||||||
width: 0.2rem;
|
|
||||||
height: 0.2rem;
|
|
||||||
color: $text-dark;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__resume-text {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 0.02rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__resume-label {
|
|
||||||
font-size: 0.1rem;
|
|
||||||
color: $text-light;
|
|
||||||
line-height: 1.2;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__resume-name {
|
|
||||||
font-size: 0.12rem;
|
|
||||||
color: $text-dark;
|
|
||||||
font-weight: 500;
|
|
||||||
line-height: 1.2;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__resume-select-btn {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.04rem;
|
|
||||||
background: $bg-white;
|
|
||||||
border: 1px solid $border-color;
|
|
||||||
border-radius: 0.14rem;
|
|
||||||
padding: 0.05rem 0.12rem;
|
|
||||||
font-size: 0.11rem;
|
|
||||||
color: $text-dark;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.2s;
|
|
||||||
white-space: nowrap;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
border-color: $accent;
|
|
||||||
color: $accent;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__dropdown-arrow {
|
&__gap-item-content {
|
||||||
width: 0.1rem;
|
flex: 1;
|
||||||
height: 0.1rem;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__gap-item-title {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
font-weight: 520;
|
||||||
|
color: $text-dark;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
margin-bottom: 0.04rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__gap-item-desc {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
font-weight: 330;
|
||||||
|
color: $text-middle;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 简历下拉选项(通用) ====================
|
||||||
|
|
||||||
&__resume-dropdown {
|
&__resume-dropdown {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 100%;
|
top: 100%;
|
||||||
@@ -551,67 +570,80 @@
|
|||||||
background: $theme-color;
|
background: $theme-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 岗位关键词标签 ====================
|
// ==================== 步骤三:定制简历(v2 新版上下布局) ====================
|
||||||
&__gap-keywords {
|
|
||||||
|
// 定制简历整体容器(纵向布局)
|
||||||
|
&__custom-v2 {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-direction: column;
|
||||||
|
gap: 0.32rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 每个区块
|
||||||
|
&__custom-section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 区块头部(标题+描述)
|
||||||
|
&__custom-section-header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
gap: 0.08rem;
|
gap: 0.08rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__gap-kw-tag {
|
// 区块标题
|
||||||
font-size: 0.12rem;
|
&__custom-section-title {
|
||||||
background: $text-middle;
|
font-size: 0.18rem;
|
||||||
color: $bg-white;
|
font-weight: 600;
|
||||||
border-radius: 0.04rem;
|
color: #101828;
|
||||||
padding: 0.04rem 0.12rem;
|
margin: 0;
|
||||||
line-height: 1.2;
|
line-height: 0.24rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 步骤三:定制简历 ====================
|
// 区块描述
|
||||||
|
&__custom-section-desc {
|
||||||
// 定制简历左右两栏布局
|
font-size: 0.14rem;
|
||||||
&__custom {
|
font-weight: 400;
|
||||||
display: flex;
|
color: #99A1AF;
|
||||||
gap: 0.16rem;
|
margin: 0;
|
||||||
height: 100%;
|
line-height: 0.19rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 左右面板
|
// 卡片选项列表
|
||||||
&__custom-panel {
|
&__custom-cards {
|
||||||
flex: 1;
|
|
||||||
background: $bg-main;
|
|
||||||
border-radius: 0.12rem;
|
|
||||||
padding: 0.28rem 0.24rem;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 面板标题
|
|
||||||
&__custom-panel-title {
|
|
||||||
font-size: 0.17rem;
|
|
||||||
font-weight: 700;
|
|
||||||
color: $text-dark;
|
|
||||||
margin: 0 0 0.24rem 0;
|
|
||||||
line-height: 1.2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 选项列表
|
|
||||||
&__custom-options {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.2rem;
|
gap: 0.13rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 单个复选框行
|
// 单个选项卡片
|
||||||
&__custom-checkbox {
|
&__custom-card {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
padding: 0.16rem 0.2rem;
|
||||||
gap: 0.1rem;
|
gap: 0.1rem;
|
||||||
|
border: 1px solid #F0F0F0;
|
||||||
|
border-radius: 0.12rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: relative;
|
transition: all 0.2s;
|
||||||
|
background: $bg-white;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: transparent;
|
||||||
|
background: #F3F4F6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选中态:无背景填充,仅品牌色边框
|
||||||
|
&__custom-card--checked {
|
||||||
|
border-color: #52CAD1;
|
||||||
|
background: $bg-white;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 隐藏原生 checkbox
|
// 隐藏原生 checkbox
|
||||||
&__custom-input {
|
&__custom-card-input {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
width: 0;
|
width: 0;
|
||||||
@@ -619,63 +651,91 @@
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 自定义复选框样式
|
// 圆形复选框容器
|
||||||
&__custom-checkmark {
|
&__custom-card-check {
|
||||||
width: 0.18rem;
|
width: 0.2rem;
|
||||||
height: 0.18rem;
|
height: 0.2rem;
|
||||||
border: 1.5px solid $border-color;
|
|
||||||
border-radius: 0.04rem;
|
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
transition: all 0.2s;
|
|
||||||
background: $bg-white;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 选中态
|
// 圆形复选框SVG
|
||||||
&__custom-input:checked + &__custom-checkmark {
|
&__custom-card-check-svg {
|
||||||
background: $accent;
|
width: 0.2rem;
|
||||||
border-color: $accent;
|
height: 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
&::after {
|
// 文字内容区域
|
||||||
content: '';
|
&__custom-card-text {
|
||||||
display: block;
|
display: flex;
|
||||||
width: 0.05rem;
|
align-items: center;
|
||||||
height: 0.09rem;
|
gap: 0.12rem;
|
||||||
border: solid $bg-white;
|
flex: 1;
|
||||||
border-width: 0 2px 2px 0;
|
min-width: 0;
|
||||||
transform: rotate(45deg);
|
}
|
||||||
margin-top: -0.04rem;
|
|
||||||
|
// 选项主文字(加粗)
|
||||||
|
&__custom-card-label {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1A1A1A;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选项说明文字(灰色小字)
|
||||||
|
&__custom-card-tip {
|
||||||
|
font-size: 0.12rem;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #6A7282;
|
||||||
|
line-height: 0.16rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 底部双按钮布局(上一步 + 下一步) ====================
|
||||||
|
&__footer-btns {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.24rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 上一步按钮(品牌色边框 + 品牌色文字)
|
||||||
|
&__prev-btn {
|
||||||
|
flex: 1;
|
||||||
|
height: 0.45rem;
|
||||||
|
background: $bg-white;
|
||||||
|
border: 1px solid #52CAD1;
|
||||||
|
border-radius: 0.12rem;
|
||||||
|
font-size: 0.14rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #52CAD1;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #F6FCFC;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 选项文字
|
// 下一步按钮(品牌色填充 + 白色文字)
|
||||||
&__custom-label {
|
&__next-btn {
|
||||||
|
flex: 1;
|
||||||
|
height: 0.45rem;
|
||||||
|
background: #52CAD1;
|
||||||
|
border: none;
|
||||||
|
border-radius: 0.12rem;
|
||||||
font-size: 0.14rem;
|
font-size: 0.14rem;
|
||||||
color: $text-dark;
|
font-weight: 600;
|
||||||
line-height: 1.2;
|
color: $bg-white;
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 问号提示触发器
|
|
||||||
&__custom-tooltip-trigger {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin-left: 0.04rem;
|
|
||||||
//cursor: help;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
transition: background 0.2s;
|
||||||
|
|
||||||
// 问号图标
|
|
||||||
&__custom-tooltip-icon {
|
|
||||||
width: 0.15rem;
|
|
||||||
height: 0.15rem;
|
|
||||||
color: $text-light;
|
|
||||||
transition: color 0.2s;
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: $text-middle;
|
background: #47b8bf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -704,7 +764,6 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.12rem;
|
gap: 0.12rem;
|
||||||
padding: 0.2rem 0.1rem;
|
padding: 0.2rem 0.1rem;
|
||||||
border-bottom: 1px solid $border-color;
|
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -731,23 +790,75 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 步骤四:返回按钮 ====================
|
// ==================== 步骤四:返回按钮 ====================
|
||||||
&__back-btn {
|
// 顶部下载简历按钮区域
|
||||||
|
&__top-download {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0.7rem;
|
top: 0.7rem;
|
||||||
left: 0.2rem;
|
left: 0.2rem;
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__top-download-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.04rem;
|
||||||
|
width: 1.04rem;
|
||||||
|
height: 0.36rem;
|
||||||
background: $bg-white;
|
background: $bg-white;
|
||||||
border: 1px solid $border-color;
|
border: 1px solid #52CAD1;
|
||||||
border-radius: 0.2rem;
|
border-radius: 0.08rem;
|
||||||
padding: 0.06rem 0.2rem;
|
|
||||||
font-size: 0.13rem;
|
font-size: 0.13rem;
|
||||||
color: $text-dark;
|
font-weight: 500;
|
||||||
|
color: #52CAD1;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #F6FCFC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__top-download-icon {
|
||||||
|
width: 0.14rem;
|
||||||
|
height: 0.14rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 顶部下载下拉菜单(向下弹出)
|
||||||
|
&__top-download-menu {
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
left: 0;
|
||||||
|
margin-top: 0.06rem;
|
||||||
|
width: 1.04rem;
|
||||||
|
background: $bg-white;
|
||||||
|
border: 1px solid $border-color;
|
||||||
|
border-radius: 0.08rem;
|
||||||
|
box-shadow: 0 0.04rem 0.12rem rgba(0, 0, 0, 0.1);
|
||||||
|
overflow: hidden;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__top-download-option {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.1rem 0;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
color: $text-dark;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: center;
|
||||||
|
transition: background 0.15s;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: $bg-main;
|
background: $bg-main;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
& + & {
|
||||||
|
border-top: 1px solid $border-color;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 步骤四:预览布局 ====================
|
// ==================== 步骤四:预览布局 ====================
|
||||||
@@ -1217,6 +1328,24 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 步骤三底部:上一步按钮(品牌色边框样式)
|
||||||
|
&__footer-prev-btn {
|
||||||
|
flex: 1;
|
||||||
|
height: 0.48rem;
|
||||||
|
background: $bg-white;
|
||||||
|
border: 1px solid #52CAD1;
|
||||||
|
border-radius: 0.08rem;
|
||||||
|
font-size: 0.15rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #52CAD1;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #F6FCFC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 立即去投递按钮
|
// 立即去投递按钮
|
||||||
&__submit-btn {
|
&__submit-btn {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
@@ -1224,7 +1353,7 @@
|
|||||||
background: $btn-dark;
|
background: $btn-dark;
|
||||||
color: $bg-white;
|
color: $bg-white;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 0.24rem;
|
border-radius: 0.08rem;
|
||||||
font-size: 0.15rem;
|
font-size: 0.15rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__tab-item {
|
&__tab-item {
|
||||||
font-size: 0.14rem;
|
font-size: 0.18rem;
|
||||||
color: $text-middle;
|
color: $text-middle;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding-bottom: 0.06rem;
|
padding-bottom: 0.06rem;
|
||||||
@@ -86,7 +86,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__card-title {
|
&__card-title {
|
||||||
font-size: 0.16rem;
|
font-size: 0.20rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: $text-dark;
|
color: $text-dark;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|||||||
@@ -638,8 +638,12 @@
|
|||||||
background: #FBFDF7;
|
background: #FBFDF7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&--medium {
|
||||||
|
background: #FFFBF5;
|
||||||
|
}
|
||||||
|
|
||||||
&--low {
|
&--low {
|
||||||
background: #FBFDF7;
|
background: #FFF6F5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -686,13 +690,22 @@
|
|||||||
color: #9FD051;
|
color: #9FD051;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 中匹配度颜色
|
||||||
|
&__job-match--medium &__match-score {
|
||||||
|
color: #F59E0B;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__job-match--medium &__match-level {
|
||||||
|
color: #F59E0B;
|
||||||
|
}
|
||||||
|
|
||||||
// 低匹配度颜色
|
// 低匹配度颜色
|
||||||
&__job-match--low &__match-score {
|
&__job-match--low &__match-score {
|
||||||
color: #9FD051;
|
color: #FE6D52;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__job-match--low &__match-level {
|
&__job-match--low &__match-level {
|
||||||
color: #9FD051;
|
color: #FE6D52;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 未登录锁定态
|
// 未登录锁定态
|
||||||
|
|||||||
@@ -22,18 +22,16 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } 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 { fetchFavoriteCount, fetchApplyCount } from '@/api/jobs'
|
||||||
|
|
||||||
// ==================== Props & Emits ====================
|
// ==================== Props & Emits ====================
|
||||||
|
|
||||||
/** activeTab: 当前激活的 Tab key,由父组件通过 v-model 传入 */
|
/** activeTab: 当前激活的 Tab key,由父组件通过 v-model 传入 */
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
activeTab: string
|
activeTab: string
|
||||||
/** 收藏总数,由父组件传入 */
|
|
||||||
favoriteCount?: number
|
|
||||||
/** 投递总数,由父组件传入 */
|
|
||||||
applyCount?: number
|
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
/** 双向绑定事件,在 Jobs 页面内切换 Tab 时触发 */
|
/** 双向绑定事件,在 Jobs 页面内切换 Tab 时触发 */
|
||||||
@@ -45,14 +43,58 @@ const emit = defineEmits<{
|
|||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
const store = useStore()
|
||||||
|
|
||||||
|
/** 登录状态 */
|
||||||
|
const isAuthenticated = computed(() => store.state.isAuthenticated)
|
||||||
|
|
||||||
|
// ==================== 收藏 & 投递统计 ====================
|
||||||
|
|
||||||
|
/** 收藏总数 */
|
||||||
|
const favoriteTotal = ref(0)
|
||||||
|
|
||||||
|
/** 投递总数 */
|
||||||
|
const applyTotal = ref(0)
|
||||||
|
|
||||||
|
/** 加载收藏统计 */
|
||||||
|
async function loadFavoriteCount() {
|
||||||
|
try {
|
||||||
|
const res = await fetchFavoriteCount()
|
||||||
|
if (res.code === '0' && res.data) {
|
||||||
|
favoriteTotal.value = res.data.totalCount
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('加载收藏统计失败', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 加载投递统计 */
|
||||||
|
async function loadApplyCount() {
|
||||||
|
try {
|
||||||
|
const res = await fetchApplyCount()
|
||||||
|
if (res.code === '0' && res.data) {
|
||||||
|
applyTotal.value = res.data.totalCount
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('加载投递统计失败', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 组件挂载时请求收藏和投递统计 */
|
||||||
|
onMounted(() => {
|
||||||
|
if (isAuthenticated.value) {
|
||||||
|
loadFavoriteCount()
|
||||||
|
loadApplyCount()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// ==================== 常量数据 ====================
|
// ==================== 常量数据 ====================
|
||||||
|
|
||||||
/** Tab 选项列表,count 用于显示圆形徽章计数 */
|
/** Tab 选项列表,count 用于显示圆形徽章计数 */
|
||||||
const tabs = computed(() => [
|
const tabs = computed(() => [
|
||||||
{ key: 'recommend', label: '推荐', count: undefined },
|
{ key: 'recommend', label: '推荐', count: undefined },
|
||||||
{ key: 'collected', label: '收藏', count: props.favoriteCount ?? 0 },
|
{ key: 'collected', label: '收藏', count: favoriteTotal.value },
|
||||||
{ key: 'applied', label: '已投递', count: props.applyCount ?? 0 },
|
{ key: 'applied', label: '已投递', count: applyTotal.value },
|
||||||
])
|
])
|
||||||
|
|
||||||
// ==================== 事件处理 ====================
|
// ==================== 事件处理 ====================
|
||||||
|
|||||||
@@ -12,148 +12,168 @@
|
|||||||
</button>
|
</button>
|
||||||
<h2 class="job-resume-custom-dialog__drawer-title">生成你的岗位专属简历</h2>
|
<h2 class="job-resume-custom-dialog__drawer-title">生成你的岗位专属简历</h2>
|
||||||
</div>
|
</div>
|
||||||
<!-- 返回按钮(步骤四显示) -->
|
<!-- 下载简历按钮(步骤三显示,位于步骤指示器上方) -->
|
||||||
<button v-if="currentStep === 4" class="job-resume-custom-dialog__back-btn mt10" @click="goToStep(3)">返回</button>
|
<div v-if="currentStep === 4" class="job-resume-custom-dialog__top-download mt10">
|
||||||
|
<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 }">
|
||||||
<span class="job-resume-custom-dialog__step-num">1</span><span>差距分析</span>
|
<span class="job-resume-custom-dialog__step-num">1</span><span>差距分析</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="job-resume-custom-dialog__step-line"></div>
|
||||||
<div class="job-resume-custom-dialog__step" :class="{ 'job-resume-custom-dialog__step--active': currentStep === 3 }">
|
<div class="job-resume-custom-dialog__step" :class="{ 'job-resume-custom-dialog__step--active': currentStep === 3 }">
|
||||||
<span class="job-resume-custom-dialog__step-num">2</span><span>定制简历</span>
|
<span class="job-resume-custom-dialog__step-num">2</span><span>定制简历</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="job-resume-custom-dialog__step-line"></div>
|
||||||
<div class="job-resume-custom-dialog__step" :class="{ 'job-resume-custom-dialog__step--active': currentStep === 4 }">
|
<div class="job-resume-custom-dialog__step" :class="{ 'job-resume-custom-dialog__step--active': currentStep === 4 }">
|
||||||
<span class="job-resume-custom-dialog__step-num">3</span><span>简历预览</span>
|
<span class="job-resume-custom-dialog__step-num">3</span><span>简历预览</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 抽屉内容区(可滚动) -->
|
<!-- 抽屉内容区(可滚动) -->
|
||||||
<div class="job-resume-custom-dialog__drawer-body">
|
<div class="job-resume-custom-dialog__drawer-body">
|
||||||
<!-- 步骤二:差距分析 -->
|
<!-- 步骤一:差距分析 -->
|
||||||
<template v-if="currentStep === 2">
|
<template v-if="currentStep === 2">
|
||||||
|
<!-- 匹配度标题区域 -->
|
||||||
<div class="job-resume-custom-dialog__gap-header">
|
<div class="job-resume-custom-dialog__gap-header">
|
||||||
<div class="job-resume-custom-dialog__gap-left">
|
<div class="job-resume-custom-dialog__gap-left">
|
||||||
<h3 class="job-resume-custom-dialog__gap-title">你的简历与该岗位的匹配度{{ isLowMatch ? '较低' : '较高' }}</h3>
|
<h3 class="job-resume-custom-dialog__gap-title">你的简历与该岗位的<span class="job-resume-custom-dialog__gap-title-highlight">匹配度{{ isLowMatch ? '较低' : '较高' }}</span></h3>
|
||||||
<div v-if="isLowMatch" class="job-resume-custom-dialog__gap-warn">
|
<p class="job-resume-custom-dialog__gap-subtitle">匹配度低于 6.0 分的简历,在筛选环节可能会被优先淘汰。我们会帮你快速优化提升。</p>
|
||||||
<svg viewBox="0 0 16 16" fill="none" class="job-resume-custom-dialog__warn-icon"><circle cx="8" cy="8" r="7" stroke="currentColor" stroke-width="1.2"/><path d="M8 5v3M8 10.5v.5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>
|
|
||||||
<span>匹配度低于 6.0 分的简历,在筛选环节可能会被优先淘汰。我们会帮你快速优化提升。</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 右侧匹配度分数 -->
|
||||||
<div class="job-resume-custom-dialog__gap-score-area">
|
<div class="job-resume-custom-dialog__gap-score-area">
|
||||||
<div class="job-resume-custom-dialog__match-ring">
|
<div class="job-resume-custom-dialog__score-circle">
|
||||||
<svg viewBox="0 0 60 60" class="job-resume-custom-dialog__ring-svg"><circle cx="30" cy="30" r="24" stroke-width="4" stroke="#E8E8E8" fill="none" opacity="0.3"/><circle cx="30" cy="30" r="24" stroke-width="4" fill="none" stroke="#4FC2C9" stroke-linecap="round" :stroke-dasharray="2*Math.PI*24" :stroke-dashoffset="2*Math.PI*24*(1-jobInfo.matchScore/10)" transform="rotate(-90 30 30)"/></svg>
|
<svg viewBox="0 0 72 72" class="job-resume-custom-dialog__score-svg">
|
||||||
<span class="job-resume-custom-dialog__match-score">{{ jobInfo.matchScore }}</span>
|
<circle cx="36" cy="36" r="32" stroke-width="5" stroke="rgba(82,202,209,0.2)" fill="none"/>
|
||||||
|
<circle cx="36" cy="36" r="32" stroke-width="5" fill="none" stroke="#52CAD1" stroke-linecap="round" :stroke-dasharray="2*Math.PI*32" :stroke-dashoffset="2*Math.PI*32*(1-jobInfo.matchScore/10)" transform="rotate(-90 36 36)"/>
|
||||||
|
</svg>
|
||||||
|
<span class="job-resume-custom-dialog__score-num">{{ jobInfo.matchScore }}</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="job-resume-custom-dialog__match-label">{{ matchLevelText }}</span>
|
<span class="job-resume-custom-dialog__score-tag">{{ matchLevelText }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 对比卡片表格 -->
|
|
||||||
<div class="job-resume-custom-dialog__gap-table">
|
<!-- 简历选择 -->
|
||||||
<!-- 第一行:概览 -->
|
<div class="job-resume-custom-dialog__section">
|
||||||
<div class="job-resume-custom-dialog__gap-row">
|
<h4 class="job-resume-custom-dialog__section-title">简历选择</h4>
|
||||||
<!-- 标签列 -->
|
<div class="job-resume-custom-dialog__resume-select-box" @click="toggleResumeDropdown">
|
||||||
<div class="job-resume-custom-dialog__gap-cell job-resume-custom-dialog__gap-cell--label">
|
<span class="job-resume-custom-dialog__resume-select-name">{{ selectedResume.name }}</span>
|
||||||
<span class="job-resume-custom-dialog__gap-cell-title">概览</span>
|
<svg viewBox="0 0 14 14" fill="none" class="job-resume-custom-dialog__resume-select-arrow"><path d="M4 6l3 3 3-3" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||||
</div>
|
<!-- 简历下拉 -->
|
||||||
<!-- 岗位信息列 -->
|
<div v-if="showResumeDropdown" class="job-resume-custom-dialog__resume-dropdown">
|
||||||
<div class="job-resume-custom-dialog__gap-cell">
|
<div v-for="r in resumeList" :key="r.id" class="job-resume-custom-dialog__resume-option" :class="{'job-resume-custom-dialog__resume-option--active': r.id === selectedResume.id}" @click.stop="selectResume(r)">{{ r.name }}</div>
|
||||||
<div class="job-resume-custom-dialog__gap-job-info">
|
|
||||||
<div class="job-resume-custom-dialog__gap-company-icon">
|
|
||||||
<img v-if="jobInfo.companyLogoUrl" :src="jobInfo.companyLogoUrl" :alt="jobInfo.company" class="job-resume-custom-dialog__gap-company-logo" />
|
|
||||||
<svg v-else viewBox="0 0 24 24" fill="none" class="job-resume-custom-dialog__gap-company-svg"><rect x="3" y="3" width="7" height="7" rx="1" stroke="currentColor" stroke-width="1.2"/><rect x="14" y="3" width="7" height="7" rx="1" stroke="currentColor" stroke-width="1.2"/><rect x="3" y="14" width="7" height="7" rx="1" stroke="currentColor" stroke-width="1.2"/><rect x="14" y="14" width="7" height="7" rx="1" stroke="currentColor" stroke-width="1.2"/></svg>
|
|
||||||
</div>
|
|
||||||
<div class="job-resume-custom-dialog__gap-job-text">
|
|
||||||
<span class="job-resume-custom-dialog__gap-job-title">{{ jobInfo.title }}</span>
|
|
||||||
<span class="job-resume-custom-dialog__gap-job-sub">{{ jobInfo.location }} · {{ jobInfo.company }} 独角兽</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- 简历选择列 -->
|
|
||||||
<div class="job-resume-custom-dialog__gap-cell">
|
|
||||||
<div class="job-resume-custom-dialog__resume-selector">
|
|
||||||
<div class="job-resume-custom-dialog__resume-info">
|
|
||||||
<svg viewBox="0 0 24 24" fill="none" class="job-resume-custom-dialog__resume-file-icon"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8l-6-6z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/><path d="M14 2v6h6" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/></svg>
|
|
||||||
<div class="job-resume-custom-dialog__resume-text">
|
|
||||||
<span class="job-resume-custom-dialog__resume-label">你的简历</span>
|
|
||||||
<span class="job-resume-custom-dialog__resume-name">{{ selectedResume.name }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button class="job-resume-custom-dialog__resume-select-btn" @click="toggleResumeDropdown">选择 <svg viewBox="0 0 12 12" fill="none" class="job-resume-custom-dialog__dropdown-arrow"><path d="M3 5l3 3 3-3" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/></svg></button>
|
|
||||||
<div v-if="showResumeDropdown" class="job-resume-custom-dialog__resume-dropdown">
|
|
||||||
<div v-for="r in resumeList" :key="r.id" class="job-resume-custom-dialog__resume-option" :class="{'job-resume-custom-dialog__resume-option--active': r.id === selectedResume.id}" @click="selectResume(r)">{{ r.name }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 第二行:岗位名称 -->
|
</div>
|
||||||
<div class="job-resume-custom-dialog__gap-row">
|
|
||||||
<div class="job-resume-custom-dialog__gap-cell job-resume-custom-dialog__gap-cell--label">
|
<!-- 岗位概览 -->
|
||||||
<span>岗位名称</span>
|
<div class="job-resume-custom-dialog__section">
|
||||||
|
<h4 class="job-resume-custom-dialog__section-title">岗位概览</h4>
|
||||||
|
<div class="job-resume-custom-dialog__overview-card">
|
||||||
|
<div class="job-resume-custom-dialog__overview-title">{{ jobInfo.company }} · {{ jobInfo.title }}</div>
|
||||||
|
<div class="job-resume-custom-dialog__overview-sub">{{ jobInfo.location }} · {{ jobInfo.company }}</div>
|
||||||
|
<div class="job-resume-custom-dialog__overview-tags">
|
||||||
|
<span v-for="kw in jobInfo.keywords" :key="kw" class="job-resume-custom-dialog__overview-tag">{{ kw }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="job-resume-custom-dialog__gap-cell">
|
|
||||||
<span class="job-resume-custom-dialog__gap-value">{{ jobInfo.title }}</span>
|
|
||||||
</div>
|
|
||||||
<!-- <div class="job-resume-custom-dialog__gap-cell">
|
|
||||||
<span class="job-resume-custom-dialog__gap-value">{{ selectedResume.targetJob || '—' }}</span>
|
|
||||||
</div> -->
|
|
||||||
</div>
|
</div>
|
||||||
<!-- 第三行:岗位关键词 -->
|
</div>
|
||||||
<div class="job-resume-custom-dialog__gap-row">
|
|
||||||
<div class="job-resume-custom-dialog__gap-cell job-resume-custom-dialog__gap-cell--label">
|
<!-- 差距分析列表 -->
|
||||||
<span>岗位关键词</span>
|
<div class="job-resume-custom-dialog__section">
|
||||||
</div>
|
<h4 class="job-resume-custom-dialog__section-title">差距分析</h4>
|
||||||
<div class="job-resume-custom-dialog__gap-cell job-resume-custom-dialog__gap-cell--keywords">
|
<div class="job-resume-custom-dialog__gap-list">
|
||||||
<div class="job-resume-custom-dialog__gap-keywords">
|
<div v-for="(gap, idx) in gapItems" :key="idx" class="job-resume-custom-dialog__gap-item">
|
||||||
<span v-for="kw in jobInfo.keywords" :key="kw" class="job-resume-custom-dialog__gap-kw-tag">{{ kw }}</span>
|
<div class="job-resume-custom-dialog__gap-item-num">
|
||||||
|
<span>{{ idx + 1 }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="job-resume-custom-dialog__gap-item-content">
|
||||||
|
<div class="job-resume-custom-dialog__gap-item-title">{{ gap.title }}</div>
|
||||||
|
<div class="job-resume-custom-dialog__gap-item-desc">{{ gap.description }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<!-- 步骤三:定制简历 -->
|
<!-- 步骤二:定制简历 -->
|
||||||
<template v-if="currentStep === 3">
|
<template v-if="currentStep === 3">
|
||||||
<div class="job-resume-custom-dialog__custom">
|
<div class="job-resume-custom-dialog__custom-v2">
|
||||||
<!-- 左侧:选择要优化的部分 -->
|
<!-- 第一部分:选择你要优化的部分 -->
|
||||||
<div class="job-resume-custom-dialog__custom-panel">
|
<div class="job-resume-custom-dialog__custom-section">
|
||||||
<h3 class="job-resume-custom-dialog__custom-panel-title">1.选择你要优化的部分</h3>
|
<div class="job-resume-custom-dialog__custom-section-header">
|
||||||
<div class="job-resume-custom-dialog__custom-options">
|
<h3 class="job-resume-custom-dialog__custom-section-title">选择你要优化的部分</h3>
|
||||||
<label v-for="item in optimizeSections" :key="item.key" class="job-resume-custom-dialog__custom-checkbox">
|
<p class="job-resume-custom-dialog__custom-section-desc">选择后,系统会基于岗位要求自动重写对应模块,提升简历通过初筛的概率</p>
|
||||||
<input type="checkbox" v-model="item.checked" class="job-resume-custom-dialog__custom-input" />
|
</div>
|
||||||
<span class="job-resume-custom-dialog__custom-checkmark"></span>
|
<div class="job-resume-custom-dialog__custom-cards">
|
||||||
<span class="job-resume-custom-dialog__custom-label">{{ item.label }}</span>
|
<label
|
||||||
<!-- 技能和工作经验的问号提示(使用 el-tooltip) -->
|
v-for="item in optimizeSections"
|
||||||
<el-tooltip
|
:key="item.key"
|
||||||
v-if="item.tooltip"
|
class="job-resume-custom-dialog__custom-card"
|
||||||
:content="item.tooltip"
|
:class="{ 'job-resume-custom-dialog__custom-card--checked': item.checked }"
|
||||||
placement="right"
|
>
|
||||||
:show-arrow="true"
|
<input type="checkbox" v-model="item.checked" class="job-resume-custom-dialog__custom-card-input" />
|
||||||
:popper-options="{ strategy: 'fixed' }"
|
<!-- 自定义复选框圆形 -->
|
||||||
effect="dark"
|
<span class="job-resume-custom-dialog__custom-card-check">
|
||||||
>
|
<svg v-if="item.checked" viewBox="0 0 20 20" fill="none" class="job-resume-custom-dialog__custom-card-check-svg">
|
||||||
<span class="job-resume-custom-dialog__custom-tooltip-trigger">
|
<circle cx="10" cy="10" r="10" fill="#52CAD1"/>
|
||||||
<svg viewBox="0 0 16 16" fill="none" class="job-resume-custom-dialog__custom-tooltip-icon">
|
<path d="M6 10.5l2.5 2.5 5.5-5.5" stroke="#fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
<circle cx="8" cy="8" r="7" stroke="currentColor" stroke-width="1.2"/>
|
</svg>
|
||||||
<path d="M6.5 6.5a1.5 1.5 0 112.12 1.37c-.42.18-.62.5-.62.88V9.5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/>
|
<svg v-else viewBox="0 0 20 20" fill="none" class="job-resume-custom-dialog__custom-card-check-svg">
|
||||||
<circle cx="8" cy="11.5" r="0.6" fill="currentColor"/>
|
<circle cx="10" cy="10" r="9.33" stroke="#6A7282" stroke-width="1.33"/>
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
</el-tooltip>
|
<!-- 文字内容 -->
|
||||||
|
<span class="job-resume-custom-dialog__custom-card-text">
|
||||||
|
<span class="job-resume-custom-dialog__custom-card-label">{{ item.label }}</span>
|
||||||
|
<span v-if="item.tooltip" class="job-resume-custom-dialog__custom-card-tip">{{ item.tooltip }}</span>
|
||||||
|
</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 右侧:选择要新增的技能关键词 -->
|
<!-- 第二部分:选择你要新增的技能关键词 -->
|
||||||
<div class="job-resume-custom-dialog__custom-panel">
|
<div class="job-resume-custom-dialog__custom-section">
|
||||||
<h3 class="job-resume-custom-dialog__custom-panel-title">2.选择你要新增的技能关键词</h3>
|
<div class="job-resume-custom-dialog__custom-section-header">
|
||||||
<div class="job-resume-custom-dialog__custom-options">
|
<h3 class="job-resume-custom-dialog__custom-section-title">选择你要新增的技能关键词</h3>
|
||||||
<label v-for="skill in newSkillOptions" :key="skill.name" class="job-resume-custom-dialog__custom-checkbox">
|
<p class="job-resume-custom-dialog__custom-section-desc">关键词会被自然融入经历描述中,避免生硬堆砌</p>
|
||||||
<input type="checkbox" v-model="skill.checked" class="job-resume-custom-dialog__custom-input" />
|
</div>
|
||||||
<span class="job-resume-custom-dialog__custom-checkmark"></span>
|
<div class="job-resume-custom-dialog__custom-cards">
|
||||||
<span class="job-resume-custom-dialog__custom-label">{{ skill.name }}</span>
|
<label
|
||||||
|
v-for="skill in newSkillOptions"
|
||||||
|
:key="skill.name"
|
||||||
|
class="job-resume-custom-dialog__custom-card"
|
||||||
|
:class="{ 'job-resume-custom-dialog__custom-card--checked': skill.checked }"
|
||||||
|
>
|
||||||
|
<input type="checkbox" v-model="skill.checked" class="job-resume-custom-dialog__custom-card-input" />
|
||||||
|
<!-- 自定义复选框圆形 -->
|
||||||
|
<span class="job-resume-custom-dialog__custom-card-check">
|
||||||
|
<svg v-if="skill.checked" viewBox="0 0 20 20" fill="none" class="job-resume-custom-dialog__custom-card-check-svg">
|
||||||
|
<circle cx="10" cy="10" r="10" fill="#52CAD1"/>
|
||||||
|
<path d="M6 10.5l2.5 2.5 5.5-5.5" stroke="#fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
<svg v-else viewBox="0 0 20 20" fill="none" class="job-resume-custom-dialog__custom-card-check-svg">
|
||||||
|
<circle cx="10" cy="10" r="9.33" stroke="#6A7282" stroke-width="1.33"/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<!-- 文字内容 -->
|
||||||
|
<span class="job-resume-custom-dialog__custom-card-text">
|
||||||
|
<span class="job-resume-custom-dialog__custom-card-label">{{ skill.name }}</span>
|
||||||
|
</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<!-- 步骤四:预览 -->
|
<!-- 步骤三:简历预览 -->
|
||||||
<template v-if="currentStep === 4">
|
<template v-if="currentStep === 4">
|
||||||
<div class="job-resume-custom-dialog__preview">
|
<div class="job-resume-custom-dialog__preview">
|
||||||
<!-- 左侧:简历模板预览(支持差异对比模式) -->
|
<!-- 左侧:简历模板预览(支持差异对比模式) -->
|
||||||
@@ -280,18 +300,22 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- 抽屉底部按钮 -->
|
<!-- 抽屉底部按钮 -->
|
||||||
<div v-if="currentStep < 4" class="job-resume-custom-dialog__drawer-footer">
|
<div v-if="currentStep < 4" class="job-resume-custom-dialog__drawer-footer">
|
||||||
<button class="job-resume-custom-dialog__primary-btn" @click="handleDrawerNext">立即定制简历</button>
|
<!-- 步骤二(定制简历):上一步 + 下一步 -->
|
||||||
</div>
|
<template v-if="currentStep === 3">
|
||||||
<!-- 步骤四专属底部:下载简历 + 立即去投递 -->
|
<div class="job-resume-custom-dialog__footer-btns">
|
||||||
<div v-if="currentStep === 4" class="job-resume-custom-dialog__preview-footer mt10 pt30">
|
<button class="job-resume-custom-dialog__prev-btn" @click="goToStep(2)">上一步</button>
|
||||||
<!-- 左侧:下载简历按钮(带下拉) -->
|
<button class="job-resume-custom-dialog__next-btn" @click="handleDrawerNext">下一步</button>
|
||||||
<div class="job-resume-custom-dialog__download-wrap">
|
|
||||||
<button class="job-resume-custom-dialog__download-btn" @click="toggleDownloadMenu">下载简历</button>
|
|
||||||
<div v-if="showDownloadMenu" class="job-resume-custom-dialog__download-menu">
|
|
||||||
<button class="job-resume-custom-dialog__download-option" @click="handleDownload('pdf')">下载PDF</button>
|
|
||||||
<button class="job-resume-custom-dialog__download-option" @click="handleDownload('word')">下载Word</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</template>
|
||||||
|
<!-- 步骤一(差距分析):立即定制简历 -->
|
||||||
|
<template v-else>
|
||||||
|
<button class="job-resume-custom-dialog__primary-btn" @click="handleDrawerNext">立即定制简历</button>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<!-- 步骤三专属底部:下载简历 + 立即去投递 -->
|
||||||
|
<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__submit-btn" @click="handleSubmit">立即去投递</button>
|
<button class="job-resume-custom-dialog__submit-btn" @click="handleSubmit">立即去投递</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -318,7 +342,7 @@ import JobResumeTemplate from '@/components/JobResumeTemplate.vue'
|
|||||||
import JobResumeCustomEditPanel from '@/components/JobResumeCustomEditPanel.vue'
|
import JobResumeCustomEditPanel from '@/components/JobResumeCustomEditPanel.vue'
|
||||||
import type { ResumeTemplateData } from '@/components/JobResumeTemplate.vue'
|
import type { ResumeTemplateData } from '@/components/JobResumeTemplate.vue'
|
||||||
import { exportResumePdf, exportResumeWord } from '@/utils/resumeExport'
|
import { exportResumePdf, exportResumeWord } from '@/utils/resumeExport'
|
||||||
import { fetchResumeList } from '@/api/resume'
|
import { fetchResumeList, setDefaultResume } from '@/api/resume'
|
||||||
import type { ResumeListItem } from '@/api/resume'
|
import type { ResumeListItem } from '@/api/resume'
|
||||||
import { fetchCustomizeResume, generateCustomizeResume, aiEditResume, rollbackCustomizeResume } from '@/api/jobs'
|
import { fetchCustomizeResume, generateCustomizeResume, aiEditResume, rollbackCustomizeResume } from '@/api/jobs'
|
||||||
import type { CustomizeResumeData, AiEditChatMessage } from '@/api/jobs'
|
import type { CustomizeResumeData, AiEditChatMessage } from '@/api/jobs'
|
||||||
@@ -334,6 +358,13 @@ interface ResumeOption {
|
|||||||
targetJob: string
|
targetJob: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 差距分析项 */
|
||||||
|
interface GapItem {
|
||||||
|
keyword: string
|
||||||
|
title: string
|
||||||
|
description: string
|
||||||
|
}
|
||||||
|
|
||||||
/** 岗位信息 */
|
/** 岗位信息 */
|
||||||
interface JobInfo {
|
interface JobInfo {
|
||||||
title: string
|
title: string
|
||||||
@@ -344,6 +375,8 @@ interface JobInfo {
|
|||||||
missingSkills: string[]
|
missingSkills: string[]
|
||||||
keywords: string[]
|
keywords: string[]
|
||||||
sourceUrl: string
|
sourceUrl: string
|
||||||
|
/** 差距分析列表(来自 skill-gap 接口) */
|
||||||
|
gaps: GapItem[]
|
||||||
/** 默认简历信息(来自 skill-gap 接口) */
|
/** 默认简历信息(来自 skill-gap 接口) */
|
||||||
defaultResume: { resumeId: string; resumeName: string; targetPosition: string } | null
|
defaultResume: { resumeId: string; resumeName: string; targetPosition: string } | null
|
||||||
}
|
}
|
||||||
@@ -400,6 +433,9 @@ const matchLevelText = computed(() => {
|
|||||||
/** 是否为低匹配度(低于6分) */
|
/** 是否为低匹配度(低于6分) */
|
||||||
const isLowMatch = computed(() => props.jobInfo.matchScore < 6)
|
const isLowMatch = computed(() => props.jobInfo.matchScore < 6)
|
||||||
|
|
||||||
|
/** 差距分析列表(来自 jobInfo.gaps) */
|
||||||
|
const gapItems = computed(() => props.jobInfo.gaps || [])
|
||||||
|
|
||||||
/** 跳转到指定步骤 */
|
/** 跳转到指定步骤 */
|
||||||
function goToStep(step: number) {
|
function goToStep(step: number) {
|
||||||
// 从步骤4返回步骤3时,清理步骤4的状态数据(避免下次进入被旧数据影响)
|
// 从步骤4返回步骤3时,清理步骤4的状态数据(避免下次进入被旧数据影响)
|
||||||
@@ -440,6 +476,11 @@ async function handleDrawerNext() {
|
|||||||
initSkillOptions()
|
initSkillOptions()
|
||||||
currentStep.value++
|
currentStep.value++
|
||||||
} else if (currentStep.value === 3) {
|
} else if (currentStep.value === 3) {
|
||||||
|
// 校验:至少勾选一个优化部分
|
||||||
|
if (selectedSectionKeys.value.length === 0) {
|
||||||
|
ElMessage.warning('请选择你要优化的部分')
|
||||||
|
return
|
||||||
|
}
|
||||||
// 步骤3 → 步骤4:先调用定制简历接口
|
// 步骤3 → 步骤4:先调用定制简历接口
|
||||||
await fetchAndLoadCustomResume()
|
await fetchAndLoadCustomResume()
|
||||||
} else {
|
} else {
|
||||||
@@ -576,7 +617,7 @@ function handleClose() {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ==================== 定制简历选项(步骤三) ====================
|
// ==================== 定制简历选项(步骤一) ====================
|
||||||
|
|
||||||
/** 优化部分选项 */
|
/** 优化部分选项 */
|
||||||
interface OptimizeSection {
|
interface OptimizeSection {
|
||||||
@@ -594,19 +635,19 @@ interface SkillOption {
|
|||||||
|
|
||||||
/** 左侧:可优化的简历部分 */
|
/** 左侧:可优化的简历部分 */
|
||||||
const optimizeSections = ref<OptimizeSection[]>([
|
const optimizeSections = ref<OptimizeSection[]>([
|
||||||
{ key: 'summary', label: '个人概述', checked: false },
|
{ key: 'summary', label: '个人概述', checked: true },
|
||||||
{ key: 'skills', label: '技能', checked: false, tooltip: '我们将把您勾选的技能补充进简历的技能模块。这对于简历能否通过ATS关键词筛选至关重要。' },
|
{ key: 'skills', label: '技能', checked: true, tooltip: '我们将把您勾选的技能补充进简历的技能模块。这对于简历能否通过ATS关键词筛选至关重要。' },
|
||||||
{ key: 'experience', label: '工作经验', checked: false, tooltip: '我们将把您选择的技能融入工作经历中,并对关键词进行润色,最大程度提升简历与岗位的匹配度。' },
|
{ key: 'experience', label: '工作经验', checked: true, tooltip: '我们将把您选择的技能融入工作经历中,并对关键词进行润色,最大程度提升简历与岗位的匹配度。' },
|
||||||
])
|
])
|
||||||
|
|
||||||
/** 右侧:可新增的技能关键词 */
|
/** 右侧:可新增的技能关键词 */
|
||||||
const newSkillOptions = ref<SkillOption[]>([])
|
const newSkillOptions = ref<SkillOption[]>([])
|
||||||
|
|
||||||
/** 根据缺失技能初始化技能选项 */
|
/** 根据缺失技能初始化技能选项(默认全选) */
|
||||||
function initSkillOptions() {
|
function initSkillOptions() {
|
||||||
newSkillOptions.value = missingSkills.value.map(skill => ({
|
newSkillOptions.value = missingSkills.value.map(skill => ({
|
||||||
name: skill,
|
name: skill,
|
||||||
checked: false,
|
checked: true,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -620,7 +661,7 @@ const selectedNewSkills = computed(() =>
|
|||||||
newSkillOptions.value.filter(s => s.checked).map(s => s.name)
|
newSkillOptions.value.filter(s => s.checked).map(s => s.name)
|
||||||
)
|
)
|
||||||
|
|
||||||
// ==================== 简历选择(步骤二) ====================
|
// ==================== 简历选择(步骤一) ====================
|
||||||
|
|
||||||
/** 简历列表(从接口获取) */
|
/** 简历列表(从接口获取) */
|
||||||
const resumeList = ref<ResumeOption[]>([])
|
const resumeList = ref<ResumeOption[]>([])
|
||||||
@@ -680,13 +721,17 @@ function toggleResumeDropdown() {
|
|||||||
showResumeDropdown.value = !showResumeDropdown.value
|
showResumeDropdown.value = !showResumeDropdown.value
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 选择简历 */
|
/** 选择简历并设为默认 */
|
||||||
function selectResume(r: ResumeOption) {
|
function selectResume(r: ResumeOption) {
|
||||||
selectedResume.value = r
|
selectedResume.value = r
|
||||||
showResumeDropdown.value = false
|
showResumeDropdown.value = false
|
||||||
|
// 调用设为默认简历接口
|
||||||
|
setDefaultResume(r.id).catch(e => {
|
||||||
|
console.error('[JobResumeCustomDialog] 设为默认简历失败', e)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 步骤四:预览相关 ====================
|
// ==================== 步骤一:预览相关 ====================
|
||||||
|
|
||||||
/** 简历模板组件引用 */
|
/** 简历模板组件引用 */
|
||||||
const resumeTemplateRef = ref()
|
const resumeTemplateRef = ref()
|
||||||
@@ -715,7 +760,7 @@ const customResumeRawData = ref<CustomizeResumeData>({
|
|||||||
/** 当前预览右侧tab:ai-AI帮写 / edit-编辑 */
|
/** 当前预览右侧tab:ai-AI帮写 / edit-编辑 */
|
||||||
const previewTab = ref<'ai' | 'edit'>('ai')
|
const previewTab = ref<'ai' | 'edit'>('ai')
|
||||||
|
|
||||||
/** AI优化结果列表(根据步骤三勾选的优化项动态生成) */
|
/** AI优化结果列表(根据步骤一勾选的优化项动态生成) */
|
||||||
const aiOptimizeResults = computed<string[]>(() => {
|
const aiOptimizeResults = computed<string[]>(() => {
|
||||||
const results: string[] = []
|
const results: string[] = []
|
||||||
|
|
||||||
|
|||||||
@@ -401,9 +401,11 @@ const resumeCustomJobInfo = computed(() => ({
|
|||||||
companyLogoUrl: job.companyLogoUrl,
|
companyLogoUrl: job.companyLogoUrl,
|
||||||
location: job.location,
|
location: job.location,
|
||||||
matchScore: skillGapData.value?.score ?? +(job.matchScore / 10).toFixed(1),
|
matchScore: skillGapData.value?.score ?? +(job.matchScore / 10).toFixed(1),
|
||||||
missingSkills: skillGapData.value?.missingSkills || [],
|
missingSkills: skillGapData.value?.missingSkills || skillGapData.value?.gaps?.map(g => g.keyword) || [],
|
||||||
keywords: skillGapData.value?.job?.skillTags || job.requiredSkills.map(s => s.name),
|
keywords: skillGapData.value?.job?.skillTags || job.requiredSkills.map(s => s.name),
|
||||||
sourceUrl: job.sourceUrl,
|
sourceUrl: job.sourceUrl,
|
||||||
|
/** 差距分析列表(来自 skill-gap 接口) */
|
||||||
|
gaps: skillGapData.value?.gaps || [],
|
||||||
/** 默认简历信息(来自 skill-gap 接口) */
|
/** 默认简历信息(来自 skill-gap 接口) */
|
||||||
defaultResume: skillGapData.value?.resume || null,
|
defaultResume: skillGapData.value?.resume || null,
|
||||||
}))
|
}))
|
||||||
|
|||||||
+9
-6
@@ -15,7 +15,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 页面标题 + Tab 切换 -->
|
<!-- 页面标题 + Tab 切换 -->
|
||||||
<JobPageHeader v-model:activeTab="activeTab" :favoriteCount="favoriteTotal" :applyCount="applyTotal" />
|
<JobPageHeader v-model:activeTab="activeTab" />
|
||||||
|
|
||||||
<!-- 筛选条件 -->
|
<!-- 筛选条件 -->
|
||||||
<div v-if="isRecommendTab" class="jobs-page__filters-bar">
|
<div v-if="isRecommendTab" class="jobs-page__filters-bar">
|
||||||
@@ -214,7 +214,7 @@
|
|||||||
<template v-if="isAuthenticated">
|
<template v-if="isAuthenticated">
|
||||||
<div class="jobs-page__match-ring">
|
<div class="jobs-page__match-ring">
|
||||||
<svg viewBox="0 0 80 80" class="jobs-page__ring-svg">
|
<svg viewBox="0 0 80 80" class="jobs-page__ring-svg">
|
||||||
<circle cx="40" cy="40" r="34" stroke-width="5" stroke="#9FD051" fill="none" opacity="0.3"/>
|
<circle cx="40" cy="40" r="34" stroke-width="5" :stroke="matchRingColor(job.matchScore)" fill="none" opacity="0.3"/>
|
||||||
<circle cx="40" cy="40" r="34" stroke-width="5" fill="none"
|
<circle cx="40" cy="40" r="34" stroke-width="5" fill="none"
|
||||||
:stroke="matchRingColor(job.matchScore)"
|
:stroke="matchRingColor(job.matchScore)"
|
||||||
stroke-linecap="round"
|
stroke-linecap="round"
|
||||||
@@ -1194,20 +1194,23 @@ async function handleRemoveFromList(job: JobItem) {
|
|||||||
|
|
||||||
/** 根据匹配分数返回对应的 CSS 类名 */
|
/** 根据匹配分数返回对应的 CSS 类名 */
|
||||||
function matchClass(score: number) {
|
function matchClass(score: number) {
|
||||||
return score >= 80 ? 'jobs-page__job-match--high' : 'jobs-page__job-match--low'
|
if (score >= 80) return 'jobs-page__job-match--high'
|
||||||
|
if (score >= 40) return 'jobs-page__job-match--medium'
|
||||||
|
return 'jobs-page__job-match--low'
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 根据匹配分数返回环形颜色 */
|
/** 根据匹配分数返回环形颜色 */
|
||||||
function matchRingColor(score: number) {
|
function matchRingColor(score: number) {
|
||||||
if (score >= 80) return '#9FD051'
|
if (score >= 80) return '#9FD051'
|
||||||
return '#9FD051'
|
if (score >= 40) return '#F59E0B'
|
||||||
|
return '#FE6D52'
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 根据匹配分数返回匹配等级文案 */
|
/** 根据匹配分数返回匹配等级文案 */
|
||||||
function matchLevelText(score: number) {
|
function matchLevelText(score: number) {
|
||||||
if (score >= 80) return '高匹配度'
|
if (score >= 80) return '高匹配度'
|
||||||
if (score >= 60) return '一般匹配'
|
if (score >= 40) return '中匹配度'
|
||||||
return '匹配度偏低'
|
return '低匹配度'
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 跳转到岗位详情页 — 未登录弹登录框,登录后再跳转 */
|
/** 跳转到岗位详情页 — 未登录弹登录框,登录后再跳转 */
|
||||||
|
|||||||
Reference in New Issue
Block a user