uniapp 小程序 身份证 和人脸视频拍摄

news2024/11/17 9:50:20

 使用前提:

    已经在微信公众平台的用户隐私协议,已经选择配置“摄像头,录像”等权限

开发背景:客户需要使用带有拍摄边框的摄像头 ,微信小程序的方法无法支持,使用camera修改

   身份证正反面:

<template>
  <view :style="{ height: windowHeight + 'px' }">
    <camera
      mode="normal"
      :device-position="devicePosition"
      flash="off"
      :style="{ height: cameraHeight + 'px' }"
    >
      <cover-view class="controls" style="width: 100%;height: 100%;">
        <!-- 国徽面 -->
        <cover-image
          v-show="!idcardFrontSide"
          class="w569-h828"
          src="/static/images/index/camera_module_side.png"
        />
      </cover-view>
			<!-- 国徽面 -->
			  <cover-image
			    v-show="!idcardFrontSide"
			    class="w569-h828"
			    src="/static/images/index/camera_module_side.png"
			  />
			</cover-view>
    </camera>
    <view class="bottom font-36-fff">
      <view class="wrap">
        <view class="back" @click="switchBtn">切换</view>
        <view @click="takePhoto">
          <image class="w131-h131" src="/static/images/index/take_camera_btn_icon.png">
          </image>
        </view>
        <view @click="chooseImage">
          相册
        </view>
      </view>
    </view>
  </view>
</template>

<script>
  export default {
    data() {
      return {
        cameraContext: {},
        windowHeight: '',
				cameraHeight: '',
        idcardFrontSide: true,
        devicePosition: 'front',
      };
    },
    onLoad(options) {
      if(uni.createCameraContext) {
        this.cameraContext = uni.createCameraContext()
      }else {
        // 如果希望用户在最新版本的客户端上体验您的小程序,可以这样子提示
        uni.showModal({
            title: '提示',
            content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。'
        })
      }
    },
    onShow() {
      const systemInfo = uni.getSystemInfoSync()
      this.windowHeight = systemInfo.windowHeight
      this.cameraHeight = systemInfo.windowHeight - 80
    },
    methods: {
      // 拍照
      takePhoto() {
        uni.showLoading({
          title:'拍摄中'
        })
        this.cameraContext.takePhoto({
          quality: 'high',
          success: (res) => {
            uni.showToast({
              title:'拍照成功',
              icon: 'none',
              duration: 1200
            })
          },
          fail: (err) => {
            uni.showToast({
              title:'拍照失败,请检查系统是否授权',
              icon: 'none',
              duration: 1200
            })
          }
        })
      },
      // 从相册选取
      chooseImage() {
        uni.chooseImage({
          count: 1,
          sizeType: ['original', 'compressed'],
          sourceType: ['album'],
          success: (res) =>  {},
          fail: (err) => {}
        });
      },
     },
		 // 切换摄像头
     switchBtn() {
				if(this.devicePosition === 'back') {
					this.devicePosition = 'front'
				} else {
					this.devicePosition = 'back'
				}
			},
  }
</script>

