-
+
+
+
+
+
+
HR Manager
+ Sistema de RRHH
+
-
-
-
- © {{year}} {{ APP_COPYRIGHT }}
-
-
- APP {{ APP_VERSION }} API {{ $page.app.version }}
+
+
+ © {{ year }} {{ APP_COPYRIGHT }}
+
+
+ APP {{ APP_VERSION }} API {{ $page.app.version }}
diff --git a/src/index.js b/src/index.js
index 2bef60a..c62b0fc 100644
--- a/src/index.js
+++ b/src/index.js
@@ -12,6 +12,9 @@ import TailwindScreen from '@Plugins/TailwindScreen'
import { pagePlugin } from '@Services/Page';
import { defineApp, reloadApp, view } from '@Services/Page';
import { apiURL } from '@Services/Api';
+import VueApexCharts from "vue3-apexcharts";
+import VCalendar from 'v-calendar'
+import 'v-calendar/style.css';
import App from '@Components/App.vue'
import Error503 from '@Pages/Errors/503.vue'
@@ -63,6 +66,8 @@ async function boot() {
.use(pagePlugin)
.use(router)
.use(ZiggyVue)
+ .use(VCalendar, {})
+ .use(VueApexCharts)
.mount('#app');
} else {
createApp(Error503)
diff --git a/src/layouts/AdminLayout.vue b/src/layouts/AdminLayout.vue
new file mode 100644
index 0000000..b26aa69
--- /dev/null
+++ b/src/layouts/AdminLayout.vue
@@ -0,0 +1,135 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/layouts/AppLayout.vue b/src/layouts/AppLayout.vue
index d33531b..01c79b2 100644
--- a/src/layouts/AppLayout.vue
+++ b/src/layouts/AppLayout.vue
@@ -1,7 +1,6 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/layouts/RhLayout.vue b/src/layouts/RhLayout.vue
deleted file mode 100644
index d9805de..0000000
--- a/src/layouts/RhLayout.vue
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/pages/Courses/Assignamment.vue b/src/pages/Courses/Assignamment.vue
new file mode 100644
index 0000000..c354288
--- /dev/null
+++ b/src/pages/Courses/Assignamment.vue
@@ -0,0 +1,281 @@
+
+
+
+
+
+
+
+
+
Asigna cursos aprobados al personal seleccionado
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ course.name }}
+
+ {{ course.area }} • {{ formatCurrency(course.cost) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ selectedPersonnelCount }} persona(s) seleccionada(s)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/Courses/Calendar.vue b/src/pages/Courses/Calendar.vue
new file mode 100644
index 0000000..0f149c3
--- /dev/null
+++ b/src/pages/Courses/Calendar.vue
@@ -0,0 +1,411 @@
+
+
+
+
+
Calendario de Cursos Programados
+
+
+
+
+
+
{{ getCurrentMonthInfo.totalCursos }} Cursos
+
+
+
+
{{ getCurrentMonthInfo.totalExamenes }} Exámenes
+
+
+
+
+
+
+
+
+
+ Vista Mensual
+
+
+
+
+
+
+
+
+ {{ formatMonth(selectedDate) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/pages/Courses/Index.vue b/src/pages/Courses/Index.vue
new file mode 100644
index 0000000..e3724db
--- /dev/null
+++ b/src/pages/Courses/Index.vue
@@ -0,0 +1,187 @@
+
+
+
+
+
+
+
+
+
Administra y aprueba las solicitudes de cursos de capacitación
+
+
+
+
+
+
+
+
+
+
+ | Área |
+ Nombre del Curso |
+ Costo Unitario |
+ Url |
+ Opciones |
+
+
+
+
+
+ |
+
+ {{ course.area }}
+
+ |
+
+
+
+
+ {{ course.courseName }}
+
+ |
+
+
+
+
+ {{ formatCurrency(course.unitCost) }}
+
+ |
+
+
+
+
+ Ver curso
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+ Mostrando {{ courses.length }} solicitudes
+
+
+
+
+
+ Pendientes: {{ courses.filter(c => c.status === 'pending').length }}
+
+
+
+ Aprobadas: {{ courses.filter(c => c.status === 'approved').length }}
+
+
+
+ Rechazadas: {{ courses.filter(c => c.status === 'rejected').length }}
+
+
+
+
+
+
diff --git a/src/pages/Courses/Request.vue b/src/pages/Courses/Request.vue
new file mode 100644
index 0000000..27149d2
--- /dev/null
+++ b/src/pages/Courses/Request.vue
@@ -0,0 +1,232 @@
+
+
+
+
+
+
+
+
+
Completa la información para solicitar un nuevo curso de capacitación
+
+
+
+
+
+
+
diff --git a/src/pages/Dashboard/Admin.vue b/src/pages/Dashboard/Admin.vue
new file mode 100644
index 0000000..8985870
--- /dev/null
+++ b/src/pages/Dashboard/Admin.vue
@@ -0,0 +1,274 @@
+
+
+
+
+
+
+
+
+ Bienvenido, {{ $page.user.name }}
+
+
+ Administra el sistema de vacaciones y supervisa el rendimiento organizacional.
+
+
+
+
+
+
+
+
+
+
+
+
+
Total Empleados
+
{{ adminInfo.total_users }}
+
+
+
+
+
+
+
+
+
+
+
+
Solicitudes Este Mes
+
{{ adminInfo.monthly_requests }}
+
+
+
+
+
+
+
+
+
+
+
+
Solicitudes Aprobadas
+
{{ adminInfo.approved_requests }}
+
+
+
+
+
+
+
+
+
+
+
+
Eficiencia Aprobación
+
{{ adminInfo.approval_efficiency }}%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Solicitudes por Mes
+
Tendencia de solicitudes durante el año
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Solicitudes por Departamento
+
Distribución de solicitudes por área
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No hay datos de gráficos disponibles
+
+
+ Los gráficos se mostrarán cuando haya datos de solicitudes disponibles.
+
+
+
+
+
diff --git a/src/pages/Dashboard/Coordinator.vue b/src/pages/Dashboard/Coordinator.vue
new file mode 100644
index 0000000..d13379b
--- /dev/null
+++ b/src/pages/Dashboard/Coordinator.vue
@@ -0,0 +1,341 @@
+
+
+
+
+
+
+
+
+ Bienvenido, {{ $page.user.name }}
+
+
+ Coordina y gestiona las solicitudes de vacaciones de tu equipo.
+
+
+
+
+
+ Gestión del Equipo
+
+
+
+
+
+
+
+
+
+
+
Solicitudes Pendientes
+
{{ coordinatorInfo.pending_requests }}
+
+
+
+
+
+
+
+
+
+
+
+
Conflictos Detectados
+
{{ coordinatorInfo.conflicts }}
+
+
+
+
+
+
+
+
+
+
+
+
Miembros del Equipo
+
{{ coordinatorInfo.department_employees }}
+
+
+
+
+
+
+
+
+
+
+
+
Aprobadas Este Mes
+
{{ coordinatorInfo.approved_requests_current_month }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Solicitudes Pendientes
+
Solicitudes que requieren tu aprobación
+
+
+
+
+
+
+
+
{{ request.user.name }}
+
+ {{ request.number_of_days }} día{{ request.number_of_days !== 1 ? 's' : '' }}
+ ({{ request.count_periods }} período{{ request.count_periods !== 1 ? 's' : '' }})
+
+
+
+ Conflicto
+
+
+
+
+
+
Hay conflicto en alguno de los periodos de vacaciones
+
+
+
+
+
+
+
+
+
+
+
+
+
+
No hay solicitudes pendientes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Mi Equipo
+
Estado actual de los miembros de tu equipo
+
+
+
+
+
+
+
{{ employee.name }}
+
+ {{ employee.vacation_days_available }} día{{ employee.vacation_days_available !== 1 ? 's' : '' }} disponibles
+
+
+
+ {{ employee.status_ek }}
+
+
+
+
+
+
+
No hay miembros en el equipo
+
+
+
+
+
+
+
+
+
+
+
+
+ Mis Vacaciones Personales
+
+
+
+
+
+
+
+
+
+ Mis Días Disponibles
+
+
+ {{ vacations.available_days }}
+
+
+
+
+ Disponible
+
+
+
+
+
+
+
+
+
+
+ Próxima Renovación
+
+
+
+ {{ vacations.next_renewal_date ? (() => { const date = new Date(vacations.next_renewal_date + 'T00:00:00'); return `${date.getDate()}-${date.toLocaleDateString('es-ES', { month: 'long' })}-${date.getFullYear()}` })() : 'N/A' }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Mis Solicitudes Activas
+
+
+ {{ vacations.active_requests }}
+
+
+
+
+ Pendientes
+
+
+
+
+
+
+
+
+
+
+
Mis Días Usados
+
{{ vacations.used_days }}
+
+
+
+
+
+
+
+
+
+ Mis Solicitudes Recientes
+
+
+
+
+
No tienes solicitudes recientes
+
+
+
+
+
+
{{ request.first_period_start }} - {{ request.last_period_end }}
+
{{ request.total_days }} días
+
+
+ {{ request.status }}
+
+
+
+
+
+
+ Ver todas mis solicitudes
+
+
+
+
+
+
diff --git a/src/pages/Dashboard/Employee.vue b/src/pages/Dashboard/Employee.vue
new file mode 100644
index 0000000..f001a50
--- /dev/null
+++ b/src/pages/Dashboard/Employee.vue
@@ -0,0 +1,247 @@
+
+
+
+
+
+
+
+
+
+ Bienvenido, {{ $page.user.name }}
+
+
+ Gestiona tus solicitudes de vacaciones y revisa tu información.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Días Disponibles
+
+
+ {{ vacations.available_days }}
+
+
+
+
+ Disponible
+
+
+
+
+
+
+
+
+
+
+ Próxima Renovación
+
+
+
+ {{ vacations.next_renewal_date ? (() => { const date = new Date(vacations.next_renewal_date + 'T00:00:00'); return `${date.getDate()}-${date.toLocaleDateString('es-ES', { month: 'long' })}-${date.getFullYear()}` })() : 'N/A' }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Solicitudes Activas
+
+
+ {{ vacations.active_requests }}
+
+
+
+
+ Pendientes
+
+
+
+
+
+
+
+
+
+
+
Días Usados
+
{{ vacations.used_days }}
+
+
+
+
+
+
+
+
+
+
+
+
+ Acciones Rápidas
+
+
+ Gestiona tus vacaciones de forma rápida
+
+
+
+
+
+
+ Nueva Solicitud de Vacaciones
+
+
+
+
+
+
+
+ Ver Mis Solicitudes
+
+
+
+
+
+
+
+ Mi Perfil
+
+
+
+
+
+
+
+
+
+ Solicitudes Recientes
+
+
+
+
+
No tienes solicitudes recientes
+
+
+
+
+
+
{{ request.first_period_start }} - {{ request.last_period_end }}
+
{{ request.total_days }} días
+
+
+ {{ request.status }}
+
+
+
+
+
+
+ Ver todas las solicitudes
+
+
+
+
+
+
+
+
+
+ Resumen de Vacaciones
+
+
+
+
{{ vacations.available_days }}
+
Días Disponibles
+
+
+
{{ vacations.used_days }}
+
Días Usados
+
+
+
{{ vacations.total_days_in_period }}
+
Total del Período
+
+
+
+
Período: {{ vacations.period_start_date ? (() => { const date = new Date(vacations.period_start_date + 'T00:00:00'); return `${date.getDate()}-${date.toLocaleDateString('es-ES', { month: 'long' })}-${date.getFullYear()}` })() : 'N/A' }} - {{ vacations.period_end_date ? (() => { const date = new Date(vacations.period_end_date + 'T00:00:00'); return `${date.getDate()}-${date.toLocaleDateString('es-ES', { month: 'long' })}-${date.getFullYear()}` })() : 'N/A' }}
+
+
+
+
diff --git a/src/pages/Events/Assignamment.vue b/src/pages/Events/Assignamment.vue
new file mode 100644
index 0000000..49d3b3c
--- /dev/null
+++ b/src/pages/Events/Assignamment.vue
@@ -0,0 +1,183 @@
+
+
+
+
+
+
+
+
+
Gestiona y asigna el presupuesto anual para eventos y actividades
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Total del Presupuesto:
+
+
+ {{ formatCurrency(totalBudget) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/Events/Index.vue b/src/pages/Events/Index.vue
new file mode 100644
index 0000000..52f0e44
--- /dev/null
+++ b/src/pages/Events/Index.vue
@@ -0,0 +1,284 @@
+
+
+
+
+
+
+
+
+
Resumen financiero y distribución de gastos por concepto
+
+
+
+
+
+
+
+
+
+
+
Presupuesto Anual
+
+ {{ formatCurrency(dashboardData.annualBudget) }}
+
+
+
+
+
+
+
+
+
+
+
Gastos Justificados
+
+ {{ formatCurrency(dashboardData.justifiedExpenses) }}
+
+
+ {{ expensesPercentage }}% del presupuesto
+
+
+
+
+
+
+
+
+
+
+
Saldo Restante
+
+ {{ formatCurrency(dashboardData.remainingBalance) }}
+
+
+ {{ remainingPercentage }}% del presupuesto
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Distribución de Gastos por Concepto
+
+
+ Porcentaje de gastos por categoría
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Detalle por Categoría
+
+
+
+
+
+
+ {{ item.name }}
+
+
+
+
+ {{ item.value }}%
+
+
+ {{ formatCurrency((item.value / 100) * dashboardData.justifiedExpenses) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ dashboardData.expenseDistribution.length }}
+
+
+ Categorías
+
+
+
+
+ {{ Math.max(...dashboardData.expenseDistribution.map(item => item.value)) }}%
+
+
+ Mayor gasto
+
+
+
+
+ {{ Math.min(...dashboardData.expenseDistribution.map(item => item.value)) }}%
+
+
+ Menor gasto
+
+
+
+
+
+
+
+
diff --git a/src/pages/Events/Justification.vue b/src/pages/Events/Justification.vue
new file mode 100644
index 0000000..c1128f8
--- /dev/null
+++ b/src/pages/Events/Justification.vue
@@ -0,0 +1,360 @@
+
+
+
+
+
+
+
+
+
Documenta y justifica los gastos realizados en eventos
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/Events/Reports.vue b/src/pages/Events/Reports.vue
new file mode 100644
index 0000000..e9673cb
--- /dev/null
+++ b/src/pages/Events/Reports.vue
@@ -0,0 +1,204 @@
+
+
+
+
+
+
+
+
+
Consulta y gestiona los gastos realizados en eventos
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | FECHA |
+ CONCEPTO |
+ RAZÓN |
+ MONTO |
+ JUSTIFICANTE |
+
+
+
+
+
+ |
+
+ {{ formatDate(expense.date) }}
+
+ |
+
+
+
+
+ {{ expense.concept }}
+
+ |
+
+
+
+
+ {{ expense.reason }}
+
+ |
+
+
+
+
+ {{ formatCurrency(expense.amount) }}
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+ Total de Gastos:
+
+
+ {{ formatCurrency(totalExpenses) }}
+
+
+
+
+
+
+
+ Mostrando {{ expenses.length }} gastos registrados
+
+
+
+
+
+ Total: {{ expenses.length }} registros
+
+
+
+ Justificados: {{ expenses.length }}
+
+
+
+
+
+
+
diff --git a/src/router/Index.js b/src/router/Index.js
index 28d3ba2..56c55de 100644
--- a/src/router/Index.js
+++ b/src/router/Index.js
@@ -16,7 +16,7 @@ const router = createRouter({
routes: [
{
path: '/',
- component: () => import('@Layouts/RhLayout.vue'),
+ component: () => import('@Layouts/AppLayout.vue'),
name: 'root',
meta: {
title: 'Inicio',
@@ -32,58 +32,13 @@ const router = createRouter({
{
path: 'dashboard',
name: 'dashboard.index',
- component: () => import('@Pages/Dashboard/Index.vue'),
+ component: () => import('@Pages/Dashboard/Employee.vue'),
meta: {
title: 'Dashboard',
icon: 'grid_view',
}
},
{
- path: 'employees',
- name: 'employees.index',
- component: () => import('@Pages/Employees/Index.vue'),
- meta: {
- title: 'Empleados',
- icon: 'people',
- }
- },
- {
- path: 'academic',
- name: 'academic.index',
- component: () => import('@Pages/Academic/Index.vue'),
- meta: {
- title: 'Historial Académico',
- icon: 'school',
- }
- },
- {
- path: 'security',
- name: 'security.index',
- component: () => import('@Pages/Security/Index.vue'),
- meta: {
- title: 'Seguridad y Salud',
- icon: 'security',
- }
- },
- {
- path: 'payroll',
- name: 'payroll.index',
- component: () => import('@Pages/Payroll/Index.vue'),
- meta: {
- title: 'Nómina',
- icon: 'payments',
- }
- },
- {
- path: 'additional',
- name: 'additional.index',
- component: () => import('@Pages/Additional/Index.vue'),
- meta: {
- title: 'Información Adicional',
- icon: 'info',
- }
- },
- {
path: 'profile',
name: 'profile.show',
component: () => import('@Pages/Profile/Show.vue'),
@@ -104,15 +59,203 @@ const router = createRouter({
],
},
{
- path: '/admin',
- name: 'admin',
- component: () => import('@Layouts/AppLayout.vue'),
+ path: '/coordinator',
+ name: 'coordinator',
+ component: () => import('@Layouts/CoordinatorLayout.vue'),
meta: {
title: 'Inicio',
icon: 'home',
},
- redirect: '/',
+ redirect: '/coordinator/dashboard',
children: [
+ {
+ path: 'dashboard',
+ name: 'coordinator.dashboard',
+ component: () => import('@Pages/Dashboard/Coordinator.vue'),
+ meta: {
+ title: 'Dashboard',
+ icon: 'grid_view',
+ },
+ redirect: '/coordinator/dashboard',
+ children: [
+ {
+ path: '',
+ name: 'coordinator.dashboard.index',
+ component: () => import('@Pages/Dashboard/Coordinator.vue'),
+ }
+ ]
+ },
+ ]
+ },
+ {
+ path: '/admin',
+ name: 'admin',
+ component: () => import('@Layouts/AdminLayout.vue'),
+ meta: {
+ title: 'Inicio',
+ icon: 'home',
+ },
+ redirect: '/admin/dashboard',
+ children: [
+ {
+ path: 'dashboard',
+ name: 'admin.dashboard',
+ component: () => import('@Pages/Dashboard/Admin.vue'),
+ meta: {
+ title: 'Dashboard',
+ icon: 'grid_view',
+ },
+ redirect: '/admin/dashboard',
+ children: [
+ {
+ path: '',
+ name: 'admin.dashboard.index',
+ component: () => import('@Pages/Dashboard/Admin.vue'),
+ }
+ ]
+ },
+ {
+ path: 'employees',
+ name: 'admin.employees',
+ meta: {
+ title: 'Empleados',
+ icon: 'people',
+ },
+ redirect: '/admin/employees',
+ children: [
+ {
+ path: '',
+ name: 'admin.employees.index',
+ component: () => import('@Pages/Employees/Index.vue'),
+ }
+ ]
+ },
+ {
+ path: 'academic',
+ name: 'admin.academic',
+ meta: {
+ title: 'Historial Académico',
+ icon: 'school',
+ },
+ redirect: '/admin/academic',
+ children: [
+ {
+ path: '',
+ name: 'admin.academic.index',
+ component: () => import('@Pages/Academic/Index.vue'),
+ }
+ ]
+ },
+ {
+ path: 'security',
+ name: 'admin.security',
+ meta: {
+ title: 'Seguridad y Salud',
+ icon: 'security',
+ },
+ redirect: '/admin/security',
+ children: [
+ {
+ path: '',
+ name: 'admin.security.index',
+ component: () => import('@Pages/Security/Index.vue'),
+ }
+ ]
+ },
+ {
+ path: 'payroll',
+ name: 'admin.payroll',
+ meta: {
+ title: 'Nómina',
+ icon: 'payments',
+ },
+ redirect: '/admin/payroll',
+ children: [
+ {
+ path: '',
+ name: 'admin.payroll.index',
+ component: () => import('@Pages/Payroll/Index.vue'),
+ }
+ ]
+ },
+ {
+ path: 'additional',
+ name: 'admin.additional',
+ meta: {
+ title: 'Información Adicional',
+ icon: 'info',
+ },
+ redirect: '/admin/additional',
+ children: [
+ {
+ path: '',
+ name: 'admin.additional.index',
+ component: () => import('@Pages/Additional/Index.vue'),
+ }
+ ]
+ },
+ {
+ path: 'courses',
+ name: 'admin.courses',
+ meta: {
+ title: 'Capacitaciones',
+ icon: 'info',
+ },
+ redirect: '/admin/courses',
+ children: [
+ {
+ path: '',
+ name: 'admin.courses.index',
+ component: () => import('@Pages/Courses/Index.vue'),
+ },
+ {
+ path: 'assignamment',
+ name: 'admin.courses.assignamment',
+ component: () => import('@Pages/Courses/Assignamment.vue'),
+ },
+ {
+ path: 'request',
+ name: 'admin.courses.request',
+ component: () => import('@Pages/Courses/Request.vue'),
+ },
+ {
+ path: 'calendar',
+ name: 'admin.courses.calendar',
+ component: () => import('@Pages/Courses/Calendar.vue'),
+ },
+ ]
+ },
+ {
+ path: 'events',
+ name: 'admin.events',
+ meta: {
+ title: 'Eventos',
+ icon: 'info',
+ },
+ redirect: '/admin/events',
+ children: [
+ {
+ path: '',
+ name: 'admin.events.index',
+ component: () => import('@Pages/Events/Index.vue'),
+ },
+ {
+ path: 'assignamment',
+ name: 'admin.events.assignamment',
+ component: () => import('@Pages/Events/Assignamment.vue'),
+ },
+ {
+ path: 'justification',
+ name: 'admin.events.justification',
+ component: () => import('@Pages/Events/Justification.vue'),
+ },
+ {
+ path: 'reports',
+ name: 'admin.events.reports',
+ component: () => import('@Pages/Events/Reports.vue'),
+ },
+ ]
+ },
{
path: 'users',
name: 'admin.users',