|
@@ -0,0 +1,428 @@
|
|
|
+<!DOCTYPE html>
|
|
|
+<html>
|
|
|
+ <head>
|
|
|
+ <meta name="viewport"
|
|
|
+ content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
|
|
|
+ <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
|
|
|
+ <title>视频认证</title>
|
|
|
+ <style>
|
|
|
+ body {
|
|
|
+ margin: 0;
|
|
|
+ background: #F5F6FA;
|
|
|
+ }
|
|
|
+
|
|
|
+ .content {
|
|
|
+ background: #F5F6FA;
|
|
|
+ height: 100vh;
|
|
|
+ position: relative;
|
|
|
+ }
|
|
|
+
|
|
|
+ .row {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ padding-top: 50px;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ .img-video {
|
|
|
+ position: relative;
|
|
|
+ border-radius: 280px;
|
|
|
+ width: 250px;
|
|
|
+ height: 250px;
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+
|
|
|
+ .row2 {
|
|
|
+ display: flex;
|
|
|
+ font-size: 20px;
|
|
|
+ justify-content: center;
|
|
|
+ margin-top: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .verify-btn {
|
|
|
+ background: #2772FB;
|
|
|
+ font-size: 20px;
|
|
|
+ padding: 10px 0;
|
|
|
+ width: 70%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ border-radius: 50px;
|
|
|
+ color: white;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ .btn {
|
|
|
+ position: absolute;
|
|
|
+ bottom: 0;
|
|
|
+ background: white;
|
|
|
+ width: 100%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ padding: 40px 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .img {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ bottom: 0;
|
|
|
+ width: 100%;
|
|
|
+ width: 564px;
|
|
|
+ height: 564px;
|
|
|
+ right: 0;
|
|
|
+ left: 0;
|
|
|
+ margin: auto;
|
|
|
+ }
|
|
|
+
|
|
|
+ .video-content {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ bottom: 0;
|
|
|
+ width: 100%;
|
|
|
+ right: 0;
|
|
|
+ left: 0;
|
|
|
+ margin: auto;
|
|
|
+ }
|
|
|
+
|
|
|
+ .video {
|
|
|
+ width: calc(100%);
|
|
|
+ background: #F5F6FA;
|
|
|
+ }
|
|
|
+
|
|
|
+ .video-btn {
|
|
|
+ width: 100%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ }
|
|
|
+ .progressBar {
|
|
|
+ width: 50%;
|
|
|
+ height: 25px;
|
|
|
+ display: block;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ bottom: 0;
|
|
|
+ right: 0;
|
|
|
+ margin: auto;
|
|
|
+ padding: 10px 10px 10px 10px;
|
|
|
+ position: absolute;
|
|
|
+ z-index: 2001;
|
|
|
+ background: rgb(102, 102, 102);
|
|
|
+ color: white;
|
|
|
+ border-radius: 5px;
|
|
|
+ }
|
|
|
+ .text{
|
|
|
+ padding: 20px;
|
|
|
+ }
|
|
|
+ </style>
|
|
|
+ </head>
|
|
|
+ <body>
|
|
|
+ <div id='app'>
|
|
|
+ <div class='content'>
|
|
|
+ <!-- <div id="progressBar" class="progressBar">地图数据加载中...</div> -->
|
|
|
+ <div class='row'>
|
|
|
+ <div class='img-video'>
|
|
|
+ <!-- <img src="./img/shipinrenzheng.png" alt="" class='img'> -->
|
|
|
+ <div class="video-content">
|
|
|
+ <!-- 人脸检测-->
|
|
|
+ <div class="video-cover"></div>
|
|
|
+ <video :src="url" ref="videoRef" autoplay playsinline x5-video-player-type="h5"
|
|
|
+ class="video"></video>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- <div class='row2' v-show="!showVideo">
|
|
|
+ 请打开摄像头 并阅读提示文字
|
|
|
+ </div> -->
|
|
|
+ <div class='row2'>
|
|
|
+ 请将头像放于圆圈内,并阅读以下文字
|
|
|
+ </div>
|
|
|
+ <div class='row2 text'>
|
|
|
+ 网络客服过段时间浪费多少级范德萨快逻辑范德萨拉丝机多亏了房价按时付款了金坷垃所肩负的看离开静安寺了发动机as在考虑家双方都会计分录卡死范德萨拉使肌肤抵抗力
|
|
|
+ </div>
|
|
|
+ <div class='btn'>
|
|
|
+ <!-- <div class="verify-btn" @click="getCamera" v-show="!showVideo">打开摄像头</div> -->
|
|
|
+ <div class='video-btn'>
|
|
|
+ <div class="verify-btn" @click="saveVideo" v-if='!isAlreadyRecord'>开始录制</div>
|
|
|
+ <div class="verify-btn" @click="saveVideo" v-if='isAlreadyRecord' data-action="navigateTo">结束录制
|
|
|
+ </div>
|
|
|
+ <!-- <button class="video-close" @click="closeVideo">×</button>
|
|
|
+ <button class="video-save" @click="saveVideo">
|
|
|
+ {{ isAlreadyRecord ? '结束录制(' + count + 's)' : '开始录制' }}</button> -->
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- <video ref="videob" controls="" name="media" width="100%" height="100"></video> -->
|
|
|
+ </div>
|
|
|
+
|
|
|
+
|
|
|
+ </div>
|
|
|
+ </body>
|
|
|
+ <script type="text/javascript" src="vue.min.js"></script>
|
|
|
+ <script type="text/javascript" src="https://taohaoliang.oss-cn-beijing.aliyuncs.com/app/jquery.min.js"></script>
|
|
|
+ <script type="text/javascript" src="base64.js"></script>
|
|
|
+ <script type="text/javascript" src="crypto.js"></script>
|
|
|
+ <script type="text/javascript" src="index.js"></script>
|
|
|
+ <script type="text/javascript">
|
|
|
+ document.addEventListener('UniAppJSBridgeReady', function() {
|
|
|
+ uni.webView.getEnv(function(res) {
|
|
|
+ console.log('当前环境:' + JSON.stringify(res));
|
|
|
+ });
|
|
|
+ //
|
|
|
+ new Vue({
|
|
|
+ el: '#app',
|
|
|
+ data: {
|
|
|
+ url: '',
|
|
|
+ // showVideo: true,
|
|
|
+ mediaRecorder: null,
|
|
|
+ MediaStreamTrack: null,
|
|
|
+ isAlreadyRecord: false,
|
|
|
+ count: 8,
|
|
|
+ countTimer: null,
|
|
|
+ recordedBlobs: [],
|
|
|
+ compId: ''
|
|
|
+ },
|
|
|
+ beforeDestroy() {
|
|
|
+ this.MediaStreamTrack && this.MediaStreamTrack.stop()
|
|
|
+ this.countTimer && clearTimeout(this.countTimer)
|
|
|
+ },
|
|
|
+ computed: {},
|
|
|
+
|
|
|
+ mounted() {
|
|
|
+ this.getCamera()
|
|
|
+ },
|
|
|
+ watch: {},
|
|
|
+ methods: {
|
|
|
+ getPolicyBase64() {
|
|
|
+ let date = new Date();
|
|
|
+ date.setHours(date.getHours() + 87600);
|
|
|
+ let srcT = date.toISOString();
|
|
|
+ const policyText = {
|
|
|
+ "expiration": srcT, //设置该Policy的失效时间,超过这个失效时间之后,就没有办法通过这个policy上传文件了
|
|
|
+ "conditions": [
|
|
|
+ ["content-length-range", 0, 100 * 1024 * 1024] // 设置上传文件的大小限制,5mb
|
|
|
+ ]
|
|
|
+ };
|
|
|
+
|
|
|
+ const policyBase64 = Window.base64.encode(JSON.stringify(policyText));
|
|
|
+ console.log(policyBase64);
|
|
|
+ return policyBase64;
|
|
|
+ },
|
|
|
+ getSignature(policyBase64) {
|
|
|
+ const accesskey = 'FpClTp4OVrRRtHEfi3lBOWUoLxKieW';
|
|
|
+ // console.log('video.js')
|
|
|
+ // console.log(Crypto)
|
|
|
+ const bytes = Window.Crypto.HMAC(Window.Crypto.SHA1, policyBase64, accesskey, {
|
|
|
+ asBytes: true
|
|
|
+ })
|
|
|
+ const signature = Window.Crypto.util.bytesToBase64(bytes);
|
|
|
+ // console.log(signature);
|
|
|
+ return signature;
|
|
|
+ },
|
|
|
+ async uploadFile(file) {
|
|
|
+ var formdata = new FormData()
|
|
|
+ const policyBase64 = this.getPolicyBase64();
|
|
|
+ const signature = this.getSignature(policyBase64); //获取签名
|
|
|
+ const urlStr = "https://taohaoliang.oss-cn-beijing.aliyuncs.com/"
|
|
|
+ const fileName = "appData/video" + new Date().getTime() + Math.floor(Math.random() *
|
|
|
+ 150) + '.mp4'
|
|
|
+ formdata.append("key", fileName)
|
|
|
+ formdata.append("policy", policyBase64)
|
|
|
+ formdata.append("OSSAccessKeyId", 'LTAI4G9c14PgKvM23WZ9zrpc')
|
|
|
+ formdata.append("signature", signature)
|
|
|
+ formdata.append("success_action_status", '200')
|
|
|
+ formdata.append("file", file)
|
|
|
+ console.log('file.name')
|
|
|
+ $.ajax({
|
|
|
+ type: "POST",
|
|
|
+ data: formdata,
|
|
|
+ contentType: false,
|
|
|
+ processData: false,
|
|
|
+ url: urlStr,
|
|
|
+ success: function(result) {
|
|
|
+ console.log(urlStr + fileName)
|
|
|
+ uni.webView.navigateTo({
|
|
|
+ url: '/pages/mine/company/addcompany?videoSrc=' +
|
|
|
+ urlStr + fileName
|
|
|
+ })
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ //请求失败,包含具体的错误信息
|
|
|
+ error: function(e) {
|
|
|
+ console.log(e);
|
|
|
+ console.log(e.status);
|
|
|
+ console.log(e.responseText);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 调用摄像头 开始录制
|
|
|
+ getCamera() {
|
|
|
+ // 注意本例需要在HTTPS协议网站中运行,新版本Chrome中getUserMedia接口在http下不再支持。
|
|
|
+ let constraints = {
|
|
|
+ audio: true,
|
|
|
+ video: {
|
|
|
+ facingMode: 'user' // 优先调前置摄像头
|
|
|
+ }
|
|
|
+ }
|
|
|
+ console.log('--------------')
|
|
|
+ console.log(navigator)
|
|
|
+ // 老的浏览器可能根本没有实现 mediaDevices,所以我们可以先设置一个空的对象
|
|
|
+ if (navigator.mediaDevices === undefined) {
|
|
|
+ navigator.mediaDevices = {}
|
|
|
+ }
|
|
|
+ // 一些浏览器部分支持 mediaDevices。我们不能直接给对象设置 getUserMedia
|
|
|
+ // 因为这样可能会覆盖已有的属性。这里我们只会在没有getUserMedia属性的时候添加它。
|
|
|
+ if (navigator.mediaDevices.getUserMedia === undefined) {
|
|
|
+ navigator.mediaDevices.getUserMedia = function(constraints) {
|
|
|
+ // 首先,如果有getUserMedia的话,就获得它
|
|
|
+ // var getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia
|
|
|
+ var getUserMedia = navigator.getUserMedia ||
|
|
|
+ navigator.webkitGetUserMedia ||
|
|
|
+ navigator.mozGetUserMedia
|
|
|
+ // 一些浏览器根本没实现它 - 那么就返回一个error到promise的reject来保持一个统一的接口
|
|
|
+ if (!getUserMedia) {
|
|
|
+ this.$messageBox.alert('该浏览器不支持getUserMedia,请使用其他浏览器')
|
|
|
+ return Promise.reject(new Error(
|
|
|
+ 'getUserMedia is not implemented in this browser'))
|
|
|
+ }
|
|
|
+ // 否则,为老的navigator.getUserMedia方法包裹一个Promise
|
|
|
+ return new Promise(function(resolve, reject) {
|
|
|
+ getUserMedia.call(navigator, constraints, resolve, reject)
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ navigator.mediaDevices.getUserMedia(constraints)
|
|
|
+ .then((stream) => {
|
|
|
+ this.MediaStreamTrack = typeof stream.stop === 'function' ? stream :
|
|
|
+ stream
|
|
|
+ .getTracks()[0]
|
|
|
+ console.log(stream)
|
|
|
+ console.log(this.MediaStreamTrack)
|
|
|
+ // 显示录制框
|
|
|
+ this.showVideo = true
|
|
|
+ this.isAlreadyRecord = false
|
|
|
+ let winURL = window.URL || window.webkitURL
|
|
|
+ if ('srcObject' in this.$refs.videoRef) {
|
|
|
+ this.$refs.videoRef.srcObject = stream
|
|
|
+ } else {
|
|
|
+ this.$refs.videoRef.src = winURL.createObjectURL(stream)
|
|
|
+ }
|
|
|
+ console.log(this.$refs.videoRef)
|
|
|
+ this.$refs.videoRef.onloadedmetadata = e => {
|
|
|
+ // 播放视频
|
|
|
+ this.$refs.videoRef.play()
|
|
|
+ }
|
|
|
+ let options = {
|
|
|
+ videoBitsPerSecond: 2500000
|
|
|
+ }
|
|
|
+ this.mediaRecorder = new MediaRecorder(stream, options)
|
|
|
+ })
|
|
|
+ .catch((err) => {
|
|
|
+ console.log(err)
|
|
|
+ console.log('摄像头开启失败,请检查摄像头是否授权或是否可用!')
|
|
|
+ })
|
|
|
+ $("#progressBar").hide();
|
|
|
+ },
|
|
|
+ // 关闭活体检测
|
|
|
+ closeVideo() {
|
|
|
+ this.recordedBlobs = ''
|
|
|
+ this.isAlreadyRecord = false
|
|
|
+ this.MediaStreamTrack && this.MediaStreamTrack.stop()
|
|
|
+ this.countTimer && clearTimeout(this.countTimer)
|
|
|
+ this.$router.go(0)
|
|
|
+ },
|
|
|
+ // 录制倒计时
|
|
|
+ countDown() {
|
|
|
+ let that = this
|
|
|
+ let sendTime = Math.round(+new Date() / 1000)
|
|
|
+ return function walk() {
|
|
|
+ that.countTimer = setTimeout(function() {
|
|
|
+ that.countTimer && clearTimeout(that.countTimer)
|
|
|
+ let diff = sendTime + 8 - Math.round(+new Date() / 1000)
|
|
|
+ if (diff > 0) {
|
|
|
+ that.count = diff
|
|
|
+ walk()
|
|
|
+ } else {
|
|
|
+ console.log('倒计时结束')
|
|
|
+ // this.showVideo = false
|
|
|
+ console.log(this.url)
|
|
|
+ console.log(this.MediaStreamTrack)
|
|
|
+ }
|
|
|
+ }, 1000)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ dataURLtoBlob(dataurl) {
|
|
|
+
|
|
|
+ var arr = dataurl.split(","),
|
|
|
+
|
|
|
+ mime = arr[0].match(/:(.*?);/)[1],
|
|
|
+
|
|
|
+ bstr = atob(arr[1]),
|
|
|
+
|
|
|
+ n = bstr.length,
|
|
|
+
|
|
|
+ u8arr = new Uint8Array(n);
|
|
|
+
|
|
|
+ while (n--) {
|
|
|
+
|
|
|
+ u8arr[n] = bstr.charCodeAt(n);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return this.blobToFile(new Blob([u8arr], {
|
|
|
+ type: mime
|
|
|
+ }), {
|
|
|
+ type: mime
|
|
|
+ });
|
|
|
+
|
|
|
+ },
|
|
|
+ blobToFile(theBlob, type) {
|
|
|
+ theBlob.lastModifiedDate = new Date();
|
|
|
+ return new File([theBlob], `${new Date().getTime()}.mp4`, type);
|
|
|
+
|
|
|
+ },
|
|
|
+ // 保存录制视频
|
|
|
+ saveVideo() {
|
|
|
+ let that = this
|
|
|
+ if (this.isAlreadyRecord) {
|
|
|
+ this.countTimer && clearTimeout(this.countTimer)
|
|
|
+ // this.showVideo = false
|
|
|
+ //当录制的数据可用时
|
|
|
+ this.mediaRecorder.ondataavailable = (e) => {
|
|
|
+ if (e.data && e.data.size > 0) {
|
|
|
+ this.recordedBlobs.push(e.data)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.mediaRecorder.stop()
|
|
|
+ setTimeout(() => {
|
|
|
+ console.log("this.recordedBlobs-------------------------")
|
|
|
+ var blob = new Blob(this.recordedBlobs, {
|
|
|
+ type: 'video/mp4'
|
|
|
+ })
|
|
|
+ this.isAlreadyRecord = false
|
|
|
+ this.MediaStreamTrack && this.MediaStreamTrack.stop()
|
|
|
+ var reader = new FileReader();
|
|
|
+ reader.readAsDataURL(blob)
|
|
|
+ reader.onload = (e) => {
|
|
|
+ // this.$refs.videob.src = reader.result
|
|
|
+ let a = this.dataURLtoBlob(reader.result)
|
|
|
+ console.log(a)
|
|
|
+ this.uploadFile(a)
|
|
|
+ }
|
|
|
+ }, 100)
|
|
|
+ } else {
|
|
|
+ this.count = 8
|
|
|
+ this.isAlreadyRecord = true
|
|
|
+ this.mediaRecorder.start(8000)
|
|
|
+ this.countDown()()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ changeVideo(e) {
|
|
|
+ let file = this.$refs.videoFile.files
|
|
|
+ console.log(file)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ });
|
|
|
+ </script>
|
|
|
+
|
|
|
+</html>
|