math/ui/src/components/LoginForm.vue

113 lines
3.6 KiB
Vue

<template>
<v-card class="mx-auto pa-12 pb-8" width="448" elevation="8" rounded="lg">
<v-form fast-fail @submit.prevent="submit">
<!-- <v-img class="mx-auto my-6" max-width="228"
src="https://cdn.vuetifyjs.com/docs/images/logos/vuetify-logo-v3-slim-text-light.svg"></v-img> -->
<v-text-field v-model="userId" prepend-inner-icon="mdi-account-circle" :rules="userIdRules"
label="账号"></v-text-field>
<v-divider :thickness="10" class="border-opacity-0"></v-divider>
<v-text-field v-model="password" :rules="passwordRules" :error-messages="passwordValidate" label="密码"
:append-inner-icon="visible ? 'mdi-eye' : 'mdi-eye-off'" :type="visible ? 'text' : 'password'"
@click:append-inner="visible = !visible" prepend-inner-icon="mdi-lock-outline"></v-text-field>
<v-divider :thickness="10" class="border-opacity-0"></v-divider>
<v-btn class="mb-8" color="blue" size="large" variant="tonal" type="submit" block>
登录
</v-btn>
<v-card-text class="text-center">
<a class="text-red text-decoration-none"
@click="dialog('忘记密码', '请联系老师重置密码。')">
忘记密码<v-icon icon="mdi-chevron-right"></v-icon>
</a>
</v-card-text>
</v-form>
</v-card>
<v-dialog v-model="dialogShow" width="auto">
<v-card max-width="400" prepend-icon="mdi-update" :text="dialogText" :title="dialogTitle">
<template v-slot:actions>
<v-btn class="ms-auto" text="Ok" @click="dialogShow = false, dialogClose()"></v-btn>
</template>
</v-card>
</v-dialog>
</template>
<script setup lang="ts">
import { useAuthStore } from '@/store/auth';
import axios, { AxiosError } from 'axios';
import { jwtDecode } from 'jwt-decode';
import { ref } from 'vue';
const visible = ref(false);
const authStore = useAuthStore();
const storedToken = ref(authStore.token);
const dialogShow = ref(false);
const dialogTitle = ref('');
const dialogText = ref('');
const dialogClose = ref(() => { });
const loading = ref(false);
const userId = ref('');
const password = ref('');
const passwordValidate = ref<string>("");
type LoginResponse = { success?: string, token?: string, error?: string };
const dialog = (title: string, text: string) => {
dialogTitle.value = title;
dialogText.value = text;
dialogShow.value = true;
return new Promise(res => {
dialogClose.value = res as () => void;
});
};
const login = async (userId: string, password: string) => {
try {
const formData = new FormData;
formData.append("user_id", userId);
formData.append("password", password);
let res = await axios.post('/api/auth/login', formData);
return res.data as LoginResponse;
} catch (e) {
let ex = e as AxiosError;
return ex.response?.data as LoginResponse;
}
};
const submit = async (event: SubmitEvent) => {
const results: any = await event;
if (results.valid) {
loading.value = true
let res = await login(userId.value, password.value);
loading.value = false
if (res?.error) {
passwordValidate.value = res.error;
await dialog('错误', `登录失败:${res.error}`);
} else {
await dialog('信息', `登录成功,你好 ${(jwtDecode(res.token as string) as any).user_id}`);
authStore.setToken(res.token as string);
}
}
};
const userIdRules: any = [(value: string) => {
passwordValidate.value = '';
if (value?.length > 0) return true;
return '账号不能为空';
}];
const passwordRules: any = [(value: string) => {
passwordValidate.value = '';
if (value?.length > 0) return true;
return '密码不能为空';
}];
</script>