_index.vue 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. <script setup>
  2. import { Html5QrcodeScanner, Html5Qrcode, Html5QrcodeSupportedFormats, Html5QrcodeScanType } from 'html5-qrcode'
  3. const router = useRouter()
  4. definePageMeta({
  5. layout: 'scan'
  6. })
  7. let scanInstance = null; // 扫码实例
  8. let results = ref(null); // 扫码结果
  9. const initScanInstance = () => {
  10. if (!scanInstance) {
  11. // reader放置扫码功能的元素ID
  12. scanInstance = new Html5Qrcode('qr-reader', {
  13. formatsToSupport: [
  14. Html5QrcodeSupportedFormats.QR_CODE,
  15. ],
  16. })
  17. }
  18. }
  19. const openQrcode = async () => {
  20. Html5Qrcode.getCameras()
  21. .then(devices => {
  22. if (devices && devices.length) {// 当前环境下能识别出摄像头,并且摄像头的数据可能不止一个
  23. initScanInstance()
  24. scanInstance.start(
  25. {facingMode: "environment"},
  26. {
  27. focusMode: 'continuous',
  28. fps: 10, // 可选,每n秒帧扫描一次
  29. qrbox: { // 扫描的UI框
  30. width: 250,
  31. height: 250
  32. },
  33. videoConstraints: {
  34. // width: 375,
  35. // height: (window.visualViewport.height - 50),
  36. aspectRatio: window.visualViewport.height / window.visualViewport.width,
  37. facingMode: "environment",
  38. }
  39. },
  40. (decodedText, decodedResult) => {
  41. showToast('识别成功')
  42. handleSuccess({decodedText, decodedResult})
  43. },
  44. (errorMessage, error) => {
  45. handleFail(errorMessage)
  46. }
  47. )
  48. }
  49. })
  50. .catch((err) => {
  51. // 错误信息处理仅供参考,具体情况看输出!!!
  52. let errorStr = ''
  53. if (typeof err === "string") {
  54. errorStr = err
  55. } else {
  56. if (err.name === "NotAllowedError")
  57. errorStr = "您需要授予相机访问权限"
  58. if (err.name === "NotFoundError") {
  59. errorStr = "未检测到摄像头"
  60. }
  61. if (err.name === "NotSupportedError")
  62. errorStr = "摄像头访问只支持在安全的上下文中,如https或localhost"
  63. if (err.name === "NotReadableError") errorStr = "摄像头被占用"
  64. if (err.name === "OverconstrainedError")
  65. errorStr = "安装摄像头不合适"
  66. if (err.name === "StreamApiNotSupportedError")
  67. errorStr = "此浏览器不支持流API"
  68. }
  69. showToast(errorStr)
  70. })
  71. }
  72. const scanLoadImg = (e) => {
  73. try {
  74. initScanInstance()
  75. scanInstance.scanFile(e.file, false)
  76. .then(result => {
  77. // 二维码结果
  78. console.log(result, '上传扫码成功')
  79. handleSuccess(result)
  80. })
  81. .catch(err => {
  82. handleFail(err)
  83. })
  84. } catch (e) {
  85. console.error(e, '失败')
  86. }
  87. }
  88. const getResults = (result) => {
  89. if (!result) {
  90. return {success: false, groupId: null, overTime: false}
  91. }
  92. const url = new URL(result);
  93. const urlParams = new URLSearchParams(url.search);
  94. const hasGroupId = urlParams.has('groupId');
  95. const hasTime = urlParams.has('time');
  96. console.log(url.search, hasGroupId, hasTime, 'hasTime')
  97. if (!hasGroupId || !hasTime) {
  98. return {success: false, groupId: null, overTime: false}
  99. }
  100. const givenDate = new Date(urlParams.get('time'));
  101. const currentDate = new Date();
  102. const givenDateCst = new Date(givenDate.getTime() + (8 * 60 * 60 * 1000));
  103. const currentDateCst = new Date(currentDate.getTime() + (8 * 60 * 60 * 1000));
  104. const diffInMilliseconds = currentDateCst - givenDateCst;
  105. const sevenDaysInMilliseconds = 7 * 24 * 60 * 60 * 1000;
  106. return {
  107. success: true,
  108. groupId: urlParams.get('groupId'),
  109. overTime: diffInMilliseconds > sevenDaysInMilliseconds
  110. }
  111. }
  112. const handleSuccess = (result) => {
  113. results.value = result
  114. router.replace({
  115. path: '/chat/qr-results',
  116. query: result ? getResults(result) : result
  117. })
  118. }
  119. const handleFail = (err) => {
  120. alert(err)
  121. /* router.replace({
  122. path: '/chat/qr-results',
  123. query: {success: false, groupId: null, overTime: false}
  124. })*/
  125. }
  126. const closeQrcode = () => {
  127. if (scanInstance && scanInstance.isScanning) scanInstance.stop()
  128. router.back()
  129. }
  130. onMounted(async () => {
  131. await nextTick()
  132. // initScanInstance()
  133. await openQrcode()
  134. })
  135. onUnmounted(() => {
  136. if (scanInstance && scanInstance.isScanning) scanInstance.stop()
  137. })
  138. </script>
  139. <template>
  140. <div>
  141. <div v-if="false" class="h-200">
  142. {{ results }}
  143. </div>
  144. <div class="overlay">
  145. <div class="absolute w-full z-30 flex flex-row items-center justify-center p-12">
  146. <div class="absolute left-12 font-bold" @click="closeQrcode">
  147. <span class="iconfont icon-left text-white"></span>
  148. </div>
  149. <div class="text-base text-[#fff] font-bold">
  150. 扫描二维码
  151. </div>
  152. </div>
  153. <div class="relative qr-reader z-20" id="qr-reader"></div>
  154. <p class="absolute w-full p-12 text-center bottom-100 z-30 text-sm text-[#fff]">请将二维码对准扫码框中心</p>
  155. <div id="qr-code-file"
  156. class="absolute w-54 h-54 grid place-items-center bottom-40 z-30 rounded-full bg-[#000]/80 text-white left-1/2 -translate-x-1/2">
  157. <van-uploader
  158. :preview-image="false"
  159. :after-read="scanLoadImg"
  160. accept="image/*"
  161. :multiple="false"
  162. :max-count="1"
  163. ><img src="~/assets/img/scan/pic.png" height="32" width="32" alt=""/>
  164. </van-uploader>
  165. </div>
  166. </div>
  167. </div>
  168. </template>
  169. <style scoped lang="scss">
  170. .overlay {
  171. position: fixed;
  172. bottom: 0;
  173. left: 0;
  174. z-index: 999999;
  175. width: 100%;
  176. height: 100%;
  177. background: rgba(0, 0, 0, 0.7);
  178. }
  179. </style>