Autosave: 20260205-053735
@ -1,21 +1,65 @@
|
|||||||
<?php
|
<?php
|
||||||
|
$pageTitle = "Añadir Nueva Columna al Kanban";
|
||||||
|
require_once 'layout_header.php';
|
||||||
require_once 'db/config.php';
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
// Asegurarse de que el usuario sea administrador
|
||||||
|
if ($_SESSION['user_role'] !== 'Administrador' && $_SESSION['user_role'] !== 'admin') {
|
||||||
|
echo "<div class='alert alert-danger'>Acceso denegado.</div>";
|
||||||
|
require_once 'layout_footer.php';
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$message = '';
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
$nombre = trim($_POST['nombre']);
|
$nombre = trim($_POST['nombre'] ?? '');
|
||||||
|
|
||||||
if (!empty($nombre)) {
|
if (!empty($nombre)) {
|
||||||
|
try {
|
||||||
$pdo = db();
|
$pdo = db();
|
||||||
|
|
||||||
// Find the current max order value
|
// Find the current max order value
|
||||||
$stmt_max_order = $pdo->query('SELECT MAX(orden) AS max_orden FROM kanban_columns');
|
$stmt_max_order = $pdo->query('SELECT MAX(orden) AS max_orden FROM kanban_columns');
|
||||||
$max_orden = $stmt_max_order->fetchColumn();
|
$max_orden = $stmt_max_order->fetchColumn();
|
||||||
$new_orden = $max_orden + 1;
|
$new_orden = ($max_orden === null) ? 0 : $max_orden + 1;
|
||||||
|
|
||||||
$stmt = $pdo->prepare('INSERT INTO kanban_columns (nombre, orden) VALUES (?, ?)');
|
$stmt = $pdo->prepare('INSERT INTO kanban_columns (nombre, orden) VALUES (?, ?)');
|
||||||
$stmt->execute([$nombre, $new_orden]);
|
|
||||||
|
if ($stmt->execute([$nombre, $new_orden])) {
|
||||||
|
// Usar una variable de sesión para mostrar el mensaje en la página de configuración
|
||||||
|
$_SESSION['success_message'] = "Columna '" . htmlspecialchars($nombre) . "' añadida correctamente.";
|
||||||
|
header('Location: configuracion.php');
|
||||||
|
exit;
|
||||||
|
} else {
|
||||||
|
$message = "<div class='alert alert-danger'>Error al añadir la columna.</div>";
|
||||||
|
}
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$message = "<div class='alert alert-danger'>Error de base de datos: " . $e->getMessage() . "</div>";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$message = "<div class='alert alert-warning'>El nombre de la columna no puede estar vacío.</div>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
header('Location: kanban.php');
|
<div class="container mt-5">
|
||||||
exit;
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h2>Añadir Nueva Columna al Kanban</h2>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<?php echo $message; ?>
|
||||||
|
<form method="POST" action="add_column.php">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="nombre" class="form-label">Nombre de la Nueva Columna</label>
|
||||||
|
<input type="text" class="form-control" id="nombre" name="nombre" required>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">Guardar Columna</button>
|
||||||
|
<a href="configuracion.php" class="btn btn-secondary">Cancelar</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php require_once 'layout_footer.php'; ?>
|
||||||
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 57 KiB |
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 144 KiB |
|
After Width: | Height: | Size: 98 KiB |
|
After Width: | Height: | Size: 119 KiB |
@ -12,63 +12,119 @@ if ($_SESSION['user_role'] !== 'Administrador' && $_SESSION['user_role'] !== 'ad
|
|||||||
|
|
||||||
$conn = db();
|
$conn = db();
|
||||||
|
|
||||||
// Obtener la configuración actual
|
// --- Gestión de Columnas ---
|
||||||
$query = "SELECT * FROM configuracion WHERE id = 1";
|
|
||||||
$result = $conn->query($query);
|
|
||||||
$config = $result->fetch(PDO::FETCH_ASSOC);
|
|
||||||
|
|
||||||
// Columnas disponibles
|
// Obtener todas las columnas del Kanban para la tabla de gestión
|
||||||
$available_columns = [
|
$query_manage_columns = "SELECT * FROM kanban_columns ORDER BY orden ASC";
|
||||||
'new' => 'Nuevos',
|
$stmt_manage_columns = $conn->query($query_manage_columns);
|
||||||
'reagendado' => 'Reagendado',
|
$management_columns = $stmt_manage_columns->fetchAll(PDO::FETCH_ASSOC);
|
||||||
'no_contactado' => 'No Contactado',
|
|
||||||
'contactado' => 'Contactado',
|
|
||||||
'agendado' => 'Agendado',
|
// --- Visibilidad de Columnas ---
|
||||||
'en_ruta' => 'En Ruta',
|
|
||||||
'entregado' => 'Entregado',
|
// Obtener la configuración actual de visibilidad
|
||||||
'no_entregado' => 'No Entregado',
|
$query_config = "SELECT * FROM configuracion WHERE id = 1";
|
||||||
'reprogramado' => 'Reprogramado'
|
$result_config = $conn->query($query_config);
|
||||||
];
|
$config = $result_config->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
$visible_columns = $config ? json_decode($config['kanban_columns'], true) : [];
|
$visible_columns = $config ? json_decode($config['kanban_columns'], true) : [];
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_visibility'])) {
|
||||||
$new_visible_columns = $_POST['columns'] ?? [];
|
$new_visible_columns = $_POST['columns'] ?? [];
|
||||||
$json_columns = json_encode($new_visible_columns);
|
$json_columns = json_encode($new_visible_columns);
|
||||||
|
|
||||||
$update_query = "UPDATE configuracion SET kanban_columns = :kanban_columns WHERE id = 1";
|
// Usar INSERT ... ON DUPLICATE KEY UPDATE para seguridad
|
||||||
|
$update_query = "INSERT INTO configuracion (id, kanban_columns) VALUES (1, :kanban_columns)
|
||||||
|
ON DUPLICATE KEY UPDATE kanban_columns = :kanban_columns";
|
||||||
$stmt = $conn->prepare($update_query);
|
$stmt = $conn->prepare($update_query);
|
||||||
$stmt->bindParam(':kanban_columns', $json_columns);
|
$stmt->bindParam(':kanban_columns', $json_columns);
|
||||||
|
|
||||||
if ($stmt->execute()) {
|
if ($stmt->execute()) {
|
||||||
echo "<div class='alert alert-success'>Configuración guardada correctamente.</div>";
|
echo "<div class='alert alert-success'>Configuración de visibilidad guardada.</div>";
|
||||||
$visible_columns = $new_visible_columns;
|
$visible_columns = $new_visible_columns; // Actualizar para mostrar el cambio inmediatamente
|
||||||
} else {
|
} else {
|
||||||
echo "<div class='alert alert-danger'>Error al guardar la configuración.</div>";
|
echo "<div class='alert alert-danger'>Error al guardar la configuración de visibilidad.</div>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Obtener todas las columnas de kanban_columns para el formulario de visibilidad
|
||||||
|
$all_db_columns_query = "SELECT nombre FROM kanban_columns ORDER BY orden ASC";
|
||||||
|
$stmt_all_db_columns = $conn->query($all_db_columns_query);
|
||||||
|
$available_columns_for_visibility = $stmt_all_db_columns->fetchAll(PDO::FETCH_COLUMN);
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div class="container mt-5">
|
<div class="container mt-5">
|
||||||
<h2>Configuración de Columnas del Kanban</h2>
|
|
||||||
<p>Selecciona las columnas que deseas que sean visibles en el tablero Kanban.</p>
|
|
||||||
|
|
||||||
|
<!-- Sección para Gestionar Columnas (Añadir, Editar, Eliminar) -->
|
||||||
|
<div class="card mb-5">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3>Gestionar Columnas del Kanban</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>Aquí puedes añadir, editar y eliminar las columnas que se usarán en el tablero Kanban.</p>
|
||||||
|
<a href="add_column.php" class="btn btn-success mb-3">
|
||||||
|
<i class="fas fa-plus"></i> Añadir Nueva Columna
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<table class="table table-bordered table-striped">
|
||||||
|
<thead class="table-dark">
|
||||||
|
<tr>
|
||||||
|
<th>Nombre de la Columna</th>
|
||||||
|
<th style="width: 150px;">Acciones</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php if (empty($management_columns)): ?>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2" class="text-center">No hay columnas definidas.</td>
|
||||||
|
</tr>
|
||||||
|
<?php else: ?>
|
||||||
|
<?php foreach ($management_columns as $column): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?php echo htmlspecialchars($column['nombre']); ?></td>
|
||||||
|
<td>
|
||||||
|
<a href="edit_column.php?id=<?php echo $column['id']; ?>" class="btn btn-primary btn-sm">
|
||||||
|
<i class="fas fa-edit"></i> Editar
|
||||||
|
</a>
|
||||||
|
<a href="delete_column.php?id=<?php echo $column['id']; ?>" class="btn btn-danger btn-sm" onclick="return confirm('¿Estás seguro de que quieres eliminar esta columna?');">
|
||||||
|
<i class="fas fa-trash"></i> Eliminar
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Sección para Configurar Visibilidad de Columnas -->
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3>Configurar Visibilidad de Columnas</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>Selecciona las columnas que deseas que sean visibles en el tablero Kanban.</p>
|
||||||
<form method="POST">
|
<form method="POST">
|
||||||
|
<input type="hidden" name="save_visibility" value="1">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<?php foreach ($available_columns as $key => $name): ?>
|
<?php foreach ($available_columns_for_visibility as $column_name): ?>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="checkbox" name="columns[]" value="<?php echo $key; ?>" id="col_<?php echo $key; ?>" <?php echo in_array($key, $visible_columns) ? 'checked' : ''; ?>>
|
<input class="form-check-input" type="checkbox" name="columns[]" value="<?php echo htmlspecialchars($column_name); ?>" id="col_<?php echo htmlspecialchars($column_name); ?>" <?php echo in_array($column_name, $visible_columns) ? 'checked' : ''; ?>>
|
||||||
<label class="form-check-label" for="col_<?php echo $key; ?>">
|
<label class="form-check-label" for="col_<?php echo htmlspecialchars($column_name); ?>">
|
||||||
<?php echo htmlspecialchars($name); ?>
|
<?php echo htmlspecialchars($column_name); ?>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary mt-3">Guardar Configuración</button>
|
<button type="submit" class="btn btn-primary mt-3">Guardar Visibilidad</button>
|
||||||
</form>
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php require_once 'layout_footer.php'; ?>
|
<?php require_once 'layout_footer.php'; ?>
|
||||||
@ -1,21 +1,45 @@
|
|||||||
<?php
|
<?php
|
||||||
|
session_start();
|
||||||
require_once 'db/config.php';
|
require_once 'db/config.php';
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
// Asegurarse de que el usuario sea administrador
|
||||||
$id = $_POST['id'];
|
if ($_SESSION['user_role'] !== 'Administrador' && $_SESSION['user_role'] !== 'admin') {
|
||||||
|
$_SESSION['error_message'] = "Acceso denegado.";
|
||||||
|
header('Location: configuracion.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
if (!empty($id)) {
|
if (isset($_GET['id']) && is_numeric($_GET['id'])) {
|
||||||
|
$id = $_GET['id'];
|
||||||
|
|
||||||
|
try {
|
||||||
$pdo = db();
|
$pdo = db();
|
||||||
|
|
||||||
// First, update info_productos to set column_id to NULL for the cards in the deleted column
|
// Opcional: Obtener el nombre de la columna antes de eliminarla para el mensaje
|
||||||
|
$stmt_name = $pdo->prepare("SELECT nombre FROM kanban_columns WHERE id = ?");
|
||||||
|
$stmt_name->execute([$id]);
|
||||||
|
$column_name = $stmt_name->fetchColumn();
|
||||||
|
|
||||||
|
// Primero, actualiza info_productos para desasociar las tarjetas de la columna
|
||||||
$stmt_update = $pdo->prepare('UPDATE info_productos SET column_id = NULL WHERE column_id = ?');
|
$stmt_update = $pdo->prepare('UPDATE info_productos SET column_id = NULL WHERE column_id = ?');
|
||||||
$stmt_update->execute([$id]);
|
$stmt_update->execute([$id]);
|
||||||
|
|
||||||
// Then, delete the column
|
// Luego, elimina la columna
|
||||||
$stmt_delete = $pdo->prepare('DELETE FROM kanban_columns WHERE id = ?');
|
$stmt_delete = $pdo->prepare('DELETE FROM kanban_columns WHERE id = ?');
|
||||||
$stmt_delete->execute([$id]);
|
|
||||||
|
if ($stmt_delete->execute([$id])) {
|
||||||
|
$_SESSION['success_message'] = "Columna '" . htmlspecialchars($column_name) . "' eliminada correctamente.";
|
||||||
|
} else {
|
||||||
|
$_SESSION['error_message'] = "Error al eliminar la columna.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$_SESSION['error_message'] = "Error de base de datos: " . $e->getMessage();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$_SESSION['error_message'] = "ID de columna no válido.";
|
||||||
}
|
}
|
||||||
|
|
||||||
header('Location: kanban.php');
|
header('Location: configuracion.php');
|
||||||
exit;
|
exit;
|
||||||
|
?>
|
||||||
@ -1,18 +1,82 @@
|
|||||||
<?php
|
<?php
|
||||||
session_start();
|
$pageTitle = "Editar Columna del Kanban";
|
||||||
|
require_once 'layout_header.php';
|
||||||
require_once 'db/config.php';
|
require_once 'db/config.php';
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['id'])) {
|
// Asegurarse de que el usuario sea administrador
|
||||||
$id = $_POST['id'];
|
if ($_SESSION['user_role'] !== 'Administrador' && $_SESSION['user_role'] !== 'admin') {
|
||||||
$nombre = $_POST['nombre'];
|
echo "<div class='alert alert-danger'>Acceso denegado.</div>";
|
||||||
|
require_once 'layout_footer.php';
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
$db = db();
|
$message = '';
|
||||||
$stmt = $db->prepare("UPDATE kanban_columns SET name = ? WHERE id = ?");
|
$column = null;
|
||||||
$stmt->bind_param('si', $nombre, $id);
|
|
||||||
$stmt->execute();
|
|
||||||
|
|
||||||
$_SESSION['success_message'] = "Columna actualizada exitosamente.";
|
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
|
||||||
header('Location: info_producto.php');
|
header('Location: configuracion.php');
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$column_id = $_GET['id'];
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// Procesar el formulario cuando se envía
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
$nombre = trim($_POST['nombre'] ?? '');
|
||||||
|
|
||||||
|
if (!empty($nombre)) {
|
||||||
|
$stmt = $pdo->prepare('UPDATE kanban_columns SET nombre = ? WHERE id = ?');
|
||||||
|
if ($stmt->execute([$nombre, $column_id])) {
|
||||||
|
$_SESSION['success_message'] = "Columna actualizada a '" . htmlspecialchars($nombre) . "'.";
|
||||||
|
header('Location: configuracion.php');
|
||||||
|
exit;
|
||||||
|
} else {
|
||||||
|
$message = "<div class='alert alert-danger'>Error al actualizar la columna.</div>";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$message = "<div class='alert alert-warning'>El nombre de la columna no puede estar vacío.</div>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obtener los datos de la columna para mostrar en el formulario
|
||||||
|
$stmt = $pdo->prepare('SELECT * FROM kanban_columns WHERE id = ?');
|
||||||
|
$stmt->execute([$column_id]);
|
||||||
|
$column = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (!$column) {
|
||||||
|
echo "<div class='alert alert-danger'>La columna no existe.</div>";
|
||||||
|
require_once 'layout_footer.php';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$message = "<div class='alert alert-danger'>Error de base de datos: " . $e->getMessage() . "</div>";
|
||||||
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
||||||
|
<div class="container mt-5">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h2>Editar Columna del Kanban</h2>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<?php echo $message; ?>
|
||||||
|
<?php if ($column): ?>
|
||||||
|
<form method="POST" action="edit_column.php?id=<?php echo $column_id; ?>">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="nombre" class="form-label">Nombre de la Columna</label>
|
||||||
|
<input type="text" class="form-control" id="nombre" name="nombre" value="<?php echo htmlspecialchars($column['nombre']); ?>" required>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">Actualizar Columna</button>
|
||||||
|
<a href="configuracion.php" class="btn btn-secondary">Cancelar</a>
|
||||||
|
</form>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php require_once 'layout_footer.php'; ?>
|
||||||
|
|||||||
140
kanban.php
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
session_start();
|
session_start();
|
||||||
require_once 'db/config.php';
|
require_once 'db/config.php';
|
||||||
|
|
||||||
@ -8,35 +9,44 @@ if (!isset($_SESSION['username'])) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$username = $_SESSION['username'];
|
$username = $_SESSION['username'];
|
||||||
$role = $_SESSION['role'];
|
$role = isset($_SESSION['role']) ? $_SESSION['role'] : '';
|
||||||
|
|
||||||
// Conectar a la base de datos
|
// Conectar a la base de datos
|
||||||
$pdo = db();
|
$pdo = db();
|
||||||
|
|
||||||
// Obtener la configuración de las columnas del Kanban
|
// 1. Obtener todas las columnas del Kanban
|
||||||
$stmt = $pdo->query("SELECT kanban_columns FROM configuracion WHERE id = 1");
|
$stmt_cols = $pdo->query("SELECT id, nombre FROM kanban_columns ORDER BY orden, id");
|
||||||
$config = $stmt->fetch(PDO::FETCH_ASSOC);
|
$columns_to_display = $stmt_cols->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
$columns_to_display = [];
|
// 2. Obtener todos los productos de información, uniéndolos con productos y columnas
|
||||||
if ($config && !empty($config['kanban_columns'])) {
|
$stmt_items = $pdo->query("
|
||||||
$column_ids = json_decode($config['kanban_columns'], true);
|
SELECT
|
||||||
if (!empty($column_ids)) {
|
ip.id,
|
||||||
$placeholders = implode(',', array_fill(0, count($column_ids), '?'));
|
ip.texto_informativo,
|
||||||
$stmt = $pdo->prepare("SELECT id, nombre FROM kanban_columns WHERE id IN ($placeholders)");
|
ip.imagen_url,
|
||||||
$stmt->execute($column_ids);
|
p.nombre as producto_nombre,
|
||||||
$columns_to_display = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
kc.nombre as estado_kanban
|
||||||
|
FROM
|
||||||
|
info_productos ip
|
||||||
|
LEFT JOIN
|
||||||
|
products p ON ip.producto_id = p.id
|
||||||
|
LEFT JOIN
|
||||||
|
kanban_columns kc ON ip.column_id = kc.id
|
||||||
|
ORDER BY
|
||||||
|
ip.orden, ip.id
|
||||||
|
");
|
||||||
|
$items = $stmt_items->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// 3. Agrupar items por el nombre de la columna (estado_kanban)
|
||||||
|
$items_by_column = [];
|
||||||
|
if ($items) {
|
||||||
|
foreach ($items as $item) {
|
||||||
|
if (!empty($item['estado_kanban'])) {
|
||||||
|
$items_by_column[$item['estado_kanban']][] = $item;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($columns_to_display)) {
|
|
||||||
$stmt = $pdo->query("SELECT id, nombre FROM kanban_columns");
|
|
||||||
$columns_to_display = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtener todos los productos de información
|
|
||||||
$stmt = $pdo->query("SELECT ip.*, p.nombre as producto_nombre FROM info_productos ip LEFT JOIN products p ON ip.product_id = p.id");
|
|
||||||
$items = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
|
|
||||||
$pageTitle = "Kanban de Productos";
|
$pageTitle = "Kanban de Productos";
|
||||||
$pageDescription = "Tablero Kanban para visualizar la información de los productos.";
|
$pageDescription = "Tablero Kanban para visualizar la información de los productos.";
|
||||||
|
|
||||||
@ -58,26 +68,31 @@ include 'layout_header.php';
|
|||||||
<div class="kanban-board-container">
|
<div class="kanban-board-container">
|
||||||
<div class="kanban-board">
|
<div class="kanban-board">
|
||||||
<?php foreach ($columns_to_display as $column): ?>
|
<?php foreach ($columns_to_display as $column): ?>
|
||||||
<div class="kanban-column" data-column-id="<?php echo $column['nombre']; ?>">
|
<div class="kanban-column" data-column-id="<?php echo $column['id']; ?>">
|
||||||
<div class="kanban-column-header">
|
<div class="kanban-column-header">
|
||||||
<h5><?php echo htmlspecialchars($column['nombre']); ?></h5>
|
<h5><?php echo htmlspecialchars($column['nombre']); ?></h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="kanban-column-body">
|
<div class="kanban-column-body">
|
||||||
<?php foreach ($items as $item): ?>
|
<?php if (isset($items_by_column[$column['nombre']])): ?>
|
||||||
<?php if ($item['estado_kanban'] == $column['nombre']): ?>
|
<?php foreach ($items_by_column[$column['nombre']] as $item): ?>
|
||||||
<div class="kanban-card" data-item-id="<?php echo $item['id']; ?>">
|
<div class="kanban-card" data-item-id="<?php echo $item['id']; ?>">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<?php if (!empty($item['imagen'])): ?>
|
<?php if (!empty($item['imagen_url']) && file_exists($item['imagen_url'])): ?>
|
||||||
<img src="assets/uploads/info_images/<?php echo htmlspecialchars($item['imagen']); ?>" class="card-img-top mb-2" alt="Imagen del producto">
|
<img src="<?php echo htmlspecialchars($item['imagen_url']); ?>" class="card-img-top mb-2" alt="Imagen del producto">
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<h6 class="card-title"><?php echo htmlspecialchars($item['titulo']); ?></h6>
|
|
||||||
<p class="card-text small"><?php echo htmlspecialchars($item['producto_nombre']); ?></p>
|
<h6 class="card-title"><?php echo htmlspecialchars($item['producto_nombre'] ?? 'Producto sin nombre'); ?></h6>
|
||||||
<button class="btn btn-sm btn-secondary" onclick="copiarTexto(this)">Copiar Texto</button>
|
|
||||||
<div class="texto-a-copiar" style="display:none;"><?php echo htmlspecialchars($item['texto']); ?></div>
|
<p class="card-text fs-sm text-muted"><?php echo nl2br(htmlspecialchars($item['texto_informativo'])); ?></p>
|
||||||
|
|
||||||
|
<button class="btn btn-sm btn-outline-secondary w-100 mt-2" onclick="copiarTexto(this)">
|
||||||
|
Copiar Texto
|
||||||
|
</button>
|
||||||
|
<div class="texto-a-copiar" style="display:none;"><?php echo htmlspecialchars($item['texto_informativo']); ?></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
@ -101,45 +116,80 @@ include 'layout_header.php';
|
|||||||
width: 300px;
|
width: 300px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
background-color: #f4f5f7;
|
background-color: #f4f5f7;
|
||||||
border-radius: 3px;
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||||
}
|
}
|
||||||
.kanban-column-header {
|
.kanban-column-header {
|
||||||
padding: 10px 15px;
|
padding: 12px 15px;
|
||||||
border-bottom: 1px solid #ddd;
|
border-bottom: 1px solid #e0e0e0;
|
||||||
|
background-color: #fff;
|
||||||
|
border-top-left-radius: 8px;
|
||||||
|
border-top-right-radius: 8px;
|
||||||
}
|
}
|
||||||
.kanban-column-body {
|
.kanban-column-body {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
min-height: 400px;
|
min-height: 200px; /* Altura mínima por si la columna está vacía */
|
||||||
overflow-y: auto;
|
max-height: 70vh; /* Altura máxima del 70% de la pantalla */
|
||||||
|
overflow-y: auto; /* Scroll vertical si el contenido excede la altura */
|
||||||
}
|
}
|
||||||
.kanban-card {
|
.kanban-card {
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
border-radius: 3px;
|
border-radius: 6px;
|
||||||
padding: 10px;
|
padding: 15px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
cursor: grab;
|
cursor: grab;
|
||||||
|
transition: box-shadow 0.2s ease;
|
||||||
|
}
|
||||||
|
.kanban-card:hover {
|
||||||
|
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
|
||||||
|
}
|
||||||
|
.card-title {
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 0; /* Ajustado para dar espacio al botón */
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function copiarTexto(button) {
|
function copiarTexto(button) {
|
||||||
var cardBody = button.closest('.card-body');
|
const cardBody = button.closest('.card-body');
|
||||||
var texto = cardBody.querySelector('.texto-a-copiar').innerText;
|
const texto = cardBody.querySelector('.texto-a-copiar').innerText;
|
||||||
|
const originalText = button.innerHTML;
|
||||||
|
|
||||||
var tempInput = document.createElement('textarea');
|
navigator.clipboard.writeText(texto).then(() => {
|
||||||
|
button.innerHTML = '<i class="fas fa-check"></i> Copiado!';
|
||||||
|
button.classList.remove('btn-outline-secondary');
|
||||||
|
button.classList.add('btn-success');
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
button.innerHTML = originalText;
|
||||||
|
button.classList.remove('btn-success');
|
||||||
|
button.classList.add('btn-outline-secondary');
|
||||||
|
}, 2000);
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Error al copiar texto: ', err);
|
||||||
|
const tempInput = document.createElement('textarea');
|
||||||
tempInput.style.position = 'absolute';
|
tempInput.style.position = 'absolute';
|
||||||
tempInput.style.left = '-9999px';
|
tempInput.style.left = '-9999px';
|
||||||
tempInput.value = texto;
|
tempInput.value = texto;
|
||||||
document.body.appendChild(tempInput);
|
document.body.appendChild(tempInput);
|
||||||
tempInput.select();
|
tempInput.select();
|
||||||
|
try {
|
||||||
document.execCommand('copy');
|
document.execCommand('copy');
|
||||||
document.body.removeChild(tempInput);
|
button.innerHTML = '<i class="fas fa-check"></i> Copiado!';
|
||||||
|
button.classList.remove('btn-outline-secondary');
|
||||||
|
button.classList.add('btn-success');
|
||||||
|
|
||||||
button.innerText = 'Copiado!';
|
setTimeout(() => {
|
||||||
setTimeout(function() {
|
button.innerHTML = originalText;
|
||||||
button.innerText = 'Copiar Texto';
|
button.classList.remove('btn-success');
|
||||||
|
button.classList.add('btn-outline-secondary');
|
||||||
}, 2000);
|
}, 2000);
|
||||||
|
} catch (e) {
|
||||||
|
alert('No se pudo copiar el texto.');
|
||||||
|
}
|
||||||
|
document.body.removeChild(tempInput);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||