|
|
|
@ -1,81 +1,89 @@ |
|
|
|
<template> |
|
|
|
<div class="login"> |
|
|
|
<div class="login-page"> |
|
|
|
<!-- 左上角 Logo --> |
|
|
|
<div class="login-logo"></div> |
|
|
|
|
|
|
|
<!-- 登录卡片 --> |
|
|
|
<div class="loginwrap"> |
|
|
|
<!-- 左侧插画 --> |
|
|
|
<div class="login-illustration"></div> |
|
|
|
|
|
|
|
<!-- 右侧表单区 --> |
|
|
|
<div class="loginbox"> |
|
|
|
<h1>登录</h1> |
|
|
|
|
|
|
|
<el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form"> |
|
|
|
<div class="title-box"> |
|
|
|
<h3 class="title">{{ title }}</h3> |
|
|
|
</div> |
|
|
|
<el-form-item v-if="tenantEnabled" prop="tenantId"> |
|
|
|
<el-select v-model="loginForm.tenantId" filterable :placeholder="proxy.$t('login.selectPlaceholder')" style="width: 100%"> |
|
|
|
<el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"></el-option> |
|
|
|
<template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template> |
|
|
|
<!-- 租户选择 --> |
|
|
|
<el-form-item v-if="tenantEnabled" prop="tenantId" class="form-item"> |
|
|
|
<div class="inptit">租户</div> |
|
|
|
<el-select v-model="loginForm.tenantId" filterable placeholder="请选择租户" class="form-input"> |
|
|
|
<el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId" /> |
|
|
|
</el-select> |
|
|
|
</el-form-item> |
|
|
|
<el-form-item prop="username"> |
|
|
|
<el-input v-model="loginForm.username" type="text" size="large" auto-complete="off" :placeholder="proxy.$t('login.username')"> |
|
|
|
<template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template> |
|
|
|
</el-input> |
|
|
|
|
|
|
|
<!-- 账号 --> |
|
|
|
<el-form-item prop="username" class="form-item"> |
|
|
|
<div class="inptit">账号</div> |
|
|
|
<el-input v-model="loginForm.username" type="text" size="large" auto-complete="off" placeholder="请输入用户名" class="form-input" /> |
|
|
|
</el-form-item> |
|
|
|
<el-form-item prop="password"> |
|
|
|
|
|
|
|
<!-- 密码 --> |
|
|
|
<el-form-item prop="password" class="form-item"> |
|
|
|
<div class="inptit">密码</div> |
|
|
|
<el-input |
|
|
|
v-model="loginForm.password" |
|
|
|
type="password" |
|
|
|
size="large" |
|
|
|
auto-complete="off" |
|
|
|
:placeholder="proxy.$t('login.password')" |
|
|
|
placeholder="请输入密码" |
|
|
|
class="form-input" |
|
|
|
@keyup.enter="handleLogin" |
|
|
|
> |
|
|
|
<template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template> |
|
|
|
</el-input> |
|
|
|
/> |
|
|
|
</el-form-item> |
|
|
|
<el-form-item v-if="captchaEnabled" prop="code"> |
|
|
|
|
|
|
|
<!-- 验证码 --> |
|
|
|
<el-form-item v-if="captchaEnabled" prop="code" class="form-item"> |
|
|
|
<div class="inptit">验证码</div> |
|
|
|
<div class="captcha-row"> |
|
|
|
<el-input |
|
|
|
v-model="loginForm.code" |
|
|
|
size="large" |
|
|
|
auto-complete="off" |
|
|
|
:placeholder="proxy.$t('login.code')" |
|
|
|
style="width: 63%" |
|
|
|
placeholder="请输入验证码" |
|
|
|
class="captcha-input" |
|
|
|
@keyup.enter="handleLogin" |
|
|
|
> |
|
|
|
<template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template> |
|
|
|
</el-input> |
|
|
|
<div class="login-code"> |
|
|
|
<img :src="codeUrl" class="login-code-img" @click="getCode" /> |
|
|
|
/> |
|
|
|
<div class="vcode"> |
|
|
|
<img :src="codeUrl" class="imgcode" @click="getCode" alt="验证码" /> |
|
|
|
</div> |
|
|
|
</el-form-item> |
|
|
|
<!-- <el-checkbox v-model="loginForm.rememberMe" style="margin: 0 0 25px 0">{{ proxy.$t('login.rememberPassword') }}</el-checkbox>--> |
|
|
|
<!-- <el-form-item style="float: right">--> |
|
|
|
<!-- <el-button circle :title="proxy.$t('login.social.wechat')" @click="doSocialLogin('wechat')">--> |
|
|
|
<!-- <svg-icon icon-class="wechat" />--> |
|
|
|
<!-- </el-button>--> |
|
|
|
<!-- <el-button circle :title="proxy.$t('login.social.maxkey')" @click="doSocialLogin('maxkey')">--> |
|
|
|
<!-- <svg-icon icon-class="maxkey" />--> |
|
|
|
<!-- </el-button>--> |
|
|
|
<!-- <el-button circle :title="proxy.$t('login.social.topiam')" @click="doSocialLogin('topiam')">--> |
|
|
|
<!-- <svg-icon icon-class="topiam" />--> |
|
|
|
<!-- </el-button>--> |
|
|
|
<!-- <el-button circle :title="proxy.$t('login.social.gitee')" @click="doSocialLogin('gitee')">--> |
|
|
|
<!-- <svg-icon icon-class="gitee" />--> |
|
|
|
<!-- </el-button>--> |
|
|
|
<!-- <el-button circle :title="proxy.$t('login.social.github')" @click="doSocialLogin('github')">--> |
|
|
|
<!-- <svg-icon icon-class="github" />--> |
|
|
|
<!-- </el-button>--> |
|
|
|
<!-- </el-form-item>--> |
|
|
|
<el-form-item style="width: 100%"> |
|
|
|
<el-button :loading="loading" size="large" type="primary" style="width: 100%" @click.prevent="handleLogin"> |
|
|
|
<span v-if="!loading">{{ proxy.$t('login.login') }}</span> |
|
|
|
<span v-else>{{ proxy.$t('login.logging') }}</span> |
|
|
|
</el-button> |
|
|
|
<div v-if="register" style="float: right"> |
|
|
|
<router-link class="link-type" :to="'/register'">{{ proxy.$t('login.switchRegisterPage') }}</router-link> |
|
|
|
</div> |
|
|
|
</el-form-item> |
|
|
|
<!-- 测试用户快捷登录按钮(仅localhost环境显示) --> |
|
|
|
<el-form-item v-if="isLocalhost" style="width: 100%; margin-bottom: 0"> |
|
|
|
<el-button size="large" type="danger" style="width: 100%" @click="showTestUserDialog = true"> |
|
|
|
选择测试用户 |
|
|
|
</el-button> |
|
|
|
</el-form-item> |
|
|
|
|
|
|
|
<!-- 登录按钮 + 记住密码 --> |
|
|
|
<div class="logindiv"> |
|
|
|
<div class="loginbtn" :class="{ loading: loading }" @click="handleLogin"> |
|
|
|
<span v-if="!loading">登录</span> |
|
|
|
<span v-else>登录中...</span> |
|
|
|
</div> |
|
|
|
<div class="remember-wrap"> |
|
|
|
<input class="checksty" type="checkbox" v-model="loginForm.rememberMe" /> |
|
|
|
<span class="remtxt">记住密码</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 注册链接 --> |
|
|
|
<div v-if="register" class="register-link"> |
|
|
|
<router-link class="link-type" :to="'/register'">没有账号?去注册</router-link> |
|
|
|
</div> |
|
|
|
</el-form> |
|
|
|
|
|
|
|
<!-- 测试用户快捷登录(仅localhost环境显示) --> |
|
|
|
<!-- <div v-if="isLocalhost" class="test-user-area"> |
|
|
|
<div class="loginbtn test-btn" @click="showTestUserDialog = true">选择测试用户</div> |
|
|
|
</div> --> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 测试用户选择弹窗 --> |
|
|
|
<el-dialog v-model="showTestUserDialog" title="选择测试用户" width="620px" append-to-body> |
|
|
|
<el-table :data="testUsers" highlight-current-row style="width: 100%" @row-click="selectTestUser"> |
|
|
|
@ -88,10 +96,6 @@ |
|
|
|
</el-table-column> |
|
|
|
</el-table> |
|
|
|
</el-dialog> |
|
|
|
<!-- 底部 --> |
|
|
|
<div class="el-login-footer"> |
|
|
|
<span>Copyright © 2018-2026 疯狂的狮子Li All Rights Reserved.</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
|
|
|
|
@ -130,9 +134,9 @@ const loginRules: ElFormRules = { |
|
|
|
const codeUrl = ref(''); |
|
|
|
const loading = ref(false); |
|
|
|
// 验证码开关 |
|
|
|
const captchaEnabled = ref(true); |
|
|
|
const captchaEnabled = ref(false); |
|
|
|
// 租户开关 |
|
|
|
const tenantEnabled = ref(true); |
|
|
|
const tenantEnabled = ref(false); |
|
|
|
|
|
|
|
// 注册开关 |
|
|
|
const register = ref(false); |
|
|
|
@ -268,74 +272,234 @@ const doSocialLogin = (type: string) => { |
|
|
|
}; |
|
|
|
|
|
|
|
onMounted(() => { |
|
|
|
getCode(); |
|
|
|
initTenantList(); |
|
|
|
// getCode(); |
|
|
|
// initTenantList(); |
|
|
|
getLoginData(); |
|
|
|
}); |
|
|
|
</script> |
|
|
|
|
|
|
|
<style lang="scss" scoped> |
|
|
|
.login { |
|
|
|
display: flex; |
|
|
|
justify-content: center; |
|
|
|
align-items: center; |
|
|
|
/* ===== 全局重置 ===== */ |
|
|
|
.login-page { |
|
|
|
position: relative; |
|
|
|
width: 100%; |
|
|
|
height: 100%; |
|
|
|
background-image: url('../assets/images/login-background.jpg'); |
|
|
|
background: url('/img/bg_login.jpg') no-repeat #dde1e2 center -130px; |
|
|
|
background-size: cover; |
|
|
|
overflow: hidden; |
|
|
|
font-family: 'Microsoft Yahei', Arial, Verdana, sans-serif; |
|
|
|
} |
|
|
|
|
|
|
|
.title-box { |
|
|
|
/* ===== 左上角 Logo ===== */ |
|
|
|
.login-logo { |
|
|
|
position: absolute; |
|
|
|
top: 5%; |
|
|
|
left: 5%; |
|
|
|
width: 35%; |
|
|
|
height: 60px; |
|
|
|
background: url('/img/logo-zfjd-st.png') no-repeat; |
|
|
|
background-size: 70%; |
|
|
|
} |
|
|
|
|
|
|
|
/* ===== 登录卡片容器 ===== */ |
|
|
|
.loginwrap { |
|
|
|
position: absolute; |
|
|
|
z-index: 9; |
|
|
|
top: 50%; |
|
|
|
left: 50%; |
|
|
|
transform: translate(-50%, -50%); |
|
|
|
width: 50%; |
|
|
|
height: 55%; |
|
|
|
min-height: 420px; |
|
|
|
padding: 3%; |
|
|
|
background: #fff url('/img/login_pic.png') no-repeat left -10% top -10px; |
|
|
|
background-size: auto 105%; |
|
|
|
border-radius: 20px; |
|
|
|
box-shadow: 0 0 15px rgba(0, 10, 51, 0.35); |
|
|
|
display: flex; |
|
|
|
} |
|
|
|
|
|
|
|
/* 左侧插画区域(背景图已设在父容器) */ |
|
|
|
.login-illustration { |
|
|
|
flex: 0 0 55%; |
|
|
|
} |
|
|
|
|
|
|
|
/* ===== 右侧表单区 ===== */ |
|
|
|
.loginbox { |
|
|
|
position: relative; |
|
|
|
flex: 0 0 42%; |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
//justify-content: center; |
|
|
|
letter-spacing: 2px; |
|
|
|
margin-left: 6%; |
|
|
|
top:-50px; |
|
|
|
} |
|
|
|
|
|
|
|
.title { |
|
|
|
margin: 0px auto 30px auto; |
|
|
|
.loginbox h1 { |
|
|
|
font-size: 24px; |
|
|
|
font-weight: 550; |
|
|
|
line-height: 3; |
|
|
|
text-align: center; |
|
|
|
color: #707070; |
|
|
|
margin-bottom: 10px; |
|
|
|
} |
|
|
|
|
|
|
|
:deep(.lang-select--style) { |
|
|
|
line-height: 0; |
|
|
|
color: #7483a3; |
|
|
|
/* ===== 表单项 ===== */ |
|
|
|
.form-item { |
|
|
|
margin-bottom: 16px; |
|
|
|
} |
|
|
|
|
|
|
|
.inptit { |
|
|
|
margin: 0 0 0px 5%; |
|
|
|
font-size: 16px; |
|
|
|
color: #000; |
|
|
|
font-weight: 500; |
|
|
|
} |
|
|
|
|
|
|
|
.login-form { |
|
|
|
border-radius: 6px; |
|
|
|
background: #ffffff; |
|
|
|
width: 400px; |
|
|
|
padding: 25px 25px 5px 25px; |
|
|
|
z-index: 1; |
|
|
|
.el-input { |
|
|
|
height: 40px; |
|
|
|
input { |
|
|
|
.form-input { |
|
|
|
margin: 0 3%; |
|
|
|
width: 90%; |
|
|
|
|
|
|
|
:deep(.el-input__wrapper) { |
|
|
|
border: 0; |
|
|
|
border-bottom: 1px solid #ddd; |
|
|
|
border-radius: 0; |
|
|
|
box-shadow: none; |
|
|
|
background: transparent; |
|
|
|
} |
|
|
|
|
|
|
|
:deep(.el-input__inner) { |
|
|
|
border: none; |
|
|
|
height: 40px; |
|
|
|
line-height: 40px; |
|
|
|
color: #999; |
|
|
|
} |
|
|
|
|
|
|
|
:deep(.el-select__wrapper) { |
|
|
|
border: 0; |
|
|
|
border-bottom: 1px solid #ddd; |
|
|
|
border-radius: 0; |
|
|
|
box-shadow: none; |
|
|
|
background: transparent; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.input-icon { |
|
|
|
height: 39px; |
|
|
|
width: 14px; |
|
|
|
margin-left: 0px; |
|
|
|
/* 验证码行 */ |
|
|
|
.captcha-row { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
margin: 0 5%; |
|
|
|
width: 90%; |
|
|
|
gap: 8px; |
|
|
|
} |
|
|
|
|
|
|
|
.captcha-input { |
|
|
|
flex: 1; |
|
|
|
|
|
|
|
:deep(.el-input__wrapper) { |
|
|
|
border: 0; |
|
|
|
border-bottom: 1px solid #ddd; |
|
|
|
border-radius: 0; |
|
|
|
box-shadow: none; |
|
|
|
background: transparent; |
|
|
|
} |
|
|
|
|
|
|
|
.login-tip { |
|
|
|
font-size: 13px; |
|
|
|
text-align: center; |
|
|
|
color: #bfbfbf; |
|
|
|
:deep(.el-input__inner) { |
|
|
|
border: none; |
|
|
|
height: 40px; |
|
|
|
line-height: 40px; |
|
|
|
color: #999; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.login-code { |
|
|
|
width: 33%; |
|
|
|
.vcode { |
|
|
|
flex-shrink: 0; |
|
|
|
width: 120px; |
|
|
|
height: 40px; |
|
|
|
float: right; |
|
|
|
border: 1px solid #eee; |
|
|
|
overflow: hidden; |
|
|
|
border-radius: 4px; |
|
|
|
cursor: pointer; |
|
|
|
|
|
|
|
img { |
|
|
|
.imgcode { |
|
|
|
width: auto; |
|
|
|
height: 100%; |
|
|
|
cursor: pointer; |
|
|
|
vertical-align: middle; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* ===== 登录按钮 + 记住密码 ===== */ |
|
|
|
.logindiv { |
|
|
|
margin: 20px 5% 0; |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
justify-content: space-between; |
|
|
|
} |
|
|
|
|
|
|
|
.remember-wrap { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
position: relative; |
|
|
|
} |
|
|
|
|
|
|
|
.checksty { |
|
|
|
width: 16px; |
|
|
|
height: 16px; |
|
|
|
margin: 0; |
|
|
|
cursor: pointer; |
|
|
|
} |
|
|
|
|
|
|
|
.remtxt { |
|
|
|
margin-left: 8px; |
|
|
|
color: #666; |
|
|
|
font-size: 14px; |
|
|
|
} |
|
|
|
|
|
|
|
.loginbtn { |
|
|
|
background-color: #1367fe; |
|
|
|
border-radius: 50px; |
|
|
|
color: #fff; |
|
|
|
font-size: 16px; |
|
|
|
line-height: 40px; |
|
|
|
text-align: center; |
|
|
|
box-shadow: 0 0 10px rgba(19, 103, 254, 0.8); |
|
|
|
width: 60%; |
|
|
|
cursor: pointer; |
|
|
|
transition: opacity 0.2s; |
|
|
|
user-select: none; |
|
|
|
|
|
|
|
&:hover { |
|
|
|
opacity: 0.8; |
|
|
|
} |
|
|
|
|
|
|
|
&.loading { |
|
|
|
opacity: 0.6; |
|
|
|
pointer-events: none; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.test-user-area { |
|
|
|
margin-top: 12px; |
|
|
|
|
|
|
|
.test-btn { |
|
|
|
width: 100%; |
|
|
|
background-color: #e6a23c; |
|
|
|
box-shadow: 0 0 10px rgba(230, 162, 60, 0.8); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.register-link { |
|
|
|
margin-top: 12px; |
|
|
|
text-align: center; |
|
|
|
|
|
|
|
.link-type { |
|
|
|
color: #2380fe; |
|
|
|
text-decoration: none; |
|
|
|
font-size: 14px; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* ===== 底部版权 ===== */ |
|
|
|
.el-login-footer { |
|
|
|
height: 40px; |
|
|
|
line-height: 40px; |
|
|
|
@ -349,8 +513,27 @@ onMounted(() => { |
|
|
|
letter-spacing: 1px; |
|
|
|
} |
|
|
|
|
|
|
|
.login-code-img { |
|
|
|
height: 40px; |
|
|
|
padding-left: 12px; |
|
|
|
/* ===== 响应式 ===== */ |
|
|
|
@media screen and (max-width: 1600px) { |
|
|
|
.loginwrap { |
|
|
|
width: 60%; |
|
|
|
background-position: left -12% top -10px; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@media screen and (max-width: 1024px) { |
|
|
|
.loginwrap { |
|
|
|
width: 65%; |
|
|
|
background-position: left -15% top -10px; |
|
|
|
} |
|
|
|
|
|
|
|
.login-illustration { |
|
|
|
display: none; |
|
|
|
} |
|
|
|
|
|
|
|
.loginbox { |
|
|
|
flex: 0 0 90%; |
|
|
|
margin-left: 0; |
|
|
|
} |
|
|
|
} |
|
|
|
</style> |
|
|
|
|