|
|
@@ -1,50 +1,195 @@
|
|
|
<template>
|
|
|
<div class="login">
|
|
|
<main class="login-container">
|
|
|
- <div class="title">登录</div>
|
|
|
- <el-form ref="loginForm" :model="form" :rules="rules" label-position="right">
|
|
|
- <el-form-item prop="server_address" label="服务器地址">
|
|
|
- <el-input v-model="form.server_address" placeholder="请输入服务器地址" @change="updateServerAddress" />
|
|
|
- </el-form-item>
|
|
|
- <el-form-item prop="user_name" label="用户名">
|
|
|
- <el-input v-model="form.user_name" />
|
|
|
- </el-form-item>
|
|
|
- <el-form-item prop="password" label="密码">
|
|
|
- <el-input v-model="form.password" type="password" show-password />
|
|
|
- </el-form-item>
|
|
|
- <el-form-item prop="verification_code_image_text" class="verification-code" label="验证码">
|
|
|
- <el-input v-model="form.verification_code_image_text" @keyup.enter.native="signIn" />
|
|
|
- <el-image
|
|
|
- v-if="image_content_base64.length > 0"
|
|
|
- :src="`data:image/jpg;base64,${image_content_base64}`"
|
|
|
- @click="updateVerificationCode"
|
|
|
- />
|
|
|
- </el-form-item>
|
|
|
- <el-form-item prop="user_type" label="用户类型">
|
|
|
- <el-radio-group v-model="form.user_type">
|
|
|
- <el-radio label="USER">机构用户</el-radio>
|
|
|
- <el-radio label="ORG_MANAGER">机构管理员</el-radio>
|
|
|
- <el-radio label="ADMIN">系统管理员</el-radio>
|
|
|
- </el-radio-group>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item>
|
|
|
- <el-button class="submit" type="primary" @click="signIn">登录</el-button>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item>
|
|
|
- <div class="protocol">
|
|
|
- <span>
|
|
|
- <el-checkbox v-model="isAgree" @change="changeAgree" /> 我已阅读并同意<span
|
|
|
- style="color: #4d78ff; cursor: pointer"
|
|
|
- @click="viewUserAgreement"
|
|
|
- >《用户协议》</span
|
|
|
- >
|
|
|
- </span>
|
|
|
- <span style="color: #4d78ff; cursor: pointer" @click="forgotPwd">
|
|
|
- 忘记密码?| <a @click="goRegister">注册</a>
|
|
|
- </span>
|
|
|
+ <div class="brand-panel">
|
|
|
+ <div class="brand-content">
|
|
|
+ <div class="brand-logo">
|
|
|
+ <div class="logo-icon"><img src="@/assets/login/logo.png" alt="LOGO" /></div>
|
|
|
+ <div class="logo-text">智慧<span>梧桐</span></div>
|
|
|
</div>
|
|
|
- </el-form-item>
|
|
|
- </el-form>
|
|
|
+ <div class="brand-title-group">
|
|
|
+ <div class="brand-position">数字教材编辑器</div>
|
|
|
+ <div class="brand-desc">专业化数字教材编校平台</div>
|
|
|
+ </div>
|
|
|
+ <div class="flow-zone">
|
|
|
+ <div class="flow-track">
|
|
|
+ <div class="flow-node">
|
|
|
+ <div class="flow-dot dot-1"></div>
|
|
|
+ <div class="flow-card">
|
|
|
+ <span class="fc-icon"
|
|
|
+ ><svg viewBox="0 0 24 24" fill="none" stroke="#2D3E8F">
|
|
|
+ <path d="M12 20h9" />
|
|
|
+ <path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z" /></svg
|
|
|
+ ></span>
|
|
|
+ <div class="fc-title">内容创作</div>
|
|
|
+ <div class="fc-sub">结构化编写</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="flow-node">
|
|
|
+ <div class="flow-dot dot-2"></div>
|
|
|
+ <div class="flow-card">
|
|
|
+ <span class="fc-icon"
|
|
|
+ ><svg viewBox="0 0 24 24" fill="none" stroke="#3B52C4">
|
|
|
+ <rect x="3" y="3" width="7" height="7" rx="1" />
|
|
|
+ <rect x="14" y="3" width="7" height="7" rx="1" />
|
|
|
+ <rect x="3" y="14" width="7" height="7" rx="1" />
|
|
|
+ <circle cx="17.5" cy="17.5" r="3.5" /></svg
|
|
|
+ ></span>
|
|
|
+ <div class="fc-title">组件编排</div>
|
|
|
+ <div class="fc-sub">模块化搭建</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="flow-node">
|
|
|
+ <div class="flow-dot dot-3"></div>
|
|
|
+ <div class="flow-card">
|
|
|
+ <span class="fc-icon"
|
|
|
+ ><svg viewBox="0 0 24 24" fill="none" stroke="#4A7DD4">
|
|
|
+ <path d="M12 2v4" />
|
|
|
+ <path d="m16.2 7.8 2.9-2.9" />
|
|
|
+ <path d="M18 12h4" />
|
|
|
+ <path d="m16.2 16.2 2.9 2.9" />
|
|
|
+ <path d="M12 18v4" />
|
|
|
+ <path d="m4.9 19.1 2.9-2.9" />
|
|
|
+ <path d="M2 12h4" />
|
|
|
+ <path d="m4.9 4.9 2.9 2.9" /></svg
|
|
|
+ ></span>
|
|
|
+ <div class="fc-title">自动生成</div>
|
|
|
+ <div class="fc-sub">AI赋能</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="flow-node">
|
|
|
+ <div class="flow-dot dot-4"></div>
|
|
|
+ <div class="flow-card">
|
|
|
+ <span class="fc-icon"
|
|
|
+ ><svg viewBox="0 0 24 24" fill="none" stroke="#4DC9F6">
|
|
|
+ <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" />
|
|
|
+ <circle cx="12" cy="12" r="3" />
|
|
|
+ <path d="m9 12 2 2 4-4" /></svg
|
|
|
+ ></span>
|
|
|
+ <div class="fc-title">专业审校</div>
|
|
|
+ <div class="fc-sub">质量把关</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="flow-node">
|
|
|
+ <div class="flow-dot dot-5"></div>
|
|
|
+ <div class="flow-card">
|
|
|
+ <span class="fc-icon"
|
|
|
+ ><svg viewBox="0 0 24 24" fill="none" stroke="#38B8E8">
|
|
|
+ <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
|
|
|
+ <polyline points="17 8 12 3 7 8" />
|
|
|
+ <line x1="12" y1="3" x2="12" y2="15" /></svg
|
|
|
+ ></span>
|
|
|
+ <div class="fc-title">一键发布</div>
|
|
|
+ <div class="fc-sub">多平台分发</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="flow-node">
|
|
|
+ <div class="flow-dot dot-6"></div>
|
|
|
+ <div class="flow-card">
|
|
|
+ <span class="fc-icon"
|
|
|
+ ><svg viewBox="0 0 24 24" fill="none" stroke="#2D9BD4">
|
|
|
+ <path d="M22 10v6M2 10l10-5 10 5-10 5z" />
|
|
|
+ <path d="M6 12v5c3 3 9 3 12 0v-5" /></svg
|
|
|
+ ></span>
|
|
|
+ <div class="fc-title">教学应用</div>
|
|
|
+ <div class="fc-sub">智慧教学</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="flow-arrow a1">›</div>
|
|
|
+ <div class="flow-arrow a2">›</div>
|
|
|
+ <div class="flow-arrow a3">›</div>
|
|
|
+ <div class="flow-arrow a4">›</div>
|
|
|
+ <div class="flow-arrow a5">›</div>
|
|
|
+ </div>
|
|
|
+ <div class="flow-progress"><div class="fp-fill"></div></div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="login-panel">
|
|
|
+ <div class="login-card">
|
|
|
+ <div class="lc-header">
|
|
|
+ <div class="lc-logo"><img src="@/assets/login/logo.png" alt="LOGO" /></div>
|
|
|
+ <h2>欢迎登录</h2>
|
|
|
+ <p class="sub">登录您的账号</p>
|
|
|
+ </div>
|
|
|
+ <div class="role-tabs" id="roleTabs">
|
|
|
+ <div class="role-tab" :class="[form.user_type === 'USER' ? 'active' : '']" @click="switchRole('USER')">
|
|
|
+ 机构用户
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="role-tab"
|
|
|
+ :class="[form.user_type === 'ORG_MANAGER' ? 'active' : '']"
|
|
|
+ @click="switchRole('ORG_MANAGER')"
|
|
|
+ >
|
|
|
+ 机构管理员
|
|
|
+ </div>
|
|
|
+ <div class="role-tab" :class="[form.user_type === 'ADMIN' ? 'active' : '']" @click="switchRole('ADMIN')">
|
|
|
+ 系统管理员
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <el-form ref="loginForm" :model="form" :rules="rules" label-position="right">
|
|
|
+ <el-form-item prop="server_address" label="服务器地址">
|
|
|
+ <el-input
|
|
|
+ v-model="form.server_address"
|
|
|
+ placeholder="请输入服务器地址"
|
|
|
+ prefix-icon="el-icon-monitor"
|
|
|
+ @change="updateServerAddress"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item prop="user_name" label="账号">
|
|
|
+ <el-input v-model="form.user_name" prefix-icon="el-icon-user" placeholder="请输入账号" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item prop="password" label="密码">
|
|
|
+ <el-input
|
|
|
+ v-model="form.password"
|
|
|
+ type="password"
|
|
|
+ show-password
|
|
|
+ prefix-icon="el-icon-lock"
|
|
|
+ placeholder="请输入密码"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item prop="verification_code_image_text" class="verification-code" label="验证码">
|
|
|
+ <el-input
|
|
|
+ v-model="form.verification_code_image_text"
|
|
|
+ @keyup.enter.native="signIn"
|
|
|
+ prefix-icon="el-icon-finished"
|
|
|
+ placeholder="请输入验证码"
|
|
|
+ />
|
|
|
+ <el-image
|
|
|
+ v-if="image_content_base64.length > 0"
|
|
|
+ :src="`data:image/jpg;base64,${image_content_base64}`"
|
|
|
+ @click="updateVerificationCode"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <!-- <el-form-item prop="user_type" label="用户类型">
|
|
|
+ <el-radio-group v-model="form.user_type">
|
|
|
+ <el-radio label="USER">机构用户</el-radio>
|
|
|
+ <el-radio label="ORG_MANAGER">机构管理员</el-radio>
|
|
|
+ <el-radio label="ADMIN">系统管理员</el-radio>
|
|
|
+ </el-radio-group>
|
|
|
+ </el-form-item> -->
|
|
|
+ <el-form-item style="margin-bottom: 6px">
|
|
|
+ <div class="protocol">
|
|
|
+ <span>
|
|
|
+ <el-checkbox v-model="isAgree" @change="changeAgree" /> 我已阅读并同意<span
|
|
|
+ style="font-weight: 500; color: #2d3e8f; cursor: pointer"
|
|
|
+ @click="viewUserAgreement"
|
|
|
+ >《用户协议》</span
|
|
|
+ >
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item style="margin-bottom: 6px">
|
|
|
+ <el-button class="submit" type="primary" @click="signIn">登 录</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item style="text-align: center">
|
|
|
+ <!-- | <a @click="goRegister">注册</a> -->
|
|
|
+
|
|
|
+ <span style=" font-size: 12px;color: #94a3b8; cursor: pointer" @click="forgotPwd"> 忘记密码 </span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</main>
|
|
|
<el-dialog
|
|
|
:visible.sync="showUseragreement"
|
|
|
@@ -181,26 +326,30 @@ export default {
|
|
|
cancelFot() {
|
|
|
this.forgotPwdFlag = false;
|
|
|
},
|
|
|
+ // 切换角色
|
|
|
+ switchRole(role) {
|
|
|
+ this.form.user_type = role;
|
|
|
+ },
|
|
|
},
|
|
|
};
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
.login {
|
|
|
- position: relative;
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
overflow: hidden;
|
|
|
- background: #2148c0 url('~@/assets/login/login-bg.png') no-repeat center center / cover;
|
|
|
+ font-family:
|
|
|
+ -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', 'Noto Sans SC', sans-serif;
|
|
|
+ background: #f7f9fe;
|
|
|
|
|
|
&-container {
|
|
|
- position: absolute;
|
|
|
- top: 50%;
|
|
|
- left: 50%;
|
|
|
- margin-top: -350px;
|
|
|
- margin-left: -200px;
|
|
|
+ display: flex;
|
|
|
+ height: 100vh;
|
|
|
+ min-height: 100vh;
|
|
|
+ overflow: hidden;
|
|
|
|
|
|
- .title {
|
|
|
+ position:relative .title {
|
|
|
margin-bottom: 28px;
|
|
|
font-size: 24px;
|
|
|
color: #fff;
|
|
|
@@ -208,18 +357,15 @@ export default {
|
|
|
}
|
|
|
|
|
|
:deep .el-form {
|
|
|
- max-width: 400px;
|
|
|
- padding: 24px 32px;
|
|
|
margin: 0 auto;
|
|
|
- background-color: #fff;
|
|
|
- border-radius: 16px;
|
|
|
|
|
|
&-item {
|
|
|
&__label {
|
|
|
- margin-bottom: 4px;
|
|
|
- font-size: 18px;
|
|
|
- font-weight: bold;
|
|
|
- color: #000;
|
|
|
+ margin-bottom: 6px;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 600;
|
|
|
+ line-height: 1;
|
|
|
+ color: #1f2937;
|
|
|
|
|
|
&::before {
|
|
|
display: none;
|
|
|
@@ -230,8 +376,36 @@ export default {
|
|
|
.el-input {
|
|
|
&__inner {
|
|
|
height: 40px;
|
|
|
+ padding: 0 14px 0 42px;
|
|
|
+ font-family: inherit;
|
|
|
+ font-size: 14px;
|
|
|
line-height: 40px;
|
|
|
- background-color: #fff;
|
|
|
+ color: #1f2937;
|
|
|
+ background: #f8fafc;
|
|
|
+ border: 1.5px solid #e2e8f0;
|
|
|
+ border-radius: 10px;
|
|
|
+ outline: none;
|
|
|
+ transition:
|
|
|
+ border-color 0.2s,
|
|
|
+ box-shadow 0.2s,
|
|
|
+ background 0.2s;
|
|
|
+
|
|
|
+ &::placeholder {
|
|
|
+ color: #94a3b8;
|
|
|
+ }
|
|
|
+
|
|
|
+ &:focus {
|
|
|
+ background: #fff;
|
|
|
+ border-color: #2d3e8f;
|
|
|
+ box-shadow: 0 0 0 4px rgba(45, 62, 143, 12%);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-input__prefix {
|
|
|
+ left: 10px;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #94a3b8;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -249,26 +423,62 @@ export default {
|
|
|
}
|
|
|
|
|
|
.el-image {
|
|
|
- height: 38px;
|
|
|
+ height: 40px;
|
|
|
vertical-align: bottom;
|
|
|
cursor: pointer;
|
|
|
+ background: linear-gradient(135deg, #e8f4fd, #f0e8fd);
|
|
|
+ border: 1.5px solid #e2e8f0;
|
|
|
+ border-radius: 10px;
|
|
|
+ transition: 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.submit {
|
|
|
width: 100%;
|
|
|
+ height: 46px;
|
|
|
+ font-family: inherit;
|
|
|
+ font-size: 15px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #fff;
|
|
|
+ letter-spacing: 0.5px;
|
|
|
+ cursor: pointer;
|
|
|
+ background: linear-gradient(135deg, #2d3e8f, #4a7dd4);
|
|
|
+ border: none;
|
|
|
+ border-radius: 10px;
|
|
|
+ box-shadow: 0 4px 14px rgba(45, 62, 143, 25%);
|
|
|
+ transition: all 0.2s;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background: linear-gradient(135deg, #1e2d6e, #3b52c4);
|
|
|
+ box-shadow: 0 6px 22px rgba(45, 62, 143, 35%);
|
|
|
+ transform: translateY(-1px);
|
|
|
+ }
|
|
|
+
|
|
|
+ &:active {
|
|
|
+ transform: translateY(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ &:focus {
|
|
|
+ outline: none;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
.protocol {
|
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
|
font-size: 12px;
|
|
|
- color: #000;
|
|
|
+ color: #94a3b8;
|
|
|
}
|
|
|
|
|
|
.el-form-item--small.el-form-item:last-child {
|
|
|
margin-bottom: 0;
|
|
|
}
|
|
|
+
|
|
|
+ .el-checkbox__input.is-checked .el-checkbox__inner {
|
|
|
+ accent-color: #2d3e8f;
|
|
|
+ background-color: #2d3e8f;
|
|
|
+ border-color: #2d3e8f;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
.not-tips {
|
|
|
@@ -279,6 +489,526 @@ export default {
|
|
|
cursor: pointer;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ .brand-panel {
|
|
|
+ position: relative;
|
|
|
+ z-index: 1;
|
|
|
+ display: flex;
|
|
|
+ flex: 0 0 62%;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 62%;
|
|
|
+ padding: 40px 55px;
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+
|
|
|
+ .brand-content {
|
|
|
+ position: relative;
|
|
|
+ z-index: 2;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ width: 100%;
|
|
|
+ max-width: 620px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .brand-logo {
|
|
|
+ display: flex;
|
|
|
+ gap: 14px;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 12px;
|
|
|
+ animation: fadeDown 0.7s cubic-bezier(0.22, 1, 0.36, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ @keyframes fadeDown {
|
|
|
+ from {
|
|
|
+ opacity: 0;
|
|
|
+ transform: translateY(-10px);
|
|
|
+ }
|
|
|
+
|
|
|
+ to {
|
|
|
+ opacity: 1;
|
|
|
+ transform: translateY(0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .brand-logo .logo-icon {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 52px;
|
|
|
+ height: 52px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .brand-logo .logo-icon img {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ object-fit: contain;
|
|
|
+ }
|
|
|
+
|
|
|
+ .brand-logo .logo-text {
|
|
|
+ font-size: 27px;
|
|
|
+ font-weight: 700;
|
|
|
+ color: #1f2937;
|
|
|
+ letter-spacing: 0.3px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .brand-logo .logo-text span {
|
|
|
+ color: #2d3e8f;
|
|
|
+ }
|
|
|
+
|
|
|
+ .brand-title-group {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 2px;
|
|
|
+ align-items: center;
|
|
|
+ margin-top: 4px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .brand-position {
|
|
|
+ margin-bottom: 4px;
|
|
|
+ font-size: 13px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #64748b;
|
|
|
+ letter-spacing: 0.8px;
|
|
|
+ animation: fadeDown 0.7s 0.04s cubic-bezier(0.22, 1, 0.36, 1) both;
|
|
|
+ }
|
|
|
+
|
|
|
+ .brand-desc {
|
|
|
+ margin-bottom: 40px;
|
|
|
+ font-size: 13px;
|
|
|
+ color: #64748b;
|
|
|
+ animation: fadeDown 0.7s 0.08s cubic-bezier(0.22, 1, 0.36, 1) both;
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-zone {
|
|
|
+ position: relative;
|
|
|
+ width: 100%;
|
|
|
+ max-width: 580px;
|
|
|
+ margin-bottom: 38px;
|
|
|
+ animation: fadeDown 0.7s 0.16s cubic-bezier(0.22, 1, 0.36, 1) both;
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-track {
|
|
|
+ position: relative;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ height: 155px;
|
|
|
+ padding: 0 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-track::before {
|
|
|
+ position: absolute;
|
|
|
+ top: 44%;
|
|
|
+ right: 28px;
|
|
|
+ left: 28px;
|
|
|
+ height: 2px;
|
|
|
+ content: '';
|
|
|
+ background: linear-gradient(
|
|
|
+ 90deg,
|
|
|
+ rgba(45, 62, 143, 6%),
|
|
|
+ rgba(45, 62, 143, 18%) 18%,
|
|
|
+ rgba(45, 62, 143, 22%) 36%,
|
|
|
+ rgba(77, 201, 246, 20%) 54%,
|
|
|
+ rgba(77, 201, 246, 15%) 72%,
|
|
|
+ rgba(77, 201, 246, 10%) 90%,
|
|
|
+ rgba(77, 201, 246, 4%) 100%
|
|
|
+ );
|
|
|
+ border-radius: 1px;
|
|
|
+ transform: translateY(-50%);
|
|
|
+ animation: trackGlow 3s ease-in-out infinite;
|
|
|
+ }
|
|
|
+
|
|
|
+ @keyframes trackGlow {
|
|
|
+ 0%,
|
|
|
+ 100% {
|
|
|
+ opacity: 0.6;
|
|
|
+ }
|
|
|
+
|
|
|
+ 50% {
|
|
|
+ opacity: 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-node {
|
|
|
+ position: relative;
|
|
|
+ z-index: 2;
|
|
|
+ display: flex;
|
|
|
+ flex: 1;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ animation: nodeRise 0.7s cubic-bezier(0.22, 1, 0.36, 1) both;
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-node:nth-child(1) {
|
|
|
+ animation-delay: 0.15s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-node:nth-child(2) {
|
|
|
+ animation-delay: 0.27s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-node:nth-child(3) {
|
|
|
+ animation-delay: 0.39s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-node:nth-child(4) {
|
|
|
+ animation-delay: 0.51s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-node:nth-child(5) {
|
|
|
+ animation-delay: 0.63s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-node:nth-child(6) {
|
|
|
+ animation-delay: 0.75s;
|
|
|
+ }
|
|
|
+
|
|
|
+ @keyframes nodeRise {
|
|
|
+ from {
|
|
|
+ opacity: 0;
|
|
|
+ transform: translateY(20px);
|
|
|
+ }
|
|
|
+
|
|
|
+ to {
|
|
|
+ opacity: 1;
|
|
|
+ transform: translateY(0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-dot {
|
|
|
+ position: relative;
|
|
|
+ z-index: 3;
|
|
|
+ width: 14px;
|
|
|
+ height: 14px;
|
|
|
+ border: 2.5px solid #f7f9fe;
|
|
|
+ border-radius: 50%;
|
|
|
+ box-shadow:
|
|
|
+ 0 0 0 4px var(--sd, transparent),
|
|
|
+ 0 2px 8px rgba(0, 0, 0, 6%);
|
|
|
+ animation: dotGlow 3s ease-in-out infinite;
|
|
|
+ animation-delay: var(--dg, 0s);
|
|
|
+ }
|
|
|
+
|
|
|
+ @keyframes dotGlow {
|
|
|
+ 0%,
|
|
|
+ 100% {
|
|
|
+ box-shadow:
|
|
|
+ 0 0 0 4px var(--sd, transparent),
|
|
|
+ 0 2px 8px rgba(0, 0, 0, 6%);
|
|
|
+ }
|
|
|
+
|
|
|
+ 50% {
|
|
|
+ box-shadow:
|
|
|
+ 0 0 0 8px var(--sd, transparent),
|
|
|
+ 0 4px 16px rgba(0, 0, 0, 10%);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .dot-1 {
|
|
|
+ background: #2d3e8f;
|
|
|
+
|
|
|
+ --sd: rgba(45, 62, 143, 20%);
|
|
|
+ --dg: 0s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .dot-2 {
|
|
|
+ background: #3b52c4;
|
|
|
+
|
|
|
+ --sd: rgba(59, 82, 196, 20%);
|
|
|
+ --dg: 0.5s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .dot-3 {
|
|
|
+ background: #4a7dd4;
|
|
|
+
|
|
|
+ --sd: rgba(74, 125, 212, 20%);
|
|
|
+ --dg: 1s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .dot-4 {
|
|
|
+ background: #4dc9f6;
|
|
|
+
|
|
|
+ --sd: rgba(77, 201, 246, 20%);
|
|
|
+ --dg: 1.5s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .dot-5 {
|
|
|
+ background: #38b8e8;
|
|
|
+
|
|
|
+ --sd: rgba(56, 184, 232, 20%);
|
|
|
+ --dg: 2s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .dot-6 {
|
|
|
+ background: #2d9bd4;
|
|
|
+
|
|
|
+ --sd: rgba(45, 155, 212, 20%);
|
|
|
+ --dg: 2.5s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-card {
|
|
|
+ min-width: 80px;
|
|
|
+ padding: 10px 12px;
|
|
|
+ margin-top: 14px;
|
|
|
+ text-align: center;
|
|
|
+ cursor: default;
|
|
|
+ background: rgba(255, 255, 255, 88%);
|
|
|
+ backdrop-filter: blur(18px);
|
|
|
+ border: 1px solid rgba(255, 255, 255, 85%);
|
|
|
+ border-radius: 11px;
|
|
|
+ box-shadow:
|
|
|
+ 0 3px 14px rgba(0, 0, 0, 4%),
|
|
|
+ 0 1px 3px rgba(0, 0, 0, 2%);
|
|
|
+ transition: all 0.38s cubic-bezier(0.22, 1, 0.36, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-card:hover {
|
|
|
+ box-shadow:
|
|
|
+ 0 10px 28px rgba(45, 62, 143, 8%),
|
|
|
+ 0 4px 12px rgba(0, 0, 0, 4%);
|
|
|
+ transform: translateY(-5px);
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-card .fc-icon {
|
|
|
+ display: block;
|
|
|
+ margin-bottom: 4px;
|
|
|
+ font-size: 22px;
|
|
|
+ transition: 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-card:hover .fc-icon {
|
|
|
+ transform: scale(1.1);
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-card .fc-icon svg {
|
|
|
+ width: 22px;
|
|
|
+ height: 22px;
|
|
|
+ stroke-linecap: round;
|
|
|
+ stroke-linejoin: round;
|
|
|
+ stroke-width: 1.8;
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-card .fc-title {
|
|
|
+ margin-bottom: 1px;
|
|
|
+ font-size: 11px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #1f2937;
|
|
|
+ white-space: nowrap;
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-card .fc-sub {
|
|
|
+ font-size: 9px;
|
|
|
+ color: #94a3b8;
|
|
|
+ white-space: nowrap;
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-arrow {
|
|
|
+ position: absolute;
|
|
|
+ top: 44%;
|
|
|
+ z-index: 2;
|
|
|
+ font-size: 12px;
|
|
|
+ color: rgba(45, 62, 143, 18%);
|
|
|
+ pointer-events: none;
|
|
|
+ transform: translateY(-50%);
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-arrow.a1 {
|
|
|
+ left: 12%;
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-arrow.a2 {
|
|
|
+ left: 28%;
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-arrow.a3 {
|
|
|
+ left: 44%;
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-arrow.a4 {
|
|
|
+ left: 60%;
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-arrow.a5 {
|
|
|
+ left: 76%;
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-progress {
|
|
|
+ position: absolute;
|
|
|
+ right: 28px;
|
|
|
+ bottom: -28px;
|
|
|
+ left: 28px;
|
|
|
+ height: 3px;
|
|
|
+ overflow: hidden;
|
|
|
+ background: #e5e7eb;
|
|
|
+ border-radius: 2px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-progress .fp-fill {
|
|
|
+ height: 100%;
|
|
|
+ background: linear-gradient(90deg, #2d3e8f, #3b52c4, #4a7dd4, #4dc9f6, #38b8e8, #2d9bd4);
|
|
|
+ border-radius: 2px;
|
|
|
+ animation: progressFill 4.5s ease-in-out infinite;
|
|
|
+ }
|
|
|
+
|
|
|
+ @keyframes progressFill {
|
|
|
+ 0% {
|
|
|
+ width: 0%;
|
|
|
+ }
|
|
|
+
|
|
|
+ 50% {
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+
|
|
|
+ 100% {
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-labels {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-around;
|
|
|
+ padding: 0 8px;
|
|
|
+ margin-top: 14px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-label {
|
|
|
+ font-size: 10px;
|
|
|
+ color: #94a3b8;
|
|
|
+ text-align: center;
|
|
|
+ animation: nodeRise 0.7s cubic-bezier(0.22, 1, 0.36, 1) both;
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-label:nth-child(1) {
|
|
|
+ animation-delay: 0.25s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-label:nth-child(2) {
|
|
|
+ animation-delay: 0.37s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-label:nth-child(3) {
|
|
|
+ animation-delay: 0.49s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-label:nth-child(4) {
|
|
|
+ animation-delay: 0.61s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-label:nth-child(5) {
|
|
|
+ animation-delay: 0.73s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .flow-label:nth-child(6) {
|
|
|
+ animation-delay: 0.85s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .login-panel {
|
|
|
+ position: relative;
|
|
|
+ z-index: 1;
|
|
|
+ display: flex;
|
|
|
+ flex: 0 0 38%;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 38%;
|
|
|
+ padding: 40px;
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+
|
|
|
+ .login-card {
|
|
|
+ position: relative;
|
|
|
+ z-index: 2;
|
|
|
+ width: 100%;
|
|
|
+ max-width: 420px;
|
|
|
+ padding: 32px 36px 28px;
|
|
|
+ background: #fff;
|
|
|
+ border: 1px solid rgba(226, 232, 240, 60%);
|
|
|
+ border-radius: 16px;
|
|
|
+ box-shadow:
|
|
|
+ 0 8px 40px rgba(0, 0, 0, 6%),
|
|
|
+ 0 2px 12px rgba(0, 0, 0, 3%);
|
|
|
+ animation: fadeUp 0.7s 0.2s cubic-bezier(0.22, 1, 0.36, 1) both;
|
|
|
+ }
|
|
|
+
|
|
|
+ @keyframes fadeUp {
|
|
|
+ from {
|
|
|
+ opacity: 0;
|
|
|
+ transform: translateY(16px);
|
|
|
+ }
|
|
|
+
|
|
|
+ to {
|
|
|
+ opacity: 1;
|
|
|
+ transform: translateY(0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .login-card .lc-header {
|
|
|
+ margin-bottom: 28px;
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ .login-card .lc-logo {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 44px;
|
|
|
+ height: 44px;
|
|
|
+ margin: 0 auto 16px;
|
|
|
+ overflow: hidden;
|
|
|
+ border-radius: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .login-card .lc-logo img {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ object-fit: contain;
|
|
|
+ }
|
|
|
+
|
|
|
+ .login-card h2 {
|
|
|
+ margin-bottom: 4px;
|
|
|
+ font-size: 22px;
|
|
|
+ font-weight: 700;
|
|
|
+ color: #1f2937;
|
|
|
+ }
|
|
|
+
|
|
|
+ .login-card .sub {
|
|
|
+ font-size: 13px;
|
|
|
+ color: #94a3b8;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 角色选择 */
|
|
|
+ .role-tabs {
|
|
|
+ display: flex;
|
|
|
+ gap: 0;
|
|
|
+ padding: 3px;
|
|
|
+ margin-bottom: 22px;
|
|
|
+ background: #f1f5f9;
|
|
|
+ border-radius: 8px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .role-tabs .role-tab {
|
|
|
+ flex: 1;
|
|
|
+ padding: 8px 0;
|
|
|
+ font-size: 13px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #64748b;
|
|
|
+ text-align: center;
|
|
|
+ cursor: pointer;
|
|
|
+ user-select: none;
|
|
|
+ border-radius: 6px;
|
|
|
+ transition: 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ .role-tabs .role-tab.active {
|
|
|
+ color: #2d3e8f;
|
|
|
+ background: #fff;
|
|
|
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 8%);
|
|
|
+ }
|
|
|
+
|
|
|
+ .role-tabs .role-tab:hover:not(.active) {
|
|
|
+ color: #1f2937;
|
|
|
+ }
|
|
|
}
|
|
|
</style>
|
|
|
<style lang="scss">
|