155 lines
3.7 KiB
Vue
155 lines
3.7 KiB
Vue
<template>
|
|
<el-form :model="form" :rules="rules" ref="formRef" @submit.prevent="handleLogin">
|
|
<el-form-item prop="username">
|
|
<el-input
|
|
v-model="form.username"
|
|
placeholder="请输入账号"
|
|
clearable
|
|
>
|
|
<template #prefix><el-icon><User /></el-icon></template>
|
|
</el-input>
|
|
</el-form-item>
|
|
<el-form-item prop="password">
|
|
<el-input
|
|
v-model="form.password"
|
|
type="password"
|
|
placeholder="请输入密码"
|
|
show-password
|
|
>
|
|
<template #prefix><el-icon><Lock /></el-icon></template>
|
|
</el-input>
|
|
</el-form-item>
|
|
<el-form-item prop="captcha">
|
|
<div class="captcha-row">
|
|
<el-input
|
|
v-model="form.captcha"
|
|
placeholder="请输入验证码"
|
|
clearable
|
|
@keyup.enter="handleLogin"
|
|
>
|
|
<template #prefix><el-icon><Key /></el-icon></template>
|
|
</el-input>
|
|
<img
|
|
:src="captchaImage"
|
|
class="captcha-img"
|
|
@click="refreshCaptcha"
|
|
title="点击刷新验证码"
|
|
/>
|
|
</div>
|
|
</el-form-item>
|
|
<el-form-item>
|
|
<el-button
|
|
type="primary"
|
|
:loading="loading"
|
|
:disabled="!isFormComplete"
|
|
native-type="submit"
|
|
style="width: 100%"
|
|
>
|
|
<template v-if="loading">
|
|
<span>登录中...</span>
|
|
</template>
|
|
<template v-else>
|
|
<el-icon><Right /></el-icon>
|
|
<span style="margin-left: 4px">登录</span>
|
|
</template>
|
|
</el-button>
|
|
</el-form-item>
|
|
</el-form>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, reactive, computed, onMounted } from 'vue'
|
|
import { ElMessage } from 'element-plus'
|
|
import { User, Lock, Right, Key } from '@element-plus/icons-vue'
|
|
import { login, getCaptcha } from '@/api/auth'
|
|
|
|
const emit = defineEmits(['success'])
|
|
|
|
const formRef = ref(null)
|
|
const loading = ref(false)
|
|
const captchaImage = ref('')
|
|
|
|
const form = reactive({ username: '', password: '', captcha: '' })
|
|
|
|
// 表单是否填写完整
|
|
const isFormComplete = computed(() => {
|
|
return form.username.trim() && form.password.trim() && form.captcha.trim()
|
|
})
|
|
|
|
const rules = {
|
|
username: [{ required: true, message: '请输入账号', trigger: 'blur' }],
|
|
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
|
|
captcha: [{ required: true, message: '请输入验证码', trigger: 'blur' }]
|
|
}
|
|
|
|
const refreshCaptcha = async () => {
|
|
try {
|
|
const res = await getCaptcha()
|
|
captchaImage.value = res.data.image
|
|
} catch (e) {
|
|
console.error('获取验证码失败', e)
|
|
}
|
|
}
|
|
|
|
// 暴露方法给父组件
|
|
defineExpose({
|
|
refreshCaptcha
|
|
})
|
|
|
|
const handleLogin = async () => {
|
|
if (!isFormComplete.value || loading.value) return
|
|
|
|
loading.value = true
|
|
try {
|
|
const res = await login(form)
|
|
ElMessage.success('登录成功,正在跳转...')
|
|
emit('success', res.data)
|
|
} catch (e) {
|
|
// 登录失败刷新验证码
|
|
refreshCaptcha()
|
|
form.captcha = ''
|
|
if (!e.response) {
|
|
ElMessage.error('后端服务不可用,请稍后重试')
|
|
} else if (e.response.status >= 500) {
|
|
ElMessage.error('服务器异常,请稍后重试')
|
|
} else {
|
|
ElMessage.error(e.response.data?.message || '账号或密码错误')
|
|
}
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
onMounted(() => {
|
|
refreshCaptcha()
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.captcha-row {
|
|
display: flex;
|
|
gap: 12px;
|
|
width: 100%;
|
|
align-items: center;
|
|
}
|
|
|
|
.captcha-row .el-input {
|
|
flex: 1;
|
|
}
|
|
|
|
.captcha-img {
|
|
width: 140px;
|
|
height: 32px;
|
|
cursor: pointer;
|
|
border-radius: 4px;
|
|
border: 1px solid #dcdfe6;
|
|
object-fit: fill;
|
|
background: #fff;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.captcha-img:hover {
|
|
border-color: #409eff;
|
|
}
|
|
</style>
|