151 lines
5.1 KiB
Vue
151 lines
5.1 KiB
Vue
<script setup>
|
|
import { onMounted, ref } from 'vue';
|
|
import { useRouter } from 'vue-router';
|
|
import { useSearcher } from '@Services/Api';
|
|
import { getDate } from '@Controllers/DateController';
|
|
import { apiTo, viewTo } from './Module'
|
|
|
|
import GoogleIcon from '@Shared/GoogleIcon.vue';
|
|
import Searcher from '@Holos/Searcher.vue';
|
|
import AcademicRecords from '@Holos/Card/AcademicRecords.vue';
|
|
import Certifications from '@Holos/Card/Certifications.vue';
|
|
import DestroyView from '@Holos/Modal/Template/Destroy.vue';
|
|
|
|
/** Propiedades */
|
|
const models = ref([]);
|
|
|
|
/** Definidores */
|
|
const router = useRouter();
|
|
|
|
/** Referencias */
|
|
const destroyRecordModal = ref(false);
|
|
const destroyCertModal = ref(false);
|
|
|
|
/** Métodos */
|
|
const searcher = useSearcher({
|
|
url: apiTo('index'),
|
|
onSuccess: (r) => models.value = r.models,
|
|
onError: () => models.value = []
|
|
});
|
|
|
|
function openDestroyRecord(record) {
|
|
destroyRecordModal.value.open(record);
|
|
}
|
|
|
|
function openDestroyCert(cert) {
|
|
destroyCertModal.value.open(cert);
|
|
}
|
|
|
|
function openEditRecord(record) {
|
|
router.push(viewTo({ name: 'editRecord', params: { id: record.user_id, record: record.id } }));
|
|
}
|
|
|
|
function openEditCert(cert) {
|
|
router.push(viewTo({ name: 'editCertification', params: { id: cert.user_id, certification: cert.id } }));
|
|
}
|
|
|
|
/** Ciclos */
|
|
onMounted(() => {
|
|
searcher.search();
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div>
|
|
<!-- Página: Header principal -->
|
|
<div class="flex items-start justify-between">
|
|
<div>
|
|
<h1 class="text-4xl font-extrabold text-gray-900 dark:text-primary-dt">Historial Académico</h1>
|
|
<p class="mt-1 text-sm text-gray-500 dark:text-primary-dt/70">Gestión de grados académicos y certificaciones profesionales</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Search Card -->
|
|
<div class="pt-2 w-full">
|
|
<Searcher @search="(x) => searcher.search(x)">
|
|
</Searcher>
|
|
</div>
|
|
|
|
<!-- Cards principales: una por usuario -->
|
|
<section
|
|
v-for="user in models.data"
|
|
:key="user.id"
|
|
class="mt-6 bg-white rounded-lg shadow-sm p-6 dark:bg-primary-d dark:border-primary/20 dark:text-primary-dt"
|
|
>
|
|
<!-- Perfil -->
|
|
<header class="flex items-start gap-4">
|
|
<div class="flex-shrink-0">
|
|
<div class="w-12 h-12 rounded-full bg-gray-100 flex items-center justify-center text-gray-600 dark:bg-primary/10 dark:text-primary-dt">
|
|
<!-- icono usuario -->
|
|
<GoogleIcon
|
|
class="text-black dark:text-primary-dt text-xl"
|
|
name="school"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex-1">
|
|
<h2 class="text-xl font-semibold text-gray-800 dark:text-primary-dt">{{ user.full_name }}</h2>
|
|
<p class="text-sm text-gray-500 mt-1 dark:text-primary-dt/70">Información académica y certificaciones profesionales</p>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Secciones: Grados Académicos -->
|
|
<AcademicRecords
|
|
:records="user.academic_records || []"
|
|
@destroy="openDestroyRecord"
|
|
@edit="openEditRecord"
|
|
/>
|
|
|
|
<!-- Secciones: Certificaciones -->
|
|
<Certifications
|
|
:certifications="user.certificates || []"
|
|
@destroy="openDestroyCert"
|
|
@edit="openEditCert"
|
|
/>
|
|
|
|
<!-- Acciones al final de la tarjeta -->
|
|
<div class="mt-6 border-t border-gray-100 pt-4 flex gap-3 dark:border-primary/20">
|
|
<RouterLink :to="viewTo({ name: 'createRecord', params: { id: user.id } })" class="inline-flex items-center gap-2 px-3 py-2 rounded-md border border-gray-200 bg-white text-sm text-gray-700 shadow-sm dark:bg-primary-d dark:border-primary/20 dark:text-primary-dt">
|
|
<GoogleIcon
|
|
class="text-black dark:text-primary-dt text-xl"
|
|
name="add"
|
|
/>
|
|
Agregar Grado
|
|
</RouterLink>
|
|
|
|
<RouterLink :to="viewTo({ name: 'createCertification', params: { id: user.id } })" class="inline-flex items-center gap-2 px-3 py-2 rounded-md border border-gray-200 bg-white text-sm text-gray-700 shadow-sm dark:bg-primary-d dark:border-primary/20 dark:text-primary-dt">
|
|
<GoogleIcon
|
|
class="text-black dark:text-primary-dt text-xl"
|
|
name="add"
|
|
/>
|
|
Agregar Certificación
|
|
</RouterLink>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Estado vacío general -->
|
|
<div v-if="models.length === 0" class="mt-6 py-12 text-center">
|
|
<div class="text-gray-500 dark:text-primary-dt/70">
|
|
<GoogleIcon name="person_search" class="w-12 h-12 mx-auto mb-4 text-gray-400" />
|
|
<p class="text-lg font-medium">No se encontraron usuarios</p>
|
|
<p class="text-sm mt-1">Intenta ajustar los filtros de búsqueda</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modales de eliminación -->
|
|
<DestroyView
|
|
ref="destroyRecordModal"
|
|
subtitle="title"
|
|
:to="(academicRecord) => apiTo('destroy-record', { academicRecord })"
|
|
@update="searcher.search()"
|
|
/>
|
|
|
|
<DestroyView
|
|
ref="destroyCertModal"
|
|
subtitle="name"
|
|
:to="(certificate) => apiTo('destroy-certificate', { certificate })"
|
|
@update="searcher.search()"
|
|
/>
|
|
</div>
|
|
</template> |