Merge pull request #26 from josedario87/feat/centralize-nucleo-table there is still required to fix the hover feature
Feat/centralize nucleo table
This commit is contained in:
@@ -1,66 +1,43 @@
|
||||
<template>
|
||||
<div
|
||||
class="p-4 sm:p-6 rounded-lg overflow-x-auto"
|
||||
:style="{ backgroundColor: ui.tableBgColorAsistencias }"
|
||||
<NucleoTable
|
||||
:columns="columns"
|
||||
:items="props.asistencias"
|
||||
accent-color="--accent-color-asistencias"
|
||||
table-bg-color-name="tableBgColorAsistencias"
|
||||
>
|
||||
<table
|
||||
class="min-w-full divide-y divide-[var(--accent-color-asistencias)]"
|
||||
:style="{ backgroundColor: ui.tableBgColorAsistencias }"
|
||||
>
|
||||
<thead
|
||||
class="divide-y divide-[var(--accent-color-asistencias)]"
|
||||
:style="{ backgroundColor: ui.tableBgColorAsistencias }"
|
||||
>
|
||||
<tr>
|
||||
<th class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">ID</th>
|
||||
<th class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">Empleado ID</th>
|
||||
<th class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">Entrada</th>
|
||||
<th class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">Salida</th>
|
||||
<th class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">Estado</th>
|
||||
<th class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">Observación</th>
|
||||
<th class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody
|
||||
class="divide-y divide-[var(--accent-color-asistencias)]"
|
||||
:style="{ backgroundColor: ui.tableBgColorAsistencias }"
|
||||
>
|
||||
<tr v-if="!asistencias || asistencias.length === 0">
|
||||
<td colspan="7" class="px-6 py-10 text-center text-gray-500 dark:text-slate-400 text-lg">No hay asistencias para mostrar.</td>
|
||||
</tr>
|
||||
<tr v-for="asistencia in asistencias" :key="asistencia.id" class="transition-colors duration-150 ease-in-out hover:bg-[var(--accent-color-asistencias)]/10 dark:hover:bg-[var(--accent-color-asistencias)]/20">
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">{{ asistencia.id }}</td>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">{{ asistencia.empleado_id }}</td>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">{{ formatDateTime(asistencia.entrada) }}</td>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">{{ asistencia.salida ? formatDateTime(asistencia.salida) : 'N/A' }}</td>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">
|
||||
<span :class="['px-2.5 py-0.5 rounded-full text-xs font-semibold', getStatusClass(asistencia.estado)]">{{ asistencia.estado }}</span>
|
||||
</td>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 text-sm text-gray-700 dark:text-slate-300 max-w-xs whitespace-nowrap" :title="asistencia.observacion">{{ truncateText(asistencia.observacion, 50) }}</td>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">
|
||||
<div class="flex items-center space-x-2">
|
||||
<button @click="editAsistencia(asistencia.id)" class="p-1.5 sm:p-2 rounded-md transition-all duration-150 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2 text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 hover:bg-blue-100 dark:hover:bg-blue-600/20 focus:ring-blue-500 dark:focus:ring-blue-400" title="Editar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10" /></svg>
|
||||
</button>
|
||||
<button @click="confirmDeleteAsistencia(asistencia)" class="p-1.5 sm:p-2 rounded-md transition-all duration-150 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2 text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-300 hover:bg-red-100 dark:hover:bg-red-600/20 focus:ring-red-500 dark:focus:ring-red-400" title="Eliminar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12.56 0c1.153 0 2.24.03 3.22.077m3.22-.077L10.879 3.28a2.25 2.25 0 012.244-2.077h.093c.956 0 1.853.543 2.244 2.077L14.74 5.79m-4.858 0l-2.828-2.828A1.875 1.875 0 016.188 2.188l2.828 2.828m6.912 0l2.828-2.828a1.875 1.875 0 00-2.652-2.652L12 5.79M9.26 9h5.48L9.26 9z" /></svg>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<template #cell-entrada="{ item }">
|
||||
{{ formatDateTime(item.entrada) }}
|
||||
</template>
|
||||
<template #cell-salida="{ item }">
|
||||
{{ item.salida ? formatDateTime(item.salida) : 'N/A' }}
|
||||
</template>
|
||||
<template #cell-estado="{ item }">
|
||||
<span :class="['px-2.5 py-0.5 rounded-full text-xs font-semibold', getStatusClass(item.estado)]">
|
||||
{{ item.estado }}
|
||||
</span>
|
||||
</template>
|
||||
<template #cell-observacion="{ item }">
|
||||
<span :title="item.observacion">{{ truncateText(item.observacion, 50) }}</span>
|
||||
</template>
|
||||
<template #actions="{ item }">
|
||||
<div class="flex items-center space-x-2">
|
||||
<button @click="editAsistencia(item.id)" class="p-1.5 sm:p-2 rounded-md transition-all duration-150 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2 text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 hover:bg-blue-100 dark:hover:bg-blue-600/20 focus:ring-blue-500 dark:focus:ring-blue-400" title="Editar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10" /></svg>
|
||||
</button>
|
||||
<button @click="confirmDeleteAsistencia(item)" class="p-1.5 sm:p-2 rounded-md transition-all duration-150 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2 text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-300 hover:bg-red-100 dark:hover:bg-red-600/20 focus:ring-red-500 dark:focus:ring-red-400" title="Eliminar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12.56 0c1.153 0 2.24.03 3.22.077m3.22-.077L10.879 3.28a2.25 2.25 0 012.244-2.077h.093c.956 0 1.853.543 2.244 2.077L14.74 5.79m-4.858 0l-2.828-2.828A1.875 1.875 0 016.188 2.188l2.828 2.828m6.912 0l2.828-2.828a1.875 1.875 0 00-2.652-2.652L12 5.79M9.26 9h5.48L9.26 9z" /></svg>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</NucleoTable>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineProps, defineEmits } from 'vue';
|
||||
import NucleoTable from '../ui/NucleoTable.vue'; // Import NucleoTable
|
||||
import { useAsistenciasStore } from '../../stores/useAsistencias';
|
||||
import { formatDateTime, truncateText, getStatusClass } from '../../utils/formatters.js';
|
||||
import { useUi } from '../../stores/useUi.js';
|
||||
|
||||
const ui = useUi();
|
||||
// useUi store is now handled by NucleoTable for tableBgColorAsistencias
|
||||
|
||||
const props = defineProps({
|
||||
asistencias: {
|
||||
@@ -70,12 +47,22 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['edit']);
|
||||
const emit = defineEmits(['edit']); // This component still emits 'edit' to its parent (AsistenciasIndex.vue)
|
||||
|
||||
const asistenciasStore = useAsistenciasStore();
|
||||
|
||||
const columns = [
|
||||
{ key: 'id', label: 'ID' },
|
||||
{ key: 'empleado_id', label: 'Empleado ID' },
|
||||
{ key: 'entrada', label: 'Entrada' },
|
||||
{ key: 'salida', label: 'Salida' },
|
||||
{ key: 'estado', label: 'Estado' },
|
||||
{ key: 'observacion', label: 'Observación' },
|
||||
];
|
||||
|
||||
// Keep existing methods, they are used by the action buttons
|
||||
const editAsistencia = (id) => {
|
||||
emit('edit', id);
|
||||
emit('edit', id); // Emitting to parent (AsistenciasIndex)
|
||||
};
|
||||
|
||||
const confirmDeleteAsistencia = (asistencia) => {
|
||||
@@ -87,7 +74,6 @@ const confirmDeleteAsistencia = (asistencia) => {
|
||||
const deleteAsistenciaInternal = async (id) => {
|
||||
try {
|
||||
await asistenciasStore.deleteAsistencia(id);
|
||||
// Optional: Show success notification or emit 'deleted' event
|
||||
} catch (error) {
|
||||
console.error(`Error deleting asistencia with id ${id}:`, error);
|
||||
alert('Ocurrió un error al eliminar la asistencia.');
|
||||
|
||||
@@ -1,86 +1,41 @@
|
||||
<template>
|
||||
<div class="p-4 sm:p-6 rounded-lg overflow-x-auto" :style="{ backgroundColor: ui.tableBgColorEmpleados }">
|
||||
<table class="min-w-full divide-y divide-[var(--accent-color-empleados)]" :style="{ backgroundColor: ui.tableBgColorEmpleados }">
|
||||
<thead class="divide-y divide-[var(--accent-color-empleados)]" :style="{ backgroundColor: ui.tableBgColorEmpleados }">
|
||||
<tr>
|
||||
<th scope="col" class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">
|
||||
Avatar
|
||||
</th>
|
||||
<th scope="col" class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">
|
||||
Nombre
|
||||
</th>
|
||||
<th scope="col" class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">
|
||||
Cédula
|
||||
</th>
|
||||
<th scope="col" class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">
|
||||
Teléfono
|
||||
</th>
|
||||
<th scope="col" class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">
|
||||
Ubicación
|
||||
</th>
|
||||
<th scope="col" class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">
|
||||
ID CIAT
|
||||
</th>
|
||||
<th scope="col" class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">
|
||||
Acciones
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-[var(--accent-color-empleados)]" :style="{ backgroundColor: ui.tableBgColorEmpleados }">
|
||||
<tr v-if="!employees || employees.length === 0">
|
||||
<td colspan="7" class="px-6 py-10 text-center text-gray-500 dark:text-slate-400 text-lg">
|
||||
No hay empleados para mostrar.
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-for="employee in employees" :key="employee.id" class="transition-colors duration-150 ease-in-out hover:bg-[var(--accent-color-empleados)]/10 dark:hover:bg-[var(--accent-color-empleados)]/20">
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap">
|
||||
<img
|
||||
:src="employee.avatar_url || 'https://via.placeholder.com/40'"
|
||||
alt="Avatar"
|
||||
class="w-10 h-10 rounded-full object-cover border border-gray-300 shadow-sm"
|
||||
/>
|
||||
</td>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm">
|
||||
<div class="text-sm font-semibold text-gray-800 dark:text-slate-200">{{ employee.name }}</div>
|
||||
<div v-if="employee.grupo_estudio" class="text-xs text-gray-500 dark:text-slate-400">
|
||||
Grupo: {{ employee.grupo_estudio }}
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">
|
||||
{{ employee.cedula }}
|
||||
</td>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">
|
||||
{{ employee.telefono || '-' }}
|
||||
</td>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">
|
||||
{{ employee.ubicacion }}
|
||||
</td>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">
|
||||
{{ employee.idciat || '-' }}
|
||||
</td>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm font-medium">
|
||||
<div class="flex items-center space-x-2">
|
||||
<button @click="handleEdit(employee.id)" class="p-1.5 sm:p-2 rounded-md transition-all duration-150 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2 text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 hover:bg-blue-100 dark:hover:bg-blue-600/20 focus:ring-blue-500 dark:focus:ring-blue-400" title="Editar Empleado">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10" /></svg>
|
||||
</button>
|
||||
<button @click="confirmDeleteEmpleado(employee)" class="p-1.5 sm:p-2 rounded-md transition-all duration-150 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2 text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-300 hover:bg-red-100 dark:hover:bg-red-600/20 focus:ring-red-500 dark:focus:ring-red-400" title="Eliminar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12.56 0c1.153 0 2.24.03 3.22.077m3.22-.077L10.879 3.28a2.25 2.25 0 012.244-2.077h.093c.956 0 1.853.543 2.244 2.077L14.74 5.79m-4.858 0l-2.828-2.828A1.875 1.875 0 016.188 2.188l2.828 2.828m6.912 0l2.828-2.828a1.875 1.875 0 00-2.652-2.652L12 5.79M9.26 9h5.48L9.26 9z" /></svg>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<NucleoTable
|
||||
:columns="columns"
|
||||
:items="props.employees"
|
||||
accent-color="--accent-color-empleados"
|
||||
table-bg-color-name="tableBgColorEmpleados"
|
||||
>
|
||||
<template #cell-avatar_url="{ item }">
|
||||
<img
|
||||
:src="item.avatar_url || 'https://via.placeholder.com/40'"
|
||||
alt="Avatar"
|
||||
class="w-10 h-10 rounded-full object-cover border border-gray-300 dark:border-slate-600 shadow-sm"
|
||||
/>
|
||||
</template>
|
||||
<template #cell-name="{ item }">
|
||||
<div class="text-sm font-semibold text-gray-800 dark:text-slate-200">{{ item.name }}</div>
|
||||
<div v-if="item.grupo_estudio" class="text-xs text-gray-500 dark:text-slate-400">
|
||||
Grupo: {{ item.grupo_estudio }}
|
||||
</div>
|
||||
</template>
|
||||
<template #actions="{ item }">
|
||||
<div class="flex items-center space-x-2">
|
||||
<button @click="handleEdit(item.id)" class="p-1.5 sm:p-2 rounded-md transition-all duration-150 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2 text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 hover:bg-blue-100 dark:hover:bg-blue-600/20 focus:ring-blue-500 dark:focus:ring-blue-400" title="Editar Empleado">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10" /></svg>
|
||||
</button>
|
||||
<button @click="confirmDeleteEmpleado(item)" class="p-1.5 sm:p-2 rounded-md transition-all duration-150 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2 text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-300 hover:bg-red-100 dark:hover:bg-red-600/20 focus:ring-red-500 dark:focus:ring-red-400" title="Eliminar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12.56 0c1.153 0 2.24.03 3.22.077m3.22-.077L10.879 3.28a2.25 2.25 0 012.244-2.077h.093c.956 0 1.853.543 2.244 2.077L14.74 5.79m-4.858 0l-2.828-2.828A1.875 1.875 0 016.188 2.188l2.828 2.828m6.912 0l2.828-2.828a1.875 1.875 0 00-2.652-2.652L12 5.79M9.26 9h5.48L9.26 9z" /></svg>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</NucleoTable>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useUi } from '../../stores/useUi.js';
|
||||
import { defineProps, defineEmits } from 'vue';
|
||||
import NucleoTable from '../ui/NucleoTable.vue'; // Import NucleoTable
|
||||
import { useEmpleadosStore } from '../../stores/useEmpleados';
|
||||
|
||||
const ui = useUi();
|
||||
const emit = defineEmits(['edit']);
|
||||
const empleadosStore = useEmpleadosStore();
|
||||
// useUi store is now handled by NucleoTable
|
||||
|
||||
const props = defineProps({
|
||||
employees: {
|
||||
@@ -90,6 +45,19 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['edit']); // Emits 'edit' to parent (EmpleadosIndex.vue)
|
||||
const empleadosStore = useEmpleadosStore();
|
||||
|
||||
const columns = [
|
||||
{ key: 'avatar_url', label: 'Avatar' },
|
||||
{ key: 'name', label: 'Nombre' },
|
||||
{ key: 'cedula', label: 'Cédula' },
|
||||
{ key: 'telefono', label: 'Teléfono' },
|
||||
{ key: 'ubicacion', label: 'Ubicación' },
|
||||
{ key: 'idciat', label: 'ID CIAT' },
|
||||
];
|
||||
|
||||
// Keep existing methods
|
||||
const handleEdit = (employeeId) => {
|
||||
emit('edit', employeeId);
|
||||
};
|
||||
@@ -112,16 +80,7 @@ const deleteEmpleadoInternal = async (id) => {
|
||||
|
||||
<style scoped>
|
||||
/* Scoped styles can be minimized or removed if Tailwind covers all needs */
|
||||
|
||||
.rounded-full {
|
||||
object-fit: cover; /* Ensures avatar images are displayed nicely */
|
||||
}
|
||||
|
||||
/* Optional: Keep icon transition if not handled by Tailwind's transition utilities on the button */
|
||||
button svg {
|
||||
transition: transform 0.15s ease-in-out;
|
||||
}
|
||||
button:hover svg {
|
||||
transform: scale(1.1); /* Adjusted scale for a subtler effect */
|
||||
}
|
||||
/* .rounded-full { object-fit: cover; } */
|
||||
/* button svg { transition: transform 0.15s ease-in-out; } */
|
||||
/* button:hover svg { transform: scale(1.1); } */
|
||||
</style>
|
||||
|
||||
@@ -1,55 +1,43 @@
|
||||
<template>
|
||||
<div class="p-4 sm:p-6 rounded-lg overflow-x-auto" :style="{ backgroundColor: ui.tableBgColorPlanillas }">
|
||||
<table class="min-w-full divide-y divide-[var(--accent-color-planillas)]" :style="{ backgroundColor: ui.tableBgColorPlanillas }">
|
||||
<thead class="divide-y divide-[var(--accent-color-planillas)]" :style="{ backgroundColor: ui.tableBgColorPlanillas }">
|
||||
<tr>
|
||||
<th class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">ID</th>
|
||||
<th class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">Título</th>
|
||||
<th class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">Empleado ID</th>
|
||||
<th class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">Fecha Desde</th>
|
||||
<th class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">Fecha Hasta</th>
|
||||
<th class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">Total</th>
|
||||
<th class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">Estado</th>
|
||||
<th class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-[var(--accent-color-planillas)]" :style="{ backgroundColor: ui.tableBgColorPlanillas }">
|
||||
<tr v-if="planillas && planillas.length === 0">
|
||||
<td colspan="8" class="px-6 py-10 text-center text-gray-500 dark:text-slate-400 text-lg">No hay planillas para mostrar.</td>
|
||||
</tr>
|
||||
<tr v-for="planilla in planillas" :key="planilla.id" class="transition-colors duration-150 ease-in-out hover:bg-[var(--accent-color-planillas)]/10 dark:hover:bg-[var(--accent-color-planillas)]/20">
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">{{ planilla.id }}</td>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">{{ planilla.titulo }}</td>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">{{ planilla.empleado_id }}</td>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">{{ formatDate(planilla.fecha_desde) }}</td>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">{{ formatDate(planilla.fecha_hasta) }}</td>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">{{ formatCurrency(planilla.total) }}</td>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">
|
||||
<span :class="['px-2.5 py-0.5 rounded-full text-xs font-semibold', getStatusClass(planilla.estado)]">{{ planilla.estado }}</span>
|
||||
</td>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">
|
||||
<div class="flex items-center space-x-2">
|
||||
<button @click="editPlanilla(planilla.id)" class="p-1.5 sm:p-2 rounded-md transition-all duration-150 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2 text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 hover:bg-blue-100 dark:hover:bg-blue-600/20 focus:ring-blue-500 dark:focus:ring-blue-400" title="Editar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10" /></svg>
|
||||
</button>
|
||||
<button @click="confirmDeletePlanilla(planilla)" class="p-1.5 sm:p-2 rounded-md transition-all duration-150 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2 text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-300 hover:bg-red-100 dark:hover:bg-red-600/20 focus:ring-red-500 dark:focus:ring-red-400" title="Eliminar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12.56 0c1.153 0 2.24.03 3.22.077m3.22-.077L10.879 3.28a2.25 2.25 0 012.244-2.077h.093c.956 0 1.853.543 2.244 2.077L14.74 5.79m-4.858 0l-2.828-2.828A1.875 1.875 0 016.188 2.188l2.828 2.828m6.912 0l2.828-2.828a1.875 1.875 0 00-2.652-2.652L12 5.79M9.26 9h5.48L9.26 9z" /></svg>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<NucleoTable
|
||||
:columns="columns"
|
||||
:items="props.planillas"
|
||||
accent-color="--accent-color-planillas"
|
||||
table-bg-color-name="tableBgColorPlanillas"
|
||||
>
|
||||
<template #cell-fecha_desde="{ item }">
|
||||
{{ formatDate(item.fecha_desde) }}
|
||||
</template>
|
||||
<template #cell-fecha_hasta="{ item }">
|
||||
{{ formatDate(item.fecha_hasta) }}
|
||||
</template>
|
||||
<template #cell-total="{ item }">
|
||||
{{ formatCurrency(item.total) }}
|
||||
</template>
|
||||
<template #cell-estado="{ item }">
|
||||
<span :class="['px-2.5 py-0.5 rounded-full text-xs font-semibold', getStatusClass(item.estado)]">
|
||||
{{ item.estado }}
|
||||
</span>
|
||||
</template>
|
||||
<template #actions="{ item }">
|
||||
<div class="flex items-center space-x-2">
|
||||
<button @click="editPlanilla(item.id)" class="p-1.5 sm:p-2 rounded-md transition-all duration-150 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2 text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 hover:bg-blue-100 dark:hover:bg-blue-600/20 focus:ring-blue-500 dark:focus:ring-blue-400" title="Editar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10" /></svg>
|
||||
</button>
|
||||
<button @click="confirmDeletePlanilla(item)" class="p-1.5 sm:p-2 rounded-md transition-all duration-150 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2 text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-300 hover:bg-red-100 dark:hover:bg-red-600/20 focus:ring-red-500 dark:focus:ring-red-400" title="Eliminar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12.56 0c1.153 0 2.24.03 3.22.077m3.22-.077L10.879 3.28a2.25 2.25 0 012.244-2.077h.093c.956 0 1.853.543 2.244 2.077L14.74 5.79m-4.858 0l-2.828-2.828A1.875 1.875 0 016.188 2.188l2.828 2.828m6.912 0l2.828-2.828a1.875 1.875 0 00-2.652-2.652L12 5.79M9.26 9h5.48L9.26 9z" /></svg>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</NucleoTable>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineProps, defineEmits } from 'vue';
|
||||
import NucleoTable from '../ui/NucleoTable.vue'; // Import NucleoTable
|
||||
import { usePlanillasStore } from '../../stores/usePlanillas';
|
||||
import { formatDate, formatCurrency, getStatusClass } from '../../utils/formatters.js';
|
||||
import { useUi } from '../../stores/useUi.js';
|
||||
|
||||
const ui = useUi();
|
||||
// useUi store is now handled by NucleoTable
|
||||
|
||||
const props = defineProps({
|
||||
planillas: {
|
||||
@@ -59,10 +47,20 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['edit']); // Removed 'delete' as it's handled internally
|
||||
|
||||
const emit = defineEmits(['edit']); // Emits 'edit' to parent (PlanillasIndex.vue)
|
||||
const planillasStore = usePlanillasStore();
|
||||
|
||||
const columns = [
|
||||
{ key: 'id', label: 'ID' },
|
||||
{ key: 'titulo', label: 'Título' },
|
||||
{ key: 'empleado_id', label: 'Empleado ID' },
|
||||
{ key: 'fecha_desde', label: 'Fecha Desde' },
|
||||
{ key: 'fecha_hasta', label: 'Fecha Hasta' },
|
||||
{ key: 'total', label: 'Total' },
|
||||
{ key: 'estado', label: 'Estado' },
|
||||
];
|
||||
|
||||
// Keep existing methods
|
||||
const editPlanilla = (id) => {
|
||||
emit('edit', id);
|
||||
};
|
||||
@@ -76,8 +74,6 @@ const confirmDeletePlanilla = (planilla) => {
|
||||
const deletePlanillaInternal = async (id) => {
|
||||
try {
|
||||
await planillasStore.deletePlanilla(id);
|
||||
// Optional: Show success notification
|
||||
// No need to emit 'delete' if the store handles list updates and parent components react to store changes
|
||||
} catch (error) {
|
||||
console.error(`Error deleting planilla with id ${id}:`, error);
|
||||
// Optional: Show error notification
|
||||
|
||||
@@ -1,109 +1,80 @@
|
||||
<template>
|
||||
<div
|
||||
class="p-4 sm:p-6 rounded-lg overflow-x-auto"
|
||||
:style="{ '--bg-tareas': ui.tableBgColorTareas }"
|
||||
<NucleoTable
|
||||
:columns="columns"
|
||||
:items="props.tareas"
|
||||
accent-color="--accent-color-tareas"
|
||||
table-bg-color-name="tableBgColorTareas"
|
||||
>
|
||||
<table
|
||||
class="min-w-full divide-y divide-[var(--accent-color-tareas)]"
|
||||
:style="{ backgroundColor: ui.tableBgColorTareas }"
|
||||
>
|
||||
<thead
|
||||
class="divide-y divide-[var(--accent-color-tareas)]"
|
||||
:style="{ backgroundColor: ui.tableBgColorTareas }"
|
||||
>
|
||||
<tr>
|
||||
<th class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">ID</th>
|
||||
<th class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">Título</th>
|
||||
<th class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">Empleado ID</th>
|
||||
<th class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">Fecha</th>
|
||||
<th class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">Estado</th>
|
||||
<th class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">Tipo</th>
|
||||
<th class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">Precio</th>
|
||||
<th class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">Planilla ID</th>
|
||||
<th class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody
|
||||
class="divide-y divide-[var(--accent-color-tareas)]"
|
||||
:style="{ backgroundColor: ui.tableBgColorTareas }"
|
||||
>
|
||||
<tr v-if="!tareas || tareas.length === 0">
|
||||
<td colspan="9" class="px-6 py-10 text-center text-gray-500 dark:text-slate-400 text-lg">
|
||||
No hay tareas para mostrar.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr
|
||||
v-for="tarea in tareas"
|
||||
:key="tarea.id"
|
||||
class="bg-[var(--bg-tareas)] transition-colors duration-150 ease-in-out hover:bg-[var(--accent-color-tareas)]/10 dark:hover:bg-[var(--accent-color-tareas)]/20"
|
||||
>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">{{ tarea.id }}</td>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">{{ tarea.titulo }}</td>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">{{ tarea.empleado_id }}</td>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">{{ formatDate(tarea.fecha) }}</td>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">
|
||||
<span :class="['px-2.5 py-0.5 rounded-full text-xs font-semibold', getStatusClass(tarea.estado)]">
|
||||
{{ tarea.estado }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">{{ tarea.tipo || 'N/A' }}</td>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">{{ tarea.precio != null ? formatCurrency(tarea.precio) : 'N/A' }}</td>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">{{ tarea.planilla_id || 'N/A' }}</td>
|
||||
<td class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">
|
||||
<div class="flex items-center space-x-2">
|
||||
<button
|
||||
@click="editTarea(tarea.id)"
|
||||
class="p-1.5 sm:p-2 rounded-md transition-all duration-150 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2 text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 hover:bg-blue-100 dark:hover:bg-blue-600/20 focus:ring-blue-500 dark:focus:ring-blue-400"
|
||||
title="Editar"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10" /></svg>
|
||||
</button>
|
||||
|
||||
<button
|
||||
@click="confirmDeleteTarea(tarea)"
|
||||
class="p-1.5 sm:p-2 rounded-md transition-all duration-150 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2 text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-300 hover:bg-red-100 dark:hover:bg-red-600/20 focus:ring-red-500 dark:focus:ring-red-400"
|
||||
title="Eliminar"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12.56 0c1.153 0 2.24.03 3.22.077m3.22-.077L10.879 3.28a2.25 2.25 0 012.244-2.077h.093c.956 0 1.853.543 2.244 2.077L14.74 5.79m-4.858 0l-2.828-2.828A1.875 1.875 0 016.188 2.188l2.828 2.828m6.912 0l2.828-2.828a1.875 1.875 0 00-2.652-2.652L12 5.79M9.26 9h5.48L9.26 9z" /></svg>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<template #cell-fecha="{ item }">
|
||||
{{ formatDate(item.fecha) }}
|
||||
</template>
|
||||
<template #cell-estado="{ item }">
|
||||
<span :class="['px-2.5 py-0.5 rounded-full text-xs font-semibold', getStatusClass(item.estado)]">
|
||||
{{ item.estado }}
|
||||
</span>
|
||||
</template>
|
||||
<template #cell-tipo="{ item }">
|
||||
{{ item.tipo || 'N/A' }}
|
||||
</template>
|
||||
<template #cell-precio="{ item }">
|
||||
{{ item.precio != null ? formatCurrency(item.precio) : 'N/A' }}
|
||||
</template>
|
||||
<template #cell-planilla_id="{ item }">
|
||||
{{ item.planilla_id || 'N/A' }}
|
||||
</template>
|
||||
<template #actions="{ item }">
|
||||
<div class="flex items-center space-x-2">
|
||||
<button @click="editTarea(item.id)" class="p-1.5 sm:p-2 rounded-md transition-all duration-150 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2 text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 hover:bg-blue-100 dark:hover:bg-blue-600/20 focus:ring-blue-500 dark:focus:ring-blue-400" title="Editar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10" /></svg>
|
||||
</button>
|
||||
<button @click="confirmDeleteTarea(item)" class="p-1.5 sm:p-2 rounded-md transition-all duration-150 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2 text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-300 hover:bg-red-100 dark:hover:bg-red-600/20 focus:ring-red-500 dark:focus:ring-red-400" title="Eliminar">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12.56 0c1.153 0 2.24.03 3.22.077m3.22-.077L10.879 3.28a2.25 2.25 0 012.244-2.077h.093c.956 0 1.853.543 2.244 2.077L14.74 5.79m-4.858 0l-2.828-2.828A1.875 1.875 0 016.188 2.188l2.828 2.828m6.912 0l2.828-2.828a1.875 1.875 0 00-2.652-2.652L12 5.79M9.26 9h5.48L9.26 9z" /></svg>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</NucleoTable>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineProps, defineEmits } from 'vue'
|
||||
import { useTareasStore } from '@/stores/useTareas'
|
||||
import { formatDate, formatCurrency, getStatusClass } from '@/utils/formatters'
|
||||
import { useUi } from '@/stores/useUi'
|
||||
import { defineProps, defineEmits } from 'vue';
|
||||
import NucleoTable from '../ui/NucleoTable.vue'; // Import NucleoTable
|
||||
import { useTareasStore } from '../../stores/useTareas';
|
||||
import { formatDate, formatCurrency, getStatusClass } from '../../utils/formatters.js';
|
||||
// useUi store is now handled by NucleoTable
|
||||
|
||||
const ui = useUi()
|
||||
|
||||
defineProps({
|
||||
const props = defineProps({
|
||||
tareas: { type: Array, required: true, default: () => [] },
|
||||
})
|
||||
});
|
||||
|
||||
const emit = defineEmits(['edit'])
|
||||
const tareasStore = useTareasStore()
|
||||
const emit = defineEmits(['edit']); // Emits 'edit' to parent (TareasIndex.vue)
|
||||
const tareasStore = useTareasStore();
|
||||
|
||||
const editTarea = (id) => emit('edit', id)
|
||||
const columns = [
|
||||
{ key: 'id', label: 'ID' },
|
||||
{ key: 'titulo', label: 'Título' },
|
||||
{ key: 'empleado_id', label: 'Empleado ID' },
|
||||
{ key: 'fecha', label: 'Fecha' },
|
||||
{ key: 'estado', label: 'Estado' },
|
||||
{ key: 'tipo', label: 'Tipo' },
|
||||
{ key: 'precio', label: 'Precio' },
|
||||
{ key: 'planilla_id', label: 'Planilla ID' },
|
||||
];
|
||||
|
||||
// Keep existing methods
|
||||
const editTarea = (id) => emit('edit', id);
|
||||
|
||||
const confirmDeleteTarea = (tarea) => {
|
||||
if (confirm(`¿Está seguro de que desea eliminar la tarea "${tarea.titulo}" (ID: ${tarea.id})?`))
|
||||
deleteTareaInternal(tarea.id)
|
||||
}
|
||||
if (confirm(`¿Está seguro de que desea eliminar la tarea "${tarea.titulo}" (ID: ${tarea.id})?`)) {
|
||||
deleteTareaInternal(tarea.id);
|
||||
}
|
||||
};
|
||||
|
||||
const deleteTareaInternal = async (id) => {
|
||||
try {
|
||||
await tareasStore.deleteTarea(id)
|
||||
await tareasStore.deleteTarea(id);
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
alert('Ocurrió un error al eliminar la tarea.')
|
||||
console.error('Error deleting tarea:', e);
|
||||
alert('Ocurrió un error al eliminar la tarea.');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
64
ui/src/components/ui/NucleoTable.vue
Normal file
64
ui/src/components/ui/NucleoTable.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<div class="p-4 sm:p-6 rounded-lg overflow-x-auto" :style="{ backgroundColor: tableBgColor }">
|
||||
<table class="min-w-full divide-y" :class="[`divide-[var(${props.accentColor})]`]" :style="{ backgroundColor: tableBgColor }">
|
||||
<thead :class="[`divide-y divide-[var(${props.accentColor})]`]" :style="{ backgroundColor: tableBgColor }">
|
||||
<tr>
|
||||
<th v-for="column in columns" :key="column.key" class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">
|
||||
{{ column.label }}
|
||||
</th>
|
||||
<th v-if="hasActionSlot" class="px-4 py-3 sm:px-6 sm:py-3 text-left text-xs font-medium text-gray-500 dark:text-slate-400 uppercase tracking-wider">
|
||||
Acciones
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y" :class="[`divide-[var(${props.accentColor})]`]" :style="{ backgroundColor: tableBgColor }">
|
||||
<tr v-if="!items || items.length === 0">
|
||||
<td :colspan="columns.length + (hasActionSlot ? 1 : 0)" class="px-6 py-10 text-center text-gray-500 dark:text-slate-400 text-lg">
|
||||
No hay datos para mostrar.
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
v-for="(item, index) in items"
|
||||
:key="item.id || index"
|
||||
class="transition-colors duration-150 ease-in-out"
|
||||
:class="[`hover:bg-[var(${props.accentColor})]/10 dark:hover:bg-[var(${props.accentColor})]/20`]"
|
||||
>
|
||||
<td v-for="column in columns" :key="column.key" class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm text-gray-700 dark:text-slate-300">
|
||||
<slot :name="`cell-${column.key}`" :item="item" :index="index">
|
||||
{{ item[column.key] }}
|
||||
</slot>
|
||||
</td>
|
||||
<td v-if="hasActionSlot" class="px-4 py-3 sm:px-6 sm:py-4 whitespace-nowrap text-sm">
|
||||
<slot name="actions" :item="item" :index="index"></slot>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineProps, defineEmits, computed, useSlots } from 'vue';
|
||||
import { useUi } from '../../stores/useUi';
|
||||
|
||||
const props = defineProps({
|
||||
columns: { type: Array, required: true, default: () => [] },
|
||||
items: { type: Array, required: true, default: () => [] },
|
||||
accentColor: { type: String, required: true }, // Example: '--accent-color-empleados'
|
||||
tableBgColorName: { type: String, required: true }, // Example: 'tableBgColorEmpleados'
|
||||
});
|
||||
|
||||
const emit = defineEmits(['editItem', 'deleteItem']); // Define the emits that can be triggered
|
||||
|
||||
const ui = useUi();
|
||||
const slots = useSlots();
|
||||
|
||||
const tableBgColor = computed(() => {
|
||||
return ui[props.tableBgColorName] || 'transparent'; // Default to transparent if not found
|
||||
});
|
||||
|
||||
const hasActionSlot = computed(() => {
|
||||
// Check if the actions slot has content
|
||||
return !!slots.actions;
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user