Porcentaje de tareas por proyecto

This commit is contained in:
2026-08-04 01:00:36 +02:00
parent 4d76e7b7e3
commit 6752a9333d
3 changed files with 84 additions and 10 deletions

View File

@@ -10,7 +10,12 @@ class ProjectController extends Controller
{
public function index()
{
$projects = auth()->user()->projects()->latest()->get();
$projects = auth()->user()->projects()
->with(['tasks' => function ($query) {
$query->select('id', 'project_id', 'status');
}])
->latest()
->get();
return Inertia::render('Projects/Index', [
'projects' => $projects,

View File

@@ -111,6 +111,44 @@ .feature-icon {
width: 3rem;
}
.project-card {
background: rgba(255, 255, 255, 0.96);
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.project-card:hover {
transform: translateY(-2px);
box-shadow: 0 18px 35px rgba(13, 110, 253, 0.16) !important;
}
.project-card-top {
background: linear-gradient(135deg, rgba(13, 110, 253, 0.15), rgba(111, 66, 193, 0.20));
height: 7px;
}
.project-icon-badge {
align-items: center;
background: linear-gradient(135deg, #0d6efd, #6f42c1);
border-radius: 0.85rem;
color: #fff;
display: inline-flex;
font-size: 0.95rem;
height: 2.2rem;
justify-content: center;
min-width: 2.2rem;
}
.progress {
border-radius: 999px;
height: 0.55rem;
overflow: hidden;
}
.progress-bar {
background: linear-gradient(135deg, #0d6efd, #6f42c1);
border-radius: 999px;
}
.offcanvas {
max-width: 100vw;
}

View File

@@ -1,10 +1,23 @@
<script setup>
import { ref } from 'vue';
import { computed, ref } from 'vue';
import { Link, router } from '@inertiajs/vue3';
import { Modal } from 'bootstrap';
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue';
defineProps({ projects: Array });
const props = defineProps({ projects: Array });
const projectStats = computed(() => props.projects.map((project) => {
const tasks = Array.isArray(project.tasks) ? project.tasks : [];
const totalTasks = tasks.length;
const completedTasks = tasks.filter(task => task.status === 'done').length;
return {
project,
totalTasks,
completedTasks,
progress: totalTasks ? Math.round((completedTasks / totalTasks) * 100) : 0,
};
}));
// Referencia al elemento del DOM para manejar el modal de Bootstrap
const modalElement = ref(null);
@@ -122,19 +135,25 @@ const guardarRegistro = async () => {
</div>
<div class="row g-3">
<div v-for="project in projects" :key="project.id" class="col-sm-6 col-lg-4">
<div class="card h-100 shadow-sm">
<div v-for="item in projectStats" :key="item.project.id" class="col-sm-6 col-lg-4">
<div class="project-card card h-100 rounded-4 shadow-sm border-0 overflow-hidden">
<div class="project-card-top"></div>
<div class="card-body">
<div class="d-flex justify-content-between align-items-start gap-2 mb-3">
<Link :href="`/projects/${project.id}`" class="text-decoration-none text-dark flex-grow-1">
<h5 class="card-title mb-0">{{ project.name }}</h5>
<Link :href="`/projects/${item.project.id}`" class="text-decoration-none text-dark flex-grow-1">
<div class="d-flex align-items-center gap-2 mb-2">
<span class="project-icon-badge">
<i class="bi bi-kanban"></i>
</span>
<h5 class="card-title mb-0">{{ item.project.name }}</h5>
</div>
</Link>
<div class="d-flex align-items-center gap-2">
<button
type="button"
class="btn btn-link text-dark text-decoration-none p-0"
@click.stop="abrirEditar(project)"
@click.stop="abrirEditar(item.project)"
aria-label="Editar proyecto"
>
<i class="bi bi-pencil-square fs-5"></i>
@@ -143,14 +162,26 @@ const guardarRegistro = async () => {
<button
type="button"
class="btn btn-link text-danger text-decoration-none p-0"
@click.stop="eliminarProyecto(project)"
@click.stop="eliminarProyecto(item.project)"
aria-label="Eliminar proyecto"
>
<i class="bi bi-trash fs-5"></i>
</button>
</div>
</div>
<p class="card-text text-muted mb-0">{{ project.description }}</p>
<p class="card-text text-muted mb-3">
{{ item.project.description || 'Sin descripción' }}
</p>
<div class="d-flex justify-content-between align-items-center small text-muted mb-2">
<span>{{ item.totalTasks }} tareas</span>
<span>{{ item.completedTasks }} completas</span>
</div>
<div class="progress" role="progressbar" aria-label="Progreso del proyecto" aria-valuemin="0" aria-valuemax="100">
<div class="progress-bar" :style="{ width: `${item.progress}%` }"></div>
</div>
</div>
</div>
</div>