Files
dafuweng-saiadmin6.x/saiadmin-artd/src/views/auth/login/index.vue
2026-03-03 18:55:03 +08:00

227 lines
6.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- 登录页面 -->
<template>
<div class="flex w-full h-screen">
<LoginLeftView />
<div class="relative flex-1">
<AuthTopBar />
<div class="auth-right-wrap">
<div class="form">
<h3 class="title">{{ $t('login.title') }}</h3>
<p class="sub-title">{{ $t('login.subTitle') }}</p>
<ElForm
ref="formRef"
:model="formData"
:rules="rules"
:key="formKey"
@keyup.enter="handleSubmit"
style="margin-top: 25px"
>
<ElFormItem prop="username">
<ElInput
class="custom-height"
:placeholder="$t('login.placeholder.username')"
v-model.trim="formData.username"
/>
</ElFormItem>
<ElFormItem prop="password">
<ElInput
class="custom-height"
:placeholder="$t('login.placeholder.password')"
v-model.trim="formData.password"
type="password"
autocomplete="off"
show-password
/>
</ElFormItem>
<ElFormItem v-if="captchaEnabled" prop="code">
<ElInput
class="custom-height"
:placeholder="$t('login.placeholder.code')"
v-model.trim="formData.code"
type="text"
autocomplete="off"
>
<template #append>
<img
:src="captcha"
style="height: 36px; cursor: pointer"
@click="refreshCaptcha"
/>
</template>
</ElInput>
</ElFormItem>
<div class="flex-cb mt-2 text-sm">
<ElCheckbox v-model="formData.rememberPassword">{{
$t('login.rememberPwd')
}}</ElCheckbox>
<!-- <RouterLink class="text-theme" :to="{ name: 'ForgetPassword' }">{{
$t('login.forgetPwd')
}}</RouterLink> -->
</div>
<div style="margin-top: 30px">
<ElButton
class="w-full custom-height"
type="primary"
@click="handleSubmit"
:loading="loading"
v-ripple
>
{{ $t('login.btnText') }}
</ElButton>
</div>
<!-- <div class="mt-5 text-sm text-gray-600">
<span>{{ $t('login.noAccount') }}</span>
<RouterLink class="text-theme" :to="{ name: 'Register' }">{{
$t('login.register')
}}</RouterLink>
</div> -->
</ElForm>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import AppConfig from '@/config'
import { useUserStore } from '@/store/modules/user'
import { useI18n } from 'vue-i18n'
import { HttpError } from '@/utils/http/error'
import { fetchCaptcha, fetchLogin, fetchGetUserInfo } from '@/api/auth'
import { ElNotification, type FormInstance, type FormRules } from 'element-plus'
defineOptions({ name: 'Login' })
const { t, locale } = useI18n()
const formKey = ref(0)
// 监听语言切换,重置表单
watch(locale, () => {
formKey.value++
})
const userStore = useUserStore()
const router = useRouter()
const captcha = ref(
'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
)
const systemName = AppConfig.systemInfo.name
const formRef = ref<FormInstance>()
/** 是否启用登录验证码(与后端 LOGIN_CAPTCHA_ENABLE 保持一致) */
const captchaEnabled = computed(() => {
const v = import.meta.env.VITE_LOGIN_CAPTCHA_ENABLED
return v !== 'false' && v !== '0'
})
const formData = reactive({
username: '',
password: '',
code: '',
uuid: '',
rememberPassword: true
})
const rules = computed<FormRules>(() => {
const r: FormRules = {
username: [{ required: true, message: t('login.placeholder.username'), trigger: 'blur' }],
password: [{ required: true, message: t('login.placeholder.password'), trigger: 'blur' }]
}
if (captchaEnabled.value) {
r.code = [{ required: true, message: t('login.placeholder.code'), trigger: 'blur' }]
}
return r
})
const loading = ref(false)
onMounted(() => {
if (captchaEnabled.value) refreshCaptcha()
})
// 登录
const handleSubmit = async () => {
if (!formRef.value) return
try {
// 表单验证
const valid = await formRef.value.validate()
if (!valid) return
loading.value = true
// 登录请求(关闭验证码时不传 code/uuid
const { access_token, refresh_token } = await fetchLogin({
username: formData.username,
password: formData.password,
...(captchaEnabled.value ? { code: formData.code, uuid: formData.uuid } : {})
})
// 验证token
if (!access_token) {
throw new Error('Login failed - no token received')
}
// 存储token和用户信息
userStore.setToken(access_token, refresh_token)
const userInfo = await fetchGetUserInfo()
userStore.setUserInfo(userInfo)
userStore.setLoginStatus(true)
// 登录成功处理
showLoginSuccessNotice()
router.push('/')
} catch (error) {
// 处理 HttpError
if (error instanceof HttpError) {
// console.log(error.code)
} else {
// 处理非 HttpError
// ElMessage.error('登录失败,请稍后重试')
console.error('[Login] Unexpected error:', error)
}
} finally {
if (captchaEnabled.value) refreshCaptcha()
loading.value = false
}
}
// 获取验证码
const refreshCaptcha = async () => {
fetchCaptcha().then((res) => {
formData.uuid = res.uuid
captcha.value = res.image
})
}
// 登录成功提示
const showLoginSuccessNotice = () => {
setTimeout(() => {
ElNotification({
title: t('login.success.title'),
type: 'success',
duration: 2500,
zIndex: 10000,
message: `${t('login.success.message')}, ${systemName}!`
})
}, 150)
}
</script>
<style scoped>
@import './style.css';
</style>
<style lang="scss" scoped>
:deep(.el-select__wrapper) {
height: 40px !important;
}
</style>