feat(UserManagement): creada vista para gestionar a los usuarios del sistema (solo admin)

parent d494c29a
Showing with 264 additions and 0 deletions
<template>
<Header :show-search="true"></Header>
<div class="container my-5">
<div class="row justify-content-center">
<div class="col-lg-12">
<div class="card h-100 card-custom">
<div class="card-body p-4">
<div class="text-center mb-4">
<h4 class="fw-bolder mb-2 text-primary-custom">Gestión de Usuarios</h4>
<p class="text-muted">Administra los usuarios de la plataforma.</p>
<hr>
</div>
<div class="d-flex justify-content-between align-items-center mb-3">
<div>
<label>
Mostrar
<select v-model="itemsPerPage" class="form-select form-select-sm d-inline-block w-auto mx-1">
<option value="5">5</option>
<option value="10">10</option>
<option value="15">15</option>
<option value="20">20</option>
</select>
entradas
</label>
</div>
</div>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead class="table-primary-custom">
<tr>
<th scope="col" @click="sortBy('name')" class="clickable-header">
Nombre
<i :class="getSortIcon('name')"></i>
</th>
<th scope="col" @click="sortBy('surname')" class="clickable-header">
Apellidos
<i :class="getSortIcon('surname')"></i>
</th>
<th scope="col" @click="sortBy('email')" class="clickable-header">
Email
<i :class="getSortIcon('email')"></i>
</th>
<th scope="col">Rol</th>
<th scope="col">Estado</th>
<th scope="col">Fecha desactivado</th>
<th scope="col">Acciones</th>
</tr>
</thead>
<tbody>
<tr v-for="user in paginatedUsers" :key="user.id">
<td>{{ user.name }}</td>
<td>{{ user.surname }}</td>
<td>{{ user.email }}</td>
<td>{{ user.role }}</td>
<td>
<span v-if="user.active" class="badge bg-custom-active">Activo</span>
<span v-else class="badge bg-custom-inactive">Inactivo</span>
</td>
<td>{{ user.deactivatedAt ? user.deactivatedAt : '-' }}</td>
<td>
<div class="d-flex gap-2">
<button v-if="user.active" @click="deactivateUser(user.id)" class="btn btn-outline-danger btn-sm" title="Desactivar">
<i class="bi bi-person-slash"></i>
</button>
<button v-else @click="reactivateUser(user.id)" class="btn btn-outline-success btn-sm" title="Reactivar">
<i class="bi bi-person-plus"></i>
</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="d-flex justify-content-between align-items-center mt-3">
<div class="small text-muted">Mostrando {{ startIndex + 1 }} a {{ endIndex }} de {{ users.length }} usuarios</div>
<nav aria-label="Page navigation">
<ul class="pagination pagination-sm mb-0 pagination-custom">
<li class="page-item" :class="{ 'disabled': currentPage === 1 }">
<a class="page-link" href="#" @click.prevent="prevPage">Anterior</a>
</li>
<li class="page-item" v-for="page in totalPages" :key="page" :class="{ 'active': page === currentPage }">
<a class="page-link" href="#" @click.prevent="goToPage(page)">{{ page }}</a>
</li>
<li class="page-item" :class="{ 'disabled': currentPage === totalPages }">
<a class="page-link" href="#" @click.prevent="nextPage">Siguiente</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
import Header from '@/components/Header.vue';
const users = ref([
{ id: 1, name: 'Adrián', surname: 'García Pérez', email: 'adrian@example.com', role: 'Usuario', active: true, deactivatedAt: null },
{ id: 2, name: 'Sofía', surname: 'Martínez López', email: 'sofia@example.com', role: 'Administrador', active: true, deactivatedAt: null },
{ id: 3, name: 'Pablo', surname: 'Díaz Ruiz', email: 'pablo@example.com', role: 'Usuario', active: false, deactivatedAt: '2024-05-10' },
{ id: 4, name: 'Lucía', surname: 'Fernández Gil', email: 'lucia@example.com', role: 'Usuario', active: true, deactivatedAt: null },
{ id: 5, name: 'Javier', surname: 'Torres Soto', email: 'javier@example.com', role: 'Usuario', active: false, deactivatedAt: '2024-05-15' },
{ id: 6, name: 'Carla', surname: 'Jiménez Vega', email: 'carla@example.com', role: 'Usuario', active: true, deactivatedAt: null },
{ id: 7, name: 'Daniel', surname: 'Sánchez Milla', email: 'daniel@example.com', role: 'Usuario', active: true, deactivatedAt: null },
{ id: 8, name: 'Elena', surname: 'Soto Ramos', email: 'elena@example.com', role: 'Usuario', active: false, deactivatedAt: '2024-05-20' }
]);
// Estado de la paginación y ordenación
const currentPage = ref(1);
const itemsPerPage = ref(5);
const sortKey = ref('name');
const sortOrder = ref('asc');
// Propiedad computada para ordenar los usuarios
const sortedUsers = computed(() => {
return users.value.slice().sort((a, b) => {
const keyA = a[sortKey.value];
const keyB = b[sortKey.value];
if (typeof keyA === 'string') {
const result = keyA.localeCompare(keyB);
return sortOrder.value === 'asc' ? result : -result;
} else {
const result = keyA - keyB;
return sortOrder.value === 'asc' ? result : -result;
}
});
});
// Propiedad computada para la paginación
const paginatedUsers = computed(() => {
const start = (currentPage.value - 1) * itemsPerPage.value;
const end = start + parseInt(itemsPerPage.value);
return sortedUsers.value.slice(start, end);
});
// Propiedad computada para el número total de páginas
const totalPages = computed(() => {
return Math.ceil(users.value.length / itemsPerPage.value);
});
// Propiedades computadas para el rango de la tabla
const startIndex = computed(() => (currentPage.value - 1) * itemsPerPage.value);
const endIndex = computed(() => {
const end = startIndex.value + parseInt(itemsPerPage.value);
return Math.min(end, users.value.length);
});
// Métodos de paginación
const goToPage = (page) => {
currentPage.value = page;
};
const prevPage = () => {
if (currentPage.value > 1) {
currentPage.value--;
}
};
const nextPage = () => {
if (currentPage.value < totalPages.value) {
currentPage.value++;
}
};
// Método de ordenación
const sortBy = (key) => {
if (sortKey.value === key) {
sortOrder.value = sortOrder.value === 'asc' ? 'desc' : 'asc';
} else {
sortKey.value = key;
sortOrder.value = 'asc';
}
};
// Método para mostrar el icono de ordenación
const getSortIcon = (key) => {
if (sortKey.value !== key) {
return 'bi bi-sort-alpha-down-alt';
}
return sortOrder.value === 'asc' ? 'bi bi-sort-alpha-down' : 'bi bi-sort-alpha-up';
};
// Métodos para activar/desactivar usuarios
const deactivateUser = (id) => {
const user = users.value.find(u => u.id === id);
if (user) {
user.active = false;
user.deactivatedAt = new Date().toISOString().slice(0, 10);
alert(`Usuario ${user.name} desactivado.`);
}
};
const reactivateUser = (id) => {
const user = users.value.find(u => u.id === id);
if (user) {
user.active = true;
user.deactivatedAt = null;
alert(`Usuario ${user.name} reactivado.`);
}
};
</script>
<style scoped>
.card-custom {
border-color: #793E6C;
box-shadow: 0 0 1rem rgba(121, 62, 108, 0.1);
border-radius: 1rem;
}
.table-primary-custom {
background-color: #793E6C;
color: white;
}
.table-hover tbody tr:hover {
background-color: #f4f6f5;
}
.text-primary-custom {
color:#2C0C21;
}
.clickable-header {
cursor: pointer;
}
.bg-custom-active {
background-color: #B386A2 !important;
color: white;
}
.bg-custom-inactive {
background-color: #E0E0E0 !important;
color: #6C6C6C;
}
/* Estilos para la paginación */
.pagination-custom .page-item .page-link {
border-radius: 5px;
margin: 0 2px;
border-color: #ccc;
color: #333;
font-weight: bold;
}
.pagination-custom .page-item.active .page-link {
background-color: #793E6C;
border-color: #793E6C;
color: white;
}
.pagination-custom .page-item.disabled .page-link {
color: #bbb;
}
</style>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment