Scanner.svelte 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. <script>
  2. import { configData, db, scan_status } from "./../stores.js";
  3. import { DontBubbleException } from './../exceptions.js'
  4. import { onDestroy } from 'svelte';
  5. import { focus, sort_by_name } from './../helpers.js';
  6. onDestroy(() => $scan_status = {})
  7. export let scaninterface
  8. const { update, ausleihe, rueckgabe, zuordnung } = scaninterface
  9. $scan_status = { ausleihe, rueckgabe, zuordnung }
  10. const prefix_length = $configData.scan_prefix.length;
  11. let buffer = [],
  12. barcode,
  13. barcode_manuell,
  14. registrieren,
  15. fehlermeldung,
  16. lastKeyTime = Date.now(),
  17. medium,
  18. neuer_titel = "",
  19. medium_selected;
  20. function handle_keydown(event) {
  21. if (registrieren) {
  22. (event.key === 'Escape') && (registrieren = false)
  23. return
  24. }
  25. if (event.key === 'Escape') {
  26. barcode = ''
  27. barcode_manuell = !barcode_manuell
  28. }
  29. if (barcode_manuell) return
  30. const currentTime = Date.now();
  31. if (currentTime - lastKeyTime > 1000) buffer = [];
  32. if (event.key === 'Enter' && !buffer.length) return
  33. if (
  34. event.key === "Enter" &&
  35. buffer.slice(0, prefix_length).join("") === $configData.scan_prefix
  36. ) {
  37. barcode = buffer.slice(prefix_length).join("");
  38. buffer = [];
  39. scan();
  40. } else {
  41. const charList = "abcdefghijklmnopqrstuvwxyz0123456789";
  42. const key = event.key.toLowerCase();
  43. if (charList.indexOf(key) === -1) return;
  44. buffer.push(event.key);
  45. lastKeyTime = currentTime;
  46. }
  47. }
  48. function scan() {
  49. const res = $db
  50. .prepare(
  51. `
  52. SELECT x.barcode, x.id AS x_id, m.name, m.id AS m_id, x.medienbezeichnung_id, a.*, a.id AS ausleihe_id
  53. FROM medienexemplar x
  54. LEFT JOIN medienbezeichnung AS m ON (x.medienbezeichnung_id = m.id)
  55. LEFT JOIN ausleihe AS a ON (a.medienexemplar_id = x.id)
  56. WHERE barcode = ?
  57. `
  58. )
  59. .get(barcode);
  60. console.log('Ergebnis Barcodesuche: ', res || '– nichts gefunden –');
  61. if (!res) {
  62. try {
  63. zuordnung(barcode);
  64. } catch (e) {
  65. medium = $db.prepare(`SELECT * FROM medienbezeichnung`).all();
  66. registrieren = true
  67. console.log(e, "Barcode unbekannt; Medium registrieren");
  68. return
  69. }
  70. } else if (res.ausleihe_id) {
  71. try {
  72. rueckgabe(res);
  73. } catch (e) {
  74. if (e instanceof DontBubbleException) return
  75. }
  76. } else {
  77. try {
  78. ausleihe(res);
  79. } catch (e) {
  80. if (e instanceof DontBubbleException) return
  81. }
  82. }
  83. try {
  84. update();
  85. } catch (e) {
  86. console.log("Ausgeliehene Medien konnten nicht aktualisiert werden");
  87. }
  88. }
  89. function neu_anlegen() {
  90. if (!neuer_titel.length) return
  91. try {
  92. const res = $db
  93. .prepare(
  94. `
  95. INSERT INTO medienbezeichnung (name) VALUES (?)
  96. `
  97. )
  98. .run(neuer_titel.trim());
  99. neuer_titel = ''
  100. fehlermeldung = null
  101. zuordnen(res.lastInsertRowid)
  102. } catch (e) {
  103. console.log("Fehler beim Anlegen eines neuen Titels: ", e)
  104. if (e.code = "SQLITE_CONSTRAINT_UNIQUE") {
  105. fehlermeldung = "Dieser Titel existiert bereits"
  106. } else fehlermeldung = "Es ist ein Fehler aufgetreten"
  107. }
  108. }
  109. function zuordnen(medien_id) {
  110. if (!medien_id) return
  111. const res = $db
  112. .prepare(
  113. `
  114. INSERT INTO medienexemplar (barcode, medienbezeichnung_id) VALUES (?,?)
  115. `
  116. )
  117. .run(barcode, medien_id);
  118. registrieren = false;
  119. scan()
  120. }
  121. </script>
  122. <svelte:window on:keydown={handle_keydown} />
  123. {#if barcode_manuell}
  124. <div class="modal is-active">
  125. <div class="modal-background" on:click={()=>barcode_manuell=false}/>
  126. <button class="modal-close is-large" aria-label="close" on:click={()=>barcode_manuell=false}></button>
  127. <div class="modal-content">
  128. <div class="box">
  129. <div class="field">
  130. <div class="control">
  131. <label class="label">
  132. Barcode eingeben
  133. <input
  134. class="input"
  135. type="text"
  136. bind:value={barcode}
  137. use:focus
  138. on:keydown={e => {if (e.key === 'Enter') { barcode_manuell=false; scan()}}} />
  139. </label>
  140. </div>
  141. </div>
  142. </div>
  143. </div>
  144. </div>
  145. {/if}
  146. {#if registrieren}
  147. <div class="modal is-active">
  148. <div class="modal-background" on:click={()=>registrieren=false}/>
  149. <button class="modal-close is-large" aria-label="close" on:click={()=>registrieren=false}></button>
  150. <div class="modal-content">
  151. <div class="box">
  152. Was machen wir mit dem Barcode?
  153. <pre>{barcode}</pre>
  154. <hr />
  155. {#if medium.length}
  156. <label class="label" for="auswahl">Das gehört zu</label>
  157. <div class="field has-addons">
  158. <div class="control is-expanded">
  159. <div class="select is-fullwidth">
  160. <select bind:value={medium_selected} id="auswahl">
  161. <option>– nichts ausgewählt –</option>
  162. {#each medium.sort(sort_by_name) as m}
  163. <option value={m.id}>{m.name}</option>
  164. {/each}
  165. </select>
  166. </div>
  167. </div>
  168. <div class="control">
  169. <button
  170. class="button is-primary"
  171. on:click={() => zuordnen(medium_selected)}>
  172. Titel verwenden
  173. </button>
  174. </div>
  175. </div>
  176. {/if}
  177. <label class="label" for="neuwahl">Neu anlegen unter</label>
  178. <div class="field has-addons">
  179. <div class="control is-expanded">
  180. <input
  181. id="neuwahl"
  182. class="input is-fullwidth" class:is-danger={fehlermeldung}
  183. type="text"
  184. bind:value={neuer_titel}
  185. on:keydown={e => e.key === 'Enter' && neu_anlegen()} />
  186. </div>
  187. <div class="control">
  188. <button
  189. class="button is-primary"
  190. on:click={() => neu_anlegen()}>
  191. Titel anlegen
  192. </button>
  193. </div>
  194. </div>
  195. {#if fehlermeldung}
  196. <div class="notification is-danger">
  197. {fehlermeldung}
  198. </div>
  199. {/if}
  200. </div>
  201. </div>
  202. </div>
  203. {/if}