+
+
+
+
+
@@ -51,7 +61,7 @@ const navItems = ref([
-
+
diff --git a/frontend/admin/src/api/authService.js b/frontend/admin/src/api/authService.js
new file mode 100644
index 0000000..e1ead84
--- /dev/null
+++ b/frontend/admin/src/api/authService.js
@@ -0,0 +1,7 @@
+import { http } from '@/utils/http';
+
+export const authService = {
+ login(username, password) {
+ return http.post('/admin/auth/login', { username, password });
+ },
+};
diff --git a/frontend/admin/src/main.js b/frontend/admin/src/main.js
index a909627..5b91226 100644
--- a/frontend/admin/src/main.js
+++ b/frontend/admin/src/main.js
@@ -1,4 +1,5 @@
import Aura from '@primeuix/themes/aura';
+import { createPinia } from 'pinia';
import PrimeVue from 'primevue/config';
import ConfirmationService from 'primevue/confirmationservice';
import ToastService from 'primevue/toastservice';
@@ -20,7 +21,13 @@ if (typeof import.meta !== 'undefined') {
}
console.log('=============================');
+
const app = createApp(App)
+
+
+const pinia = createPinia()
+app.use(pinia);
+
app.use(router);
app.use(PrimeVue, {
theme: {
diff --git a/frontend/admin/src/pages/LoginPage.vue b/frontend/admin/src/pages/LoginPage.vue
new file mode 100644
index 0000000..6428f48
--- /dev/null
+++ b/frontend/admin/src/pages/LoginPage.vue
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ errorMessage }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/admin/src/router.js b/frontend/admin/src/router.js
index 0f6e104..e285f5f 100644
--- a/frontend/admin/src/router.js
+++ b/frontend/admin/src/router.js
@@ -1,4 +1,5 @@
import { createRouter, createWebHashHistory } from 'vue-router';
+import { useAuthStore } from './stores/auth';
// Define your routes here
const routes = [
@@ -44,6 +45,12 @@ const routes = [
path: '/orders',
name: 'Orders',
component: () => import('./pages/OrderPage.vue'),
+ },
+ {
+ path: '/login',
+ name: 'Login',
+ component: () => import('./pages/LoginPage.vue'),
+ meta: { requiresAuth: false }
}
];
@@ -53,3 +60,14 @@ export const router = createRouter({
history: createWebHashHistory(),
routes
});
+
+// Add navigation guard
+router.beforeEach((to, from, next) => {
+ const authStore = useAuthStore();
+
+ if (to.meta.requiresAuth !== false && !authStore.isAuthenticated) {
+ next('/login');
+ } else {
+ next();
+ }
+});
diff --git a/frontend/admin/src/router/index.js b/frontend/admin/src/router/index.js
new file mode 100644
index 0000000..d3a661e
--- /dev/null
+++ b/frontend/admin/src/router/index.js
@@ -0,0 +1,33 @@
+import { useAuthStore } from '@/stores/authStore';
+import { createRouter, createWebHistory } from 'vue-router';
+
+// ...existing code...
+
+// Add login route
+const routes = [
+ {
+ path: '/login',
+ name: 'Login',
+ component: () => import('@/pages/LoginPage.vue'),
+ meta: { requiresAuth: false }
+ },
+ // ...existing routes...
+];
+
+// Add navigation guard
+const router = createRouter({
+ history: createWebHistory(),
+ routes,
+});
+
+router.beforeEach((to, from, next) => {
+ const authStore = useAuthStore();
+
+ if (to.meta.requiresAuth !== false && !authStore.isAuthenticated) {
+ next('/login');
+ } else {
+ next();
+ }
+});
+
+export default router;
\ No newline at end of file
diff --git a/frontend/admin/src/stores/auth.js b/frontend/admin/src/stores/auth.js
new file mode 100644
index 0000000..b393bef
--- /dev/null
+++ b/frontend/admin/src/stores/auth.js
@@ -0,0 +1,31 @@
+import { authService } from '@/api/authService';
+import { defineStore } from 'pinia';
+import { computed, ref } from 'vue';
+
+export const useAuthStore = defineStore('auth', () => {
+ const token = ref(localStorage.getItem('token'));
+ const user = ref(null);
+
+ const isAuthenticated = computed(() => !!token.value);
+
+ async function login(username, password) {
+ const { data } = await authService.login(username, password);
+ token.value = data.token;
+ user.value = data.user;
+ localStorage.setItem('token', data.token);
+ }
+
+ function logout() {
+ token.value = null;
+ user.value = null;
+ localStorage.removeItem('token');
+ }
+
+ return {
+ token,
+ user,
+ isAuthenticated,
+ login,
+ logout
+ };
+});
diff --git a/frontend/admin/src/utils/http.js b/frontend/admin/src/utils/http.js
new file mode 100644
index 0000000..eea9c6a
--- /dev/null
+++ b/frontend/admin/src/utils/http.js
@@ -0,0 +1,27 @@
+import { router } from '@/router';
+import { useAuthStore } from '@/stores/auth';
+import axios from 'axios';
+
+export const http = axios.create({
+ baseURL: import.meta.env.VITE_API_BASE_URL,
+});
+
+http.interceptors.request.use((config) => {
+ const authStore = useAuthStore();
+ if (authStore.token) {
+ config.headers.Authorization = `Bearer ${authStore.token}`;
+ }
+ return config;
+});
+
+http.interceptors.response.use(
+ (response) => response,
+ (error) => {
+ if (error.response?.status === 401) {
+ const authStore = useAuthStore();
+ authStore.logout();
+ router.push('/login');
+ }
+ return Promise.reject(error);
+ }
+);