mirror of
https://github.com/creativetimofficial/vue-material-kit.git
synced 2025-05-23 04:04:22 +08:00
Merge 49409ba211a4c33f46a4e48843c7546359df954d into aae8bbdb3510697f541de4d58abc954d359b9391
This commit is contained in:
commit
4ed62cb7c1
@ -9,6 +9,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@popperjs/core": "2.11.5",
|
||||
"axios": "^1.6.8",
|
||||
"bootstrap": "5.1.3",
|
||||
"pinia": "2.0.14",
|
||||
"prismjs": "1.28.0",
|
||||
|
13
src/App.vue
13
src/App.vue
@ -1,18 +1,5 @@
|
||||
<script setup>
|
||||
/*
|
||||
=========================================================
|
||||
* Vue Material Kit 2 - v2.0.0
|
||||
=========================================================
|
||||
|
||||
* Product Page: https://www.creative-tim.com/product/vue-material-kit
|
||||
* Copyright 2022 Creative Tim (https://www.creative-tim.com)
|
||||
|
||||
Coded by www.creative-tim.com
|
||||
|
||||
=========================================================
|
||||
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*/
|
||||
import { RouterView } from "vue-router";
|
||||
</script>
|
||||
|
||||
|
5
src/router/constants.js
Normal file
5
src/router/constants.js
Normal file
@ -0,0 +1,5 @@
|
||||
export const Role = {
|
||||
Admin: 'admin',
|
||||
User: 'user',
|
||||
Guest: 'guest',
|
||||
};
|
@ -23,6 +23,19 @@ import ElDropdowns from "../layouts/sections/elements/dropdowns/DropdownsView.vu
|
||||
import ElProgressBars from "../layouts/sections/elements/progress-bars/ProgressBarsView.vue";
|
||||
import ElToggles from "../layouts/sections/elements/toggles/TogglesView.vue";
|
||||
import ElTypography from "../layouts/sections/elements/typography/TypographyView.vue";
|
||||
|
||||
import AdminLoginView from "../views/Auth/AdminLogin.vue";
|
||||
import UserLoginView from "../views/Auth/UserLogin.vue";
|
||||
import AdminDashboardView from "../views/Admin/dashboard.vue";
|
||||
import AdminSettingsView from "../views/Admin/Settings.vue"
|
||||
import AdminUsersView from "../views/Admin/Users.vue"
|
||||
|
||||
// import AdminView from "../views/LandingPages/Author/AuthorView.vue";
|
||||
import { Role } from './constants';
|
||||
import { useStore } from '@/stores'
|
||||
|
||||
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
@ -30,6 +43,7 @@ const router = createRouter({
|
||||
path: "/",
|
||||
name: "presentation",
|
||||
component: PresentationView,
|
||||
//meta: { requiresAuth: true, requiredRole: Role.Admin },
|
||||
},
|
||||
{
|
||||
path: "/pages/landing-pages/about-us",
|
||||
@ -146,7 +160,100 @@ const router = createRouter({
|
||||
name: "el-typography",
|
||||
component: ElTypography,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
{
|
||||
path: '/admin/auth',
|
||||
component: AdminLoginView,
|
||||
name: "admin-login",
|
||||
},
|
||||
{
|
||||
path: '/admin/dashboard',
|
||||
component: AdminDashboardView,
|
||||
name: "admin-dashboard",
|
||||
|
||||
export default router;
|
||||
children: [
|
||||
{
|
||||
path: '/admin/users',
|
||||
component: AdminUsersView,
|
||||
name: "admin-users",
|
||||
},
|
||||
{
|
||||
path: '/admin/settings',
|
||||
component: AdminSettingsView,
|
||||
name: "admin-settings",
|
||||
},
|
||||
// Other child routes for the dashboard
|
||||
]
|
||||
|
||||
},
|
||||
// {
|
||||
// path: "/unauthorized",
|
||||
// name: "unauthorized",
|
||||
// component: UnauthorizedView,
|
||||
// },
|
||||
{
|
||||
path: "/user/login",
|
||||
name: "user-login",
|
||||
component: UserLoginView,
|
||||
},
|
||||
|
||||
|
||||
],
|
||||
});
|
||||
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
const store = useStore()
|
||||
console.log(store.isAuthenticated,store.user,"store")
|
||||
//console.log(store.isAuthenticated,"store")
|
||||
if (to.meta.requiresAuth && !store.isAuthenticated) {
|
||||
next('/admin/auth')
|
||||
} else if (to.meta.requiresVisitor && store.isAuthenticated) {
|
||||
next('/sections/elements/progress-bars')
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
// function isAuthenticated() {
|
||||
// // Check if the user is authenticated, e.g., by verifying the presence of a valid token or logged-in state
|
||||
// // Return true if authenticated, false otherwise
|
||||
// // Example: return localStorage.getItem('token') !== null;
|
||||
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// function getCurrentUserRole() {
|
||||
// // Retrieve the current user's role from your authentication system or state management
|
||||
// // Return the role of the current user
|
||||
// // Example: return localStorage.getItem('userRole');
|
||||
// return "guest";
|
||||
// }
|
||||
|
||||
// // Route guard
|
||||
// router.beforeEach((to, from, next) => {
|
||||
// if (to.meta.requiresAuth) {
|
||||
// // Check if the user is authenticated, e.g., by checking the presence of a valid token or logged-in state
|
||||
// if (isAuthenticated()) {
|
||||
// // Check if the user has the required role
|
||||
// if (to.meta.requiredRole && getCurrentUserRole() !== to.meta.requiredRole) {
|
||||
// // Redirect to a different route or show an error message
|
||||
// next({ path: '/unauthorized' });
|
||||
// } else {
|
||||
// // Proceed to the requested route
|
||||
// next();
|
||||
// }
|
||||
// } else {
|
||||
// // Redirect to the login page or a suitable route for unauthenticated users
|
||||
// next({ path: '/logout' });
|
||||
// }
|
||||
// } else {
|
||||
// // No authentication required for the route
|
||||
// next();
|
||||
// }
|
||||
// });
|
||||
|
||||
export default router;
|
||||
|
@ -1,7 +1,27 @@
|
||||
import { defineStore } from "pinia";
|
||||
import bootstrap from "bootstrap/dist/js/bootstrap.min.js";
|
||||
|
||||
export const useAppStore = defineStore("storeId", {
|
||||
state: () => ({
|
||||
bootstrap,
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
export const useStore = defineStore({
|
||||
id: 'main',
|
||||
state: () => ({
|
||||
isAuthenticated: false,
|
||||
user: null,
|
||||
}),
|
||||
actions: {
|
||||
login(user) {
|
||||
this.isAuthenticated = true
|
||||
this.user = user
|
||||
},
|
||||
logout() {
|
||||
this.isAuthenticated = false
|
||||
this.user = null
|
||||
},
|
||||
},
|
||||
})
|
3
src/views/Admin/Settings.vue
Normal file
3
src/views/Admin/Settings.vue
Normal file
@ -0,0 +1,3 @@
|
||||
<template>
|
||||
Settings Page
|
||||
</template>
|
44
src/views/Admin/SideNavAdmin.vue
Normal file
44
src/views/Admin/SideNavAdmin.vue
Normal file
@ -0,0 +1,44 @@
|
||||
<template>
|
||||
|
||||
|
||||
<div id="sidebar">
|
||||
|
||||
<ul class="nav">
|
||||
<li>
|
||||
<a class="nav-link" href="#" @click.prevent="goToPage('el-badges')" active-class="active">
|
||||
<i class="zmdi zmdi-view-dashboard"></i> Dashboard
|
||||
</a>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<a class="nav-link" href="#" @click.prevent="goToPage('admin-users')" >
|
||||
<i class="zmdi zmdi-link"></i> Users
|
||||
</a>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
|
||||
<a class="nav-link" href="#" @click.prevent="goToPage('admin-settings')">
|
||||
<i class="zmdi zmdi-widgets"></i> Analytics
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
methods: {
|
||||
goToPage(page) {
|
||||
this.$router.push({ name: page });
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
3
src/views/Admin/Users.vue
Normal file
3
src/views/Admin/Users.vue
Normal file
@ -0,0 +1,3 @@
|
||||
<template>
|
||||
Users Page
|
||||
</template>
|
97
src/views/Admin/dashboard.vue
Normal file
97
src/views/Admin/dashboard.vue
Normal file
@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<div id="viewport">
|
||||
<Sidebar />
|
||||
<div id="content">
|
||||
<router-view />
|
||||
|
||||
<div class="container-fluid">
|
||||
<h1>Simple Sidebar</h1>
|
||||
<p>
|
||||
Make sure to keep all page content within the
|
||||
<code>#content</code>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Sidebar from './SideNavAdmin.vue';
|
||||
|
||||
export default {
|
||||
components: { Sidebar }
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>/* Toggle Styles */
|
||||
|
||||
#viewport {
|
||||
padding-left: 250px;
|
||||
-webkit-transition: all 0.5s ease;
|
||||
-moz-transition: all 0.5s ease;
|
||||
-o-transition: all 0.5s ease;
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
|
||||
#content {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
/* Sidebar Styles */
|
||||
|
||||
#sidebar {
|
||||
z-index: 1000;
|
||||
position: fixed;
|
||||
left: 250px;
|
||||
width: 250px;
|
||||
height: 100%;
|
||||
margin-left: -250px;
|
||||
overflow-y: auto;
|
||||
background: #37474F;
|
||||
-webkit-transition: all 0.5s ease;
|
||||
-moz-transition: all 0.5s ease;
|
||||
-o-transition: all 0.5s ease;
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
|
||||
#sidebar header {
|
||||
background-color: #263238;
|
||||
font-size: 20px;
|
||||
line-height: 52px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#sidebar header a {
|
||||
color: #fff;
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#sidebar header a:hover {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#sidebar .nav{
|
||||
|
||||
}
|
||||
|
||||
#sidebar .nav a{
|
||||
background: none;
|
||||
border-bottom: 1px solid #455A64;
|
||||
color: #CFD8DC;
|
||||
font-size: 14px;
|
||||
padding: 16px 24px;
|
||||
}
|
||||
|
||||
#sidebar .nav a:hover{
|
||||
background: none;
|
||||
color: #ECEFF1;
|
||||
}
|
||||
|
||||
#sidebar .nav a i{
|
||||
margin-right: 16px;
|
||||
}
|
||||
</style>
|
128
src/views/Auth/AdminLogin.vue
Normal file
128
src/views/Auth/AdminLogin.vue
Normal file
@ -0,0 +1,128 @@
|
||||
<script setup>
|
||||
import { onMounted } from "vue";
|
||||
import Header from "@/examples/Header.vue";
|
||||
import MaterialInput from "@/components/MaterialInput.vue";
|
||||
import MaterialButton from "@/components/MaterialButton.vue";
|
||||
import setMaterialInput from "@/assets/js/material-input";
|
||||
import axios from "axios";
|
||||
import { ref } from 'vue'
|
||||
import { useStore } from '@/stores'
|
||||
import router from '@/router'
|
||||
onMounted(() => {
|
||||
setMaterialInput();
|
||||
});
|
||||
|
||||
const store = useStore()
|
||||
const email = ref('')
|
||||
const password = ref('')
|
||||
|
||||
|
||||
const handleLogin = async () => {
|
||||
try {
|
||||
// Send a POST request to the login endpoint
|
||||
const response = await axios.get('https://dummyjson.com/products/1', {
|
||||
email: email.value,
|
||||
password: password.value
|
||||
})
|
||||
|
||||
// Check if the login was successful
|
||||
console.log(response && response.status===200);
|
||||
if (response && response.status===200) {
|
||||
// Save the user to the store
|
||||
store.login({
|
||||
name: response.data.name,
|
||||
email: response.data.email
|
||||
})
|
||||
|
||||
// Navigate the user to the admin dashboard
|
||||
router.push('/')
|
||||
} else {
|
||||
// Display an error message if the login failed
|
||||
alert('Invalid email or password')
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Error:', err);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Header>
|
||||
<div
|
||||
class="page-header align-items-start min-vh-100"
|
||||
:style="{
|
||||
backgroundImage:
|
||||
'url(https://images.unsplash.com/photo-1497294815431-9365093b7331?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1950&q=80)'
|
||||
}"
|
||||
loading="lazy"
|
||||
>
|
||||
<span class="mask bg-gradient-dark opacity-6"></span>
|
||||
<div class="container my-auto">
|
||||
<div class="row">
|
||||
<div class="col-lg-4 col-md-8 col-12 mx-auto">
|
||||
<div class="card z-index-0 fadeIn3 fadeInBottom">
|
||||
<div
|
||||
class="card-header p-0 position-relative mt-n4 mx-3 z-index-2"
|
||||
>
|
||||
<div
|
||||
class="bg-gradient-info shadow-success border-radius-lg py-3 pe-1"
|
||||
>
|
||||
<h4
|
||||
class="text-white font-weight-bolder text-center mt-2 mb-0"
|
||||
>
|
||||
Admin Sign in
|
||||
</h4>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form role="form" class="text-start" @submit.prevent="handleLogin">
|
||||
<MaterialInput
|
||||
id="email"
|
||||
class="input-group-outline my-3"
|
||||
:label="{ text: 'Email', class: 'form-label' }"
|
||||
type="email"
|
||||
v-model="email"
|
||||
/>
|
||||
<MaterialInput
|
||||
id="password"
|
||||
class="input-group-outline mb-3"
|
||||
:label="{ text: 'Password', class: 'form-label' }"
|
||||
type="password"
|
||||
v-model="password"
|
||||
/>
|
||||
|
||||
<div class="text-center">
|
||||
<MaterialButton
|
||||
class="my-4 mb-2"
|
||||
variant="gradient"
|
||||
color="info"
|
||||
fullWidth
|
||||
@click="handleLogin"
|
||||
>
|
||||
Sign in
|
||||
</MaterialButton>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="footer position-absolute bottom-2 py-2 w-100">
|
||||
<div class="container">
|
||||
<div class="row align-items-center justify-content-lg-between">
|
||||
<div class="col-12 col-md-6 my-auto">
|
||||
<div
|
||||
class="copyright text-center text-sm text-white text-lg-start"
|
||||
>
|
||||
© {{ new Date().getFullYear() }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</Header>
|
||||
</template>
|
171
src/views/Auth/UserLogin.vue
Normal file
171
src/views/Auth/UserLogin.vue
Normal file
@ -0,0 +1,171 @@
|
||||
<script setup>
|
||||
import { onMounted } from "vue";
|
||||
|
||||
// example components
|
||||
import DefaultNavbar from "@/examples/navbars/NavbarDefault.vue";
|
||||
import Header from "@/examples/Header.vue";
|
||||
|
||||
//Vue Material Kit 2 components
|
||||
import MaterialInput from "@/components/MaterialInput.vue";
|
||||
import MaterialSwitch from "@/components/MaterialSwitch.vue";
|
||||
import MaterialButton from "@/components/MaterialButton.vue";
|
||||
|
||||
// material-input
|
||||
import setMaterialInput from "@/assets/js/material-input";
|
||||
onMounted(() => {
|
||||
setMaterialInput();
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<DefaultNavbar transparent />
|
||||
<Header>
|
||||
<div
|
||||
class="page-header align-items-start min-vh-100"
|
||||
:style="{
|
||||
backgroundImage:
|
||||
'url(https://images.unsplash.com/photo-1497294815431-9365093b7331?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1950&q=80)'
|
||||
}"
|
||||
loading="lazy"
|
||||
>
|
||||
<span class="mask bg-gradient-dark opacity-6"></span>
|
||||
<div class="container my-auto">
|
||||
<div class="row">
|
||||
<div class="col-lg-4 col-md-8 col-12 mx-auto">
|
||||
<div class="card z-index-0 fadeIn3 fadeInBottom">
|
||||
<div
|
||||
class="card-header p-0 position-relative mt-n4 mx-3 z-index-2"
|
||||
>
|
||||
<div
|
||||
class="bg-gradient-success shadow-success border-radius-lg py-3 pe-1"
|
||||
>
|
||||
<h4
|
||||
class="text-white font-weight-bolder text-center mt-2 mb-0"
|
||||
>
|
||||
Sign in
|
||||
</h4>
|
||||
<div class="row mt-3">
|
||||
<div class="col-2 text-center ms-auto">
|
||||
<a class="btn btn-link px-3" href="javascript:;">
|
||||
<i class="fa fa-facebook text-white text-lg"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-2 text-center px-1">
|
||||
<a class="btn btn-link px-3" href="javascript:;">
|
||||
<i class="fa fa-github text-white text-lg"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-2 text-center me-auto">
|
||||
<a class="btn btn-link px-3" href="javascript:;">
|
||||
<i class="fa fa-google text-white text-lg"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form role="form" class="text-start">
|
||||
<MaterialInput
|
||||
id="email"
|
||||
class="input-group-outline my-3"
|
||||
:label="{ text: 'Email', class: 'form-label' }"
|
||||
type="email"
|
||||
/>
|
||||
<MaterialInput
|
||||
id="password"
|
||||
class="input-group-outline mb-3"
|
||||
:label="{ text: 'Password', class: 'form-label' }"
|
||||
type="password"
|
||||
/>
|
||||
<MaterialSwitch
|
||||
class="d-flex align-items-center mb-3"
|
||||
id="rememberMe"
|
||||
labelClass="mb-0 ms-3"
|
||||
checked
|
||||
>Remember me</MaterialSwitch
|
||||
>
|
||||
|
||||
<div class="text-center">
|
||||
<MaterialButton
|
||||
class="my-4 mb-2"
|
||||
variant="gradient"
|
||||
color="success"
|
||||
fullWidth
|
||||
>Sign in</MaterialButton
|
||||
>
|
||||
</div>
|
||||
<p class="mt-4 text-sm text-center">
|
||||
Don't have an account?
|
||||
<a
|
||||
href="#"
|
||||
class="text-success text-gradient font-weight-bold"
|
||||
>Sign up</a
|
||||
>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="footer position-absolute bottom-2 py-2 w-100">
|
||||
<div class="container">
|
||||
<div class="row align-items-center justify-content-lg-between">
|
||||
<div class="col-12 col-md-6 my-auto">
|
||||
<div
|
||||
class="copyright text-center text-sm text-white text-lg-start"
|
||||
>
|
||||
© {{ new Date().getFullYear() }}, made with
|
||||
<i class="fa fa-heart" aria-hidden="true"></i> by
|
||||
<a
|
||||
href="https://www.creative-tim.com"
|
||||
class="font-weight-bold text-white"
|
||||
target="_blank"
|
||||
>Creative Tim</a
|
||||
>
|
||||
for a better web.
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<ul
|
||||
class="nav nav-footer justify-content-center justify-content-lg-end"
|
||||
>
|
||||
<li class="nav-item">
|
||||
<a
|
||||
href="https://www.creative-tim.com"
|
||||
class="nav-link text-white"
|
||||
target="_blank"
|
||||
>Creative Tim</a
|
||||
>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a
|
||||
href="https://www.creative-tim.com/presentation"
|
||||
class="nav-link text-white"
|
||||
target="_blank"
|
||||
>About Us</a
|
||||
>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a
|
||||
href="https://www.creative-tim.com/blog"
|
||||
class="nav-link text-white"
|
||||
target="_blank"
|
||||
>Blog</a
|
||||
>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a
|
||||
href="https://www.creative-tim.com/license"
|
||||
class="nav-link pe-0 text-white"
|
||||
target="_blank"
|
||||
>License</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</Header>
|
||||
</template>
|
Loading…
x
Reference in New Issue
Block a user