This commit introduces the following features:
1. **Empleado UI Components:**
* `EmpleadoForm.vue`: A form for creating and editing employee data.
* `cardEmpleado.vue`: A component to display a summary of employee information in a card format.
* `tablaEmpleados.vue`: A component to display a list of employees in a table format.
* `EmpleadosIndex.vue`: A view that displays both the card and table components, allowing you to switch between views and create new employees.
2. **Chat Interface Integration:**
* Modified `agent/handlers.js` to parse specific chat commands:
* "Quiero crear un nuevo @empleado": Responds with the `EmpleadoForm`.
* "Ver @empleado<CEDULA>": Responds with the `cardEmpleado` for the specified employee.
* "Mostrame los primeros X @empleados": Responds with `tablaEmpleados` displaying the requested number of employees.
* I send formatted messages (e.g., `CHAT_UI_COMPONENT::EmpleadoForm`) that the chat UI can interpret to render the Vue components.
3. **Tests:**
* Added unit tests for the new Vue components (`EmpleadoForm.vue`, `cardEmpleado.vue`, `tablaEmpleados.vue`) using Vitest.
* Added integration tests for the chat command handling in `agent/handlers.js` using Jest.
* (Note: Test execution was inconclusive, but all necessary files and configurations are included).
These changes fulfill the issue requirements by creating the necessary UI for the empleado module and enabling the summoning of these UI elements through the chat interface.
113 lines
5.6 KiB
Vue
113 lines
5.6 KiB
Vue
<template>
|
|
<div class="bg-white shadow-lg rounded-lg p-6 m-4 w-full max-w-sm hover:shadow-xl transition-shadow duration-300 ease-in-out">
|
|
<div class="flex items-center mb-4">
|
|
<img
|
|
:src="employee.avatar_url || 'https://via.placeholder.com/150'"
|
|
alt="Avatar del empleado"
|
|
class="w-20 h-20 rounded-full mr-6 border-2 border-blue-500 object-cover"
|
|
/>
|
|
<div>
|
|
<h2 class="text-2xl font-bold text-gray-800">{{ employee.name }}</h2>
|
|
<p class="text-gray-600 text-sm">Cédula: {{ employee.cedula }}</p>
|
|
</div>
|
|
</div>
|
|
<div class="space-y-2">
|
|
<div v-if="employee.telefono" class="flex items-center text-gray-700">
|
|
<svg class="w-5 h-5 mr-2 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.308 1.154a11.042 11.042 0 005.516 5.516l1.154-2.308a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z"></path></svg>
|
|
<span>{{ employee.telefono }}</span>
|
|
</div>
|
|
<div v-if="employee.ubicacion" class="flex items-center text-gray-700">
|
|
<svg class="w-5 h-5 mr-2 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"></path></svg>
|
|
<span>{{ employee.ubicacion }}</span>
|
|
</div>
|
|
<div v-if="employee.idciat" class="flex items-center text-gray-700">
|
|
<svg class="w-5 h-5 mr-2 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V8a2 2 0 00-2-2h-5m-4 0V5a2 2 0 012-2h2a2 2 0 012 2v1m-4 0h4m-6 10v-5m0 5v0z"></path></svg>
|
|
<span>ID CIAT: {{ employee.idciat }}</span>
|
|
</div>
|
|
<div v-if="employee.grupo_estudio" class="flex items-center text-gray-700">
|
|
<svg class="w-5 h-5 mr-2 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12 14l9-5-9-5-9 5 9 5z"></path><path d="M12 14l6.16-3.422a12.083 12.083 0 01.665 6.479A11.952 11.952 0 0012 20.055a11.952 11.952 0 00-6.824-5.998 12.083 12.083 0 01.665-6.479L12 14z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 14l9-5-9-5-9 5 9 5zm0 0v3.945m0-3.945L6.161 10.58M17.839 10.58L12 14m5.839-3.42L12 14m0 0l6.161 3.42m-6.161-3.42L5.839 14.002"></path></svg>
|
|
<span>Grupo Estudio: {{ employee.grupo_estudio }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="mt-6 flex justify-end space-x-3">
|
|
<button @click="handleEdit" class="px-4 py-2 bg-blue-500 text-white text-sm font-medium rounded-md hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-offset-2">
|
|
Editar
|
|
</button>
|
|
<button @click="handleViewDetails" class="px-4 py-2 bg-gray-200 text-gray-700 text-sm font-medium rounded-md hover:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2">
|
|
Ver Detalles
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { PropType } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
|
|
// Define the structure of the employee object based on the Prisma schema
|
|
interface Employee {
|
|
id: string | number // Changed from BigInt to string | number for easier handling in frontend
|
|
name: string
|
|
cedula: number // Changed from BigInt
|
|
avatar_url?: string
|
|
telefono?: string
|
|
ubicacion: string
|
|
idciat?: string
|
|
grupo_estudio?: string
|
|
// created_at and updated_at are usually not displayed directly in a summary card
|
|
// empleado: boolean // This is implicit as it's an employee card
|
|
}
|
|
|
|
const props = defineProps({
|
|
employee: {
|
|
type: Object as PropType<Employee>,
|
|
required: true,
|
|
},
|
|
})
|
|
|
|
const router = useRouter()
|
|
|
|
const handleEdit = () => {
|
|
// Ensure employee.id is available and correctly typed for URL
|
|
router.push(`/empleados/edit/${props.employee.id}`)
|
|
}
|
|
|
|
const handleViewDetails = () => {
|
|
// This could navigate to a more detailed employee page if one exists
|
|
// For now, it can also navigate to an edit page or a specific detail view
|
|
// Depending on the application's routing structure, this might be the same as edit or a different view
|
|
router.push(`/empleados/view/${props.employee.id}`) // Assuming a dedicated view route exists or will be created
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
/* Scoped styles for the card ensure they don't leak */
|
|
.max-w-sm {
|
|
max-width: 24rem; /* Consistent with Tailwind's sm breakpoint for max-width */
|
|
}
|
|
|
|
/* Adding some subtle enhancements for visual appeal */
|
|
.text-2xl {
|
|
line-height: 1.2; /* Adjust line height for the title for better readability */
|
|
}
|
|
|
|
.flex svg {
|
|
flex-shrink: 0; /* Prevent SVGs from shrinking if text is long, ensuring icon consistency */
|
|
}
|
|
|
|
/* Styling for buttons for a more refined and interactive look */
|
|
button {
|
|
transition: background-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out, transform 0.1s ease-in-out;
|
|
}
|
|
button:hover {
|
|
transform: translateY(-1px); /* Slight lift on hover */
|
|
}
|
|
button:active {
|
|
transform: translateY(0px); /* Reset lift on click */
|
|
}
|
|
|
|
.rounded-full {
|
|
object-fit: cover; /* Ensures the avatar image covers the area without distortion */
|
|
}
|
|
</style>
|