List.vue
<template>
<!--人像采集-->
<div class="typt-list-container">
<div>人像采集</div>
<img v-if="image" :src="image" class="border" style="width: 200px;height: 200px;"/>
<el-button @click="openCamera">打开摄像头</el-button>
<el-dialog :visible.sync="cameraVisible"
class="passport-imgDialog"
:before-close="closeCamera"
width="800px"
:show-close="true"
style="padding: 0;"
title="人像采集"
:close-on-click-modal="false">
<div style="height: 400px;text-align: center;" v-if="cameraHack">
<Photograph :image="image"
:statusInfo="statusInfo"
@getPhoto="getPhoto"></Photograph>
</div>
</el-dialog>
</div>
</template>
<script>
import gateCamera from '../../../assets/acms/mixins/gateCamera/index.js'
import Photograph from '../../../components/acms/Photograph'
import { MsgShow } from '../../../assets/acms/js/Message'
export default {
components: {
Photograph
},
mixins: [gateCamera],
data () {
return {
cameraVisible: false,
cameraHack: false,
image: '', // 传递图像数据
statusInfo: { // 状态显示
status: '', // loading | fail
msg: ''
}
}
},
props: ['params', 'modifyData', 'pageData', 'searchData'],
mounted () {
},
methods: {
// 获取拍照图像
getPhoto ({ formdata, base64 }) {
MsgShow('success', '获取中......', 2000)
// 上传中
this.statusInfo.status = 'loading'
this.statusInfo.msg = '上传中'
// 上传成功
setTimeout(() => {
MsgShow('success', '人像采集成功', 2000)
this.statusInfo.status = ''
this.statusInfo.msg = ''
this.image = base64
this.closeCamera()
}, 2000)
},
// 打开摄像头
openCamera () {
this.cameraHack = false
this.cameraVisible = false
this.$nextTick(() => {
this.cameraHack = true
this.cameraVisible = true
})
},
// 关闭拍照弹窗
closeCamera () {
this.cameraHack = false
this.cameraVisible = false
}
}
}
</script>
Photograph.vue
<template>
<div id="Photograph">
<div class="ptoContainer">
<video id="video" class="video" width="320" autoplay="autoplay"></video>
<div :style="{backgroundImage: `url(${image})`}"
class="headImage"
v-if="image"
v-show="!cameraStatus"></div>
<!-- 图片获取状态 -->
<div class="photoViewStatus" v-show="photoAlertStatus || statusInfo.status !== ''">
<div class="Loading">
<!-- <img src="./loading.png"-->
<img src="/static/acms/img/default.png"
class="loader"
v-show="statusInfo.status === 'loading'"/>
<!-- <img src="./success.png"-->
<img src="/static/acms/img/default.png"
class="loaderNoAni"
v-show="statusInfo.status === 'success'"/>
</div>
<p>{{statusInfo.msg}}</p>
</div>
</div>
<div class="btnBox">
<!-- 拍照按钮 -->
<button class="btn" v-if="!cameraStatus" @click="connectCameraFn">拍照</button>
<button class="btn" v-else @click="takePhotoFn">确认</button>
</div>
</div>
</template>
<script>
import MyLib from './MyLib.js'
import { ResultMsg } from '../../../assets/acms/js/Message'
export default {
name: '',
props: {
image: {
type: String,
default: ''
},
statusInfo: {
type: Object,
// eslint-disable-next-line vue/require-valid-default-prop
default: {
status: '', // loading | success
msg: ''
}
}
},
data () {
return {
cameraStatus: false, // 拍照状态, true => 开启;false => 关闭
photo: '',
photoAlertStatus: false, // 图像提示文案显示状态 true => 显示;false => 隐藏
getStatus: true // true => loading状态, false => 失败状态
}
},
computed: {
// 浏览器类型/版本(控制摄像头video区域大小),在部分浏览器获取的摄像头拍照区域为长方形,所以需要判断浏览器,当前低版本的 safari 和 uc 会是长方形区域
systemCameraVideo () {
let system = MyLib.judgeBrowser()
let v = parseInt(system.version.replace(/\./g, ''))
if (system.browser === 'chrome' || (system.browser === 'safari' && v >= 1211)) {
return true
} else {
return false
}
}
},
methods: {
// 连接摄像头
connectCameraFn () {
this.photoAlertStatus = false // 关闭提示框
// 区域控制
let obj = {}
if (this.systemCameraVideo) {
obj = { width: 320, height: 320 }
} else {
obj = { width: 320 }
}
// end
let constraints = {
video: obj,
audio: false
}
const video = document.getElementById('video')
// 当前在IE浏览器无法调用摄像头
try {
let Promise = navigator.mediaDevices.getUserMedia(constraints)
Promise.then(MediaStream => {
video.srcObject = MediaStream
window.MediaStreamTrack = MediaStream.getTracks()[0] // 摄像头对象
video.play()
this.cameraStatus = true
})
} catch (err) {
ResultMsg('error', '浏览器不支持调用摄像头,请更换最新的谷歌浏览器,或者其他最新版')
}
},
// 绘制照片
takePhotoFn () {
let video = document.getElementById('video')
let canvas = document.createElement('canvas')
canvas.width = canvas.height = 320
let ctx = canvas.getContext('2d')
let w = video.offsetWidth
let h = video.offsetHeight
let y = (canvas.width - h) / 2
// 区域控制
if (this.systemCameraVideo) {
y = 0
}
// end
ctx.drawImage(video, 0, y, w, h)
let base64 = canvas.toDataURL('image/jpeg', 0.4)
this.photo = base64
// base64 => FormData
let Blob = MyLib.convertBase64UrlToBlob(base64)
let formData = new FormData()
formData.append('file', Blob)
this.$emit('getPhoto', { formData: this.photo, base64: base64 })
console.log(base64)
// 关闭
this.cameraStatus = false // 修改摄像头启动状态
window.MediaStreamTrack &&
window.MediaStreamTrack.stop &&
window.MediaStreamTrack.stop() // 关闭摄像头
this.deviceInfoStatus = false
// end
}
}
}
</script>
MyLib.js
const MyLib = {
// base64转blob
convertBase64UrlToBlob (urlData) {
let arr = urlData.split(',')
let mime = arr[0].match(/:(.*?);/)[1]
let bstr = atob(arr[1])
let n = bstr.length
let u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new Blob([u8arr], { type: mime })
},
// 浏览器类型判断及版本
judgeBrowser () {
// 获取IE浏览器版本
function getIeVersion () {
let IEMode = document.documentMode
let rMsie = /(msie\s|trident.*rv:)([\w.]+)/
let ma = navigator.userAgent.toLowerCase()
let match = rMsie.exec(ma)
try {
return match[2]
} catch (e) {
return IEMode
}
}
let System = {}
let ua = navigator.userAgent.toLowerCase()
if (ua.match(/msie/) != null || ua.match(/trident/) != null) {
System.browser = 'IE'
System.version = getIeVersion()
} else if (ua.indexOf('ubrowser') > -1) {
System.browser = 'uc'
System.version = ''
} else {
let re = /(msie|firefox|chrome|opera|version).*?([\d.]+)/
let m = ua.match(re)
System.browser = m[1].replace(/version/, 'safari')
System.version = m[2]
}
return System
}
}
export default MyLib