2021-06-07 17:22:07 +08:00
|
|
|
|
<template>
|
2022-07-18 20:36:31 +08:00
|
|
|
|
<div>
|
|
|
|
|
|
<el-form ref="loginFormRef" :model="loginForm" :rules="rules" class="login-content-form" size="large">
|
|
|
|
|
|
<el-form-item prop="username">
|
2022-10-29 20:08:15 +08:00
|
|
|
|
<el-input type="text" placeholder="请输入用户名" prefix-icon="user" v-model="loginForm.username" clearable
|
|
|
|
|
|
autocomplete="off">
|
2022-07-18 20:36:31 +08:00
|
|
|
|
</el-input>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item prop="password">
|
2022-10-29 20:08:15 +08:00
|
|
|
|
<el-input type="password" placeholder="请输入密码" prefix-icon="lock" v-model="loginForm.password"
|
2023-03-15 11:41:03 +08:00
|
|
|
|
autocomplete="off" @keyup.enter="login" show-password>
|
2022-07-18 20:36:31 +08:00
|
|
|
|
</el-input>
|
|
|
|
|
|
</el-form-item>
|
2023-06-17 15:15:03 +08:00
|
|
|
|
<el-form-item v-if="accountLoginSecurity.useCaptcha" prop="captcha">
|
2022-07-18 20:36:31 +08:00
|
|
|
|
<el-row :gutter="15">
|
|
|
|
|
|
<el-col :span="16">
|
2022-10-29 20:08:15 +08:00
|
|
|
|
<el-input type="text" maxlength="6" placeholder="请输入验证码" prefix-icon="position"
|
|
|
|
|
|
v-model="loginForm.captcha" clearable autocomplete="off" @keyup.enter="login"></el-input>
|
2022-07-18 20:36:31 +08:00
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="8">
|
|
|
|
|
|
<div class="login-content-code">
|
2022-10-29 20:08:15 +08:00
|
|
|
|
<img class="login-content-code-img" @click="getCaptcha" width="130px" height="40px"
|
|
|
|
|
|
:src="captchaImage" style="cursor: pointer" />
|
2022-07-18 20:36:31 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
</el-form-item>
|
2023-06-17 15:15:03 +08:00
|
|
|
|
<span v-if="showLoginFailTips" style="color: #f56c6c;font-size: 12px;">
|
|
|
|
|
|
提示:登录失败超过{{ accountLoginSecurity.loginFailCount }}次后将被限制{{ accountLoginSecurity.loginFailMin }}分钟内不可再次登录
|
|
|
|
|
|
</span>
|
2022-07-18 20:36:31 +08:00
|
|
|
|
<el-form-item>
|
|
|
|
|
|
<el-button type="primary" class="login-content-submit" round @click="login" :loading="loading.signIn">
|
|
|
|
|
|
<span>登 录</span>
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-form>
|
|
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
<el-dialog title="修改密码" v-model="changePwdDialog.visible" :close-on-click-modal="false" width="450px"
|
|
|
|
|
|
:destroy-on-close="true">
|
2023-06-17 15:15:03 +08:00
|
|
|
|
<el-form :model="changePwdDialog.form" :rules="changePwdDialog.rules" ref="changePwdFormRef" label-width="65px">
|
2022-07-18 20:36:31 +08:00
|
|
|
|
<el-form-item prop="username" label="用户名" required>
|
|
|
|
|
|
<el-input v-model.trim="changePwdDialog.form.username" disabled></el-input>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item prop="oldPassword" label="旧密码" required>
|
2022-10-29 20:08:15 +08:00
|
|
|
|
<el-input v-model.trim="changePwdDialog.form.oldPassword" autocomplete="new-password"
|
|
|
|
|
|
type="password"></el-input>
|
2022-07-18 20:36:31 +08:00
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item prop="newPassword" label="新密码" required>
|
2022-10-29 20:08:15 +08:00
|
|
|
|
<el-input v-model.trim="changePwdDialog.form.newPassword" placeholder="须为8位以上且包含字⺟⼤⼩写+数字+特殊符号"
|
|
|
|
|
|
type="password" autocomplete="new-password"></el-input>
|
2022-07-18 20:36:31 +08:00
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-form>
|
|
|
|
|
|
|
|
|
|
|
|
<template #footer>
|
|
|
|
|
|
<div class="dialog-footer">
|
|
|
|
|
|
<el-button @click="cancelChangePwd">取 消</el-button>
|
|
|
|
|
|
<el-button @click="changePwd" type="primary" :loading="loading.changePwd">确 定</el-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-dialog>
|
2023-06-17 15:15:03 +08:00
|
|
|
|
|
|
|
|
|
|
<el-dialog title="OTP校验" v-model="otpDialog.visible" @close="loading.signIn = false" :close-on-click-modal="false"
|
2023-06-21 15:18:43 +08:00
|
|
|
|
width="350px" :destroy-on-close="true">
|
2023-07-01 14:34:42 +08:00
|
|
|
|
<el-form ref="otpFormRef" :model="otpDialog.form" :rules="otpDialog.rules" @submit.native.prevent label-width="65px">
|
2023-06-17 15:15:03 +08:00
|
|
|
|
<el-form-item v-if="otpDialog.otpUrl" label="二维码">
|
|
|
|
|
|
<qrcode-vue :value="otpDialog.otpUrl" :size="200" level="H" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
|
|
|
|
|
|
<el-form-item prop="code" label="OTP" required>
|
2023-06-21 15:18:43 +08:00
|
|
|
|
<el-input style="width:220px" ref="otpCodeInputRef" v-model.trim="otpDialog.form.code" clearable @keyup.enter="otpVerify"
|
|
|
|
|
|
placeholder="请输入令牌APP中显示的授权码"></el-input>
|
2023-06-17 15:15:03 +08:00
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-form>
|
|
|
|
|
|
|
|
|
|
|
|
<template #footer>
|
|
|
|
|
|
<div class="dialog-footer">
|
|
|
|
|
|
<el-button @click="otpVerify" type="primary" :loading="loading.otpConfirm">确 定</el-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-dialog>
|
2022-07-18 20:36:31 +08:00
|
|
|
|
</div>
|
2021-06-07 17:22:07 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
<script lang="ts" setup>
|
|
|
|
|
|
import { nextTick, onMounted, ref, toRefs, reactive, computed } from 'vue';
|
2021-06-07 17:22:07 +08:00
|
|
|
|
import { useRoute, useRouter } from 'vue-router';
|
|
|
|
|
|
import { ElMessage } from 'element-plus';
|
2023-04-13 20:11:22 +08:00
|
|
|
|
import { initRouter } from '@/router/index';
|
2023-03-15 11:41:03 +08:00
|
|
|
|
import { setSession, setUserInfo2Session, setUseWatermark2Session } from '@/common/utils/storage';
|
|
|
|
|
|
import { formatAxis } from '@/common/utils/format';
|
2021-06-07 17:22:07 +08:00
|
|
|
|
import openApi from '@/common/openApi';
|
2022-07-18 20:36:31 +08:00
|
|
|
|
import { RsaEncrypt } from '@/common/rsa';
|
2023-06-17 15:15:03 +08:00
|
|
|
|
import { getAccountLoginSecurity, useWartermark } from '@/common/sysconfig';
|
2021-06-07 17:22:07 +08:00
|
|
|
|
import { letterAvatar } from '@/common/utils/string';
|
2023-03-15 11:41:03 +08:00
|
|
|
|
import { useUserInfo } from '@/store/userInfo';
|
2023-06-17 15:15:03 +08:00
|
|
|
|
import QrcodeVue from 'qrcode.vue'
|
2022-07-18 20:36:31 +08:00
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
const rules = {
|
|
|
|
|
|
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
|
|
|
|
|
|
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
|
|
|
|
|
|
captcha: [{ required: true, message: '请输入验证码', trigger: 'blur' }],
|
|
|
|
|
|
}
|
2022-07-18 20:36:31 +08:00
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
const route = useRoute();
|
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
|
const loginFormRef: any = ref(null);
|
|
|
|
|
|
const changePwdFormRef: any = ref(null);
|
2023-06-17 15:15:03 +08:00
|
|
|
|
const otpFormRef: any = ref(null);
|
|
|
|
|
|
const otpCodeInputRef: any = ref(null);
|
2022-10-29 20:08:15 +08:00
|
|
|
|
|
|
|
|
|
|
const state = reactive({
|
2023-06-17 15:15:03 +08:00
|
|
|
|
accountLoginSecurity: {
|
|
|
|
|
|
useCaptcha: true,
|
|
|
|
|
|
useOtp: false,
|
|
|
|
|
|
loginFailCount: 5,
|
|
|
|
|
|
loginFailMin: 10,
|
|
|
|
|
|
},
|
|
|
|
|
|
showLoginFailTips: false,
|
2022-10-29 20:08:15 +08:00
|
|
|
|
captchaImage: '',
|
|
|
|
|
|
loginForm: {
|
|
|
|
|
|
username: '',
|
|
|
|
|
|
password: '',
|
|
|
|
|
|
captcha: '',
|
|
|
|
|
|
cid: '',
|
|
|
|
|
|
},
|
|
|
|
|
|
changePwdDialog: {
|
|
|
|
|
|
visible: false,
|
|
|
|
|
|
form: {
|
|
|
|
|
|
username: '',
|
|
|
|
|
|
oldPassword: '',
|
|
|
|
|
|
newPassword: '',
|
|
|
|
|
|
},
|
|
|
|
|
|
rules: {
|
|
|
|
|
|
newPassword: [
|
|
|
|
|
|
{ required: true, message: '请输入新密码', trigger: 'blur' },
|
|
|
|
|
|
{
|
|
|
|
|
|
pattern: /^(?=.*[A-Za-z])(?=.*\d)(?=.*[`~!@#$%^&*()_+<>?:"{},.\/\\;'[\]])[A-Za-z\d`~!@#$%^&*()_+<>?:"{},.\/\\;'[\]]{8,}$/,
|
|
|
|
|
|
message: '须为8位以上且包含字⺟⼤⼩写+数字+特殊符号',
|
|
|
|
|
|
trigger: 'blur',
|
2022-07-18 20:36:31 +08:00
|
|
|
|
},
|
2022-10-29 20:08:15 +08:00
|
|
|
|
],
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
2023-06-17 15:15:03 +08:00
|
|
|
|
otpDialog: {
|
|
|
|
|
|
visible: false,
|
|
|
|
|
|
otpUrl: "",
|
|
|
|
|
|
form: {
|
|
|
|
|
|
code: '',
|
|
|
|
|
|
otpToken: '',
|
|
|
|
|
|
},
|
|
|
|
|
|
rules: {
|
|
|
|
|
|
code: [
|
|
|
|
|
|
{ required: true, message: '请输入OTP授权码', trigger: 'blur' },
|
|
|
|
|
|
],
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
2022-10-29 20:08:15 +08:00
|
|
|
|
loading: {
|
|
|
|
|
|
signIn: false,
|
|
|
|
|
|
changePwd: false,
|
2023-06-17 15:15:03 +08:00
|
|
|
|
otpConfirm: false,
|
2022-10-29 20:08:15 +08:00
|
|
|
|
},
|
|
|
|
|
|
});
|
2021-06-07 17:22:07 +08:00
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
const {
|
2023-06-17 15:15:03 +08:00
|
|
|
|
accountLoginSecurity,
|
|
|
|
|
|
showLoginFailTips,
|
2022-10-29 20:08:15 +08:00
|
|
|
|
captchaImage,
|
|
|
|
|
|
loginForm,
|
|
|
|
|
|
changePwdDialog,
|
2023-06-17 15:15:03 +08:00
|
|
|
|
otpDialog,
|
2022-10-29 20:08:15 +08:00
|
|
|
|
loading,
|
|
|
|
|
|
} = toRefs(state)
|
2021-07-28 18:03:19 +08:00
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
onMounted(async () => {
|
|
|
|
|
|
nextTick(async () => {
|
2023-06-17 15:15:03 +08:00
|
|
|
|
const res = await getAccountLoginSecurity();
|
|
|
|
|
|
if (res) {
|
|
|
|
|
|
state.accountLoginSecurity = res;
|
|
|
|
|
|
}
|
2022-10-29 20:08:15 +08:00
|
|
|
|
getCaptcha();
|
|
|
|
|
|
});
|
|
|
|
|
|
// 移除公钥, 方便后续重新获取
|
|
|
|
|
|
sessionStorage.removeItem('RsaPublicKey');
|
|
|
|
|
|
});
|
2021-07-28 18:03:19 +08:00
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
const getCaptcha = async () => {
|
2023-06-17 15:15:03 +08:00
|
|
|
|
if (!state.accountLoginSecurity.useCaptcha) {
|
2022-10-29 20:08:15 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2023-04-13 20:11:22 +08:00
|
|
|
|
let res: any = await openApi.captcha.request();
|
2022-10-29 20:08:15 +08:00
|
|
|
|
state.captchaImage = res.base64Captcha;
|
|
|
|
|
|
state.loginForm.cid = res.cid;
|
|
|
|
|
|
};
|
2021-06-07 17:22:07 +08:00
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
// 时间获取
|
|
|
|
|
|
const currentTime = computed(() => {
|
|
|
|
|
|
return formatAxis(new Date());
|
|
|
|
|
|
});
|
2021-07-28 18:03:19 +08:00
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
// 校验登录表单并登录
|
|
|
|
|
|
const login = () => {
|
|
|
|
|
|
loginFormRef.value.validate((valid: boolean) => {
|
|
|
|
|
|
if (valid) {
|
|
|
|
|
|
onSignIn();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
2021-06-07 17:22:07 +08:00
|
|
|
|
|
2023-06-17 15:15:03 +08:00
|
|
|
|
const otpVerify = async () => {
|
|
|
|
|
|
otpFormRef.value.validate(async (valid: boolean) => {
|
|
|
|
|
|
if (!valid) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
|
|
|
state.loading.otpConfirm = true;
|
|
|
|
|
|
const accessToken = await openApi.otpVerify.request(state.otpDialog.form);
|
|
|
|
|
|
await signInSuccess(accessToken);
|
|
|
|
|
|
state.otpDialog.visible = false;
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
state.loading.otpConfirm = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
// 登录
|
|
|
|
|
|
const onSignIn = async () => {
|
|
|
|
|
|
state.loading.signIn = true;
|
|
|
|
|
|
let loginRes;
|
|
|
|
|
|
const originPwd = state.loginForm.password;
|
|
|
|
|
|
try {
|
|
|
|
|
|
const loginReq = { ...state.loginForm };
|
|
|
|
|
|
loginReq.password = await RsaEncrypt(originPwd);
|
2023-04-13 20:11:22 +08:00
|
|
|
|
loginRes = await openApi.login.request(loginReq);
|
2022-10-29 20:08:15 +08:00
|
|
|
|
} catch (e: any) {
|
|
|
|
|
|
state.loading.signIn = false;
|
|
|
|
|
|
state.loginForm.captcha = '';
|
|
|
|
|
|
// 密码强度不足
|
|
|
|
|
|
if (e.code && e.code == 401) {
|
|
|
|
|
|
state.changePwdDialog.form.username = state.loginForm.username;
|
|
|
|
|
|
state.changePwdDialog.form.oldPassword = originPwd;
|
|
|
|
|
|
state.changePwdDialog.form.newPassword = '';
|
|
|
|
|
|
state.changePwdDialog.visible = true;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
getCaptcha();
|
2023-06-17 15:15:03 +08:00
|
|
|
|
state.showLoginFailTips = true;
|
2022-10-29 20:08:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2023-06-17 15:15:03 +08:00
|
|
|
|
state.showLoginFailTips = false;
|
2022-10-29 20:08:15 +08:00
|
|
|
|
// 用户信息
|
|
|
|
|
|
const userInfos = {
|
2022-10-30 22:56:57 +08:00
|
|
|
|
name: loginRes.name,
|
2022-10-29 20:08:15 +08:00
|
|
|
|
username: state.loginForm.username,
|
|
|
|
|
|
// 头像
|
|
|
|
|
|
photo: letterAvatar(state.loginForm.username),
|
|
|
|
|
|
time: new Date().getTime(),
|
2023-06-17 15:15:03 +08:00
|
|
|
|
// permissions: loginRes.permissions,
|
2022-10-29 20:08:15 +08:00
|
|
|
|
lastLoginTime: loginRes.lastLoginTime,
|
|
|
|
|
|
lastLoginIp: loginRes.lastLoginIp,
|
|
|
|
|
|
};
|
2021-06-07 17:22:07 +08:00
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
// 存储用户信息到浏览器缓存
|
|
|
|
|
|
setUserInfo2Session(userInfos);
|
|
|
|
|
|
// 1、请注意执行顺序(存储用户信息到vuex)
|
2023-04-13 20:11:22 +08:00
|
|
|
|
useUserInfo().setUserInfo(userInfos);
|
2023-06-17 15:15:03 +08:00
|
|
|
|
|
|
|
|
|
|
const token = loginRes.token;
|
|
|
|
|
|
// 如果不需要otp校验,则该token即为accessToken,否则为otp校验token
|
|
|
|
|
|
if (loginRes.otp == -1) {
|
|
|
|
|
|
signInSuccess(token);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
state.otpDialog.form.otpToken = token;
|
|
|
|
|
|
state.otpDialog.otpUrl = loginRes.otpUrl
|
|
|
|
|
|
state.otpDialog.visible = true;
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
otpCodeInputRef.value.focus();
|
|
|
|
|
|
}, 400);
|
2022-10-29 20:08:15 +08:00
|
|
|
|
};
|
2021-07-28 18:03:19 +08:00
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
// 登录成功后的跳转
|
2023-06-17 15:15:03 +08:00
|
|
|
|
const signInSuccess = async (accessToken: string = "") => {
|
|
|
|
|
|
// 存储 token 到浏览器缓存
|
|
|
|
|
|
setSession('token', accessToken);
|
|
|
|
|
|
// 初始化路由
|
|
|
|
|
|
await initRouter();
|
2022-10-29 20:08:15 +08:00
|
|
|
|
// 初始化登录成功时间问候语
|
|
|
|
|
|
let currentTimeInfo = currentTime.value;
|
|
|
|
|
|
// 登录成功,跳到转首页
|
|
|
|
|
|
// 添加完动态路由,再进行 router 跳转,否则可能报错 No match found for location with path "/"
|
|
|
|
|
|
// 如果是复制粘贴的路径,非首页/登录页,那么登录成功后重定向到对应的路径中
|
|
|
|
|
|
route.query?.redirect ? router.push(route.query.redirect as string) : router.push('/');
|
|
|
|
|
|
// 登录成功提示
|
|
|
|
|
|
setTimeout(async () => {
|
|
|
|
|
|
// 关闭 loading
|
|
|
|
|
|
state.loading.signIn = true;
|
|
|
|
|
|
ElMessage.success(`${currentTimeInfo},欢迎回来!`);
|
|
|
|
|
|
if (await useWartermark()) {
|
|
|
|
|
|
setUseWatermark2Session(true);
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 300);
|
|
|
|
|
|
};
|
2022-07-18 20:36:31 +08:00
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
const changePwd = () => {
|
|
|
|
|
|
changePwdFormRef.value.validate(async (valid: boolean) => {
|
|
|
|
|
|
if (!valid) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
|
|
|
state.loading.changePwd = true;
|
|
|
|
|
|
const form = state.changePwdDialog.form;
|
|
|
|
|
|
const changePwdReq: any = { ...form };
|
|
|
|
|
|
changePwdReq.oldPassword = await RsaEncrypt(form.oldPassword);
|
|
|
|
|
|
changePwdReq.newPassword = await RsaEncrypt(form.newPassword);
|
2023-04-13 20:11:22 +08:00
|
|
|
|
await openApi.changePwd.request(changePwdReq);
|
2022-10-29 20:08:15 +08:00
|
|
|
|
ElMessage.success('密码修改成功, 新密码已填充至登录密码框');
|
|
|
|
|
|
state.loginForm.password = state.changePwdDialog.form.newPassword;
|
2022-07-18 20:36:31 +08:00
|
|
|
|
state.changePwdDialog.visible = false;
|
|
|
|
|
|
getCaptcha();
|
2022-10-29 20:08:15 +08:00
|
|
|
|
} finally {
|
|
|
|
|
|
state.loading.changePwd = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
2022-07-18 20:36:31 +08:00
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
const cancelChangePwd = () => {
|
|
|
|
|
|
state.changePwdDialog.visible = false;
|
|
|
|
|
|
state.changePwdDialog.form.newPassword = '';
|
|
|
|
|
|
state.changePwdDialog.form.oldPassword = '';
|
|
|
|
|
|
state.changePwdDialog.form.username = '';
|
|
|
|
|
|
getCaptcha();
|
|
|
|
|
|
};
|
2021-06-07 17:22:07 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
|
|
.login-content-form {
|
|
|
|
|
|
margin-top: 20px;
|
2022-10-29 20:08:15 +08:00
|
|
|
|
|
2021-06-07 17:22:07 +08:00
|
|
|
|
.login-content-code {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: space-around;
|
2022-10-29 20:08:15 +08:00
|
|
|
|
|
2021-06-07 17:22:07 +08:00
|
|
|
|
.login-content-code-img {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 40px;
|
|
|
|
|
|
line-height: 40px;
|
|
|
|
|
|
background-color: #ffffff;
|
|
|
|
|
|
border: 1px solid rgb(220, 223, 230);
|
|
|
|
|
|
color: #333;
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
letter-spacing: 5px;
|
|
|
|
|
|
text-indent: 5px;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
transition: all ease 0.2s;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
user-select: none;
|
2022-10-29 20:08:15 +08:00
|
|
|
|
|
2021-06-07 17:22:07 +08:00
|
|
|
|
&:hover {
|
|
|
|
|
|
border-color: #c0c4cc;
|
|
|
|
|
|
transition: all ease 0.2s;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-10-29 20:08:15 +08:00
|
|
|
|
|
2021-06-07 17:22:07 +08:00
|
|
|
|
.login-content-submit {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
letter-spacing: 2px;
|
|
|
|
|
|
font-weight: 300;
|
|
|
|
|
|
margin-top: 15px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|