| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604 |
- <template>
- <div class="login" ref="loginRef">
- <!-- <a-carousel autoplay class="carousel" dotsClass="dots" lazyLoad :autoplaySpeed="60000" adaptiveHeight>
- <div>
- <img :src="loginBg1" class="img" alt="">
- </div>
- <div>
- <img :src="loginBg2" class="img" alt="">
- </div>
- </a-carousel> -->
- <div class="login-box">
- <div class="login-left">
- <div class="login-left-box">
- <!-- <img class="logo" :src="logo" alt=""> -->
- <!-- <div class="slogan">合作共赢 · 品质第一 </div> -->
- <!-- <div class="type">
- 研发设计/生产制造/工程管理/投资运营
- </div> -->
- </div>
- </div>
- <div class="login-right">
- <div class="login-right-box">
- <div class="login-right-title">
- <span class="welcome">欢迎登录</span>Admin内控平台
- </div>
- <div class="login-right-form">
- <a-tabs v-model:activeKey="activeKey" class="tabs">
- <a-tab-pane key="0" tab="账号登录" force-render>
- <div class="login-form" v-if="activeKey === '0'">
- <a-form ref="formRef" :model="loginForm" :rules="rules">
- <a-form-item name="loginName" class="form-item">
- <div class="label">
- 账户
- </div>
- <a-input class="input" v-model:value.trim="loginForm.loginName" placeholder="请输入用户名">
- <template #prefix>
- <UserOutlined />
- </template>
- </a-input>
- </a-form-item>
- <a-form-item name="emailCode" class="form-item" v-if="emailCodeShowFlag" label="邮箱验证码">
- <a-input-group compact>
- <a-input style="width: calc(100% - 110px)" v-model:value="loginForm.emailCode" autocomplete="on"
- placeholder="请输入邮箱验证码" />
- <a-button @click="sendSmsCode" type="primary" :disabled="emailCodeButtonDisabled">
- {{ emailCodeTips }}
- </a-button>
- </a-input-group>
- </a-form-item>
- <a-form-item name="password" class="form-item">
- <div class="label">
- 密码
- </div>
- <a-input-password class="input" v-model:value="loginForm.password" autocomplete="on"
- :type="showPassword ? 'text' : 'password'" placeholder="请输入密码">
- <template #prefix>
- <SafetyOutlined />
- </template>
- </a-input-password>
- </a-form-item>
- <a-form-item name="captchaCode" class="form-item">
- <div class="label">
- 验证码
- </div>
- <div class="captchaCode-img">
- <a-input v-model:value.trim="loginForm.captchaCode" class="input" placeholder="请输入验证码">
- <template #prefix>
- <SafetyOutlined />
- </template>
- <template #suffix>
- <img :src="captchaBase64Image" class="img" @click="getCaptcha" />
- </template>
- </a-input>
- </div>
- </a-form-item>
- <!-- <a-form-item>
- <a-checkbox v-model:checked="rememberPwd">记住密码</a-checkbox>
- </a-form-item> -->
- <a-form-item class="form-item">
- <div class="form-btn">
- <a-button class="btn" @click="onLogin" type="primary" size="large">登录</a-button>
- </div>
- </a-form-item>
- </a-form>
- </div>
- </a-tab-pane>
- <a-tab-pane key="1" tab="扫码登录" force-render>
- <div class="qrcode-login" v-if="activeKey === '1'" :class="ratio > 0.985 ? 'margin-top' : 'flex-center'">
- <img class="img" :src="tip" alt="" v-if="ratio > 0.985">
- <div class="code" :class="{ 'absolute-right': ratio > 0.985 }">
- <ddLogin />
- <!-- <a-qrcode value="https://www.antdv.com/" :size="250" /> -->
- </div>
- </div>
- </a-tab-pane>
- </a-tabs>
- <!-- <div class="login-right-bottom">如有疑问请致电:营销热线0532-88988868</div> -->
- </div>
- </div>
- </div>
- </div>
- </div>
- </template>
- <script setup>
- import { message } from 'ant-design-vue';
- import { onMounted, onUnmounted, reactive, ref, watch } from 'vue';
- import { useRouter } from 'vue-router';
- import { loginApi } from '/@/api/system/login-api';
- import { SmartLoading } from '/@/components/framework/smart-loading';
- import { LOGIN_DEVICE_ENUM } from '/@/constants/system/login-device-const';
- import { useUserStore } from '/@/store/modules/system/user';
- import loginBg2 from '/@/assets/images/login/login_bg2.png'
- import loginBg1 from '/@/assets/images/login/login_bg1.png'
- import tip from '/@/assets/images/login/tooltip.png'
- import logo from '/@/assets/images/login/logo1.png'
- import { buildRoutes } from '/@/router/index';
- import { smartSentry } from '/@/lib/smart-sentry';
- import { encryptData, decryptData } from '/@/lib/encrypt';
- import { localSave, localRemove, localRead } from '/@/utils/local-util.js';
- import LocalStorageKeyConst from '/@/constants/local-storage-key-const.js';
- import { Form } from 'ant-design-vue';
- import useBsDict from "/@/utils/dict.js";
- import ddLogin from '/@/components/support/dd-login/index.vue'
- const activeKey = ref('0')
- //--------------------- 登录表单 ---------------------------------
- const loginForm = reactive({
- loginName: 'admin',
- password: '',
- captchaCode: '',
- captchaUuid: '',
- loginDevice: LOGIN_DEVICE_ENUM.PC.value,
- });
- const rules = {
- loginName: [{ required: true, message: '用户名不能为空' }],
- password: [{ required: true, message: '密码不能为空' }],
- captchaCode: [{ required: true, message: '验证码不能为空' }],
- };
- const showPassword = ref(false);
- const router = useRouter();
- const formRef = ref();
- // const rememberPwd = ref(false);
- // function readLocalRememberMe() {
- // const rememberMe = JSON.parse(localRead('rememberMe') || null);
- // if (rememberMe) {
- // rememberMe.password = rememberMe.password ? decryptData(rememberMe.password) : '';
- // loginForm.loginName = rememberMe.loginName;
- // loginForm.password = rememberMe.password;
- // rememberPwd.value = true;
- // // console.log('readLocalRememberMe', rememberMe);
- // }
- // }
- onMounted(() => {
- // readLocalRememberMe();
- document.onkeyup = (e) => {
- if (e.keyCode === 13) {
- onLogin();
- }
- };
- });
- onUnmounted(() => {
- document.onkeyup = null;
- });
- //登录
- async function onLogin() {
- formRef.value.validate().then(async () => {
- try {
- SmartLoading.show();
- // 密码加密
- let encryptPasswordForm = Object.assign({}, loginForm, {
- password: encryptData(loginForm.password),
- });
- const res = await loginApi.login(encryptPasswordForm);
- stopRefreshCaptchaInterval();
- // if (rememberPwd.value === true) {
- // localSave('rememberMe', JSON.stringify({ loginName: encryptPasswordForm.loginName, password: encryptPasswordForm.password }));
- // } else {
- // localRemove('rememberMe');
- // }
- localSave(LocalStorageKeyConst.USER_TOKEN, res.data.token ? res.data.token : '');
- message.success('登录成功');
- // 刷新本地缓存
- await useBsDict.refresh();
- //更新用户信息到pinia
- useUserStore().setUserLoginInfo(res.data);
- localSave('loginFrom', '0');
- //构建系统的路由
- buildRoutes();
- router.push('/home');
- } catch (e) {
- if (e.data && e.data.code !== 0) {
- loginForm.captchaCode = '';
- getCaptcha();
- }
- smartSentry.captureError(e);
- } finally {
- SmartLoading.hide();
- }
- });
- }
- //--------------------- 验证码 ---------------------------------
- const captchaBase64Image = ref('');
- async function getCaptcha() {
- try {
- let captchaResult = await loginApi.getCaptcha();
- captchaBase64Image.value = captchaResult.data.captchaBase64Image;
- loginForm.captchaUuid = captchaResult.data.captchaUuid;
- beginRefreshCaptchaInterval(captchaResult.data.expireSeconds);
- } catch (e) {
- console.log(e);
- }
- }
- let refreshCaptchaInterval = null;
- function beginRefreshCaptchaInterval(expireSeconds) {
- if (refreshCaptchaInterval === null) {
- refreshCaptchaInterval = setInterval(getCaptcha, (expireSeconds - 5) * 1000);
- }
- }
- function stopRefreshCaptchaInterval() {
- if (refreshCaptchaInterval != null) {
- clearInterval(refreshCaptchaInterval);
- refreshCaptchaInterval = null;
- }
- }
- onMounted(() => {
- getCaptcha();
- getTwoFactorLoginFlag();
- });
- //--------------------- 邮箱验证码 ---------------------------------
- const emailCodeShowFlag = ref(false);
- let emailCodeTips = ref('获取邮箱验证码');
- let emailCodeButtonDisabled = ref(false);
- // 定时器
- let countDownTimer = null;
- // 开始倒计时
- function runCountDown() {
- emailCodeButtonDisabled.value = true;
- let countDown = 60;
- emailCodeTips.value = `${countDown}秒后重新获取`;
- countDownTimer = setInterval(() => {
- if (countDown > 1) {
- countDown--;
- emailCodeTips.value = `${countDown}秒后重新获取`;
- } else {
- clearInterval(countDownTimer);
- emailCodeButtonDisabled.value = false;
- emailCodeTips.value = '获取验证码';
- }
- }, 1000);
- }
- // 获取双因子登录标识
- async function getTwoFactorLoginFlag() {
- try {
- let result = await loginApi.getTwoFactorLoginFlag();
- emailCodeShowFlag.value = result.data;
- } catch (e) {
- smartSentry.captureError(e);
- }
- }
- // 发送邮箱验证码
- async function sendSmsCode() {
- try {
- SmartLoading.show();
- let result = await loginApi.sendLoginEmailCode(loginForm.loginName);
- message.success('验证码发送成功!请登录邮箱查看验证码~');
- runCountDown();
- } catch (e) {
- smartSentry.captureError(e);
- } finally {
- SmartLoading.hide();
- }
- }
- // ---------------- 适配屏幕缩放 ----------------
- const loginRef = ref(null);
- const ratio = ref(1);
- function reduceRatio() {
- handleResize();
- window.addEventListener('resize', handleResize);
- }
- function handleResize() {
- ratio.value = window.innerWidth / 1920;
- loginRef.value.style.setProperty('--fitWidthRatio', ratio.value);
- }
- watch(() => ratio.value, (value) => {
- console.log(value);
- })
- onMounted(() => {
- reduceRatio();
- });
- onUnmounted(() => {
- window.removeEventListener('resize', handleResize);
- });
- </script>
- <style lang="scss" scoped>
- .login {
- height: 100vh;
- width: 100vw;
- // background-color: #e39f77;
- .carousel {
- height: 100%;
- position: absolute;
- width: 100%;
- left: 0;
- top: 0;
- z-index: 0;
- .img {
- height: 100vh;
- width: 100vw;
- }
- :deep(.dots) {
- width: 65%;
- align-items: center;
- }
- :deep(.dots li) {
- height: calc(var(--fitWidthRatio) * 20px);
- width: calc(var(--fitWidthRatio) * 20px);
- }
- :deep(.dots :not(.slick-active) button) {
- height: 100%;
- border-radius: calc(var(--fitWidthRatio) * 20px);
- }
- :deep(.dots .slick-active) {
- width: calc(var(--fitWidthRatio) * 52px);
- height: calc(var(--fitWidthRatio) * 16px);
- }
- :deep(.slick-active button) {
- background-color: #2b69f8;
- border-radius: calc(var(--fitWidthRatio) * 20px);
- height: 100%;
- }
- }
- .login-box {
- display: flex;
- flex-direction: row;
- // align-items: center;
- gap: calc(var(--fitWidthRatio) * 60px);
- height: 100%;
- width: 100%;
- .login-left {
- display: flex;
- flex-direction: column;
- height: 35%;
- width: 55%;
- position: absolute;
- left: 0;
- top: 20%;
- background: linear-gradient(to right, #FFFFFF, #99999900);
- z-index: 1;
- padding: calc(var(--fitWidthRatio) * 30px);
- .login-left-box {
- // width: 46%;
- height: 100%;
- display: flex;
- flex-direction: column;
- justify-content: space-evenly;
- .logo {
- height: calc(var(--fitWidthRatio) * 84px);
- width: calc(var(--fitWidthRatio) * 240px);
- }
- .slogan {
- font-size: calc(var(--fitWidthRatio) * 32px);
- font-weight: 600;
- font-family: 'PingFang SC';
- color: #1C449B;
- }
- .type {
- width: 31.5%;
- background-color: #1c449b;
- padding: calc(var(--fitWidthRatio) * 8px) calc(var(--fitWidthRatio) * 16px);
- border-radius: calc(var(--fitWidthRatio) * 16px);
- color: #FFFFFF;
- font-size: calc(var(--fitWidthRatio) * 16px);
- font-weight: 600;
- font-family: 'PingFang SC';
- }
- }
- }
- .login-right {
- display: flex;
- flex-direction: column;
- align-items: center;
- height: 100%;
- width: 40%;
- position: absolute;
- right: 0;
- background-color: rgba(255, 255, 255, 0.6);
- border-radius: calc(var(--fitWidthRatio) * 20px) 0 0 calc(var(--fitWidthRatio) * 20px);
- backdrop-filter: blur(10px);
- .login-right-box {
- display: flex;
- flex-direction: column;
- gap: calc(var(--fitWidthRatio) * 20px);
- position: absolute;
- top: 12%;
- .login-right-title {
- font-size: calc(var(--fitWidthRatio) * 24px);
- font-weight: 600;
- width: 100%;
- color: rgba(0, 0, 0, 1);
- font-family: 'PingFang SC';
- .welcome {
- font-size: calc(var(--fitWidthRatio) * 32px);
- }
- }
- .login-right-form {
- width: 30vw;
- height: 65vh;
- min-height: 386px;
- background-color: #ffffff;
- box-shadow: 0px calc(var(--fitWidthRatio) * 6px) calc(var(--fitWidthRatio) * 4px) 0px rgba(149, 149, 149, 0.25);
- border-radius: calc(var(--fitWidthRatio) * 8px);
- display: flex;
- flex-direction: column;
- align-items: center;
- .tabs {
- height: 90%;
- width: 100%;
- padding: calc(var(--fitWidthRatio) * 32px) calc(var(--fitWidthRatio) * 32px) 0 calc(var(--fitWidthRatio) * 32px);
- :deep(.ant-tabs-nav) {
- margin: 0;
- padding: 0 calc(var(--fitWidthRatio) * 24px);
- }
- :deep(.ant-tabs-tab) {
- padding: calc(var(--fitWidthRatio) * 4px) 0;
- }
- :deep(.ant-tabs-tab-active .ant-tabs-tab-btn) {
- color: #000;
- }
- :deep(.ant-tabs-nav-list :not(.ant-tabs-tab-active) .ant-tabs-tab-btn) {
- color: #9B9B9B;
- }
- :deep(.ant-tabs-nav::before) {
- border: none;
- }
- :deep(.ant-tabs-tab-btn) {
- font-size: calc(var(--fitWidthRatio) * 24px);
- }
- :deep(.ant-tabs-content) {
- height: 100%;
- }
- .margin-top {
- margin-top: calc(var(--fitWidthRatio) * 50px);
- }
- .flex-center {
- margin: 0;
- display: flex;
- justify-content: center;
- align-items: center;
- height: 100%;
- width: 100%;
- }
- .qrcode-login {
- .img {
- width: calc(var(--fitWidthRatio) * 355px);
- height: calc(var(--fitWidthRatio) * 370px);
- position: absolute;
- z-index: 1;
- right: 0;
- }
- .code {
- left: 0;
- top: calc(var(--fitWidthRatio) * 16px);
- }
- .absolute-right {
- position: absolute;
- }
- }
- .login-form {
- width: 100%;
- height: 100%;
- display: flex;
- justify-content: center;
- align-items: center;
- padding: 0 calc(var(--fitWidthRatio) * 32px) 0 calc(var(--fitWidthRatio) * 16px);
- .label {
- font-size: calc(var(--fitWidthRatio) * 16px);
- font-family: 'PingFang SC';
- font-weight: 500;
- margin-top: calc(var(--fitWidthRatio) * 16px);
- margin-bottom: calc(var(--fitWidthRatio) * 8px);
- }
- .input {
- height: calc(var(--fitWidthRatio) * 44px);
- width: 100%;
- font-size: calc(var(--fitWidthRatio) * 16px);
- border: 1px solid rgba(238, 238, 238, 1);
- box-shadow: 0px calc(var(--fitWidthRatio) * 4px) calc(var(--fitWidthRatio) * 4px) 0px rgba(214, 214, 214, 0.25);
- }
- .form-item {
- margin: 0;
- .form-btn {
- width: 100%;
- height: calc(var(--fitWidthRatio) * 50px);
- margin-top: calc(var(--fitWidthRatio) * 24px);
- display: flex;
- justify-content: center;
- .btn {
- height: 100%;
- width:calc(var(--fitWidthRatio) * 410px) ;
- font-size: calc(var(--fitWidthRatio) * 16px);
- }
- }
- .img {
- width: calc(var(--fitWidthRatio) * 124px);
- height: calc(var(--fitWidthRatio) * 34px);
- border-radius: calc(var(--fitWidthRatio) * 8px);
- }
- }
- :deep(.ant-form) {
- width: 100%;
- height: 100%;
- display: flex;
- flex-direction: column;
- justify-content: center;
- }
- :deep(.ant-form-item) {
- margin-left: calc(var(--fitWidthRatio) * 20px);
- }
- }
- }
- .login-right-bottom {
- width: 100%;
- height: 10%;
- text-align: center;
- font-size: calc(var(--fitWidthRatio) * 16px);
- padding: calc(var(--fitWidthRatio) * 16px);
- border-top: 1px dotted #DEDEDE;
- color: #EF2F22;
- }
- }
- }
- }
- }
- }
- </style>
|