|
@@ -1,111 +1,54 @@
|
|
|
<template>
|
|
|
<div class="login-wrapper">
|
|
|
- <div class="login_background">
|
|
|
- <div class="logo_background">
|
|
|
- <a
|
|
|
- :class="{ 'no-link': !sysBaseConfig.SNOWY_SYS_COPYRIGHT_URL }"
|
|
|
- :href="sysBaseConfig.SNOWY_SYS_COPYRIGHT_URL"
|
|
|
- target="_blank"
|
|
|
- @click="handleLink"
|
|
|
- >
|
|
|
- <img :alt="sysBaseConfig.SNOWY_SYS_NAME" :src="sysBaseConfig.SNOWY_SYS_LOGO" />
|
|
|
- <label>{{ sysBaseConfig.SNOWY_SYS_NAME }}</label>
|
|
|
- </a>
|
|
|
- </div>
|
|
|
- <div class="version">
|
|
|
- <p>{{ sysBaseConfig.SNOWY_SYS_DEFAULT_DESCRRIPTION }}</p>
|
|
|
- <p>{{ sysBaseConfig.SNOWY_SYS_COPYRIGHT }} {{ sysBaseConfig.SNOWY_SYS_VERSION }}</p>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="login_main">
|
|
|
- <div class="login_config">
|
|
|
- <a-dropdown>
|
|
|
- <global-outlined />
|
|
|
- <template #overlay>
|
|
|
- <a-menu>
|
|
|
- <a-menu-item
|
|
|
- v-for="item in lang"
|
|
|
- :key="item.value"
|
|
|
- :command="item"
|
|
|
- :class="{ selected: config.lang === item.value }"
|
|
|
- @click="configLang(item.value)"
|
|
|
- >
|
|
|
- {{ item.name }}
|
|
|
- </a-menu-item>
|
|
|
- </a-menu>
|
|
|
- </template>
|
|
|
- </a-dropdown>
|
|
|
- </div>
|
|
|
- <div class="login-form">
|
|
|
- <a-card>
|
|
|
- <div class="login-header">
|
|
|
- <h2>{{ $t('login.signInTitle') }}</h2>
|
|
|
- </div>
|
|
|
- <a-tabs v-model:activeKey="activeKey">
|
|
|
- <a-tab-pane key="userAccount" :tab="$t('login.accountPassword')">
|
|
|
- <a-form ref="loginForm" :model="ruleForm" :rules="rules">
|
|
|
- <a-form-item name="account">
|
|
|
- <a-input
|
|
|
- v-model:value="ruleForm.account"
|
|
|
- :placeholder="$t('login.accountPlaceholder')"
|
|
|
- size="large"
|
|
|
- @keyup.enter="login"
|
|
|
- >
|
|
|
- <template #prefix>
|
|
|
- <UserOutlined class="login-icon-gray" />
|
|
|
- </template>
|
|
|
- </a-input>
|
|
|
- </a-form-item>
|
|
|
- <a-form-item name="password">
|
|
|
- <a-input-password
|
|
|
- v-model:value="ruleForm.password"
|
|
|
- :placeholder="$t('login.PWPlaceholder')"
|
|
|
- size="large"
|
|
|
- autocomplete="off"
|
|
|
- @keyup.enter="login"
|
|
|
- >
|
|
|
- <template #prefix>
|
|
|
- <LockOutlined class="login-icon-gray" />
|
|
|
- </template>
|
|
|
- </a-input-password>
|
|
|
- </a-form-item>
|
|
|
- <a-form-item name="validCode" v-if="captchaOpen === 'true'">
|
|
|
- <a-row :gutter="8">
|
|
|
- <a-col :span="17">
|
|
|
- <a-input
|
|
|
- v-model:value="ruleForm.validCode"
|
|
|
- :placeholder="$t('login.validLaceholder')"
|
|
|
- size="large"
|
|
|
- @keyup.enter="login"
|
|
|
- >
|
|
|
- <template #prefix>
|
|
|
- <verified-outlined class="login-icon-gray" />
|
|
|
- </template>
|
|
|
- </a-input>
|
|
|
- </a-col>
|
|
|
- <a-col :span="7">
|
|
|
- <img :src="validCodeBase64" class="login-validCode-img" @click="loginCaptcha" />
|
|
|
- </a-col>
|
|
|
- </a-row>
|
|
|
- </a-form-item>
|
|
|
+ <div class="login-title">{{ sysBaseConfig.SNOWY_SYS_NAME }}</div>
|
|
|
+ <div class="login_form">
|
|
|
+ <div class="form_head">登 录</div>
|
|
|
+ <div class="form_body">
|
|
|
+ <a-form ref="loginForm" :model="ruleForm" :rules="rules">
|
|
|
+ <!-- 用户名 -->
|
|
|
+ <a-form-item name="account">
|
|
|
+ <a-input v-model:value="ruleForm.account" placeholder="用户名" size="large" @keyup.enter="login"> </a-input>
|
|
|
+ </a-form-item>
|
|
|
|
|
|
- <a-form-item>
|
|
|
- <a href="/findpwd" class="xn-color-0d84ff">{{ $t('login.forgetPassword') }}?</a>
|
|
|
- </a-form-item>
|
|
|
- <a-form-item>
|
|
|
- <a-button type="primary" class="w-full" :loading="loading" round size="large" @click="login"
|
|
|
- >{{ $t('login.signIn') }}
|
|
|
- </a-button>
|
|
|
- </a-form-item>
|
|
|
- </a-form>
|
|
|
- </a-tab-pane>
|
|
|
- <a-tab-pane key="userSms" :tab="$t('login.phoneSms')" force-render>
|
|
|
- <phone-login-form />
|
|
|
- </a-tab-pane>
|
|
|
- </a-tabs>
|
|
|
- <three-login />
|
|
|
- </a-card>
|
|
|
+ <!-- 密码 -->
|
|
|
+ <a-form-item name="password">
|
|
|
+ <a-input-password
|
|
|
+ v-model:value="ruleForm.password"
|
|
|
+ placeholder="密码"
|
|
|
+ size="large"
|
|
|
+ autocomplete="off"
|
|
|
+ @keyup.enter="login"
|
|
|
+ >
|
|
|
+ </a-input-password>
|
|
|
+ </a-form-item>
|
|
|
+
|
|
|
+ <!-- 验证码 -->
|
|
|
+ <a-form-item name="validCode" v-if="captchaOpen === 'true'">
|
|
|
+ <a-row :gutter="8">
|
|
|
+ <a-col :span="17">
|
|
|
+ <a-input v-model:value="ruleForm.validCode" placeholder="验证码" size="large" @keyup.enter="login">
|
|
|
+ </a-input>
|
|
|
+ </a-col>
|
|
|
+ <a-col :span="7">
|
|
|
+ <img :src="validCodeBase64" class="login-validCode-img" @click="loginCaptcha" />
|
|
|
+ </a-col>
|
|
|
+ </a-row>
|
|
|
+ </a-form-item>
|
|
|
+
|
|
|
+ <!-- 记住登录状态 -->
|
|
|
+ <a-form-item>
|
|
|
+ <a-checkbox v-model:checked="ruleForm.autologin">记住登录状态</a-checkbox>
|
|
|
+ </a-form-item>
|
|
|
+
|
|
|
+ <!-- 登录按钮 -->
|
|
|
+ <a-form-item>
|
|
|
+ <a-button type="primary" class="w-full" :loading="loading" round size="large" @click="login"
|
|
|
+ >{{ $t('login.signIn') }}
|
|
|
+ </a-button>
|
|
|
+ </a-form-item>
|
|
|
+ </a-form>
|
|
|
</div>
|
|
|
+ <div class="form_foot">没有账号?点击<router-link to="/findpwd" class="nav-link">注册</router-link></div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</template>
|
|
@@ -114,16 +57,19 @@
|
|
|
const PhoneLoginForm = defineAsyncComponent(() => import('./phoneLoginForm.vue'))
|
|
|
import ThreeLogin from './threeLogin.vue'
|
|
|
import smCrypto from '@/utils/smCrypto'
|
|
|
+
|
|
|
import { required } from '@/utils/formRules'
|
|
|
import { afterLogin } from './util'
|
|
|
import configData from '@/config'
|
|
|
import configApi from '@/api/dev/configApi'
|
|
|
import tool from '@/utils/tool'
|
|
|
import { globalStore, iframeStore, keepAliveStore, viewTagsStore } from '@/store'
|
|
|
+
|
|
|
const { proxy } = getCurrentInstance()
|
|
|
|
|
|
const activeKey = ref('userAccount')
|
|
|
const captchaOpen = ref(configData.SYS_BASE_CONFIG.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN)
|
|
|
+
|
|
|
const validCodeBase64 = ref('')
|
|
|
const loading = ref(false)
|
|
|
|
|
@@ -136,7 +82,7 @@
|
|
|
})
|
|
|
|
|
|
const rules = reactive({
|
|
|
- account: [required(proxy.$t('login.accountError'), 'blur')],
|
|
|
+ account: [required('请输入用户名', 'blur')],
|
|
|
password: [required(proxy.$t('login.PWError'), 'blur')]
|
|
|
})
|
|
|
const lang = ref([
|
|
@@ -170,6 +116,8 @@
|
|
|
|
|
|
onMounted(() => {
|
|
|
let formData = ref(configData.SYS_BASE_CONFIG)
|
|
|
+ getAutologin() //记住登录状态
|
|
|
+
|
|
|
configApi
|
|
|
.configSysBaseList()
|
|
|
.then((data) => {
|
|
@@ -177,6 +125,7 @@
|
|
|
data.forEach((item) => {
|
|
|
formData.value[item.configKey] = item.configValue
|
|
|
})
|
|
|
+
|
|
|
captchaOpen.value = formData.value.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN
|
|
|
tool.data.set('SNOWY_SYS_BASE_CONFIG', formData.value)
|
|
|
setSysBaseConfig(formData.value)
|
|
@@ -207,6 +156,17 @@
|
|
|
document.body.setAttribute('data-theme', newValue)
|
|
|
}
|
|
|
)
|
|
|
+
|
|
|
+ //记住状态
|
|
|
+ const getAutologin = () => {
|
|
|
+ let account = tool.data.get('account')
|
|
|
+ let password = tool.data.get('password')
|
|
|
+ let autologin = tool.data.get('autologin')
|
|
|
+
|
|
|
+ ruleForm.account = account === undefined ? ruleForm.account : account
|
|
|
+ ruleForm.password = password === undefined ? ruleForm.password : password
|
|
|
+ ruleForm.autologin = autologin === undefined ? ruleForm.account : autologin
|
|
|
+ }
|
|
|
// 通过开关加载内容
|
|
|
const refreshSwitch = () => {
|
|
|
// 判断是否开启验证码
|
|
@@ -231,6 +191,7 @@
|
|
|
.validate()
|
|
|
.then(async () => {
|
|
|
loading.value = true
|
|
|
+
|
|
|
const loginData = {
|
|
|
account: ruleForm.account,
|
|
|
// 密码进行SM2加密,传输过程中看到的只有密文,后端存储使用hash
|
|
@@ -238,6 +199,18 @@
|
|
|
validCode: ruleForm.validCode,
|
|
|
validCodeReqNo: ruleForm.validCodeReqNo
|
|
|
}
|
|
|
+
|
|
|
+ //是否记住登录状态
|
|
|
+ if (ruleForm.autologin) {
|
|
|
+ tool.data.set('loginForm', ruleForm.account)
|
|
|
+ tool.data.set('password', ruleForm.password)
|
|
|
+ tool.data.set('autologin', ruleForm.autologin)
|
|
|
+ } else {
|
|
|
+ tool.data.remove('account')
|
|
|
+ tool.data.remove('password')
|
|
|
+ tool.data.remove('autologin')
|
|
|
+ }
|
|
|
+
|
|
|
// 获取token
|
|
|
try {
|
|
|
const loginToken = await loginApi.login(loginData)
|
|
@@ -262,9 +235,62 @@
|
|
|
}
|
|
|
}
|
|
|
</script>
|
|
|
-<style lang="less">
|
|
|
- @import 'login';
|
|
|
- .xn-color-0d84ff {
|
|
|
- color: #0d84ff;
|
|
|
+<style lang="less" scoped>
|
|
|
+ .login-wrapper {
|
|
|
+ width: 100%;
|
|
|
+ min-height: 600px;
|
|
|
+ height: 100vh;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ padding: 5% 0;
|
|
|
+ align-items: center;
|
|
|
+ background-image: url('/src/assets/images/login/logo_background.png');
|
|
|
+ background-size: cover;
|
|
|
+ background-position: center;
|
|
|
+ .login-title {
|
|
|
+ font-size: 28px;
|
|
|
+ font-weight: bold;
|
|
|
+ margin-bottom: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 登录
|
|
|
+ .login_form {
|
|
|
+ width: 400px;
|
|
|
+ padding: 0 0 30px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ border-radius: 5px;
|
|
|
+ background-color: #fbfcfd;
|
|
|
+
|
|
|
+ .form_head {
|
|
|
+ font-size: 20px;
|
|
|
+ font-weight: bold;
|
|
|
+ height: 70px;
|
|
|
+ line-height: 70px;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 表单
|
|
|
+ .form_body {
|
|
|
+ width: 100%;
|
|
|
+ padding: 0 30px;
|
|
|
+
|
|
|
+ .w-full {
|
|
|
+ background-color: #0052cc;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 注册
|
|
|
+ .form_foot {
|
|
|
+ font-size: 14px;
|
|
|
+ .nav-link {
|
|
|
+ text-decoration: none;
|
|
|
+ color: #0052cc;
|
|
|
+ }
|
|
|
+ .nav-link:hover {
|
|
|
+ text-decoration: underline;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
</style>
|