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>
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
{% extends "base.html" %}
|
||||
{% block judul %}Kelola Akun & Mahasiswa — RPS & Portofolio UNTAN{% endblock %}
|
||||
{% block isi %}
|
||||
<h1>Kelola Akun & Mahasiswa</h1>
|
||||
{% if pesan %}<div class="info">{{ pesan }}</div>{% endif %}
|
||||
|
||||
<h2 class="bagian">A. Akun Pengguna & Penugasan Mata Kuliah</h2>
|
||||
<p class="keterangan">Dosen hanya dapat mengedit RPS/portofolio dan melihat nilai
|
||||
mahasiswa pada MK yang ditugaskan kepadanya. Kaprodi dapat mengakses semuanya.</p>
|
||||
<div class="gulir">
|
||||
<table class="grid">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:170px">Nama</th>
|
||||
<th style="width:160px">NIP</th>
|
||||
<th style="width:90px">Peran</th>
|
||||
<th>MK yang Diampu</th>
|
||||
<th style="width:340px">Tindakan</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for p in pengguna %}
|
||||
<tr>
|
||||
<td>{{ p.nama }}</td>
|
||||
<td>{{ p.username }}</td>
|
||||
<td>{{ 'Kaprodi' if p.role == 'kaprodi' else 'Dosen' }}</td>
|
||||
<td>
|
||||
{% if p.role == 'kaprodi' %}
|
||||
<i style="color:var(--grey)">semua MK</i>
|
||||
{% else %}
|
||||
{{ p.mk|join(', ') if p.mk else '—' }}
|
||||
<details style="margin-top:6px">
|
||||
<summary style="cursor:pointer;color:var(--blue);font-size:13px">Ubah penugasan…</summary>
|
||||
<form method="post" action="/admin/pengguna/{{ p.id }}/tugas">
|
||||
<div class="pilih-sub" style="max-height:220px;margin:6px 0">
|
||||
{% for mk in daftar %}
|
||||
<label><input type="checkbox" name="mk" value="{{ mk.kode }}"
|
||||
{% if mk.kode in p.mk %}checked{% endif %}> {{ mk.kode }} — {{ mk.nama }}</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<button class="tombol garis" type="submit" style="padding:4px 12px;font-size:13px">Simpan Penugasan</button>
|
||||
</form>
|
||||
</details>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<form method="post" action="/admin/pengguna/{{ p.id }}/reset"
|
||||
style="display:inline">
|
||||
<button class="tombol garis" type="submit"
|
||||
style="padding:4px 10px;font-size:13px">Reset Password ke NIP</button>
|
||||
</form>
|
||||
{% if p.id != user.id %}
|
||||
<form method="post" action="/admin/pengguna/{{ p.id }}/hapus"
|
||||
style="display:inline" onsubmit="return confirm('Hapus akun {{ p.nama }} ({{ p.username }})?')">
|
||||
<button class="tombol garis" type="submit"
|
||||
style="padding:4px 10px;font-size:13px;color:var(--red);border-color:var(--red)">Hapus</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h2 class="bagian">B. Buat Akun Baru</h2>
|
||||
<p class="keterangan">NIP menjadi username sekaligus password awal — dosen langsung
|
||||
bisa masuk dengan NIP-nya.</p>
|
||||
<form method="post" action="/admin/pengguna" class="aksi-baris"
|
||||
style="border-top:none;padding-top:0;margin-top:8px">
|
||||
<label>Nama lengkap <input type="text" name="nama" required style="width:230px"></label>
|
||||
<label>NIP <input type="text" name="nip" required style="width:180px"></label>
|
||||
<label>Peran
|
||||
<select name="role" style="width:110px">
|
||||
<option value="dosen" selected>Dosen</option>
|
||||
<option value="kaprodi">Kaprodi</option>
|
||||
</select>
|
||||
</label>
|
||||
<button class="tombol" type="submit">Buat Akun</button>
|
||||
</form>
|
||||
|
||||
<h2 class="bagian">C. Daftar Mahasiswa Mengontrak MK — {{ tahun }}</h2>
|
||||
<p class="keterangan">Unggah satu file Excel berisi seluruh kontrak semester ini
|
||||
(kolom: NPM, Nama, Kode MK, Kelas — satu baris per kontrak). Impor baru
|
||||
<b>menggantikan seluruh daftar</b> tahun ajaran aktif. Daftar ini dipakai untuk
|
||||
mengisi otomatis template nilai tiap MK.</p>
|
||||
<div class="aksi-baris" style="border-top:none;padding-top:0;margin-top:8px">
|
||||
<a class="tombol garis" href="/admin/mahasiswa/template.xlsx">Unduh Template Daftar Mahasiswa (.xlsx)</a>
|
||||
<form method="post" action="/admin/mahasiswa" enctype="multipart/form-data"
|
||||
style="display:inline-flex;gap:10px;align-items:center">
|
||||
<input type="file" name="berkas" accept=".xlsx" required>
|
||||
<button class="tombol" type="submit">Impor & Ganti Daftar</button>
|
||||
</form>
|
||||
</div>
|
||||
{% if mhs %}
|
||||
<div class="gulir" style="margin-top:12px">
|
||||
<table class="grid" style="max-width:720px">
|
||||
<thead>
|
||||
<tr><th style="width:120px">Kode MK</th><th class="tengah" style="width:130px">Mahasiswa</th><th>Kelas</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for mk in daftar if mk.kode in mhs %}
|
||||
<tr>
|
||||
<td>{{ mk.kode }} — {{ mk.nama }}</td>
|
||||
<td class="tengah">{{ mhs[mk.kode].n }}</td>
|
||||
<td>{{ mhs[mk.kode].kelas|join(', ') if mhs[mk.kode].kelas else '—' }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="keterangan">Belum ada daftar mahasiswa untuk tahun ajaran ini.</p>
|
||||
{% endif %}
|
||||
|
||||
<h2 class="bagian">D. Cadangan Data</h2>
|
||||
<p class="keterangan">Unduh salinan seluruh isian secara berkala dan simpan di
|
||||
tempat aman — terutama sebelum pemutakhiran aplikasi atau pergantian server.</p>
|
||||
<a class="tombol garis" href="/cadangan.json">Unduh cadangan JSON (seluruh isian)</a>
|
||||
<a class="tombol garis" href="/cadangan.db">Unduh cadangan SQLite (file DB mentah)</a>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user