forked from verdnatura/salix-front
Login fixed
This commit is contained in:
parent
517c6c2d5f
commit
659a396fbb
|
@ -80,6 +80,12 @@ module.exports = {
|
||||||
// TypeScript
|
// TypeScript
|
||||||
quotes: ['warn', 'single', { avoidEscape: true }],
|
quotes: ['warn', 'single', { avoidEscape: true }],
|
||||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||||
|
"@typescript-eslint/unbound-method": "off",
|
||||||
|
|
||||||
|
|
||||||
|
'@typescript-eslint/no-unsafe-assignment': 'off',
|
||||||
|
'@typescript-eslint/no-unsafe-member-access': 'off',
|
||||||
|
'@typescript-eslint/no-floating-promises': 'off',
|
||||||
|
|
||||||
// allow debugger during development only
|
// allow debugger during development only
|
||||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
|
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
|
||||||
|
|
|
@ -58,6 +58,7 @@ module.exports = {
|
||||||
'^src/(.*)$': '<rootDir>/src/$1',
|
'^src/(.*)$': '<rootDir>/src/$1',
|
||||||
'^app/(.*)$': '<rootDir>/$1',
|
'^app/(.*)$': '<rootDir>/$1',
|
||||||
'^components/(.*)$': '<rootDir>/src/components/$1',
|
'^components/(.*)$': '<rootDir>/src/components/$1',
|
||||||
|
'^composables/(.*)$': '<rootDir>/src/composables/$1',
|
||||||
'^layouts/(.*)$': '<rootDir>/src/layouts/$1',
|
'^layouts/(.*)$': '<rootDir>/src/layouts/$1',
|
||||||
'^pages/(.*)$': '<rootDir>/src/pages/$1',
|
'^pages/(.*)$': '<rootDir>/src/pages/$1',
|
||||||
'^assets/(.*)$': '<rootDir>/src/assets/$1',
|
'^assets/(.*)$': '<rootDir>/src/assets/$1',
|
||||||
|
|
|
@ -107,7 +107,7 @@ module.exports = configure(function (ctx) {
|
||||||
// directives: [],
|
// directives: [],
|
||||||
|
|
||||||
// Quasar plugins
|
// Quasar plugins
|
||||||
plugins: [],
|
plugins: ['Notify'],
|
||||||
},
|
},
|
||||||
|
|
||||||
// animations: 'all', // --- includes all animations
|
// animations: 'all', // --- includes all animations
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
import { boot } from 'quasar/wrappers';
|
import { boot } from 'quasar/wrappers';
|
||||||
import axios, { AxiosInstance } from 'axios';
|
import axios, { AxiosInstance } from 'axios';
|
||||||
|
|
||||||
|
import { useSession } from 'src/composables/useSession';
|
||||||
|
const { getToken } = useSession();
|
||||||
|
|
||||||
|
|
||||||
declare module '@vue/runtime-core' {
|
declare module '@vue/runtime-core' {
|
||||||
interface ComponentCustomProperties {
|
interface ComponentCustomProperties {
|
||||||
$axios: AxiosInstance;
|
$axios: AxiosInstance;
|
||||||
|
@ -15,6 +19,22 @@ declare module '@vue/runtime-core' {
|
||||||
// for each client)
|
// for each client)
|
||||||
const api = axios.create({ baseURL: 'https://api.example.com' });
|
const api = axios.create({ baseURL: 'https://api.example.com' });
|
||||||
|
|
||||||
|
axios.interceptors.request.use(
|
||||||
|
function (context) {
|
||||||
|
const token = getToken();
|
||||||
|
|
||||||
|
if (token.length && context.headers) {
|
||||||
|
context.headers.Authorization = token;
|
||||||
|
}
|
||||||
|
|
||||||
|
return context;
|
||||||
|
},
|
||||||
|
function (error) {
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
export default boot(({ app }) => {
|
export default boot(({ app }) => {
|
||||||
// for use inside Vue files (Options API) through this.$axios and this.$api
|
// for use inside Vue files (Options API) through this.$axios and this.$api
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
<template>
|
||||||
|
<q-header class="bg-dark" color="white" elevated bordered>
|
||||||
|
<q-toolbar class="q-py-sm q-px-md">
|
||||||
|
<q-btn flat @click="$emit('on-toggle-drawer')" round dense icon="menu" />
|
||||||
|
<router-link to="/">
|
||||||
|
<q-btn flat round class="q-ml-xs" v-if="$q.screen.gt.xs">
|
||||||
|
<q-avatar square size="md">
|
||||||
|
<q-img src="~/assets/logo_icon.svg" alt="Logo" />
|
||||||
|
</q-avatar>
|
||||||
|
</q-btn>
|
||||||
|
</router-link>
|
||||||
|
<q-toolbar-title shrink class="text-weight-bold">Salix</q-toolbar-title>
|
||||||
|
<q-space></q-space>
|
||||||
|
<div class="q-pl-sm q-gutter-sm row items-center no-wrap">
|
||||||
|
<q-btn v-if="$q.screen.gt.xs" dense flat size="md" icon="add">
|
||||||
|
<q-icon name="arrow_drop_down" size="s" />
|
||||||
|
<q-menu>
|
||||||
|
<q-list style="min-width: 150px">
|
||||||
|
<q-item clickable>
|
||||||
|
<q-item-section>New customer</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
<q-item clickable>
|
||||||
|
<q-item-section>New ticket</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-menu>
|
||||||
|
</q-btn>
|
||||||
|
<q-btn v-if="$q.screen.gt.xs" dense flat round size="md" icon="notifications" />
|
||||||
|
<q-btn dense flat no-wrap>
|
||||||
|
<q-avatar size="lg">
|
||||||
|
<q-img
|
||||||
|
:src="`/api/Images/user/160x160/${user.id}/download?access_token=${token}`"
|
||||||
|
spinner-color="white"
|
||||||
|
/>
|
||||||
|
</q-avatar>
|
||||||
|
<q-tooltip>Account</q-tooltip>
|
||||||
|
<q-icon name="arrow_drop_down" size="s" />
|
||||||
|
<UserPanel />
|
||||||
|
</q-btn>
|
||||||
|
</div>
|
||||||
|
</q-toolbar>
|
||||||
|
</q-header>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { useState } from 'src/composables/useState';
|
||||||
|
import { useSession } from 'src/composables/useSession';
|
||||||
|
import UserPanel from 'src/components/UserPanel.vue';
|
||||||
|
|
||||||
|
const session = useSession();
|
||||||
|
const state = useState();
|
||||||
|
const user = state.getUser();
|
||||||
|
const token = session.getToken();
|
||||||
|
</script>
|
|
@ -0,0 +1,104 @@
|
||||||
|
<template>
|
||||||
|
<q-menu>
|
||||||
|
<div class="row no-wrap q-pa-md">
|
||||||
|
<div class="column">
|
||||||
|
<div class="text-h6 q-mb-md">{{ t('components.userPanel.settings') }}</div>
|
||||||
|
<q-toggle
|
||||||
|
:label="t(`globals.lang['${locale}']`)"
|
||||||
|
icon="public"
|
||||||
|
color="orange"
|
||||||
|
false-value="es"
|
||||||
|
true-value="en"
|
||||||
|
v-model="locale"
|
||||||
|
/>
|
||||||
|
<q-toggle
|
||||||
|
v-model="darkMode"
|
||||||
|
checked-icon="dark_mode"
|
||||||
|
color="orange"
|
||||||
|
unchecked-icon="light_mode"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<q-btn color="orange" outline size="sm" label="Settings" icon="settings" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<q-separator vertical inset class="q-mx-lg" />
|
||||||
|
|
||||||
|
<div class="column items-center" style="min-width: 150px">
|
||||||
|
<q-avatar size="80px">
|
||||||
|
<q-img
|
||||||
|
:src="`/api/Images/user/160x160/${user.id}/download?access_token=${token}`"
|
||||||
|
spinner-color="white"
|
||||||
|
/>
|
||||||
|
</q-avatar>
|
||||||
|
|
||||||
|
<div class="text-subtitle1 q-mt-md">
|
||||||
|
<strong>{{ user.nickname }}</strong>
|
||||||
|
</div>
|
||||||
|
<div class="text-subtitle3 text-grey-7 q-mb-xs">@{{ user.username }}</div>
|
||||||
|
|
||||||
|
<q-btn
|
||||||
|
color="orange"
|
||||||
|
flat
|
||||||
|
label="Log Out"
|
||||||
|
size="sm"
|
||||||
|
icon="logout"
|
||||||
|
@click="logout()"
|
||||||
|
v-close-popup
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</q-menu>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { onMounted, computed } from 'vue';
|
||||||
|
import { Dark, useQuasar } from 'quasar';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
import { useState } from 'src/composables/useState';
|
||||||
|
import { useSession } from 'src/composables/useSession';
|
||||||
|
|
||||||
|
const quasar = useQuasar();
|
||||||
|
const state = useState();
|
||||||
|
const session = useSession();
|
||||||
|
const router = useRouter();
|
||||||
|
const { t, locale } = useI18n();
|
||||||
|
|
||||||
|
const darkMode = computed({
|
||||||
|
get(): boolean {
|
||||||
|
return Dark.isActive;
|
||||||
|
},
|
||||||
|
set(value: boolean): void {
|
||||||
|
Dark.set(value);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const user = state.getUser();
|
||||||
|
const token = session.getToken();
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
axios
|
||||||
|
.get('/api/accounts/acl')
|
||||||
|
.then(({ data }) => {
|
||||||
|
state.setUser({
|
||||||
|
id: data.user.id,
|
||||||
|
username: data.user.name,
|
||||||
|
nickname: data.user.nickname,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
quasar.notify({
|
||||||
|
message: t('errors.statusUnauthorized'),
|
||||||
|
type: 'negative',
|
||||||
|
});
|
||||||
|
logout();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function logout(): void {
|
||||||
|
session.destroy();
|
||||||
|
router.push('/login');
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -1,4 +1,4 @@
|
||||||
import store from '@/store';
|
/* import store from '@/store';
|
||||||
|
|
||||||
export function useRole() {
|
export function useRole() {
|
||||||
function hasAny(roles: string[]): boolean {
|
function hasAny(roles: string[]): boolean {
|
||||||
|
@ -15,3 +15,4 @@ export function useRole() {
|
||||||
hasAny,
|
hasAny,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
*/
|
|
@ -2,6 +2,31 @@
|
||||||
// so you can safely delete all default props below
|
// so you can safely delete all default props below
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
failed: 'Action failed',
|
'globals': {
|
||||||
success: 'Action was successful',
|
'lang': {
|
||||||
|
'es': 'Spanish',
|
||||||
|
'en': 'English'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'errors': {
|
||||||
|
'statusUnauthorized': 'Access denied',
|
||||||
|
'statusInternalServerError': 'An internal server error has ocurred'
|
||||||
|
},
|
||||||
|
'login': {
|
||||||
|
'title': 'Login',
|
||||||
|
'username': 'Username',
|
||||||
|
'password': 'Password',
|
||||||
|
'submit': 'Log in',
|
||||||
|
'keepLogin': 'Keep me logged in',
|
||||||
|
'loginSuccess': 'You have successfully logged in',
|
||||||
|
'loginError': 'Invalid username or password'
|
||||||
|
},
|
||||||
|
'customer': {},
|
||||||
|
'components': {
|
||||||
|
'topbar': {},
|
||||||
|
'userPanel': {
|
||||||
|
'settings': 'Settings',
|
||||||
|
'logOut': 'Log Out'
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
export default {
|
||||||
|
'globals': {
|
||||||
|
'lang': {
|
||||||
|
'es': 'Español',
|
||||||
|
'en': 'Inglés'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'errors': {
|
||||||
|
'statusUnauthorized': 'Acceso denegado',
|
||||||
|
'statusInternalServerError': 'Ha ocurrido un error interno del servidor'
|
||||||
|
},
|
||||||
|
'login': {
|
||||||
|
'title': 'Iniciar sesión',
|
||||||
|
'username': 'Nombre de usuario',
|
||||||
|
'password': 'Contraseña',
|
||||||
|
'submit': 'Iniciar sesión',
|
||||||
|
'keepLogin': 'Mantener sesión iniciada',
|
||||||
|
'loginSuccess': 'Inicio de sesión correcto',
|
||||||
|
'loginError': 'Nombre de usuario o contraseña incorrectos'
|
||||||
|
},
|
||||||
|
'customer': {},
|
||||||
|
'components': {
|
||||||
|
'topbar': {},
|
||||||
|
'userPanel': {
|
||||||
|
'settings': 'Configuración',
|
||||||
|
'logOut': 'Cerrar sesión'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
import en from './en';
|
import en from './en';
|
||||||
|
import es from './es';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
'en': en,
|
'en': en,
|
||||||
|
'es': es,
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,30 +13,40 @@
|
||||||
>
|
>
|
||||||
<q-scroll-area class="fit text-grey-8">
|
<q-scroll-area class="fit text-grey-8">
|
||||||
<q-list padding>
|
<q-list padding>
|
||||||
<q-item clickable v-ripple :to="{ path: '/dashboard' }" active-class="text-orange">
|
<q-item
|
||||||
|
clickable
|
||||||
|
v-ripple
|
||||||
|
:to="{ path: '/dashboard' }"
|
||||||
|
active-class="text-orange"
|
||||||
|
>
|
||||||
<q-item-section avatar>
|
<q-item-section avatar>
|
||||||
<q-icon name="dashboard" />
|
<q-icon name="dashboard" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section> Dashboard</q-item-section>
|
<q-item-section>Dashboard</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-item clickable v-ripple :to="{ path: '/customer' }" active-class="text-orange">
|
<q-item
|
||||||
|
clickable
|
||||||
|
v-ripple
|
||||||
|
:to="{ path: '/customer' }"
|
||||||
|
active-class="text-orange"
|
||||||
|
>
|
||||||
<q-item-section avatar>
|
<q-item-section avatar>
|
||||||
<q-icon name="people" />
|
<q-icon name="people" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section> Customers </q-item-section>
|
<q-item-section>Customers</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-item clickable v-ripple :to="{ path: '/ticket' }" active-class="text-orange">
|
<q-item clickable v-ripple :to="{ path: '/ticket' }" active-class="text-orange">
|
||||||
<q-item-section avatar>
|
<q-item-section avatar>
|
||||||
<q-icon name="vn:ticket" />
|
<q-icon name="vn:ticket" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section> Tickets </q-item-section>
|
<q-item-section>Tickets</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-item clickable v-ripple>
|
<q-item clickable v-ripple>
|
||||||
<q-item-section avatar>
|
<q-item-section avatar>
|
||||||
<q-icon name="receipt" />
|
<q-icon name="receipt" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
|
|
||||||
<q-item-section> Invoice Out </q-item-section>
|
<q-item-section>Invoice Out</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
|
|
||||||
<q-item clickable v-ripple>
|
<q-item clickable v-ripple>
|
||||||
|
@ -44,7 +54,7 @@
|
||||||
<q-icon name="shopping_cart" />
|
<q-icon name="shopping_cart" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
|
|
||||||
<q-item-section> Catalog </q-item-section>
|
<q-item-section>Catalog</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
|
|
||||||
<q-separator />
|
<q-separator />
|
||||||
|
@ -54,7 +64,7 @@
|
||||||
<q-icon name="drafts" />
|
<q-icon name="drafts" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
|
|
||||||
<q-item-section> Drafts </q-item-section>
|
<q-item-section>Drafts</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
</q-list>
|
</q-list>
|
||||||
</q-scroll-area>
|
</q-scroll-area>
|
||||||
|
@ -67,7 +77,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import Topbar from '@/components/Topbar.vue';
|
import Topbar from 'src/components/Topbar.vue';
|
||||||
const drawer = ref(false);
|
const drawer = ref(false);
|
||||||
const miniState = ref(true);
|
const miniState = ref(true);
|
||||||
|
|
||||||
|
@ -77,7 +87,4 @@ function onToggleDrawer(): void {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.bg-darker {
|
|
||||||
background-color: $darker;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -23,7 +23,13 @@
|
||||||
<q-page>
|
<q-page>
|
||||||
<div id="login">
|
<div id="login">
|
||||||
<q-card class="login q-pa-xl">
|
<q-card class="login q-pa-xl">
|
||||||
<img src="@/assets/logo.svg" alt="Logo" class="logo q-mb-xl" />
|
<q-img
|
||||||
|
src="~/assets/logo.svg"
|
||||||
|
alt="Logo"
|
||||||
|
fit="contain"
|
||||||
|
:ratio="16 / 9"
|
||||||
|
class="q-mb-md"
|
||||||
|
/>
|
||||||
<q-form @submit="onSubmit" class="q-gutter-md">
|
<q-form @submit="onSubmit" class="q-gutter-md">
|
||||||
<q-input
|
<q-input
|
||||||
filled
|
filled
|
||||||
|
@ -70,7 +76,7 @@ import { useI18n } from 'vue-i18n';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
import { useSession } from '/components/Session';
|
import { useSession } from 'src/composables/useSession';
|
||||||
|
|
||||||
const quasar = useQuasar();
|
const quasar = useQuasar();
|
||||||
const session = useSession();
|
const session = useSession();
|
||||||
|
@ -90,15 +96,14 @@ const darkMode = computed({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
function onSubmit(): void {
|
async function onSubmit(): Promise<void> {
|
||||||
axios
|
try {
|
||||||
.post('/api/accounts/login', {
|
const { data } = await axios.post('/api/accounts/login', {
|
||||||
user: username.value,
|
user: username.value,
|
||||||
password: password.value,
|
password: password.value,
|
||||||
})
|
});
|
||||||
.then((response) => {
|
|
||||||
session.setToken({
|
session.setToken({
|
||||||
token: response.data.token,
|
token: data.token,
|
||||||
keepLogin: keepLogin.value,
|
keepLogin: keepLogin.value,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -106,22 +111,23 @@ function onSubmit(): void {
|
||||||
message: t('login.loginSuccess'),
|
message: t('login.loginSuccess'),
|
||||||
type: 'positive',
|
type: 'positive',
|
||||||
});
|
});
|
||||||
router.push('/dashboard');
|
await router.push({ path: '/dashboard' });
|
||||||
})
|
} catch (error) {
|
||||||
.catch((error) => {
|
if (axios.isAxiosError(error)) {
|
||||||
const errorCode = error.response.status;
|
const errorCode = error.response && error.response.status;
|
||||||
if (errorCode === 401) {
|
if (errorCode === 401) {
|
||||||
quasar.notify({
|
quasar.notify({
|
||||||
message: t('login.loginFailed'),
|
message: t('login.loginFailed'),
|
||||||
type: 'negative',
|
type: 'negative',
|
||||||
});
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
quasar.notify({
|
quasar.notify({
|
||||||
message: t('errors.statusInternalServerError'),
|
message: t('errors.statusInternalServerError'),
|
||||||
type: 'negative',
|
type: 'negative',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,8 @@ import {
|
||||||
createWebHistory,
|
createWebHistory,
|
||||||
} from 'vue-router';
|
} from 'vue-router';
|
||||||
import routes from './routes';
|
import routes from './routes';
|
||||||
|
import { useSession } from 'src/composables/useSession';
|
||||||
|
const session = useSession();
|
||||||
/*
|
/*
|
||||||
* If not building with SSR mode, you can
|
* If not building with SSR mode, you can
|
||||||
* directly export the Router instantiation;
|
* directly export the Router instantiation;
|
||||||
|
@ -35,5 +36,16 @@ export default route(function (/* { store, ssrContext } */) {
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Router.beforeEach((to, from, next) => {
|
||||||
|
|
||||||
|
const { isLoggedIn } = session;
|
||||||
|
|
||||||
|
if (!isLoggedIn && to.name !== 'Login') {
|
||||||
|
next({ path: '/login', query: { redirect: to.fullPath } });
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return Router;
|
return Router;
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,7 +9,7 @@ const routes: RouteRecordRaw[] = [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
name: 'Main',
|
name: 'Main',
|
||||||
component: () => import('../Layout/Main.vue'),
|
component: () => import('../layouts/Main.vue'),
|
||||||
redirect: { name: 'Dashboard' },
|
redirect: { name: 'Dashboard' },
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
|
@ -38,7 +38,7 @@ const routes: RouteRecordRaw[] = [
|
||||||
{
|
{
|
||||||
path: '/:pathMatch(.*)*',
|
path: '/:pathMatch(.*)*',
|
||||||
name: 'NotFound',
|
name: 'NotFound',
|
||||||
component: () => import('../pages/Layout/NotFound.vue'),
|
component: () => import('../pages/NotFound.vue'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue