Files
OBE-Mapping/app/templates/form_rps.html
T
Power BI Dev 5f615aa7e8 Rapikan tampilan nilai, ganti NPM->NIM, fitur ganti password, kunci RPS view-only
- Tampilan "Isi Per Komponen Penilaian" diganti dari tombol bertumpuk teks
  jadi tabel (Komponen/Sub-CPMK/Bobot/Status/Aksi) dengan status berupa
  stempel, lebih mudah dipindai.
- Filter pencarian MK (ketik kode/nama) di kotak penugasan dosen /admin.
- Istilah NPM diseragamkan jadi NIM di seluruh aplikasi (label, header,
  template Excel, dokumen portofolio), termasuk migrasi kolom database
  mahasiswa.npm -> nim yang aman (ALTER TABLE RENAME COLUMN, otomatis saat
  startup, tanpa kehilangan data; parser Excel tetap terima file lama
  berheader NPM).
- Fitur ganti password mandiri (/akun): verifikasi password lama, sesi lain
  otomatis keluar setelah berhasil, sesi yang dipakai tetap aktif.
- RPS: dosen RPS+MK kini bisa menyesuaikan redaksi kalimat Sub-CPMK (bagian
  D) untuk MK yang diampu -- kode & kaitan CPMK/CPL tetap dari kurikulum,
  hanya teksnya yang bisa disesuaikan. Penyesuaian otomatis konsisten di
  dropdown mingguan (F), checklist komponen (G), serta unduhan RPS &
  portofolio, tanpa menyentuh data kurikulum induk atau halaman nilai/
  dashboard prodi.
- Form RPS dibungkus <fieldset disabled> untuk dosen tanpa hak edit --
  seluruh field benar-benar terkunci (bukan cuma tombol simpan hilang).
2026-07-22 08:37:54 +07:00

288 lines
16 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 %}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 tidak memiliki hak edit RPS untuk MK ini — form terbuka
<b>hanya untuk dibaca</b>. Ini karena Anda bukan pengampu MK ini, atau peran Anda
<b>Dosen MK</b> (hanya mengelola nilai &amp; portofolio). Hubungi kaprodi bila ini
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 }}">
<fieldset {% if not boleh_edit %}disabled{% endif %} style="border:none;padding:0;margin:0">
<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
&nbsp;(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)">— kode &amp; kaitan CPMK otomatis dari pemetaan kurikulum ({{ peta.subs|length }} butir); redaksi kalimat boleh disesuaikan bila perlu</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 class="isian"><textarea name="sub_uraian_{{ s.kode }}" rows="2">{{ s.uraian }}</textarea></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 %.
{% if boleh_edit %}Pilih Sub-CPMK lalu klik <b>Isi Otomatis</b> untuk mengisi kolom kosong dengan teks
bantu (termasuk usulan Bobot — UTS 20%, UAS 30%, minggu biasa 3,5% — sesuaikan lagi agar totalnya
pas 100%).{% endif %}</p>
{% if boleh_edit %}
<details style="margin:0 0 10px">
<summary style="cursor:pointer;color:var(--blue);font-size:13px">Lihat contoh teks bantu per kolom</summary>
<div class="info" style="margin-top:6px;line-height:1.7">
<b>Indikator</b> — turunan Sub-CPMK, mis. "Mahasiswa mampu menjelaskan …"; "Ketepatan dan kelengkapan dalam …"<br>
<b>Kriteria &amp; Teknik</b> — mis. "Rubrik holistik; tes tertulis" / "Ketepatan jawaban; unjuk kerja" / "Kelengkapan tugas; observasi"<br>
<b>Tatap Muka</b> — mis. "Ceramah, diskusi, tanya jawab [TM: 2x50 menit]" / "Studi kasus &amp; presentasi kelompok [TM: 2x50 menit]"<br>
<b>Daring</b> — mis. "Membaca modul &amp; kuis di LMS [BT+BM: 2x60 menit]" / "Diskusi forum LMS [BT+BM: 2x60 menit]"<br>
<b>Kegiatan Pembelajaran</b> — mis. "Mahasiswa menyimak paparan dosen, berdiskusi, dan mengerjakan latihan terkait materi minggu ini."<br>
<b>Materi [Pustaka]</b> — rujuk nomor pustaka di Bagian H, mis. "Bab 3 (Pustaka Utama #1)"
</div>
</details>
{% endif %}
<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 &amp; 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" {% if boleh_edit %}onchange="document.getElementById('btn-isi-m{{ m.ke }}').style.display = this.value ? '' : 'none'"{% endif %}>
<option value="">— pilih —</option>
{% for s in peta.subs %}
<option value="{{ s.kode }}" {% if m.sub == s.kode %}selected{% endif %}>{{ s.kode }} — {{ s.uraian }}</option>
<option disabled>──────────────────────</option>
{% endfor %}
<option value="__uts__" {% if m.sub == '__uts__' %}selected{% endif %}>Sub-CPMK minggu 17 (UTS)</option>
<option value="__uas__" {% if m.sub == '__uas__' %}selected{% endif %}>Sub-CPMK minggu 915 (UAS)</option>
</select>
{% if boleh_edit %}
<button type="button" id="btn-isi-m{{ m.ke }}" class="tombol garis"
style="padding:1px 6px;font-size:10px;margin-top:4px;{% if not m.sub %}display:none{% endif %}"
onclick="isiOtomatis({{ m.ke }})" title="Isi kolom kosong dengan teks bantu dari Sub-CPMK terpilih">Isi Otomatis</button>
{% endif %}
</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">Enam komponen teknik asesmen baku prodi. Bobot boleh dikosongkan untuk
komponen yang tidak dipakai MK ini (opsional), tapi total seluruh komponen yang diisi harus
tepat 100%. 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>{{ 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 }}</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>
</fieldset>
<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 &amp; 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>
const SUB_URAIAN = {{ sub_uraian | tojson | safe }};
function isiOtomatis(mg) {
const sel = document.querySelector(`select[name="m${mg}_sub"]`);
const nilai = sel ? sel.value : '';
const isi = (nama, teks) => {
const el = document.querySelector(`[name="m${mg}_${nama}"]`);
if (el && !el.value.trim()) el.value = teks;
};
if (SUB_URAIAN[nilai]) {
const uraian = SUB_URAIAN[nilai];
isi('indikator', 'Mahasiswa ' + uraian.charAt(0).toLowerCase() + uraian.slice(1));
} else if (nilai === '__uts__') {
isi('indikator', 'Mahasiswa menguasai capaian Sub-CPMK minggu 17.');
} else if (nilai === '__uas__') {
isi('indikator', 'Mahasiswa menguasai capaian Sub-CPMK minggu 915.');
} else {
return; // belum pilih Sub-CPMK — tak ada dasar untuk mengisi
}
isi('kriteria', 'Ketepatan dan kelengkapan jawaban/tugas sesuai rubrik penilaian.');
isi('metode', 'Ceramah, diskusi, dan tanya jawab [TM: 2x50 menit]');
isi('daring', 'Membaca materi & berdiskusi di LMS [BT+BM: 2x60 menit]');
isi('kegiatan', 'Mahasiswa menyimak penjelasan dosen, berdiskusi, dan mengerjakan latihan terkait materi minggu ini.');
// bobot: usulan awal (UTS/UAS lazim lebih besar) — total tetap harus disesuaikan ke 100%
isi('bobot', mg == 8 ? '20' : mg == 16 ? '30' : '3.5');
segarkan();
}
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 %}