| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- <template>
- <el-form ref="loginFormRef" :model="loginForm" :rules="loginRules" size="large">
- <el-form-item prop="username">
- <el-input v-model="loginForm.username" placeholder="请输入用户名">
- <template #prefix>
- <el-icon class="el-input__icon">
- <user />
- </el-icon>
- </template>
- </el-input>
- </el-form-item>
- <el-form-item prop="password">
- <el-input v-model="loginForm.password" type="password" placeholder="请输入密码" show-password autocomplete="new-password">
- <template #prefix>
- <el-icon class="el-input__icon">
- <lock />
- </el-icon>
- </template>
- </el-input>
- </el-form-item>
- <el-form-item prop="captcha">
- <div class="captcha-row">
- <el-input v-model="loginForm.captcha" placeholder="请输入验证码" maxlength="6" />
- <div class="captcha-code" @click="refreshCaptcha" title="点击刷新验证码">
- {{ captchaCode }}
- </div>
- </div>
- </el-form-item>
- </el-form>
- <div class="login-btn">
- <el-button :icon="CircleClose" round size="large" @click="resetForm(loginFormRef)"> 重置 </el-button>
- <el-button :icon="UserFilled" round size="large" type="primary" :loading="loading" @click="login(loginFormRef)">
- 登录
- </el-button>
- </div>
- <!-- <div class="form-footer">
- 还没有账号?
- <el-button link type="primary" @click="goRegister">立即注册</el-button>
- </div> -->
- </template>
- <script setup lang="ts">
- import { ref, reactive, onMounted, onBeforeUnmount } from "vue";
- import { useRouter } from "vue-router";
- import { HOME_URL, REGISTER_URL } from "@/config";
- // import { getTimeState } from "@/utils";
- import { Login } from "@/api/interface/index";
- import { ElNotification } from "element-plus";
- import { loginApi } from "@/api/modules/login";
- import { useUserStore } from "@/stores/modules/user";
- import { useTabsStore } from "@/stores/modules/tabs";
- import { useKeepAliveStore } from "@/stores/modules/keepAlive";
- import { initDynamicRouter } from "@/routers/modules/dynamicRouter";
- import { CircleClose, UserFilled } from "@element-plus/icons-vue";
- import type { ElForm } from "element-plus";
- import md5 from "md5";
- const router = useRouter();
- const userStore = useUserStore();
- const tabsStore = useTabsStore();
- const keepAliveStore = useKeepAliveStore();
- type FormInstance = InstanceType<typeof ElForm>;
- const loginFormRef = ref<FormInstance>();
- const loginRules = reactive({
- username: [{ required: true, message: "请输入用户名", trigger: "blur" }],
- password: [{ required: true, message: "请输入密码", trigger: "blur" }],
- captcha: [{ required: true, message: "请输入验证码", trigger: "blur" }]
- });
- const loading = ref(false);
- const loginForm = reactive<Login.ReqLoginForm & { captcha: string }>({
- username: "",
- password: "",
- captcha: ""
- });
- const captchaCode = ref("");
- const generateCaptcha = () => {
- captchaCode.value = Math.floor(Math.random() * 1000000)
- .toString()
- .padStart(6, "0");
- };
- const refreshCaptcha = () => {
- generateCaptcha();
- loginForm.captcha = "";
- };
- // login
- const login = (formEl: FormInstance | undefined) => {
- if (!formEl) return;
- formEl.validate(async valid => {
- if (!valid) return;
- if (loginForm.captcha !== captchaCode.value) {
- ElNotification({
- title: "验证码错误",
- message: "请重新输入验证码",
- type: "error",
- duration: 5000
- });
- refreshCaptcha();
- return;
- }
- loading.value = true;
- try {
- // 1.执行登录接口
- const loginPayload = {
- username: loginForm.username,
- password: md5(loginForm.password)
- };
- const { data } = (await loginApi(loginPayload)) as { data: Login.ResLogin };
- console.log(data);
- if (data.result) {
- userStore.setToken(data.token);
- // 2.添加动态路由
- await initDynamicRouter();
- // 3.清空 tabs、keepAlive 数据
- tabsStore.setTabs([]);
- keepAliveStore.setKeepAliveName([]);
- // 4.跳转到首页
- router.push(HOME_URL);
- // ElNotification({
- // title: getTimeState(),
- // message: "欢迎登录 Geeker-Admin",
- // type: "success",
- // duration: 3000
- // });
- ElNotification({
- title: "登录成功",
- dangerouslyUseHTMLString: true,
- type: "success",
- duration: 8000
- });
- } else {
- ElNotification({
- title: "登录失败,请检查用户名和密码",
- dangerouslyUseHTMLString: true,
- type: "error",
- duration: 8000
- });
- }
- } finally {
- loading.value = false;
- }
- });
- };
- // resetForm
- const resetForm = (formEl: FormInstance | undefined) => {
- if (!formEl) return;
- formEl.resetFields();
- refreshCaptcha();
- };
- onMounted(() => {
- generateCaptcha();
- // 监听 enter 事件(调用登录)
- document.onkeydown = (e: KeyboardEvent) => {
- if (e.code === "Enter" || e.code === "enter" || e.code === "NumpadEnter") {
- if (loading.value) return;
- login(loginFormRef.value);
- }
- };
- });
- onBeforeUnmount(() => {
- document.onkeydown = null;
- });
- const goRegister = () => {
- router.push(REGISTER_URL);
- };
- </script>
- <style scoped lang="scss">
- @import "../index";
- .captcha-row {
- display: flex;
- gap: 12px;
- align-items: center;
- }
- .captcha-code {
- padding: 0 16px;
- font-weight: 600;
- color: var(--el-color-primary);
- text-align: center;
- letter-spacing: 4px;
- cursor: pointer;
- user-select: none;
- background-color: var(--el-color-primary-light-9);
- border: 1px solid var(--el-color-primary);
- border-radius: 6px;
- }
- </style>
|