Files
system-file/web-vue/src/views/login/LoginForm.vue
2026-04-04 00:04:37 +08:00

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>