2025-09-30 21:27:17 +00:00

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>