<style lang="less" scoped>
  .icon-w569-h828 {
    width: 569rpx;
    height: 828rpx;
  }

  .controls {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .bottom {
    width: 100%;
    background-color: #000;

    .wrap {
      display: flex;
      align-items: center;
      justify-content: space-between;
      height: 80px;
      padding: 0 73rpx;
    }
  }

  .w569-h828 {
    width: 569rpx;
    height: 828rpx;
  }
  
  .w131-h131 {
    width: 131rpx;
    height: 131rpx;
  }

  .font-36-fff {
    font-size: 36rpx;
    color: #fff;
  }
</style>

人脸视频:

<template>
	<!-- 第三步上传视频 -->
	<view class="container background-color-474747" :style="{height: windowHeight + 'px'}">
		<view class="video-wrap wpercent-100 text-align" :style="{height: takeVideoHeight + 'px'}" v-if="tipShow">
			<view class="content-wrap">
				<view class="font-36-fff font-weight">请保持声音清晰,话术完整,露出五官</view>
				<view class="padding-top-20 font-36-fff font-weight">不符合以上要求,需重新拍摄</view>
				<view class="padding-top-35 padding-bottom-30 font-24-FF2323 font-weight">点击下方按钮开始拍摄</view>
				<image class="tips-icon" src="/static/images/index/take_video_tips.png"></image>
				<text class="know" @click="startCenterCountDown">知道了</text>
			</view>
		</view>
		<view class="video-wrap wpercent-100" v-if="cameraShow" >
			<view v-if="!centerCountDownShow" class="number">{{ second }}s</view>
			<camera 
				mode="normal"
				class="wpercent-100"
				:device-position="devicePosition" 
				:style="{height: takeVideoHeight + 'px'}">
				<!-- 中间3,2,1倒计时 -->
				<cover-view class="center-count-down-wrap" v-if="centerCountDownShow && centerCountDownValue != 4">
					<cover-view :class="centerCountDownValue === '开始' ? 'center-count-down-start' : 'center-count-down'">{{ centerCountDownValue }}</cover-view>
				</cover-view>
				<!-- 正式拍照人面框 -->
				<cover-image v-if="!centerCountDownShow" class="controls" src="/static/images/index/take_video_back.png"/>
				<cover-view class="font-36-fff font-weight absolute-one-font" v-if="!centerCountDownShow">
					正视镜头录制一段匀速朗读下方数字的视频
				</cover-view>
				<cover-view class="font-36-fff font-weight absolute-two-font" v-if="!centerCountDownShow">
					1234
				</cover-view>
			</camera>
		</view>
		<transition name="fade" :duration="{ enter: 500, leave: 800 }">
			<view class="bottom" v-if="showBottom">
				<view class="wrap">
					<view class="back" @click="backTwoStep">
						<image class="w55-h49" src="/static/images/index/back_before_icon.png"></image>
					</view>
					<!-- 开始倒计时 -->
					<view class="take" @click="startCenterCountDown" v-if="tipShow">		
						<image class="w100-h100" src="/static/images/index/take_btn_icon.png"></image>
					</view>
					<!-- 点击就暂停 -->
					<view class="take" @click="stopRecord" v-if="cameraShow && !centerCountDownShow">
						<image class="w100-h100" src="/static/images/index/take_btn_icon.png"></image>
					</view>
					<view class="switch" @click="switchCamera">
						<image class="w69-h56" src="/static/images/index/switch_camera_icon.png"></image>
					</view>
				</view>
			</view>
		</transition>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				windowHeight: '',
				takeVideoHeight: '',
				tipShow: true,
				showBottom: true,
				centerCountDownShow: false,
				cameraShow: false,
				centerCountDownValue: 4,
				cameraContext: {},
				devicePosition: 'front',
				second: 9,
				setTimer: '',
			};
		},
		onLoad() {
			if(uni.createCameraContext) {
				setTimeout(() => {
					this.cameraContext = uni.createCameraContext();
				},200)
			}else {
				// 如果希望用户在最新版本的客户端上体验您的小程序,可以这样子提示
				uni.showModal({
					title: '提示',
					content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。'
				})
			}
		},
		created() {
			const systemInfo = uni.getSystemInfoSync()
      this.windowHeight = systemInfo.windowHeight
			this.computedHeight(80)
		},
		methods: {
			// 计算height
			computedHeight (number) {
        const systemInfo = uni.getSystemInfoSync()
				this.takeVideoHeight = systemInfo.windowHeight - number
			},
			// 开始倒计时 3,2,1,开始
			startCenterCountDown () {
				this.computedHeight(0)
				this.setBoolean(false)
				this.centerCountDown()
			},
			// 中间倒计时
			centerCountDown() {
				let promise = new Promise((resolve, reject) => {
					let setTimer = setInterval(() => {
						if(this.centerCountDownValue === 1) {
							this.centerCountDownValue = '开始'
							resolve(setTimer)
						} else {
							this.centerCountDownValue = this.centerCountDownValue - 1
						}
						if(this.centerCountDownValue === 2) {			// this.cameraContext.startRecord 有延迟执行的问题,所以需要提前半秒执行
							setTimeout(() => {
								this.startRecord()
							}, 1200)
						}
					}, 1000)
				})
				promise.then((setTimer) => {
					clearInterval(setTimer)
					this.computedHeight(80)
					this.showBottom = true
					this.centerCountDownShow = false
				})
			},
			// 开始录像
			startRecord() {
				this.cameraContext.startRecord({
					success: (res) => {
						this.rightTopCountDown()
					},
					fail: (err) => {
						uni.showToast({
							title: '录像失败,请重试',
							icon: 'none',
							duration: 1200
						})
					}
				})
			},
			// 右上角倒计时
			rightTopCountDown() {
				let promise = new Promise((resolve, reject) => {
					this.setTimer = setInterval(() => {
						this.second = this.second - 1
						if (this.second <= 0) {
							this.stopRecord()
							resolve(this.setTimer)
						}
					}, 1000)
				})
				promise.then((setTimer) => {
					clearInterval(setTimer)
					this.second = 9
				})
			},
			// 结束录像
			stopRecord() {
				uni.showToast({
					title: '结束录像,正在处理视频',
					icon: 'none',
					duration: 10000
				})
				clearInterval(this.setTimer)
				this.second = 9
				this.showBottom = false
				this.computedHeight(0)
			    this.cameraContext.stopRecord({
					compressed: true,
					success: (res) => {
						uni.setStorageSync('taxCollectVideoPath',res.tempVideoPath)
						setTimeout(() => {
							this.stopRecordInitData()
						}, 500)
					},
					fail: (err) => {
						this.showBottom = true
						this.computedHeight(80)
						uni.showToast({
							title: '操作失败,请重试',
							icon: 'none',
							duration: 1200
						})
					}
				})
			},
			// 切换摄像头
			switchCamera() {
				if(this.devicePosition === 'back') {
					this.devicePosition = 'front'
				} else {
					this.devicePosition = 'back'
				}
			},
			// 结束录像之后 初始数据
			stopRecordInitData () {
				this.computedHeight(80)
				this.setBoolean(true)
				this.centerCountDownValue = 4
				this.second = 9
			},
			// 设置 boolean
			setBoolean(boolean) {
				this.tipShow = boolean
				this.showBottom = boolean
				this.cameraShow = !boolean
				this.centerCountDownShow = !boolean
			},
		}
	}
