From e1b028d486713eaf55aaf35fbf334aa568059c0d Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期二, 14 四月 2026 15:46:54 +0800
Subject: [PATCH] 项目复制
---
src/views/h5/faceAuth/components/camera.vue | 263 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 263 insertions(+), 0 deletions(-)
diff --git a/src/views/h5/faceAuth/components/camera.vue b/src/views/h5/faceAuth/components/camera.vue
new file mode 100644
index 0000000..21bec1c
--- /dev/null
+++ b/src/views/h5/faceAuth/components/camera.vue
@@ -0,0 +1,263 @@
+<template>
+ <div ref="cameraBox" class="camera_box" :style="cameraStyle" v-show="isCameraOpening">
+ <video ref="videoEl" :width="videoWidth" :height="videoHeight" autoplay></video>
+ <canvas ref="canvasEl" :width="videoWidth" :height="videoHeight" style="display:none;"></canvas>
+
+ <el-row justify="center" class="btn_box">
+ <el-button plain text @click="closeCamera()">
+ <Icon icon="material-symbols:cancel" width="28" height="28" style="color: #FA5252" />
+ </el-button>
+ <el-button plain text @click="startRecordImage()">
+ <Icon icon="ant-design:camera-filled" width="28" height="28" style="color: #FA5252" />
+ </el-button>
+ </el-row>
+ </div>
+</template>
+
+<script>
+export default {
+ data () {
+ return {
+ recorderOptions: { // recorder 閰嶇疆椤�
+ mimeType: 'video/webm;codecs=vp8,opus'
+ },
+ isCameraOpening: false,
+ }
+ },
+ computed: {
+ videoWidth: function () {
+ return 400
+ },
+ videoHeight: function(){
+ return (this.videoWidth * 3) / 4
+ },
+ cameraStyle: function(){
+ return {
+ width: `${this.videoWidth}px`,
+ height: `${this.videoHeight}px`
+ }
+ },
+ },
+ beforeUnmount(){
+ this.closeCamera()
+ },
+ mounted () {
+ this.initNavigatorMedia()
+ this.openCamera()
+ },
+ methods: {
+ initNavigatorMedia: function(){
+ // 鑾峰彇濯掍綋灞炴�э紝鏃х増鏈祻瑙堝櫒鍙兘涓嶆敮鎸乵ediaDevices锛岃缃竴涓┖瀵硅薄
+ if (navigator.mediaDevices === undefined) {
+ navigator.mediaDevices = {};
+ }
+ // 浣跨敤getUserMedia锛屽洜涓哄畠浼氳鐩栫幇鏈夌殑灞炴�с��
+ // 杩欓噷锛屽鏋滅己灏慻etUserMedia灞炴�э紝灏辨坊鍔犲畠銆�
+ if (navigator.mediaDevices.getUserMedia === undefined) {
+ this.initGetUserMedia()
+ }
+ },
+ initGetUserMedia: function(){
+ navigator.mediaDevices.getUserMedia = (constraints) => {
+ // 棣栧厛鑾峰彇鐜板瓨鐨刧etUserMedia(濡傛灉瀛樺湪)
+ let getUserMedia =
+ navigator.webkitGetUserMedia ||
+ navigator.mozGetUserMedia ||
+ navigator.getUserMedia;
+ // 鏈変簺娴忚鍣ㄤ笉鏀寔锛屼細杩斿洖閿欒淇℃伅
+ // 淇濇寔鎺ュ彛涓�鑷�
+ if (!getUserMedia) {//涓嶅瓨鍦ㄥ垯鎶ラ敊
+ return Promise.reject(
+ new Error("getUserMedia is not implemented in this browser")
+ );
+ }
+ // 鍚﹀垯锛屼娇鐢≒romise灏嗚皟鐢ㄥ寘瑁呭埌鏃х殑navigator.getUserMedia
+ return new Promise((resolve, reject) => {
+ getUserMedia.call(navigator, constraints, resolve, reject);
+ });
+ };
+ },
+ openCamera: function(){ // 鎵撳紑鎽勫儚澶�
+ navigator.mediaDevices.getUserMedia({
+ audio: false,
+ video: {
+ width: this.videoWidth,
+ height: this.videoHeight,
+ }
+ }).then((stream) => {
+ this.isCameraOpening = true
+ this.mediaStream = stream
+ this.initVideoSrcObject()
+ }).catch(err => {
+ console.log(`${err.name}锛�${err.message}`);
+ this.closeCamera()
+ this.mediaErrorHandler(err)
+ });
+ },
+ closeCamera() { // 鍏抽棴鎽勫儚澶�
+ if (!this.isCameraOpening) return false
+
+ this.isCameraOpening = false
+
+ if (this.mediaStream) {
+ let tracks = this.mediaStream.getTracks()
+ tracks.forEach(track => track.stop());
+ }
+
+ if (this.mediaRecorder) this.mediaRecorder.stop();
+ this.$emit('close')
+ },
+ initVideoSrcObject: function(){ // 鍒濆鍖� 瑙嗛褰曞埗 鐨� video srcObject
+ // 鏃х殑娴忚鍣ㄥ彲鑳芥病鏈塻rcObject
+ if ("srcObject" in this.$refs.videoEl) {
+ this.$refs.videoEl.srcObject = this.mediaStream;
+ this.initVideoMoveListener()
+ } else {
+ console.log('娴忚鍣ㄤ笉鏀寔')
+ }
+ },
+ initVideoMoveListener: function(){ // 鍒濆鍖� 瑙嗛绐楀彛 鐨� 绉诲姩浜嬩欢
+ let eventState = {}
+ let startMoving = (e) => { // 寮�濮嬬Щ鍔ㄧ殑鍥炶皟
+ e.preventDefault()
+ e.stopPropagation()
+ eventState = {
+ left: this.$refs.cameraBox.offsetLeft,
+ top: this.$refs.cameraBox.offsetTop,
+ x: e.clientX,
+ y: e.clientY
+ }
+ document.addEventListener('mousemove', moving)
+ document.addEventListener('mouseup', endMoving)
+ }
+ let moving = (e) => { // 绉诲姩鐨勫洖璋�
+ e.preventDefault()
+ e.stopPropagation()
+
+ let margin = 10
+ let left = e.clientX - (eventState.x - eventState.left)
+ let top = e.clientY - (eventState.y - eventState.top)
+ let maxLeft = document.documentElement.clientWidth - this.videoWidth - margin
+ let maxTop = document.documentElement.clientHeight - this.videoHeight - margin
+
+ // 闄愬埗绉诲姩鎴浘鍖哄煙涓嶈兘绉诲埌鍙鍖哄煙澶�
+ if (left < 10) left = margin
+ if (top < 10) top = margin
+ if (left > maxLeft) left = maxLeft
+ if (top > maxTop) top = maxTop
+
+ this.$refs.cameraBox.style.left = `${left}px`
+ this.$refs.cameraBox.style.top = `${top}px`
+ }
+ let endMoving = (e) => { // 缁撴潫绉诲姩鐨勫洖璋�
+ e.preventDefault()
+ document.removeEventListener('mousemove', moving)
+ document.removeEventListener('mouseup', endMoving)
+ }
+ this.$refs.cameraBox.addEventListener('mousedown', startMoving)
+ },
+ initUploadChunk: async function(blobs){ // 鍒濆鍖栦笂浼犱换鍔�
+ let tmpBlob = new Blob(blobs, { 'type': this.recorderOptions.mimeType });
+ // let file = new File(blobs, fileName, { type: 'video/webm' });
+ let file = null
+ try {
+ // 瑙e喅 Webm 瑙嗛 duration 闂
+ file = await fixWebmMetaInfo(tmpBlob)
+ } catch (error) {
+ file = tmpBlob
+ console.log(error)
+ }
+
+ let path = await uploadChunk(file, '瀛︿範瑙嗛', 'webm')
+ if (!path) return false
+
+ if (this.recordingFlag || this.recordCameraFlag) {
+ this.$store.commit('authCamera/recordVideoUrl', path)
+ this.$store.commit('authCamera/faceCaptureAll', { flag: false, imgList: this.faceCaptureAllImgList })
+ } else {
+ this.$store.commit('authCamera/biopsyVideoUrl', path)
+ }
+ },
+ startRecordImage() { // 寮�濮嬪綍鍒跺浘鍍忥紙鎷嶇収锛�
+ if (!this.$refs.canvasEl) return false
+
+ this.drawImage()
+ // this.closeCamera()
+ },
+ drawImage: function(){ // 缁樺埗鍥剧墖
+ this.$refs.canvasEl.getContext('2d').drawImage(
+ this.$refs.videoEl,
+ 0,
+ 0,
+ this.videoWidth,
+ this.videoHeight
+ );
+ this.uploadBase64()
+ },
+ async uploadBase64(){ // 涓婁紶鍥剧墖
+ let base64 = this.$refs.canvasEl.toDataURL("image/png", 1);
+ if (base64) {
+ this.$emit('handlerSuccess', base64)
+ this.closeCamera()
+ } else {
+ this.$message.error('鎷嶆憚澶辫触')
+ }
+ },
+ uploadErrorHandler: function (evt) { // 涓婁紶澶辫触鍥炶皟
+ console.log(JSON.stringify(evt.target))
+ },
+ mediaErrorHandler: function(){ // 寮�鍚憚鍍忓ご鎴栧綍鍒跺睆骞曞紓甯稿鐞�
+ this.$message.error('褰撳墠娴忚鍣ㄤ笉鏀寔锛岃鏇存崲娴忚鍣�')
+ },
+ }
+};
+</script>
+
+<style lang="scss" scoped>
+.camera_box{
+ position: fixed;
+ bottom: 10px;
+ right: 10px;
+ z-index: 300;
+}
+.status_box{
+ position: absolute;
+ left: 0;
+ right: 0;
+ padding: 6px;
+ margin-top: -38px;
+ font-size: 0.8rem;
+ color: white;
+ background: rgba(0,0,0,0.4);
+ .normal > span,
+ .abnormal > span{
+ width: 6px;
+ height: 6px;
+ border-radius: 28px;
+ display: inline-block;
+ margin-right: 5px;
+ }
+ .normal > span{
+ background-color: #00E63C;
+ }
+ .abnormal > span{
+ background-color: #FF3232;
+ }
+}
+.btn_box{
+ background: rgba(0,0,0,0.4);
+ margin-top: -63px;
+ padding-top: 10px;
+ padding-bottom: 7px;
+ position: absolute;
+ left: 0;
+ right: 0;
+}
+.duration{
+ position: absolute;
+ top: 0;
+ right: 0;
+ color: white;
+ text-shadow: 1px 1px 1px black, 1px -1px 1px black, -1px -1px 1px black, -1px 1px 1px black;
+}
+</style>
\ No newline at end of file
--
Gitblit v1.8.0