2024-06-13 11:30:23 +08:00
|
|
|
|
<template>
|
2024-06-19 16:32:11 +08:00
|
|
|
|
<div class="login-div">
|
|
|
|
|
<!-- <div class="switch-language">
|
2024-06-13 11:30:23 +08:00
|
|
|
|
<el-dropdown size="large" :hide-timeout="50" placement="bottom-end" :hide-on-click="true">
|
|
|
|
|
<Icon name="fa fa-globe" color="var(--el-text-color-secondary)" size="28" />
|
|
|
|
|
<template #dropdown>
|
|
|
|
|
<el-dropdown-menu class="chang-lang">
|
|
|
|
|
<el-dropdown-item v-for="item in config.lang.langArray" :key="item.name" @click="editDefaultLang(item.name)">
|
|
|
|
|
{{ item.value }}
|
|
|
|
|
</el-dropdown-item>
|
|
|
|
|
</el-dropdown-menu>
|
|
|
|
|
</template>
|
|
|
|
|
</el-dropdown>
|
2024-06-19 16:32:11 +08:00
|
|
|
|
</div> -->
|
2024-06-13 11:30:23 +08:00
|
|
|
|
<div @contextmenu.stop="" id="bubble" class="bubble">
|
|
|
|
|
<canvas id="bubble-canvas" class="bubble-canvas"></canvas>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="login">
|
|
|
|
|
<div class="login-box">
|
|
|
|
|
<div class="form">
|
2024-06-19 16:32:11 +08:00
|
|
|
|
<div class="title">
|
|
|
|
|
<div class="title1">欢迎使用润阳风电场系统</div>
|
|
|
|
|
<div class="title2">一站式数据采集平台</div>
|
|
|
|
|
</div>
|
2024-06-13 11:30:23 +08:00
|
|
|
|
<div class="content">
|
|
|
|
|
<el-form @keyup.enter="onSubmitPre()" ref="formRef" :rules="rules" size="large" :model="form">
|
|
|
|
|
<el-form-item prop="username">
|
|
|
|
|
<el-input
|
|
|
|
|
ref="usernameRef"
|
|
|
|
|
type="text"
|
|
|
|
|
clearable
|
|
|
|
|
v-model="form.username"
|
|
|
|
|
:placeholder="t('login.Please enter an account')"
|
|
|
|
|
>
|
|
|
|
|
<template #prefix>
|
|
|
|
|
<Icon name="fa fa-user" class="form-item-icon" size="16" color="var(--el-input-icon-color)" />
|
|
|
|
|
</template>
|
|
|
|
|
</el-input>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item prop="password">
|
|
|
|
|
<el-input
|
|
|
|
|
ref="passwordRef"
|
|
|
|
|
v-model="form.password"
|
|
|
|
|
type="password"
|
|
|
|
|
:placeholder="t('login.Please input a password')"
|
|
|
|
|
show-password
|
|
|
|
|
>
|
|
|
|
|
<template #prefix>
|
|
|
|
|
<Icon name="fa fa-unlock-alt" class="form-item-icon" size="16" color="var(--el-input-icon-color)" />
|
|
|
|
|
</template>
|
|
|
|
|
</el-input>
|
|
|
|
|
</el-form-item>
|
2024-06-19 10:56:57 +08:00
|
|
|
|
<el-form-item v-if="state.showCaptcha" prop="captcha">
|
|
|
|
|
<el-space>
|
2024-06-19 18:05:52 +08:00
|
|
|
|
<el-input ref="captchaRef" v-model="form.code" type="text" :placeholder="t('login.Please input a captcha')">
|
2024-06-19 10:56:57 +08:00
|
|
|
|
<template #prefix>
|
|
|
|
|
<Icon name="fa fa-unlock-alt" class="form-item-icon" size="16" color="var(--el-input-icon-color)" />
|
|
|
|
|
</template>
|
|
|
|
|
</el-input>
|
2024-06-19 18:05:52 +08:00
|
|
|
|
<img @click.prevent="load()" :src="state.captcha" />
|
2024-06-19 10:56:57 +08:00
|
|
|
|
</el-space>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<!-- <el-checkbox v-model="form.keep" :label="t('login.Hold session')" size="default"></el-checkbox> -->
|
2024-06-13 11:30:23 +08:00
|
|
|
|
<el-form-item>
|
|
|
|
|
<el-button
|
|
|
|
|
:loading="state.submitLoading"
|
|
|
|
|
class="submit-button"
|
|
|
|
|
round
|
|
|
|
|
type="primary"
|
|
|
|
|
size="large"
|
|
|
|
|
@click="onSubmitPre()"
|
|
|
|
|
>
|
|
|
|
|
{{ t('login.Sign in') }}
|
|
|
|
|
</el-button>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-form>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { onMounted, onBeforeUnmount, reactive, ref, nextTick } from 'vue'
|
2024-06-19 10:56:57 +08:00
|
|
|
|
import { getCaptchaData } from '/@/api/common'
|
2024-06-13 11:30:23 +08:00
|
|
|
|
import * as pageBubble from '/@/utils/pageBubble'
|
|
|
|
|
import type { FormInstance, InputInstance } from 'element-plus'
|
2024-06-19 18:05:52 +08:00
|
|
|
|
import { ElNotification } from 'element-plus'
|
2024-06-13 11:30:23 +08:00
|
|
|
|
import { useI18n } from 'vue-i18n'
|
|
|
|
|
import { editDefaultLang } from '/@/lang/index'
|
|
|
|
|
import { useConfig } from '/@/stores/config'
|
|
|
|
|
import { useAdminInfo } from '/@/stores/adminInfo'
|
|
|
|
|
import { login } from '/@/api/backend'
|
|
|
|
|
import { buildValidatorData } from '/@/utils/validate'
|
|
|
|
|
import router from '/@/router'
|
2024-06-19 10:56:57 +08:00
|
|
|
|
// import clickCaptcha from '/@/components/clickCaptcha'
|
2024-06-13 11:30:23 +08:00
|
|
|
|
import toggleDark from '/@/utils/useDark'
|
|
|
|
|
import { fullUrl } from '/@/utils/common'
|
|
|
|
|
import { adminBaseRoutePath } from '/@/router/static/adminBase'
|
|
|
|
|
import JSEncrypt from 'jsencrypt'
|
|
|
|
|
let timer: number
|
|
|
|
|
|
|
|
|
|
const config = useConfig()
|
|
|
|
|
const adminInfo = useAdminInfo()
|
|
|
|
|
toggleDark(config.layout.isDark)
|
|
|
|
|
|
|
|
|
|
const formRef = ref<FormInstance>()
|
|
|
|
|
const usernameRef = ref<InputInstance>()
|
|
|
|
|
const passwordRef = ref<InputInstance>()
|
2024-06-19 10:56:57 +08:00
|
|
|
|
const captchaRef = ref<InputInstance>()
|
2024-06-13 11:30:23 +08:00
|
|
|
|
const state = reactive({
|
2024-06-19 10:56:57 +08:00
|
|
|
|
showCaptcha: true,
|
2024-06-13 11:30:23 +08:00
|
|
|
|
submitLoading: false,
|
2024-06-19 10:56:57 +08:00
|
|
|
|
captcha: '',
|
2024-06-13 11:30:23 +08:00
|
|
|
|
})
|
|
|
|
|
const form = reactive({
|
|
|
|
|
username: '',
|
|
|
|
|
password: '',
|
|
|
|
|
keep: false,
|
2024-06-19 10:56:57 +08:00
|
|
|
|
uuid: '',
|
|
|
|
|
code: '',
|
2024-06-13 11:30:23 +08:00
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const { t } = useI18n()
|
|
|
|
|
|
|
|
|
|
// 表单验证规则
|
|
|
|
|
const rules = reactive({
|
|
|
|
|
username: [buildValidatorData({ name: 'required', message: t('login.Please enter an account') }), buildValidatorData({ name: 'account' })],
|
|
|
|
|
password: [buildValidatorData({ name: 'required', message: t('login.Please input a password') }), buildValidatorData({ name: 'password' })],
|
2024-06-19 18:05:52 +08:00
|
|
|
|
code: [buildValidatorData({ name: 'required', message: t('login.Please input a captcha') })],
|
2024-06-13 11:30:23 +08:00
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const focusInput = () => {
|
|
|
|
|
if (form.username === '') {
|
|
|
|
|
usernameRef.value!.focus()
|
|
|
|
|
} else if (form.password === '') {
|
|
|
|
|
passwordRef.value!.focus()
|
2024-06-19 10:56:57 +08:00
|
|
|
|
} else if (form.code === '') {
|
|
|
|
|
captchaRef.value!.focus()
|
2024-06-13 11:30:23 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
timer = window.setTimeout(() => {
|
|
|
|
|
pageBubble.init()
|
|
|
|
|
}, 1000)
|
2024-06-19 10:56:57 +08:00
|
|
|
|
load()
|
2024-06-13 11:30:23 +08:00
|
|
|
|
// login('get')
|
|
|
|
|
// .then((res) => {
|
|
|
|
|
// state.showCaptcha = res.data.captcha
|
|
|
|
|
// nextTick(() => focusInput())
|
|
|
|
|
// })
|
|
|
|
|
// .catch((err) => {
|
|
|
|
|
// console.log(err)
|
|
|
|
|
// })
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
onBeforeUnmount(() => {
|
|
|
|
|
clearTimeout(timer)
|
|
|
|
|
pageBubble.removeListeners()
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const onSubmitPre = () => {
|
|
|
|
|
formRef.value?.validate((valid) => {
|
|
|
|
|
if (valid) {
|
2024-06-19 10:56:57 +08:00
|
|
|
|
// if (state.showCaptcha) {
|
|
|
|
|
// clickCaptcha(form.uuid, (captchaInfo: string) => onSubmit(captchaInfo))
|
|
|
|
|
// } else {
|
|
|
|
|
onSubmit()
|
|
|
|
|
// }
|
2024-06-13 11:30:23 +08:00
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-19 10:56:57 +08:00
|
|
|
|
const load = () => {
|
|
|
|
|
getCaptchaData().then((res) => {
|
2024-06-19 11:41:29 +08:00
|
|
|
|
form.uuid = res.data.key
|
2024-06-19 10:56:57 +08:00
|
|
|
|
state.captcha = 'data:image\/png;base64,' + res.data.img
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-19 11:41:29 +08:00
|
|
|
|
const onSubmit = () => {
|
2024-06-13 11:30:23 +08:00
|
|
|
|
state.submitLoading = true
|
2024-06-19 10:56:57 +08:00
|
|
|
|
login(form)
|
2024-06-13 11:30:23 +08:00
|
|
|
|
.then((res) => {
|
2024-06-19 18:05:52 +08:00
|
|
|
|
if (res.code == 200) {
|
|
|
|
|
adminInfo.dataFill({
|
|
|
|
|
id: res.data.sysUser.id,
|
|
|
|
|
username: res.data.sysUser.account,
|
|
|
|
|
nickname: res.data.sysUser.userName,
|
|
|
|
|
avatar: '',
|
|
|
|
|
last_login_time: '',
|
|
|
|
|
token: res.data.token,
|
|
|
|
|
refresh_token: '',
|
|
|
|
|
// 是否是superAdmin,用于判定是否显示终端按钮等,不做任何权限判断
|
|
|
|
|
super: false,
|
|
|
|
|
})
|
|
|
|
|
router.push({ path: adminBaseRoutePath })
|
|
|
|
|
} else {
|
|
|
|
|
ElNotification({
|
|
|
|
|
message: res.msg,
|
|
|
|
|
type: 'error',
|
|
|
|
|
})
|
|
|
|
|
load()
|
|
|
|
|
}
|
2024-06-13 11:30:23 +08:00
|
|
|
|
})
|
|
|
|
|
.finally(() => {
|
|
|
|
|
state.submitLoading = false
|
2024-06-19 16:32:11 +08:00
|
|
|
|
// load()
|
2024-06-13 11:30:23 +08:00
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
2024-06-19 16:32:11 +08:00
|
|
|
|
.login-div {
|
|
|
|
|
}
|
2024-06-13 11:30:23 +08:00
|
|
|
|
.switch-language {
|
|
|
|
|
position: fixed;
|
|
|
|
|
top: 20px;
|
|
|
|
|
right: 20px;
|
|
|
|
|
z-index: 1;
|
|
|
|
|
}
|
|
|
|
|
.bubble {
|
|
|
|
|
overflow: hidden;
|
2024-06-19 16:32:11 +08:00
|
|
|
|
width: 64%;
|
|
|
|
|
background: url(/@/assets/bg.png) no-repeat;
|
|
|
|
|
background-size: 100% 100%;
|
2024-06-13 11:30:23 +08:00
|
|
|
|
}
|
|
|
|
|
.form-item-icon {
|
|
|
|
|
height: auto;
|
|
|
|
|
}
|
|
|
|
|
.login {
|
|
|
|
|
position: absolute;
|
|
|
|
|
top: 0;
|
2024-06-19 16:32:11 +08:00
|
|
|
|
right: 0;
|
2024-06-13 11:30:23 +08:00
|
|
|
|
display: flex;
|
2024-06-19 16:32:11 +08:00
|
|
|
|
width: 36%;
|
|
|
|
|
height: 100%;
|
2024-06-13 11:30:23 +08:00
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
.login-box {
|
|
|
|
|
overflow: hidden;
|
2024-06-19 16:32:11 +08:00
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
2024-06-13 11:30:23 +08:00
|
|
|
|
background: var(--ba-bg-color-overlay);
|
2024-06-19 16:32:11 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
2024-06-13 11:30:23 +08:00
|
|
|
|
}
|
2024-06-19 16:32:11 +08:00
|
|
|
|
.title {
|
|
|
|
|
.title1 {
|
|
|
|
|
font-size: 36px;
|
|
|
|
|
color: #333333;
|
|
|
|
|
letter-spacing: 0;
|
|
|
|
|
line-height: 36px;
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
}
|
|
|
|
|
.title2 {
|
|
|
|
|
padding-top: 20px;
|
|
|
|
|
font-size: 24px;
|
|
|
|
|
color: #666666;
|
|
|
|
|
letter-spacing: 0;
|
|
|
|
|
line-height: 24px;
|
|
|
|
|
font-weight: 400;
|
2024-06-13 11:30:23 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.form {
|
|
|
|
|
position: relative;
|
|
|
|
|
.profile-avatar {
|
|
|
|
|
display: block;
|
|
|
|
|
position: absolute;
|
|
|
|
|
height: 100px;
|
|
|
|
|
width: 100px;
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
border: 4px solid var(--ba-bg-color-overlay);
|
|
|
|
|
top: -50px;
|
|
|
|
|
right: calc(50% - 50px);
|
|
|
|
|
z-index: 2;
|
|
|
|
|
user-select: none;
|
|
|
|
|
}
|
|
|
|
|
.content {
|
2024-06-19 16:32:11 +08:00
|
|
|
|
padding: 100px 0;
|
2024-06-13 11:30:23 +08:00
|
|
|
|
}
|
|
|
|
|
.submit-button {
|
|
|
|
|
width: 100%;
|
|
|
|
|
letter-spacing: 2px;
|
|
|
|
|
font-weight: 300;
|
|
|
|
|
margin-top: 15px;
|
2024-06-19 16:32:11 +08:00
|
|
|
|
// --el-button-bg-color: var(--el-color-primary);
|
2024-06-13 11:30:23 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-19 16:32:11 +08:00
|
|
|
|
@media screen and (max-width: 1370px) {
|
|
|
|
|
.title {
|
|
|
|
|
.title1 {
|
|
|
|
|
font-size: 30px !important;
|
|
|
|
|
}
|
|
|
|
|
.title2 {
|
|
|
|
|
font-size: 20px !important;
|
2024-06-13 11:30:23 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.chang-lang :deep(.el-dropdown-menu__item) {
|
|
|
|
|
justify-content: center;
|
|
|
|
|
}
|
|
|
|
|
.content :deep(.el-input__prefix) {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 暗黑样式
|
|
|
|
|
@at-root .dark {
|
|
|
|
|
.bubble {
|
|
|
|
|
background: url(/@/assets/bg-dark.jpg) repeat;
|
|
|
|
|
}
|
|
|
|
|
.login {
|
|
|
|
|
.login-box {
|
|
|
|
|
background: #161b22;
|
|
|
|
|
}
|
|
|
|
|
.head {
|
|
|
|
|
img {
|
|
|
|
|
filter: brightness(61%);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.form {
|
|
|
|
|
.submit-button {
|
|
|
|
|
--el-button-bg-color: var(--el-color-primary-light-5);
|
|
|
|
|
--el-button-border-color: rgba(240, 252, 241, 0.1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@media screen and (max-height: 800px) {
|
|
|
|
|
.login .login-box {
|
|
|
|
|
margin-bottom: 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</style>
|