Frontend responsive
HTML, CSS y JavaScript sin frameworks. La tabla se ordena y pagina, los formularios se validan en cliente y en móvil cada fila pasa a ser una tarjeta. Todas las acciones se hacen con fetch contra la API.
Desarrollo web · Proyecto 02
Aplicación web CRUD y responsive para controlar el material de una pequeña empresa: portátiles, monitores, periféricos y licencias. Búsqueda, filtros, avisos de bajo stock y exportación a CSV, sobre una API REST en PHP y una base de datos MySQL.
ⓘ Demo con datos ficticios. En el navegador usa localStorage; la carpeta incluye el backend real en PHP/MySQL.
Oficina demo · datos ficticios
| Estado | Acciones |
|---|
HTML, CSS y JavaScript sin frameworks. La tabla se ordena y pagina, los formularios se validan en cliente y en móvil cada fila pasa a ser una tarjeta. Todas las acciones se hacen con fetch contra la API.
api.php expone GET, POST, PUT, PATCH y DELETE sobre artículos. Valida la entrada, usa PDO con sentencias preparadas y responde JSON con el código HTTP adecuado (201, 404, 409, 422…).
Dos tablas, categorias y articulos, con clave foránea, SKU único e índices para búsqueda y filtros. Los KPIs se calculan con una sola consulta agregada.
// POST: validar, insertar con sentencia preparada y devolver 201
case 'POST':
[$d, $errores] = validarArticulo(leerJson());
if ($errores) {
error(422, 'Revisa los campos marcados.', $errores);
}
$st = $pdo->prepare(
'INSERT INTO articulos (sku, nombre, categoria_id, estado, stock, stock_minimo, precio, ubicacion)
VALUES (:sku, :nombre, :categoria_id, :estado, :stock, :stock_minimo, :precio, :ubicacion)'
);
$st->execute($d);
responder(201, ['ok' => true, 'data' => buscarArticulo($pdo, (int) $pdo->lastInsertId())]);
// PATCH: ajuste de stock atómico, nunca por debajo de 0
case 'PATCH':
$delta = filter_var(leerJson()['delta'] ?? null, FILTER_VALIDATE_INT);
$st = $pdo->prepare(
'UPDATE articulos SET stock = CAST(stock AS SIGNED) + :delta
WHERE id = :id AND CAST(stock AS SIGNED) + :delta2 >= 0'
);
$st->execute(['delta' => $delta, 'delta2' => $delta, 'id' => $id]);
if ($st->rowCount() === 0) {
error(409, 'El stock no puede ser negativo.');
}
CREATE TABLE articulos (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
sku VARCHAR(20) NOT NULL,
nombre VARCHAR(120) NOT NULL,
categoria_id SMALLINT UNSIGNED NOT NULL,
estado ENUM('disponible','asignado','reparacion','baja') NOT NULL DEFAULT 'disponible',
stock INT UNSIGNED NOT NULL DEFAULT 0,
stock_minimo INT UNSIGNED NOT NULL DEFAULT 1,
precio DECIMAL(10,2) NOT NULL DEFAULT 0.00,
PRIMARY KEY (id),
UNIQUE KEY uq_articulos_sku (sku),
KEY idx_articulos_categoria (categoria_id),
KEY idx_articulos_estado (estado),
CONSTRAINT fk_articulos_categoria
FOREIGN KEY (categoria_id) REFERENCES categorias (id)
ON UPDATE CASCADE ON DELETE RESTRICT
) ENGINE=InnoDB; -- (extracto)
En un hosting estático los archivos .php pueden descargarse en lugar de mostrarse; para ejecutarlos hace falta PHP 8.1+ y MySQL (ver README).