hbox-docs/docs/tableros/pendientes.md
Leopoldo Rodríguez 1e63a7c738 Pendientes: campeón por pendiente, flechas ← →, franja para soltar y columna en el detalle
Pedido de Leo (27-oct): mover un pendiente a otra columna sin arrastrar y bajar a la vez,
cambiar la columna desde el detalle, y un solo campeón por pendiente que es quien lo mueve.

- backend/app.py: campo «campeon» (uno de los responsables; por omisión el primero).
  PATCH /api/tarea y POST /api/tareas/orden solo cambian la columna o el campeón si quien
  escribe es el campeón, un administrador o TAREAS_MUEVEN_SIEMPRE (claude, por los lotes).
  GET /api/tareas trae campeon y mueven_siempre.
- kanban.js / tablero.css: avatar del campeón primero y con anillo; flechas ← → en la
  tarjeta; franja fija arriba con las 4 columnas mientras se arrastra; botones de Columna
  y selector de Campeón en el detalle; tarjetas de otros sin arrastre ni flechas.
- tablero.py y lotes/README.md: «campeon» se puede poner en un lote.
- tests-campeon.sh (25 pruebas); tests-1014.sh: el PATCH de bob ya no cambia la columna.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013SfRSvyewSyFLfK9mjbGL8
2026-10-28 08:38:56 -06:00

52 lines
3.4 KiB
Markdown

---
title: "Pendientes"
description: "El tablero de pendientes del equipo: por hacer, en curso, bloqueado y hecho."
template: tablero.html
hide:
- toc
---
<div class="tb tb-pendientes">
<header class="tb-cab">
<div class="tb-cab__t"><h1>Pendientes</h1><span class="meta" id="meta">Ingeniería, producción, mecánica, compras, campo y gestión · por sitio</span></div>
<div class="tb-cab__acc"><span id="acciones-kb"></span></div>
</header>
<details class="info tb-como">
<summary>Cómo se usa</summary>
<ol>
<li>Cada tarjeta del tablero es un <b>pendiente</b> (no confundir con la tarjeta EinarBoard). Léelo antes de empezar el trabajo.</li>
<li>Para cambiarlo de columna: arrástralo (arriba aparece una franja con las cuatro columnas, suéltalo ahí y no tienes que bajar), usa las flechas <b>← →</b> de la tarjeta o los botones de <b>Columna</b> en el detalle; en el teléfono, <b>Mover a…</b>. El tablero anota quién lo movió y cuándo.</li>
<li><b>Campeón:</b> aunque un pendiente tenga varios responsables, uno solo lo mueve entre columnas y responde por él (su avatar va primero, con anillo). Se elige en el detalle; sin elegir, es el primero de la lista. Los demás responsables editan todo lo demás; para moverlo, pídele al campeón que te lo pase. Leo (administrador) puede mover cualquiera.</li>
<li>Toca el título para ver el detalle: descripción, enlaces, de qué depende y su historial. Ahí mismo edita y guarda.</li>
<li><b>Nuevo pendiente</b>: título corto, pista, responsable y fecha límite. Si depende de otro, márcalo en «Bloqueado por».</li>
<li>Columna <b>Bloqueado</b>: solo si no puedes avanzar. Escribe en la descripción qué falta y quién lo destraba.</li>
<li>Al terminar, muévelo a <b>Hecho</b>. No lo borres: solo el administrador borra, y el historial sirve de bitácora.</li>
<li>Rojo = vencido. Filtra por pista, responsable o versión de tarjeta; los filtros no cambian nada en el servidor.</li>
<li><b>Sitio</b>: cada pendiente dice dónde pasa (ICAVE, TIMSA, EIT, LCT o Querétaro). Los botones de sitio dejan solo los de tu sitio (puedes elegir varios); <b>Por sitio</b> muestra una fila por sitio. Al crear un pendiente con un sitio filtrado, ese sitio ya viene marcado. La dirección (<code>?sitio=eit</code>) se puede compartir.</li>
<li><b>Por persona</b> muestra una fila por responsable con sus pendientes en cada estado: sirve para ver quién está cargado y quién está libre. La dirección (<code>?vista=persona</code>, <code>?mios=1</code>) se puede compartir tal cual.</li>
</ol>
</details>
<div id="kb"></div>
</div>
<script>
(function () {
Kanban.montar(document.getElementById('kb'), {
filtros: true,
vistas: true,
botonNuevoEn: document.getElementById('acciones-kb'),
onCargado: (tareas, meta) => {
const abiertas = tareas.filter(t => t.estado !== 'hecho').length;
const venc = tareas.filter(t => t.vencida).length;
const bloq = tareas.filter(t => t.estado === 'bloqueado').length;
const n = (k, uno, varios) => k + ' ' + (k === 1 ? uno : varios);
document.getElementById('meta').textContent = [n(abiertas, 'abierto', 'abiertos'), n(bloq, 'bloqueado', 'bloqueados'), n(venc, 'vencido', 'vencidos')].join(' · ')
+ ' · al día a las ' + new Date().toLocaleTimeString('es-MX', { hour: '2-digit', minute: '2-digit', hour12: false })
+ (meta.user ? ' · ' + meta.user + (meta.admin ? ' (admin)' : '') : '');
}
});
})();
</script>