projektwoche-schueler.svelte 9.0 KB

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