AI定制专属简历和简历预览调整
This commit is contained in:
@@ -174,18 +174,19 @@
|
|||||||
&__match-score {
|
&__match-score {
|
||||||
font-size: 0.18rem;
|
font-size: 0.18rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: $text-dark;
|
color: #52CAD1;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__match-label {
|
&__match-label {
|
||||||
font-size: 0.1rem;
|
font-size: 0.12rem;
|
||||||
color: $text-middle;
|
color: $bg-white;
|
||||||
margin-top: 0.04rem;
|
margin-top: 0.04rem;
|
||||||
background: $bg-main;
|
background: $text-dark;
|
||||||
border-radius: 0.04rem;
|
border-radius: 0.04rem;
|
||||||
padding: 0.02rem 0.08rem;
|
padding: 0.02rem 0.08rem;
|
||||||
|
line-height: 0.16rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 缺少技能区域
|
// 缺少技能区域
|
||||||
@@ -886,33 +887,38 @@
|
|||||||
min-height: 0;
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tab 切换栏
|
// Tab 切换栏(胶囊风格)
|
||||||
&__preview-tabs {
|
&__preview-tabs {
|
||||||
display: flex;
|
display: flex;
|
||||||
border-bottom: 1px solid $border-color;
|
align-items: center;
|
||||||
|
padding: 0.09rem 0.16rem;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
gap: 0.12rem;
|
||||||
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__preview-tab {
|
&__preview-tab {
|
||||||
flex: 1;
|
width: 1.48rem;
|
||||||
padding: 0.12rem 0;
|
height: 0.4rem;
|
||||||
font-size: 0.14rem;
|
line-height: 0.4rem;
|
||||||
color: $text-middle;
|
font-size: 0.16rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: $text-light;
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
border-bottom: 2px solid transparent;
|
border-radius: 0.28rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
&--active {
|
&--active {
|
||||||
color: $text-dark;
|
color: $bg-white;
|
||||||
font-weight: 600;
|
background: #52CAD1;
|
||||||
border-bottom-color: $text-dark;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover:not(&--active) {
|
||||||
color: $text-dark;
|
color: $text-dark;
|
||||||
|
background: $bg-main;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -923,100 +929,139 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-bottom: 0.01rem solid $border-color;
|
background: $bg-white;
|
||||||
}
|
}
|
||||||
|
|
||||||
// AI优化结果卡片
|
// 匹配度提升整体容器(左卡片+右圆环)
|
||||||
&__ai-result {
|
&__ai-congrats-wrap {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: center;
|
||||||
justify-content: space-between;
|
gap: 0.12rem;
|
||||||
padding: 0.2rem;
|
padding: 0.16rem;
|
||||||
gap: 0.16rem;
|
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__ai-result-text {
|
// 左侧绿色边框卡片
|
||||||
|
&__ai-congrats {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
padding: 0.16rem;
|
||||||
|
background: #F4FBFB;
|
||||||
|
border: 1px solid $accent;
|
||||||
|
border-radius: 0.12rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__ai-result-title {
|
&__ai-congrats-title {
|
||||||
font-size: 0.15rem;
|
font-size: 0.14rem;
|
||||||
|
font-weight: 450;
|
||||||
|
color: $text-dark;
|
||||||
|
margin: 0;
|
||||||
|
line-height: 0.26rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分数加粗黑色
|
||||||
|
&__ai-congrats-bold {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: $text-dark;
|
color: $accent;
|
||||||
margin: 0 0 0.12rem 0;
|
font-size: 0.18rem;
|
||||||
line-height: 1.5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__ai-result-detail {
|
// 右侧圆环+标签区域(卡片外面)
|
||||||
margin: 0;
|
&__ai-congrats-score {
|
||||||
}
|
|
||||||
|
|
||||||
&__ai-result-subtitle {
|
|
||||||
font-size: 0.12rem;
|
|
||||||
font-weight: 600;
|
|
||||||
color: $text-dark;
|
|
||||||
margin: 0 0 0.06rem 0;
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__ai-result-list {
|
|
||||||
list-style: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
li {
|
|
||||||
font-size: 0.12rem;
|
|
||||||
color: $text-dark;
|
|
||||||
line-height: 1.6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__ai-result-score {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 大号匹配度环
|
// 改写说明区域(卡片外平铺)
|
||||||
&__match-ring--large {
|
&__ai-optimize-detail {
|
||||||
width: 0.64rem;
|
padding: 0 0.16rem;
|
||||||
height: 0.64rem;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 高匹配标签
|
&__ai-optimize-subtitle {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $text-light;
|
||||||
|
margin: 0 0 0.12rem 0;
|
||||||
|
line-height: 0.19rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__ai-optimize-list {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__ai-optimize-item {
|
||||||
|
font-size: 0.14rem;
|
||||||
|
font-weight: 330;
|
||||||
|
color: $text-light;
|
||||||
|
margin: 0 0 0.08rem 0;
|
||||||
|
line-height: 0.22rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 大号匹配度环(设计稿60x60,粗线圈)
|
||||||
|
&__match-ring--large {
|
||||||
|
width: 0.66rem;
|
||||||
|
height: 0.66rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 匹配度分数文字
|
||||||
|
&__match-score {
|
||||||
|
font-size: 0.18rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #52CAD1;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 高匹配标签(黑底白字圆角)
|
||||||
&__match-label--high {
|
&__match-label--high {
|
||||||
background: $text-dark;
|
background: $text-dark;
|
||||||
color: $bg-white;
|
color: $bg-white;
|
||||||
font-weight: 600;
|
font-size: 0.12rem;
|
||||||
|
font-weight: 400;
|
||||||
|
border-radius: 0.04rem;
|
||||||
|
padding: 0.02rem 0.08rem;
|
||||||
|
margin-top: -0.12rem;
|
||||||
|
line-height: 0.16rem;
|
||||||
|
position: relative;
|
||||||
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 快捷操作按钮区
|
// 快捷操作按钮区(用户消息风格,右对齐)
|
||||||
&__ai-quick-actions {
|
&__ai-quick-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
gap: 0.08rem;
|
gap: 0.08rem;
|
||||||
padding: 0 0.2rem 0.16rem;
|
padding: 0.12rem 0.16rem;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 无左右padding的快捷操作(prl0类复写)
|
||||||
|
&__ai-quick-actions.prl0 {
|
||||||
|
padding-left: 0.16rem;
|
||||||
|
padding-right: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
&__ai-quick-btn {
|
&__ai-quick-btn {
|
||||||
background: $bg-white;
|
background: #52CAD1;
|
||||||
border: 1px solid $border-color;
|
border: none;
|
||||||
border-radius: 0.16rem;
|
border-radius: 0.12rem 0.04rem 0.12rem 0.12rem;
|
||||||
padding: 0.08rem 0.16rem;
|
padding: 0.08rem 0.12rem;
|
||||||
font-size: 0.12rem;
|
font-size: 0.14rem;
|
||||||
color: $text-dark;
|
font-weight: 305;
|
||||||
|
color: $bg-white;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
max-width: 2.38rem;
|
||||||
|
line-height: 0.24rem;
|
||||||
|
box-shadow: 0 0.01rem 0.04rem rgba(0, 0, 0, 0.04);
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: $bg-main;
|
background: #47b8bf;
|
||||||
border-color: $accent;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1024,7 +1069,6 @@
|
|||||||
&__ai-messages {
|
&__ai-messages {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
padding: 0 0.2rem;
|
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1041,22 +1085,29 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__ai-msg-bubble {
|
&__ai-msg-bubble {
|
||||||
border-radius: 0.1rem;
|
border-radius: 0.12rem;
|
||||||
padding: 0.1rem 0.14rem;
|
padding: 0.08rem 0.12rem;
|
||||||
font-size: 0.12rem;
|
font-size: 0.14rem;
|
||||||
line-height: 1.6;
|
font-weight: 330;
|
||||||
max-width: 85%;
|
line-height: 0.24rem;
|
||||||
|
max-width: 2.38rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AI消息气泡(品牌色边框+阴影)
|
||||||
&__ai-msg--ai &__ai-msg-bubble {
|
&__ai-msg--ai &__ai-msg-bubble {
|
||||||
background: $bg-main;
|
background: $bg-white;
|
||||||
color: $text-dark;
|
color: $text-dark;
|
||||||
border: 1px solid $border-color;
|
border: 1px solid #AEE6EA;
|
||||||
|
box-shadow: 0 0.02rem 0.04rem rgba(82, 202, 209, 0.1);
|
||||||
|
border-radius: 0.04rem 0.12rem 0.12rem 0.12rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 用户消息气泡(品牌色填充)
|
||||||
&__ai-msg--user &__ai-msg-bubble {
|
&__ai-msg--user &__ai-msg-bubble {
|
||||||
background: $text-dark;
|
background: #52CAD1;
|
||||||
color: $bg-white;
|
color: $bg-white;
|
||||||
|
border-radius: 0.12rem 0.04rem 0.12rem 0.12rem;
|
||||||
|
box-shadow: 0 0.01rem 0.04rem rgba(0, 0, 0, 0.04);
|
||||||
}
|
}
|
||||||
|
|
||||||
// AI正在思考中的加载气泡
|
// AI正在思考中的加载气泡
|
||||||
@@ -1199,36 +1250,37 @@
|
|||||||
&__ai-input-area {
|
&__ai-input-area {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0.08rem 0.12rem;
|
||||||
|
margin: 0.12rem 0.16rem;
|
||||||
gap: 0.08rem;
|
gap: 0.08rem;
|
||||||
padding: 0.12rem 0.2rem;
|
background: rgba(255, 255, 255, 0.95);
|
||||||
border-top: 1px solid $border-color;
|
border: 1px solid #AEE6EA;
|
||||||
|
border-radius: 0.12rem;
|
||||||
|
backdrop-filter: blur(12px);
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__ai-input {
|
&__ai-input {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
background: $bg-main;
|
background: none;
|
||||||
border: 1px solid $border-color;
|
border: none;
|
||||||
border-radius: 0.2rem;
|
padding: 0.04rem 0;
|
||||||
padding: 0.1rem 0.14rem;
|
|
||||||
font-size: 0.12rem;
|
font-size: 0.12rem;
|
||||||
color: $text-dark;
|
color: $text-dark;
|
||||||
outline: none;
|
outline: none;
|
||||||
|
line-height: 0.15rem;
|
||||||
|
|
||||||
&::placeholder {
|
&::placeholder {
|
||||||
color: $text-light;
|
color: $text-middle;
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
border-color: $accent;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__ai-send-btn {
|
&__ai-send-btn {
|
||||||
width: 0.34rem;
|
width: 0.32rem;
|
||||||
height: 0.34rem;
|
height: 0.32rem;
|
||||||
border-radius: 50%;
|
border-radius: 0.08rem;
|
||||||
background: $text-dark;
|
background: #52CAD1;
|
||||||
border: none;
|
border: none;
|
||||||
color: $bg-white;
|
color: $bg-white;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -1239,13 +1291,13 @@
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: $btn-dark-hover;
|
background: #47b8bf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__ai-send-icon {
|
&__ai-send-icon {
|
||||||
width: 0.16rem;
|
width: 0.2rem;
|
||||||
height: 0.16rem;
|
height: 0.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 编辑tab内容区
|
// 编辑tab内容区
|
||||||
|
|||||||
@@ -156,15 +156,13 @@
|
|||||||
&__card-index {
|
&__card-index {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.04rem;
|
font-size: 0.14rem;
|
||||||
font-size: 0.12rem;
|
color: $accent;
|
||||||
font-weight: 600;
|
|
||||||
color: $text-dark;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__card-index-dot {
|
&__card-index-dot {
|
||||||
width: 0.08rem;
|
width: 0.0rem;
|
||||||
height: 0.08rem;
|
height: 0.0rem;
|
||||||
color: $accent;
|
color: $accent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,7 +172,7 @@
|
|||||||
border: none;
|
border: none;
|
||||||
padding: 0.03rem;
|
padding: 0.03rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: $text-light;
|
color: $accent;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-radius: 0.04rem;
|
border-radius: 0.04rem;
|
||||||
|
|||||||
@@ -12,13 +12,15 @@
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 简历HTML内容区
|
// 简历HTML内容区(默认预览模式用小padding,导出模式用大padding)
|
||||||
.resume-html {
|
.resume-html {
|
||||||
padding: 50px 60px;
|
padding: 10px;
|
||||||
font-family: 'SimSun', 'Songti SC', serif;
|
font-family: 'SimSun', 'Songti SC', serif;
|
||||||
color: $text-dark;
|
color: $text-dark;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
|
|
||||||
|
// 导出模式:恢复完整内边距,去除差异样式 → 见底部统一 &--export 块
|
||||||
|
|
||||||
// 姓名
|
// 姓名
|
||||||
&__name {
|
&__name {
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
@@ -150,9 +152,30 @@
|
|||||||
|
|
||||||
// ==================== 差异对比高亮样式 ====================
|
// ==================== 差异对比高亮样式 ====================
|
||||||
&__diff-highlight {
|
&__diff-highlight {
|
||||||
background-color: #D4EDDA;
|
font-weight: 700;
|
||||||
color: #155724;
|
color: #52CAD1;
|
||||||
border-radius: 2px;
|
text-decoration: underline;
|
||||||
padding: 0 1px;
|
text-decoration-color: #52CAD1;
|
||||||
|
text-underline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 含有差异文字的经历块/个人概述背景色(仅预览模式)
|
||||||
|
&__diff-block {
|
||||||
|
background-color: #EDF9FA;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导出模式下去除差异相关样式
|
||||||
|
&--export {
|
||||||
|
padding: 50px 60px;
|
||||||
|
|
||||||
|
.resume-html__diff-highlight {
|
||||||
|
font-weight: inherit;
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resume-html__diff-block {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,18 +21,18 @@ $bg-white: #FFFFFF;
|
|||||||
$text-dark: #1A1A1A;
|
$text-dark: #1A1A1A;
|
||||||
|
|
||||||
// 浅色文字(副标题、占位符、辅助信息)
|
// 浅色文字(副标题、占位符、辅助信息)
|
||||||
$text-light: #BFBFBF;
|
$text-light: #99A1AF;
|
||||||
|
|
||||||
// 中间色文字(使用优先级高于浅色文字,稍微要深色一点的副标题、占位符、辅助信息)
|
// 中间色文字(使用优先级高于浅色文字,稍微要深色一点的副标题、占位符、辅助信息)
|
||||||
$text-middle: #6A7282;
|
$text-middle: #6A7282;
|
||||||
|
|
||||||
// 强调色 / 品牌色
|
// 强调色 / 品牌色
|
||||||
//$accent: #4FC2C9;
|
//$accent: #4FC2C9;
|
||||||
//$accent: #52CAD1;
|
//$accent: #12C7BE;
|
||||||
$accent: #12C7BE;
|
$accent: #52CAD1;
|
||||||
|
|
||||||
// 强调色悬停态
|
// 强调色悬停态
|
||||||
$accent-hover: #11b5ac;
|
$accent-hover: #42A8B3;
|
||||||
|
|
||||||
// 危险色 / 警告色(删除、错误等)
|
// 危险色 / 警告色(删除、错误等)
|
||||||
$danger: #E85635;
|
$danger: #E85635;
|
||||||
@@ -44,10 +44,10 @@ $border-color: #E8E8E8;
|
|||||||
$overlay-bg: rgba(0, 0, 0, 0.5);
|
$overlay-bg: rgba(0, 0, 0, 0.5);
|
||||||
|
|
||||||
// 主按钮颜色背景(确认提交等)
|
// 主按钮颜色背景(确认提交等)
|
||||||
$btn-dark: #12C7BE;
|
$btn-dark: #52CAD1;
|
||||||
|
|
||||||
// 主按钮颜色悬停态
|
// 主按钮颜色悬停态
|
||||||
$btn-dark-hover: #11b5ac;
|
$btn-dark-hover: #42A8B3;
|
||||||
|
|
||||||
// 次要深色按钮背景(除非特意指定使用否则不用这个按钮色)
|
// 次要深色按钮背景(除非特意指定使用否则不用这个按钮色)
|
||||||
//$btn-dark: #1A1A2E;
|
//$btn-dark: #1A1A2E;
|
||||||
@@ -56,5 +56,5 @@ $btn-dark-hover: #11b5ac;
|
|||||||
//$btn-dark-hover: #2E3142;
|
//$btn-dark-hover: #2E3142;
|
||||||
|
|
||||||
// 渐变色背景
|
// 渐变色背景
|
||||||
//$gradient-bg: linear-gradient(to right, #52CAD1, #42A8B3);
|
$gradient-bg: linear-gradient(to right, #52CAD1, #42A8B3);
|
||||||
$gradient-bg: linear-gradient(to right, #12C7BE, #11b5ac);
|
//$gradient-bg: linear-gradient(to right, #12C7BE, #11b5ac);
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<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">
|
<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">
|
<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">
|
<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="M8 2v8M8 10l-3-3M8 10l3-3" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
@@ -182,6 +182,7 @@
|
|||||||
:resumeData="resumeTemplateData"
|
:resumeData="resumeTemplateData"
|
||||||
:showDiff="isShowDiff"
|
:showDiff="isShowDiff"
|
||||||
:oldResumeData="oldResumeTemplateData"
|
:oldResumeData="oldResumeTemplateData"
|
||||||
|
:mode="resumeTemplateMode"
|
||||||
ref="resumeTemplateRef"
|
ref="resumeTemplateRef"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -207,29 +208,32 @@
|
|||||||
<div class="job-resume-custom-dialog__ai-messages" ref="aiMessagesRef">
|
<div class="job-resume-custom-dialog__ai-messages" ref="aiMessagesRef">
|
||||||
|
|
||||||
<!-- 匹配度提升提示 -->
|
<!-- 匹配度提升提示 -->
|
||||||
<div class="job-resume-custom-dialog__ai-result prl0">
|
<div class="job-resume-custom-dialog__ai-congrats-wrap">
|
||||||
<div class="job-resume-custom-dialog__ai-result-text">
|
<!-- 左侧绿色边框卡片:文字部分 -->
|
||||||
<p class="job-resume-custom-dialog__ai-result-title">恭喜!你的简历匹配值从<br/>{{ jobInfo.matchScore }}分提升到了{{ cachedOptimizedScore }}分!</p>
|
<div class="job-resume-custom-dialog__ai-congrats">
|
||||||
<div class="job-resume-custom-dialog__ai-result-detail">
|
<p class="job-resume-custom-dialog__ai-congrats-title">🎉 恭喜!你的简历匹配值<br/>从 <span class="job-resume-custom-dialog__ai-congrats-bold">{{ jobInfo.matchScore }}分</span> 提升到了 <span class="job-resume-custom-dialog__ai-congrats-bold">{{ cachedOptimizedScore }}分</span>!</p>
|
||||||
<p class="job-resume-custom-dialog__ai-result-subtitle">做了哪些优化?</p>
|
|
||||||
<ul class="job-resume-custom-dialog__ai-result-list">
|
|
||||||
<li v-for="(item, i) in aiOptimizeResults" :key="i">·{{ item }}</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="job-resume-custom-dialog__ai-result-score">
|
<!-- 右侧圆环+标签(卡片外面) -->
|
||||||
|
<div class="job-resume-custom-dialog__ai-congrats-score">
|
||||||
<div class="job-resume-custom-dialog__match-ring job-resume-custom-dialog__match-ring--large">
|
<div class="job-resume-custom-dialog__match-ring job-resume-custom-dialog__match-ring--large">
|
||||||
<svg viewBox="0 0 60 60" class="job-resume-custom-dialog__ring-svg">
|
<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="5" 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-cachedOptimizedScore/10)" transform="rotate(-90 30 30)"/>
|
<circle cx="30" cy="30" r="24" stroke-width="5" fill="none" stroke="#4FC2C9" stroke-linecap="round" :stroke-dasharray="2*Math.PI*24" :stroke-dashoffset="2*Math.PI*24*(1-cachedOptimizedScore/10)" transform="rotate(-90 30 30)"/>
|
||||||
</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>
|
||||||
|
<!-- 改写说明(卡片外面平铺) -->
|
||||||
|
<div class="job-resume-custom-dialog__ai-optimize-detail">
|
||||||
|
<p class="job-resume-custom-dialog__ai-optimize-subtitle">改写说明·共{{ aiOptimizeResults.length }}处</p>
|
||||||
|
<div class="job-resume-custom-dialog__ai-optimize-list">
|
||||||
|
<p v-for="(item, i) in aiOptimizeResults" :key="i" class="job-resume-custom-dialog__ai-optimize-item">{{ i + 1 }}、{{ item }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!-- 快捷操作按钮 -->
|
<!-- 快捷操作按钮 -->
|
||||||
<div class="job-resume-custom-dialog__ai-quick-actions prl0">
|
<div v-if="false" class="job-resume-custom-dialog__ai-quick-actions prl0">
|
||||||
<button
|
<button
|
||||||
v-for="(action, i) in aiQuickActions"
|
v-for="(action, i) in aiQuickActions"
|
||||||
:key="i"
|
:key="i"
|
||||||
@@ -284,8 +288,15 @@
|
|||||||
@keyup.enter="sendAiMessage(aiInputText)"
|
@keyup.enter="sendAiMessage(aiInputText)"
|
||||||
/>
|
/>
|
||||||
<button class="job-resume-custom-dialog__ai-send-btn" @click="sendAiMessage(aiInputText)">
|
<button class="job-resume-custom-dialog__ai-send-btn" @click="sendAiMessage(aiInputText)">
|
||||||
<svg viewBox="0 0 24 24" fill="none" class="job-resume-custom-dialog__ai-send-icon">
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M5 12h14M12 5l7 7-7 7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
<g clip-path="url(#clip0_118_2831)">
|
||||||
|
<path d="M16.8621 4.73833C17.2221 3.7425 16.2571 2.7775 15.2613 3.13833L3.09046 7.54C2.09129 7.90167 1.97046 9.265 2.88963 9.7975L6.77463 12.0467L10.2438 8.5775C10.401 8.4257 10.6115 8.34171 10.83 8.34361C11.0485 8.34551 11.2575 8.43315 11.412 8.58765C11.5665 8.74216 11.6541 8.95117 11.656 9.16967C11.6579 9.38816 11.5739 9.59867 11.4221 9.75583L7.95296 13.225L10.203 17.11C10.7346 18.0292 12.098 17.9075 12.4596 16.9092L16.8621 4.73833Z" fill="white"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_118_2831">
|
||||||
|
<rect width="20" height="20" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -736,6 +747,9 @@ function selectResume(r: ResumeOption) {
|
|||||||
/** 简历模板组件引用 */
|
/** 简历模板组件引用 */
|
||||||
const resumeTemplateRef = ref()
|
const resumeTemplateRef = ref()
|
||||||
|
|
||||||
|
/** 简历模板模式:preview=预览,export=导出 */
|
||||||
|
const resumeTemplateMode = ref<'preview' | 'export'>('preview')
|
||||||
|
|
||||||
/** 简历模板数据 */
|
/** 简历模板数据 */
|
||||||
const resumeTemplateData = ref<ResumeTemplateData>({
|
const resumeTemplateData = ref<ResumeTemplateData>({
|
||||||
name: '',
|
name: '',
|
||||||
@@ -1013,9 +1027,14 @@ function toggleDownloadMenu() {
|
|||||||
async function handleDownload(type: 'pdf' | 'word') {
|
async function handleDownload(type: 'pdf' | 'word') {
|
||||||
showDownloadMenu.value = false
|
showDownloadMenu.value = false
|
||||||
|
|
||||||
|
// 切换到导出模式(大padding)
|
||||||
|
resumeTemplateMode.value = 'export'
|
||||||
|
await nextTick()
|
||||||
|
|
||||||
const element = resumeTemplateRef.value?.resumeRef
|
const element = resumeTemplateRef.value?.resumeRef
|
||||||
if (!element) {
|
if (!element) {
|
||||||
console.error('[下载简历] 无法获取简历模板DOM')
|
console.error('[下载简历] 无法获取简历模板DOM')
|
||||||
|
resumeTemplateMode.value = 'preview'
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1029,6 +1048,9 @@ async function handleDownload(type: 'pdf' | 'word') {
|
|||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('[下载简历] 导出失败', err)
|
console.error('[下载简历] 导出失败', err)
|
||||||
|
} finally {
|
||||||
|
// 导出完成后恢复预览模式
|
||||||
|
resumeTemplateMode.value = 'preview'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,12 @@
|
|||||||
<div v-for="(edu, idx) in editData.education" :key="'edu-'+idx" class="job-resume-edit__card">
|
<div v-for="(edu, idx) in editData.education" :key="'edu-'+idx" class="job-resume-edit__card">
|
||||||
<div class="job-resume-edit__card-header">
|
<div class="job-resume-edit__card-header">
|
||||||
<span class="job-resume-edit__card-index"><svg viewBox="0 0 16 16" fill="none" class="job-resume-edit__card-index-dot"><circle cx="8" cy="8" r="3" fill="currentColor"/></svg>教育经历{{ idx + 1 }}</span>
|
<span class="job-resume-edit__card-index"><svg viewBox="0 0 16 16" fill="none" class="job-resume-edit__card-index-dot"><circle cx="8" cy="8" r="3" fill="currentColor"/></svg>教育经历{{ idx + 1 }}</span>
|
||||||
<button v-if="editData.education.length > 1" class="job-resume-edit__card-delete" @click="removeItem('education', idx)"><svg viewBox="0 0 16 16" fill="none" class="job-resume-edit__card-delete-icon"><path d="M3 4h10M6 4V3a1 1 0 011-1h2a1 1 0 011 1v1M5 4v8a1 1 0 001 1h4a1 1 0 001-1V4" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/></svg></button>
|
<button v-if="editData.education.length > 1" class="job-resume-edit__card-delete" @click="removeItem('education', idx)"><svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.2214 3.31982C12.2595 3.43697 12.2595 3.56318 12.2214 3.68034C12.1834 3.79749 12.1092 3.89959 12.0095 3.97201C11.9099 4.04441 11.7899 4.08341 11.6667 4.08341H11.0833L11.0816 4.12483L10.5373 11.7495C10.5235 11.9445 10.4608 12.1328 10.3552 12.2972C10.2496 12.4617 10.1044 12.5969 9.93283 12.6906C9.76131 12.7843 9.56901 12.8334 9.37359 12.8334H4.62583C4.4304 12.8334 4.2381 12.7843 4.06658 12.6906C3.89506 12.5969 3.74983 12.4617 3.6442 12.2972C3.53858 12.1328 3.47596 11.9445 3.46209 11.7495L2.91783 4.12541L2.91666 4.08341H2.33334C2.21014 4.08341 2.09011 4.04441 1.99046 3.97201C1.89079 3.89959 1.81662 3.79749 1.77855 3.68034C1.74048 3.56318 1.74048 3.43697 1.77855 3.31982C1.81662 3.20266 1.89079 3.10056 1.99046 3.02815C2.09011 2.95575 2.21014 2.91675 2.33334 2.91675H11.6667C11.7899 2.91675 11.9099 2.95575 12.0095 3.02815C12.1092 3.10056 12.1834 3.20266 12.2214 3.31982ZM4.62632 11.6666H9.37368L9.91504 4.08325H4.08496L4.62632 11.6666Z" fill="#52CAD1"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.72145 1.56981C8.75952 1.68696 8.75952 1.81316 8.72145 1.93031C8.68338 2.04747 8.6092 2.14957 8.50954 2.22197C8.40988 2.29438 8.28986 2.33337 8.16667 2.33337H5.83333C5.71014 2.33337 5.59012 2.29438 5.49046 2.22197C5.3908 2.14957 5.31662 2.04747 5.27855 1.93031C5.24048 1.81316 5.24048 1.68696 5.27855 1.56981C5.31662 1.45265 5.3908 1.35056 5.49046 1.27815C5.59012 1.20574 5.71014 1.16675 5.83333 1.16675H8.16667C8.28986 1.16675 8.40988 1.20574 8.50954 1.27815C8.6092 1.35056 8.68338 1.45265 8.72145 1.56981Z" fill="#52CAD1"/>
|
||||||
|
</svg>
|
||||||
|
<span class="ml5">删除</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="job-resume-edit__field"><label class="job-resume-edit__label">学校</label><input class="job-resume-edit__input" placeholder="请输入学校" v-model="edu.school" @blur="autoSave" /></div>
|
<div class="job-resume-edit__field"><label class="job-resume-edit__label">学校</label><input class="job-resume-edit__input" placeholder="请输入学校" v-model="edu.school" @blur="autoSave" /></div>
|
||||||
<div class="job-resume-edit__field"><label class="job-resume-edit__label">专业</label><input class="job-resume-edit__input" placeholder="请输入专业" v-model="edu.major" @blur="autoSave" /></div>
|
<div class="job-resume-edit__field"><label class="job-resume-edit__label">专业</label><input class="job-resume-edit__input" placeholder="请输入专业" v-model="edu.major" @blur="autoSave" /></div>
|
||||||
@@ -48,11 +53,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="job-resume-edit__field">
|
<div class="job-resume-edit__field">
|
||||||
<label class="job-resume-edit__label">经历描述</label>
|
<label class="job-resume-edit__label">经历描述</label>
|
||||||
<div v-for="(desc, dIdx) in edu.description" :key="desc.id" class="job-resume-edit__desc-item">
|
<textarea class="job-resume-edit__textarea" placeholder="请输入描述,每行一条" v-model="descTextMap.education[idx]" rows="4" @blur="syncDescFromText('education', idx)"></textarea>
|
||||||
<textarea class="job-resume-edit__textarea job-resume-edit__textarea--with-remove" placeholder="请输入描述" v-model="desc.text" rows="3" @blur="autoSave"></textarea>
|
|
||||||
<button v-if="edu.description.length > 1" class="job-resume-edit__desc-remove" @click="removeDesc('education', idx, dIdx)"><svg viewBox="0 0 16 16" fill="none" class="job-resume-edit__desc-remove-icon"><path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg></button>
|
|
||||||
</div>
|
|
||||||
<button class="job-resume-edit__add-btn" @click="addDesc('education', idx)"><span class="job-resume-edit__add-icon">+</span> 新增描述</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="job-resume-edit__add-btn job-resume-edit__add-btn--full" @click="addItem('education')"><span class="job-resume-edit__add-icon">+</span> 新增教育经历</button>
|
<button class="job-resume-edit__add-btn job-resume-edit__add-btn--full" @click="addItem('education')"><span class="job-resume-edit__add-icon">+</span> 新增教育经历</button>
|
||||||
@@ -63,7 +64,12 @@
|
|||||||
<div v-for="(item, idx) in editData.internship" :key="'intern-'+idx" class="job-resume-edit__card">
|
<div v-for="(item, idx) in editData.internship" :key="'intern-'+idx" class="job-resume-edit__card">
|
||||||
<div class="job-resume-edit__card-header">
|
<div class="job-resume-edit__card-header">
|
||||||
<span class="job-resume-edit__card-index"><svg viewBox="0 0 16 16" fill="none" class="job-resume-edit__card-index-dot"><circle cx="8" cy="8" r="3" fill="currentColor"/></svg>实习经历{{ idx + 1 }}</span>
|
<span class="job-resume-edit__card-index"><svg viewBox="0 0 16 16" fill="none" class="job-resume-edit__card-index-dot"><circle cx="8" cy="8" r="3" fill="currentColor"/></svg>实习经历{{ idx + 1 }}</span>
|
||||||
<button v-if="editData.internship.length > 1" class="job-resume-edit__card-delete" @click="removeItem('internship', idx)"><svg viewBox="0 0 16 16" fill="none" class="job-resume-edit__card-delete-icon"><path d="M3 4h10M6 4V3a1 1 0 011-1h2a1 1 0 011 1v1M5 4v8a1 1 0 001 1h4a1 1 0 001-1V4" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/></svg></button>
|
<button v-if="editData.internship.length > 1" class="job-resume-edit__card-delete" @click="removeItem('internship', idx)"><svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.2214 3.31982C12.2595 3.43697 12.2595 3.56318 12.2214 3.68034C12.1834 3.79749 12.1092 3.89959 12.0095 3.97201C11.9099 4.04441 11.7899 4.08341 11.6667 4.08341H11.0833L11.0816 4.12483L10.5373 11.7495C10.5235 11.9445 10.4608 12.1328 10.3552 12.2972C10.2496 12.4617 10.1044 12.5969 9.93283 12.6906C9.76131 12.7843 9.56901 12.8334 9.37359 12.8334H4.62583C4.4304 12.8334 4.2381 12.7843 4.06658 12.6906C3.89506 12.5969 3.74983 12.4617 3.6442 12.2972C3.53858 12.1328 3.47596 11.9445 3.46209 11.7495L2.91783 4.12541L2.91666 4.08341H2.33334C2.21014 4.08341 2.09011 4.04441 1.99046 3.97201C1.89079 3.89959 1.81662 3.79749 1.77855 3.68034C1.74048 3.56318 1.74048 3.43697 1.77855 3.31982C1.81662 3.20266 1.89079 3.10056 1.99046 3.02815C2.09011 2.95575 2.21014 2.91675 2.33334 2.91675H11.6667C11.7899 2.91675 11.9099 2.95575 12.0095 3.02815C12.1092 3.10056 12.1834 3.20266 12.2214 3.31982ZM4.62632 11.6666H9.37368L9.91504 4.08325H4.08496L4.62632 11.6666Z" fill="#52CAD1"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.72145 1.56981C8.75952 1.68696 8.75952 1.81316 8.72145 1.93031C8.68338 2.04747 8.6092 2.14957 8.50954 2.22197C8.40988 2.29438 8.28986 2.33337 8.16667 2.33337H5.83333C5.71014 2.33337 5.59012 2.29438 5.49046 2.22197C5.3908 2.14957 5.31662 2.04747 5.27855 1.93031C5.24048 1.81316 5.24048 1.68696 5.27855 1.56981C5.31662 1.45265 5.3908 1.35056 5.49046 1.27815C5.59012 1.20574 5.71014 1.16675 5.83333 1.16675H8.16667C8.28986 1.16675 8.40988 1.20574 8.50954 1.27815C8.6092 1.35056 8.68338 1.45265 8.72145 1.56981Z" fill="#52CAD1"/>
|
||||||
|
</svg>
|
||||||
|
<span class="ml5">删除</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="job-resume-edit__field"><label class="job-resume-edit__label">公司名称</label><input class="job-resume-edit__input" placeholder="请输入公司名称" v-model="item.companyName" @blur="autoSave" /></div>
|
<div class="job-resume-edit__field"><label class="job-resume-edit__label">公司名称</label><input class="job-resume-edit__input" placeholder="请输入公司名称" v-model="item.companyName" @blur="autoSave" /></div>
|
||||||
<div class="job-resume-edit__field"><label class="job-resume-edit__label">职位</label><input class="job-resume-edit__input" placeholder="请输入职位" v-model="item.position" @blur="autoSave" /></div>
|
<div class="job-resume-edit__field"><label class="job-resume-edit__label">职位</label><input class="job-resume-edit__input" placeholder="请输入职位" v-model="item.position" @blur="autoSave" /></div>
|
||||||
@@ -73,11 +79,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="job-resume-edit__field">
|
<div class="job-resume-edit__field">
|
||||||
<label class="job-resume-edit__label">经历描述</label>
|
<label class="job-resume-edit__label">经历描述</label>
|
||||||
<div v-for="(desc, dIdx) in item.description" :key="desc.id" class="job-resume-edit__desc-item">
|
<textarea class="job-resume-edit__textarea" placeholder="请输入描述,每行一条" v-model="descTextMap.internship[idx]" rows="4" @blur="syncDescFromText('internship', idx)"></textarea>
|
||||||
<textarea class="job-resume-edit__textarea job-resume-edit__textarea--with-remove" placeholder="请输入描述" v-model="desc.text" rows="3" @blur="autoSave"></textarea>
|
|
||||||
<button v-if="item.description.length > 1" class="job-resume-edit__desc-remove" @click="removeDesc('internship', idx, dIdx)"><svg viewBox="0 0 16 16" fill="none" class="job-resume-edit__desc-remove-icon"><path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg></button>
|
|
||||||
</div>
|
|
||||||
<button class="job-resume-edit__add-btn" @click="addDesc('internship', idx)"><span class="job-resume-edit__add-icon">+</span> 新增描述</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="job-resume-edit__add-btn job-resume-edit__add-btn--full" @click="addItem('internship')"><span class="job-resume-edit__add-icon">+</span> 新增实习经历</button>
|
<button class="job-resume-edit__add-btn job-resume-edit__add-btn--full" @click="addItem('internship')"><span class="job-resume-edit__add-icon">+</span> 新增实习经历</button>
|
||||||
@@ -88,7 +90,12 @@
|
|||||||
<div v-for="(item, idx) in editData.work" :key="'work-'+idx" class="job-resume-edit__card">
|
<div v-for="(item, idx) in editData.work" :key="'work-'+idx" class="job-resume-edit__card">
|
||||||
<div class="job-resume-edit__card-header">
|
<div class="job-resume-edit__card-header">
|
||||||
<span class="job-resume-edit__card-index"><svg viewBox="0 0 16 16" fill="none" class="job-resume-edit__card-index-dot"><circle cx="8" cy="8" r="3" fill="currentColor"/></svg>工作经历{{ idx + 1 }}</span>
|
<span class="job-resume-edit__card-index"><svg viewBox="0 0 16 16" fill="none" class="job-resume-edit__card-index-dot"><circle cx="8" cy="8" r="3" fill="currentColor"/></svg>工作经历{{ idx + 1 }}</span>
|
||||||
<button v-if="editData.work.length > 1" class="job-resume-edit__card-delete" @click="removeItem('work', idx)"><svg viewBox="0 0 16 16" fill="none" class="job-resume-edit__card-delete-icon"><path d="M3 4h10M6 4V3a1 1 0 011-1h2a1 1 0 011 1v1M5 4v8a1 1 0 001 1h4a1 1 0 001-1V4" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/></svg></button>
|
<button v-if="editData.work.length > 1" class="job-resume-edit__card-delete" @click="removeItem('work', idx)"><svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.2214 3.31982C12.2595 3.43697 12.2595 3.56318 12.2214 3.68034C12.1834 3.79749 12.1092 3.89959 12.0095 3.97201C11.9099 4.04441 11.7899 4.08341 11.6667 4.08341H11.0833L11.0816 4.12483L10.5373 11.7495C10.5235 11.9445 10.4608 12.1328 10.3552 12.2972C10.2496 12.4617 10.1044 12.5969 9.93283 12.6906C9.76131 12.7843 9.56901 12.8334 9.37359 12.8334H4.62583C4.4304 12.8334 4.2381 12.7843 4.06658 12.6906C3.89506 12.5969 3.74983 12.4617 3.6442 12.2972C3.53858 12.1328 3.47596 11.9445 3.46209 11.7495L2.91783 4.12541L2.91666 4.08341H2.33334C2.21014 4.08341 2.09011 4.04441 1.99046 3.97201C1.89079 3.89959 1.81662 3.79749 1.77855 3.68034C1.74048 3.56318 1.74048 3.43697 1.77855 3.31982C1.81662 3.20266 1.89079 3.10056 1.99046 3.02815C2.09011 2.95575 2.21014 2.91675 2.33334 2.91675H11.6667C11.7899 2.91675 11.9099 2.95575 12.0095 3.02815C12.1092 3.10056 12.1834 3.20266 12.2214 3.31982ZM4.62632 11.6666H9.37368L9.91504 4.08325H4.08496L4.62632 11.6666Z" fill="#52CAD1"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.72145 1.56981C8.75952 1.68696 8.75952 1.81316 8.72145 1.93031C8.68338 2.04747 8.6092 2.14957 8.50954 2.22197C8.40988 2.29438 8.28986 2.33337 8.16667 2.33337H5.83333C5.71014 2.33337 5.59012 2.29438 5.49046 2.22197C5.3908 2.14957 5.31662 2.04747 5.27855 1.93031C5.24048 1.81316 5.24048 1.68696 5.27855 1.56981C5.31662 1.45265 5.3908 1.35056 5.49046 1.27815C5.59012 1.20574 5.71014 1.16675 5.83333 1.16675H8.16667C8.28986 1.16675 8.40988 1.20574 8.50954 1.27815C8.6092 1.35056 8.68338 1.45265 8.72145 1.56981Z" fill="#52CAD1"/>
|
||||||
|
</svg>
|
||||||
|
<span class="ml5">删除</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="job-resume-edit__field"><label class="job-resume-edit__label">公司名称</label><input class="job-resume-edit__input" placeholder="请输入公司名称" v-model="item.companyName" @blur="autoSave" /></div>
|
<div class="job-resume-edit__field"><label class="job-resume-edit__label">公司名称</label><input class="job-resume-edit__input" placeholder="请输入公司名称" v-model="item.companyName" @blur="autoSave" /></div>
|
||||||
<div class="job-resume-edit__field"><label class="job-resume-edit__label">职位</label><input class="job-resume-edit__input" placeholder="请输入职位" v-model="item.position" @blur="autoSave" /></div>
|
<div class="job-resume-edit__field"><label class="job-resume-edit__label">职位</label><input class="job-resume-edit__input" placeholder="请输入职位" v-model="item.position" @blur="autoSave" /></div>
|
||||||
@@ -98,11 +105,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="job-resume-edit__field">
|
<div class="job-resume-edit__field">
|
||||||
<label class="job-resume-edit__label">经历描述</label>
|
<label class="job-resume-edit__label">经历描述</label>
|
||||||
<div v-for="(desc, dIdx) in item.description" :key="desc.id" class="job-resume-edit__desc-item">
|
<textarea class="job-resume-edit__textarea" placeholder="请输入描述,每行一条" v-model="descTextMap.work[idx]" rows="4" @blur="syncDescFromText('work', idx)"></textarea>
|
||||||
<textarea class="job-resume-edit__textarea job-resume-edit__textarea--with-remove" placeholder="请输入描述" v-model="desc.text" rows="3" @blur="autoSave"></textarea>
|
|
||||||
<button v-if="item.description.length > 1" class="job-resume-edit__desc-remove" @click="removeDesc('work', idx, dIdx)"><svg viewBox="0 0 16 16" fill="none" class="job-resume-edit__desc-remove-icon"><path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg></button>
|
|
||||||
</div>
|
|
||||||
<button class="job-resume-edit__add-btn" @click="addDesc('work', idx)"><span class="job-resume-edit__add-icon">+</span> 新增描述</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="job-resume-edit__add-btn job-resume-edit__add-btn--full" @click="addItem('work')"><span class="job-resume-edit__add-icon">+</span> 新增工作经历</button>
|
<button class="job-resume-edit__add-btn job-resume-edit__add-btn--full" @click="addItem('work')"><span class="job-resume-edit__add-icon">+</span> 新增工作经历</button>
|
||||||
@@ -113,7 +116,12 @@
|
|||||||
<div v-for="(item, idx) in editData.project" :key="'proj-'+idx" class="job-resume-edit__card">
|
<div v-for="(item, idx) in editData.project" :key="'proj-'+idx" class="job-resume-edit__card">
|
||||||
<div class="job-resume-edit__card-header">
|
<div class="job-resume-edit__card-header">
|
||||||
<span class="job-resume-edit__card-index"><svg viewBox="0 0 16 16" fill="none" class="job-resume-edit__card-index-dot"><circle cx="8" cy="8" r="3" fill="currentColor"/></svg>项目经历{{ idx + 1 }}</span>
|
<span class="job-resume-edit__card-index"><svg viewBox="0 0 16 16" fill="none" class="job-resume-edit__card-index-dot"><circle cx="8" cy="8" r="3" fill="currentColor"/></svg>项目经历{{ idx + 1 }}</span>
|
||||||
<button v-if="editData.project.length > 1" class="job-resume-edit__card-delete" @click="removeItem('project', idx)"><svg viewBox="0 0 16 16" fill="none" class="job-resume-edit__card-delete-icon"><path d="M3 4h10M6 4V3a1 1 0 011-1h2a1 1 0 011 1v1M5 4v8a1 1 0 001 1h4a1 1 0 001-1V4" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/></svg></button>
|
<button v-if="editData.project.length > 1" class="job-resume-edit__card-delete" @click="removeItem('project', idx)"><svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.2214 3.31982C12.2595 3.43697 12.2595 3.56318 12.2214 3.68034C12.1834 3.79749 12.1092 3.89959 12.0095 3.97201C11.9099 4.04441 11.7899 4.08341 11.6667 4.08341H11.0833L11.0816 4.12483L10.5373 11.7495C10.5235 11.9445 10.4608 12.1328 10.3552 12.2972C10.2496 12.4617 10.1044 12.5969 9.93283 12.6906C9.76131 12.7843 9.56901 12.8334 9.37359 12.8334H4.62583C4.4304 12.8334 4.2381 12.7843 4.06658 12.6906C3.89506 12.5969 3.74983 12.4617 3.6442 12.2972C3.53858 12.1328 3.47596 11.9445 3.46209 11.7495L2.91783 4.12541L2.91666 4.08341H2.33334C2.21014 4.08341 2.09011 4.04441 1.99046 3.97201C1.89079 3.89959 1.81662 3.79749 1.77855 3.68034C1.74048 3.56318 1.74048 3.43697 1.77855 3.31982C1.81662 3.20266 1.89079 3.10056 1.99046 3.02815C2.09011 2.95575 2.21014 2.91675 2.33334 2.91675H11.6667C11.7899 2.91675 11.9099 2.95575 12.0095 3.02815C12.1092 3.10056 12.1834 3.20266 12.2214 3.31982ZM4.62632 11.6666H9.37368L9.91504 4.08325H4.08496L4.62632 11.6666Z" fill="#52CAD1"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.72145 1.56981C8.75952 1.68696 8.75952 1.81316 8.72145 1.93031C8.68338 2.04747 8.6092 2.14957 8.50954 2.22197C8.40988 2.29438 8.28986 2.33337 8.16667 2.33337H5.83333C5.71014 2.33337 5.59012 2.29438 5.49046 2.22197C5.3908 2.14957 5.31662 2.04747 5.27855 1.93031C5.24048 1.81316 5.24048 1.68696 5.27855 1.56981C5.31662 1.45265 5.3908 1.35056 5.49046 1.27815C5.59012 1.20574 5.71014 1.16675 5.83333 1.16675H8.16667C8.28986 1.16675 8.40988 1.20574 8.50954 1.27815C8.6092 1.35056 8.68338 1.45265 8.72145 1.56981Z" fill="#52CAD1"/>
|
||||||
|
</svg>
|
||||||
|
<span class="ml5">删除</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="job-resume-edit__field"><label class="job-resume-edit__label">项目名称</label><input class="job-resume-edit__input" placeholder="请输入项目名称" v-model="item.projectName" @blur="autoSave" /></div>
|
<div class="job-resume-edit__field"><label class="job-resume-edit__label">项目名称</label><input class="job-resume-edit__input" placeholder="请输入项目名称" v-model="item.projectName" @blur="autoSave" /></div>
|
||||||
<div class="job-resume-edit__field"><label class="job-resume-edit__label">所属公司</label><input class="job-resume-edit__input" placeholder="请输入所属公司" v-model="item.companyName" @blur="autoSave" /></div>
|
<div class="job-resume-edit__field"><label class="job-resume-edit__label">所属公司</label><input class="job-resume-edit__input" placeholder="请输入所属公司" v-model="item.companyName" @blur="autoSave" /></div>
|
||||||
@@ -124,11 +132,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="job-resume-edit__field">
|
<div class="job-resume-edit__field">
|
||||||
<label class="job-resume-edit__label">经历描述</label>
|
<label class="job-resume-edit__label">经历描述</label>
|
||||||
<div v-for="(desc, dIdx) in item.description" :key="desc.id" class="job-resume-edit__desc-item">
|
<textarea class="job-resume-edit__textarea" placeholder="请输入描述,每行一条" v-model="descTextMap.project[idx]" rows="4" @blur="syncDescFromText('project', idx)"></textarea>
|
||||||
<textarea class="job-resume-edit__textarea job-resume-edit__textarea--with-remove" placeholder="请输入描述" v-model="desc.text" rows="3" @blur="autoSave"></textarea>
|
|
||||||
<button v-if="item.description.length > 1" class="job-resume-edit__desc-remove" @click="removeDesc('project', idx, dIdx)"><svg viewBox="0 0 16 16" fill="none" class="job-resume-edit__desc-remove-icon"><path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg></button>
|
|
||||||
</div>
|
|
||||||
<button class="job-resume-edit__add-btn" @click="addDesc('project', idx)"><span class="job-resume-edit__add-icon">+</span> 新增描述</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="job-resume-edit__add-btn job-resume-edit__add-btn--full" @click="addItem('project')"><span class="job-resume-edit__add-icon">+</span> 新增项目经历</button>
|
<button class="job-resume-edit__add-btn job-resume-edit__add-btn--full" @click="addItem('project')"><span class="job-resume-edit__add-icon">+</span> 新增项目经历</button>
|
||||||
@@ -138,8 +142,14 @@
|
|||||||
<template v-else-if="sec.key === 'competition'">
|
<template v-else-if="sec.key === 'competition'">
|
||||||
<div v-for="(item, idx) in editData.competition" :key="'comp-'+idx" class="job-resume-edit__card">
|
<div v-for="(item, idx) in editData.competition" :key="'comp-'+idx" class="job-resume-edit__card">
|
||||||
<div class="job-resume-edit__card-header">
|
<div class="job-resume-edit__card-header">
|
||||||
<span class="job-resume-edit__card-index"><svg viewBox="0 0 16 16" fill="none" class="job-resume-edit__card-index-dot"><circle cx="8" cy="8" r="3" fill="currentColor"/></svg>竞赛{{ idx + 1 }}</span>
|
<span class="job-resume-edit__card-index"><svg viewBox="0 0 16 16" fill="none" class="job-resume-edit__card-index-dot"><circle cx="8" cy="8" r="3" fill="currentColor"/></svg>竞赛经历{{ idx + 1 }}</span>
|
||||||
<button v-if="editData.competition.length > 1" class="job-resume-edit__card-delete" @click="removeItem('competition', idx)"><svg viewBox="0 0 16 16" fill="none" class="job-resume-edit__card-delete-icon"><path d="M3 4h10M6 4V3a1 1 0 011-1h2a1 1 0 011 1v1M5 4v8a1 1 0 001 1h4a1 1 0 001-1V4" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/></svg></button>
|
<button v-if="editData.competition.length > 1" class="job-resume-edit__card-delete" @click="removeItem('competition', idx)">
|
||||||
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.2214 3.31982C12.2595 3.43697 12.2595 3.56318 12.2214 3.68034C12.1834 3.79749 12.1092 3.89959 12.0095 3.97201C11.9099 4.04441 11.7899 4.08341 11.6667 4.08341H11.0833L11.0816 4.12483L10.5373 11.7495C10.5235 11.9445 10.4608 12.1328 10.3552 12.2972C10.2496 12.4617 10.1044 12.5969 9.93283 12.6906C9.76131 12.7843 9.56901 12.8334 9.37359 12.8334H4.62583C4.4304 12.8334 4.2381 12.7843 4.06658 12.6906C3.89506 12.5969 3.74983 12.4617 3.6442 12.2972C3.53858 12.1328 3.47596 11.9445 3.46209 11.7495L2.91783 4.12541L2.91666 4.08341H2.33334C2.21014 4.08341 2.09011 4.04441 1.99046 3.97201C1.89079 3.89959 1.81662 3.79749 1.77855 3.68034C1.74048 3.56318 1.74048 3.43697 1.77855 3.31982C1.81662 3.20266 1.89079 3.10056 1.99046 3.02815C2.09011 2.95575 2.21014 2.91675 2.33334 2.91675H11.6667C11.7899 2.91675 11.9099 2.95575 12.0095 3.02815C12.1092 3.10056 12.1834 3.20266 12.2214 3.31982ZM4.62632 11.6666H9.37368L9.91504 4.08325H4.08496L4.62632 11.6666Z" fill="#52CAD1"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.72145 1.56981C8.75952 1.68696 8.75952 1.81316 8.72145 1.93031C8.68338 2.04747 8.6092 2.14957 8.50954 2.22197C8.40988 2.29438 8.28986 2.33337 8.16667 2.33337H5.83333C5.71014 2.33337 5.59012 2.29438 5.49046 2.22197C5.3908 2.14957 5.31662 2.04747 5.27855 1.93031C5.24048 1.81316 5.24048 1.68696 5.27855 1.56981C5.31662 1.45265 5.3908 1.35056 5.49046 1.27815C5.59012 1.20574 5.71014 1.16675 5.83333 1.16675H8.16667C8.28986 1.16675 8.40988 1.20574 8.50954 1.27815C8.6092 1.35056 8.68338 1.45265 8.72145 1.56981Z" fill="#52CAD1"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<span class="ml5">删除</span></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="job-resume-edit__field"><label class="job-resume-edit__label">竞赛名称</label><input class="job-resume-edit__input" placeholder="请输入竞赛名称" v-model="item.competitionName" @blur="autoSave" /></div>
|
<div class="job-resume-edit__field"><label class="job-resume-edit__label">竞赛名称</label><input class="job-resume-edit__input" placeholder="请输入竞赛名称" v-model="item.competitionName" @blur="autoSave" /></div>
|
||||||
<div class="job-resume-edit__field"><label class="job-resume-edit__label">获奖名次</label><input class="job-resume-edit__input" placeholder="请输入获奖名次" v-model="item.award" @blur="autoSave" /></div>
|
<div class="job-resume-edit__field"><label class="job-resume-edit__label">获奖名次</label><input class="job-resume-edit__input" placeholder="请输入获奖名次" v-model="item.award" @blur="autoSave" /></div>
|
||||||
@@ -178,13 +188,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- ========== 作品集 ========== -->
|
|
||||||
<template v-else-if="sec.key === 'portfolio'">
|
|
||||||
<div class="job-resume-edit__field">
|
|
||||||
<input class="job-resume-edit__input" placeholder="请输入作品集链接" v-model="editData.resume.portfolioUrl" @blur="autoSave" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -269,14 +272,13 @@ const sectionList = [
|
|||||||
{ key: 'competition', label: '竞赛' },
|
{ key: 'competition', label: '竞赛' },
|
||||||
{ key: 'certificate', label: '证书' },
|
{ key: 'certificate', label: '证书' },
|
||||||
{ key: 'skills', label: '技能' },
|
{ key: 'skills', label: '技能' },
|
||||||
{ key: 'portfolio', label: '作品集' },
|
|
||||||
]
|
]
|
||||||
|
|
||||||
/** 各模块展开状态 */
|
/** 各模块展开状态 */
|
||||||
const openSections = reactive<Record<string, boolean>>({
|
const openSections = reactive<Record<string, boolean>>({
|
||||||
info: false, summary: false, education: false, internship: false,
|
info: false, summary: false, education: false, internship: false,
|
||||||
work: false, project: false, competition: false, certificate: false,
|
work: false, project: false, competition: false, certificate: false,
|
||||||
skills: false, portfolio: false,
|
skills: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
/** 切换模块展开/收起 */
|
/** 切换模块展开/收起 */
|
||||||
@@ -347,9 +349,45 @@ function initEditData(data: CustomizeResumeData) {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== 描述文本映射(合并编辑用) ====================
|
||||||
|
|
||||||
|
/** 每个模块每条经历的描述文本(将description数组用换行拼成单个字符串) */
|
||||||
|
const descTextMap = reactive<Record<string, string[]>>({
|
||||||
|
education: [],
|
||||||
|
work: [],
|
||||||
|
internship: [],
|
||||||
|
project: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
/** 从 editData 的 description 数组生成合并文本 */
|
||||||
|
function buildDescTextMap() {
|
||||||
|
descTextMap.education = editData.education.map(e => e.description.map(d => d.text).join('\n'))
|
||||||
|
descTextMap.work = editData.work.map(w => w.description.map(d => d.text).join('\n'))
|
||||||
|
descTextMap.internship = editData.internship.map(i => i.description.map(d => d.text).join('\n'))
|
||||||
|
descTextMap.project = editData.project.map(p => p.description.map(d => d.text).join('\n'))
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 将文本框内容按换行拆分回 description 数组,并触发自动保存 */
|
||||||
|
function syncDescFromText(type: 'education' | 'work' | 'internship' | 'project', itemIdx: number) {
|
||||||
|
const text = descTextMap[type][itemIdx] || ''
|
||||||
|
const lines = text.split('\n').filter(s => s.trim())
|
||||||
|
const oldDesc = editData[type][itemIdx].description
|
||||||
|
// 保留原有id,超出的生成新id
|
||||||
|
const newDesc: DescParagraph[] = lines.map((line, i) => ({
|
||||||
|
id: i < oldDesc.length ? oldDesc[i].id : genId(),
|
||||||
|
text: line,
|
||||||
|
}))
|
||||||
|
// 如果全部为空则保留一个空描述
|
||||||
|
editData[type][itemIdx].description = newDesc.length ? newDesc : [{ id: genId(), text: '' }]
|
||||||
|
autoSave()
|
||||||
|
}
|
||||||
|
|
||||||
/** 监听 props 变化,初始化编辑数据 */
|
/** 监听 props 变化,初始化编辑数据 */
|
||||||
watch(() => props.resumeData, (val) => {
|
watch(() => props.resumeData, (val) => {
|
||||||
if (val) initEditData(val)
|
if (val) {
|
||||||
|
initEditData(val)
|
||||||
|
buildDescTextMap()
|
||||||
|
}
|
||||||
}, { immediate: true, deep: true })
|
}, { immediate: true, deep: true })
|
||||||
|
|
||||||
// ==================== 自动保存(失焦/选择后触发PUT接口) ====================
|
// ==================== 自动保存(失焦/选择后触发PUT接口) ====================
|
||||||
@@ -360,7 +398,9 @@ let saveTimer: ReturnType<typeof setTimeout> | null = null
|
|||||||
/** 将编辑数据转换为接口所需的 CustomizeResumeData 格式 */
|
/** 将编辑数据转换为接口所需的 CustomizeResumeData 格式 */
|
||||||
function buildSavePayload(): CustomizeResumeData {
|
function buildSavePayload(): CustomizeResumeData {
|
||||||
return {
|
return {
|
||||||
|
// 主表字段:以原始数据为基础,覆盖编辑数据,确保不丢失任何字段
|
||||||
resume: {
|
resume: {
|
||||||
|
...(props.resumeData?.resume || {}),
|
||||||
avatarUrl: editData.resume.avatarUrl,
|
avatarUrl: editData.resume.avatarUrl,
|
||||||
name: editData.resume.name,
|
name: editData.resume.name,
|
||||||
email: editData.resume.email,
|
email: editData.resume.email,
|
||||||
@@ -423,12 +463,16 @@ function addItem(type: 'education' | 'work' | 'internship' | 'project' | 'compet
|
|||||||
const emptyDesc: DescParagraph[] = [{ id: genId(), text: '' }]
|
const emptyDesc: DescParagraph[] = [{ id: genId(), text: '' }]
|
||||||
if (type === 'education') {
|
if (type === 'education') {
|
||||||
editData.education.push({ id, school: '', major: '', degree: '本科', studyType: '全日制', startDate: '', endDate: '', description: emptyDesc })
|
editData.education.push({ id, school: '', major: '', degree: '本科', studyType: '全日制', startDate: '', endDate: '', description: emptyDesc })
|
||||||
|
descTextMap.education.push('')
|
||||||
} else if (type === 'work') {
|
} else if (type === 'work') {
|
||||||
editData.work.push({ id, companyName: '', position: '', startDate: '', endDate: '', description: emptyDesc })
|
editData.work.push({ id, companyName: '', position: '', startDate: '', endDate: '', description: emptyDesc })
|
||||||
|
descTextMap.work.push('')
|
||||||
} else if (type === 'internship') {
|
} else if (type === 'internship') {
|
||||||
editData.internship.push({ id, companyName: '', position: '', startDate: '', endDate: '', description: emptyDesc })
|
editData.internship.push({ id, companyName: '', position: '', startDate: '', endDate: '', description: emptyDesc })
|
||||||
|
descTextMap.internship.push('')
|
||||||
} else if (type === 'project') {
|
} else if (type === 'project') {
|
||||||
editData.project.push({ id, companyName: '', projectName: '', role: '', startDate: '', endDate: '', description: emptyDesc })
|
editData.project.push({ id, companyName: '', projectName: '', role: '', startDate: '', endDate: '', description: emptyDesc })
|
||||||
|
descTextMap.project.push('')
|
||||||
} else if (type === 'competition') {
|
} else if (type === 'competition') {
|
||||||
editData.competition.push({ id, competitionName: '', award: '', awardDate: '', description: emptyDesc })
|
editData.competition.push({ id, competitionName: '', award: '', awardDate: '', description: emptyDesc })
|
||||||
}
|
}
|
||||||
@@ -438,17 +482,10 @@ function addItem(type: 'education' | 'work' | 'internship' | 'project' | 'compet
|
|||||||
/** 删除一条经历记录 */
|
/** 删除一条经历记录 */
|
||||||
function removeItem(type: 'education' | 'work' | 'internship' | 'project' | 'competition', idx: number) {
|
function removeItem(type: 'education' | 'work' | 'internship' | 'project' | 'competition', idx: number) {
|
||||||
editData[type].splice(idx, 1)
|
editData[type].splice(idx, 1)
|
||||||
autoSave()
|
// 同步更新描述文本映射
|
||||||
}
|
if (type !== 'competition' && descTextMap[type]) {
|
||||||
|
descTextMap[type].splice(idx, 1)
|
||||||
/** 新增一条描述段落 */
|
}
|
||||||
function addDesc(type: 'education' | 'work' | 'internship' | 'project', itemIdx: number) {
|
|
||||||
editData[type][itemIdx].description.push({ id: genId(), text: '' })
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 删除一条描述段落 */
|
|
||||||
function removeDesc(type: 'education' | 'work' | 'internship' | 'project', itemIdx: number, descIdx: number) {
|
|
||||||
editData[type][itemIdx].description.splice(descIdx, 1)
|
|
||||||
autoSave()
|
autoSave()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<!-- 简历HTML模板组件:用于预览和后续导出PDF/Word -->
|
<!-- 简历HTML模板组件:用于预览和后续导出PDF/Word -->
|
||||||
<div class="job-resume-template" ref="resumeRef">
|
<div class="job-resume-template" ref="resumeRef">
|
||||||
<div class="resume-html">
|
<div class="resume-html" :class="{ 'resume-html--export': props.mode === 'export' }">
|
||||||
<!-- 姓名 -->
|
<!-- 姓名 -->
|
||||||
<h1 class="resume-html__name">
|
<h1 class="resume-html__name">
|
||||||
<template v-if="showDiff">
|
<template v-if="showDiff">
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
<template v-if="resumeData.summary">
|
<template v-if="resumeData.summary">
|
||||||
<div class="resume-html__section-title">个人概述</div>
|
<div class="resume-html__section-title">个人概述</div>
|
||||||
<div class="resume-html__divider"></div>
|
<div class="resume-html__divider"></div>
|
||||||
<div class="resume-html__summary">
|
<div class="resume-html__summary" :class="{ 'resume-html__diff-block': isSummaryDiffBlock() }">
|
||||||
<template v-if="showDiff">
|
<template v-if="showDiff">
|
||||||
<template v-for="(seg, si) in diffText(oldResumeData?.summary, resumeData.summary)" :key="'sum-' + si">
|
<template v-for="(seg, si) in diffText(oldResumeData?.summary, resumeData.summary)" :key="'sum-' + si">
|
||||||
<span v-if="seg.highlight" class="resume-html__diff-highlight">{{ seg.text }}</span>
|
<span v-if="seg.highlight" class="resume-html__diff-highlight">{{ seg.text }}</span>
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
<template v-if="resumeData.educations && resumeData.educations.length">
|
<template v-if="resumeData.educations && resumeData.educations.length">
|
||||||
<div class="resume-html__section-title">教育背景</div>
|
<div class="resume-html__section-title">教育背景</div>
|
||||||
<div class="resume-html__divider"></div>
|
<div class="resume-html__divider"></div>
|
||||||
<div v-for="(edu, idx) in resumeData.educations" :key="'edu-' + idx" class="resume-html__item">
|
<div v-for="(edu, idx) in resumeData.educations" :key="'edu-' + idx" class="resume-html__item" :class="{ 'resume-html__diff-block': isEduDiffBlock(idx) }">
|
||||||
<div class="resume-html__item-header">
|
<div class="resume-html__item-header">
|
||||||
<span class="resume-html__item-main">
|
<span class="resume-html__item-main">
|
||||||
<!-- 教育经历标题差异对比 -->
|
<!-- 教育经历标题差异对比 -->
|
||||||
@@ -77,7 +77,7 @@
|
|||||||
<template v-if="resumeData.workExperiences && resumeData.workExperiences.length">
|
<template v-if="resumeData.workExperiences && resumeData.workExperiences.length">
|
||||||
<div class="resume-html__section-title">工作经历</div>
|
<div class="resume-html__section-title">工作经历</div>
|
||||||
<div class="resume-html__divider"></div>
|
<div class="resume-html__divider"></div>
|
||||||
<div v-for="(work, idx) in resumeData.workExperiences" :key="'work-' + idx" class="resume-html__item">
|
<div v-for="(work, idx) in resumeData.workExperiences" :key="'work-' + idx" class="resume-html__item" :class="{ 'resume-html__diff-block': isWorkDiffBlock(idx) }">
|
||||||
<div class="resume-html__item-header">
|
<div class="resume-html__item-header">
|
||||||
<span class="resume-html__item-main">
|
<span class="resume-html__item-main">
|
||||||
<!-- 工作经历标题差异对比 -->
|
<!-- 工作经历标题差异对比 -->
|
||||||
@@ -114,7 +114,7 @@
|
|||||||
<template v-if="resumeData.internships && resumeData.internships.length">
|
<template v-if="resumeData.internships && resumeData.internships.length">
|
||||||
<div class="resume-html__section-title">实习经历</div>
|
<div class="resume-html__section-title">实习经历</div>
|
||||||
<div class="resume-html__divider"></div>
|
<div class="resume-html__divider"></div>
|
||||||
<div v-for="(intern, idx) in resumeData.internships" :key="'intern-' + idx" class="resume-html__item">
|
<div v-for="(intern, idx) in resumeData.internships" :key="'intern-' + idx" class="resume-html__item" :class="{ 'resume-html__diff-block': isInternDiffBlock(idx) }">
|
||||||
<div class="resume-html__item-header">
|
<div class="resume-html__item-header">
|
||||||
<span class="resume-html__item-main">
|
<span class="resume-html__item-main">
|
||||||
<!-- 实习经历标题差异对比 -->
|
<!-- 实习经历标题差异对比 -->
|
||||||
@@ -151,7 +151,7 @@
|
|||||||
<template v-if="resumeData.projects && resumeData.projects.length">
|
<template v-if="resumeData.projects && resumeData.projects.length">
|
||||||
<div class="resume-html__section-title">项目经历</div>
|
<div class="resume-html__section-title">项目经历</div>
|
||||||
<div class="resume-html__divider"></div>
|
<div class="resume-html__divider"></div>
|
||||||
<div v-for="(proj, idx) in resumeData.projects" :key="'proj-' + idx" class="resume-html__item">
|
<div v-for="(proj, idx) in resumeData.projects" :key="'proj-' + idx" class="resume-html__item" :class="{ 'resume-html__diff-block': isProjDiffBlock(idx) }">
|
||||||
<div class="resume-html__item-header">
|
<div class="resume-html__item-header">
|
||||||
<span class="resume-html__item-main">
|
<span class="resume-html__item-main">
|
||||||
<!-- 项目经历标题差异对比 -->
|
<!-- 项目经历标题差异对比 -->
|
||||||
@@ -196,7 +196,7 @@
|
|||||||
<template v-if="resumeData.competitions && resumeData.competitions.length">
|
<template v-if="resumeData.competitions && resumeData.competitions.length">
|
||||||
<div class="resume-html__section-title">获奖经历</div>
|
<div class="resume-html__section-title">获奖经历</div>
|
||||||
<div class="resume-html__divider"></div>
|
<div class="resume-html__divider"></div>
|
||||||
<div v-for="(comp, idx) in resumeData.competitions" :key="'comp-' + idx" class="resume-html__item">
|
<div v-for="(comp, idx) in resumeData.competitions" :key="'comp-' + idx" class="resume-html__item" :class="{ 'resume-html__diff-block': isCompDiffBlock(idx) }">
|
||||||
<div class="resume-html__item-header">
|
<div class="resume-html__item-header">
|
||||||
<span class="resume-html__item-main">
|
<span class="resume-html__item-main">
|
||||||
<!-- 竞赛经历标题差异对比 -->
|
<!-- 竞赛经历标题差异对比 -->
|
||||||
@@ -349,6 +349,8 @@ const props = defineProps<{
|
|||||||
showDiff?: boolean
|
showDiff?: boolean
|
||||||
/** 旧简历数据(差异对比时使用,与resumeData对比) */
|
/** 旧简历数据(差异对比时使用,与resumeData对比) */
|
||||||
oldResumeData?: ResumeTemplateData
|
oldResumeData?: ResumeTemplateData
|
||||||
|
/** 模式:preview=预览(小padding),export=导出(大padding),默认preview */
|
||||||
|
mode?: 'preview' | 'export'
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
// ==================== DOM引用(供父组件获取HTML内容) ====================
|
// ==================== DOM引用(供父组件获取HTML内容) ====================
|
||||||
@@ -372,6 +374,74 @@ const hasSkillsSection = computed(() => {
|
|||||||
(props.resumeData.certificates && props.resumeData.certificates.length > 0)
|
(props.resumeData.certificates && props.resumeData.certificates.length > 0)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// ==================== 差异块背景判断方法 ====================
|
||||||
|
|
||||||
|
/** 个人概述是否有差异 */
|
||||||
|
function isSummaryDiffBlock(): boolean {
|
||||||
|
if (!props.showDiff || !props.oldResumeData) return false
|
||||||
|
return props.oldResumeData.summary !== props.resumeData.summary
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 教育经历某项是否有差异 */
|
||||||
|
function isEduDiffBlock(idx: number): boolean {
|
||||||
|
if (!props.showDiff || !props.oldResumeData) return false
|
||||||
|
const oldEdu = props.oldResumeData.educations?.[idx]
|
||||||
|
const newEdu = props.resumeData.educations?.[idx]
|
||||||
|
if (!oldEdu || !newEdu) return true
|
||||||
|
if (oldEdu.school !== newEdu.school || oldEdu.major !== newEdu.major || oldEdu.degree !== newEdu.degree) return true
|
||||||
|
const oldDescs = oldEdu.description?.map(d => d.text).join('') || ''
|
||||||
|
const newDescs = newEdu.description?.map(d => d.text).join('') || ''
|
||||||
|
return oldDescs !== newDescs
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 工作经历某项是否有差异 */
|
||||||
|
function isWorkDiffBlock(idx: number): boolean {
|
||||||
|
if (!props.showDiff || !props.oldResumeData) return false
|
||||||
|
const oldItem = props.oldResumeData.workExperiences?.[idx]
|
||||||
|
const newItem = props.resumeData.workExperiences?.[idx]
|
||||||
|
if (!oldItem || !newItem) return true
|
||||||
|
if (oldItem.companyName !== newItem.companyName || oldItem.position !== newItem.position) return true
|
||||||
|
const oldDescs = oldItem.description?.map(d => d.text).join('') || ''
|
||||||
|
const newDescs = newItem.description?.map(d => d.text).join('') || ''
|
||||||
|
return oldDescs !== newDescs
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 实习经历某项是否有差异 */
|
||||||
|
function isInternDiffBlock(idx: number): boolean {
|
||||||
|
if (!props.showDiff || !props.oldResumeData) return false
|
||||||
|
const oldItem = props.oldResumeData.internships?.[idx]
|
||||||
|
const newItem = props.resumeData.internships?.[idx]
|
||||||
|
if (!oldItem || !newItem) return true
|
||||||
|
if (oldItem.companyName !== newItem.companyName || oldItem.position !== newItem.position) return true
|
||||||
|
const oldDescs = oldItem.description?.map(d => d.text).join('') || ''
|
||||||
|
const newDescs = newItem.description?.map(d => d.text).join('') || ''
|
||||||
|
return oldDescs !== newDescs
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 项目经历某项是否有差异 */
|
||||||
|
function isProjDiffBlock(idx: number): boolean {
|
||||||
|
if (!props.showDiff || !props.oldResumeData) return false
|
||||||
|
const oldItem = props.oldResumeData.projects?.[idx]
|
||||||
|
const newItem = props.resumeData.projects?.[idx]
|
||||||
|
if (!oldItem || !newItem) return true
|
||||||
|
if (oldItem.projectName !== newItem.projectName || oldItem.role !== newItem.role || oldItem.companyName !== newItem.companyName) return true
|
||||||
|
const oldDescs = oldItem.description?.map(d => d.text).join('') || ''
|
||||||
|
const newDescs = newItem.description?.map(d => d.text).join('') || ''
|
||||||
|
return oldDescs !== newDescs
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 竞赛经历某项是否有差异 */
|
||||||
|
function isCompDiffBlock(idx: number): boolean {
|
||||||
|
if (!props.showDiff || !props.oldResumeData) return false
|
||||||
|
const oldItem = props.oldResumeData.competitions?.[idx]
|
||||||
|
const newItem = props.resumeData.competitions?.[idx]
|
||||||
|
if (!oldItem || !newItem) return true
|
||||||
|
if (oldItem.competitionName !== newItem.competitionName || oldItem.award !== newItem.award) return true
|
||||||
|
const oldDescs = oldItem.description?.map(d => d.text).join('') || ''
|
||||||
|
const newDescs = newItem.description?.map(d => d.text).join('') || ''
|
||||||
|
return oldDescs !== newDescs
|
||||||
|
}
|
||||||
|
|
||||||
// ==================== 差异对比工具方法 ====================
|
// ==================== 差异对比工具方法 ====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
<!-- 隐藏的简历模板,用于导出时渲染DOM -->
|
<!-- 隐藏的简历模板,用于导出时渲染DOM -->
|
||||||
<div v-if="exportTemplateData" style="position:absolute;left:-9999px;top:0;">
|
<div v-if="exportTemplateData" style="position:absolute;left:-9999px;top:0;">
|
||||||
<JobResumeTemplate ref="exportTemplateRef" :resume-data="exportTemplateData" />
|
<JobResumeTemplate ref="exportTemplateRef" :resume-data="exportTemplateData" mode="export" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
+9
-2
@@ -125,7 +125,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- 模式3:简历预览 -->
|
<!-- 模式3:简历预览 -->
|
||||||
<div v-else-if="rightPanelMode === 'resume'" class="agent-main__right-resume">
|
<div v-else-if="rightPanelMode === 'resume'" class="agent-main__right-resume">
|
||||||
<JobResumeTemplate ref="applyResumeTemplateRef" :resume-data="applyResumeData" />
|
<JobResumeTemplate ref="applyResumeTemplateRef" :resume-data="applyResumeData" :mode="applyResumeMode" />
|
||||||
</div>
|
</div>
|
||||||
<!-- 模式4:岗位预览 -->
|
<!-- 模式4:岗位预览 -->
|
||||||
<AgentJobPreviewPanel
|
<AgentJobPreviewPanel
|
||||||
@@ -675,6 +675,9 @@ const applyResumeData = ref<ResumeTemplateData>({} as ResumeTemplateData)
|
|||||||
/** 右侧面板简历模板组件引用 */
|
/** 右侧面板简历模板组件引用 */
|
||||||
const applyResumeTemplateRef = ref<InstanceType<typeof JobResumeTemplate> | null>(null)
|
const applyResumeTemplateRef = ref<InstanceType<typeof JobResumeTemplate> | null>(null)
|
||||||
|
|
||||||
|
/** 简历模板模式:preview=预览,export=导出 */
|
||||||
|
const applyResumeMode = ref<'preview' | 'export'>('preview')
|
||||||
|
|
||||||
/** 进度条定时器 */
|
/** 进度条定时器 */
|
||||||
let progressTimer: ReturnType<typeof setInterval> | null = null
|
let progressTimer: ReturnType<typeof setInterval> | null = null
|
||||||
|
|
||||||
@@ -879,7 +882,8 @@ async function handleConfirmResumeStep(index: number) {
|
|||||||
progressItem.step = 3
|
progressItem.step = 3
|
||||||
saveProgressToStorage()
|
saveProgressToStorage()
|
||||||
|
|
||||||
// 生成 PDF 并缓存到 localStorage
|
// 切换到导出模式(大padding)
|
||||||
|
applyResumeMode.value = 'export'
|
||||||
await nextTick()
|
await nextTick()
|
||||||
const element = applyResumeTemplateRef.value?.resumeRef
|
const element = applyResumeTemplateRef.value?.resumeRef
|
||||||
if (element) {
|
if (element) {
|
||||||
@@ -893,8 +897,11 @@ async function handleConfirmResumeStep(index: number) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 恢复预览模式
|
||||||
|
applyResumeMode.value = 'preview'
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('[Agent] 简历PDF缓存失败', e)
|
console.error('[Agent] 简历PDF缓存失败', e)
|
||||||
|
applyResumeMode.value = 'preview'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1193,7 +1193,21 @@ async function updateModuleContent(item: FixAllSubmitItem) {
|
|||||||
// 更新个人概述
|
// 更新个人概述
|
||||||
const newSummary = item.newContent as string
|
const newSummary = item.newContent as string
|
||||||
resumeMain.value.summary = newSummary
|
resumeMain.value.summary = newSummary
|
||||||
await saveResumeMain({ resumeId, summary: newSummary })
|
await saveResumeMain({
|
||||||
|
resumeId,
|
||||||
|
resumeName: resumeMain.value.resumeName,
|
||||||
|
targetPosition: resumeMain.value.targetPosition,
|
||||||
|
name: resumeMain.value.name || '',
|
||||||
|
email: resumeMain.value.email || '',
|
||||||
|
mobileNumber: resumeMain.value.mobileNumber || '',
|
||||||
|
city: resumeMain.value.city || '',
|
||||||
|
regionCode: resumeMain.value.regionCode || '',
|
||||||
|
wechatNumber: resumeMain.value.wechatNumber || '',
|
||||||
|
portfolioUrl: resumeMain.value.portfolioUrl || '',
|
||||||
|
skills: resumeMain.value.skills || [],
|
||||||
|
certificates: resumeMain.value.certificates || [],
|
||||||
|
summary: newSummary,
|
||||||
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1230,7 +1244,21 @@ async function handleFixSubmit(content: string[]) {
|
|||||||
// 个人概述:content 只有一个元素,直接更新 summary 字段
|
// 个人概述:content 只有一个元素,直接更新 summary 字段
|
||||||
const newSummary = content.join('\n')
|
const newSummary = content.join('\n')
|
||||||
resumeMain.value.summary = newSummary
|
resumeMain.value.summary = newSummary
|
||||||
await saveResumeMain({ resumeId, summary: newSummary })
|
await saveResumeMain({
|
||||||
|
resumeId,
|
||||||
|
resumeName: resumeMain.value.resumeName,
|
||||||
|
targetPosition: resumeMain.value.targetPosition,
|
||||||
|
name: resumeMain.value.name || '',
|
||||||
|
email: resumeMain.value.email || '',
|
||||||
|
mobileNumber: resumeMain.value.mobileNumber || '',
|
||||||
|
city: resumeMain.value.city || '',
|
||||||
|
regionCode: resumeMain.value.regionCode || '',
|
||||||
|
wechatNumber: resumeMain.value.wechatNumber || '',
|
||||||
|
portfolioUrl: resumeMain.value.portfolioUrl || '',
|
||||||
|
skills: resumeMain.value.skills || [],
|
||||||
|
certificates: resumeMain.value.certificates || [],
|
||||||
|
summary: newSummary,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
// 5 大经历模块:找到对应经历记录,按 id 对应更新 description 数组里的 text
|
// 5 大经历模块:找到对应经历记录,按 id 对应更新 description 数组里的 text
|
||||||
const listMap: Record<string, any[]> = {
|
const listMap: Record<string, any[]> = {
|
||||||
@@ -1529,9 +1557,11 @@ function openEditDrawer(section: string) {
|
|||||||
async function handleSaveEdit(data: Record<string, any>) {
|
async function handleSaveEdit(data: Record<string, any>) {
|
||||||
try {
|
try {
|
||||||
if (editModule.value === 'info') {
|
if (editModule.value === 'info') {
|
||||||
// 保存基本信息到简历主表(含作品集链接)
|
// 保存基本信息到简历主表(含作品集链接)— 传入完整主表字段
|
||||||
await saveResumeMain({
|
await saveResumeMain({
|
||||||
resumeId,
|
resumeId,
|
||||||
|
resumeName: resumeMain.value.resumeName,
|
||||||
|
targetPosition: resumeMain.value.targetPosition,
|
||||||
name: data.name,
|
name: data.name,
|
||||||
email: data.email,
|
email: data.email,
|
||||||
mobileNumber: data.phone,
|
mobileNumber: data.phone,
|
||||||
@@ -1539,6 +1569,9 @@ async function handleSaveEdit(data: Record<string, any>) {
|
|||||||
regionCode: data.location || '',
|
regionCode: data.location || '',
|
||||||
wechatNumber: data.wechat,
|
wechatNumber: data.wechat,
|
||||||
portfolioUrl: data.portfolioUrl,
|
portfolioUrl: data.portfolioUrl,
|
||||||
|
skills: resumeMain.value.skills || [],
|
||||||
|
certificates: resumeMain.value.certificates || [],
|
||||||
|
summary: resumeMain.value.summary || '',
|
||||||
})
|
})
|
||||||
resumeMain.value.name = data.name
|
resumeMain.value.name = data.name
|
||||||
resumeMain.value.email = data.email
|
resumeMain.value.email = data.email
|
||||||
@@ -1548,9 +1581,20 @@ async function handleSaveEdit(data: Record<string, any>) {
|
|||||||
resumeMain.value.wechatNumber = data.wechat
|
resumeMain.value.wechatNumber = data.wechat
|
||||||
resumeMain.value.portfolioUrl = data.portfolioUrl
|
resumeMain.value.portfolioUrl = data.portfolioUrl
|
||||||
} else if (editModule.value === 'summary') {
|
} else if (editModule.value === 'summary') {
|
||||||
// 保存个人概述到简历主表
|
// 保存个人概述到简历主表 — 传入完整主表字段
|
||||||
await saveResumeMain({
|
await saveResumeMain({
|
||||||
resumeId,
|
resumeId,
|
||||||
|
resumeName: resumeMain.value.resumeName,
|
||||||
|
targetPosition: resumeMain.value.targetPosition,
|
||||||
|
name: resumeMain.value.name || '',
|
||||||
|
email: resumeMain.value.email || '',
|
||||||
|
mobileNumber: resumeMain.value.mobileNumber || '',
|
||||||
|
city: resumeMain.value.city || '',
|
||||||
|
regionCode: resumeMain.value.regionCode || '',
|
||||||
|
wechatNumber: resumeMain.value.wechatNumber || '',
|
||||||
|
portfolioUrl: resumeMain.value.portfolioUrl || '',
|
||||||
|
skills: resumeMain.value.skills || [],
|
||||||
|
certificates: resumeMain.value.certificates || [],
|
||||||
summary: data.summary,
|
summary: data.summary,
|
||||||
})
|
})
|
||||||
resumeMain.value.summary = data.summary
|
resumeMain.value.summary = data.summary
|
||||||
@@ -1685,24 +1729,57 @@ async function handleSaveEdit(data: Record<string, any>) {
|
|||||||
}
|
}
|
||||||
await Promise.all([...addPromises, ...updatePromises, ...deletePromises])
|
await Promise.all([...addPromises, ...updatePromises, ...deletePromises])
|
||||||
} else if (editModule.value === 'portfolio') {
|
} else if (editModule.value === 'portfolio') {
|
||||||
// 保存作品集链接到简历主表
|
// 保存作品集链接到简历主表 — 传入完整主表字段
|
||||||
await saveResumeMain({
|
await saveResumeMain({
|
||||||
resumeId,
|
resumeId,
|
||||||
|
resumeName: resumeMain.value.resumeName,
|
||||||
|
targetPosition: resumeMain.value.targetPosition,
|
||||||
|
name: resumeMain.value.name || '',
|
||||||
|
email: resumeMain.value.email || '',
|
||||||
|
mobileNumber: resumeMain.value.mobileNumber || '',
|
||||||
|
city: resumeMain.value.city || '',
|
||||||
|
regionCode: resumeMain.value.regionCode || '',
|
||||||
|
wechatNumber: resumeMain.value.wechatNumber || '',
|
||||||
portfolioUrl: data.portfolioUrl,
|
portfolioUrl: data.portfolioUrl,
|
||||||
|
skills: resumeMain.value.skills || [],
|
||||||
|
certificates: resumeMain.value.certificates || [],
|
||||||
|
summary: resumeMain.value.summary || '',
|
||||||
})
|
})
|
||||||
resumeMain.value.portfolioUrl = data.portfolioUrl
|
resumeMain.value.portfolioUrl = data.portfolioUrl
|
||||||
} else if (editModule.value === 'skills') {
|
} else if (editModule.value === 'skills') {
|
||||||
// 保存技能到简历主表
|
// 保存技能到简历主表 — 传入完整主表字段
|
||||||
await saveResumeMain({
|
await saveResumeMain({
|
||||||
resumeId,
|
resumeId,
|
||||||
|
resumeName: resumeMain.value.resumeName,
|
||||||
|
targetPosition: resumeMain.value.targetPosition,
|
||||||
|
name: resumeMain.value.name || '',
|
||||||
|
email: resumeMain.value.email || '',
|
||||||
|
mobileNumber: resumeMain.value.mobileNumber || '',
|
||||||
|
city: resumeMain.value.city || '',
|
||||||
|
regionCode: resumeMain.value.regionCode || '',
|
||||||
|
wechatNumber: resumeMain.value.wechatNumber || '',
|
||||||
|
portfolioUrl: resumeMain.value.portfolioUrl || '',
|
||||||
skills: [...data.skills],
|
skills: [...data.skills],
|
||||||
|
certificates: resumeMain.value.certificates || [],
|
||||||
|
summary: resumeMain.value.summary || '',
|
||||||
})
|
})
|
||||||
resumeMain.value.skills = [...data.skills]
|
resumeMain.value.skills = [...data.skills]
|
||||||
} else if (editModule.value === 'certificate') {
|
} else if (editModule.value === 'certificate') {
|
||||||
// 保存证书到简历主表
|
// 保存证书到简历主表 — 传入完整主表字段
|
||||||
await saveResumeMain({
|
await saveResumeMain({
|
||||||
resumeId,
|
resumeId,
|
||||||
|
resumeName: resumeMain.value.resumeName,
|
||||||
|
targetPosition: resumeMain.value.targetPosition,
|
||||||
|
name: resumeMain.value.name || '',
|
||||||
|
email: resumeMain.value.email || '',
|
||||||
|
mobileNumber: resumeMain.value.mobileNumber || '',
|
||||||
|
city: resumeMain.value.city || '',
|
||||||
|
regionCode: resumeMain.value.regionCode || '',
|
||||||
|
wechatNumber: resumeMain.value.wechatNumber || '',
|
||||||
|
portfolioUrl: resumeMain.value.portfolioUrl || '',
|
||||||
|
skills: resumeMain.value.skills || [],
|
||||||
certificates: [...data.certificates],
|
certificates: [...data.certificates],
|
||||||
|
summary: resumeMain.value.summary || '',
|
||||||
})
|
})
|
||||||
resumeMain.value.certificates = [...data.certificates]
|
resumeMain.value.certificates = [...data.certificates]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user