HTML

Krankenhaus-Management-Simulation

Unvollständiger Mockup einer Patienten Aufnahme Zimmer Zuordnungssimulation

Keine Vorschau vorhanden

Code-Snapshot

Dies ist der veröffentlichte Zustand. Spätere Änderungen am Code überschreiben diese Veröffentlichung nicht automatisch.

[{"text":"Projekt","spriteCssClass":"fa fa-folder","items":[{"text":"index.html","spriteCssClass":"fa fa-file-code-o","code":"<!DOCTYPE html>\n<html lang='de'>\n<head>\n  <meta charset='UTF-8'>\n  <meta name='viewport' content='width=device-width, initial-scale=1.0'>\n  <title>Krankenhaus-Management-Simulation</title>\n  <link rel='stylesheet' href='style.css'>\n</head>\n<body>\n  <header class='hero'>\n    <div>\n      <p class='eyebrow'>CodeRoom Projekt Lab</p>\n      <h1>Krankenhaus-Management-Simulation</h1>\n      <p class='subtitle'>Steuere Aufnahme, Untersuchung und Behandlung, bevor die Wartezeiten kritisch werden.</p>\n    </div>\n    <div class='status-card'>\n      <span class='status-label'>Krankenhausstatus</span>\n      <strong id='hospitalStatus'>Stabil</strong>\n      <small id='statusHint'>Das Team ist bereit.</small>\n    </div>\n  </header>\n\n  <main class='layout'>\n    <section class='panel control-panel'>\n      <h2>Leitstelle</h2>\n      <div class='button-row'>\n        <button id='addPatientButton'>Patient aufnehmen</button>\n        <button id='treatPatientButton'>Behandlung starten</button>\n        <button id='pauseButton' class='secondary'>Pause</button>\n      </div>\n      <div class='resource-grid'>\n        <div>\n          <span>Ärzte frei</span>\n          <strong id='doctorCount'>2</strong>\n        </div>\n        <div>\n          <span>Zimmer frei</span>\n          <strong id='roomCount'>3</strong>\n        </div>\n        <div>\n          <span>Pflege frei</span>\n          <strong id='nurseCount'>3</strong>\n        </div>\n      </div>\n      <p class='hint'>Tipp: Kritische Fälle sollten zuerst behandelt werden. TODO: Baue später eine echte Prioritätenlogik ein.</p>\n    </section>\n\n    <section class='panel queue-panel'>\n      <div class='section-heading'>\n        <h2>Notaufnahme</h2>\n        <span id='queueCount'>0 wartend</span>\n      </div>\n      <div id='patientList' class='patient-list'></div>\n    </section>\n\n    <section class='panel rooms-panel'>\n      <div class='section-heading'>\n        <h2>Zimmerplan</h2>\n        <span>Prototyp</span>\n      </div>\n      <div class='rooms'>\n        <div class='room'><strong>Zimmer 1</strong><span id='roomOne'>frei</span></div>\n        <div class='room'><strong>Zimmer 2</strong><span id='roomTwo'>frei</span></div>\n        <div class='room'><strong>Zimmer 3</strong><span id='roomThree'>frei</span></div>\n      </div>\n      <p class='hint'>TODO: Verknüpfe echte Patientendaten mit den Zimmern.</p>\n    </section>\n\n    <section class='panel stats-panel'>\n      <h2>Tagesstatistik</h2>\n      <div class='stats'>\n        <div><span>Behandelt</span><strong id='treatedCount'>0</strong></div>\n        <div><span>Entlassen</span><strong id='releasedCount'>0</strong></div>\n        <div><span>Kritisch</span><strong id='criticalCount'>0</strong></div>\n        <div><span>Ø Wartezeit</span><strong id='avgWaitTime'>0</strong></div>\n      </div>\n    </section>\n  </main>\n\n  <script src='script.js'></script>\n</body>\n</html>","isMain":true},{"text":"script.js","spriteCssClass":"fa fa-file-code-o","code":"const patientNames = ['Mia Becker', 'Noah Schulz', 'Lea Wagner', 'Emil Hoffmann', 'Sara Klein', 'Ben Fischer'];\nconst conditions = ['Atemnot', 'Fieber', 'Sportverletzung', 'Bauchschmerzen', 'Schwindel', 'Schnittwunde'];\nconst priorities = ['stabil', 'dringend', 'kritisch'];\n\nlet patients = [];\nlet treated = 0;\nlet released = 0;\nlet isPaused = false;\nlet nextId = 1;\nlet waitingTimes = [];\n\n// Array to track room occupancy\nlet rooms = ['frei', 'frei', 'frei'];\n\n// Event system\nconst events = [\n  { type: 'normal', message: 'Neue Lieferung von Medikamenten eingetroffen.', probability: 0.6 },\n  { type: 'normal', message: 'Rettungswagen eingetroffen mit neuem Patienten.', probability: 0.5 },\n  { type: 'normal', message: 'Schulung des Personals abgeschlossen.', probability: 0.4 },\n  { type: 'grippewelle', message: 'Grippewelle gemeldet! Erhöhte Patientenzahlen erwartet.', probability: 0.2 },\n  { type: 'normal', message: 'Technische Wartung der Geräte durchgeführt.', probability: 0.5 },\n  { type: 'normal', message: 'Besprechung des Behandlungsteams abgeschlossen.', probability: 0.4 }\n];\n\nconst patientList = document.querySelector('#patientList');\nconst queueCount = document.querySelector('#queueCount');\nconst treatedCount = document.querySelector('#treatedCount');\nconst releasedCount = document.querySelector('#releasedCount');\nconst criticalCount = document.querySelector('#criticalCount');\nconst avgWaitTime = document.querySelector('#avgWaitTime');\nconst hospitalStatus = document.querySelector('#hospitalStatus');\nconst statusHint = document.querySelector('#statusHint');\nconst doctorCount = document.querySelector('#doctorCount');\nconst roomCount = document.querySelector('#roomCount');\nconst nurseCount = document.querySelector('#nurseCount');\nconst pauseButton = document.querySelector('#pauseButton');\n\nfunction randomItem(list) {\n  return list[Math.floor(Math.random() * list.length)];\n}\nfunction triggerRandomEvent() {\n  // Filter events based on their probability\n  const possibleEvents = events.filter(event => Math.random() < event.probability);\n  \n  if (possibleEvents.length > 0) {\n    const randomEvent = randomItem(possibleEvents);\n    \n    // Show event message in status area\n    statusHint.textContent = randomEvent.message;\n    \n    // Handle special event types\n    if (randomEvent.type === 'grippewelle') {\n      // Add two additional patients during flu wave\n      addPatient();\n      addPatient();\n      \n      // Update status to reflect the flu wave\n      hospitalStatus.textContent = 'Angespannt';\n    }\n  }\n}\n\n\nfunction createPatient() {\n  const priority = randomItem(priorities);\n\n  return {\n    id: nextId++,\n    name: randomItem(patientNames),\n    condition: randomItem(conditions),\n    priority: priority,\n    wait: 0,\n    treatmentTime: priority === 'kritisch' ? 4 : 3\n  };\n}\n\nfunction addPatient() {\n  patients.push(createPatient());\n  renderAll();\n}\n\nfunction selectPatient(patientId) {\n  const patient = patients.find(p => p.id === patientId);\n  if (patient) {\n    statusHint.textContent = 'Patient ' + patient.name + ' ausgewählt.';\n    return patient;\n  }\n  return null;\n}\n\nfunction admitPatient(patientId) {\n  const patient = patients.find(p => p.id === patientId);\n  if (!patient) {\n    statusHint.textContent = 'Patient nicht gefunden.';\n    return;\n  }\n\n  // Find a free room\n  let roomIndex = -1;\n  for (let i = 0; i < rooms.length; i++) {\n    if (rooms[i] === 'frei') {\n      roomIndex = i;\n      break;\n    }\n  }\n\n  if (roomIndex !== -1) {\n    // Remove patient from waiting list\n    patients = patients.filter(p => p.id !== patientId);\n    treated += 1;\n\n    if (patient.priority === 'kritisch') {\n      released += 1;\n    }\n\n    // Record waiting time\n    waitingTimes.push(patient.wait);\n\n    // Assign patient to room\n    rooms[roomIndex] = patient.name;\n    statusHint.textContent = patient.name + ' wird in Zimmer ' + (roomIndex + 1) + ' aufgenommen.';\n\n    // Release room after treatment time\n    setTimeout(function() {\n      rooms[roomIndex] = 'frei';\n      statusHint.textContent = 'Zimmer ' + (roomIndex + 1) + ' ist wieder frei.';\n      renderAll();\n    }, patient.treatmentTime * 1000);\n  } else {\n    statusHint.textContent = 'Kein freies Zimmer verfügbar!';\n  }\n\n  renderAll();\n}\n\nfunction treatPatient() {\n  if (patients.length === 0) {\n    statusHint.textContent = 'Keine wartenden Patienten.';\n    return;\n  }\n\n  // Find patient with highest priority (kritisch > dringend > stabil)\n  let selectedPatient = null;\n  let selectedIndex = -1;\n  \n  // First look for kritisch patients\n  for (let i = 0; i < patients.length; i++) {\n    if (patients[i].priority === 'kritisch') {\n      selectedPatient = patients[i];\n      selectedIndex = i;\n      break;\n    }\n  }\n  \n  // If no kritisch, look for dringend\n  if (selectedPatient === null) {\n    for (let i = 0; i < patients.length; i++) {\n      if (patients[i].priority === 'dringend') {\n        selectedPatient = patients[i];\n        selectedIndex = i;\n        break;\n      }\n    }\n  }\n  \n  // If no kritisch or dringend, look for stabil\n  if (selectedPatient === null) {\n    for (let i = 0; i < patients.length; i++) {\n      if (patients[i].priority === 'stabil') {\n        selectedPatient = patients[i];\n        selectedIndex = i;\n        break;\n      }\n    }\n  }\n\n  // Find a free room\n  let roomIndex = -1;\n  for (let i = 0; i < rooms.length; i++) {\n    if (rooms[i] === 'frei') {\n      roomIndex = i;\n      break;\n    }\n  }\n\n  // Remove the selected patient from the array\n  if (selectedIndex !== -1 && roomIndex !== -1) {\n    patients.splice(selectedIndex, 1);\n    treated += 1;\n\n    if (selectedPatient.priority === 'kritisch') {\n      released += 1;\n    }\n\n    // Record waiting time of treated patient\n    waitingTimes.push(selectedPatient.wait);\n\n    // Assign patient to room\n    rooms[roomIndex] = selectedPatient.name;\n    statusHint.textContent = selectedPatient.name + ' wird in Zimmer ' + (roomIndex + 1) + ' behandelt.';\n\n    // Release room after treatment time\n    setTimeout(function() {\n      rooms[roomIndex] = 'frei';\n      statusHint.textContent = 'Zimmer ' + (roomIndex + 1) + ' ist wieder frei.';\n      renderAll();\n    }, selectedPatient.treatmentTime * 1000);\n  } else if (roomIndex === -1) {\n    statusHint.textContent = 'Kein freies Zimmer verfügbar!';\n  }\n  \n  renderAll();\n}\n\nfunction updateWaitingTimes() {\n  if (isPaused) {\n    return;\n  }\n\n  patients.forEach(function(patient) {\n    patient.wait += 1;\n\n    // TODO: Verfeinere diese Eskalation mit mehreren Regeln.\n    if (patient.wait > 8 && patient.priority === 'stabil') {\n      patient.priority = 'dringend';\n    }\n\n    if (patient.wait > 14 && patient.priority === 'dringend') {\n      patient.priority = 'kritisch';\n    }\n  });\n\n  // Trigger random events occasionally\n  if (Math.random() > 0.7) {\n    triggerRandomEvent();\n  }\n\n  if (Math.random() > 0.55) {\n    addPatient();\n    return;\n  }\n\n  renderAll();\n}\n\nfunction createPatientCard(patient) {\n  const card = document.createElement('article');\n  card.className = 'patient-card';\n  card.dataset.patientId = patient.id;\n\n  if (patient.priority === 'dringend') {\n    card.classList.add('warn');\n  }\n\n  if (patient.priority === 'kritisch') {\n    card.classList.add('danger');\n  }\n\n  const info = document.createElement('div');\n\n  const title = document.createElement('h3');\n  title.textContent = patient.name;\n\n  const condition = document.createElement('p');\n  condition.textContent = 'Zustand: ' + patient.condition;\n\n  const wait = document.createElement('p');\n  wait.textContent = 'Wartezeit: ' + patient.wait + ' Minuten';\n\n  const badge = document.createElement('span');\n  badge.className = 'priority-badge';\n  badge.textContent = patient.priority;\n\n  const selectButton = document.createElement('button');\n  selectButton.textContent = 'Auswählen';\n  selectButton.className = 'select-button';\n  selectButton.dataset.patientId = patient.id;\n\n  const admitButton = document.createElement('button');\n  admitButton.textContent = 'Aufnehmen';\n  admitButton.className = 'admit-button';\n  admitButton.dataset.patientId = patient.id;\n\n  info.appendChild(title);\n  info.appendChild(condition);\n  info.appendChild(wait);\n  card.appendChild(info);\n  card.appendChild(badge);\n  card.appendChild(selectButton);\n  card.appendChild(admitButton);\n\n  return card;\n}\n\nfunction renderPatients() {\n  patientList.textContent = '';\n\n  if (patients.length === 0) {\n    const empty = document.createElement('p');\n    empty.className = 'hint';\n    empty.textContent = 'Die Notaufnahme ist leer. Nimm einen neuen Patienten auf.';\n    patientList.appendChild(empty);\n    return;\n  }\n\n  patients.forEach(function(patient) {\n    patientList.appendChild(createPatientCard(patient));\n  });\n}\n\nfunction renderStats() {\n  const criticalPatients = patients.filter(function(patient) {\n    return patient.priority === 'kritisch';\n  }).length;\n\n  queueCount.textContent = patients.length + ' wartend';\n  treatedCount.textContent = treated;\n  releasedCount.textContent = released;\n  criticalCount.textContent = criticalPatients;\n\n  // Calculate average waiting time\n  if (waitingTimes.length > 0) {\n    const sum = waitingTimes.reduce((a, b) => a + b, 0);\n    const avg = Math.round(sum / waitingTimes.length);\n    avgWaitTime.textContent = avg;\n  } else {\n    avgWaitTime.textContent = '0';\n  }\n\n  doctorCount.textContent = Math.max(0, 2 - criticalPatients);\n  roomCount.textContent = Math.max(0, 3 - patients.length);\n  nurseCount.textContent = Math.max(0, 3 - Math.floor(patients.length / 2));\n\n  if (criticalPatients >= 3 || patients.length >= 7) {\n    hospitalStatus.textContent = 'Überlastet';\n    statusHint.textContent = 'Priorisiere kritische Fälle.';\n  } else if (criticalPatients > 0 || patients.length >= 4) {\n    hospitalStatus.textContent = 'Angespannt';\n  } else {\n    hospitalStatus.textContent = 'Stabil';\n  }\n}\n\nfunction renderRooms() {\n  const roomOne = document.querySelector('#roomOne');\n  const roomTwo = document.querySelector('#roomTwo');\n  const roomThree = document.querySelector('#roomThree');\n  const roomElements = [roomOne, roomTwo, roomThree];\n\n  roomElements.forEach(function(roomElement, index) {\n    roomElement.textContent = rooms[index];\n  });\n}\n\nfunction renderAll() {\n  renderPatients();\n  renderStats();\n  renderRooms();\n}\n// Event listeners for select and admit buttons\ndocument.addEventListener('click', function(event) {\n  if (event.target.classList.contains('select-button')) {\n    const patientId = parseInt(event.target.dataset.patientId);\n    selectPatient(patientId);\n  } else if (event.target.classList.contains('admit-button')) {\n    const patientId = parseInt(event.target.dataset.patientId);\n    admitPatient(patientId);\n  }\n});\n\n\ndocument.querySelector('#addPatientButton').addEventListener('click', addPatient);\ndocument.querySelector('#treatPatientButton').addEventListener('click', treatPatient);\npauseButton.addEventListener('click', function() {\n  isPaused = !isPaused;\n  pauseButton.textContent = isPaused ? 'Weiter' : 'Pause';\n  statusHint.textContent = isPaused ? 'Simulation pausiert.' : 'Simulation läuft weiter.';\n});\n\naddPatient();\naddPatient();\nrenderAll();\nsetInterval(updateWaitingTimes, 2500);\n","isMain":false},{"text":"style.css","spriteCssClass":"fa fa-file-code-o","code":":root {\n  --bg: #101827;\n  --panel: #172235;\n  --panel-light: #22314a;\n  --text: #eef4ff;\n  --muted: #9fb0cc;\n  --accent: #57d3ff;\n  --good: #68e391;\n  --warn: #ffd166;\n  --danger: #ff6b6b;\n}\n\n* {\n  box-sizing: border-box;\n}\n\nbody {\n  margin: 0;\n  font-family: Arial, Helvetica, sans-serif;\n  background: radial-gradient(circle at top left, #1f3b65, var(--bg));\n  color: var(--text);\n  min-height: 100vh;\n}\n\n.hero {\n  display: flex;\n  justify-content: space-between;\n  gap: 1rem;\n  padding: 2rem;\n  align-items: stretch;\n}\n\n.eyebrow {\n  color: var(--accent);\n  text-transform: uppercase;\n  letter-spacing: 0.12em;\n  font-size: 0.8rem;\n  margin: 0 0 0.5rem;\n}\n\nh1, h2, p {\n  margin-top: 0;\n}\n\nh1 {\n  font-size: clamp(2rem, 5vw, 4rem);\n  margin-bottom: 0.5rem;\n}\n\n.subtitle {\n  color: var(--muted);\n  max-width: 680px;\n  font-size: 1.1rem;\n}\n\n.status-card, .panel {\n  background: rgba(23, 34, 53, 0.88);\n  border: 1px solid rgba(255, 255, 255, 0.08);\n  border-radius: 22px;\n  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25);\n}\n\n.status-card {\n  min-width: 220px;\n  padding: 1.4rem;\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n}\n\n.status-label, .section-heading span, .hint, .resource-grid span, .stats span, .room span {\n  color: var(--muted);\n}\n\n.status-card strong {\n  font-size: 2rem;\n  margin: 0.4rem 0;\n}\n\n.layout {\n  display: grid;\n  grid-template-columns: 1fr 1.4fr;\n  gap: 1rem;\n  padding: 0 2rem 2rem;\n}\n\n.panel {\n  padding: 1.3rem;\n}\n\n.queue-panel {\n  grid-row: span 2;\n}\n\n.section-heading {\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n  gap: 1rem;\n}\n\n.button-row {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 0.7rem;\n  margin-bottom: 1rem;\n}\n\nbutton {\n  border: 0;\n  border-radius: 999px;\n  background: var(--accent);\n  color: #07111f;\n  font-weight: 700;\n  padding: 0.8rem 1rem;\n  cursor: pointer;\n  transition: transform 0.15s ease, filter 0.15s ease;\n}\n\nbutton:hover {\n  transform: translateY(-2px);\n  filter: brightness(1.08);\n}\n\nbutton.secondary {\n  background: var(--panel-light);\n  color: var(--text);\n}\n\n.resource-grid, .stats {\n  display: grid;\n  grid-template-columns: repeat(3, 1fr);\n  gap: 0.7rem;\n}\n\n.resource-grid div, .stats div, .room, .patient-card {\n  background: var(--panel-light);\n  border-radius: 16px;\n  padding: 1rem;\n}\n\n.resource-grid strong, .stats strong {\n  display: block;\n  font-size: 1.7rem;\n  margin-top: 0.2rem;\n}\n\n.patient-list {\n  display: grid;\n  gap: 0.8rem;\n}\n\n.patient-card {\n  display: grid;\n  grid-template-columns: 1fr auto auto auto;\n  gap: 0.6rem;\n  border-left: 8px solid var(--good);\n}\n.patient-card button {\n  padding: 0.4rem 0.8rem;\n  border-radius: 8px;\n  font-size: 0.8rem;\n  margin-left: 0.4rem;\n}\n\n.patient-card .select-button {\n  background: var(--panel-light);\n  color: var(--text);\n}\n\n.patient-card .admit-button {\n  background: var(--accent);\n  color: #07111f;\n}\n\n\n.patient-card.warn {\n  border-left-color: var(--warn);\n}\n\n.patient-card.danger {\n  border-left-color: var(--danger);\n}\n\n.patient-card h3 {\n  margin: 0 0 0.3rem;\n}\n\n.patient-card p {\n  margin: 0.15rem 0;\n  color: var(--muted);\n}\n\n.priority-badge {\n  padding: 0.35rem 0.6rem;\n  border-radius: 999px;\n  background: rgba(255, 255, 255, 0.1);\n  align-self: start;\n  font-weight: 700;\n}\n\n.rooms {\n  display: grid;\n  gap: 0.7rem;\n}\n\n.room {\n  display: flex;\n  justify-content: space-between;\n}\n\n.hint {\n  margin: 1rem 0 0;\n  line-height: 1.5;\n}\n\n@media (max-width: 850px) {\n  .hero, .layout {\n    grid-template-columns: 1fr;\n    display: grid;\n    padding-left: 1rem;\n    padding-right: 1rem;\n  }\n\n  .hero {\n    padding-top: 1rem;\n  }\n\n  .resource-grid, .stats {\n    grid-template-columns: 1fr;\n  }\n\n  .button-row {\n    flex-direction: column;\n    gap: 0.5rem;\n  }\n\n  button {\n    width: 100%;\n    padding: 0.8rem;\n  }\n\n  .patient-list {\n    gap: 0.6rem;\n  }\n\n  .patient-card {\n    display: flex;\n    flex-direction: column;\n    gap: 0.5rem;\n  }\n}\n","isMain":false}]}]