From d6059f43258a8cb537483a8b2d249b71c422f87c Mon Sep 17 00:00:00 2001 From: Vladimir Zagainov Date: Tue, 17 Jun 2025 10:00:17 +0300 Subject: [PATCH] feat(auth): implement login page and state management --- src/App.vue | 27 ++++++++-- src/api/auth.ts | 7 ++- src/stores/auth.ts | 53 +++++++++++++++++-- src/types.ts | 22 ++++++++ src/views/LoginView.vue | 111 +++++++++++++++++++++++++++++++++++++++- 5 files changed, 209 insertions(+), 11 deletions(-) diff --git a/src/App.vue b/src/App.vue index b14e16c..bc97256 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,16 +1,31 @@ + + diff --git a/src/api/auth.ts b/src/api/auth.ts index 7245885..aa913c0 100644 --- a/src/api/auth.ts +++ b/src/api/auth.ts @@ -1,7 +1,10 @@ -import type { RegisterRequest } from "@/types"; // Мы создадим этот тип +import type { RegisterRequest } from "@/types"; import apiClient from "./axios"; export const registerUser = (userData: RegisterRequest) => { - // apiClient уже настроен на /api, поэтому путь относительный return apiClient.post("/register", userData); }; + +export const loginUser = (credentials: LoginRequest) => { + return apiClient.post("/login", credentials); +}; diff --git a/src/stores/auth.ts b/src/stores/auth.ts index 4bab45f..04dfe8a 100644 --- a/src/stores/auth.ts +++ b/src/stores/auth.ts @@ -1,26 +1,53 @@ import { defineStore } from "pinia"; -import { ref } from "vue"; +import { ref, computed } from "vue"; import { registerUser as apiRegisterUser } from "@/api/auth"; import type { RegisterRequest } from "@/types"; import router from "@/router"; +import apiClient from "@/api/axios"; export const useAuthStore = defineStore("auth", () => { // State + const user = ref(null); + const token = ref(localStorage.getItem("authToken")); const isLoading = ref(false); const error = ref(null); + // === Getters === + const isAuthenticated = computed(() => !!user.value && !!token.value); + // Actions + function setAuthData(userData: User, authToken: string) { + user.value = userData; + token.value = authToken; + localStorage.setItem("authToken", authToken); + apiClient.defaults.headers.common["Authorization"] = `Bearer ${authToken}`; + } + + async function handleLogin(credentials: LoginRequest) { + isLoading.value = true; + error.value = null; + try { + const response = await apiLoginUser(credentials); + setAuthData(response.data.user, response.data.token); + await router.push({ name: "home" }); + } catch (e: any) { + if (e.response && e.response.data) { + error.value = e.response.data; + } else { + error.value = "Произошла неизвестная ошибка при входе"; + } + } finally { + isLoading.value = false; + } + } + async function handleRegister(userData: RegisterRequest) { isLoading.value = true; error.value = null; try { await apiRegisterUser(userData); - // После успешной регистрации перенаправляем на страницу входа await router.push({ name: "login" }); - // Можно добавить сообщение об успехе ("тост") - // alert('Регистрация прошла успешно! Теперь вы можете войти.'); } catch (e: any) { - // Обрабатываем ошибки от Axios if (e.response && e.response.data) { error.value = e.response.data; } else { @@ -30,10 +57,26 @@ export const useAuthStore = defineStore("auth", () => { isLoading.value = false; } } + // Функция для выхода + function handleLogout() { + user.value = null; + token.value = null; + localStorage.removeItem("authToken"); + delete apiClient.defaults.headers.common["Authorization"]; + router.push({ name: "login" }); + } return { + // State + user, + token, isLoading, error, + // Getters + isAuthenticated, + // Actions + handleLogin, handleRegister, + handleLogout, }; }); diff --git a/src/types.ts b/src/types.ts index 3f1907c..27c2c9e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -4,3 +4,25 @@ export interface RegisterRequest { email: string; password: string; } + +// Тип для запроса на логин +export interface LoginRequest { + login: string; + password: string; +} + +// Тип для ответа с бэкенда +export interface LoginResponse { + token: string; + user: User; +} + +// Тип для объекта пользователя +export interface User { + uuid: string; + username: string; + email: string; + role: string; + created_at: string; + updated_at: string; +} diff --git a/src/views/LoginView.vue b/src/views/LoginView.vue index e81a3c9..a01bcb5 100644 --- a/src/views/LoginView.vue +++ b/src/views/LoginView.vue @@ -1,3 +1,112 @@ + + + +