Update simulasi-mk.html

versi 3
This commit is contained in:
izu
2026-02-04 02:15:52 +00:00
parent f90bb4d85c
commit 6732dcc5dc

View File

@@ -25,6 +25,9 @@
.course-card.violation .cat-bar { background-color: #ef4444 !important; } .course-card.violation .cat-bar { background-color: #ef4444 !important; }
.violation-badge { position: absolute; right: 0.5rem; bottom: 0.5rem; font-size: 0.65rem; color: #dc2626; font-weight: bold; display: flex; align-items: center; gap: 2px; } .violation-badge { position: absolute; right: 0.5rem; bottom: 0.5rem; font-size: 0.65rem; color: #dc2626; font-weight: bold; display: flex; align-items: center; gap: 2px; }
/* Elective Styles (New) */
.course-card.is-elective { background-color: #fffbeb; border-color: #fcd34d; } /* Yellow tint */
/* Grade Badges */ /* Grade Badges */
.grade-badge { position: absolute; right: 0.5rem; top: 0.5rem; font-size: 0.7rem; font-weight: bold; padding: 0.1rem 0.4rem; border-radius: 0.25rem; } .grade-badge { position: absolute; right: 0.5rem; top: 0.5rem; font-size: 0.7rem; font-weight: bold; padding: 0.1rem 0.4rem; border-radius: 0.25rem; }
.grade-A { background: #dcfce7; color: #166534; border: 1px solid #bbf7d0; } .grade-A { background: #dcfce7; color: #166534; border: 1px solid #bbf7d0; }
@@ -131,7 +134,7 @@
<h1 class="text-3xl md:text-4xl font-bold text-slate-900 mb-2">Simulasi Studi Berbasis IPS</h1> <h1 class="text-3xl md:text-4xl font-bold text-slate-900 mb-2">Simulasi Studi Berbasis IPS</h1>
<p class="text-slate-600 max-w-2xl mx-auto text-sm md:text-base"> <p class="text-slate-600 max-w-2xl mx-auto text-sm md:text-base">
Simulasi nyata: <strong>IPS Semester lalu menentukan jatah SKS semester depan.</strong><br> Simulasi nyata: <strong>IPS Semester lalu menentukan jatah SKS semester depan.</strong><br>
Sistem <strong>Prasyarat Aktif</strong>: Anda tidak bisa mengambil mata kuliah lanjut jika prasyarat belum lulus. Jalur <strong>UMUM (Campuran)</strong> sekarang menampilkan mata kuliah spesifik di semester akhir. Buka Katalog untuk mengganti sesuai minat Anda.
</p> </p>
<div class="mt-6 flex flex-wrap justify-center gap-3 text-xs font-semibold opacity-80"> <div class="mt-6 flex flex-wrap justify-center gap-3 text-xs font-semibold opacity-80">
@@ -166,8 +169,8 @@
<!-- Track Selector --> <!-- Track Selector -->
<div class="flex flex-wrap justify-center mb-10 gap-2"> <div class="flex flex-wrap justify-center mb-10 gap-2">
<button onclick="switchTrack('general')" class="track-btn active px-4 py-2 rounded-full text-xs font-bold border transition-colors bg-slate-800 text-white" id="btn-general">Umum</button> <button onclick="switchTrack('general')" class="track-btn active px-4 py-2 rounded-full text-xs font-bold border transition-colors bg-slate-800 text-white" id="btn-general">Umum (Campuran)</button>
<button onclick="switchTrack('ai')" class="track-btn px-4 py-2 rounded-full text-xs font-bold border transition-colors bg-white hover:bg-slate-50" id="btn-ai">AI</button> <button onclick="switchTrack('ai')" class="track-btn px-4 py-2 rounded-full text-xs font-bold border transition-colors bg-white hover:bg-slate-50" id="btn-ai">AI & Data</button>
<button onclick="switchTrack('rpl')" class="track-btn px-4 py-2 rounded-full text-xs font-bold border transition-colors bg-white hover:bg-slate-50" id="btn-rpl">RPL</button> <button onclick="switchTrack('rpl')" class="track-btn px-4 py-2 rounded-full text-xs font-bold border transition-colors bg-white hover:bg-slate-50" id="btn-rpl">RPL</button>
<button onclick="switchTrack('net')" class="track-btn px-4 py-2 rounded-full text-xs font-bold border transition-colors bg-white hover:bg-slate-50" id="btn-net">Jaringan</button> <button onclick="switchTrack('net')" class="track-btn px-4 py-2 rounded-full text-xs font-bold border transition-colors bg-white hover:bg-slate-50" id="btn-net">Jaringan</button>
<button onclick="switchTrack('si')" class="track-btn px-4 py-2 rounded-full text-xs font-bold border transition-colors bg-white hover:bg-slate-50" id="btn-si">SI & GIS</button> <button onclick="switchTrack('si')" class="track-btn px-4 py-2 rounded-full text-xs font-bold border transition-colors bg-white hover:bg-slate-50" id="btn-si">SI & GIS</button>
@@ -222,12 +225,6 @@
}; };
// --- Prerequisite Rules --- // --- Prerequisite Rules ---
// M7: Logika Komputasional
// M14: Dasar Pemrograman
// M19: Struktur Data
// M20: Jaringan Komputer
// M28: Pemrograman Jaringan
// M31: Manajemen Jaringan
const prerequisites = { const prerequisites = {
"M14": { reqId: "M7", reqName: "Logika Komputasional" }, "M14": { reqId: "M7", reqName: "Logika Komputasional" },
"M19": { reqId: "M14", reqName: "Dasar Pemrograman" }, "M19": { reqId: "M14", reqName: "Dasar Pemrograman" },
@@ -303,12 +300,13 @@
}; };
const electives = { const electives = {
// General track now has specific courses as a "Sample Mix"
general: [ general: [
{ id: "EL1", name: "MK Pilihan I", sks: 3, cat: "EL" }, { id: "GEN1", name: "Cross-Platform Dev", sks: 3, cat: "EL" }, // RPL flavor
{ id: "EL2", name: "MK Pilihan II", sks: 3, cat: "EL" }, { id: "GEN2", name: "Data Mining", sks: 3, cat: "EL" }, // AI flavor
{ id: "EL3", name: "MK Pilihan III", sks: 3, cat: "EL" }, { id: "GEN3", name: "Cloud Computing", sks: 3, cat: "EL" }, // Net flavor
{ id: "EL4", name: "MK Pilihan IV", sks: 3, cat: "EL" }, { id: "GEN4", name: "E-Business", sks: 3, cat: "EL" }, // SI flavor
{ id: "EL5", name: "MK Pilihan V", sks: 3, cat: "EL" } { id: "GEN5", name: "Blockchain Tech", sks: 3, cat: "EL" } // Advanced
], ],
ai: [ ai: [
{ id: "AI1", name: "Deep Learning", sks: 3, cat: "EL" }, { id: "AI1", name: "Deep Learning", sks: 3, cat: "EL" },
@@ -359,11 +357,18 @@
} }
} }
// Add Electives // Add Electives with Flag
const tr = electives[trackId] || electives['general']; const tr = electives[trackId] || electives['general'];
const distribute = [[5,0], [6,1], [7,2], [7,3], [8,4]]; const distribute = [[5,0], [6,1], [7,2], [7,3], [8,4]];
distribute.forEach(([sem, idx]) => { distribute.forEach(([sem, idx]) => {
if(tr[idx]) currentPlan[sem].push({...tr[idx], grade: 4, uuid: generateUUID()}); if(tr[idx]) {
currentPlan[sem].push({
...tr[idx],
grade: 4,
uuid: generateUUID(),
isElective: true // Tag as elective
});
}
}); });
renderCatalog(); renderCatalog();
@@ -424,7 +429,6 @@
grid.innerHTML = ''; grid.innerHTML = '';
// First Pass: Check Violations (Prerequisites) // First Pass: Check Violations (Prerequisites)
// Need to run this before rendering to mark cards
for(let i=1; i<=8; i++) { for(let i=1; i<=8; i++) {
currentPlan[i].forEach(course => { currentPlan[i].forEach(course => {
const check = checkPrerequisite(course.id, i); const check = checkPrerequisite(course.id, i);
@@ -507,11 +511,12 @@
const isFailed = c.grade === 0; const isFailed = c.grade === 0;
const isRetake = c.isRetake === true; const isRetake = c.isRetake === true;
const isViolation = c.violation === true; const isViolation = c.violation === true;
const isElective = c.isElective === true;
// Add 'violation' class if prereq failed
card.className = `course-card bg-white p-2 pl-4 rounded shadow-sm border border-slate-200 relative card.className = `course-card bg-white p-2 pl-4 rounded shadow-sm border border-slate-200 relative
${isFailed ? 'border-red-300 bg-red-50' : ''} ${isFailed ? 'border-red-300 bg-red-50' : ''}
${isViolation ? 'violation' : ''}`; ${isViolation ? 'violation' : ''}
${isElective ? 'is-elective' : ''}`;
card.draggable = true; card.draggable = true;
card.setAttribute('ondragstart', `dragSemester(event, ${semId}, ${index})`); card.setAttribute('ondragstart', `dragSemester(event, ${semId}, ${index})`);
@@ -530,6 +535,7 @@
<div class="text-xs font-bold text-slate-700 leading-tight mb-1 flex items-center"> <div class="text-xs font-bold text-slate-700 leading-tight mb-1 flex items-center">
${c.name} ${c.name}
${isRetake ? '<i class="fas fa-redo-alt text-[10px] text-blue-500 ml-2" title="Mengulang"></i>' : ''} ${isRetake ? '<i class="fas fa-redo-alt text-[10px] text-blue-500 ml-2" title="Mengulang"></i>' : ''}
${isElective ? '<i class="fas fa-star text-[10px] text-yellow-500 ml-2" title="MK Peminatan"></i>' : ''}
</div> </div>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<span class="text-[10px] text-slate-500 bg-slate-100 px-1 rounded border">${c.sks} SKS</span> <span class="text-[10px] text-slate-500 bg-slate-100 px-1 rounded border">${c.sks} SKS</span>
@@ -570,11 +576,10 @@
courseToAdd = currentPlan[dragSource.semId][dragSource.index]; courseToAdd = currentPlan[dragSource.semId][dragSource.index];
} }
// --- Prerequisite Check Before Dropping ---
const check = checkPrerequisite(courseToAdd.id, targetSem); const check = checkPrerequisite(courseToAdd.id, targetSem);
if (!check.allowed) { if (!check.allowed) {
showToast("❌ " + check.msg); showToast("❌ " + check.msg);
return; // Block Action return;
} }
if(dragSource.type === 'catalog') { if(dragSource.type === 'catalog') {
@@ -625,7 +630,7 @@
showToast("Mata kuliah Gagal (E). Klik kanan > 'Ulang di Tahun Depan' untuk memperbaiki."); showToast("Mata kuliah Gagal (E). Klik kanan > 'Ulang di Tahun Depan' untuk memperbaiki.");
} }
renderAll(); // Will trigger re-validation of downstream courses renderAll();
} }
hideContextMenu(); hideContextMenu();
} }
@@ -644,7 +649,6 @@
if (exists) { if (exists) {
showToast("Mata kuliah ini sudah ada di Semester " + targetSem + "."); showToast("Mata kuliah ini sudah ada di Semester " + targetSem + ".");
} else { } else {
// Check Prereq again for the target sem (just in case)
const check = checkPrerequisite(course.id, targetSem); const check = checkPrerequisite(course.id, targetSem);
if (!check.allowed) { if (!check.allowed) {
showToast("❌ Tidak bisa mengulang: " + check.msg); showToast("❌ Tidak bisa mengulang: " + check.msg);
@@ -695,8 +699,18 @@
list.innerHTML = ''; list.innerHTML = '';
let allCourses = []; let allCourses = [];
// Base Courses
for(let i=1; i<=8; i++) if(baseCurriculum[i]) allCourses.push(...baseCurriculum[i]); for(let i=1; i<=8; i++) if(baseCurriculum[i]) allCourses.push(...baseCurriculum[i]);
// Logic Baru: Jika Track == 'general', TAMPILKAN SEMUA PILIHAN
if(currentTrackId === 'general') {
allCourses.push(...electives['ai']);
allCourses.push(...electives['rpl']);
allCourses.push(...electives['net']);
allCourses.push(...electives['si']);
} else {
allCourses.push(...(electives[currentTrackId] || [])); allCourses.push(...(electives[currentTrackId] || []));
}
const unique = []; const unique = [];
const seen = new Set(); const seen = new Set();
@@ -738,6 +752,14 @@
btn.classList.remove('bg-white', 'text-slate-800'); btn.classList.remove('bg-white', 'text-slate-800');
btn.classList.add('bg-slate-800', 'text-white'); btn.classList.add('bg-slate-800', 'text-white');
// Notification
let trackName = "Umum";
if(trackId === 'ai') trackName = "AI & Data";
if(trackId === 'rpl') trackName = "RPL";
if(trackId === 'net') trackName = "Jaringan";
if(trackId === 'si') trackName = "SI & GIS";
showToast(`Jalur diubah ke ${trackName}.`);
initPlan(trackId); initPlan(trackId);
} }