</script>

<style lang="less" scoped>
	.container {
		position: relative;

		.video-wrap {
			position: relative;

			.content-wrap {
				position: absolute;
				bottom: 150px;
				width: 100%;
			}

			.padding-bottom-40 {
				padding-bottom: 40rpx;
			}

			.tips-icon {
				position: absolute;
				left: 242rpx;
				width: 96rpx;
				height: 327rpx;
			}

			.know {
				position: relative;
				top: 210rpx;
				left: 155rpx;
				display: inline-block;
				width: 199rpx;
				height: 92rpx;
				line-height: 92rpx;
				text-align: center;
				border: 3rpx dashed #fff;
				border-radius: 5rpx;
				font-size: 48rpx;
				color: #fff;
			}

			.number {
				position: absolute;
				top: 15px;
				right: 20px;
				z-index: 11;
				color: #fff;
				width: 30px;
				height: 30px;
				background-color: #7a7a7a;
				border-radius: 50%;
				text-align: center;
				line-height: 30px;
			}

			.center-count-down-wrap {
				display: flex;
				justify-content: center;
				align-items: center;
				width: 100%;
				height: 100%;
			}

			.center-count-down {
				font-size: 330rpx;
				color: #fff;
				font-weight: bold;
			}

			.center-count-down-start {
				font-size: 220rpx;
				color: #fff;
				font-weight: bold;
			}
		}

		.controls {
			position: absolute;
			bottom: 200rpx;
			width: 100%;
			height: 753rpx;
		}

		.absolute-one-font {
			position: absolute;
			left: 4.5%;
			bottom: 130rpx;
		}

		.absolute-two-font {
			position: absolute;
			bottom: 30rpx;
			left: 44%;
		}

		.bottom {
			// position: fixed;
			// bottom: 0;
			width: 100%;
			background-color: #000;

			.wrap {
				display: flex;
				align-items: center;
				justify-content: space-between;
				height: 80px;
				padding: 0 73rpx;
			}
		}

		.fade-enter-active, .fade-leave-active {
			transition: opacity .5s;
		}

		.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
			opacity: 0;
		}

		.background-color-474747 {
			background-color: #474747;
		}

		.wpercent-100 {
			width: 100%;
		}

		.text-align {
			text-align: center;
		}

		.font-36-fff {
			font-size: 36rpx;
			color: #fff;
		}
		
		.font-weight {
			font-weight: bold;
		}

		.w55-h49 {
			width: 55rpx;
			height: 49rpx;
		}

		.w100-h100 {
			width: 100rpx;
			height: 100rpx;
		}

		.w69-h56 {
			width: 69rpx;
			height: 56rpx;
		}
	}
