|
@@ -1,142 +1,162 @@
|
|
|
<template>
|
|
|
- <div class="login-container">
|
|
|
- <el-form @submit.prevent="handleSubmit" :model="form" status-icon :rules="rules" ref="loginFormRef">
|
|
|
- <!-- <h2>登录</h2> -->
|
|
|
- <ItemWrap class="contetn_lr-item" title="登录">
|
|
|
- <el-form-item prop="username">
|
|
|
- <el-input v-model="form.username" placeholder="请输入用户名"></el-input>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item prop="password">
|
|
|
- <el-input v-model="form.password" type="password" placeholder="请输入密码"></el-input>
|
|
|
- </el-form-item>
|
|
|
-
|
|
|
- <el-form-item prop="captcha">
|
|
|
- <div class="captcha-container">
|
|
|
- <canvas ref="captchaCanvas" width="150" height="40"></canvas>
|
|
|
- <el-button @click="refreshCaptcha" type="text">刷新验证码</el-button>
|
|
|
- </div>
|
|
|
- <el-input v-model="form.captchaAnswer" type="text" placeholder="请输入验证码"></el-input>
|
|
|
- </el-form-item>
|
|
|
-
|
|
|
- <el-form-item>
|
|
|
- <el-button type="primary" :class="{ 'grayed-out': !isLoginFormValid }" :disabled="!isLoginFormValid" native-type="submit">登录</el-button>
|
|
|
- </el-form-item>
|
|
|
- </ItemWrap>
|
|
|
-
|
|
|
- </el-form>
|
|
|
- </div>
|
|
|
+ <div class="login-container">
|
|
|
+ <el-form @submit.prevent="handleSubmit" :model="form" status-icon :rules="rules" ref="loginFormRef">
|
|
|
+ <!-- <h2>登录</h2> -->
|
|
|
+ <ItemWrap class="contetn_lr-item" title="登录">
|
|
|
+ <el-form-item prop="username">
|
|
|
+ <el-input v-model="form.account" placeholder="请输入用户名"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item prop="password">
|
|
|
+ <el-input v-model="form.password" type="password" placeholder="请输入密码"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item prop="captcha">
|
|
|
+ <div class="captcha-container">
|
|
|
+ <canvas ref="captchaCanvas" width="150" height="40"></canvas>
|
|
|
+ <el-button @click="refreshCaptcha" type="text">刷新验证码</el-button>
|
|
|
+ </div>
|
|
|
+ <el-input v-model="form.captchaAnswer" type="text" placeholder="请输入验证码"></el-input>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="primary" :class="{ 'grayed-out': !isLoginFormValid }" :disabled="!isLoginFormValid"
|
|
|
+ native-type="submit">登录</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </ItemWrap>
|
|
|
+
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
-import { reactive, onMounted, ref,computed } from 'vue';
|
|
|
+import { reactive, onMounted, ref, computed } from 'vue';
|
|
|
import { ElMessage } from 'element-plus';
|
|
|
import router from '@/router';
|
|
|
+import { Logins } from '@/api/modules/login';
|
|
|
+import { StorageEnum, RequestEnum } from "@/enums";
|
|
|
+import { setLocalStorage } from "@/utils";
|
|
|
|
|
|
const form = reactive({
|
|
|
- username: '',
|
|
|
- password: '',
|
|
|
- captchaAnswer: '',
|
|
|
+ account: '',
|
|
|
+ password: '',
|
|
|
+ captchaAnswer: '',
|
|
|
});
|
|
|
|
|
|
const captchaAnswerFromServer = ref('');
|
|
|
|
|
|
const isLoginFormValid = computed(() => {
|
|
|
- return Boolean(form.username && form.password && form.captchaAnswer);
|
|
|
+ return Boolean(form.account && form.password && form.captchaAnswer);
|
|
|
});
|
|
|
|
|
|
const rules = reactive({
|
|
|
- username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
|
|
|
- password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
|
|
|
- captchaAnswer: [{ required: true, message: '请输入验证码', trigger: 'blur' }],
|
|
|
+ account: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
|
|
|
+ password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
|
|
|
+ captchaAnswer: [{ required: true, message: '请输入验证码', trigger: 'blur' }],
|
|
|
});
|
|
|
|
|
|
const captchaCanvas = ref(null);
|
|
|
|
|
|
function generateRandomString(length) {
|
|
|
- const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
|
- let result = '';
|
|
|
- for (let i = 0; i < length; i++) {
|
|
|
- result += characters.charAt(Math.floor(Math.random() * characters.length));
|
|
|
- }
|
|
|
- return result;
|
|
|
+ // const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
|
+ const characters = '0123456789';
|
|
|
+ let result = '';
|
|
|
+ for (let i = 0; i < length; i++) {
|
|
|
+ result += characters.charAt(Math.floor(Math.random() * characters.length));
|
|
|
+ }
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
function drawCaptcha(canvas) {
|
|
|
- const ctx = canvas.getContext('2d');
|
|
|
- const width = canvas.width;
|
|
|
- const height = canvas.height;
|
|
|
-
|
|
|
- // 清除画布
|
|
|
- ctx.clearRect(0, 0, width, height);
|
|
|
-
|
|
|
- // 绘制背景
|
|
|
- ctx.fillStyle = '#eee';
|
|
|
- ctx.fillRect(0, 0, width, height);
|
|
|
-
|
|
|
- // 绘制验证码文本
|
|
|
- const captchaText = generateRandomString(4);
|
|
|
- captchaAnswerFromServer.value = captchaText;
|
|
|
- ctx.font = 'bold 28px Arial';
|
|
|
- ctx.textBaseline = 'middle';
|
|
|
- ctx.fillStyle = '#333';
|
|
|
- ctx.fillText(captchaText, width / 2 - 30, height / 2);
|
|
|
-
|
|
|
- // 绘制干扰线
|
|
|
- for (let i = 0; i < 5; i++) {
|
|
|
- ctx.beginPath();
|
|
|
- ctx.moveTo(Math.random() * width, Math.random() * height);
|
|
|
- ctx.lineTo(Math.random() * width, Math.random() * height);
|
|
|
- ctx.strokeStyle = '#aaa';
|
|
|
- ctx.stroke();
|
|
|
- }
|
|
|
+ const ctx = canvas.getContext('2d');
|
|
|
+ const width = canvas.width;
|
|
|
+ const height = canvas.height;
|
|
|
+
|
|
|
+ // 清除画布
|
|
|
+ ctx.clearRect(0, 0, width, height);
|
|
|
+
|
|
|
+ // 绘制背景
|
|
|
+ ctx.fillStyle = '#eee';
|
|
|
+ ctx.fillRect(0, 0, width, height);
|
|
|
+
|
|
|
+ // 绘制验证码文本
|
|
|
+ const captchaText = generateRandomString(4);
|
|
|
+ captchaAnswerFromServer.value = captchaText;
|
|
|
+ ctx.font = 'bold 28px Arial';
|
|
|
+ ctx.textBaseline = 'middle';
|
|
|
+ ctx.fillStyle = '#333';
|
|
|
+ ctx.fillText(captchaText, width / 2 - 30, height / 2);
|
|
|
+
|
|
|
+ // 绘制干扰线
|
|
|
+ for (let i = 0; i < 5; i++) {
|
|
|
+ ctx.beginPath();
|
|
|
+ ctx.moveTo(Math.random() * width, Math.random() * height);
|
|
|
+ ctx.lineTo(Math.random() * width, Math.random() * height);
|
|
|
+ ctx.strokeStyle = '#aaa';
|
|
|
+ ctx.stroke();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
function refreshCaptcha() {
|
|
|
- if (captchaCanvas.value) {
|
|
|
- drawCaptcha(captchaCanvas.value);
|
|
|
- }
|
|
|
+ if (captchaCanvas.value) {
|
|
|
+ drawCaptcha(captchaCanvas.value);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
function handleSubmit() {
|
|
|
- if (form.captchaAnswer.toLowerCase() !== captchaAnswerFromServer.value.toLowerCase()) {
|
|
|
- ElMessage.error('验证码错误,请重新输入');
|
|
|
- return;
|
|
|
+ if (form.captchaAnswer.toLowerCase() !== captchaAnswerFromServer.value.toLowerCase()) {
|
|
|
+ ElMessage.error('验证码错误,请重新输入');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 登录逻辑,例如跳转页面或调用API
|
|
|
+ Logins(form).then(res => {
|
|
|
+ if (res.code === 200) {
|
|
|
+ ElMessage.success('登录成功');
|
|
|
+ // console.log("登录", res.data.token);
|
|
|
+ // localStorage.setItem('token', res.data.token);
|
|
|
+ setLocalStorage(StorageEnum.GB_TOKEN_STORE, res.data.token);
|
|
|
+ router.push('/index');
|
|
|
+ form.account = '';
|
|
|
+ form.password = '';
|
|
|
+ form.captchaAnswer = '';
|
|
|
+ refreshCaptcha();
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ ElMessage.error(res.message)
|
|
|
+ form.account = '';
|
|
|
+ form.password = '';
|
|
|
+ form.captchaAnswer = '';
|
|
|
}
|
|
|
+ })
|
|
|
|
|
|
- // 登录逻辑,例如跳转页面或调用API
|
|
|
- ElMessage.success('登录成功');
|
|
|
- localStorage.setItem('token', form.username);
|
|
|
- router.push('/index');
|
|
|
- form.username = '';
|
|
|
- form.password = '';
|
|
|
- form.captchaAnswer = '';
|
|
|
- refreshCaptcha();
|
|
|
}
|
|
|
|
|
|
onMounted(() => {
|
|
|
- if (captchaCanvas.value) {
|
|
|
- drawCaptcha(captchaCanvas.value);
|
|
|
- }
|
|
|
+ if (captchaCanvas.value) {
|
|
|
+ drawCaptcha(captchaCanvas.value);
|
|
|
+ }
|
|
|
});
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
.captcha-container {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 10px;
|
|
|
- margin-bottom: 10px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+ margin-bottom: 10px;
|
|
|
}
|
|
|
|
|
|
.captcha-container canvas {
|
|
|
- border: 1px solid #ccc;
|
|
|
- border-radius: 5px;
|
|
|
+ border: 1px solid #ccc;
|
|
|
+ border-radius: 5px;
|
|
|
}
|
|
|
-.contetn_lr-item{
|
|
|
+
|
|
|
+.contetn_lr-item {
|
|
|
font-size: 30px;
|
|
|
width: 500px;
|
|
|
height: auto;
|
|
|
}
|
|
|
+
|
|
|
.login-container {
|
|
|
width: 500px;
|
|
|
margin: 300px auto;
|
|
@@ -186,7 +206,7 @@ label {
|
|
|
color: #61dafb;
|
|
|
margin-right: 10px;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
#captcha span {
|
|
|
color: #61dafb;
|
|
|
margin-right: 10px;
|
|
@@ -196,10 +216,12 @@ label {
|
|
|
width: 100px;
|
|
|
margin-left: 10px;
|
|
|
}
|
|
|
+
|
|
|
.contetn_lr-item {
|
|
|
height: 310px;
|
|
|
}
|
|
|
+
|
|
|
.grayed-out {
|
|
|
- background-color: gray !important;
|
|
|
+ background-color: gray !important;
|
|
|
}
|
|
|
</style>
|