登陆也左侧调整
This commit is contained in:
@@ -518,6 +518,9 @@ body:not(#_) {
|
|||||||
.color-9B9EAB{
|
.color-9B9EAB{
|
||||||
color:#9B9EAB;
|
color:#9B9EAB;
|
||||||
}
|
}
|
||||||
|
.color-accent{
|
||||||
|
color:$accent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*border*/
|
/*border*/
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
@use '../variables' as *;
|
||||||
/* 登录页面 — 左右分栏全屏布局 */
|
/* 登录页面 — 左右分栏全屏布局 */
|
||||||
.login-view {
|
.login-view {
|
||||||
font-size: 0.14rem;
|
font-size: 0.14rem;
|
||||||
@@ -168,7 +169,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
width: 43%;
|
width: 43%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: #F6FDFB;
|
background: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Logo 行(右侧及简历阶段通用) */
|
/* Logo 行(右侧及简历阶段通用) */
|
||||||
@@ -176,6 +177,12 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.12rem;
|
gap: 0.12rem;
|
||||||
|
width: 3.41rem;
|
||||||
|
|
||||||
|
img{
|
||||||
|
width: 1.6rem;
|
||||||
|
height: 0.4rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-view__logo-box {
|
.login-view__logo-box {
|
||||||
@@ -215,112 +222,135 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.login-view__logo-row--right {
|
.login-view__logo-row--right {
|
||||||
margin-bottom: 0.4rem;
|
margin-bottom: 0.6rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 表单包裹 */
|
/* 表单包裹 */
|
||||||
.login-view__form-wrap {
|
.login-view__form-wrap {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
gap: 0.24rem;
|
||||||
gap: 0.28rem;
|
width: 3.41rem;
|
||||||
width: 4rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 标题 */
|
/* 标题 */
|
||||||
.login-view__heading {
|
.login-view__heading {
|
||||||
width: 100%;
|
width: 3.41rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.1rem;
|
gap: 0.05rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-view__title {
|
.login-view__title {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-size: 0.32rem;
|
font-size: 0.18rem;
|
||||||
line-height: 0.39rem;
|
line-height: 0.22rem;
|
||||||
color: #132034;
|
color: #18181A;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-view__subtitle {
|
.login-view__subtitle {
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 0.15rem;
|
font-size: 0.10rem;
|
||||||
line-height: 0.18rem;
|
line-height: 0.12rem;
|
||||||
color: #64748B;
|
color: #616367;
|
||||||
|
|
||||||
|
>span:nth-child(2){
|
||||||
|
color: $accent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==================== 手机号输入行 ==================== */
|
/* ==================== 手机号输入行 ==================== */
|
||||||
.login-view__phone-row {
|
.login-view__phone-row {
|
||||||
|
box-sizing: border-box;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 100%;
|
width: 3.41rem;
|
||||||
height: 0.52rem;
|
height: 0.40rem;
|
||||||
border-radius: 0.12rem;
|
background: #FFFFFF;
|
||||||
overflow: hidden;
|
border: 1px solid #C8C9CD;
|
||||||
|
box-shadow: 0 0.08rem 0.20rem rgba(15, 83, 87, 0.05);
|
||||||
|
border-radius: 0.08rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-view__country-code {
|
/* 手机图标 */
|
||||||
|
.login-view__phone-icon {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0 0.16rem;
|
justify-content: center;
|
||||||
gap: 0.06rem;
|
width: 0.18rem;
|
||||||
width: 0.96rem;
|
height: 0.18rem;
|
||||||
height: 100%;
|
margin-left: 0.16rem;
|
||||||
background: #F3FFFD;
|
flex-shrink: 0;
|
||||||
border: 1px solid #BFE8E2;
|
|
||||||
border-radius: 0.12rem 0 0 0.12rem;
|
svg {
|
||||||
cursor: pointer;
|
width: 0.18rem;
|
||||||
|
height: 0.18rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-view__flag {
|
/* 国家码标签 */
|
||||||
font-size: 0.16rem;
|
.login-view__country-label {
|
||||||
line-height: 1;
|
margin-left: 0.06rem;
|
||||||
}
|
|
||||||
|
|
||||||
.login-view__code-text {
|
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-size: 0.15rem;
|
font-size: 0.12rem;
|
||||||
line-height: 0.18rem;
|
line-height: 0.15rem;
|
||||||
color: #132034;
|
color: #202124;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-view__code-arrow {
|
/* 下拉箭头 */
|
||||||
font-size: 0.11rem;
|
.login-view__country-chevron {
|
||||||
color: #94A3B8;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 0.20rem;
|
||||||
|
height: 0.20rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 0.20rem;
|
||||||
|
height: 0.20rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-view__separator {
|
/* 分隔线 */
|
||||||
|
.login-view__input-divider {
|
||||||
width: 1px;
|
width: 1px;
|
||||||
height: 100%;
|
height: 0.30rem;
|
||||||
background: #BFE8E2;
|
background: #E7F2F3;
|
||||||
|
margin: 0 0.16rem;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 手机号输入框 */
|
||||||
.login-view__phone-input {
|
.login-view__phone-input {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 0 0.16rem;
|
border: none;
|
||||||
background: #FAFBFC;
|
background: transparent;
|
||||||
border: 1px solid #E2E8F0;
|
font-weight: 400;
|
||||||
border-left: none;
|
font-size: 0.12rem;
|
||||||
border-radius: 0 0.12rem 0.12rem 0;
|
line-height: 0.15rem;
|
||||||
font-size: 0.15rem;
|
color: #202124;
|
||||||
color: #132034;
|
|
||||||
outline: none;
|
outline: none;
|
||||||
|
|
||||||
&::placeholder {
|
&::placeholder {
|
||||||
color: #94A3B8;
|
color: #939599;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==================== 发送验证码按钮(步骤一) ==================== */
|
/* ==================== 发送验证码按钮(步骤一) ==================== */
|
||||||
.login-view__send-btn {
|
.login-view__send-btn {
|
||||||
width: 100%;
|
width: 3.41rem;
|
||||||
height: 0.52rem;
|
height: 0.40rem;
|
||||||
background: linear-gradient(90deg, #12C7BE 0%, #06B6D4 100%);
|
background: linear-gradient(90deg, #4FC2C9 0%, #42A8B3 100%);
|
||||||
border-radius: 0.12rem;
|
box-shadow: 0 0.16rem 0.30rem rgba(15, 83, 87, 0.15);
|
||||||
|
border-radius: 0.08rem;
|
||||||
border: none;
|
border: none;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 0.16rem;
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.15rem;
|
||||||
color: #FFFFFF;
|
color: #FFFFFF;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: opacity 0.2s;
|
transition: opacity 0.2s;
|
||||||
@@ -361,8 +391,8 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 0.56rem;
|
width: 0.42rem;
|
||||||
height: 0.64rem;
|
height: 0.46rem;
|
||||||
background: #FAFBFC;
|
background: #FAFBFC;
|
||||||
border: 1px solid #E2E8F0;
|
border: 1px solid #E2E8F0;
|
||||||
border-radius: 0.12rem;
|
border-radius: 0.12rem;
|
||||||
@@ -409,8 +439,8 @@
|
|||||||
color: #64748B;
|
color: #64748B;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding-right: 0.1rem;
|
padding-right: 0.1rem;
|
||||||
margin-top: -0.19rem;
|
margin-top: -0.14rem;
|
||||||
margin-bottom: -0.10rem;
|
margin-bottom: -0.06rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-view__sms-status--error {
|
.login-view__sms-status--error {
|
||||||
@@ -420,12 +450,12 @@
|
|||||||
/* ==================== 状态按钮(步骤二) ==================== */
|
/* ==================== 状态按钮(步骤二) ==================== */
|
||||||
.login-view__status-btn {
|
.login-view__status-btn {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 0.52rem;
|
height: 0.4rem;
|
||||||
background: linear-gradient(90deg, #12C7BE 0%, #06B6D4 100%);
|
background: linear-gradient(90deg, #12C7BE 0%, #06B6D4 100%);
|
||||||
border-radius: 0.12rem;
|
border-radius: 0.12rem;
|
||||||
border: none;
|
border: none;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 0.16rem;
|
font-size: 0.14rem;
|
||||||
color: #FFFFFF;
|
color: #FFFFFF;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -464,6 +494,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.06rem;
|
gap: 0.06rem;
|
||||||
|
width: 3.41rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-view__checkbox {
|
.login-view__checkbox {
|
||||||
@@ -472,17 +503,18 @@
|
|||||||
height: 0.18rem;
|
height: 0.18rem;
|
||||||
background: #FFFFFF;
|
background: #FFFFFF;
|
||||||
border: 1.5px solid #CBD5E1;
|
border: 1.5px solid #CBD5E1;
|
||||||
border-radius: 0.05rem;
|
border-radius: 0.04rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-view__checkbox--checked {
|
.login-view__checkbox--checked {
|
||||||
background: #12C7BE;
|
background: #4FC2C9;
|
||||||
border-color: #12C7BE;
|
border-color: #4FC2C9;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-view__check-icon {
|
.login-view__check-icon {
|
||||||
@@ -496,14 +528,14 @@
|
|||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 0.12rem;
|
font-size: 0.12rem;
|
||||||
line-height: 0.15rem;
|
line-height: 0.15rem;
|
||||||
color: #94A3B8;
|
color: #616367;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-view__agreement-link {
|
.login-view__agreement-link {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-size: 0.12rem;
|
font-size: 0.12rem;
|
||||||
line-height: 0.15rem;
|
line-height: 0.15rem;
|
||||||
color: #12C7BE;
|
color: #42A8B3;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
@@ -515,17 +547,16 @@
|
|||||||
|
|
||||||
/* ==================== 简历上传阶段 — 右侧面板 ==================== */
|
/* ==================== 简历上传阶段 — 右侧面板 ==================== */
|
||||||
.login-view__form-wrap--resume {
|
.login-view__form-wrap--resume {
|
||||||
width: 4.6rem;
|
width: 3.41rem;
|
||||||
min-height: 4rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 上传区域 */
|
/* 上传区域 */
|
||||||
.login-view__upload-area {
|
.login-view__upload-area {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0.6rem 0.4rem;
|
padding: 0.4rem 0.4rem;
|
||||||
border: 1px dashed #E2E8F0;
|
border: 2px solid #D6F1EF;
|
||||||
border-radius: 0.12rem;
|
border-radius: 0.12rem;
|
||||||
background: #FFFFFF;
|
background: #F6FFFF;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -560,10 +591,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.login-view__upload-btn {
|
.login-view__upload-btn {
|
||||||
padding: 0.14rem 0.4rem;
|
height: 0.4rem;
|
||||||
|
line-height: 0.4rem;
|
||||||
background: linear-gradient(90deg, #12C7BE 0%, #06B6D4 100%);
|
background: linear-gradient(90deg, #12C7BE 0%, #06B6D4 100%);
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 0.26rem;
|
border-radius: 0.08rem;
|
||||||
font-size: 0.16rem;
|
font-size: 0.16rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #FFFFFF;
|
color: #FFFFFF;
|
||||||
@@ -575,29 +607,387 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 解析中状态 */
|
/* 解析中状态 — 新版步骤面板 */
|
||||||
.login-view__parsing {
|
.login-view__parse-panel {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 3.41rem;
|
||||||
|
padding: 0.24rem;
|
||||||
|
background: #F6FFFF;
|
||||||
|
border: 1px solid #D6F1EF;
|
||||||
|
border-radius: 0.08rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 进度条头部 */
|
||||||
|
.login-view__parse-progress-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 0.08rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__parse-progress-label {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.15rem;
|
||||||
|
color: #616367;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__parse-progress-percent {
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.15rem;
|
||||||
|
color: #42A8B3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 进度轨道 */
|
||||||
|
.login-view__parse-progress-rail {
|
||||||
|
width: 100%;
|
||||||
|
height: 0.06rem;
|
||||||
|
background: #E7F2F3;
|
||||||
|
border-radius: 0.03rem;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-bottom: 0.20rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__parse-progress-fill {
|
||||||
|
height: 100%;
|
||||||
|
background: #4FC2C9;
|
||||||
|
border-radius: 0.03rem;
|
||||||
|
transition: width 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 步骤列表 */
|
||||||
|
.login-view__parse-steps {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
}
|
||||||
|
|
||||||
|
.login-view__parse-step-item {
|
||||||
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
width: 100%;
|
position: relative;
|
||||||
min-height: 3rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-view__parsing-title {
|
.login-view__parse-step-left {
|
||||||
font-size: 0.32rem;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 0.10rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 步骤圆圈 — 完成(实心深色) */
|
||||||
|
.login-view__parse-dot {
|
||||||
|
width: 0.12rem;
|
||||||
|
height: 0.12rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__parse-dot--done {
|
||||||
|
background: #4FC2C9;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 步骤圆圈 — 进行中(光晕 + 呼吸内圆) */
|
||||||
|
.login-view__parse-dot--active {
|
||||||
|
width: 0.16rem;
|
||||||
|
height: 0.16rem;
|
||||||
|
background: #E7FAF5;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-left: -0.02rem;
|
||||||
|
margin-right: -0.02rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__parse-dot-pulse {
|
||||||
|
width: 0.08rem;
|
||||||
|
height: 0.08rem;
|
||||||
|
background: #4FC2C9;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: parse-dot-breathe 1.2s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes parse-dot-breathe {
|
||||||
|
0%, 100% { transform: scale(0.7); opacity: 0.7; }
|
||||||
|
50% { transform: scale(1.2); opacity: 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 步骤圆圈 — 等待(浅色) */
|
||||||
|
.login-view__parse-dot--pending {
|
||||||
|
background: #D6F1EF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 连接线 */
|
||||||
|
.login-view__parse-connector {
|
||||||
|
width: 0.02rem;
|
||||||
|
height: 0.18rem;
|
||||||
|
background: #D6F1EF;
|
||||||
|
border-radius: 0.01rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 步骤文字 */
|
||||||
|
.login-view__parse-step-text {
|
||||||
|
flex: 1;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.15rem;
|
||||||
|
color: #18181A;
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__parse-step-text--pending {
|
||||||
|
font-weight: 400;
|
||||||
|
color: #616367;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 步骤状态文字 */
|
||||||
|
.login-view__parse-step-state {
|
||||||
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.15rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-left: 0.10rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__parse-step-state--done {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #42A8B3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__parse-step-state--active {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #42A8B3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__parse-step-state--pending {
|
||||||
|
font-weight: 400;
|
||||||
|
color: #939599;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 解析中按钮(禁用样式) */
|
||||||
|
.login-view__parse-btn {
|
||||||
|
width: 3.41rem;
|
||||||
|
height: 0.40rem;
|
||||||
|
background: #A6EAE7;
|
||||||
|
border-radius: 0.08rem;
|
||||||
|
border: none;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.15rem;
|
||||||
|
color: #FFFFFF;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==================== 状态4:上传成功面板 ==================== */
|
||||||
|
.login-view__success-panel {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 3.41rem;
|
||||||
|
padding: 0.28rem 0.24rem;
|
||||||
|
background: #F6FFFB;
|
||||||
|
border: 1px solid #BCEED7;
|
||||||
|
border-radius: 0.08rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__success-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.14rem;
|
||||||
|
margin-bottom: 0.24rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__success-icon-bg {
|
||||||
|
width: 0.40rem;
|
||||||
|
height: 0.40rem;
|
||||||
|
background: #E7FAF0;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__success-icon-mark {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: #132034;
|
font-size: 0.18rem;
|
||||||
margin-bottom: 0.12rem;
|
line-height: 0.22rem;
|
||||||
|
color: #22B36A;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-view__parsing-subtitle {
|
.login-view__success-header-text {
|
||||||
font-size: 0.15rem;
|
display: flex;
|
||||||
color: #64748B;
|
flex-direction: column;
|
||||||
|
gap: 0.04rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 失败状态标题红色 */
|
.login-view__success-title {
|
||||||
.login-view__title--error {
|
font-weight: 500;
|
||||||
color: #12C7BE;
|
font-size: 0.13rem;
|
||||||
|
line-height: 0.16rem;
|
||||||
|
color: #18181A;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__success-detail {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.15rem;
|
||||||
|
color: #616367;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__success-tips {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__success-tip-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.10rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__success-tip-dot {
|
||||||
|
width: 0.06rem;
|
||||||
|
height: 0.06rem;
|
||||||
|
background: #22B36A;
|
||||||
|
border-radius: 50%;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__success-tip-text {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.15rem;
|
||||||
|
color: #616367;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 进入后台按钮 */
|
||||||
|
.login-view__success-btn {
|
||||||
|
width: 3.41rem;
|
||||||
|
height: 0.40rem;
|
||||||
|
background: #4FC2C9;
|
||||||
|
border-radius: 0.08rem;
|
||||||
|
border: none;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.15rem;
|
||||||
|
color: #FFFFFF;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==================== 状态3:上传失败面板 ==================== */
|
||||||
|
.login-view__failed-panel {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 3.41rem;
|
||||||
|
padding: 0.28rem 0.24rem;
|
||||||
|
background: #FFFBFA;
|
||||||
|
border: 1px solid #FADBD5;
|
||||||
|
border-radius: 0.08rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__failed-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.14rem;
|
||||||
|
margin-bottom: 0.24rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__failed-icon-bg {
|
||||||
|
width: 0.40rem;
|
||||||
|
height: 0.40rem;
|
||||||
|
background: #FFF0ED;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__failed-icon-mark {
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 0.18rem;
|
||||||
|
line-height: 0.22rem;
|
||||||
|
color: #FF6B4A;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__failed-header-text {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.04rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__failed-title {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 0.13rem;
|
||||||
|
line-height: 0.16rem;
|
||||||
|
color: #18181A;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__failed-detail {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.15rem;
|
||||||
|
color: #616367;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__failed-tips {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__failed-tip-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.10rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__failed-tip-dot {
|
||||||
|
width: 0.06rem;
|
||||||
|
height: 0.06rem;
|
||||||
|
background: #FF8D76;
|
||||||
|
border-radius: 50%;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__failed-tip-text {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.15rem;
|
||||||
|
color: #616367;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 重新上传按钮 */
|
||||||
|
.login-view__failed-btn {
|
||||||
|
width: 3.41rem;
|
||||||
|
height: 0.40rem;
|
||||||
|
background: linear-gradient(90deg, #4FC2C9 0%, #42A8B3 100%);
|
||||||
|
box-shadow: 0 0.16rem 0.30rem rgba(15, 83, 87, 0.15);
|
||||||
|
border-radius: 0.08rem;
|
||||||
|
border: none;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.12rem;
|
||||||
|
line-height: 0.15rem;
|
||||||
|
color: #FFFFFF;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-view__right-footer{
|
||||||
|
margin-top: 0.37rem;
|
||||||
|
font-size: 0.13rem;
|
||||||
|
width: 4rem;
|
||||||
|
text-align: center;
|
||||||
|
color: #999;
|
||||||
|
padding-top: 0.3rem;
|
||||||
|
border-top: 1px solid #E7F2F3;
|
||||||
}
|
}
|
||||||
|
|||||||
+258
-52
@@ -27,8 +27,7 @@
|
|||||||
<!-- ===== 登录阶段(step 1 & 2)===== -->
|
<!-- ===== 登录阶段(step 1 & 2)===== -->
|
||||||
<template v-if="step === 1 || step === 2">
|
<template v-if="step === 1 || step === 2">
|
||||||
<div class="login-view__logo-row login-view__logo-row--right">
|
<div class="login-view__logo-row login-view__logo-row--right">
|
||||||
<div class="login-view__logo-box login-view__logo-box--green">O</div>
|
<img src="@/assets/images/logo.png" alt="">
|
||||||
<span class="login-view__logo-text login-view__logo-text--dark">Offer派</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="login-view__form-wrap">
|
<div class="login-view__form-wrap">
|
||||||
@@ -38,15 +37,29 @@
|
|||||||
<h2 class="login-view__title">手机号登录/注册</h2>
|
<h2 class="login-view__title">手机号登录/注册</h2>
|
||||||
<p class="login-view__subtitle">未注册用户验证后将自动注册并登录</p>
|
<p class="login-view__subtitle">未注册用户验证后将自动注册并登录</p>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 手机号输入组 -->
|
||||||
<div class="login-view__phone-row">
|
<div class="login-view__phone-row">
|
||||||
<div class="login-view__country-code">
|
<!-- 手机图标 -->
|
||||||
<span class="login-view__flag">🇨🇳</span>
|
<div class="login-view__phone-icon">
|
||||||
<span class="login-view__code-text">+86</span>
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<span class="login-view__code-arrow">▾</span>
|
<rect x="4.5" y="2" width="9" height="14" rx="1.5" stroke="#0F6B66" stroke-width="1.5"/>
|
||||||
|
<line x1="9" y1="2" x2="9" y2="3.5" stroke="#0F6B66" stroke-width="1.5" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div class="login-view__separator"></div>
|
<!-- 国家码标签 -->
|
||||||
|
<span class="login-view__country-label">中国 +86</span>
|
||||||
|
<!-- 下拉箭头 -->
|
||||||
|
<div class="login-view__country-chevron">
|
||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M6 8L10 12L14 8" stroke="#6F8586" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<!-- 分隔线 -->
|
||||||
|
<div class="login-view__input-divider"></div>
|
||||||
|
<!-- 手机号输入框 -->
|
||||||
<input v-model="phone" type="tel" class="login-view__phone-input" placeholder="请输入手机号码" maxlength="11" />
|
<input v-model="phone" type="tel" class="login-view__phone-input" placeholder="请输入手机号码" maxlength="11" />
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 发送验证码按钮 -->
|
||||||
<button class="login-view__send-btn" :disabled="!canSend" @click="handleSendCode">发送验证码</button>
|
<button class="login-view__send-btn" :disabled="!canSend" @click="handleSendCode">发送验证码</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -54,7 +67,7 @@
|
|||||||
<template v-if="step === 2">
|
<template v-if="step === 2">
|
||||||
<div class="login-view__heading">
|
<div class="login-view__heading">
|
||||||
<h2 class="login-view__title">请输入验证码</h2>
|
<h2 class="login-view__title">请输入验证码</h2>
|
||||||
<p class="login-view__subtitle">短信验证码已发送至 +86{{ phone }} <span class="fw600 ml5 cursor-po" @click="handleChangePhone">修改手机号</span></p>
|
<p class="login-view__subtitle dflex"><span class="dib">短信验证码已发送至 +86{{ phone }} </span><span class="fw600 ml5 dib cursor-po mlauto" @click="handleChangePhone">修改手机号</span></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="login-view__otp-wrap" @click="focusOtpInput">
|
<div class="login-view__otp-wrap" @click="focusOtpInput">
|
||||||
<input ref="otpInputRef" v-model="otpValue" type="text" inputmode="numeric" class="login-view__otp-hidden-input" maxlength="6" :disabled="isLoggingIn" @input="handleOtpInput" />
|
<input ref="otpInputRef" v-model="otpValue" type="text" inputmode="numeric" class="login-view__otp-hidden-input" maxlength="6" :disabled="isLoggingIn" @input="handleOtpInput" />
|
||||||
@@ -74,7 +87,7 @@
|
|||||||
<!-- 协议勾选(步骤一二通用) -->
|
<!-- 协议勾选(步骤一二通用) -->
|
||||||
<div class="login-view__agreement">
|
<div class="login-view__agreement">
|
||||||
<div class="login-view__checkbox" :class="{ 'login-view__checkbox--checked': agreedTerms }" @click="agreedTerms = !agreedTerms">
|
<div class="login-view__checkbox" :class="{ 'login-view__checkbox--checked': agreedTerms }" @click="agreedTerms = !agreedTerms">
|
||||||
<span v-if="agreedTerms" class="login-view__check-icon">✓</span>
|
<span v-if="agreedTerms" class="login-view__check-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="0.13rem" height="0.13rem"><path stroke="currentColor" fill="currentColor" d="M77.248 415.04a64 64 0 0 1 90.496 0l226.304 226.304L846.528 188.8a64 64 0 1 1 90.56 90.496l-543.04 543.04-316.8-316.8a64 64 0 0 1 0-90.496"></path></svg></span>
|
||||||
</div>
|
</div>
|
||||||
<span class="login-view__agreement-text">登录即表示同意</span>
|
<span class="login-view__agreement-text">登录即表示同意</span>
|
||||||
<span class="login-view__agreement-link" @click="openAgreement('ae8065i3')">《用户协议》</span>
|
<span class="login-view__agreement-link" @click="openAgreement('ae8065i3')">《用户协议》</span>
|
||||||
@@ -88,15 +101,24 @@
|
|||||||
<template v-if="step === 3">
|
<template v-if="step === 3">
|
||||||
<div class="login-view__form-wrap login-view__form-wrap--resume">
|
<div class="login-view__form-wrap login-view__form-wrap--resume">
|
||||||
|
|
||||||
<!-- 状态1:上传区域 -->
|
<!-- 状态1:上传区域 upload-->
|
||||||
<template v-if="resumeState === 'upload'">
|
<template v-if="resumeState === 'upload'">
|
||||||
<div class="login-view__heading">
|
<div class="login-view__heading">
|
||||||
<h2 class="login-view__title">一切美好,从简历开始~</h2>
|
<h2 class="login-view__title">上传简历,开启求职之旅</h2>
|
||||||
<p class="login-view__subtitle">自动解析您的简历,为你匹配最合适的岗位</p>
|
<p class="login-view__subtitle">解析后为你匹配岗位,也会用于后续简历优化</p>
|
||||||
</div>
|
</div>
|
||||||
<!-- 拖拽上传区域 -->
|
<!-- 拖拽上传区域 -->
|
||||||
<div class="login-view__upload-area" @dragover.prevent @drop.prevent="handleDrop" @click="triggerFileInput">
|
<div class="login-view__upload-area" @dragover.prevent @drop.prevent="handleDrop" @click="triggerFileInput">
|
||||||
<div class="login-view__upload-circle"></div>
|
<div class="login-view__upload-circle">
|
||||||
|
<svg width="52" height="56" viewBox="0 0 52 56" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect x="0.5" y="0.5" width="51" height="55" rx="7.5" fill="#EAF8F7" stroke="#D6F1EF"/>
|
||||||
|
<rect x="36" width="16" height="16" rx="3" fill="#D6F1EF"/>
|
||||||
|
<rect x="13" y="21" width="26" height="4" rx="2" fill="#4FC2C9"/>
|
||||||
|
<rect x="13" y="33" width="30" height="4" rx="2" fill="#BFEAE8"/>
|
||||||
|
<rect x="13" y="45" width="20" height="4" rx="2" fill="#BFEAE8"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
</div>
|
||||||
<p class="login-view__upload-text">拖拽简历到这里,或点击上传</p>
|
<p class="login-view__upload-text">拖拽简历到这里,或点击上传</p>
|
||||||
<p class="login-view__upload-hint">支持 PDF / DOC / DOCX,不超过 20MB</p>
|
<p class="login-view__upload-hint">支持 PDF / DOC / DOCX,不超过 20MB</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -106,26 +128,122 @@
|
|||||||
<button class="login-view__upload-btn" @click="triggerFileInput">+ 上传简历</button>
|
<button class="login-view__upload-btn" @click="triggerFileInput">+ 上传简历</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 状态2:解析中 -->
|
<!-- 状态2:解析中 parsing -->
|
||||||
<template v-if="resumeState === 'parsing'">
|
<template v-if="resumeState === 'parsing'">
|
||||||
<div class="login-view__parsing">
|
<div class="login-view__heading m0auto">
|
||||||
<h2 class="login-view__parsing-title">{{ parsingText }}</h2>
|
<h2 class="login-view__title">正在解析简历</h2>
|
||||||
<p class="login-view__parsing-subtitle">自动解析您的简历,为你匹配最合适的岗位</p>
|
<p class="login-view__subtitle">正在识别教育背景、工作经历与技能关键词</p>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 解析面板 -->
|
||||||
|
<div class="login-view__parse-panel m0auto">
|
||||||
|
<!-- 顶部进度条 -->
|
||||||
|
<div class="login-view__parse-progress-header">
|
||||||
|
<span class="login-view__parse-progress-label">解析进度</span>
|
||||||
|
<span class="login-view__parse-progress-percent">{{ parsePercent }}%</span>
|
||||||
|
</div>
|
||||||
|
<div class="login-view__parse-progress-rail">
|
||||||
|
<div class="login-view__parse-progress-fill" :style="{ width: parsePercent + '%' }"></div>
|
||||||
|
</div>
|
||||||
|
<!-- 步骤列表 -->
|
||||||
|
<div class="login-view__parse-steps">
|
||||||
|
<div v-for="(ps, idx) in parseStepList" :key="idx" class="login-view__parse-step-item">
|
||||||
|
<!-- 步骤圆圈 + 连接线 -->
|
||||||
|
<div class="login-view__parse-step-left">
|
||||||
|
<!-- 完成状态:实心深色圆 -->
|
||||||
|
<div v-if="ps.status === 'done'" class="login-view__parse-dot login-view__parse-dot--done"></div>
|
||||||
|
<!-- 进行中:浅色光晕 + 呼吸动画深色内圆 -->
|
||||||
|
<div v-else-if="ps.status === 'active'" class="login-view__parse-dot login-view__parse-dot--active">
|
||||||
|
<div class="login-view__parse-dot-pulse"></div>
|
||||||
|
</div>
|
||||||
|
<!-- 等待状态:浅色圆 -->
|
||||||
|
<div v-else class="login-view__parse-dot login-view__parse-dot--pending"></div>
|
||||||
|
<!-- 连接线(最后一项不显示) -->
|
||||||
|
<div v-if="idx < parseStepList.length - 1" class="login-view__parse-connector"></div>
|
||||||
|
</div>
|
||||||
|
<!-- 步骤文字 -->
|
||||||
|
<span class="login-view__parse-step-text" :class="{ 'login-view__parse-step-text--pending': ps.status === 'pending' }">{{ ps.label }}</span>
|
||||||
|
<!-- 步骤状态文字 -->
|
||||||
|
<span class="login-view__parse-step-state" :class="{ 'login-view__parse-step-state--done': ps.status === 'done', 'login-view__parse-step-state--active': ps.status === 'active', 'login-view__parse-step-state--pending': ps.status === 'pending' }">{{ ps.stateText }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 解析中按钮(禁用状态) -->
|
||||||
|
<button class="login-view__parse-btn m0auto" disabled>解析中,请稍候</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 状态3:上传失败 -->
|
<!-- 状态4:上传成功 success-->
|
||||||
<template v-if="resumeState === 'failed'">
|
<template v-if="resumeState === 'success'">
|
||||||
<div class="login-view__heading">
|
<div class="login-view__heading m0auto">
|
||||||
<h2 class="login-view__title login-view__title--error">上传失败!</h2>
|
<h2 class="login-view__title">简历上传成功</h2>
|
||||||
<p class="login-view__subtitle">您的简历解析失败了,请重试一次吧~</p>
|
<p class="login-view__subtitle">简历已完成解析,进入后台继续完善与投递</p>
|
||||||
</div>
|
</div>
|
||||||
<button class="login-view__upload-btn" @click="handleRetryUpload">重新上传</button>
|
<!-- 成功面板 -->
|
||||||
|
<div class="login-view__success-panel m0auto">
|
||||||
|
<!-- 成功图标和标题 -->
|
||||||
|
<div class="login-view__success-header">
|
||||||
|
<div class="login-view__success-icon-bg">
|
||||||
|
<span class="login-view__success-icon-mark"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="0.15rem" height="0.15rem"><path stroke="currentColor" fill="currentColor" d="M77.248 415.04a64 64 0 0 1 90.496 0l226.304 226.304L846.528 188.8a64 64 0 1 1 90.56 90.496l-543.04 543.04-316.8-316.8a64 64 0 0 1 0-90.496"></path></svg></span>
|
||||||
|
</div>
|
||||||
|
<div class="login-view__success-header-text">
|
||||||
|
<span class="login-view__success-title">简历解析完成</span>
|
||||||
|
<span class="login-view__success-detail">已识别关键信息,岗位匹配已准备好</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 成功提示项 -->
|
||||||
|
<div class="login-view__success-tips">
|
||||||
|
<div class="login-view__success-tip-item">
|
||||||
|
<span class="login-view__success-tip-dot"></span>
|
||||||
|
<span class="login-view__success-tip-text">已提取教育背景、工作经历与技能</span>
|
||||||
|
</div>
|
||||||
|
<div class="login-view__success-tip-item">
|
||||||
|
<span class="login-view__success-tip-dot"></span>
|
||||||
|
<span class="login-view__success-tip-text">可进入后台查看推荐岗位并继续投递</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 进入后台按钮 -->
|
||||||
|
<button class="login-view__success-btn m0auto" @click="handleEnterDashboard">上传成功,进入后台</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 状态3:上传失败 failed-->
|
||||||
|
<template v-if="resumeState === 'failed'">
|
||||||
|
<div class="login-view__heading m0auto">
|
||||||
|
<h2 class="login-view__title">简历上传失败</h2>
|
||||||
|
<p class="login-view__subtitle">文件没有解析成功,请检查格式后重新上传 或 <span class="color-accent cursor-po" @click="handleEnterDashboard">跳过,稍后填写</span></p>
|
||||||
|
</div>
|
||||||
|
<!-- 失败面板 -->
|
||||||
|
<div class="login-view__failed-panel">
|
||||||
|
<!-- 失败图标和标题 -->
|
||||||
|
<div class="login-view__failed-header">
|
||||||
|
<div class="login-view__failed-icon-bg">
|
||||||
|
<span class="login-view__failed-icon-mark">!</span>
|
||||||
|
</div>
|
||||||
|
<div class="login-view__failed-header-text">
|
||||||
|
<span class="login-view__failed-title">未能读取文件内容</span>
|
||||||
|
<span class="login-view__failed-detail">可能是文件加密、损坏或格式不支持</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 失败提示项 -->
|
||||||
|
<div class="login-view__failed-tips">
|
||||||
|
<div class="login-view__failed-tip-item">
|
||||||
|
<span class="login-view__failed-tip-dot"></span>
|
||||||
|
<span class="login-view__failed-tip-text">请上传 PDF / DOC / DOCX 格式</span>
|
||||||
|
</div>
|
||||||
|
<div class="login-view__failed-tip-item">
|
||||||
|
<span class="login-view__failed-tip-dot"></span>
|
||||||
|
<span class="login-view__failed-tip-text">文件大小不超过 20MB,且未加密</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 重新上传按钮 -->
|
||||||
|
<button class="login-view__failed-btn" @click="handleRetryUpload">重新上传</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<div class="login-view__right-footer">
|
||||||
|
Offer派 求职工作台
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 协议预览弹窗 -->
|
<!-- 协议预览弹窗 -->
|
||||||
@@ -252,19 +370,37 @@ let loginRedirect = '/'
|
|||||||
const canSend = computed(() => phone.value.length === 11 && agreedTerms.value)
|
const canSend = computed(() => phone.value.length === 11 && agreedTerms.value)
|
||||||
|
|
||||||
// ==================== 简历上传相关状态 ====================
|
// ==================== 简历上传相关状态 ====================
|
||||||
/** 简历上传子状态:upload=上传区域 parsing=解析中 failed=失败 */
|
/** 简历上传子状态:upload=上传区域 parsing=解析中 failed=失败 success=成功 */
|
||||||
const resumeState = ref<'upload' | 'parsing' | 'failed'>('upload')
|
const resumeState = ref<'upload' | 'parsing' | 'failed' | 'success'>('upload')
|
||||||
/** 解析中显示的文字 */
|
|
||||||
const parsingText = ref('正在解析个人资料...')
|
|
||||||
/** 解析文字轮换定时器 */
|
/** 解析文字轮换定时器 */
|
||||||
let parsingTimer: ReturnType<typeof setInterval> | null = null
|
let parsingTimer: ReturnType<typeof setInterval> | null = null
|
||||||
/** 文件选择器引用 */
|
/** 文件选择器引用 */
|
||||||
const fileInputRef = ref<HTMLInputElement | null>(null)
|
const fileInputRef = ref<HTMLInputElement | null>(null)
|
||||||
|
|
||||||
|
/** 进度条百分比 */
|
||||||
|
const parsePercent = ref(0)
|
||||||
|
/** 进度条动画定时器 */
|
||||||
|
let progressTimer: ReturnType<typeof setInterval> | null = null
|
||||||
|
/** 接口是否已返回成功 */
|
||||||
|
let uploadDone = false
|
||||||
|
|
||||||
|
/** 解析步骤定义 */
|
||||||
|
interface ParseStep {
|
||||||
|
label: string
|
||||||
|
status: 'pending' | 'active' | 'done'
|
||||||
|
stateText: string
|
||||||
|
}
|
||||||
|
|
||||||
/** 解析中文字轮换列表 */
|
/** 4个解析步骤 */
|
||||||
const parsingSteps = ['正在解析个人资料...', '正在解析教育背景...', '正在解析工作经历...', '正在解析技能特长...', '简历解析成功,即将跳转']
|
const parseStepList = ref<ParseStep[]>([
|
||||||
|
{ label: '教育背景解析...', status: 'pending', stateText: '等待' },
|
||||||
|
{ label: '工作经历解析...', status: 'pending', stateText: '等待' },
|
||||||
|
{ label: '技能特长解析...', status: 'pending', stateText: '等待' },
|
||||||
|
{ label: '个人资料最终确认', status: 'pending', stateText: '等待' }
|
||||||
|
])
|
||||||
|
|
||||||
|
/** 每个步骤的时间分配(毫秒),总模拟时间约8秒 */
|
||||||
|
const stepDurations = [2000, 2000, 2000, 2000]
|
||||||
|
|
||||||
// ==================== 登录逻辑 ====================
|
// ==================== 登录逻辑 ====================
|
||||||
|
|
||||||
@@ -432,6 +568,11 @@ function handleRetryUpload() {
|
|||||||
resumeState.value = 'upload'
|
resumeState.value = 'upload'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 进入后台(状态4按钮) */
|
||||||
|
function handleEnterDashboard() {
|
||||||
|
router.replace(loginRedirect)
|
||||||
|
}
|
||||||
|
|
||||||
/** 开始上传并解析简历 */
|
/** 开始上传并解析简历 */
|
||||||
async function startUpload(file: File) {
|
async function startUpload(file: File) {
|
||||||
// 校验文件类型和大小
|
// 校验文件类型和大小
|
||||||
@@ -445,8 +586,16 @@ async function startUpload(file: File) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 进入解析状态
|
// 进入解析状态,重置步骤
|
||||||
resumeState.value = 'parsing'
|
resumeState.value = 'parsing'
|
||||||
|
uploadDone = false
|
||||||
|
parsePercent.value = 0
|
||||||
|
parseStepList.value = [
|
||||||
|
{ label: '教育背景解析...', status: 'pending', stateText: '等待' },
|
||||||
|
{ label: '工作经历解析...', status: 'pending', stateText: '等待' },
|
||||||
|
{ label: '技能特长解析...', status: 'pending', stateText: '等待' },
|
||||||
|
{ label: '个人资料最终确认', status: 'pending', stateText: '等待' }
|
||||||
|
]
|
||||||
startParsingAnimation()
|
startParsingAnimation()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -454,13 +603,10 @@ async function startUpload(file: File) {
|
|||||||
if (res.code === 0 && res.data?.resumeId) {
|
if (res.code === 0 && res.data?.resumeId) {
|
||||||
// 上传成功,同步个人资料
|
// 上传成功,同步个人资料
|
||||||
await syncProfileFromResume(String(res.data.resumeId))
|
await syncProfileFromResume(String(res.data.resumeId))
|
||||||
// 停止轮换动画,显示成功
|
// 标记接口已返回
|
||||||
stopParsingAnimation()
|
uploadDone = true
|
||||||
parsingText.value = '简历解析成功,即将跳转'
|
// 完成所有步骤的动画后会自动过渡到 success 状态
|
||||||
// 等1秒后跳转
|
finishParsingAnimation()
|
||||||
setTimeout(() => {
|
|
||||||
router.replace(loginRedirect)
|
|
||||||
}, 1000)
|
|
||||||
} else {
|
} else {
|
||||||
// 解析失败
|
// 解析失败
|
||||||
stopParsingAnimation()
|
stopParsingAnimation()
|
||||||
@@ -472,25 +618,84 @@ async function startUpload(file: File) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 开始解析文字轮换动画 */
|
/** 开始解析步骤动画(模拟4步进度) */
|
||||||
function startParsingAnimation() {
|
function startParsingAnimation() {
|
||||||
let index = 0
|
let currentStep = 0
|
||||||
parsingText.value = parsingSteps[0]
|
const totalSteps = parseStepList.value.length
|
||||||
parsingTimer = setInterval(() => {
|
/** 每个步骤对应的进度百分比段 */
|
||||||
index++
|
const stepPercents = [25, 50, 75, 95]
|
||||||
if (index < parsingSteps.length - 1) {
|
|
||||||
// 前4个每2秒切换
|
// 第一个步骤立即进入进行中
|
||||||
parsingText.value = parsingSteps[index]
|
parseStepList.value[0].status = 'active'
|
||||||
} else {
|
parseStepList.value[0].stateText = '进行中'
|
||||||
// 到第4个(技能特长)后停止轮换,保持显示直到接口返回
|
|
||||||
parsingText.value = parsingSteps[parsingSteps.length - 2]
|
// 开始进度条平滑增长
|
||||||
if (parsingTimer) { clearInterval(parsingTimer); parsingTimer = null }
|
let targetPercent = stepPercents[0]
|
||||||
|
const startTime = Date.now()
|
||||||
|
let lastStepTime = startTime
|
||||||
|
|
||||||
|
progressTimer = setInterval(() => {
|
||||||
|
const elapsed = Date.now() - lastStepTime
|
||||||
|
const stepDuration = stepDurations[currentStep] || 2000
|
||||||
|
|
||||||
|
if (elapsed >= stepDuration && currentStep < totalSteps - 1) {
|
||||||
|
// 当前步骤完成
|
||||||
|
parseStepList.value[currentStep].status = 'done'
|
||||||
|
parseStepList.value[currentStep].stateText = '完成'
|
||||||
|
currentStep++
|
||||||
|
// 下一个步骤进入进行中
|
||||||
|
parseStepList.value[currentStep].status = 'active'
|
||||||
|
parseStepList.value[currentStep].stateText = '进行中'
|
||||||
|
targetPercent = stepPercents[currentStep]
|
||||||
|
lastStepTime = Date.now()
|
||||||
|
} else if (currentStep >= totalSteps - 1 && elapsed >= stepDuration) {
|
||||||
|
// 最后一个步骤时间到,但如果接口还没返回就停在这里等
|
||||||
|
if (uploadDone) {
|
||||||
|
// 接口已返回,最后一步也完成
|
||||||
|
parseStepList.value[currentStep].status = 'done'
|
||||||
|
parseStepList.value[currentStep].stateText = '完成'
|
||||||
|
if (progressTimer) { clearInterval(progressTimer); progressTimer = null }
|
||||||
|
// 进度条跳到随机95-99再走完到100
|
||||||
|
const finalPercent = Math.floor(95 + Math.random() * 4)
|
||||||
|
parsePercent.value = finalPercent
|
||||||
|
setTimeout(() => {
|
||||||
|
parsePercent.value = 100
|
||||||
|
setTimeout(() => { resumeState.value = 'success' }, 600)
|
||||||
|
}, 1000)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 接口未返回,保持在最后步骤的进行中状态
|
||||||
|
parsePercent.value = Math.min(parsePercent.value + 0.1, 94)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}, 2000)
|
|
||||||
|
// 平滑增长进度
|
||||||
|
const progress = Math.min(elapsed / stepDuration, 1)
|
||||||
|
const prevPercent = currentStep > 0 ? stepPercents[currentStep - 1] : 0
|
||||||
|
parsePercent.value = Math.floor(prevPercent + (targetPercent - prevPercent) * progress)
|
||||||
|
}, 50)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 停止解析文字轮换动画 */
|
/** 接口返回后完成动画 */
|
||||||
|
function finishParsingAnimation() {
|
||||||
|
// 如果进度动画还在跑,标记 uploadDone 即可让 progressTimer 逻辑处理完成
|
||||||
|
// 如果动画已经停了(最后一步时间到了等接口),手动完成
|
||||||
|
if (!progressTimer) {
|
||||||
|
const lastIdx = parseStepList.value.length - 1
|
||||||
|
parseStepList.value[lastIdx].status = 'done'
|
||||||
|
parseStepList.value[lastIdx].stateText = '完成'
|
||||||
|
const finalPercent = Math.floor(95 + Math.random() * 4)
|
||||||
|
parsePercent.value = finalPercent
|
||||||
|
setTimeout(() => {
|
||||||
|
parsePercent.value = 100
|
||||||
|
setTimeout(() => { resumeState.value = 'success' }, 600)
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 停止解析动画(失败时调用) */
|
||||||
function stopParsingAnimation() {
|
function stopParsingAnimation() {
|
||||||
|
if (progressTimer) { clearInterval(progressTimer); progressTimer = null }
|
||||||
if (parsingTimer) { clearInterval(parsingTimer); parsingTimer = null }
|
if (parsingTimer) { clearInterval(parsingTimer); parsingTimer = null }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -498,6 +703,7 @@ function stopParsingAnimation() {
|
|||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
if (countdownTimer) { clearInterval(countdownTimer) }
|
if (countdownTimer) { clearInterval(countdownTimer) }
|
||||||
if (parsingTimer) { clearInterval(parsingTimer) }
|
if (parsingTimer) { clearInterval(parsingTimer) }
|
||||||
|
if (progressTimer) { clearInterval(progressTimer) }
|
||||||
if (waveTimer) { clearTimeout(waveTimer); waveTimer = null }
|
if (waveTimer) { clearTimeout(waveTimer); waveTimer = null }
|
||||||
if (blinkTimer) { clearTimeout(blinkTimer); blinkTimer = null }
|
if (blinkTimer) { clearTimeout(blinkTimer); blinkTimer = null }
|
||||||
if (idleLookTimer) { clearTimeout(idleLookTimer); idleLookTimer = null }
|
if (idleLookTimer) { clearTimeout(idleLookTimer); idleLookTimer = null }
|
||||||
|
|||||||
Reference in New Issue
Block a user