</style>


效果图:

借鉴的是uniapp-components,记录一下如何使用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1201761.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[sd_scripts]之gen_img

https://github.com/kohya-ss/sd-scripts/blob/main/docs/gen_img_README-ja.mdhttps://github.com/kohya-ss/sd-scripts/blob/main/docs/gen_img_README-ja.md1.图像生成 ckpt "/home/image_team/image_team_docker_home/lgd/e_commerce_sd/stable-diffusion-webui/mod…

数据结构-静态查找、二分查找、分块查找

静态查找 在静态查找表中&#xff0c;我们只允许下面两件事&#xff1a; 1.在查找表中查找某个记录是否在表中 2.查找表中记录的各个属性 动态查找 在动态查找表中&#xff0c;我们允许四件事&#xff1a; 1.在查找表中查找某个记录是否在表中 2.查找表中记录的各个属性…

代理模式-静态动态代理-jdk动态代理-cglib动态代理

代理模式 静态代理 动态代理&#xff1a;jdk动态代理 cglib动态代理 注意 &#xff1a;下面的代码截图 要配合文字去看 我对代码的每一步都做了解释 所以需要配合图片观看提取吗1111https://pan.baidu.com/s/1OxQSwbQ--t5Zvmwzjh1T0A?pwd1111 这里直接把项目文件 及代码 …

Linux 使用随记

Linux 使用随记 shell 命令行模式登录后所取得的程序被成为shell&#xff0c;这是因为这个程序负责最外层的跟用户&#xff08;我们&#xff09;通信工作&#xff0c;所以才被戏称为shell。 命令 1、命令格式 command [-options] parameter1 parameter2 … 1、一行命令中第…

FNPLicensingService.exe 总提示要联网

目录预览 一、问题描述二、原因分析三、解决方案&#xff1a;四、参考链接 一、问题描述 FNPLicensingService.exe 总提示要联网 找到路径如下&#xff1a; C:\Program Files (x86)\Common Files\Macrovision Shared\FlexNet Publisher然而从文件目录来看&#xff0c;并没有…

成都优优聚美团代运营:打造高效电商运营的利器

一、引人注目的标题 在繁杂的电商市场中&#xff0c;成都优优聚美团代运营以其专业的服务&#xff0c;为商家提供了一站式的解决方案。那么&#xff0c;这个备受瞩目的代运营平台有何特别之处呢&#xff1f;今天&#xff0c;我们就来一探究竟。 二、平台背景与优势 成都优优聚…

Electronica Samtec展台连接器Demo回顾 | 224Gbps PAM4:令人瞠目的速率

【摘要/前言】 最近&#xff0c;我们正在为大家带来2023慕尼黑上海电子展虎家展台Demo演示回顾系列。 今天虎家工程师团队再次为大家带来系列第一期&#xff1a; 我们邀请到了合作伙伴Keysight&#xff0c;与我们一同带来了Samtec NovaRay高密度、高性能阵列连接器以及Keysig…

微信小程序用户隐私API

用户隐私保护 由于用户隐私保护的政策执行&#xff0c;我们在调用涉及到用户隐私的API时&#xff0c;未更新用户隐私保护协议是无法直接调用的&#xff0c;小程序会默认判断是否更新用户隐私保护 &#xff0c;并根据用户隐私保护中的协议来判断是否可以调用对应的API&#xff…

Generated Key 的功能

Generated Key 简介 一. 前言现场报错原因解决扩展 二. Generated Key简介&#xff1a;作用使用 一. 前言 现场报错 在客户现场遇到如下报错&#xff0c;现象是无法使用调度系统进行数据库的 insert 操作&#xff1a; 原因 数据库版本太老&#xff0c;而 insert 语句是使…

高性能图表库LightningChart JS v5.0 - 轻松实现图表自定义布局

LightningChart JS是Web上性能最高的图表库具有出色的执行性能 - 使用高数据速率同时监控数十个数据源。 GPU加速和WebGL渲染确保您的设备的图形处理器得到有效利用&#xff0c;从而实现高刷新率和流畅的动画。 点击获取LightningChart JS v5.0正式版下载 LightningChart JS …

如何压缩文件?学会这4个简单方法!

“我有一些文件需要发送&#xff0c;但是文件太大了无法发送&#xff0c;我想把它们压缩但是不知道怎么操作。怎么压缩文件呢&#xff1f;谁能帮我出出主意呀&#xff1f;” 在数字化时代&#xff0c;文件传输和存储变得日益重要。压缩文件是一种有效的方式&#xff0c;可以减小…

清单式管理提高巡检质量——巡检管理系统体系化管理

巡检管理系统采用体系化的清单式管理方法&#xff0c;减少巡检工作中人为因素的误差&#xff0c;让巡检工作落实到细节&#xff0c;并有迹可查。 清单式管理是一种高效、系统化的巡检方法&#xff0c;广泛应用于各种行业和领域。通过制定详细的巡检清单&#xff0c;明确巡检内容…

MATLAB Simulink和SMART PLC水箱液位高度PID控制联合仿真

SMART PLC 向导PID的详细介绍请查看下面文章链接: S7-200 SMART PLC PID向导详细介绍(如何实现P、PD、PID控制器)-CSDN博客文章浏览阅读1k次。这篇博客主要介绍SMART PLC PID向导的使用,PID控制相关的其它内容请查看专栏系列文章,常用链接如下:SMART PLC PID负压控制(过程…

简洁高效的微信小程序分页器封装实践

前言 在现今的移动应用开发中&#xff0c;微信小程序已经成为了一个备受欢迎的平台。然而&#xff0c;随着应用的复杂性增加&#xff0c;数据的管理和加载成为了一个问题。本文将探讨微信小程序中的一个关键概念&#xff1a;封装分页器&#xff0c;它是提升小程序性能和用户体验…

windows qos api使用示例

简介 本文给出C版以及Rust版调用windows API实现QOS的示例&#xff0c;并提出一些注意事项。QOS可以用来区分socket 优先级、实现带宽控制等诸多功能。 UDP版本 该示例的重要部分是客户端应用程序。客户端代码的工作方式如下&#xff1a; 1. 通过套接字连接到目标 IP 地址。…

手把手教你数据流图如何画,轻松搞定!

数据流图是一种强大的工具&#xff0c;用于可视化和分析系统中的数据流动和处理过程。它不仅能够帮助我们更好地理解系统的功能和流程&#xff0c;还能够帮助我们发现和解决潜在的问题。在本篇文章中&#xff0c;我们将手把手教你掌握数据流图。 一、数据流图的概念和构成元素 …

合合信息亮相新加坡科技周——Big Data AI World Expo展示AI驱动文档数字化的前沿能力

展会规模背景&#xff1a; 2023年10月11日-12日&#xff0c;合合信息在TECH WEEK SINGAPORE&#xff08;新加坡科技周&#xff09;亮相&#xff0c;并在人工智能世界博览会&#xff08;Big Data & AI World&#xff09;展示合合信息核心人工智能文字识别技术能力。合合信息…

cadence virtuoso 导出电路图

去掉网格&#xff1a;option-display file-export image

FPGA高端项目:图像采集+GTX+UDP架构,高速接口以太网视频传输,提供2套工程源码加QT上位机源码和技术支持

目录 1、前言免责声明本项目特点 2、相关方案推荐我这里已有的 GT 高速接口解决方案我这里已有的以太网方案 3、设计思路框架设计框图视频源选择OV5640摄像头配置及采集动态彩条视频数据组包GTX 全网最细解读GTX 基本结构GTX 发送和接收处理流程GTX 的参考时钟GTX 发送接口GTX …

如何在电脑和手机设备上编辑只读 PDF

我们大多数人更喜欢以 PDF 格式共享和查看文件&#xff0c;因为它更专业、更便携。但是&#xff0c;通常情况下您被拒绝访问除查看之外的内容编辑、复制或评论。如果您希望更好地控制您的 PDF 或更灵活地编辑它&#xff0c;请弄清楚为什么您的 PDF 是只读的&#xff0c;然后使用…