scan-frame.vue 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. <template>
  2. <view class="cameraBg">
  3. <!-- position: absolute;left: 100000px; 隐藏canvas画布 -->
  4. <canvas style="width: 100%; height: 100vh;position: absolute;left: 100000px;" canvas-id="canvas" id="canvas"></canvas>
  5. <!-- 相机组件 -->
  6. <camera device-position="back" flash="auto" style="width: 100%; height: 100vh">
  7. <cover-image src="@/static/scan-frame/cameraBg.png" class="cover-img"> </cover-image>
  8. <cover-view class="scanBtn" v-if="scanShow">
  9. <cover-view class="beat" @click="scan">
  10. <cover-image class="beatImg" src="@/static/scan-frame/album.png"></cover-image>
  11. <cover-view> 相册 </cover-view>
  12. </cover-view>
  13. <cover-view class="album" @click="takePhoto">
  14. <cover-image class="albumImg" src="@/static/scan-frame/beat.png"></cover-image>
  15. <cover-view> 拍照 </cover-view>
  16. </cover-view>
  17. <cover-view class="inputs" @click="inputs">
  18. <cover-image class="beatImg" src="@/static/scan-frame/inputs.png"></cover-image>
  19. <cover-view> 手动输入 </cover-view>
  20. </cover-view>
  21. </cover-view>
  22. </camera>
  23. </view>
  24. </template>
  25. <script>
  26. import { vinCode } from '@/api/car.js'
  27. export default {
  28. data() {
  29. return {
  30. scanShow: true, // 显示操作按钮
  31. sysinfo: null, // 设备信息
  32. imageInfo: null // 拍照图片信息
  33. }
  34. },
  35. onReady() {
  36. const sysinfo = uni.getSystemInfoSync()
  37. this.sysinfo = sysinfo
  38. },
  39. onLoad() {
  40. uni.getSetting({
  41. success(res) {
  42. console.log(res.authSetting['scope.camera'])
  43. if(!res.authSetting['scope.camera']){
  44. uni.showModal({
  45. title: '您未开启摄像机权限',
  46. content: '请点击右上角,然后在设置里面开启。',
  47. success: (ret) => {
  48. if(ret.confirm){
  49. uni.openSetting({
  50. success(res) {
  51. console.log(res.authSetting)
  52. }
  53. })
  54. }
  55. }
  56. })
  57. }
  58. }
  59. })
  60. },
  61. methods: {
  62. // 手动输入
  63. inputs(){
  64. uni.redirectTo({
  65. url: "/pages/vinInput/confirmVin?verifyCode="
  66. })
  67. },
  68. // 相册
  69. scan() {
  70. // 选择图片
  71. uni.chooseImage({
  72. count: 1,
  73. sizeType: ['original', 'compressed'],
  74. sourceType: ['album'],
  75. success: (res) => {
  76. this.compress(res.tempFilePaths[0],false)
  77. }
  78. })
  79. },
  80. delImgs(filePath){
  81. // #ifdef MP-WEIXIN
  82. const fs = wx.getFileSystemManager();
  83. try {
  84. const res = fs.unlinkSync(filePath)
  85. console.log(res)
  86. } catch(e) {
  87. console.error(e)
  88. }
  89. // #endif
  90. },
  91. // 裁剪图片
  92. cutImg(fileUrl){
  93. const vm = this
  94. const ctx = uni.createCanvasContext('canvas')
  95. // 将拍照的图片绘制到canvas,宽高等于窗口宽高和手机窗口保持一致
  96. ctx.drawImage(fileUrl,0,0,this.sysinfo.windowWidth,this.sysinfo.windowHeight)
  97. ctx.draw(true,()=>{
  98. const cutW = 650 // 裁剪框宽度
  99. const cutH = 160 // 裁剪框高度
  100. const cutT = 400 // 裁剪框距离顶部距离
  101. const cutL = 50 // 裁剪框距离左侧距离
  102. // 以上裁剪框宽高及坐标是相对于实际蒙板图片的位置
  103. const canvasW=cutW/750*this.sysinfo.windowWidth; // canvas 画布实际宽度
  104. const canvasH=cutH/1624*this.sysinfo.windowHeight; // canvas 画布实际高度
  105. const canvasL =cutL/750*this.sysinfo.windowWidth; // canvas 画布开始坐标x
  106. const canvasT= cutT/1624*this.sysinfo.windowHeight; // canvas 画布开始坐标y
  107. // 开始裁剪
  108. uni.canvasToTempFilePath({
  109. x: canvasL,
  110. y: canvasT,
  111. width: canvasW,
  112. height: canvasH,
  113. canvasId: 'canvas',
  114. success: function(res) {
  115. // 在H5平台下,tempFilePath 为 base64
  116. vm.parseImgs(res.tempFilePath)
  117. // 删除临时文件
  118. // vm.delImgs(fileUrl)
  119. }
  120. })
  121. })
  122. },
  123. // 启动图片压缩
  124. compress(tempFilePaths,isCut) {
  125. const vm = this
  126. vm.scanShow = false
  127. uni.showLoading({
  128. title: '智能识别中...'
  129. })
  130. uni.compressImage({
  131. src: tempFilePaths,
  132. quality: 100,
  133. success: (imageRes) => {
  134. // 获取类型
  135. uni.getImageInfo({
  136. src: imageRes.tempFilePath,
  137. success(imageInfo) {
  138. console.log(imageInfo)
  139. vm.imageInfo = imageInfo
  140. if(isCut){
  141. // 裁剪图片
  142. vm.cutImg(imageRes.tempFilePath)
  143. }else{
  144. // 相册选择的图片直接解析,这里如果需要裁剪可以跳转到裁剪图片页面在继续下一步
  145. vm.parseImgs(imageRes.tempFilePath)
  146. }
  147. }
  148. })
  149. }
  150. })
  151. },
  152. // 拿到图片转base64后在开始进行识别
  153. parseImgs(filePath) {
  154. // 图片转base64格式
  155. uni.getFileSystemManager().readFile({
  156. filePath: filePath,
  157. encoding: 'base64',
  158. success: (base) => {
  159. // 拿到base64,不需要base64 就把上层的转换去掉
  160. this.scanShow = true
  161. // 此处为后端接口 传base64图片 进行ocr识别
  162. this.parseVinNo(base.data)
  163. },
  164. fail: (err) => {
  165. uni.hideLoading()
  166. console.log(err)
  167. }
  168. })
  169. },
  170. // 点击开始拍照
  171. takePhoto() {
  172. // 获取相机上下文对象
  173. const ctx = uni.createCameraContext()
  174. ctx.takePhoto({
  175. quality: 'high',
  176. success: (res) => {
  177. this.compress(res.tempImagePath,true)
  178. }
  179. })
  180. },
  181. // 识别vin
  182. parseVinNo(data) {
  183. const _this = this
  184. const base64Str = 'data:image/' + this.imageInfo.type + ';base64,' + data
  185. vinCode({
  186. imageByte: data
  187. }).then(res => {
  188. console.log(res, '识别VIN')
  189. if(res.status == 200){
  190. uni.redirectTo({
  191. url: "/pages/vinInput/confirmVin?verifyCode=123456ads11234567&filePath="+base64Str + "&verifyCode="+res.data
  192. })
  193. }else{
  194. uni.showToast({
  195. icon: 'none',
  196. title: res.message
  197. })
  198. }
  199. uni.hideLoading()
  200. }).catch(err => {
  201. uni.hideLoading()
  202. uni.showToast({
  203. icon: 'none',
  204. title: '系统错误或超时,请重试'
  205. })
  206. })
  207. },
  208. error(e) {
  209. console.log(e.detail)
  210. }
  211. }
  212. }
  213. </script>
  214. <style lang="scss" scoped>
  215. .cameraBg {
  216. width: 100%;
  217. height: 100vh;
  218. position: fixed;
  219. .cover-img {
  220. width: 100%;
  221. height: 100vh;
  222. z-index: 1;
  223. }
  224. .scanBtn {
  225. width: 100%;
  226. z-index: 99999;
  227. position: fixed;
  228. bottom: 100rpx;
  229. display: flex;
  230. flex-direction: column;
  231. justify-content: center;
  232. align-items: center;
  233. .beat {
  234. position: absolute;
  235. bottom: 0rpx;
  236. left: 100rpx;
  237. display: flex;
  238. flex-direction: column;
  239. justify-content: center;
  240. align-items: center;
  241. font-size: 24rpx;
  242. font-weight: 400;
  243. color: #ffffff;
  244. .beatImg {
  245. width: 88rpx;
  246. height: 88rpx;
  247. margin-bottom: 30rpx;
  248. }
  249. }
  250. .inputs{
  251. position: absolute;
  252. bottom: 0rpx;
  253. right: 100rpx;
  254. display: flex;
  255. flex-direction: column;
  256. justify-content: center;
  257. align-items: center;
  258. font-size: 24rpx;
  259. font-weight: 400;
  260. color: #ffffff;
  261. .beatImg {
  262. width: 88rpx;
  263. height: 88rpx;
  264. margin-bottom: 30rpx;
  265. }
  266. }
  267. .album {
  268. display: flex;
  269. flex-direction: column;
  270. justify-content: center;
  271. align-items: center;
  272. font-size: 24rpx;
  273. font-weight: 400;
  274. color: #ffffff;
  275. .albumImg {
  276. width: 120rpx;
  277. height: 120rpx;
  278. margin-bottom: 30rpx;
  279. }
  280. }
  281. }
  282. }
  283. </style>