457 lines
12 KiB
JavaScript
457 lines
12 KiB
JavaScript
import { createRouter, createWebHistory } from 'vue-router'
|
|
import { useAuthStore } from '@/stores/auth'
|
|
|
|
const routes = [
|
|
{
|
|
path: '/',
|
|
redirect: '/dashboard'
|
|
},
|
|
{
|
|
path: '/login',
|
|
name: 'Login',
|
|
component: () => import('@/views/auth/LoginView.vue'),
|
|
meta: { requiresGuest: true }
|
|
},
|
|
{
|
|
path: '/register',
|
|
name: 'Register',
|
|
component: () => import('@/views/auth/RegisterView.vue'),
|
|
meta: { requiresGuest: true }
|
|
},
|
|
{
|
|
path: '/forgot-password',
|
|
name: 'ForgotPassword',
|
|
component: () => import('@/views/auth/ForgotPasswordView.vue'),
|
|
meta: { requiresGuest: true }
|
|
},
|
|
{
|
|
path: '/reset-password',
|
|
name: 'ResetPassword',
|
|
component: () => import('@/views/auth/ResetPasswordView.vue'),
|
|
meta: { requiresGuest: true }
|
|
},
|
|
{
|
|
path: '/dashboard',
|
|
name: 'Dashboard',
|
|
component: () => import('@/views/dashboard/DashboardView.vue')
|
|
// meta: { requiresAuth: true }
|
|
},
|
|
{
|
|
path: '/work-orders',
|
|
name: 'WorkOrders',
|
|
component: () => import('@/views/workorders/WorkOrdersView.vue'),
|
|
// meta: { requiresAuth: true },
|
|
children: [
|
|
{
|
|
path: '',
|
|
name: 'WorkOrdersList',
|
|
component: () => import('@/views/workorders/WorkOrdersListView.vue')
|
|
},
|
|
{
|
|
path: 'create',
|
|
name: 'CreateWorkOrder',
|
|
component: () => import('@/views/workorders/CreateWorkOrderView.vue')
|
|
},
|
|
{
|
|
path: ':id',
|
|
name: 'WorkOrderDetail',
|
|
component: () => import('@/views/workorders/WorkOrderDetailView.vue'),
|
|
props: true
|
|
},
|
|
{
|
|
path: ':id/edit',
|
|
name: 'EditWorkOrder',
|
|
component: () => import('@/views/workorders/EditWorkOrderView.vue'),
|
|
props: true
|
|
},
|
|
{
|
|
path: 'calendar',
|
|
name: 'WorkOrdersCalendar',
|
|
component: () => import('@/views/workorders/WorkOrdersCalendarView.vue')
|
|
}
|
|
]
|
|
},
|
|
{
|
|
path: '/assets',
|
|
name: 'Assets',
|
|
component: () => import('@/views/assets/AssetsView.vue'),
|
|
// meta: { requiresAuth: true }, // Removed for development access
|
|
children: [
|
|
{
|
|
path: '',
|
|
name: 'AssetsList',
|
|
component: () => import('@/views/assets/AssetsListView.vue')
|
|
},
|
|
{
|
|
path: 'create',
|
|
name: 'CreateAsset',
|
|
component: () => import('@/views/assets/CreateAssetView.vue')
|
|
},
|
|
{
|
|
path: ':id',
|
|
name: 'AssetDetail',
|
|
component: () => import('@/views/assets/AssetDetailView.vue'),
|
|
props: true
|
|
},
|
|
{
|
|
path: ':id/edit',
|
|
name: 'EditAsset',
|
|
component: () => import('@/views/assets/EditAssetView.vue'),
|
|
props: true
|
|
}
|
|
]
|
|
},
|
|
{
|
|
path: '/locations',
|
|
name: 'Locations',
|
|
component: () => import('@/views/locations/LocationsView.vue'),
|
|
// meta: { requiresAuth: true },
|
|
children: [
|
|
{
|
|
path: '',
|
|
name: 'LocationsList',
|
|
component: () => import('@/views/locations/LocationsListView.vue')
|
|
},
|
|
{
|
|
path: ':id',
|
|
name: 'LocationDetail',
|
|
component: () => import('@/views/locations/LocationDetailView.vue'),
|
|
props: true
|
|
}
|
|
]
|
|
},
|
|
{
|
|
path: '/people',
|
|
name: 'People',
|
|
component: () => import('@/views/people/PeopleView.vue'),
|
|
// meta: { requiresAuth: true, requiresPermission: 'PEOPLE_AND_TEAMS:VIEW' },
|
|
children: [
|
|
{
|
|
path: '',
|
|
name: 'PeopleList',
|
|
component: () => import('@/views/people/PeopleListView.vue')
|
|
},
|
|
{
|
|
path: 'teams',
|
|
name: 'TeamsList',
|
|
component: () => import('@/views/people/TeamsListView.vue')
|
|
}
|
|
]
|
|
},
|
|
{
|
|
path: '/inventory',
|
|
name: 'Inventory',
|
|
component: () => import('@/views/inventory/InventoryView.vue')
|
|
// meta: { requiresAuth: true }
|
|
},
|
|
{
|
|
path: '/inventory/parts',
|
|
name: 'Parts',
|
|
component: () => import('@/views/inventory/PartsView.vue'),
|
|
// meta: { requiresAuth: true },
|
|
children: [
|
|
{
|
|
path: '',
|
|
name: 'PartsList',
|
|
component: () => import('@/views/inventory/PartsListView.vue')
|
|
},
|
|
{
|
|
path: ':id',
|
|
name: 'PartDetail',
|
|
component: () => import('@/views/inventory/PartDetailView.vue'),
|
|
props: true
|
|
}
|
|
]
|
|
},
|
|
{
|
|
path: '/inventory/stock-alerts',
|
|
name: 'StockAlerts',
|
|
component: () => import('@/views/inventory/StockAlertsView.vue')
|
|
// meta: { requiresAuth: true }
|
|
},
|
|
{
|
|
path: '/inventory/transfers',
|
|
name: 'InventoryTransfers',
|
|
component: () => import('@/views/inventory/InventoryTransfersView.vue')
|
|
// meta: { requiresAuth: true }
|
|
},
|
|
{
|
|
path: '/maintenance',
|
|
name: 'Maintenance',
|
|
component: () => import('@/views/maintenance/MaintenanceView.vue')
|
|
// meta: { requiresAuth: true }
|
|
},
|
|
{
|
|
path: '/maintenance/preventive',
|
|
name: 'PreventiveMaintenance',
|
|
component: () => import('@/views/maintenance/PreventiveMaintenanceView.vue'),
|
|
// meta: { requiresAuth: true },
|
|
children: [
|
|
{
|
|
path: '',
|
|
name: 'PreventiveMaintenanceList',
|
|
component: () => import('@/views/maintenance/PreventiveMaintenanceListView.vue')
|
|
},
|
|
{
|
|
path: ':id',
|
|
name: 'PreventiveMaintenanceDetail',
|
|
component: () => import('@/views/maintenance/PreventiveMaintenanceDetailView.vue'),
|
|
props: true
|
|
}
|
|
]
|
|
},
|
|
{
|
|
path: '/reports',
|
|
name: 'Reports',
|
|
component: () => import('@/views/reports/ReportsView.vue')
|
|
// meta: { requiresAuth: true }
|
|
},
|
|
{
|
|
path: '/categories',
|
|
name: 'Categories',
|
|
component: () => import('@/views/categories/CategoriesView.vue'),
|
|
// meta: { requiresAuth: true },
|
|
children: [
|
|
{
|
|
path: '',
|
|
name: 'CategoriesIndex',
|
|
component: () => import('@/views/categories/CategoriesIndexView.vue')
|
|
},
|
|
{
|
|
path: 'work-order-categories',
|
|
name: 'WorkOrderCategories',
|
|
component: () => import('@/views/categories/CategoriesListView.vue'),
|
|
props: { categoryType: 'work-order-categories' }
|
|
},
|
|
{
|
|
path: 'asset-categories',
|
|
name: 'AssetCategories',
|
|
component: () => import('@/views/categories/CategoriesListView.vue'),
|
|
props: { categoryType: 'asset-categories' }
|
|
},
|
|
{
|
|
path: 'part-categories',
|
|
name: 'PartCategories',
|
|
component: () => import('@/views/categories/CategoriesListView.vue'),
|
|
props: { categoryType: 'part-categories' }
|
|
},
|
|
{
|
|
path: 'cost-categories',
|
|
name: 'CostCategories',
|
|
component: () => import('@/views/categories/CategoriesListView.vue'),
|
|
props: { categoryType: 'cost-categories' }
|
|
},
|
|
{
|
|
path: 'meter-categories',
|
|
name: 'MeterCategories',
|
|
component: () => import('@/views/categories/CategoriesListView.vue'),
|
|
props: { categoryType: 'meter-categories' }
|
|
},
|
|
{
|
|
path: 'purchase-order-categories',
|
|
name: 'PurchaseOrderCategories',
|
|
component: () => import('@/views/categories/CategoriesListView.vue'),
|
|
props: { categoryType: 'purchase-order-categories' }
|
|
}
|
|
]
|
|
},
|
|
{
|
|
path: '/vendors',
|
|
name: 'Vendors',
|
|
component: () => import('@/views/vendors/VendorsView.vue'),
|
|
// meta: { requiresAuth: true },
|
|
children: [
|
|
{
|
|
path: '',
|
|
name: 'VendorsList',
|
|
component: () => import('@/views/vendors/VendorsListView.vue')
|
|
},
|
|
{
|
|
path: ':id',
|
|
name: 'VendorDetail',
|
|
component: () => import('@/views/vendors/VendorDetailView.vue'),
|
|
props: true
|
|
}
|
|
]
|
|
},
|
|
{
|
|
path: '/requests',
|
|
name: 'Requests',
|
|
component: () => import('@/views/requests/RequestsView.vue'),
|
|
// meta: { requiresAuth: true },
|
|
children: [
|
|
{
|
|
path: '',
|
|
name: 'RequestsList',
|
|
component: () => import('@/views/requests/RequestsListView.vue')
|
|
},
|
|
{
|
|
path: ':id',
|
|
name: 'RequestDetail',
|
|
component: () => import('@/views/requests/RequestDetailView.vue'),
|
|
props: true
|
|
}
|
|
]
|
|
},
|
|
{
|
|
path: '/meters',
|
|
name: 'Meters',
|
|
component: () => import('@/views/meters/MetersView.vue'),
|
|
// meta: { requiresAuth: true },
|
|
children: [
|
|
{
|
|
path: '',
|
|
name: 'MetersList',
|
|
component: () => import('@/views/meters/MetersListView.vue')
|
|
},
|
|
{
|
|
path: ':id',
|
|
name: 'MeterDetail',
|
|
component: () => import('@/views/meters/MeterDetailView.vue'),
|
|
props: true
|
|
}
|
|
]
|
|
},
|
|
{
|
|
path: '/customers',
|
|
name: 'Customers',
|
|
component: () => import('@/views/customers/CustomersView.vue'),
|
|
// meta: { requiresAuth: true },
|
|
children: [
|
|
{
|
|
path: '',
|
|
name: 'CustomersList',
|
|
component: () => import('@/views/customers/CustomersListView.vue')
|
|
},
|
|
{
|
|
path: ':id',
|
|
name: 'CustomerDetail',
|
|
component: () => import('@/views/customers/CustomerDetailView.vue'),
|
|
props: true
|
|
}
|
|
]
|
|
},
|
|
{
|
|
path: '/contracts',
|
|
name: 'Contracts',
|
|
component: () => import('@/views/contracts/ContractsView.vue'),
|
|
// meta: { requiresAuth: true },
|
|
children: [
|
|
{
|
|
path: '',
|
|
name: 'ContractsList',
|
|
component: () => import('@/views/contracts/ContractsListView.vue')
|
|
},
|
|
{
|
|
path: ':id',
|
|
name: 'ContractDetail',
|
|
component: () => import('@/views/contracts/ContractDetailView.vue'),
|
|
props: true
|
|
}
|
|
]
|
|
},
|
|
{
|
|
path: '/settings',
|
|
name: 'Settings',
|
|
component: () => import('@/views/settings/SettingsView.vue')
|
|
// meta: { requiresAuth: true, requiresRole: ['ADMIN', 'MANAGER'] }
|
|
},
|
|
{
|
|
path: '/profile',
|
|
name: 'Profile',
|
|
component: () => import('@/views/settings/ProfileView.vue')
|
|
// meta: { requiresAuth: true }
|
|
},
|
|
{
|
|
path: '/demo',
|
|
name: 'FrappeUIDemo',
|
|
component: () => import('@/views/demo/FrappeUIDemo.vue')
|
|
},
|
|
{
|
|
path: '/simple-demo',
|
|
name: 'SimpleDemo',
|
|
component: () => import('@/views/demo/SimpleDemo.vue')
|
|
},
|
|
{
|
|
path: '/basic-test',
|
|
name: 'BasicTest',
|
|
component: () => import('@/views/demo/BasicTest.vue')
|
|
},
|
|
{
|
|
path: '/theme-test',
|
|
name: 'ThemeTest',
|
|
component: () => import('@/views/demo/ThemeTest.vue')
|
|
},
|
|
{
|
|
path: '/unauthorized',
|
|
name: 'Unauthorized',
|
|
component: () => import('@/views/UnauthorizedView.vue')
|
|
},
|
|
{
|
|
path: '/:pathMatch(.*)*',
|
|
name: 'NotFound',
|
|
component: () => import('@/views/NotFoundView.vue')
|
|
}
|
|
]
|
|
|
|
const router = createRouter({
|
|
history: createWebHistory(),
|
|
routes
|
|
})
|
|
|
|
router.beforeEach(async (to, from, next) => {
|
|
const authStore = useAuthStore()
|
|
|
|
if (to.meta.requiresAuth) {
|
|
if (!authStore.isAuthenticated) {
|
|
next('/login')
|
|
return
|
|
}
|
|
|
|
if (!authStore.user) {
|
|
try {
|
|
await authStore.getCurrentUser()
|
|
} catch (error) {
|
|
console.error('Failed to get current user:', error)
|
|
next('/login')
|
|
return
|
|
}
|
|
}
|
|
|
|
if (to.meta.requiresRole) {
|
|
const userRole = authStore.userRole
|
|
const allowedRoles = Array.isArray(to.meta.requiresRole)
|
|
? to.meta.requiresRole
|
|
: [to.meta.requiresRole]
|
|
|
|
if (!allowedRoles.includes(userRole)) {
|
|
next('/unauthorized')
|
|
return
|
|
}
|
|
}
|
|
|
|
if (to.meta.requiresPermission) {
|
|
const requiredPermissions = Array.isArray(to.meta.requiresPermission)
|
|
? to.meta.requiresPermission
|
|
: [to.meta.requiresPermission]
|
|
|
|
const hasPermission = requiredPermissions.every(permission =>
|
|
authStore.hasPermission(permission)
|
|
)
|
|
|
|
if (!hasPermission) {
|
|
next('/unauthorized')
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
if (to.meta.requiresGuest && authStore.isAuthenticated) {
|
|
next('/dashboard')
|
|
return
|
|
}
|
|
|
|
next()
|
|
})
|
|
|
|
export default router |