Files
Pivot/templates/database_eigendom.html
T
marinostrusandClaude Opus 5.5 8b7fa3f716 Donker thema toevoegen via gebruikersmenu rechtsboven
Klik op je naam rechtsboven om een menu te openen met een schakelaar
voor het donkere thema. De keuze wordt per browser onthouden.

- global.css: donkere kleurvariabelen, alleen op scherm (afdrukken blijft licht)
- base.html: gebruikersmenu met themaschakelaar
- vaste witte achtergronden en pastelkleuren op enkele pagina's
  volgen nu het thema

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 18:08:30 +02:00

163 lines
9.8 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "base.html" %}
{% block title %}Eigendom importeren{% endblock %}
{% block page_title %}Database › Eigendom{% endblock %}
{% block loader_text %}Bestand controleren...{% endblock %}
{% block extra_css %}
<style>
.stappen { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; align-items: start; }
.stappen > .card + .card { margin-top: 0; }
@media (max-width: 860px) { .stappen { grid-template-columns: 1fr; } }
.stap-nr { display: inline-grid; place-items: center; width: 26px; height: 26px; border-radius: 50%;
background: var(--primary-color); color: #fff; font-size: 14px; margin-right: 6px; }
.kolom-lijst { margin: 10px 0 0; padding: 0; list-style: none; font-size: 14px; }
.kolom-lijst li { padding: 6px 0; border-bottom: 1px solid var(--border); }
.kolom-lijst li:last-child { border-bottom: 0; }
.kolom-lijst strong { display: inline-block; min-width: 120px; }
.modus-keuze { display: grid; gap: 8px; margin: 4px 0 16px; }
.modus-keuze label { display: flex; gap: 10px; align-items: flex-start; padding: 10px 12px; border: 1px solid var(--border);
border-radius: var(--radius-sm); font-weight: 500; cursor: pointer; background: var(--surface-muted); }
.modus-keuze label:has(input:checked) { border-color: var(--primary-color); background: var(--primary-light); }
.modus-keuze input { margin-top: 2px; flex-shrink: 0; }
.modus-keuze small { display: block; color: var(--text-muted); font-weight: 400; }
.tellers { display: flex; flex-wrap: wrap; gap: 10px; margin: 6px 0 14px; }
.teller-knop { all: unset; cursor: pointer; display: inline-flex; gap: 8px; align-items: center; padding: 8px 14px;
border-radius: var(--radius); border: 1px solid var(--border); background: var(--surface); font-weight: 600; font-size: 14px; }
.teller-knop.actief { border-color: var(--primary-color); box-shadow: 0 0 0 2px rgba(30,111,165,.18); }
.teller-knop .n { font-size: 18px; }
tr.rij-fout td { background: #fff7f7; }
td.melding { font-size: 13px; color: var(--text-muted); min-width: 220px; }
td.melding .fout { color: var(--danger-text); }
td.melding .wijz { color: var(--text); }
.bevestig { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; justify-content: space-between; margin-top: 16px; }
</style>
{% endblock %}
{% block content %}
{% if not plan %}
<div class="stappen">
<div class="card">
<h2 class="card-title"><span class="stap-nr">1</span>Sjabloon downloaden</h2>
<p class="muted">Vul het sjabloon in met één toekenning (leerling + toestel) per rij. Leerling en toestel moeten al
in PIVOT staan{% if mag('database_toestellen') %}; nieuwe toestellen voeg je eerst toe via
<a href="{{ url_for('database_beheer.toestellen') }}">Toestellen importeren</a>{% endif %}.</p>
<a class="btn" href="{{ url_for('database_beheer.eigendom_sjabloon') }}">⬇️ Sjabloon downloaden (.xlsx)</a>
<ul class="kolom-lijst">
{% for k in kolommen %}
<li><strong>{{ k[1] }}</strong> <span class="muted">{{ k[3] }}</span></li>
{% endfor %}
</ul>
</div>
<div class="card">
<h2 class="card-title"><span class="stap-nr">2</span>Excel uploaden</h2>
<p class="muted">Je krijgt eerst een voorbeeld te zien. Er wordt pas iets bewaard als je bevestigt.
{% if aantal is not none %}Er zijn nu <strong>{{ aantal }}</strong> toestellen uitgeleend.{% endif %}</p>
<form method="POST" action="{{ url_for('database_beheer.eigendom_controleren') }}" enctype="multipart/form-data"
onsubmit="showLoader('Bestand controleren...')">
<div class="field">
<label for="bestand">Excel-bestand (.xlsx)</label>
<input type="file" id="bestand" name="bestand" accept=".xlsx,.xlsm,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" required>
<div class="field-hint">Max. {{ max_rijen }} rijen. Het tabblad <em>Eigendom</em> wordt gelezen (of anders het eerste tabblad).</div>
</div>
<label>Toestel staat nu bij een andere leerling</label>
<div class="modus-keuze">
<label><input type="radio" name="modus" value="aanvullen" checked>
<span>Als fout tonen <small>De rij wordt overgeslagen; de huidige toekenning blijft staan. (Aanbevolen)</small></span></label>
<label><input type="radio" name="modus" value="overschrijven">
<span>Vorige toekenning afsluiten <small>Het toestel wordt bij de vorige leerling ingeleverd op de datum toekenning uit Excel. Ook een andere datum inlevering wordt dan overschreven.</small></span></label>
</div>
<button type="submit">🔎 Controleren</button>
</form>
</div>
</div>
{% else %}
{% set t = plan.tellers %}
<div class="card">
<div class="page-head">
<h2>🔎 Voorbeeld: {{ bestandsnaam }}</h2>
<a class="btn btn-light" href="{{ url_for('database_beheer.eigendom') }}">↩️ Ander bestand</a>
</div>
<p class="muted" style="margin-top:-8px">Nog niets bewaard. Toestel bij een andere leerling:
<strong>{{ 'vorige toekenning afsluiten' if plan.modus == 'overschrijven' else 'als fout tonen' }}</strong>.</p>
{% if onbekend %}
<div class="alert alert-warning">Deze kolommen worden genegeerd: {{ onbekend|join(', ') }}.</div>
{% endif %}
<div class="tellers" role="group" aria-label="Filter">
<button type="button" class="teller-knop actief" data-filter="">Alle <span class="n">{{ plan.rijen|length }}</span></button>
<button type="button" class="teller-knop" data-filter="nieuw"><span class="badge badge-success">➕ Nieuw</span> <span class="n">{{ t.nieuw }}</span></button>
<button type="button" class="teller-knop" data-filter="bijwerken"><span class="badge badge-info">✏️ Bijwerken</span> <span class="n">{{ t.bijwerken }}</span></button>
<button type="button" class="teller-knop" data-filter="ongewijzigd"><span class="badge">= Ongewijzigd</span> <span class="n">{{ t.ongewijzigd }}</span></button>
<button type="button" class="teller-knop" data-filter="fout"><span class="badge badge-danger">⚠️ Fout</span> <span class="n">{{ t.fout }}</span></button>
</div>
<div class="table-wrap">
<table id="voorbeeld">
<thead>
<tr>
<th>Rij</th><th>Actie</th>
{% for k in kolommen %}<th>{{ k[1] }}</th>{% endfor %}
<th>Wat gebeurt er</th>
</tr>
</thead>
<tbody>
{% for r in plan.rijen %}
<tr data-actie="{{ r.actie }}" class="{{ 'rij-fout' if r.actie == 'fout' }}">
<td class="muted">{{ r.rij }}</td>
<td>
{% if r.actie == 'nieuw' %}<span class="badge badge-success">➕ Nieuw</span>
{% elif r.actie == 'bijwerken' %}<span class="badge badge-info">✏️ Bijwerken</span>
{% elif r.actie == 'ongewijzigd' %}<span class="badge">= Ongewijzigd</span>
{% else %}<span class="badge badge-danger">⚠️ Fout</span>{% endif %}
</td>
{% for k in kolommen %}<td class="{{ 'mono' if k[0] in ('leerling', 'toestel') }}">{{ r.invoer[k[0]] }}</td>{% endfor %}
<td class="melding">
{% if r.actie == 'fout' %}{% for m in r.meldingen %}<div class="fout">{{ m }}</div>{% endfor %}
{% else %}
{% if r.label %}<div>{{ r.label }}</div>{% endif %}
{% if r.actie == 'nieuw' %}<div class="wijz">Wordt toegevoegd{{ ' als geschiedenis' if r.invoer.datum_inlevering }}.</div>{% endif %}
{% for w in r.wijzigingen %}<div class="wijz">{{ w }}</div>{% endfor %}
{% for m in r.meldingen %}<div>{{ m }}</div>{% endfor %}
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% set te_doen = t.nieuw + t.bijwerken %}
<form method="POST" action="{{ url_for('database_beheer.eigendom_importeren') }}" class="bevestig"
onsubmit="return confirm({{ ('Nu ' ~ t.nieuw ~ ' toekenning(en) toevoegen en ' ~ t.bijwerken ~ ' bijwerken?' ~ (' De ' ~ t.fout ~ ' rij(en) met een fout worden overgeslagen.' if t.fout else ''))|tojson|forceescape }}) && (showLoader('Importeren...'), true)">
<input type="hidden" name="modus" value="{{ plan.modus }}">
<input type="hidden" name="rijen" value="{{ rijen_json }}">
<span class="muted">
{% if te_doen %}{{ t.nieuw }} nieuw en {{ t.bijwerken }} bij te werken toekenning(en).
{% if t.fout %}Rijen met een fout worden overgeslagen; verbeter ze in Excel en upload opnieuw.{% endif %}
{% else %}Er is niets te importeren.{% endif %}
</span>
<span style="display:flex;gap:8px">
<a class="btn btn-light" href="{{ url_for('database_beheer.eigendom') }}">Annuleren</a>
<button type="submit" class="btn-success" {{ 'disabled' if not te_doen }}>✅ Importeren</button>
</span>
</form>
</div>
{% endif %}
{% endblock %}
{% block scripts %}
<script>
// Voorbeeld filteren op actie (nieuw / bijwerken / ongewijzigd / fout)
document.querySelectorAll('.teller-knop').forEach(knop => knop.addEventListener('click', () => {
document.querySelectorAll('.teller-knop').forEach(k => k.classList.toggle('actief', k === knop));
const f = knop.dataset.filter;
document.querySelectorAll('#voorbeeld tbody tr').forEach(tr => {
tr.style.display = !f || tr.dataset.actie === f ? '' : 'none';
});
}));
</script>
{% endblock %}