Scan.vue 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. <template>
  2. <div style="display: flex">
  3. <div style="display: flex">
  4. <span> {{texts['scan_scan_instruction']}}</span>
  5. <div ref="webcam_placeholder" style="height: 80vh; display: flex;
  6. overflow:hidden">
  7. <webcam @ready="camera_ready()" :maxres="500" ref="webcam" :height="webcam_height"/>
  8. </div>
  9. <!--v<img :src="this.img" style="max-height:90vh"/> -->
  10. </div>
  11. <q-field style="display: flex" :label="texts['scan_enter_barcode_manually']">
  12. <q-input type="tel" @focus="onfocus()"
  13. @blur="onblur()" @keyup.enter="on_click_manual_entry()" v-model="manual_result"/>
  14. <q-btn @click="on_click_manual_entry()"> {{ texts['scan_submit'] }} </q-btn>
  15. </q-field>
  16. <q-modal no-esc-dismiss no-backdrop-dismiss minimized v-model="opened">
  17. <div style="padding: 5%">
  18. <div v-if="scanning==2">
  19. <img :src="this.img" style="max-height:30vh"/>
  20. <div ref="result">loading...</div>
  21. <div class="row">
  22. <q-btn @click="close_dialog()">{{texts['scan_back']}}</q-btn>
  23. <q-btn :loading="searching" @click="_continue()" :disabled="!result">{{texts['scan_continue']}}</q-btn>
  24. </div>
  25. </div>
  26. <div v-if="scanning==3">
  27. <q-card v-if="products.length>0">
  28. <span> {{texts['scan_found_text']}}</span>
  29. <div class="row" style="flex-wrap:nowrap; overflow-y: auto; width:300px" >
  30. <template v-for="product in products">
  31. <q-item v-for="picture in product.pictures">
  32. <img :src="api.apiHostname + picture.slice(5)"
  33. style="max-height: 100px">
  34. <q-tooltip>
  35. {{ product.name }}
  36. </q-tooltip>
  37. </img>
  38. </q-item>
  39. </template>
  40. </div>
  41. <div> {{texts['scan_add_new']}} </div>
  42. <div class="row" style="margin:10px">
  43. <q-btn @click="$router.push('/new')"> {{texts['scan_yes']}} </q-btn>
  44. <q-btn @click="$router.push('/home')"> {{texts['scan_no']}} </q-btn>
  45. </div>
  46. </q-card>
  47. <div v-else>
  48. {{texts['scan_no_product_text']}}<br/>
  49. {{ texts['scan_create_new']}}
  50. <div class="row">
  51. <q-btn @click="$router.push('/home')">{{ texts['scan_no']}}</q-btn>
  52. <q-btn @click="create_new()">{{ texts['scan_yes']}}</q-btn>
  53. </div>
  54. </div>
  55. </div>
  56. </div>
  57. </q-modal>
  58. </div>
  59. </template>
  60. <script>
  61. import Webcam from '../components/webcam'
  62. import Quagga from 'quagga'
  63. var api = require('../api.js')
  64. var utils = require('../utils.js')
  65. import {
  66. QCard,
  67. QLayout,
  68. QToolbar,
  69. QToolbarTitle,
  70. QBtn,
  71. QIcon,
  72. QList,
  73. QListHeader,
  74. QItem,
  75. QItemSide,
  76. QItemMain,
  77. QModal,
  78. QModalLayout,
  79. QTooltip,
  80. QInput,
  81. QField
  82. } from 'quasar'
  83. export default {
  84. name: 'index',
  85. components: {
  86. QCard,
  87. QLayout,
  88. QToolbar,
  89. QToolbarTitle,
  90. QBtn,
  91. QIcon,
  92. QList,
  93. QListHeader,
  94. QItem,
  95. QItemSide,
  96. Webcam,
  97. QItemMain,
  98. QModal,
  99. QModalLayout,
  100. QTooltip,
  101. QInput,
  102. QField
  103. },
  104. data () {
  105. return {
  106. products: [],
  107. api: api,
  108. img: null,
  109. quagga: null,
  110. scanning: 2,
  111. opened: false,
  112. result: null,
  113. scan_result: null,
  114. manual_result: '',
  115. texts: '',
  116. scanned: false,
  117. webcam_height: 0,
  118. searching: false,
  119. found: false,
  120. scan_interval: null,
  121. manual_input: false
  122. }
  123. },
  124. methods: {
  125. close_dialog: function () {
  126. this.scanned = false
  127. this.opened = false
  128. },
  129. on_key_pressed: function (key) {
  130. this.on_click_manual_entry()
  131. },
  132. on_click_manual_entry: function () {
  133. var regex = /^[0-9]+$/
  134. if(!this.manual_result.match(regex)) {
  135. this.$q.notify('invalid barcode')
  136. return false
  137. }
  138. this.scanned = true
  139. this.$refs.result.innerText = this.manual_result
  140. this.result = this.manual_result
  141. this.opened = true
  142. this.scanning = 2
  143. },
  144. _continue: function () {
  145. var self = this
  146. self.searching = true
  147. api.get('scanapp/{LANG}/ean_codes/'+self.result + '/')
  148. .then((data) => {
  149. self.products = data.data.products
  150. window.sessionStorage.setItem('barcode_id', data.data.id)
  151. self.scanning = 3
  152. self.found = true
  153. })
  154. .catch(err => {
  155. self.found = false
  156. self.scanning = 3
  157. })
  158. },
  159. create_new: function () {
  160. if (!this.found) {
  161. api.create('scanapp/en-us/ean_codes/', {barcode: this.result})
  162. .then(data => {
  163. window.sessionStorage.setItem('barcode_id', data.data.id)
  164. })
  165. }
  166. this.$router.push('/new')
  167. },
  168. decode: function (img) {
  169. var self = this
  170. Quagga.decodeSingle({
  171. decoder: {
  172. readers: ['ean_reader'] // List of active readers
  173. },
  174. locate: true, // try to locate the barcode in the image
  175. src: img // or 'data:image/jpg;base64,' + data
  176. }, function (result) {
  177. if (!result) {
  178. self.scan_result = null
  179. return null
  180. }
  181. if (result.codeResult) {
  182. self.scanned = true
  183. self.$refs.result.innerText = result.codeResult.code
  184. self.scan_result = result.codeResult.code
  185. self.result = self.scan_result
  186. self.opened = true
  187. self.scanning = 2
  188. }
  189. else {
  190. self.scan_result = null
  191. }
  192. })
  193. },
  194. camera_ready: function () {
  195. // alert(22)
  196. console.log('email increase')
  197. this.scan_interval = window.setInterval(() => {
  198. if(!this.scanned){ // && !this.manual_input) {
  199. var img = this.$refs.webcam.capture()
  200. console.log(33)
  201. this.decode(img)
  202. }
  203. }, 1000)
  204. },
  205. onblur: function () {
  206. this.manual_input = false
  207. this.$refs.webcam.startCapture()
  208. },
  209. onfocus: function () {
  210. this.manual_input = true
  211. this.$refs.webcam.stop()
  212. window.clearInterval(this.scan_interval)
  213. }
  214. },
  215. mounted: function () {
  216. window.c = this
  217. utils.setTexts(this)
  218. var self = this
  219. this.webcam_height = this.$refs.webcam_placeholder.clientHeight
  220. },
  221. beforeDestroy () {
  222. }
  223. }
  224. </script>
  225. <style lang="stylus" scoped>
  226. div
  227. display: flex
  228. flex-direction: column
  229. align-items: center
  230. .row
  231. flex-direction: row
  232. </style>