scan-frame.vue 7.4 KB

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