|
@@ -0,0 +1,263 @@
|
|
|
+<template>
|
|
|
+ <div class="container">
|
|
|
+ <div class="logo"></div>
|
|
|
+ <!-- 登录区域 -->
|
|
|
+ <div class="content">
|
|
|
+ <!-- 配图 -->
|
|
|
+ <div class="pic"></div>
|
|
|
+ <!-- 表单 -->
|
|
|
+ <div class="field">
|
|
|
+ <!-- [移动端]标题 -->
|
|
|
+ <h2 class="mobile-title">
|
|
|
+ <h3 class="title">浙江万维后台管理系统</h3>
|
|
|
+ </h2>
|
|
|
+
|
|
|
+ <!-- 表单 -->
|
|
|
+ <div class="form-cont">
|
|
|
+ <el-tabs class="form" v-model="loginData.isSocialLogin" style="float: none">
|
|
|
+ <el-tab-pane label="绑定账号" name="uname" />
|
|
|
+ </el-tabs>
|
|
|
+ <div>
|
|
|
+ <el-form
|
|
|
+ ref="formLogin"
|
|
|
+ :model="loginData.loginForm"
|
|
|
+ :rules="loginRules"
|
|
|
+ class="login-form"
|
|
|
+ >
|
|
|
+ <!-- 账号密码登录 -->
|
|
|
+ <el-form-item prop="username">
|
|
|
+ <el-input
|
|
|
+ v-model="loginData.loginForm.username"
|
|
|
+ :placeholder="t('login.usernamePlaceholder')"
|
|
|
+ :prefix-icon="iconAvatar"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item prop="password">
|
|
|
+ <el-input
|
|
|
+ v-model="loginData.loginForm.password"
|
|
|
+ :placeholder="t('login.passwordPlaceholder')"
|
|
|
+ :prefix-icon="iconLock"
|
|
|
+ show-password
|
|
|
+ type="password"
|
|
|
+ @keyup.enter="getCode()"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <!-- 下方的登录按钮 -->
|
|
|
+ <el-col :span="24" style="padding-right: 10px; padding-left: 10px">
|
|
|
+ <el-form-item>
|
|
|
+ <XButton
|
|
|
+ :loading="loginLoading"
|
|
|
+ :title="t('login.login')"
|
|
|
+ class="w-[100%]"
|
|
|
+ type="primary"
|
|
|
+ @click="getCode()"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <Verify
|
|
|
+ ref="verify"
|
|
|
+ :captchaType="captchaType"
|
|
|
+ :imgSize="{ width: '400px', height: '200px' }"
|
|
|
+ mode="pop"
|
|
|
+ @success="handleLogin"
|
|
|
+ />
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script lang="ts" setup>
|
|
|
+import { ElLoading } from 'element-plus'
|
|
|
+import type { RouteLocationNormalizedLoaded } from 'vue-router'
|
|
|
+import { useRoute } from 'vue-router'
|
|
|
+
|
|
|
+import { useIcon } from '@/hooks/web/useIcon'
|
|
|
+
|
|
|
+import * as authUtil from '@/utils/auth'
|
|
|
+import { usePermissionStore } from '@/store/modules/permission'
|
|
|
+import * as LoginApi from '@/api/login'
|
|
|
+import { LoginStateEnum, useFormValid, useLoginState } from './components/useLogin'
|
|
|
+
|
|
|
+defineOptions({ name: 'SocialLogin' })
|
|
|
+
|
|
|
+const { t } = useI18n()
|
|
|
+const message = useMessage()
|
|
|
+const iconHouse = useIcon({ icon: 'ep:house' })
|
|
|
+const iconAvatar = useIcon({ icon: 'ep:avatar' })
|
|
|
+const iconLock = useIcon({ icon: 'ep:lock' })
|
|
|
+const formLogin = ref()
|
|
|
+const { validForm } = useFormValid(formLogin)
|
|
|
+const { setLoginState, getLoginState } = useLoginState()
|
|
|
+const { currentRoute, push } = useRouter()
|
|
|
+const permissionStore = usePermissionStore()
|
|
|
+const redirect = ref<string>('')
|
|
|
+const type = ref<number>('')
|
|
|
+const code = ref<string>('')
|
|
|
+const state = ref<string>('')
|
|
|
+const loginLoading = ref(false)
|
|
|
+const verify = ref()
|
|
|
+const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字
|
|
|
+
|
|
|
+const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN)
|
|
|
+
|
|
|
+const LoginRules = {
|
|
|
+ username: [required],
|
|
|
+ password: [required]
|
|
|
+}
|
|
|
+const loginData = reactive({
|
|
|
+ isShowPassword: false,
|
|
|
+ isSocialLogin: true,
|
|
|
+ captchaEnable: import.meta.env.VITE_APP_CAPTCHA_ENABLE,
|
|
|
+ tenantEnable: import.meta.env.VITE_APP_TENANT_ENABLE,
|
|
|
+ loginForm: {
|
|
|
+ tenantName: '',
|
|
|
+ username: '',
|
|
|
+ password: '',
|
|
|
+ captchaVerification: ''
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+// 获取验证码
|
|
|
+const getCode = async () => {
|
|
|
+ // 情况一,未开启:则直接登录
|
|
|
+ if (loginData.captchaEnable === 'false') {
|
|
|
+ await handleLogin({})
|
|
|
+ } else {
|
|
|
+ // 情况二,已开启:则展示验证码;只有完成验证码的情况,才进行登录
|
|
|
+ // 弹出验证码
|
|
|
+ verify.value.show()
|
|
|
+ }
|
|
|
+}
|
|
|
+// 记住我
|
|
|
+const getCookie = () => {
|
|
|
+ const loginForm = authUtil.getLoginForm()
|
|
|
+ if (loginForm) {
|
|
|
+ loginData.loginForm = {
|
|
|
+ ...loginData.loginForm,
|
|
|
+ username: loginForm.username ? loginForm.username : loginData.loginForm.username,
|
|
|
+ password: loginForm.password ? loginForm.password : loginData.loginForm.password,
|
|
|
+ rememberMe: loginForm.rememberMe ? true : false,
|
|
|
+ socialCode: code.value,
|
|
|
+ socialState: state.value,
|
|
|
+ socialType: type.value,
|
|
|
+ tenantName: loginForm.tenantName ? loginForm.tenantName : loginData.loginForm.tenantName
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+//获取租户ID
|
|
|
+const getTenantId = async () => {
|
|
|
+ if (loginData.tenantEnable === 'true') {
|
|
|
+ const res = await LoginApi.getTenantIdByName(loginData.loginForm.tenantName)
|
|
|
+ authUtil.setTenantId(res)
|
|
|
+ }
|
|
|
+}
|
|
|
+const loading = ref() // ElLoading.service 返回的实例
|
|
|
+// 登录
|
|
|
+const handleLogin = async (params) => {
|
|
|
+ loginLoading.value = true
|
|
|
+ try {
|
|
|
+ debugger
|
|
|
+ await getTenantId()
|
|
|
+ const data = await validForm()
|
|
|
+ if (!data) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ loginData.loginForm.captchaVerification = params.captchaVerification
|
|
|
+ const res = await LoginApi.login(loginData.loginForm)
|
|
|
+ debugger
|
|
|
+ if (!res) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ loading.value = ElLoading.service({
|
|
|
+ lock: true,
|
|
|
+ text: '正在加载系统中...',
|
|
|
+ background: 'rgba(0, 0, 0, 0.7)'
|
|
|
+ })
|
|
|
+ if (loginData.loginForm.rememberMe) {
|
|
|
+ authUtil.setLoginForm(loginData.loginForm)
|
|
|
+ } else {
|
|
|
+ authUtil.removeLoginForm()
|
|
|
+ }
|
|
|
+ authUtil.setToken(res)
|
|
|
+ if (!redirect.value) {
|
|
|
+ redirect.value = '/'
|
|
|
+ }
|
|
|
+ // 判断是否为SSO登录
|
|
|
+ if (redirect.value.indexOf('sso') !== -1) {
|
|
|
+ window.location.href = window.location.href.replace('/login?redirect=', '')
|
|
|
+ } else {
|
|
|
+ push({ path: redirect.value || permissionStore.addRouters[0].path })
|
|
|
+ }
|
|
|
+ } finally {
|
|
|
+ debugger
|
|
|
+ loginLoading.value = false
|
|
|
+ loading.value.close()
|
|
|
+ }
|
|
|
+}
|
|
|
+const socialLoading = ref() // ElLoading.service 返回的实例
|
|
|
+// 社交登录
|
|
|
+const socialLogin = async () => {
|
|
|
+ const route = useRoute()
|
|
|
+ // 社交登录相关
|
|
|
+ type.value = route?.query?.type as number
|
|
|
+ code.value = route?.query?.code as string
|
|
|
+ state.value = route?.query?.state as string
|
|
|
+ if (!type.value) {
|
|
|
+ type.value = 20
|
|
|
+ }
|
|
|
+ // 尝试登录一下
|
|
|
+ loginLoading.value = true
|
|
|
+ try {
|
|
|
+ const res = await LoginApi.socialLogin({
|
|
|
+ type: type.value,
|
|
|
+ code: code.value,
|
|
|
+ state: state.value
|
|
|
+ })
|
|
|
+ if (!res) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ socialLoading.value = ElLoading.service({
|
|
|
+ lock: true,
|
|
|
+ text: '正在加载系统中...',
|
|
|
+ background: 'rgba(0, 0, 0, 0.7)'
|
|
|
+ })
|
|
|
+ authUtil.setToken(res)
|
|
|
+ if (!redirect.value) {
|
|
|
+ redirect.value = '/'
|
|
|
+ }
|
|
|
+ // 判断是否为SSO登录
|
|
|
+ if (redirect.value.indexOf('sso') !== -1) {
|
|
|
+ window.location.href = window.location.href.replace('/login?redirect=', '')
|
|
|
+ } else {
|
|
|
+ push({ path: redirect.value || permissionStore.addRouters[0].path })
|
|
|
+ }
|
|
|
+ } finally {
|
|
|
+ loginLoading.value = false
|
|
|
+ socialLoading.value.close()
|
|
|
+ }
|
|
|
+}
|
|
|
+watch(
|
|
|
+ () => currentRoute.value,
|
|
|
+ (route: RouteLocationNormalizedLoaded) => {
|
|
|
+ redirect.value = route?.query?.redirect as string
|
|
|
+ },
|
|
|
+ {
|
|
|
+ immediate: true
|
|
|
+ }
|
|
|
+)
|
|
|
+onMounted(() => {
|
|
|
+ getCookie()
|
|
|
+ socialLogin()
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+:deep(.anticon) {
|
|
|
+ &:hover {
|
|
|
+ color: var(--el-color-primary) !important;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|