projektwoche-schueler.svelte 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. <div class="columns">
  2. <div class="column is-two-thirds">
  3. {#each Object.entries(schueler) as [klasse, schuelers]}
  4. <h3 class="title">{klasse}</h3>
  5. <h3 class="subtitle has-background-warning">{unterwegs(klasse)}</h3>
  6. <table class="table is-striped">
  7. <thead>
  8. <tr>
  9. <th>Name</th>
  10. <th>Vorname</th>
  11. <th>Projektwahl</th>
  12. </tr>
  13. </thead>
  14. <tbody>
  15. {#each schuelers as s,i}
  16. <tr>
  17. <td>{s.Name}</td>
  18. <td>{s.Vorname}</td>
  19. <td class={'has-background-'+wahl(s)} on:click={() => modalset(s,i)} style="cursor: pointer">
  20. {`Woche: ${s.woche == null ? '–' : s.woche} Mo/Di: ${s.mo_di == null ? '–' : s.mo_di} Mi/Do ${s.mi_do == null ? '–' : s.mi_do}`}
  21. </td>
  22. </tr>
  23. {/each}
  24. </tbody>
  25. </table>
  26. {/each}
  27. </div>
  28. <div class="column">
  29. <h3 class="title">Teilnehmerzahlen</h3>
  30. Ganze Woche: {anwesend_wo}
  31. <br>Nur Mo/Di: {anwesend_modi}
  32. <br>Nur Mi/Do: {anwesend_mido}
  33. <h3 class="title">Projektplätze</h3>
  34. Ganze Woche: {belegt_wo}/{plaetze_wo}
  35. <br>Mo/Di: {belegt_modi}/{plaetze_modi}
  36. <br>Mi/Do: {belegt_mido}/{plaetze_mido}
  37. <h3 class="title">Klassen</h3>
  38. <table class="table is-striped">
  39. <thead>
  40. <tr>
  41. <th>Klasse</th>
  42. <th>Woche</th>
  43. <th>Mo/Di</th>
  44. <th>Mi/Do</th>
  45. </tr>
  46. </thead>
  47. <tbody>
  48. {#each klassen && Object.entries(klassen) as [klasse, abwesenheit]}
  49. <tr>
  50. <td>{klasse}</td>
  51. <td class={`has-text-${abwesenheit === 0 ? 'danger':'success'}`} style="cursor: pointer;" on:click={() => switcher(klasse,0)}>{abwesenheit === 0 ? '✘':'✔'}</td>
  52. <td class={`has-text-${abwesenheit === 1 ? 'danger':'success'}`} style="cursor: pointer;" on:click={() => switcher(klasse,1)}>{abwesenheit === 1 ? '✘':'✔'}</td>
  53. <td class={`has-text-${abwesenheit === 2 ? 'danger':'success'}`} style="cursor: pointer;" on:click={() => switcher(klasse,2)}>{abwesenheit === 2 ? '✘':'✔'}</td>
  54. </tr>
  55. {/each}
  56. </tbody>
  57. </table>
  58. </div>
  59. </div>
  60. {#if modal_s}
  61. <div class="modal" class:is-active={modal}>
  62. <div class="modal-background"></div>
  63. <div class="modal-card">
  64. <header class="modal-card-head">
  65. <p class="modal-card-title">{modal_s.Vorname} {modal_s.Name}</p>
  66. <button class="delete" aria-label="close" on:click={() => modal = !modal}></button>
  67. </header>
  68. <section class="modal-card-body">
  69. <div class="field is-horizontal">
  70. <div class="field-label is-normal">
  71. <label class="label">Woche</label>
  72. </div>
  73. <div class="field-body">
  74. <div class="field is-narrow">
  75. <div class="control">
  76. <div class="select is-fullwidth">
  77. <select bind:value={selected_woche} on:change={wahl_aendern}>
  78. <option value={null}>Kein Projekt gewählt</option>
  79. {#each projekte.filter(p => p.woche) as p}
  80. <option value={p.id} selected={modal_s.woche}>{`${p.titel} – ${p.leitung} (${p.gewaehlt_woche}/${p.max_teilnehmer}`})</option>
  81. {/each}
  82. <option value={0} selected={modal_s.woche === 0}>Krank/Beurlaubt</option>
  83. </select>
  84. </div>
  85. </div>
  86. </div>
  87. </div>
  88. </div>
  89. <div class="field is-horizontal">
  90. <div class="field-label is-normal">
  91. <label class="label">Mo/Di</label>
  92. </div>
  93. <div class="field-body">
  94. <div class="field is-narrow">
  95. <div class="control">
  96. <div class="select is-fullwidth">
  97. <select bind:value={selected_mo_di} on:change={wahl_aendern}>
  98. <option value={null}>Kein Projekt gewählt</option>
  99. {#each projekte.filter(p => p.mo_di) as p}
  100. <option value={p.id} selected={modal_s.mo_di}>{`${p.titel} – ${p.leitung} (${p.gewaehlt_mo_di}/${p.max_teilnehmer}`})</option>
  101. {/each}
  102. <option value={0} selected={modal_s.mo_di === 0}>Krank/Beurlaubt</option>
  103. </select>
  104. </div>
  105. </div>
  106. </div>
  107. </div>
  108. </div>
  109. <div class="field is-horizontal">
  110. <div class="field-label is-normal">
  111. <label class="label">Mi/Do</label>
  112. </div>
  113. <div class="field-body">
  114. <div class="field is-narrow">
  115. <div class="control">
  116. <div class="select is-fullwidth">
  117. <select bind:value={selected_mi_do} on:change={wahl_aendern}>
  118. <option value={null}>Kein Projekt gewählt</option>
  119. {#each projekte.filter(p => p.mi_do) as p}
  120. <option value={p.id} selected={modal_s.mi_do}>
  121. {`${p.titel} – ${p.leitung} (${p.gewaehlt_mi_do}/${p.max_teilnehmer}`})
  122. </option>
  123. {/each}
  124. <option value={0} selected={modal_s.mi_do === 0}>Krank/Beurlaubt</option>
  125. </select>
  126. </div>
  127. </div>
  128. </div>
  129. </div>
  130. </div>
  131. </section>
  132. <footer class="modal-card-foot">
  133. Änderungen sind sofort wirksam
  134. </footer>
  135. </div>
  136. </div>
  137. {/if}
  138. <script>
  139. export let schueler, privat, knexConfig
  140. let projekte = [];
  141. let klassen = {}
  142. Object.keys(schueler).forEach(k => klassen[k] = null)
  143. let modal = false, modal_s, selected_woche, selected_mo_di, selected_mi_do;
  144. function modalset (s) {
  145. modal = true
  146. modal_s=s
  147. }
  148. const { Pool } = R('pg')
  149. const _ = R('lodash')
  150. const postgres = new Pool({ connectionString: privat.mein_bk_db})
  151. function projekte_laden () {
  152. postgres.query(`SELECT id, titel, leitung, woche, mo_di, mi_do, max_teilnehmer,
  153. (SELECT COUNT(*)
  154. FROM wahlen
  155. WHERE projekte.id = wahlen.woche
  156. ) as gewaehlt_woche,
  157. (SELECT COUNT(*)
  158. FROM wahlen
  159. WHERE projekte.id = wahlen.mo_di
  160. ) as gewaehlt_mo_di,
  161. (SELECT COUNT(*)
  162. FROM wahlen
  163. WHERE projekte.id = wahlen.mi_do
  164. ) as gewaehlt_mi_do
  165. FROM projekte`,
  166. (err, resp) => projekte = resp.rows)
  167. }
  168. projekte_laden()
  169. postgres.query(`SELECT * FROM klassen ORDER BY klasse`,
  170. (err, resp) => resp.rows.forEach(k => { klassen[k.klasse] = k.abwesenheit }))
  171. $: wahl = s => {
  172. const abwesenheit = klassen[s.Klasse]
  173. if (abwesenheit === null) {
  174. if (s.woche === s.mo_di && s.woche === s.mi_do) return 'danger'
  175. else if (typeof(s.mo_di) !== typeof(s.mi_do)) return 'warning'
  176. else if ([s.mo_di, s.mi_do, s.woche].includes(0)) return 'info'
  177. else return 'success'
  178. } else if (abwesenheit === 0) {
  179. if (s.woche === s.mo_di && s.woche === s.mi_do) return 'success'
  180. else return 'info'
  181. } else if (abwesenheit === 1) {
  182. if (s.woche === s.mo_di && s.woche === s.mi_do) return 'danger'
  183. else if (typeof(s.woche) === 'number' && (typeof(s.mo_di) === 'number'|| typeof(s.mi_do) === 'number')) return 'info'
  184. else if (typeof(s.mi_do) === 'number') return 'success'
  185. else if (s.mo_di === 0 || s.woche === 0) return 'warning'
  186. else return 'danger'
  187. } else if (abwesenheit === 2) {
  188. if (s.woche === s.mo_di && s.woche === s.mi_do) return 'danger'
  189. else if (typeof(s.woche) === 'number' && (typeof(s.mo_di) === 'number'|| typeof(s.mi_do) === 'number')) return 'info'
  190. else if (typeof(s.mo_di) === 'number') return 'success'
  191. else if (s.mi_do === 0 || s.woche === 0) return 'warning'
  192. else return 'danger'
  193. }
  194. }
  195. async function wahl_aendern () {
  196. const text = `INSERT INTO wahlen(schueler_id, woche, mo_di, mi_do)
  197. VALUES($1, $2, $3, $4)
  198. ON CONFLICT (schueler_id) DO
  199. UPDATE SET woche=$2, mo_di=$3, mi_do=$4
  200. RETURNING *`
  201. const values = [modal_s.id, selected_woche, selected_mo_di, selected_mi_do]
  202. try {
  203. const res = await postgres.query(text, values)
  204. const data = res.rows[0]
  205. projekte_laden()
  206. Object.assign(modal_s, data)
  207. schueler = schueler
  208. } catch(err) {
  209. console.log(err.stack)
  210. }
  211. }
  212. async function switcher(k, art) {
  213. const abwesenheit = klassen[k] === null || klassen[k] !== art ? art : null
  214. const text = `INSERT INTO klassen(klasse, abwesenheit)
  215. VALUES($1, $2)
  216. ON CONFLICT (klasse) DO
  217. UPDATE SET abwesenheit = $2
  218. WHERE klassen.klasse = $1
  219. RETURNING abwesenheit`
  220. const values = [k, abwesenheit]
  221. try {
  222. const res = await postgres.query(text, values)
  223. const data = res.rows[0]
  224. klassen[k] = data.abwesenheit
  225. } catch(err) {
  226. console.log(err.stack)
  227. }
  228. }
  229. $: unterwegs = klasse => {
  230. if (!klassen) return ''
  231. let out
  232. switch (klassen[klasse]) {
  233. case null: return ''; break;
  234. case 0: out = 'Montag bis Freitag'; break;
  235. case 1: out = 'Montag und Dienstag'; break;
  236. case 2: out = 'Mittwoch und Donnerstag'; break;
  237. }
  238. return `Die Klasse ist ${out} unterwegs`
  239. }
  240. let anwesend_wo, anwesend_modi, anwesend_mido
  241. $:{
  242. anwesend_wo = 0, anwesend_modi = 0, anwesend_mido = 0
  243. Object.entries(schueler).forEach(([k,v]) => {
  244. const nr = v.length
  245. console.log(klassen[k])
  246. switch (klassen[k]) {
  247. case null: anwesend_wo += nr; break;
  248. case 1: anwesend_mido += nr; break;
  249. case 2: anwesend_modi += nr; break;
  250. }
  251. })
  252. }
  253. let plaetze_wo, plaetze_modi, plaetze_mido
  254. let belegt_wo, belegt_modi, belegt_mido
  255. $:{
  256. plaetze_wo = 0, plaetze_modi = 0, plaetze_mido = 0
  257. belegt_wo = 0, belegt_modi = 0, belegt_mido = 0
  258. projekte.forEach(p => {
  259. p.woche && (plaetze_wo += p.max_teilnehmer)
  260. p.mo_di && (plaetze_modi += p.max_teilnehmer)
  261. p.mi_do && (plaetze_mido += p.max_teilnehmer)
  262. belegt_wo += parseInt(p.gewaehlt_woche)
  263. belegt_modi += parseInt(p.gewaehlt_mo_di)
  264. belegt_mido += parseInt(p.gewaehlt_mi_do)
  265. })
  266. }
  267. </script>