186 lines
7.4 KiB
HTML
186 lines
7.4 KiB
HTML
![]() |
{% extends "base.html" %}
|
|||
|
{% load i18n risk_extras %}
|
|||
|
{% block crumbs %}
|
|||
|
<li><a href="{% url 'risks:risk_matrix' %}">{% trans "Risk Matrix" %}</a></li>
|
|||
|
{% endblock %}
|
|||
|
{% block content %}
|
|||
|
<section class="section">
|
|||
|
|
|||
|
<!-- Tabs -->
|
|||
|
<div class="tabs is-boxed" role="tablist">
|
|||
|
<ul>
|
|||
|
<li class="is-active" data-tab="riskmatrix" role="tab" aria-selected="true"><a>{% trans "Risk Matrix" %}</a></li>
|
|||
|
<li data-tab="details" role="tab" aria-selected="false"><a>{% trans "Detail View" %}</a></li>
|
|||
|
</ul>
|
|||
|
</div>
|
|||
|
|
|||
|
<div class="box">
|
|||
|
<h2 class="title is-4">{% trans "Risk Matrix" %}</h2>
|
|||
|
|
|||
|
{# Panel: Brutto (Score-Matrix) #}
|
|||
|
<div class="tab-panel" data-tab="riskmatrix">
|
|||
|
<table class="table is-bordered has-text-centered risk-matrix-table">
|
|||
|
<thead>
|
|||
|
<tr>
|
|||
|
<th class="has-text-left">{% trans "Impact" %} / {% trans "Likelihood" %}</th>
|
|||
|
{% for l_val, l_label in likelihoods %}
|
|||
|
<th class="py-6 {{ l_val|likelihood_class|to_bg }}">{{ l_label }}</th>
|
|||
|
{% endfor %}
|
|||
|
</tr>
|
|||
|
</thead>
|
|||
|
<tbody>
|
|||
|
{% for i_val, i_label in impacts reversed %}
|
|||
|
<tr>
|
|||
|
<th class="py-6 has-text-left {{ i_val|impact_class|to_bg }}">{{ i_label }}</th>
|
|||
|
{% for l_val, l_label in likelihoods %}
|
|||
|
{% with s=i_val|mul:l_val %}
|
|||
|
<td class="risk-matrix-cell {{ s|score_bg_class }}">
|
|||
|
<div class="is-flex is-justify-content-center is-align-items-center py-6">
|
|||
|
<span class="tag is-light is-rounded">{% trans "Score" %} {{ s }}</span>
|
|||
|
</div>
|
|||
|
</td>
|
|||
|
{% endwith %}
|
|||
|
{% endfor %}
|
|||
|
</tr>
|
|||
|
{% endfor %}
|
|||
|
</tbody>
|
|||
|
</table>
|
|||
|
</div>
|
|||
|
|
|||
|
{# Panel: Details (Listen je Zelle, mit Brutto/Netto-Umschalter) #}
|
|||
|
<div class="tab-panel is-hidden" data-tab="details">
|
|||
|
<div class="level mb-3">
|
|||
|
<div class="level-left">
|
|||
|
<div class="level-item"><strong>{% trans "Show" %}:</strong></div>
|
|||
|
<div class="level-item">
|
|||
|
<div class="buttons has-addons">
|
|||
|
<button type="button" class="button is-small is-info is-light details-toggle is-active" data-mode="gross">
|
|||
|
{% trans "Gross" %}
|
|||
|
</button>
|
|||
|
<button type="button" class="button is-small is-info is-light details-toggle" data-mode="net">
|
|||
|
{% trans "Net" %}
|
|||
|
</button>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
|
|||
|
{# Brutto-Listen #}
|
|||
|
<div class="details-table" data-mode="gross">
|
|||
|
<table class="table is-bordered has-text-centered risk-matrix-table">
|
|||
|
<thead>
|
|||
|
<tr>
|
|||
|
<th class="has-text-left">{% trans "Impact" %} / {% trans "Likelihood" %}</th>
|
|||
|
{% for l_val, l_label in likelihoods %}
|
|||
|
<th class="py-6 {{ l_val|likelihood_class|to_bg }}">{{ l_label }}</th>
|
|||
|
{% endfor %}
|
|||
|
</tr>
|
|||
|
</thead>
|
|||
|
<tbody>
|
|||
|
{% for i_val, i_label in impacts reversed %}
|
|||
|
<tr>
|
|||
|
<th class="py-6 has-text-left {{ i_val|impact_class|to_bg }}">{{ i_label }}</th>
|
|||
|
{% for l_val, l_label in likelihoods %}
|
|||
|
{% with row=gross_matrix|dict_get:i_val %}
|
|||
|
{% with cell=row|dict_get:l_val %}
|
|||
|
{% with s=i_val|mul:l_val %}
|
|||
|
<td class="risk-matrix-cell {{ s|score_bg_class }}">
|
|||
|
{% if cell and cell|length %}
|
|||
|
<ul class="risk-cell-list">
|
|||
|
{% for risk in cell %}
|
|||
|
<li style="list-style: none;">
|
|||
|
<a href="{% url 'risks:show_risk' risk.id %}" class="tag">{{ risk.title }}</a>
|
|||
|
</li>
|
|||
|
{% endfor %}
|
|||
|
</ul>
|
|||
|
{% else %}
|
|||
|
<span class="has-text-grey">–</span>
|
|||
|
{% endif %}
|
|||
|
</td>
|
|||
|
{% endwith %}
|
|||
|
{% endwith %}
|
|||
|
{% endwith %}
|
|||
|
{% endfor %}
|
|||
|
</tr>
|
|||
|
{% endfor %}
|
|||
|
</tbody>
|
|||
|
</table>
|
|||
|
</div>
|
|||
|
|
|||
|
{# Netto-Listen #}
|
|||
|
<div class="details-table is-hidden" data-mode="net">
|
|||
|
<table class="table is-bordered has-text-centered risk-matrix-table">
|
|||
|
<thead>
|
|||
|
<tr>
|
|||
|
<th class="has-text-left">{% trans "Impact" %} / {% trans "Likelihood" %}</th>
|
|||
|
{% for l_val, l_label in likelihoods %}
|
|||
|
<th class="py-6 {{ l_val|likelihood_class|to_bg }}">{{ l_label }}</th>
|
|||
|
{% endfor %}
|
|||
|
</tr>
|
|||
|
</thead>
|
|||
|
<tbody>
|
|||
|
{% for i_val, i_label in impacts reversed %}
|
|||
|
<tr>
|
|||
|
<th class="py-6 has-text-left {{ i_val|impact_class|to_bg }}">{{ i_label }}</th>
|
|||
|
{% for l_val, l_label in likelihoods %}
|
|||
|
{% with row=net_matrix|dict_get:i_val %}
|
|||
|
{% with cell=row|dict_get:l_val %}
|
|||
|
{% with s=i_val|mul:l_val %}
|
|||
|
<td class="risk-matrix-cell {{ s|score_bg_class }}">
|
|||
|
{% if cell and cell|length %}
|
|||
|
<ul class="risk-cell-list">
|
|||
|
{% for risk in cell %}
|
|||
|
<li style="list-style: none;">
|
|||
|
<a href="{% url 'risks:show_risk' risk.id %}" class="tag">{{ risk.title }}</a>
|
|||
|
</li>
|
|||
|
{% endfor %}
|
|||
|
</ul>
|
|||
|
{% else %}
|
|||
|
<span class="has-text-grey">–</span>
|
|||
|
{% endif %}
|
|||
|
</td>
|
|||
|
{% endwith %}
|
|||
|
{% endwith %}
|
|||
|
{% endwith %}
|
|||
|
{% endfor %}
|
|||
|
</tr>
|
|||
|
{% endfor %}
|
|||
|
</tbody>
|
|||
|
</table>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
|
|||
|
</div>
|
|||
|
</section>
|
|||
|
|
|||
|
<style>
|
|||
|
.risk-matrix-table th, .risk-matrix-table td { padding: .5rem; }
|
|||
|
.risk-matrix-cell { min-height: 120px; vertical-align: middle; }
|
|||
|
.tab-panel.is-hidden { display: none; }
|
|||
|
.risk-cell-list { text-align: left; margin: 0; padding-left: 1rem; }
|
|||
|
</style>
|
|||
|
|
|||
|
<script>
|
|||
|
document.addEventListener('DOMContentLoaded', function () {
|
|||
|
// Tabs
|
|||
|
const tabs = document.querySelectorAll('.tabs li[data-tab]');
|
|||
|
const panels = document.querySelectorAll('.tab-panel');
|
|||
|
tabs.forEach(t => t.addEventListener('click', () => {
|
|||
|
tabs.forEach(x => { x.classList.remove('is-active'); x.setAttribute('aria-selected','false'); });
|
|||
|
t.classList.add('is-active'); t.setAttribute('aria-selected','true');
|
|||
|
const target = t.getAttribute('data-tab');
|
|||
|
panels.forEach(p => p.classList.toggle('is-hidden', p.getAttribute('data-tab') !== target));
|
|||
|
}));
|
|||
|
|
|||
|
// Umschalter im „Details“-Tab
|
|||
|
const toggles = document.querySelectorAll('.details-toggle');
|
|||
|
const tables = document.querySelectorAll('.details-table');
|
|||
|
toggles.forEach(btn => btn.addEventListener('click', () => {
|
|||
|
const mode = btn.getAttribute('data-mode'); // 'gross' | 'net'
|
|||
|
toggles.forEach(b => b.classList.toggle('is-active', b === btn));
|
|||
|
tables.forEach(t => t.classList.toggle('is-hidden', t.getAttribute('data-mode') !== mode));
|
|||
|
}));
|
|||
|
});
|
|||
|
</script>
|
|||
|
{% endblock %}
|