mirror of https://gitee.com/xiaonuobase/snowy
291 lines
8.7 KiB
Vue
291 lines
8.7 KiB
Vue
<template>
|
||
<div class="login-wrapper">
|
||
<div class="login_main">
|
||
<div class="login-form">
|
||
<a-card>
|
||
<div class="login-header">
|
||
<h2>登录</h2>
|
||
</div>
|
||
<a-tabs v-model:activeKey="activeKey">
|
||
<a-tab-pane key="userAccount" tab="账号密码">
|
||
<a-form ref="loginForm" :model="ruleForm" :rules="rules">
|
||
<div v-if="tenSelectShow">
|
||
<a-form-item name="tenCode" v-if="tenOptions.length > 1 || !ruleForm.tenCode">
|
||
<a-select
|
||
v-model:value="ruleForm.tenCode"
|
||
size="large"
|
||
placeholder="请选择租户"
|
||
:options="tenOptions"
|
||
@change="tenCodeChange"
|
||
/>
|
||
</a-form-item>
|
||
</div>
|
||
<a-form-item name="account">
|
||
<a-input v-model:value="ruleForm.account" placeholder="请输入账号" 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="请输入密码"
|
||
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="请输入验证码"
|
||
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>
|
||
|
||
<a-form-item>
|
||
<div style="display: flex; justify-content: space-between">
|
||
<a href="/front/client/findPwd" class="xn-color-0d84ff">忘记密码?</a>
|
||
<a href="/front/client/register" class="xn-color-0d84ff" v-if="registerOpen === 'true'">
|
||
没有账号?前往注册
|
||
</a>
|
||
</div>
|
||
</a-form-item>
|
||
<a-form-item>
|
||
<a-button
|
||
type="primary"
|
||
class="w-full"
|
||
:loading="loading"
|
||
round
|
||
size="large"
|
||
@click="login"
|
||
:disabled="loginButtonDisable"
|
||
>
|
||
登录
|
||
</a-button>
|
||
</a-form-item>
|
||
</a-form>
|
||
</a-tab-pane>
|
||
<a-tab-pane key="userSms" tab="手机号登录" force-render v-if="phoneLogin === 'true'">
|
||
<phone-login-form />
|
||
</a-tab-pane>
|
||
<a-tab-pane key="userEmail" tab="邮箱号登录" force-render v-if="emailLogin === 'true'">
|
||
<email-login-form />
|
||
</a-tab-pane>
|
||
</a-tabs>
|
||
<div v-if="configData.FRONT_BACK_LOGIN_URL_SHOW">
|
||
<a href="/login" class="xn-color-0d84ff">后台登录</a>
|
||
</div>
|
||
</a-card>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
<script setup>
|
||
import clientLoginApi from '@/api/auth/client/clientLoginApi'
|
||
import loginTenApi from '@/api/auth/loginTenApi'
|
||
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 } from '@/store'
|
||
import { useRoute } from 'vue-router'
|
||
import { isEmpty } from 'lodash-es'
|
||
const PhoneLoginForm = defineAsyncComponent(() => import('./phoneLoginForm.vue'))
|
||
const EmailLoginForm = defineAsyncComponent(() => import('./emailLoginForm.vue'))
|
||
const route = useRoute()
|
||
const activeKey = ref('userAccount')
|
||
const captchaOpen = ref(configData.SYS_BASE_CONFIG.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN_FLAG_FOR_C)
|
||
const registerOpen = ref('false')
|
||
const phoneLogin = ref('false')
|
||
const emailLogin = ref('false')
|
||
const validCodeBase64 = ref('')
|
||
const loading = ref(false)
|
||
const tenSelectShow = ref(false)
|
||
const tenOptions = ref([])
|
||
const loginButtonDisable = ref(false)
|
||
|
||
const ruleForm = reactive({
|
||
validCode: '',
|
||
validCodeReqNo: '',
|
||
autologin: false,
|
||
tenCode: ''
|
||
})
|
||
// 如果是开发环境,填充用户名密码
|
||
if (process.env.NODE_ENV === 'development') {
|
||
ruleForm.account = ''
|
||
ruleForm.password = ''
|
||
}
|
||
|
||
const rules = reactive({
|
||
account: [required('请输入账号', 'blur')],
|
||
password: [required('请输入密码', 'blur')],
|
||
tenCode: [required('请选择租户', 'blur')]
|
||
})
|
||
const config = ref({
|
||
theme: tool.data.get('APP_THEME') || 'default'
|
||
})
|
||
|
||
const store = globalStore()
|
||
|
||
const setSysBaseConfig = store.setSysBaseConfig
|
||
|
||
const sysBaseConfig = computed(() => {
|
||
return store.sysBaseConfig
|
||
})
|
||
|
||
onMounted(() => {
|
||
// 获得租户code编码
|
||
if (!isEmpty(route.query.tenCode)) {
|
||
ruleForm.tenCode = route.query.tenCode
|
||
}
|
||
loginButtonDisable.value = true
|
||
tool.data.set('SNOWY_TEN_CODE', '')
|
||
// 获得租户列表
|
||
loginTenApi
|
||
.getTenSelector()
|
||
.then((data) => {
|
||
if (isEmpty(data)) {
|
||
tool.data.remove('SNOWY_TEN_CODE')
|
||
} else {
|
||
tenOptions.value = data.map((m) => {
|
||
return {
|
||
label: m.name,
|
||
value: m.code
|
||
}
|
||
})
|
||
// 如果为空,默认选中里面的第一个,如果有那么就按指定的走
|
||
if (isEmpty(ruleForm.tenCode)) {
|
||
ruleForm.tenCode = tenOptions.value[0].value
|
||
tool.data.set('SNOWY_TEN_CODE', ruleForm.tenCode)
|
||
tenSelectShow.value = true
|
||
} else {
|
||
// 我们来验证这个code是否是有效的
|
||
const tenObj = tenOptions.value.find((f) => f.value === ruleForm.tenCode)
|
||
// 如果界面上整了个假的code
|
||
if (isEmpty(tenObj)) {
|
||
// 将其清理掉就行
|
||
ruleForm.tenCode = tenOptions.value[0].value
|
||
tool.data.set('SNOWY_TEN_CODE', ruleForm.tenCode)
|
||
tenSelectShow.value = true
|
||
} else {
|
||
// 如果验证成功是有的,就加进去
|
||
tool.data.set('SNOWY_TEN_CODE', ruleForm.tenCode)
|
||
}
|
||
}
|
||
}
|
||
// 再去查配置
|
||
getSysConfig()
|
||
})
|
||
.catch(() => {
|
||
// 报错就清理掉
|
||
tool.data.set('SNOWY_TEN_CODE', '')
|
||
})
|
||
})
|
||
// 查询这个租户的配置,租户code已经被放domain里了
|
||
const getSysConfig = () => {
|
||
let formData = ref(configData.SYS_BASE_CONFIG)
|
||
configApi
|
||
.configSysBaseList()
|
||
.then((data) => {
|
||
loginButtonDisable.value = false
|
||
if (data) {
|
||
data.forEach((item) => {
|
||
formData.value[item.configKey] = item.configValue
|
||
})
|
||
captchaOpen.value = formData.value.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN_FLAG_FOR_C
|
||
registerOpen.value = formData.value.SNOWY_SYS_DEFAULT_ALLOW_REGISTER_FLAG_FOR_C
|
||
phoneLogin.value = formData.value.SNOWY_SYS_DEFAULT_ALLOW_PHONE_LOGIN_FLAG_FOR_C
|
||
emailLogin.value = formData.value.SNOWY_SYS_DEFAULT_ALLOW_EMAIL_LOGIN_FLAG_FOR_C
|
||
tool.data.set('SNOWY_SYS_BASE_CONFIG', formData.value)
|
||
setSysBaseConfig(formData.value)
|
||
refreshSwitch()
|
||
}
|
||
})
|
||
.catch(() => {})
|
||
}
|
||
// 主题
|
||
watch(
|
||
() => config.value.theme,
|
||
(newValue) => {
|
||
document.body.setAttribute('data-theme', newValue)
|
||
}
|
||
)
|
||
// 通过开关加载内容
|
||
const refreshSwitch = () => {
|
||
// 判断是否开启验证码
|
||
if (captchaOpen.value === 'true') {
|
||
// 加载验证码
|
||
loginCaptcha()
|
||
// 加入校验
|
||
rules.validCode = [required('请输入验证码', 'blur')]
|
||
}
|
||
}
|
||
// 获取验证码
|
||
const loginCaptcha = () => {
|
||
clientLoginApi.clientGetPicCaptcha().then((data) => {
|
||
validCodeBase64.value = data.validCodeBase64
|
||
ruleForm.validCodeReqNo = data.validCodeReqNo
|
||
// 如果有输入的将其清空
|
||
ruleForm.validCode = undefined
|
||
})
|
||
}
|
||
//登陆
|
||
const loginForm = ref()
|
||
const login = async () => {
|
||
loginForm.value
|
||
.validate()
|
||
.then(async () => {
|
||
loading.value = true
|
||
const loginData = {
|
||
account: ruleForm.account,
|
||
// 密码进行SM2加密,传输过程中看到的只有密文,后端存储使用hash
|
||
password: smCrypto.doSm2Encrypt(ruleForm.password),
|
||
validCode: ruleForm.validCode,
|
||
validCodeReqNo: ruleForm.validCodeReqNo
|
||
}
|
||
// 获取token
|
||
try {
|
||
const loginToken = await clientLoginApi.clientLogin(loginData)
|
||
await afterLogin(loginToken)
|
||
} catch (err) {
|
||
if (captchaOpen.value === 'true') {
|
||
loginCaptcha()
|
||
}
|
||
}
|
||
})
|
||
.finally(() => {
|
||
loading.value = false
|
||
})
|
||
}
|
||
// 租户选择事件
|
||
const tenCodeChange = (code) => {
|
||
// 设置新的
|
||
tool.data.set('SNOWY_TEN_CODE', code)
|
||
ruleForm.tenCode = code
|
||
getSysConfig()
|
||
}
|
||
</script>
|
||
<style lang="less" scoped>
|
||
@import 'login';
|
||
</style>
|