ars-report-kit: kit portátil de branding para reportes/cotizaciones
Extraído de autosanta-stack (agente de santa) para reusarlo en cualquier proyecto: plantilla base + 2 ejemplos + logo + Paged.js, sin dependencias de servidor. Ver AGENT_GUIDE.md.
This commit is contained in:
commit
a2bd6cb697
7 changed files with 34125 additions and 0 deletions
227
AGENT_GUIDE.md
Normal file
227
AGENT_GUIDE.md
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
# AGENT_GUIDE — Generar reportes y cotizaciones con la plantilla ARS Integradores
|
||||
|
||||
Eres un agente que produce documentos ejecutivos (reportes técnicos, incidentes,
|
||||
cotizaciones, propuestas) con la identidad visual de **ARS Integradores**. Los
|
||||
entregables se ven en el navegador y se exportan a **PDF tamaño carta** con
|
||||
encabezado y pie de página en **cada** hoja.
|
||||
|
||||
Esta capacidad NO depende de ningún servidor: es un archivo HTML autocontenido que
|
||||
abres en Chrome. Trabaja en español.
|
||||
|
||||
---
|
||||
|
||||
## Archivos del kit (deben estar juntos en la misma carpeta)
|
||||
|
||||
| Archivo | Para qué |
|
||||
|---|---|
|
||||
| `ars_report_base.html` | Plantilla maestra. **Cópiala** y rellénala. No la edites en su lugar. |
|
||||
| `logo-report.jpg` | Logo ARS. Referenciado como `src="logo-report.jpg"`. |
|
||||
| `paged.polyfill.js` | Motor de paginación (Paged.js). Necesario sólo al exportar a PDF. |
|
||||
| `example_cotizacion.html` | Ejemplo completo de una cotización. |
|
||||
| `example_reporte.html` | Ejemplo completo de un reporte técnico. |
|
||||
|
||||
**Regla de oro:** cada documento que generes es una **copia** de `ars_report_base.html`
|
||||
guardada con otro nombre (p. ej. `COT-2026-014.html`), en la **misma carpeta** que
|
||||
`logo-report.jpg` y `paged.polyfill.js`.
|
||||
|
||||
---
|
||||
|
||||
## Cómo generar un documento (flujo)
|
||||
|
||||
1. Copia `ars_report_base.html` → `<FOLIO>.html`.
|
||||
2. Rellena las **ZONAS DE EDICIÓN** marcadas con `<!-- EDIT ... -->`:
|
||||
- `<title>` de la pestaña.
|
||||
- Título / subtítulo (`.title-block`).
|
||||
- Barra de folio (`.folio-bar`): folio, fecha, referencia, clasificación.
|
||||
- Info de cliente (`.contract-info`).
|
||||
- Cuerpo (`.body`): una `.section` por tema, usando los componentes de abajo.
|
||||
- Mes/año del pie (`.footer .right`) si aplica.
|
||||
3. Si necesitas estilos propios, agrégalos en el `<style>` donde dice
|
||||
`/* EDIT: agrega aquí CSS extra */`. **Nunca** toques los colores base ni la
|
||||
lógica de `@page`/`.ars-header`/`.ars-footer`.
|
||||
4. Exporta a PDF (ver más abajo).
|
||||
|
||||
---
|
||||
|
||||
## Reglas de marca — OBLIGATORIAS
|
||||
|
||||
- **Fuente:** `'Century Gothic', CenturyGothic, 'Apple Gothic', 'Trebuchet MS', Arial, sans-serif`
|
||||
(fuente de sistema). **Prohibido** importar Google Fonts o cualquier recurso externo.
|
||||
- **Color primario:** `#c81b74` (rosa magenta), variable CSS `--pink`. No lo cambies.
|
||||
- **Logo:** `logo-report.jpg`, esquina superior derecha, altura 70px.
|
||||
- **URL:** texto `arsintegradores.com` arriba a la izquierda (prefijo `ars` en negrita oscura).
|
||||
- **Título:** parallelogramo rosa (`.title-block` con `clip-path`).
|
||||
- **Encabezados de sección:** 15px, MAYÚSCULAS, rosa, borde izquierdo `3px solid var(--pink)`.
|
||||
- **Cuerpo:** 12px.
|
||||
- **Pie de página (fijo, no lo inventes):** Oficina (81) 8123 2899 · Tepatitlán 201 Col.
|
||||
Mitras Sur, Mty. NL, 64020 · arsintegradores.com.
|
||||
|
||||
---
|
||||
|
||||
## Regla #1 de PAGINACIÓN — no la reinventes
|
||||
|
||||
La plantilla YA logra encabezado + pie en CADA página impresa mediante **"running
|
||||
elements"**: `.ars-header { position: running(arsHeader) }` / `.ars-footer { ... }`
|
||||
combinado con `@page { @top-left { content: element(arsHeader) } @bottom-left { ... } }`.
|
||||
Esto se activa poniendo `class="paged"` en `<html>` (lo hace el botón "Exportar PDF").
|
||||
|
||||
**PROHIBIDO** para conseguir header/footer por página:
|
||||
- `<table>` con `<thead>`/`<tfoot>`.
|
||||
- pie con `position: fixed`.
|
||||
- el enfoque "sin running elements" (el pie sale SÓLO en la última página — está mal).
|
||||
|
||||
Para forzar que una sección empiece en página nueva, añádele la clase `page-break`:
|
||||
`<div class="section page-break">`.
|
||||
|
||||
**Evita Chart.js / `<canvas>`** — rompen la paginación de Paged.js. Usa KPIs y tablas CSS.
|
||||
|
||||
---
|
||||
|
||||
## Convención de folios
|
||||
|
||||
| Prefijo | Tipo de documento |
|
||||
|---|---|
|
||||
| `INC-YYYY-NNN` | Reporte de incidente |
|
||||
| `SOL-YYYY-NNN` | Reporte de solución / corrección |
|
||||
| `RPT-YYYY-NNN` | Reporte ejecutivo general (inventario, auditoría, análisis) |
|
||||
| `COT-YYYY-NNN` | Cotización |
|
||||
| `PROP-YYYY-NNN` | Propuesta / plan de trabajo |
|
||||
|
||||
`NNN` es correlativo por año. Fecha en formato "15 de julio de 2026".
|
||||
Clasificación típica: `Confidencial`.
|
||||
|
||||
---
|
||||
|
||||
## Componentes disponibles (copia y pega dentro de `.body`)
|
||||
|
||||
### Barras de estado (arriba del cuerpo, ancho completo)
|
||||
```html
|
||||
<div class="alert-bar"><span class="dot"></span> Incidente activo — atención requerida</div>
|
||||
<div class="resolved-bar"><span class="dot"></span> Incidente resuelto</div>
|
||||
```
|
||||
|
||||
### KPIs (métricas destacadas — 4 por fila)
|
||||
```html
|
||||
<div class="summary-grid">
|
||||
<div class="kpi pink"><div class="val">41</div><div class="lbl">Dispositivos</div></div>
|
||||
<div class="kpi green"><div class="val">99.8%</div><div class="lbl">Disponibilidad</div></div>
|
||||
<div class="kpi amber"><div class="val">3</div><div class="lbl">Advertencias</div></div>
|
||||
<div class="kpi red"><div class="val">0</div><div class="lbl">Críticos</div></div>
|
||||
</div>
|
||||
```
|
||||
Modificadores de color del `.kpi`: `pink`, `green`, `amber`, `red` (o ninguno = oscuro).
|
||||
|
||||
### Sección con texto y lista
|
||||
```html
|
||||
<div class="section">
|
||||
<h2>Diagnóstico</h2>
|
||||
<p>Párrafo...</p>
|
||||
<ul><li>Punto uno</li><li>Punto dos</li></ul>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Tabla
|
||||
```html
|
||||
<table>
|
||||
<thead><tr><th>Dispositivo</th><th>IP</th><th>Estado</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>SWP101</td><td>192.168.0.236</td><td><span class="badge badge-ok">OK</span></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
```
|
||||
Para columnas numéricas alinéalas a la derecha con `class="num"` en el `<td>`.
|
||||
|
||||
### Badges (etiquetas de estado)
|
||||
`badge-critical` · `badge-high` · `badge-medium` · `badge-ok` · `badge-active` ·
|
||||
`badge-info` · `badge-historic`.
|
||||
```html
|
||||
<span class="badge badge-critical">CRÍTICO</span>
|
||||
```
|
||||
|
||||
### Cajas de resaltado
|
||||
```html
|
||||
<div class="highlight-box">Nota clave (rosa).</div>
|
||||
<div class="info-box">Información (azul).</div>
|
||||
<div class="warn-box">Advertencia (ámbar).</div>
|
||||
<div class="success-box">Éxito / confirmado (verde).</div>
|
||||
```
|
||||
|
||||
### Rejilla de causas (2 columnas)
|
||||
```html
|
||||
<div class="cause-grid">
|
||||
<div class="cause-card"><h4>Causa raíz</h4><p>...</p></div>
|
||||
<div class="cause-card"><h4>Factor contribuyente</h4><p>...</p></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Recomendaciones (lista numerada con círculos)
|
||||
```html
|
||||
<ol class="rec-list">
|
||||
<li><div class="rec-body"><h4>Título</h4><p>Descripción...</p>
|
||||
<span class="tag green">Prioridad baja</span></div></li>
|
||||
</ol>
|
||||
```
|
||||
Variantes de `.tag`: (default rosa) · `amber` · `green` · `blue`.
|
||||
|
||||
### Línea de tiempo
|
||||
```html
|
||||
<ul class="timeline">
|
||||
<li><div class="tl-time">10:32 CST</div><div class="tl-desc">Evento...</div></li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
### Cotizaciones — tabla de partidas + totales
|
||||
```html
|
||||
<table>
|
||||
<thead><tr><th>#</th><th>Descripción</th><th>Cant.</th><th>P. Unit.</th><th>Importe</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>1</td><td>Switch UniFi US48PRO</td><td class="num">2</td>
|
||||
<td class="num">$18,500.00</td><td class="num">$37,000.00</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="totals">
|
||||
<div class="row"><span>Subtotal</span><span class="num">$37,000.00</span></div>
|
||||
<div class="row"><span>IVA (16%)</span><span class="num">$5,920.00</span></div>
|
||||
<div class="row grand"><span>Total MXN</span><span class="num">$42,920.00</span></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Otros
|
||||
- `<div class="divider"></div>` — separador fino.
|
||||
- `<code>ethernet0/1.41</code>` — código en línea (se ve en rosa).
|
||||
|
||||
---
|
||||
|
||||
## Exportar a PDF
|
||||
|
||||
**Manual (recomendado):**
|
||||
1. Abre el `.html` en Google Chrome (doble clic o `file://...`).
|
||||
2. Clic en el botón rosa **"⎙ Exportar PDF"** (esquina inferior derecha).
|
||||
3. En el diálogo de impresión: Destino = **Guardar como PDF**, Márgenes = **Predeterminados**
|
||||
(o Ninguno), **activa "Gráficos de fondo"**, Tamaño = **Carta**. Guardar.
|
||||
|
||||
**Automatizado (headless):** Chrome/Chromium headless respeta Paged.js si esperas al render.
|
||||
Ejemplo conceptual:
|
||||
```bash
|
||||
google-chrome --headless --disable-gpu --no-pdf-header-footer \
|
||||
--print-to-pdf=SALIDA.pdf --virtual-time-budget=10000 \
|
||||
"file:///ruta/COT-2026-014.html?export=1"
|
||||
```
|
||||
> Nota: el botón fija `class="paged"` vía clic. Para headless puro, agrega en tu copia
|
||||
> un pequeño script que, si `location.search` contiene `export=1`, llame a `exportPDF()`
|
||||
> automáticamente al cargar. (No lo hagas en la vista normal, o perderás el modo edición.)
|
||||
|
||||
**NO uses WeasyPrint ni wkhtmltopdf**: no ejecutan el JS de Paged.js y romperán el
|
||||
encabezado/pie por página.
|
||||
|
||||
---
|
||||
|
||||
## Checklist antes de entregar
|
||||
|
||||
- [ ] Folio correcto y correlativo (prefijo adecuado).
|
||||
- [ ] Título, cliente y fecha correctos.
|
||||
- [ ] Todo el cuerpo dentro de `.body`, en `.section`.
|
||||
- [ ] Sin recursos externos (fuentes, imágenes, CDNs). Sólo `logo-report.jpg` local.
|
||||
- [ ] Probado en pantalla (se ve bien) y exportado a PDF (header + pie en TODAS las hojas).
|
||||
- [ ] Números de cotización cuadran (subtotal + IVA = total).
|
||||
50
README.md
Normal file
50
README.md
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# ARS Report Kit
|
||||
|
||||
Kit **portátil y autocontenido** para que cualquier agente genere reportes,
|
||||
incidentes y cotizaciones con la identidad visual de **ARS Integradores** y los
|
||||
exporte a **PDF carta con encabezado y pie en cada página**. No requiere Flask,
|
||||
NetBox ni ningún servidor: sólo un navegador (Chrome) para el PDF.
|
||||
|
||||
## Contenido
|
||||
|
||||
| Archivo | Descripción |
|
||||
|---|---|
|
||||
| `AGENT_GUIDE.md` | **El prompt / instrucciones** para el agente. Empieza aquí. |
|
||||
| `ars_report_base.html` | Plantilla maestra a copiar y rellenar. |
|
||||
| `example_reporte.html` | Ejemplo completo: reporte técnico. |
|
||||
| `example_cotizacion.html` | Ejemplo completo: cotización con totales. |
|
||||
| `logo-report.jpg` | Logo ARS (referenciado localmente). |
|
||||
| `paged.polyfill.js` | Motor de paginación Paged.js (local, sin CDN). |
|
||||
|
||||
**Regla:** todo `.html` generado debe quedar en la MISMA carpeta que
|
||||
`logo-report.jpg` y `paged.polyfill.js`.
|
||||
|
||||
## Uso rápido
|
||||
|
||||
1. El agente lee `AGENT_GUIDE.md`.
|
||||
2. Copia `ars_report_base.html` → `<FOLIO>.html` y rellena las zonas `<!-- EDIT -->`.
|
||||
3. Abre en Chrome → botón **"Exportar PDF"** → Guardar como PDF (Carta, con gráficos de fondo).
|
||||
|
||||
## Distribución vía control plane (recomendado)
|
||||
|
||||
En lugar de que cada agente lleve su propio reporteador, publica **este kit** como
|
||||
un recurso único en el control plane y que los agentes lo soliciten:
|
||||
|
||||
- **Como skill/paquete compartido:** expón la carpeta `ars-report-kit/` completa.
|
||||
Los agentes descargan los 6 archivos a un directorio de trabajo y operan localmente.
|
||||
- **Contrato mínimo que un agente necesita del control plane:**
|
||||
1. `AGENT_GUIDE.md` (las reglas y componentes).
|
||||
2. `ars_report_base.html` (la plantilla).
|
||||
3. `logo-report.jpg` + `paged.polyfill.js` (assets binarios).
|
||||
- **Versionado:** trata el kit como una unidad versionada (p. ej. `ars-report-kit@1.0`).
|
||||
Si cambian marca o componentes, subes una versión; los agentes siempre piden la última.
|
||||
|
||||
De esta forma la marca y la paginación viven en **un solo lugar** y se corrigen una vez
|
||||
para todos.
|
||||
|
||||
## Notas técnicas
|
||||
|
||||
- **No** usar WeasyPrint / wkhtmltopdf: no ejecutan Paged.js → rompen header/pie por página.
|
||||
- **Evitar** Chart.js / `<canvas>`: rompen la paginación. Usar KPIs y tablas CSS.
|
||||
- Sin recursos externos (fuente de sistema, sin Google Fonts, sin CDNs).
|
||||
- Color primario `#c81b74`; fuente `Century Gothic` con fallbacks.
|
||||
298
ars_report_base.html
Normal file
298
ars_report_base.html
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<!-- ════════════════════════════════════════════════════════════════════
|
||||
PLANTILLA BASE — REPORTES / COTIZACIONES ARS INTEGRADORES
|
||||
Standalone (sin Flask/Jinja). Copia este archivo, rellena las ZONAS
|
||||
DE EDICIÓN marcadas con <!-- EDIT ... --> y ábrelo en Chrome.
|
||||
Para PDF: botón "Exportar PDF" (esquina inf. der.) → Guardar como PDF.
|
||||
Requiere que "logo-report.jpg" y "paged.polyfill.js" estén EN LA MISMA
|
||||
CARPETA que este archivo.
|
||||
════════════════════════════════════════════════════════════════════ -->
|
||||
<!-- EDIT: título de la pestaña del navegador -->
|
||||
<title>Reporte — ARS Integradores</title>
|
||||
<style>
|
||||
:root {
|
||||
--pink: #c81b74; /* color primario ARS — NO cambiar */
|
||||
--pink-light: #fce8f3;
|
||||
--dark: #2e2e2e;
|
||||
--mid: #666;
|
||||
--light: #f5f5f5;
|
||||
}
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body {
|
||||
font-family: 'Century Gothic', CenturyGothic, 'Apple Gothic', 'Trebuchet MS', Arial, sans-serif;
|
||||
font-size: 12px;
|
||||
color: var(--dark);
|
||||
}
|
||||
|
||||
/* ── Modo PANTALLA (por defecto) ─────────────────────────────── */
|
||||
body { background: #e5e5e5; padding: 40px 20px; }
|
||||
.screen-page {
|
||||
max-width: 860px; margin: 0 auto; background: #fff;
|
||||
box-shadow: 0 6px 32px rgba(0,0,0,0.14);
|
||||
}
|
||||
.export-btn {
|
||||
position: fixed; bottom: 32px; right: 32px; z-index: 9999;
|
||||
background: var(--pink); color: #fff; border: none;
|
||||
padding: 12px 24px; font-family: inherit; font-size: 13px; font-weight: 700;
|
||||
cursor: pointer; border-radius: 4px;
|
||||
box-shadow: 0 4px 16px rgba(200,27,116,0.40); transition: background 0.15s;
|
||||
}
|
||||
.export-btn:hover { background: #a5145e; }
|
||||
|
||||
/* ── Modo PAGINADO (activado por <html class="paged"> al exportar) ─
|
||||
Aquí ocurre la MAGIA de header+footer en CADA página del PDF vía
|
||||
"running elements" + @page. NO reinventar esto. ──────────────── */
|
||||
html.paged body { background: #fff; padding: 0; }
|
||||
html.paged .screen-page { max-width: none; margin: 0; box-shadow: none; }
|
||||
html.paged .export-btn { display: none; }
|
||||
html.paged .ars-header { position: running(arsHeader); }
|
||||
html.paged .ars-footer { position: running(arsFooter); }
|
||||
|
||||
@page {
|
||||
size: letter;
|
||||
margin-top: 108px;
|
||||
margin-bottom: 56px;
|
||||
margin-left: 40px;
|
||||
margin-right: 40px;
|
||||
@top-left { content: element(arsHeader); width: 100%; vertical-align: bottom; }
|
||||
@bottom-left { content: element(arsFooter); width: 100%; vertical-align: top; }
|
||||
}
|
||||
@media print { * { -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; } }
|
||||
|
||||
/* ── Header / Footer ──────────────────────────────────────────── */
|
||||
.top-bar {
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
padding: 16px 40px 14px; background: #fff;
|
||||
border-bottom: 2px solid var(--pink); width: 100%;
|
||||
}
|
||||
.ars-block { text-align: right; }
|
||||
.ars-logo { height: 70px; display: block; }
|
||||
.ars-url { font-size: 14px; font-style: italic; font-weight: 600; color: var(--pink); margin-top: 4px; }
|
||||
.ars-url b { color: var(--dark); font-style: normal; }
|
||||
|
||||
.footer {
|
||||
border-top: 2.5px solid var(--pink); padding: 10px 40px;
|
||||
display: flex; justify-content: space-between; align-items: center;
|
||||
font-size: 10px; color: var(--mid); background: #fff; width: 100%;
|
||||
}
|
||||
.footer .office-label { color: var(--pink); font-style: italic; font-weight: 600; }
|
||||
.footer .right { text-align: right; font-weight: 600; color: var(--dark); line-height: 1.6; }
|
||||
|
||||
/* ── Bloque de título (parallelogram) ─────────────────────────── */
|
||||
.title-wrap { padding: 32px 40px 24px; }
|
||||
.title-block {
|
||||
background: var(--pink);
|
||||
clip-path: polygon(0 0, 87% 0, 100% 100%, 0 100%);
|
||||
padding: 26px 130px 26px 32px;
|
||||
}
|
||||
.title-block .label { font-size: 20px; font-weight: 800; color: #fff; text-transform: uppercase; letter-spacing: 1px; line-height: 1.1; margin-bottom: 10px; }
|
||||
.title-block .subtitle { font-size: 15px; font-weight: 300; color: #fff; text-transform: uppercase; line-height: 1.4; }
|
||||
|
||||
/* ── Barra de folio ───────────────────────────────────────────── */
|
||||
.folio-bar {
|
||||
display: flex; justify-content: space-between; align-items: center;
|
||||
background: var(--pink-light); border-left: 4px solid var(--pink);
|
||||
padding: 8px 14px; margin: 0 40px 18px; font-size: 10px;
|
||||
}
|
||||
.folio-bar .folio-num { font-size: 13px; font-weight: 800; color: var(--pink); letter-spacing: 1px; }
|
||||
.folio-bar .folio-meta { color: var(--mid); text-align: right; line-height: 1.7; }
|
||||
.folio-bar .folio-meta b { color: var(--dark); }
|
||||
|
||||
/* ── Info de contrato / cliente ───────────────────────────────── */
|
||||
.contract-info { padding: 0 40px 20px; border-bottom: 1px solid #e8e8e8; margin-bottom: 20px; }
|
||||
.contract-info .cname { font-size: 14px; font-weight: 700; color: var(--dark); text-transform: uppercase; line-height: 1.65; margin-bottom: 5px; }
|
||||
.contract-info .cnum { font-size: 15px; font-weight: 700; margin-bottom: 5px; }
|
||||
.contract-info .cloc { font-size: 13px; color: var(--mid); line-height: 1.6; }
|
||||
.contract-info .cloc b { color: var(--dark); }
|
||||
|
||||
/* ── Barras de estado ─────────────────────────────────────────── */
|
||||
.alert-bar {
|
||||
margin: 0 40px 22px; background: var(--pink); color: #fff;
|
||||
padding: 10px 16px; font-size: 11px; font-weight: 600; letter-spacing: 0.3px;
|
||||
display: flex; align-items: center; gap: 10px;
|
||||
}
|
||||
.alert-bar .dot { width: 8px; height: 8px; border-radius: 50%; background: #fff; flex-shrink: 0; }
|
||||
.resolved-bar {
|
||||
margin: 0 40px 22px; background: #eafaf1; border-left: 4px solid #2a9d8f; color: #0d4f3c;
|
||||
padding: 10px 16px; font-size: 11px; font-weight: 600; letter-spacing: 0.3px;
|
||||
display: flex; align-items: center; gap: 10px;
|
||||
}
|
||||
.resolved-bar .dot { width: 8px; height: 8px; border-radius: 50%; background: #2a9d8f; flex-shrink: 0; }
|
||||
|
||||
/* ── Cuerpo ───────────────────────────────────────────────────── */
|
||||
.body { padding: 0 40px 36px; }
|
||||
|
||||
/* ── Rejilla de KPIs ──────────────────────────────────────────── */
|
||||
.summary-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin-bottom: 26px; }
|
||||
.kpi { border: 1px solid #e0e0e0; border-top: 3px solid var(--dark); padding: 14px 10px; text-align: center; }
|
||||
.kpi.pink { border-top-color: var(--pink); }
|
||||
.kpi.red { border-top-color: #cc0000; }
|
||||
.kpi.amber { border-top-color: #c05000; }
|
||||
.kpi.green { border-top-color: #2a9d8f; }
|
||||
.kpi .val { font-size: 30px; font-weight: 800; color: var(--dark); line-height: 1; }
|
||||
.kpi.pink .val { color: var(--pink); }
|
||||
.kpi.red .val { color: #cc0000; }
|
||||
.kpi.amber .val { color: #c05000; }
|
||||
.kpi.green .val { color: #1a7a6e; }
|
||||
.kpi .lbl { font-size: 8.5px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.8px; color: var(--mid); margin-top: 6px; }
|
||||
|
||||
/* ── Secciones ────────────────────────────────────────────────── */
|
||||
.section { margin-bottom: 26px; }
|
||||
.section h2 { font-size: 15px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase; color: var(--pink); border-left: 3px solid var(--pink); padding-left: 10px; margin-bottom: 12px; }
|
||||
.section p { font-size: 12px; line-height: 1.8; color: var(--dark); margin-bottom: 9px; }
|
||||
.section ul { padding-left: 18px; margin-bottom: 9px; }
|
||||
.section ul li { font-size: 12px; line-height: 1.8; color: var(--dark); margin-bottom: 2px; }
|
||||
/* Para forzar salto de página antes de una sección en el PDF: class="section page-break" */
|
||||
html.paged .page-break { break-before: page; }
|
||||
|
||||
/* ── Tablas ───────────────────────────────────────────────────── */
|
||||
.body table { width: 100%; border-collapse: collapse; font-size: 11px; margin-bottom: 16px; }
|
||||
.body table thead tr { background: var(--pink); }
|
||||
.body table thead th { padding: 9px 12px; text-align: left; font-weight: 600; font-size: 9.5px; letter-spacing: 0.5px; text-transform: uppercase; color: #fff; }
|
||||
.body table tbody tr:nth-child(even) { background: #fdf2f8; }
|
||||
.body table tbody td { padding: 8px 12px; border-bottom: 1px solid #ecdde7; vertical-align: middle; }
|
||||
.body table td.num { text-align: right; font-variant-numeric: tabular-nums; }
|
||||
|
||||
/* ── Totales (cotizaciones) ───────────────────────────────────── */
|
||||
.totals { width: 320px; margin-left: auto; font-size: 12px; }
|
||||
.totals .row { display: flex; justify-content: space-between; padding: 6px 12px; border-bottom: 1px solid #ecdde7; }
|
||||
.totals .row.grand { background: var(--pink); color: #fff; font-weight: 800; font-size: 14px; border: none; }
|
||||
.totals .row .num { font-variant-numeric: tabular-nums; }
|
||||
|
||||
/* ── Badges ───────────────────────────────────────────────────── */
|
||||
.badge { display: inline-block; padding: 2px 8px; border-radius: 10px; font-size: 9px; font-weight: 700; letter-spacing: 0.3px; }
|
||||
.badge-critical { background: #fdecea; color: #b00; }
|
||||
.badge-high { background: #fef3e2; color: #c05000; }
|
||||
.badge-medium { background: #fef9e7; color: #906000; }
|
||||
.badge-ok { background: #eafaf1; color: #1a7a6e; }
|
||||
.badge-active { background: var(--pink-light); color: var(--pink); }
|
||||
.badge-info { background: #e8f0fe; color: #1a5cc8; }
|
||||
.badge-historic { background: #f0f0f0; color: #666; }
|
||||
|
||||
/* ── Cajas de resaltado ───────────────────────────────────────── */
|
||||
.highlight-box { background: var(--pink-light); border-left: 3px solid var(--pink); padding: 12px 16px; font-size: 11px; color: #5a0030; line-height: 1.8; margin-bottom: 14px; }
|
||||
.info-box { background: #e8f0fe; border-left: 3px solid #1a5cc8; padding: 12px 16px; font-size: 11px; color: #0d2f6e; line-height: 1.8; margin-bottom: 14px; }
|
||||
.warn-box { background: #fef3e2; border-left: 3px solid #c05000; padding: 12px 16px; font-size: 11px; color: #5a2000; line-height: 1.8; margin-bottom: 14px; }
|
||||
.success-box { background: #eafaf1; border-left: 3px solid #2a9d8f; padding: 12px 16px; font-size: 11px; color: #0d4f3c; line-height: 1.8; margin-bottom: 14px; }
|
||||
|
||||
/* ── Rejilla de causas ────────────────────────────────────────── */
|
||||
.cause-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 14px; }
|
||||
.cause-card { background: var(--pink-light); border-left: 3px solid var(--pink); padding: 14px; }
|
||||
.cause-card h4 { font-size: 10px; font-weight: 700; color: var(--pink); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 6px; }
|
||||
.cause-card p { font-size: 11px; color: #444; line-height: 1.7; }
|
||||
|
||||
/* ── Lista de recomendaciones (numerada) ──────────────────────── */
|
||||
.rec-list { counter-reset: rec; list-style: none; padding: 0; }
|
||||
.rec-list li { counter-increment: rec; display: flex; gap: 14px; margin-bottom: 15px; align-items: flex-start; }
|
||||
.rec-list li::before { content: counter(rec); flex-shrink: 0; width: 24px; height: 24px; background: var(--pink); color: #fff; font-size: 11px; font-weight: 800; display: flex; align-items: center; justify-content: center; }
|
||||
.rec-body h4 { font-size: 10.5px; font-weight: 700; color: var(--dark); text-transform: uppercase; letter-spacing: 0.3px; margin-bottom: 4px; }
|
||||
.rec-body p { font-size: 11px; color: #444; line-height: 1.75; }
|
||||
.rec-body .tag { display: inline-block; margin-top: 5px; padding: 1px 8px; font-size: 9px; font-weight: 700; background: var(--pink-light); color: var(--pink); }
|
||||
.rec-body .tag.amber { background: #fef3e2; color: #c05000; }
|
||||
.rec-body .tag.green { background: #eafaf1; color: #1a7a6e; }
|
||||
.rec-body .tag.blue { background: #e8f0fe; color: #1a5cc8; }
|
||||
|
||||
/* ── Línea de tiempo ──────────────────────────────────────────── */
|
||||
.timeline { list-style: none; padding: 0; border-left: 2px solid var(--pink); margin-left: 10px; margin-bottom: 14px; }
|
||||
.timeline li { position: relative; padding: 0 0 16px 22px; }
|
||||
.timeline li:last-child { padding-bottom: 0; }
|
||||
.timeline li::before { content: ''; position: absolute; left: -6px; top: 4px; width: 10px; height: 10px; border-radius: 50%; background: var(--pink); }
|
||||
.timeline .tl-time { font-size: 9px; font-weight: 700; color: var(--mid); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 2px; }
|
||||
.timeline .tl-desc { font-size: 11px; color: var(--dark); line-height: 1.65; }
|
||||
|
||||
/* ── Misc ─────────────────────────────────────────────────────── */
|
||||
.divider { height: 1px; background: #e5dde3; margin: 20px 0; }
|
||||
code { background: #f0f0f0; padding: 1px 5px; font-family: 'Courier New', monospace; font-size: 10.5px; color: #c81b74; border-radius: 2px; }
|
||||
|
||||
/* EDIT: agrega aquí CSS extra específico de este reporte si lo necesitas */
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<button class="export-btn" onclick="exportPDF()">⎙ Exportar PDF</button>
|
||||
|
||||
<!-- ── HEADER (se repite en cada página del PDF) ───────────────────── -->
|
||||
<div class="ars-header"><div class="top-bar">
|
||||
<div class="ars-url"><b>ars</b>integradores.com</div>
|
||||
<div class="ars-block"><img class="ars-logo" src="logo-report.jpg" alt="ARS Integradores"></div>
|
||||
</div></div>
|
||||
|
||||
<div class="screen-page">
|
||||
|
||||
<!-- ══════════════════ ZONA DE EDICIÓN — CONTENIDO ══════════════════ -->
|
||||
|
||||
<!-- EDIT: Título -->
|
||||
<div class="title-wrap">
|
||||
<div class="title-block">
|
||||
<div class="label">Título del Reporte</div>
|
||||
<div class="subtitle">Subtítulo — Sitio / Cliente</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- EDIT: Barra de folio -->
|
||||
<div class="folio-bar">
|
||||
<span class="folio-num">RPT-2026-000</span>
|
||||
<span class="folio-meta">
|
||||
<b>Fecha:</b> 15 de julio de 2026 |
|
||||
<b>Referencia:</b> — |
|
||||
<b>Clasificación:</b> Confidencial
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- EDIT: Info de cliente/contrato -->
|
||||
<div class="contract-info">
|
||||
<div class="cname">Nombre del Cliente</div>
|
||||
<div class="cloc">
|
||||
<b>Contrato:</b> ... |
|
||||
<b>Responsable:</b> ARS Integradores |
|
||||
<b>Preparado por:</b> ...
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- EDIT: Cuerpo. Cada bloque temático es una .section.
|
||||
Usa los componentes documentados en AGENT_GUIDE.md -->
|
||||
<div class="body">
|
||||
|
||||
<div class="section">
|
||||
<h2>Resumen Ejecutivo</h2>
|
||||
<p>Escribe aquí el contenido...</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ════════════════ FIN ZONA DE EDICIÓN — CONTENIDO ════════════════ -->
|
||||
|
||||
</div><!-- /.screen-page -->
|
||||
|
||||
<!-- ── FOOTER (se repite en cada página del PDF) — datos fijos ARS ── -->
|
||||
<div class="ars-footer"><div class="footer">
|
||||
<div><span class="office-label">Oficina</span> (81) 8123 2899<br>Tepatitlán 201 Col. Mitras Sur, Mty. NL, 64020</div>
|
||||
<!-- EDIT: cambia el mes/año de la derecha si aplica -->
|
||||
<div class="right">arsintegradores.com<br>Julio 2026</div>
|
||||
</div></div>
|
||||
|
||||
<script>
|
||||
// Activa el modo paginado y ejecuta Paged.js sólo al exportar,
|
||||
// para que la vista de edición en pantalla sea normal.
|
||||
window.PagedConfig = { auto: false };
|
||||
function exportPDF() {
|
||||
document.documentElement.classList.add('paged');
|
||||
var s = document.createElement('script');
|
||||
s.src = 'paged.polyfill.js';
|
||||
s.onload = function () {
|
||||
new Paged.Previewer().preview().then(function () { window.print(); });
|
||||
};
|
||||
s.onerror = function () {
|
||||
alert('No se encontró paged.polyfill.js en la misma carpeta que este archivo.');
|
||||
document.documentElement.classList.remove('paged');
|
||||
};
|
||||
document.body.appendChild(s);
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
126
example_cotizacion.html
Normal file
126
example_cotizacion.html
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>COT-2026-014 — Cotización — ARS Integradores</title>
|
||||
<style>
|
||||
:root { --pink:#c81b74; --pink-light:#fce8f3; --dark:#2e2e2e; --mid:#666; --light:#f5f5f5; }
|
||||
* { box-sizing:border-box; margin:0; padding:0; }
|
||||
body { font-family:'Century Gothic',CenturyGothic,'Apple Gothic','Trebuchet MS',Arial,sans-serif; font-size:12px; color:var(--dark); }
|
||||
body { background:#e5e5e5; padding:40px 20px; }
|
||||
.screen-page { max-width:860px; margin:0 auto; background:#fff; box-shadow:0 6px 32px rgba(0,0,0,0.14); }
|
||||
.export-btn { position:fixed; bottom:32px; right:32px; z-index:9999; background:var(--pink); color:#fff; border:none; padding:12px 24px; font-family:inherit; font-size:13px; font-weight:700; cursor:pointer; border-radius:4px; box-shadow:0 4px 16px rgba(200,27,116,0.40); }
|
||||
.export-btn:hover { background:#a5145e; }
|
||||
html.paged body { background:#fff; padding:0; }
|
||||
html.paged .screen-page { max-width:none; margin:0; box-shadow:none; }
|
||||
html.paged .export-btn { display:none; }
|
||||
html.paged .ars-header { position:running(arsHeader); }
|
||||
html.paged .ars-footer { position:running(arsFooter); }
|
||||
@page { size:letter; margin-top:108px; margin-bottom:56px; margin-left:40px; margin-right:40px;
|
||||
@top-left{content:element(arsHeader);width:100%;vertical-align:bottom;}
|
||||
@bottom-left{content:element(arsFooter);width:100%;vertical-align:top;} }
|
||||
@media print { *{-webkit-print-color-adjust:exact!important;print-color-adjust:exact!important;} }
|
||||
.top-bar { display:flex; align-items:center; justify-content:space-between; padding:16px 40px 14px; background:#fff; border-bottom:2px solid var(--pink); width:100%; }
|
||||
.ars-block { text-align:right; } .ars-logo { height:70px; display:block; }
|
||||
.ars-url { font-size:14px; font-style:italic; font-weight:600; color:var(--pink); margin-top:4px; } .ars-url b { color:var(--dark); font-style:normal; }
|
||||
.footer { border-top:2.5px solid var(--pink); padding:10px 40px; display:flex; justify-content:space-between; align-items:center; font-size:10px; color:var(--mid); background:#fff; width:100%; }
|
||||
.footer .office-label { color:var(--pink); font-style:italic; font-weight:600; } .footer .right { text-align:right; font-weight:600; color:var(--dark); line-height:1.6; }
|
||||
.title-wrap { padding:32px 40px 24px; }
|
||||
.title-block { background:var(--pink); clip-path:polygon(0 0,87% 0,100% 100%,0 100%); padding:26px 130px 26px 32px; }
|
||||
.title-block .label { font-size:20px; font-weight:800; color:#fff; text-transform:uppercase; letter-spacing:1px; line-height:1.1; margin-bottom:10px; }
|
||||
.title-block .subtitle { font-size:15px; font-weight:300; color:#fff; text-transform:uppercase; line-height:1.4; }
|
||||
.folio-bar { display:flex; justify-content:space-between; align-items:center; background:var(--pink-light); border-left:4px solid var(--pink); padding:8px 14px; margin:0 40px 18px; font-size:10px; }
|
||||
.folio-bar .folio-num { font-size:13px; font-weight:800; color:var(--pink); letter-spacing:1px; }
|
||||
.folio-bar .folio-meta { color:var(--mid); text-align:right; line-height:1.7; } .folio-bar .folio-meta b { color:var(--dark); }
|
||||
.contract-info { padding:0 40px 20px; border-bottom:1px solid #e8e8e8; margin-bottom:20px; }
|
||||
.contract-info .cname { font-size:14px; font-weight:700; color:var(--dark); text-transform:uppercase; line-height:1.65; margin-bottom:5px; }
|
||||
.contract-info .cloc { font-size:13px; color:var(--mid); line-height:1.6; } .contract-info .cloc b { color:var(--dark); }
|
||||
.body { padding:0 40px 36px; }
|
||||
.section { margin-bottom:26px; } .section h2 { font-size:15px; font-weight:700; letter-spacing:1px; text-transform:uppercase; color:var(--pink); border-left:3px solid var(--pink); padding-left:10px; margin-bottom:12px; }
|
||||
.section p { font-size:12px; line-height:1.8; color:var(--dark); margin-bottom:9px; }
|
||||
.body table { width:100%; border-collapse:collapse; font-size:11px; margin-bottom:16px; }
|
||||
.body table thead tr { background:var(--pink); } .body table thead th { padding:9px 12px; text-align:left; font-weight:600; font-size:9.5px; letter-spacing:0.5px; text-transform:uppercase; color:#fff; }
|
||||
.body table tbody tr:nth-child(even) { background:#fdf2f8; } .body table tbody td { padding:8px 12px; border-bottom:1px solid #ecdde7; vertical-align:middle; }
|
||||
.body table td.num { text-align:right; font-variant-numeric:tabular-nums; }
|
||||
.totals { width:320px; margin-left:auto; font-size:12px; }
|
||||
.totals .row { display:flex; justify-content:space-between; padding:6px 12px; border-bottom:1px solid #ecdde7; }
|
||||
.totals .row.grand { background:var(--pink); color:#fff; font-weight:800; font-size:14px; border:none; } .totals .row .num { font-variant-numeric:tabular-nums; }
|
||||
.info-box { background:#e8f0fe; border-left:3px solid #1a5cc8; padding:12px 16px; font-size:11px; color:#0d2f6e; line-height:1.8; margin-bottom:14px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<button class="export-btn" onclick="exportPDF()">⎙ Exportar PDF</button>
|
||||
|
||||
<div class="ars-header"><div class="top-bar">
|
||||
<div class="ars-url"><b>ars</b>integradores.com</div>
|
||||
<div class="ars-block"><img class="ars-logo" src="logo-report.jpg" alt="ARS Integradores"></div>
|
||||
</div></div>
|
||||
|
||||
<div class="screen-page">
|
||||
<div class="title-wrap"><div class="title-block">
|
||||
<div class="label">Cotización</div>
|
||||
<div class="subtitle">Ampliación de red — Sitio DIF</div>
|
||||
</div></div>
|
||||
|
||||
<div class="folio-bar">
|
||||
<span class="folio-num">COT-2026-014</span>
|
||||
<span class="folio-meta">
|
||||
<b>Fecha:</b> 15 de julio de 2026 |
|
||||
<b>Vigencia:</b> 30 días |
|
||||
<b>Clasificación:</b> Confidencial
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="contract-info">
|
||||
<div class="cname">Municipio de Santa Catarina</div>
|
||||
<div class="cloc"><b>Atención:</b> Dirección de Informática | <b>Proveedor:</b> ARS Integradores | <b>Moneda:</b> MXN</div>
|
||||
</div>
|
||||
|
||||
<div class="body">
|
||||
<div class="section">
|
||||
<h2>Partidas</h2>
|
||||
<table>
|
||||
<thead><tr><th>#</th><th>Descripción</th><th>Cant.</th><th>P. Unitario</th><th>Importe</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>1</td><td>UniFi Switch 48 Pro (US48PRO)</td><td class="num">2</td><td class="num">$18,500.00</td><td class="num">$37,000.00</td></tr>
|
||||
<tr><td>2</td><td>UniFi AP U6 Lite (UAPL6)</td><td class="num">6</td><td class="num">$2,300.00</td><td class="num">$13,800.00</td></tr>
|
||||
<tr><td>3</td><td>Instalación y configuración (jornada)</td><td class="num">3</td><td class="num">$4,500.00</td><td class="num">$13,500.00</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="totals">
|
||||
<div class="row"><span>Subtotal</span><span class="num">$64,300.00</span></div>
|
||||
<div class="row"><span>IVA (16%)</span><span class="num">$10,288.00</span></div>
|
||||
<div class="row grand"><span>Total MXN</span><span class="num">$74,588.00</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>Condiciones</h2>
|
||||
<div class="info-box">
|
||||
Precios en pesos mexicanos, más IVA ya desglosado. Vigencia de 30 días naturales.
|
||||
Tiempo de entrega: 5 a 10 días hábiles sujeto a existencias. No incluye obra civil.
|
||||
</div>
|
||||
<p>Forma de pago: 50% anticipo, 50% contra entrega. Garantía de equipo según fabricante.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ars-footer"><div class="footer">
|
||||
<div><span class="office-label">Oficina</span> (81) 8123 2899<br>Tepatitlán 201 Col. Mitras Sur, Mty. NL, 64020</div>
|
||||
<div class="right">arsintegradores.com<br>Julio 2026</div>
|
||||
</div></div>
|
||||
|
||||
<script>
|
||||
window.PagedConfig = { auto:false };
|
||||
function exportPDF(){
|
||||
document.documentElement.classList.add('paged');
|
||||
var s=document.createElement('script'); s.src='paged.polyfill.js';
|
||||
s.onload=function(){ new Paged.Previewer().preview().then(function(){ window.print(); }); };
|
||||
s.onerror=function(){ alert('Falta paged.polyfill.js en la carpeta.'); document.documentElement.classList.remove('paged'); };
|
||||
document.body.appendChild(s);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
173
example_reporte.html
Normal file
173
example_reporte.html
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>RPT-2026-020 — Reporte de Estado de Red — ARS Integradores</title>
|
||||
<style>
|
||||
:root { --pink:#c81b74; --pink-light:#fce8f3; --dark:#2e2e2e; --mid:#666; --light:#f5f5f5; }
|
||||
* { box-sizing:border-box; margin:0; padding:0; }
|
||||
body { font-family:'Century Gothic',CenturyGothic,'Apple Gothic','Trebuchet MS',Arial,sans-serif; font-size:12px; color:var(--dark); }
|
||||
body { background:#e5e5e5; padding:40px 20px; }
|
||||
.screen-page { max-width:860px; margin:0 auto; background:#fff; box-shadow:0 6px 32px rgba(0,0,0,0.14); }
|
||||
.export-btn { position:fixed; bottom:32px; right:32px; z-index:9999; background:var(--pink); color:#fff; border:none; padding:12px 24px; font-family:inherit; font-size:13px; font-weight:700; cursor:pointer; border-radius:4px; box-shadow:0 4px 16px rgba(200,27,116,0.40); }
|
||||
.export-btn:hover { background:#a5145e; }
|
||||
html.paged body { background:#fff; padding:0; }
|
||||
html.paged .screen-page { max-width:none; margin:0; box-shadow:none; }
|
||||
html.paged .export-btn { display:none; }
|
||||
html.paged .ars-header { position:running(arsHeader); }
|
||||
html.paged .ars-footer { position:running(arsFooter); }
|
||||
html.paged .page-break { break-before:page; }
|
||||
@page { size:letter; margin-top:108px; margin-bottom:56px; margin-left:40px; margin-right:40px;
|
||||
@top-left{content:element(arsHeader);width:100%;vertical-align:bottom;}
|
||||
@bottom-left{content:element(arsFooter);width:100%;vertical-align:top;} }
|
||||
@media print { *{-webkit-print-color-adjust:exact!important;print-color-adjust:exact!important;} }
|
||||
.top-bar { display:flex; align-items:center; justify-content:space-between; padding:16px 40px 14px; background:#fff; border-bottom:2px solid var(--pink); width:100%; }
|
||||
.ars-block { text-align:right; } .ars-logo { height:70px; display:block; }
|
||||
.ars-url { font-size:14px; font-style:italic; font-weight:600; color:var(--pink); margin-top:4px; } .ars-url b { color:var(--dark); font-style:normal; }
|
||||
.footer { border-top:2.5px solid var(--pink); padding:10px 40px; display:flex; justify-content:space-between; align-items:center; font-size:10px; color:var(--mid); background:#fff; width:100%; }
|
||||
.footer .office-label { color:var(--pink); font-style:italic; font-weight:600; } .footer .right { text-align:right; font-weight:600; color:var(--dark); line-height:1.6; }
|
||||
.title-wrap { padding:32px 40px 24px; }
|
||||
.title-block { background:var(--pink); clip-path:polygon(0 0,87% 0,100% 100%,0 100%); padding:26px 130px 26px 32px; }
|
||||
.title-block .label { font-size:20px; font-weight:800; color:#fff; text-transform:uppercase; letter-spacing:1px; line-height:1.1; margin-bottom:10px; }
|
||||
.title-block .subtitle { font-size:15px; font-weight:300; color:#fff; text-transform:uppercase; line-height:1.4; }
|
||||
.folio-bar { display:flex; justify-content:space-between; align-items:center; background:var(--pink-light); border-left:4px solid var(--pink); padding:8px 14px; margin:0 40px 18px; font-size:10px; }
|
||||
.folio-bar .folio-num { font-size:13px; font-weight:800; color:var(--pink); letter-spacing:1px; }
|
||||
.folio-bar .folio-meta { color:var(--mid); text-align:right; line-height:1.7; } .folio-bar .folio-meta b { color:var(--dark); }
|
||||
.contract-info { padding:0 40px 20px; border-bottom:1px solid #e8e8e8; margin-bottom:20px; }
|
||||
.contract-info .cname { font-size:14px; font-weight:700; color:var(--dark); text-transform:uppercase; line-height:1.65; margin-bottom:5px; }
|
||||
.contract-info .cloc { font-size:13px; color:var(--mid); line-height:1.6; } .contract-info .cloc b { color:var(--dark); }
|
||||
.resolved-bar { margin:0 40px 22px; background:#eafaf1; border-left:4px solid #2a9d8f; color:#0d4f3c; padding:10px 16px; font-size:11px; font-weight:600; letter-spacing:0.3px; display:flex; align-items:center; gap:10px; }
|
||||
.resolved-bar .dot { width:8px; height:8px; border-radius:50%; background:#2a9d8f; flex-shrink:0; }
|
||||
.body { padding:0 40px 36px; }
|
||||
.summary-grid { display:grid; grid-template-columns:repeat(4,1fr); gap:10px; margin-bottom:26px; }
|
||||
.kpi { border:1px solid #e0e0e0; border-top:3px solid var(--dark); padding:14px 10px; text-align:center; }
|
||||
.kpi.pink{border-top-color:var(--pink);} .kpi.red{border-top-color:#cc0000;} .kpi.amber{border-top-color:#c05000;} .kpi.green{border-top-color:#2a9d8f;}
|
||||
.kpi .val{font-size:30px;font-weight:800;color:var(--dark);line-height:1;}
|
||||
.kpi.pink .val{color:var(--pink);} .kpi.red .val{color:#cc0000;} .kpi.amber .val{color:#c05000;} .kpi.green .val{color:#1a7a6e;}
|
||||
.kpi .lbl{font-size:8.5px;font-weight:600;text-transform:uppercase;letter-spacing:0.8px;color:var(--mid);margin-top:6px;}
|
||||
.section { margin-bottom:26px; } .section h2 { font-size:15px; font-weight:700; letter-spacing:1px; text-transform:uppercase; color:var(--pink); border-left:3px solid var(--pink); padding-left:10px; margin-bottom:12px; }
|
||||
.section p { font-size:12px; line-height:1.8; color:var(--dark); margin-bottom:9px; } .section ul { padding-left:18px; margin-bottom:9px; } .section ul li { font-size:12px; line-height:1.8; margin-bottom:2px; }
|
||||
.body table { width:100%; border-collapse:collapse; font-size:11px; margin-bottom:16px; }
|
||||
.body table thead tr { background:var(--pink); } .body table thead th { padding:9px 12px; text-align:left; font-weight:600; font-size:9.5px; letter-spacing:0.5px; text-transform:uppercase; color:#fff; }
|
||||
.body table tbody tr:nth-child(even) { background:#fdf2f8; } .body table tbody td { padding:8px 12px; border-bottom:1px solid #ecdde7; vertical-align:middle; }
|
||||
.badge { display:inline-block; padding:2px 8px; border-radius:10px; font-size:9px; font-weight:700; letter-spacing:0.3px; }
|
||||
.badge-ok{background:#eafaf1;color:#1a7a6e;} .badge-medium{background:#fef9e7;color:#906000;} .badge-critical{background:#fdecea;color:#b00;}
|
||||
.highlight-box { background:var(--pink-light); border-left:3px solid var(--pink); padding:12px 16px; font-size:11px; color:#5a0030; line-height:1.8; margin-bottom:14px; }
|
||||
.warn-box { background:#fef3e2; border-left:3px solid #c05000; padding:12px 16px; font-size:11px; color:#5a2000; line-height:1.8; margin-bottom:14px; }
|
||||
.cause-grid { display:grid; grid-template-columns:1fr 1fr; gap:12px; margin-bottom:14px; }
|
||||
.cause-card { background:var(--pink-light); border-left:3px solid var(--pink); padding:14px; }
|
||||
.cause-card h4 { font-size:10px; font-weight:700; color:var(--pink); text-transform:uppercase; letter-spacing:0.5px; margin-bottom:6px; } .cause-card p { font-size:11px; color:#444; line-height:1.7; }
|
||||
.rec-list { counter-reset:rec; list-style:none; padding:0; }
|
||||
.rec-list li { counter-increment:rec; display:flex; gap:14px; margin-bottom:15px; align-items:flex-start; }
|
||||
.rec-list li::before { content:counter(rec); flex-shrink:0; width:24px; height:24px; background:var(--pink); color:#fff; font-size:11px; font-weight:800; display:flex; align-items:center; justify-content:center; }
|
||||
.rec-body h4 { font-size:10.5px; font-weight:700; color:var(--dark); text-transform:uppercase; letter-spacing:0.3px; margin-bottom:4px; } .rec-body p { font-size:11px; color:#444; line-height:1.75; }
|
||||
.rec-body .tag { display:inline-block; margin-top:5px; padding:1px 8px; font-size:9px; font-weight:700; background:var(--pink-light); color:var(--pink); } .rec-body .tag.green{background:#eafaf1;color:#1a7a6e;} .rec-body .tag.amber{background:#fef3e2;color:#c05000;}
|
||||
.timeline { list-style:none; padding:0; border-left:2px solid var(--pink); margin-left:10px; margin-bottom:14px; }
|
||||
.timeline li { position:relative; padding:0 0 16px 22px; } .timeline li:last-child { padding-bottom:0; }
|
||||
.timeline li::before { content:''; position:absolute; left:-6px; top:4px; width:10px; height:10px; border-radius:50%; background:var(--pink); }
|
||||
.timeline .tl-time { font-size:9px; font-weight:700; color:var(--mid); text-transform:uppercase; letter-spacing:0.5px; margin-bottom:2px; } .timeline .tl-desc { font-size:11px; color:var(--dark); line-height:1.65; }
|
||||
code { background:#f0f0f0; padding:1px 5px; font-family:'Courier New',monospace; font-size:10.5px; color:#c81b74; border-radius:2px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<button class="export-btn" onclick="exportPDF()">⎙ Exportar PDF</button>
|
||||
|
||||
<div class="ars-header"><div class="top-bar">
|
||||
<div class="ars-url"><b>ars</b>integradores.com</div>
|
||||
<div class="ars-block"><img class="ars-logo" src="logo-report.jpg" alt="ARS Integradores"></div>
|
||||
</div></div>
|
||||
|
||||
<div class="screen-page">
|
||||
<div class="title-wrap"><div class="title-block">
|
||||
<div class="label">Reporte de Estado de Red</div>
|
||||
<div class="subtitle">Torre Administrativa — Municipio de Santa Catarina, N.L.</div>
|
||||
</div></div>
|
||||
|
||||
<div class="folio-bar">
|
||||
<span class="folio-num">RPT-2026-020</span>
|
||||
<span class="folio-meta">
|
||||
<b>Fecha:</b> 15 de julio de 2026 |
|
||||
<b>Periodo:</b> Julio 2026 |
|
||||
<b>Clasificación:</b> Confidencial
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="contract-info">
|
||||
<div class="cname">Municipio de Santa Catarina</div>
|
||||
<div class="cloc"><b>Contrato:</b> Administración de Red | <b>Responsable:</b> ARS Integradores | <b>Preparado por:</b> Equipo NOC</div>
|
||||
</div>
|
||||
|
||||
<div class="resolved-bar"><span class="dot"></span> Operación estable — sin incidentes críticos en el periodo</div>
|
||||
|
||||
<div class="body">
|
||||
<div class="summary-grid">
|
||||
<div class="kpi pink"><div class="val">41</div><div class="lbl">Dispositivos</div></div>
|
||||
<div class="kpi green"><div class="val">99.8%</div><div class="lbl">Disponibilidad</div></div>
|
||||
<div class="kpi amber"><div class="val">2</div><div class="lbl">Advertencias</div></div>
|
||||
<div class="kpi red"><div class="val">0</div><div class="lbl">Críticos</div></div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>Resumen Ejecutivo</h2>
|
||||
<p>Durante el periodo la red operó de forma estable con una disponibilidad del 99.8%.
|
||||
Se atendieron dos advertencias menores de saturación de puerto sin impacto al usuario.</p>
|
||||
<div class="highlight-box">Sin interrupciones de servicio reportadas por usuarios finales.</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>Estado de Equipos Principales</h2>
|
||||
<table>
|
||||
<thead><tr><th>Dispositivo</th><th>IP</th><th>Rol</th><th>Estado</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>SC Torre Administrativa</td><td>192.168.1.10</td><td>Gateway (UDMPRO)</td><td><span class="badge badge-ok">OK</span></td></tr>
|
||||
<tr><td>IDF1-Aggregation24</td><td>192.168.0.234</td><td>Agregación</td><td><span class="badge badge-medium">Revisar</span></td></tr>
|
||||
<tr><td>SWP101</td><td>192.168.0.236</td><td>Acceso</td><td><span class="badge badge-ok">OK</span></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>Hallazgos</h2>
|
||||
<div class="cause-grid">
|
||||
<div class="cause-card"><h4>Observación</h4><p>Descartes intermitentes en el puerto de <code>IDF1-Aggregation24</code> hacia el firewall.</p></div>
|
||||
<div class="cause-card"><h4>Impacto</h4><p>Bajo. Sin afectación perceptible a usuarios; monitoreo activo.</p></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section page-break">
|
||||
<h2>Cronología del Periodo</h2>
|
||||
<ul class="timeline">
|
||||
<li><div class="tl-time">04 Jul · 09:00</div><div class="tl-desc">Mantenimiento preventivo de switches de acceso.</div></li>
|
||||
<li><div class="tl-time">11 Jul · 14:20</div><div class="tl-desc">Advertencia de saturación en puerto agregación — normalizada.</div></li>
|
||||
<li><div class="tl-time">15 Jul · 08:00</div><div class="tl-desc">Corte de reporte mensual.</div></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>Recomendaciones</h2>
|
||||
<ol class="rec-list">
|
||||
<li><div class="rec-body"><h4>Sustituir enlace de agregación</h4><p>Reemplazar el cable/óptica del puerto con descartes para eliminar la advertencia recurrente.</p><span class="tag amber">Prioridad media</span></div></li>
|
||||
<li><div class="rec-body"><h4>Mantener monitoreo</h4><p>Continuar el seguimiento semanal de contadores de error en agregación.</p><span class="tag green">Prioridad baja</span></div></li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ars-footer"><div class="footer">
|
||||
<div><span class="office-label">Oficina</span> (81) 8123 2899<br>Tepatitlán 201 Col. Mitras Sur, Mty. NL, 64020</div>
|
||||
<div class="right">arsintegradores.com<br>Julio 2026</div>
|
||||
</div></div>
|
||||
|
||||
<script>
|
||||
window.PagedConfig = { auto:false };
|
||||
function exportPDF(){
|
||||
document.documentElement.classList.add('paged');
|
||||
var s=document.createElement('script'); s.src='paged.polyfill.js';
|
||||
s.onload=function(){ new Paged.Previewer().preview().then(function(){ window.print(); }); };
|
||||
s.onerror=function(){ alert('Falta paged.polyfill.js en la carpeta.'); document.documentElement.classList.remove('paged'); };
|
||||
document.body.appendChild(s);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
BIN
logo-report.jpg
Normal file
BIN
logo-report.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 666 KiB |
33251
paged.polyfill.js
Normal file
33251
paged.polyfill.js
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue