a45b08b00e
- Peran dosen dipecah jadi dosen_mk (nilai & portofolio saja, RPS baca-only) dan dosen_rps_mk (bisa edit RPS juga); migrasi otomatis dari skema lama. - Rekap Bobot Penilaian RPS pakai 6 komponen teknik asesmen baku prodi; total wajib tepat 100%, komponen individual boleh dikosongkan. - Dropdown & daftar Sub-CPMK tak lagi terpotong teksnya. - Bagian F (Rencana Mingguan): tombol "Isi Otomatis" per baris (termasuk usulan Bobot) yang muncul setelah Sub-CPMK dipilih, plus panel contoh teks bantu per kolom. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
141 lines
6.5 KiB
HTML
141 lines
6.5 KiB
HTML
{% extends "base.html" %}
|
||
{% block isi %}
|
||
<div class="kpi-baris" title="Persentase dihitung dari MK pada semester terpilih — hijau ≥ 75 %, kuning 40–74 %, merah < 40 %">
|
||
<div><b id="kpi-mk">{{ daftar|length }}</b> <span>mata kuliah</span></div>
|
||
<div><b id="kpi-rps">{{ n_selesai }}</b> <span>RPS selesai</span> <span class="kpi-pct" id="pct-rps"></span></div>
|
||
<div><b id="kpi-draft">{{ n_draft }}</b> <span>RPS draft</span></div>
|
||
<div><b id="kpi-nilai">{{ st_nilai|length }}</b> <span>MK setor nilai</span> <span class="kpi-pct" id="pct-nilai"></span></div>
|
||
<div><b id="kpi-porto">{{ st_porto.values()|selectattr('status', 'equalto', 'selesai')|list|length }}</b> <span>portofolio selesai</span> <span class="kpi-pct" id="pct-porto"></span></div>
|
||
</div>
|
||
|
||
{% if user.role != 'kaprodi' %}
|
||
{% if hanya_saya %}
|
||
<div class="info" style="margin-top:0">Menampilkan <b>{{ daftar|length }} MK yang Anda ampu</b>.
|
||
RPS mata kuliah lain tetap terbuka baca — <a href="/?semua=1">tampilkan seluruh {{ n_total }} MK</a>.</div>
|
||
{% elif mk_saya %}
|
||
<div class="info" style="margin-top:0">Menampilkan seluruh {{ n_total }} MK —
|
||
<a href="/">kembali ke MK yang Anda ampu saja</a>.</div>
|
||
{% else %}
|
||
<div class="peringatan" style="margin-top:0">Belum ada MK yang ditugaskan kepada
|
||
Anda — hubungi kaprodi agar menetapkan penugasan di halaman Kelola Akun.
|
||
Sementara itu seluruh MK ditampilkan (hanya-baca).</div>
|
||
{% endif %}
|
||
{% endif %}
|
||
|
||
<div class="filter-baris">
|
||
<label for="filter-smt">Tampilkan semester:</label>
|
||
<select id="filter-smt" style="width:auto">
|
||
<option value="">Semua</option>
|
||
<option value="ganjil">Ganjil (1, 3, 5, 7)</option>
|
||
<option value="genap">Genap (2, 4, 6, 8)</option>
|
||
{% for s in smt.values()|select|unique|sort %}
|
||
<option value="{{ s }}">Semester {{ s }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
<span id="filter-info" class="keterangan" style="margin:0"></span>
|
||
</div>
|
||
|
||
{% macro stempel(st) -%}
|
||
{% if st and st.status == 'selesai' %}<span class="stamp stamp-ok">SELESAI</span>
|
||
{% elif st %}<span class="stamp stamp-draft">DRAFT</span>
|
||
{% else %}<span class="stamp stamp-no">BELUM</span>{% endif %}
|
||
{%- endmacro %}
|
||
|
||
<div class="gulir">
|
||
<table class="grid">
|
||
<thead>
|
||
<tr>
|
||
<th style="width:56px">No.</th>
|
||
<th style="width:112px">Kode</th>
|
||
<th class="tengah" style="width:52px">Smt</th>
|
||
<th>Mata Kuliah</th>
|
||
<th style="width:150px">Pengampu</th>
|
||
<th style="width:120px">CPL Dipikul</th>
|
||
<th class="tengah" style="width:104px">RPS</th>
|
||
<th class="tengah" style="width:104px">Nilai</th>
|
||
<th class="tengah" style="width:104px">Portofolio</th>
|
||
<th style="width:170px">Pemutakhiran Terakhir</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for mk in daftar %}
|
||
{% set st = status.get(mk.kode) %}
|
||
{% set sn = st_nilai.get(mk.kode) %}
|
||
{% set sp = st_porto.get(mk.kode) %}
|
||
<tr data-smt="{{ smt.get(mk.kode) or '' }}"
|
||
data-rps="{{ st.status if st else '' }}"
|
||
data-nilai="{{ sn.status if sn else '' }}"
|
||
data-porto="{{ sp.status if sp else '' }}">
|
||
<td class="tengah">{{ mk.no }}</td>
|
||
<td>{{ mk.kode }}</td>
|
||
<td class="tengah">{{ smt.get(mk.kode) or '—' }}</td>
|
||
<td>{{ mk.nama }}<br>
|
||
<span style="font-size:12px;color:var(--grey)">{{ mk.n_cpmk }} CPMK · {{ mk.n_sub }} Sub-CPMK</span>
|
||
</td>
|
||
<td style="font-size:13px">{{ pengampu.get(mk.kode, [])|join(', ') or '—' }}</td>
|
||
<td>{{ mk.cpls|map('replace','CPL-','')|join(', ') }}</td>
|
||
<td class="tengah"><a href="/rps/{{ mk.kode }}" style="text-decoration:none">{{ stempel(st) }}</a></td>
|
||
<td class="tengah"><a href="/nilai/{{ mk.kode }}" style="text-decoration:none">{{ stempel(sn) }}</a></td>
|
||
<td class="tengah"><a href="/portofolio/{{ mk.kode }}" style="text-decoration:none">{{ stempel(sp) }}</a></td>
|
||
<td style="font-size:12.5px">
|
||
{% set terakhir = [st, sn, sp]|select|sort(attribute='updated_at')|last %}
|
||
{% if terakhir %}{{ terakhir.updated_at }}{% if terakhir.updated_by %} — {{ terakhir.updated_by }}{% endif %}{% else %}—{% endif %}
|
||
</td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<script>
|
||
(function () {
|
||
var pilih = document.getElementById('filter-smt');
|
||
var info = document.getElementById('filter-info');
|
||
var baris = document.querySelectorAll('table.grid tbody tr');
|
||
|
||
function cocok(tr, v) {
|
||
var smt = tr.dataset.smt;
|
||
return v === '' ? true :
|
||
v === 'ganjil' ? smt !== '' && smt % 2 === 1 :
|
||
v === 'genap' ? smt !== '' && smt % 2 === 0 :
|
||
smt === v;
|
||
}
|
||
|
||
function isiPct(id, n, total) {
|
||
var el = document.getElementById(id);
|
||
if (!total) { el.textContent = ''; el.className = 'kpi-pct'; return; }
|
||
var p = Math.round(100 * n / total);
|
||
el.textContent = p + ' %';
|
||
el.className = 'kpi-pct ' +
|
||
(p >= 75 ? 'kpi-hijau' : p >= 40 ? 'kpi-kuning' : 'kpi-merah');
|
||
}
|
||
|
||
function perbarui() {
|
||
var v = pilih.value, n = 0, rSel = 0, rDraft = 0, nilai = 0, porto = 0;
|
||
baris.forEach(function (tr) {
|
||
var tampil = cocok(tr, v);
|
||
tr.style.display = tampil ? '' : 'none';
|
||
if (!tampil) return;
|
||
n++;
|
||
if (tr.dataset.rps === 'selesai') rSel++;
|
||
if (tr.dataset.rps === 'draft') rDraft++;
|
||
if (tr.dataset.nilai !== '') nilai++;
|
||
if (tr.dataset.porto === 'selesai') porto++;
|
||
});
|
||
document.getElementById('kpi-mk').textContent = n;
|
||
document.getElementById('kpi-rps').textContent = rSel;
|
||
document.getElementById('kpi-draft').textContent = rDraft;
|
||
document.getElementById('kpi-nilai').textContent = nilai;
|
||
document.getElementById('kpi-porto').textContent = porto;
|
||
isiPct('pct-rps', rSel, n);
|
||
isiPct('pct-nilai', nilai, n);
|
||
isiPct('pct-porto', porto, n);
|
||
info.textContent = v === '' ? '' : n + ' dari ' + baris.length + ' MK ditampilkan';
|
||
}
|
||
|
||
pilih.addEventListener('change', perbarui);
|
||
perbarui();
|
||
})();
|
||
</script>
|
||
<p class="keterangan" style="margin-top:10px">Klik stempel untuk membuka form terkait. Alur per MK: <b>RPS</b> (rencana & bobot) → <b>Nilai</b> (unggah Excel / rata-rata) → <b>Portofolio</b> (refleksi & dokumen akhir). Rekap prodi menggulung otomatis dari nilai yang masuk.</p>
|
||
{% endblock %}
|