Files
OBE-Mapping/app/templates/form_nilai.html
T
Power BI Dev 9be6bd03e3 Gabungkan aplikasi RPS & Portofolio OBE (dashboard jadi bagian aplikasi)
Dashboard pemetaan statis kini dilayani aplikasi di /dashboard
(app/static/dashboard.html). Fitur lengkap Tahap 1-4 + dasbor monitoring,
menu global, filter semester, input nilai langsung, penggabungan nilai
team teaching, tabel bisa urut. Dockerfile berubah dari nginx statis ke
uvicorn/FastAPI: healthcheck, proxy-headers, volume /data (SQLite).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 12:05:28 +07:00

190 lines
9.7 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 judul %}Nilai {{ peta.nama }} — Informatika UNTAN{% endblock %}
{% block isi %}
<div class="nav-baris">
<div>MK ini: <a href="/rps/{{ peta.kode }}">RPS</a> · <b>Input Nilai</b> · <a href="/portofolio/{{ peta.kode }}">Portofolio</a></div>
</div>
<h1>Input Nilai — {{ peta.nama }} <span style="color:var(--grey)">({{ peta.kode }})</span></h1>
<p class="keterangan">Apa pun cara inputnya, pengukuran memakai <b>satu metodologi
yang sama</b>: skor per Sub-CPMK digulung ke CPMK lalu CPL
(rincian di halaman <a href="/metodologi">Metodologi</a>). Pilih <b>satu</b> cara
di bawah — menyimpan lewat cara mana pun menggantikan data nilai MK ini.</p>
{% if pesan %}<div class="info">{{ pesan }}</div>{% endif %}
{% for w in peringatan %}<div class="peringatan">{{ w }}</div>{% endfor %}
{% if tersimpan %}
<div class="info">
Data tersimpan: mode
<b>{% if tersimpan.data.mode == 'per_mahasiswa' %}PER MAHASISWA ({{ tersimpan.data.mahasiswa|length }} mahasiswa){% else %}BUKTI AGREGAT (rata-rata kelas){% endif %}</b>
— terakhir disimpan {{ tersimpan.updated_at }}{% if tersimpan.updated_by %} oleh {{ tersimpan.updated_by }}{% endif %}.
{% if tersimpan.data.sumber %}<br>Riwayat unggahan:
{{ tersimpan.data.sumber if tersimpan.data.sumber is string else tersimpan.data.sumber|join(' · ') }}.{% endif %}
<form method="post" action="/nilai/{{ peta.kode }}" style="display:inline;margin-left:8px"
onsubmit="return confirm('Hapus SELURUH nilai tersimpan MK ini untuk {{ tahun }}? Tindakan ini tidak bisa dibatalkan.')">
<button class="tombol garis" type="submit" name="aksi" value="hapus"
style="color:var(--red);border-color:var(--red);padding:2px 10px;font-size:13px">Mulai Ulang (hapus semua nilai)</button>
</form>
</div>
{% endif %}
{% if grid %}
{% set per_mhs = tersimpan and tersimpan.data.mode == 'per_mahasiswa' %}
<h2 class="bagian">NILAI PER MAHASISWA <span style="font-weight:normal;font-style:italic;color:var(--grey)">(ketik langsung di sel, 0100; kolom Nilai Akhir &amp; baris rata-rata dihitung dari data tersimpan)</span></h2>
<p class="keterangan">
Daftar mahasiswa dari impor kaprodi. Kosongkan sel yang belum dinilai;
<b>Simpan Nilai</b> menyimpan persis isi tabel. Nilai Akhir = tertimbang bobot
komponen RPS; angkanya diperbarui setelah disimpan.
</p>
<form method="post" action="/nilai/{{ peta.kode }}">
<div class="gulir" style="max-height:480px;overflow-y:auto">
{% set ada_kelas = grid|selectattr('kelas')|list|length > 0 %}
{% set n_kiri = 4 if ada_kelas else 3 %}
<table class="grid">
<thead>
<tr>
<th style="width:44px" class="tengah">No.</th>
<th style="width:112px">NPM</th>
<th style="min-width:150px">Nama</th>
{% if ada_kelas %}<th style="width:60px" class="tengah">Kelas</th>{% endif %}
{% for s in peta.subs %}<th class="tengah" style="font-size:11px;min-width:62px">{{ s.kode }}</th>{% endfor %}
<th class="tengah" style="width:80px">Nilai Akhir</th>
</tr>
</thead>
<tbody>
{% for m in grid %}
{% set i = loop.index0 %}
<tr>
<td class="tengah">{{ loop.index }}
<input type="hidden" name="npm_{{ i }}" value="{{ m.npm }}">
<input type="hidden" name="nama_{{ i }}" value="{{ m.nama }}"></td>
<td>{{ m.npm }}</td>
<td>{{ m.nama }}</td>
{% if ada_kelas %}<td class="tengah">{{ m.kelas or '—' }}</td>{% endif %}
{% for s in peta.subs %}
<td class="isian"><input type="number" name="skor_{{ i }}_{{ s.kode }}"
min="0" max="100" step="0.01"
value="{{ '%g'|format(m.skor[s.kode]) if s.kode in m.skor else '' }}"></td>
{% endfor %}
<td class="tengah"><b>{{ '%.1f'|format(akhir.get(m.npm)) if akhir.get(m.npm) is not none else '—' }}</b></td>
</tr>
{% endfor %}
{% if per_mhs and hasil %}
<tr class="total">
<td colspan="{{ n_kiri }}" style="text-align:right">Rata-rata kelas (tersimpan)</td>
{% for s in peta.subs %}
{% set info = hasil.sub.get(s.kode) %}
<td class="tengah">{{ '%.1f'|format(info.rata) if info else '—' }}</td>
{% endfor %}
<td class="tengah">{{ '%.1f'|format(akhir.values()|sum / akhir|length) if akhir else '—' }}</td>
</tr>
<tr class="total">
<td colspan="{{ n_kiri }}" style="text-align:right">% lulus (≥ {{ ambang|round(0)|int }})</td>
{% for s in peta.subs %}
{% set info = hasil.sub.get(s.kode) %}
<td class="tengah" {% if info and info.lulus_pct is not none and info.rata < ambang %}style="color:var(--red)"{% endif %}>{{ '%.0f'|format(info.lulus_pct) ~ '%' if info and info.lulus_pct is not none else '—' }}</td>
{% endfor %}
<td></td>
</tr>
{% endif %}
</tbody>
</table>
</div>
<div class="aksi-baris">
<span style="color:var(--grey);font-size:13px">Disimpan atas nama <b>{{ user.nama }}</b></span>
<span class="spacer"></span>
<button class="tombol" type="submit" name="aksi" value="grid">Simpan Nilai</button>
</div>
</form>
{% endif %}
<details class="cara-alt"{% if not grid %} open{% endif %}>
<summary>{{ 'ALTERNATIF — ' if grid }}UNGGAH EXCEL PER MAHASISWA <span style="font-weight:normal;font-style:italic;color:var(--grey)">(cocok bila nilai sudah direkap di Excel, atau team teaching mengisi terpisah)</span></summary>
<p class="keterangan">
Unduh template berkolom Sub-CPMK MK ini, isi nilai 0100 per mahasiswa, lalu unggah kembali.
{% if terdaftar %}Template sudah berisi <b>{{ terdaftar|length }} mahasiswa</b> yang
mengontrak MK ini (dari daftar impor kaprodi).
{% else %}<b>Daftar mahasiswa MK ini belum diimpor kaprodi</b> — template kosong,
isi NPM &amp; nama secara manual.{% endif %}
<br><b>Team teaching:</b> tiap dosen cukup mengunggah bagiannya sendiri — kolom
Sub-CPMK yang diampunya (mis. sebelum/sesudah UTS) atau baris mahasiswa kelasnya.
Unggahan <b>digabung</b>: sel terisi memperbarui nilai, sel kosong tidak menghapus
nilai yang sudah diunggah dosen lain.
</p>
<div class="aksi-baris" style="border-top:none;margin-top:0;padding-top:0">
<a class="tombol garis" href="/nilai/{{ peta.kode }}/template.xlsx">Unduh Template Excel</a>
</div>
<form method="post" action="/nilai/{{ peta.kode }}" enctype="multipart/form-data">
<div class="aksi-baris" style="border-top:none">
<input type="file" name="berkas" accept=".xlsx" style="width:auto">
<button class="tombol" type="submit" name="aksi" value="unggah">Unggah &amp; Hitung</button>
</div>
</form>
</details>
<details class="cara-alt"{% if tersimpan and tersimpan.data.mode == 'agregat' %} open{% endif %}>
<summary>ALTERNATIF — KETIK RATA-RATA KELAS PER SUB-CPMK <span style="font-weight:normal;font-style:italic;color:var(--grey)">(hanya bila nilai per mahasiswa tidak tersedia; ditandai "bukti agregat" pada rekap)</span></summary>
<form method="post" action="/nilai/{{ peta.kode }}">
<div class="gulir" style="max-height:420px;overflow-y:auto">
<table class="grid">
<thead><tr><th style="width:120px">Sub-CPMK</th><th>Uraian</th><th class="tengah" style="width:130px">Rata-rata (0100)</th></tr></thead>
<tbody>
{% for s in peta.subs %}
<tr>
<td class="tengah">{{ s.kode }}</td>
<td>{{ s.uraian[:110] }}{% if s.uraian|length > 110 %}…{% endif %}</td>
<td class="isian"><input type="number" name="rata_{{ s.kode }}" min="0" max="100" step="0.01"
value="{% if tersimpan and tersimpan.data.mode == 'agregat' %}{{ tersimpan.data.agregat.get(s.kode, '') }}{% endif %}"></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="aksi-baris">
<span style="color:var(--grey);font-size:13px">Disimpan atas nama <b>{{ user.nama }}</b></span>
<span class="spacer"></span>
<button class="tombol garis" type="submit" name="aksi" value="agregat">Simpan Rata-rata</button>
</div>
</form>
</details>
{% if hasil %}
<h2 class="bagian">HASIL KETERCAPAIAN MK INI <span style="font-weight:normal;font-style:italic;color:var(--grey)">(ambang {{ ambang|round(0)|int }}; roll-up bagi rata)</span></h2>
<div class="gulir">
<table class="grid">
<thead><tr><th>CPMK</th><th class="tengah">Skor</th><th class="tengah">Sub Ternilai</th><th>CPL Didukung</th></tr></thead>
<tbody>
{% for kode_c, v in hasil.cpmk.items() %}
<tr>
<td>{{ kode_c }}</td>
<td class="tengah">{% if v.skor is not none %}<b>{{ '%.2f'|format(v.skor) }}</b>{% else %}—{% endif %}</td>
<td class="tengah">{{ v.n_ternilai }}/{{ v.n_sub }}</td>
<td>{{ v.cpl|join(', ') }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="gulir" style="margin-top:10px">
<table class="grid">
<thead><tr><th>CPL (dalam MK ini)</th><th class="tengah">Skor</th><th class="tengah">Status</th></tr></thead>
<tbody>
{% for kode_c, v in hasil.cpl.items() %}
<tr>
<td>{{ kode_c }}</td>
<td class="tengah">{% if v.skor is not none %}<b>{{ '%.2f'|format(v.skor) }}</b>{% else %}—{% endif %}</td>
<td class="tengah">
{% if v.skor is none %}<span class="stamp stamp-draft">BELUM TERUKUR</span>
{% elif v.skor >= ambang %}<span class="stamp stamp-ok">TERCAPAI</span>
{% else %}<span class="stamp stamp-no">DI BAWAH AMBANG</span>{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
{% endblock %}