67a0e674ca
Marine maintenance management: work orders with photos, ISM/SWP procedures, MSDS, inventory, RFQ/purchases, vessel history, bilingual PDF reports. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
172 lines
9.3 KiB
HTML
172 lines
9.3 KiB
HTML
{% extends 'base.html' %}
|
|
{% block title %}{{ swp.code }} — {{ swp.title }}{% endblock %}
|
|
{% block page_title %}{{ swp.code }} — {{ swp.title }}{% endblock %}
|
|
{% block topbar_actions %}
|
|
<a href="{{ url_for('swp_pdf', sid=swp.id) }}?lang=es" target="_blank" class="btn btn-primary">📄 PDF ES</a>
|
|
<a href="{{ url_for('swp_pdf', sid=swp.id) }}?lang=en" target="_blank" class="btn btn-secondary">📄 PDF EN</a>
|
|
{% if current and current.status == 'draft' %}
|
|
<a href="{{ url_for('swp_edit_version', sid=swp.id, vid=current.id) }}" class="btn btn-warning">✏️ Editar Borrador</a>
|
|
{% else %}
|
|
<a href="{{ url_for('swp_edit', sid=swp.id) }}" class="btn btn-secondary">✏️ Editar</a>
|
|
<a href="{{ url_for('swp_new_version', sid=swp.id) }}" class="btn btn-secondary">📝 Nueva Versión</a>
|
|
{% endif %}
|
|
<a href="{{ url_for('ism_index') }}" class="btn btn-secondary">← Volver</a>
|
|
{% endblock %}
|
|
{% block content %}
|
|
|
|
{% if current and current.status == 'draft' %}
|
|
<div style="background:rgba(244,162,97,0.12);border:1px solid rgba(244,162,97,0.4);border-radius:8px;padding:12px 16px;margin-bottom:16px;display:flex;justify-content:space-between;align-items:center">
|
|
<div>
|
|
<span style="color:var(--warning);font-weight:600">📝 Versión {{ current.version }} pendiente de aprobación</span>
|
|
<span style="color:var(--gray);font-size:12px;margin-left:10px">Creada por {{ current.created_by }} · {{ current.created_at[:10] }}</span>
|
|
</div>
|
|
<div class="flex gap-2">
|
|
<a href="{{ url_for('swp_edit_version', sid=swp.id, vid=current.id) }}" class="btn btn-sm btn-warning">✏️ Editar</a>
|
|
<button onclick="approveVersion({{ current.id }})" class="btn btn-sm btn-success">✅ Aprobar ahora</button>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if current %}
|
|
{% set hazards = json.loads(current.hazards or '[]') %}
|
|
{% set ppe = json.loads(current.ppe or '[]') %}
|
|
{% set tools = json.loads(current.tools or '[]') %}
|
|
{% set steps = json.loads(current.steps or '[]') %}
|
|
{% set refs = json.loads(current.ref_standards or '[]') %}
|
|
|
|
<!-- META -->
|
|
<div class="grid-2 mb-4">
|
|
<div class="card" style="padding:16px">
|
|
<div style="font-size:10px;color:var(--gray);text-transform:uppercase;letter-spacing:1px;margin-bottom:8px">Información</div>
|
|
<table style="width:100%;font-size:13px">
|
|
<tr><td style="color:var(--gray);padding:4px 0;width:40%">Código</td><td style="color:var(--cyan);font-weight:700;font-family:monospace">{{ swp.code }}</td></tr>
|
|
<tr><td style="color:var(--gray);padding:4px 0">Versión activa</td><td><span class="badge" style="background:rgba(0,180,216,0.15);color:var(--cyan)">{{ current.version }}</span></td></tr>
|
|
<tr><td style="color:var(--gray);padding:4px 0">Categoría</td><td>{{ categories.get(swp.category, swp.category) }}</td></tr>
|
|
<tr><td style="color:var(--gray);padding:4px 0">Vigente desde</td><td>{{ current.effective_date or '—' }}</td></tr>
|
|
<tr><td style="color:var(--gray);padding:4px 0">Aprobado por</td><td>{{ current.approved_by or '—' }}</td></tr>
|
|
<tr><td style="color:var(--gray);padding:4px 0">Creado por</td><td>{{ current.created_by or '—' }}</td></tr>
|
|
</table>
|
|
</div>
|
|
<div class="card" style="padding:16px">
|
|
<div style="font-size:10px;color:var(--gray);text-transform:uppercase;letter-spacing:1px;margin-bottom:8px">Propósito y Alcance</div>
|
|
{% if current.purpose %}<p style="font-size:13px;margin-bottom:8px">{{ current.purpose }}</p>{% endif %}
|
|
{% if current.scope %}<p style="font-size:13px;color:var(--gray)">{{ current.scope }}</p>{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- RIESGOS + EPP -->
|
|
<div class="grid-2 mb-4">
|
|
<div class="card" style="padding:16px;border-left:3px solid var(--danger)">
|
|
<div style="font-size:10px;color:var(--danger);text-transform:uppercase;letter-spacing:1px;margin-bottom:10px">⚠️ Riesgos Identificados</div>
|
|
{% for h in hazards %}
|
|
<div style="display:flex;gap:8px;padding:5px 0;border-bottom:1px solid rgba(255,255,255,0.05);font-size:13px">
|
|
<span style="color:var(--danger)">●</span> {{ h }}
|
|
</div>
|
|
{% else %}<p class="text-gray" style="font-size:13px">—</p>{% endfor %}
|
|
</div>
|
|
<div class="card" style="padding:16px;border-left:3px solid var(--warning)">
|
|
<div style="font-size:10px;color:var(--warning);text-transform:uppercase;letter-spacing:1px;margin-bottom:10px">🦺 EPP Requerido</div>
|
|
{% for p in ppe %}
|
|
<div style="display:flex;gap:8px;padding:5px 0;border-bottom:1px solid rgba(255,255,255,0.05);font-size:13px">
|
|
<span style="color:var(--warning)">✓</span> {{ p }}
|
|
</div>
|
|
{% else %}<p class="text-gray" style="font-size:13px">—</p>{% endfor %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- HERRAMIENTAS -->
|
|
{% if tools %}
|
|
<div class="card mb-4" style="padding:16px;border-left:3px solid #7b2d8b">
|
|
<div style="font-size:10px;color:#7b2d8b;text-transform:uppercase;letter-spacing:1px;margin-bottom:10px">🔧 Herramientas y Materiales</div>
|
|
<div style="display:flex;gap:8px;flex-wrap:wrap">
|
|
{% for t in tools %}
|
|
<span style="background:rgba(123,45,139,0.1);border:1px solid rgba(123,45,139,0.3);color:#b57bee;padding:4px 10px;border-radius:20px;font-size:12px">{{ t }}</span>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- PASOS -->
|
|
<div class="card mb-4" style="padding:16px;border-left:3px solid var(--cyan)">
|
|
<div style="font-size:10px;color:var(--cyan);text-transform:uppercase;letter-spacing:1px;margin-bottom:12px">📋 Pasos del Procedimiento</div>
|
|
{% for step in steps %}
|
|
<div style="display:flex;gap:12px;padding:8px 0;border-bottom:1px solid rgba(255,255,255,0.05);font-size:13px">
|
|
<span style="color:var(--cyan);font-weight:700;min-width:24px">{{ loop.index }}.</span>
|
|
<span>{{ step }}</span>
|
|
</div>
|
|
{% else %}<p class="text-gray" style="font-size:13px">Sin pasos definidos.</p>{% endfor %}
|
|
</div>
|
|
|
|
<!-- EMERGENCIA -->
|
|
{% if current.emergency %}
|
|
<div class="card mb-4" style="padding:16px;border:1px solid var(--warning);background:rgba(244,162,97,0.05)">
|
|
<div style="font-size:10px;color:var(--warning);text-transform:uppercase;letter-spacing:1px;margin-bottom:8px">🚨 Medidas de Emergencia</div>
|
|
<p style="font-size:13px">{{ current.emergency }}</p>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- REFERENCIAS -->
|
|
{% if refs %}
|
|
<div class="card mb-4" style="padding:16px">
|
|
<div style="font-size:10px;color:var(--gray);text-transform:uppercase;letter-spacing:1px;margin-bottom:10px">📚 Referencias y Normativa</div>
|
|
<div style="display:flex;gap:8px;flex-wrap:wrap">
|
|
{% for r in refs %}
|
|
<span style="background:rgba(0,180,216,0.1);border:1px solid rgba(0,180,216,0.2);color:var(--cyan);padding:4px 10px;border-radius:20px;font-size:12px">{{ r }}</span>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% else %}
|
|
<div class="card" style="padding:40px;text-align:center;color:var(--gray)">
|
|
Sin versión activa. <a href="{{ url_for('swp_new_version', sid=swp.id) }}" style="color:var(--cyan)">Crear primera versión</a>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- HISTORIAL DE VERSIONES -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">📚 Historial de Versiones</div>
|
|
<div class="table-wrap">
|
|
<table>
|
|
<thead><tr><th>Versión</th><th>Estado</th><th>Motivo</th><th>Diferencias</th><th>Creado por</th><th>Aprobado por</th><th>Vigente desde</th><th></th></tr></thead>
|
|
<tbody>
|
|
{% for v in versions %}
|
|
<tr>
|
|
<td><span class="badge" style="background:rgba(0,180,216,0.15);color:var(--cyan);font-family:monospace">{{ v.version }}</span></td>
|
|
<td>
|
|
{% if v.status == 'active' %}<span class="badge badge-completed">Activa</span>
|
|
{% elif v.status == 'draft' %}<span class="badge badge-open">Borrador</span>
|
|
{% elif v.status == 'superseded' %}<span class="badge" style="background:rgba(138,155,176,0.2);color:var(--gray)">Supersedida</span>
|
|
{% else %}<span class="badge badge-cancelled">Archivada</span>{% endif %}
|
|
</td>
|
|
<td style="font-size:12px">{{ v.change_reason or '—' }}</td>
|
|
<td style="font-size:12px;color:var(--gray)">{{ v.diff_summary or '—' }}</td>
|
|
<td style="font-size:12px">{{ v.created_by or '—' }}</td>
|
|
<td style="font-size:12px">{{ v.approved_by or '—' }}</td>
|
|
<td style="font-size:12px">{{ v.effective_date or '—' }}</td>
|
|
<td>
|
|
{% if v.status == 'draft' %}
|
|
<div class="flex gap-2">
|
|
<a href="{{ url_for('swp_edit_version', sid=swp.id, vid=v.id) }}" class="btn btn-sm btn-warning">✏️</a>
|
|
<button onclick="approveVersion({{ v.id }})" class="btn btn-sm btn-success">✅ Aprobar</button>
|
|
</div>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
{% block scripts %}
|
|
<script>
|
|
function approveVersion(vid) {
|
|
if (!confirm('¿Aprobar esta versión? La versión actual quedará como supersedida.')) return;
|
|
fetch('/ism/{{ swp.id }}/versions/' + vid + '/approve', {method:'POST'})
|
|
.then(r => r.json())
|
|
.then(d => { if (d.ok) location.reload(); else alert('Error: ' + d.error); });
|
|
}
|
|
</script>
|
|
{% endblock %}
|