<template> <el-dialog :visible.sync="dialogFormVisible" :title="titleText" append-to-body> <div> <el-row :gutter="20"> <el-col :span="6"> <el-row> <div class="avatar"> <el-image :src="photo!==''?photo:defaultPhoto" fit="cover" style="width: 130px; height: 175px"/> </div> </el-row> <el-row> <el-upload ref="upload" :before-upload="handleBeforeUpload" :http-request="uploadFile" :show-file-list="false" class="avatar-uploader" action="string" accept=".jpg,.jpeg,.png,.bmp"> <el-button type="primary" class="face-btn">点击上传照片</el-button> </el-upload> </el-row> <el-row> <el-button v-if="!canSnap" type="primary" plain class="face-btn" @click="openCamera">打开摄像头</el-button> <el-button v-else type="primary" plain class="face-btn" @click="setImage">摄像头拍照</el-button> </el-row> </el-col> <el-col :span="18"> <div class="camera_outer"> <video id="videoCamera" :width="videoWidth" :height="videoHeight" autoplay /> <canvas id="canvasCamera" :width="videoWidth" :height="videoHeight" style="display: none" /> </div> </el-col> </el-row> </div> <div slot="footer" class="dialog-footer"> <el-button v-show="canSave" type="primary" @click="saveData">保存</el-button> <el-button @click="cancel">取消</el-button> </div> </el-dialog> </template> <script> import { regFace } from '@/api/system/user' export default { name: 'RegFace', data() { return { userId: '', // 用户id userName: '', // 用户名称 dialogFormVisible: false, // 对话框是否显示 defaultProps: { label: 'name', children: 'children' }, videoWidth: 396, videoHeight: 297, thisCancas: null, thisContext: null, thisVideo: null, canSnap: false, // 是否显示拍照按钮 canSave: false, // 是否可以提交 photo: '', // 图片路径 defaultPhoto: require('@/assets/global_images/photo.png'), // 默认图片路径 btnLoading: false // 保存按钮的加载中状态 } }, computed: { titleText: function() { return this.userName + '' } }, methods: { // 初始化对话框 initDialog: function(dialogFormVisible, row) { this.loading = true this.userId = row.id this.userName = row.name this.dialogFormVisible = dialogFormVisible }, // 图片上传 uploadFile(file) { console.log('uploadFile:' + file.file.name) // 转base64 this.getBase64(file.file).then(resBase64 => { this.photo = 'data:image/png;base64,' + resBase64.split(',')[1] // 直接拿到base64信息 this.canSave = true }) }, getBase64(file) { return new Promise((resolve, reject) => { const reader = new FileReader() let fileResult = '' reader.readAsDataURL(file) // 开始转 reader.onload = function() { fileResult = reader.result } // 转 失败 reader.onerror = function(error) { reject(error) } // 转 结束 咱就 resolve 出去 reader.onloadend = function() { resolve(fileResult) } }) }, // 上传前判断文件格式及大小 handleBeforeUpload(file) { const isJPG = (file.type === 'image/jpeg') || (file.type === 'image/png') || (file.type === 'image/bmp') let res = true console.log(file.size) const isLt2M = file.size / 1024 < 200 if (!isJPG) { this.$message.error('上传图片只能是 JPG 或 PNG 或 BMP 格式!') res = false } if (!isLt2M) { this.$message.error('上传图片大小不能超过 200KB!') res = false } return res }, openCamera() { // 打开摄像头 const _this = this this.thisCancas = document.getElementById('canvasCamera') this.thisContext = this.thisCancas.getContext('2d') this.thisVideo = document.getElementById('videoCamera') // 旧版本浏览器可能根本不支持mediaDevices,我们首先设置一个空对象 if (navigator.mediaDevices === undefined) { navigator.mediaDevices = {} } // 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象 // 使用getUserMedia,因为它会覆盖现有的属性。 // 这里,如果缺少getUserMedia属性,就添加它。 if (navigator.mediaDevices.getUserMedia === undefined) { navigator.mediaDevices.getUserMedia = function(constraints) { // 首先获取现存的getUserMedia(如果存在) const getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.getUserMedia // 有些浏览器不支持,会返回错误信息 // 保持接口一致 if (!getUserMedia) { return Promise.reject( new Error('getUserMedia is not implemented in this browser') ) } // 否则,使用Promise将调用包装到旧的navigator.getUserMedia return new Promise(function(resolve, reject) { getUserMedia.call(navigator, constraints, resolve, reject) }) } } const constraints = { audio: false, video: { width: this.videoWidth, height: this.videoHeight } } navigator.mediaDevices .getUserMedia(constraints) .then(function(stream) { // 旧的浏览器可能没有srcObject if ('srcObject' in _this.thisVideo) { _this.thisVideo.srcObject = stream } else { // 避免在新的浏览器中使用它,因为它正在被弃用。 _this.thisVideo.src = window.URL.createObjectURL(stream) } _this.thisVideo.onloadedmetadata = function(e) { _this.thisVideo.play() } }) .catch((err) => { console.log(err) }) this.canSnap = true }, // 绘制图片(拍照功能) setImage() { const _this = this // 点击,canvas画图 _this.thisContext.drawImage( _this.thisVideo, 0, 0, _this.videoWidth, _this.videoHeight ) // 获取图片base64链接 const image = this.thisCancas.toDataURL('image/png') this.photo = image this.canSave = true // 关闭摄像头并将按钮复位 this.canSnap = false this.stopNavigator() }, // 关闭摄像头 stopNavigator() { this.thisVideo.srcObject.getTracks()[0].stop() }, // 保存数据 saveData: function() { this.btnLoading = true regFace({ userId: this.userId, image: this.photo }).then(response => { console.log(response) if (response.code === 200) { this.$message.success('人脸注册成功') this.btnLoading = false this.$emit('watchChild') this.dialogFormVisible = false } }) }, // 点击取消 cancel() { this.dialogFormVisible = false this.$emit('watchChild') } } } </script> <style lang="scss" scoped> .camera_outer { position: relative; overflow: hidden; background-size: 100%; border: 2px solid #007eff; width: 400px; height: 301px; } .avatar-uploader .el-upload { margin-left: 12px; margin-top: 10px; cursor: pointer; position: relative; overflow: hidden; } .avatar-uploader .el-upload:hover { border-color: #409EFF; } .avatar-uploader-icon { font-size: 28px; color: #8c939d; width: 178px; height: 238px; line-height: 238px; text-align: center; } .avatar { margin: 0px 10px; display: block; } .face-btn { width:126px; margin-left: 10px; margin-top: 20px; } </style>