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,228 @@
|
||||
{% extends "base.html" %}
|
||||
{% block judul %}RPS {{ peta.nama }} — Informatika UNTAN{% endblock %}
|
||||
{% block isi %}
|
||||
<div class="nav-baris">
|
||||
<div>MK ini: <b>RPS</b> · <a href="/nilai/{{ peta.kode }}">Input Nilai</a> · <a href="/portofolio/{{ peta.kode }}">Portofolio</a></div>
|
||||
<div>
|
||||
{% if status == 'selesai' %}<span class="stamp stamp-ok">SELESAI</span>
|
||||
{% elif status == 'draft' %}<span class="stamp stamp-draft">DRAFT</span>
|
||||
{% else %}<span class="stamp stamp-no">BELUM</span>{% endif %}
|
||||
{% if updated_at %}<span style="color:var(--grey);font-size:13px"> · disimpan {{ updated_at }}{% if updated_by %} oleh {{ updated_by }}{% endif %}</span>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1>Rencana Pembelajaran Semester — {{ peta.nama }} <span style="color:var(--grey)">({{ peta.kode }})</span></h1>
|
||||
|
||||
{% if pesan %}<div class="info">{{ pesan }}</div>{% endif %}
|
||||
|
||||
{% if not boleh_edit %}
|
||||
<div class="info">Anda bukan pengampu MK ini — form terbuka <b>hanya untuk dibaca</b>.
|
||||
Hubungi kaprodi bila penugasan MK Anda perlu diubah.</div>
|
||||
{% endif %}
|
||||
|
||||
{% if tahun_lain and boleh_edit %}
|
||||
<div class="info">
|
||||
MK ini punya RPS pada tahun ajaran lain. Salin sebagai titik awal (status draft, bisa diedit):
|
||||
{% for t in tahun_lain %}
|
||||
<form method="post" action="/rps/{{ peta.kode }}/salin" style="display:inline">
|
||||
<input type="hidden" name="dari" value="{{ t }}">
|
||||
<button class="tombol garis" type="submit" style="padding:3px 10px;font-size:13px">Salin dari {{ t }}</button>
|
||||
</form>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<form method="post" action="/rps/{{ peta.kode }}">
|
||||
|
||||
<h2 class="bagian">A. IDENTITAS MATA KULIAH</h2>
|
||||
<table class="grid">
|
||||
<tr><td class="label">Nama Mata Kuliah</td><td>{{ peta.nama }}</td></tr>
|
||||
<tr><td class="label">Kode Mata Kuliah</td><td>{{ peta.kode }}</td></tr>
|
||||
<tr><td class="label">Bobot SKS</td>
|
||||
<td class="isian" style="display:flex;gap:8px;align-items:center;border:none">
|
||||
<input type="number" name="sks" min="0" max="8" style="width:70px" value="{{ f.identitas.sks }}"> SKS
|
||||
(Teori: <input type="number" name="sks_teori" min="0" max="8" style="width:70px" value="{{ f.identitas.sks_teori }}">
|
||||
| Praktikum: <input type="number" name="sks_praktikum" min="0" max="8" style="width:70px" value="{{ f.identitas.sks_praktikum }}">)
|
||||
</td></tr>
|
||||
<tr><td class="label">Semester</td><td class="isian"><input type="text" name="semester" value="{{ f.identitas.semester }}" placeholder="mis. 3 (Ganjil)"></td></tr>
|
||||
<tr><td class="label">Rumpun MK</td><td class="isian"><input type="text" name="rumpun" value="{{ f.identitas.rumpun }}" placeholder="mis. MK Inti Keilmuan"></td></tr>
|
||||
<tr><td class="label">MK Prasyarat</td><td class="isian"><input type="text" name="prasyarat" value="{{ f.identitas.prasyarat }}" placeholder="kosongkan bila tidak ada"></td></tr>
|
||||
<tr><td class="label">Dosen Pengampu</td><td class="isian"><input type="text" name="pengampu" value="{{ f.identitas.pengampu }}" placeholder="Nama Dosen 1 | Nama Dosen 2"></td></tr>
|
||||
<tr><td class="label">Dosen Pengembang RPS</td><td class="isian"><input type="text" name="pengembang" value="{{ f.identitas.pengembang }}" placeholder="bila kosong: diisi nama dosen pengampu"></td></tr>
|
||||
<tr><td class="label">Koordinator MK</td><td class="isian"><input type="text" name="koordinator" value="{{ f.identitas.koordinator }}"></td></tr>
|
||||
<tr><td class="label">Ketua Program Studi</td><td class="isian"><input type="text" name="kaprodi" value="{{ f.identitas.kaprodi }}"></td></tr>
|
||||
<tr><td class="label">Tgl Penyusunan</td><td class="isian"><input type="text" name="tgl_penyusunan" value="{{ f.identitas.tgl_penyusunan }}" placeholder="mis. 13 Juli 2026"></td></tr>
|
||||
<tr><td class="label">Kode Dokumen</td><td class="isian"><input type="text" name="kode_dokumen" value="{{ f.identitas.kode_dokumen }}" placeholder="diisi bagian penjaminan mutu, boleh kosong"></td></tr>
|
||||
</table>
|
||||
|
||||
<h2 class="bagian">B. CPL YANG DIBEBANKAN PADA MK <span style="font-weight:normal;font-style:italic;color:var(--grey)">— otomatis dari pemetaan kurikulum</span></h2>
|
||||
<table class="grid">
|
||||
<thead><tr><th style="width:90px">Kode</th><th>Deskripsi CPL</th></tr></thead>
|
||||
<tbody>
|
||||
{% for c in peta.cpls %}
|
||||
<tr><td class="tengah">{{ c.kode }}</td><td>{{ c.desk }}</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2 class="bagian">C. CPMK <span style="font-weight:normal;font-style:italic;color:var(--grey)">— otomatis dari pemetaan kurikulum</span></h2>
|
||||
<table class="grid">
|
||||
<thead><tr><th style="width:110px">Kode</th><th>Deskripsi CPMK</th><th style="width:130px">CPL Didukung</th></tr></thead>
|
||||
<tbody>
|
||||
{% for c in peta.cpmks %}
|
||||
<tr><td class="tengah">{{ c.kode }}</td><td>{{ c.desk }}</td><td class="tengah">{{ c.cpl|join(', ') }}</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2 class="bagian">D. SUB-CPMK <span style="font-weight:normal;font-style:italic;color:var(--grey)">— otomatis dari pemetaan kurikulum ({{ peta.subs|length }} butir)</span></h2>
|
||||
<div class="gulir" style="max-height:320px;overflow-y:auto">
|
||||
<table class="grid">
|
||||
<thead><tr><th style="width:110px">Kode</th><th>Uraian Sub-CPMK</th><th style="width:110px">CPMK</th></tr></thead>
|
||||
<tbody>
|
||||
{% for s in peta.subs %}
|
||||
<tr><td class="tengah">{{ s.kode }}</td><td>{{ s.uraian }}</td><td class="tengah">{{ s.cpmk }}</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h2 class="bagian">E. DESKRIPSI SINGKAT MATA KULIAH</h2>
|
||||
<textarea name="deskripsi" rows="4" placeholder="Topik utama, pendekatan pembelajaran, relevansi dengan profil lulusan dan CPL. Maksimal ± 100 kata.">{{ f.deskripsi }}</textarea>
|
||||
|
||||
<h2 class="bagian">E2. BAHAN KAJIAN — MATERI PEMBELAJARAN</h2>
|
||||
<textarea name="bahan_kajian" rows="4" placeholder="Materi/bahan kajian MK secara berurutan (sesuai format RPS UNTAN).">{{ f.bahan_kajian }}</textarea>
|
||||
|
||||
<h2 class="bagian">E3. MEDIA PEMBELAJARAN</h2>
|
||||
<textarea name="media" rows="2" placeholder="mis. LMS (e-learning UNTAN), LCD proyektor, perangkat lunak pendukung.">{{ f.media }}</textarea>
|
||||
|
||||
<h2 class="bagian">F. RENCANA MINGGUAN <span id="total-bobot-f" style="font-weight:normal">— total bobot: <b>0</b>%</span></h2>
|
||||
<p class="keterangan">Minggu 8 = UTS, minggu 16 = UAS. Total bobot seluruh minggu harus 100 %.</p>
|
||||
<div class="gulir">
|
||||
<table class="grid" id="tabel-f">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="tengah" style="width:52px" rowspan="2">Mg</th>
|
||||
<th style="min-width:190px" rowspan="2">Sub-CPMK</th>
|
||||
<th colspan="2">Penilaian</th>
|
||||
<th colspan="2">Bentuk/Metode Pembelajaran [Estimasi Waktu]</th>
|
||||
<th style="min-width:140px" rowspan="2">Kegiatan Pembelajaran</th>
|
||||
<th style="min-width:150px" rowspan="2">Materi [Pustaka]</th>
|
||||
<th class="tengah" style="width:70px" rowspan="2">Bobot (%)</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="sub" style="min-width:150px">Indikator</th>
|
||||
<th class="sub" style="min-width:140px">Kriteria & Teknik</th>
|
||||
<th class="sub" style="min-width:130px">Tatap Muka</th>
|
||||
<th class="sub" style="min-width:120px">Daring</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for m in f.minggu %}
|
||||
<tr class="{% if m.ke == 8 %}uts{% elif m.ke == 16 %}uas{% endif %}">
|
||||
<td class="tengah">{{ m.ke }}</td>
|
||||
<td class="isian">
|
||||
<select name="m{{ m.ke }}_sub">
|
||||
<option value="">— pilih —</option>
|
||||
{% for s in peta.subs %}
|
||||
<option value="{{ s.kode }}" {% if m.sub == s.kode %}selected{% endif %}>{{ s.kode }} — {{ s.uraian[:60] }}{% if s.uraian|length > 60 %}…{% endif %}</option>
|
||||
{% endfor %}
|
||||
<option value="__uts__" {% if m.sub == '__uts__' %}selected{% endif %}>Sub-CPMK minggu 1–7 (UTS)</option>
|
||||
<option value="__uas__" {% if m.sub == '__uas__' %}selected{% endif %}>Sub-CPMK minggu 9–15 (UAS)</option>
|
||||
</select>
|
||||
</td>
|
||||
<td class="isian"><textarea name="m{{ m.ke }}_indikator" rows="2">{{ m.indikator }}</textarea></td>
|
||||
<td class="isian"><textarea name="m{{ m.ke }}_kriteria" rows="2">{{ m.kriteria }}</textarea></td>
|
||||
<td class="isian"><textarea name="m{{ m.ke }}_metode" rows="2">{{ m.metode }}</textarea></td>
|
||||
<td class="isian"><textarea name="m{{ m.ke }}_daring" rows="2">{{ m.daring }}</textarea></td>
|
||||
<td class="isian"><textarea name="m{{ m.ke }}_kegiatan" rows="2">{{ m.kegiatan }}</textarea></td>
|
||||
<td class="isian"><textarea name="m{{ m.ke }}_materi" rows="2">{{ m.materi }}</textarea></td>
|
||||
<td class="isian"><input type="number" class="bobot-f" name="m{{ m.ke }}_bobot" min="0" max="100" step="0.5" value="{{ m.bobot }}"></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h2 class="bagian">G. REKAP BOBOT PENILAIAN <span id="total-bobot-g" style="font-weight:normal">— total: <b>0</b>%</span></h2>
|
||||
<p class="keterangan">Centang Sub-CPMK yang dinilai tiap komponen. Setiap Sub-CPMK harus tercakup minimal satu komponen agar CPMK/CPL-nya terukur.</p>
|
||||
<div class="gulir">
|
||||
<table class="grid">
|
||||
<thead>
|
||||
<tr><th style="width:190px">Komponen</th><th>Sub-CPMK yang Dinilai</th><th class="tengah" style="width:90px">Bobot (%)</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for k in f.komponen %}
|
||||
{% set ki = loop.index %}
|
||||
<tr>
|
||||
<td class="isian"><input type="text" name="k{{ ki }}_nama" value="{{ k.nama }}"></td>
|
||||
<td>
|
||||
<div class="pilih-sub">
|
||||
{% for s in peta.subs %}
|
||||
<label><input type="checkbox" class="sub-k" name="k{{ ki }}_subs" value="{{ s.kode }}" {% if s.kode in k.subs %}checked{% endif %}>{{ s.kode }} — {{ s.uraian[:70] }}{% if s.uraian|length > 70 %}…{% endif %}</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</td>
|
||||
<td class="isian"><input type="number" class="bobot-g" name="k{{ ki }}_bobot" min="0" max="100" step="0.5" value="{{ k.bobot }}"></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="info" id="cek-cakupan" hidden></div>
|
||||
|
||||
<h2 class="bagian">H. PUSTAKA UTAMA</h2>
|
||||
<p class="keterangan">Satu referensi per baris, format APA.</p>
|
||||
<textarea name="referensi" rows="5" placeholder="Penulis. (Tahun). Judul. Penerbit / Jurnal, Vol(No), Hal. https://doi.org/...">{{ f.referensi_teks }}</textarea>
|
||||
|
||||
<h2 class="bagian">H2. PUSTAKA PENDUKUNG</h2>
|
||||
<textarea name="referensi_pendukung" rows="3" placeholder="Satu referensi per baris; boleh kosong.">{{ f.referensi_pendukung_teks }}</textarea>
|
||||
|
||||
<div class="aksi-baris">
|
||||
{% if boleh_edit %}
|
||||
<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="draft">Simpan Draft</button>
|
||||
<button class="tombol selesai" type="submit" name="aksi" value="selesai">Simpan & Tandai Selesai</button>
|
||||
{% else %}
|
||||
<span class="spacer"></span>
|
||||
{% endif %}
|
||||
{% if status %}<a class="tombol" href="/rps/{{ peta.kode }}/unduh">Unduh .docx</a>
|
||||
<a class="tombol garis" href="/rps/{{ peta.kode }}/unduh.pdf">PDF</a>{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
function hitungTotal(kelas, idLabel) {
|
||||
let t = 0;
|
||||
document.querySelectorAll(kelas).forEach(el => { t += parseFloat(el.value) || 0; });
|
||||
const label = document.querySelector(idLabel);
|
||||
label.querySelector('b').textContent = (Math.round(t * 100) / 100);
|
||||
label.classList.toggle('salah', Math.abs(t - 100) > 0.01);
|
||||
}
|
||||
function cekCakupan() {
|
||||
const dinilai = new Set();
|
||||
document.querySelectorAll('.sub-k:checked').forEach(cb => dinilai.add(cb.value));
|
||||
const semua = [{% for s in peta.subs %}'{{ s.kode }}'{% if not loop.last %},{% endif %}{% endfor %}];
|
||||
const hilang = semua.filter(k => !dinilai.has(k));
|
||||
const kotak = document.getElementById('cek-cakupan');
|
||||
if (hilang.length === 0) {
|
||||
kotak.hidden = false;
|
||||
kotak.className = 'info';
|
||||
kotak.textContent = 'Semua ' + semua.length + ' Sub-CPMK sudah tercakup komponen penilaian — CPMK dan CPL mata kuliah ini akan terukur penuh.';
|
||||
} else {
|
||||
kotak.hidden = false;
|
||||
kotak.className = 'peringatan';
|
||||
kotak.textContent = 'Perhatian: ' + hilang.length + ' Sub-CPMK belum dinilai komponen mana pun (ketercapaian CPMK/CPL-nya tidak akan terukur): ' + hilang.join(', ');
|
||||
}
|
||||
}
|
||||
function segarkan() {
|
||||
hitungTotal('.bobot-f', '#total-bobot-f');
|
||||
hitungTotal('.bobot-g', '#total-bobot-g');
|
||||
cekCakupan();
|
||||
}
|
||||
document.addEventListener('input', segarkan);
|
||||
segarkan();
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user