UNPKG

captain-ui

Version:

有赞vue wap业务组件库

458 lines (393 loc) 12.8 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); exports.__esModule = true; exports.default = void 0; require("vant/es/toast/style"); var _toast = _interopRequireDefault(require("vant/es/toast")); require("vant/es/popup/style"); var _popup = _interopRequireDefault(require("vant/es/popup")); require("vant/es/uploader/style"); var _uploader = _interopRequireDefault(require("vant/es/uploader")); require("vant/es/dialog/style"); var _dialog = _interopRequireDefault(require("vant/es/dialog")); var _vue = _interopRequireDefault(require("vue")); var _index = require("../../common/index.js"); var _upload = require("../../../cert-id-ocr/src/utils/upload"); var _constants = require("../../constants"); // import '../../common/tracking.js'; // import '../../common/tracking-data-face.js'; // import '../../common/getUserMediaPolyfill.js'; // import { isWebRTCSupported } from '../../../constants/index.js'; // 录制时间 var VIDEO_RECORD_DURATION = 5000; // 轮询失败尝试次数 var MAX_LOOP_FAIL_COUNT = 5; // webRTC视频限制参数 var CONSTRAINTS_OPTION = { video: { frameRate: { ideal: 10, max: 15 }, facingMode: 'user' } }; // 视频录制参数 var MediaRecorderOptions = { videoBitsPerSecond: 600000 }; var _default2 = { render: function render() { var _vm = this; var _h = _vm.$createElement; var _c = _vm._self._c || _h; return _c('main', { class: [_vm.prefixCls + '__wrapper'] }, [_c('section', { class: [_vm.prefixCls + '__record-wrapper'] }, [_c('div', { class: [_vm.prefixCls + '__record-content'] }, [_c('div', { class: [_vm.prefixCls + '__record-scan'], on: { "click": _vm.startCapture } }), _c('p', { class: [_vm.prefixCls + '__record-tips'] }, [_vm._v("请将脸部正对镜头,保持光线充足")])])]), _c('section', { class: [_vm.prefixCls + '__tips-wrapper'] }, [_c('header', { class: [_vm.prefixCls + '__tips-header'] }, [_c('h4', [_vm._v("请在拍摄时朗读4位验证数字")]), _vm._m(0)]), _c('p', { class: [_vm.prefixCls + '__tips-body'] }, _vm._l(_vm.randomNums, function (n, index) { return _c('span', { key: index }, [_vm._v("\n " + _vm._s(n) + "\n ")]); }), 0), _c('p', { class: [_vm.prefixCls + '__tips-footer'] }, [_vm._v("建议视频时长不超过5秒")])]), _c('van-uploader', { directives: [{ name: "show", rawName: "v-show", value: false, expression: "false" }], ref: "uploader", attrs: { "multiple": false, "disabled": _vm.uploading, "before-read": _vm.beforeRead, "after-read": _vm.execute, "capture": "user", "accept": "video/*" } }), _c('van-popup', { class: [_vm.prefixCls + '__recorder-wrapper'], attrs: { "overlay": false, "lazy-render": false, "position": "bottom", "data-comment": "异步将 src 赋给 video" }, on: { "opened": _vm.execute }, model: { value: _vm.capturing, callback: function callback($$v) { _vm.capturing = $$v; }, expression: "capturing" } }, [_c('video', { ref: "video", attrs: { "preload": "", "autoplay": "", "loop": "", "muted": "", "controls": "", "playsinline": "" }, domProps: { "muted": true } }), _vm.isWebRTCSupported ? _c('div', { staticClass: "recognition__recorder-mask" }, [_c('p', { class: [_vm.prefixCls + '__recorder-face'] }), _c('p', { class: [_vm.prefixCls + '__recorder-instruction'] }, [_vm._v(_vm._s(_vm.instruction))])]) : _vm._e()])], 1); }, staticRenderFns: [function () { var _vm = this; var _h = _vm.$createElement; var _c = _vm._self._c || _h; return _c('p', [_c('span', [_vm._v("牢记数字")]), _c('span', [_vm._v(">")]), _c('span', [_vm._v("开始拍摄")]), _c('span', [_vm._v(">")]), _c('span', [_vm._v("边录边读")])]); }], name: 'cap-cert-recognition', components: { 'van-dialog': _dialog.default, 'van-uploader': _uploader.default, 'van-popup': _popup.default }, props: { randomNums: { type: Array, default: function _default() { return []; }, required: true }, action: { type: String, default: '' }, videoMaxSize: { type: Number, default: 9 * 1024 * 1024 }, tokenUrl: { type: String, default: '', required: true }, submitRecognition: { type: Function, default: function _default() { return Promise.resolve(); } }, queryRecognition: { type: Function, default: function _default() { return Promise.resolve(); } } }, data: function data() { return { prefixCls: _constants.prefixCls + '-recognition', isWebRTCSupported: false, // 不支持 WebRTC 需 fallback 到 input 模式 TODO:暂时默认为false capturing: false, uploading: false, loopFailCount: 0, // 连续轮询失败次数,超过 MAX_LOOP_FAIL_COUNT 就认为服务端异常,停止轮询 instruction: '请将脸部正对镜头', stream: null, // webRTC stream trackTask: null, // tracking task noWebrtcDialogOpened: false // 不支持webrtc的确认Dialog }; }, methods: { startCapture: function startCapture() { var _this = this; this.$emit('on-start-capture'); if (this.isWebRTCSupported) { this.stream = null; navigator.mediaDevices.getUserMedia(CONSTRAINTS_OPTION).then(function (stream) { _this.stream = stream; _this.capturing = true; }, function () { // webRTC回调识别fallback _this.isWebRTCSupported = false; }).catch(function () { // webRTC回调识别fallback _this.isWebRTCSupported = false; }); } else { // this.noWebrtcDialogOpened = true; this.onConfirmNoWebrtcDialog(); } }, onConfirmNoWebrtcDialog: function onConfirmNoWebrtcDialog() { this.$refs.uploader.$refs.input.click(); }, beforeRead: function beforeRead(video) { var overSize = video.size > this.videoMaxSize; if (overSize) { var megabyte = (this.videoMaxSize / 1024 / 1024).toFixed(1); (0, _toast.default)("\u89C6\u9891\u5C3A\u5BF8\u8D85\u8FC7\u9650\u5236\uFF0C\u6700\u5927\u4E3A" + megabyte + "M"); return false; } return true; }, /** * 根据 webRTC stream 或 视频文件进行识别、处理、上传、提交、查询结果一系列工作 * @param {File|undefined} file 支持 webRTC时为 undefined,否则为录像文件 */ execute: function execute(_temp) { var _this2 = this; var _ref = _temp === void 0 ? {} : _temp, file = _ref.file; var isWebRTCSupported = this.isWebRTCSupported; var capturePromise; if (isWebRTCSupported) { var video = this.$refs.video; video.playsInline = true; var source = this.stream; if ('srcObject' in video) { video.srcObject = source; } else { video.src = (0, _index.getVideoURL)(source); } capturePromise = this.startRecognize(video).then(this.startRecord).then(function (record) { // 录制结束后进入识别 _toast.default.loading({ duration: 0, mask: true, message: '识别中…' }); return record; }); } else { capturePromise = Promise.resolve().then(function () { _toast.default.loading({ duration: 0, mask: true, message: '识别中…' }); return file; }); } capturePromise.then(this.uploadFile).then(this.commitRecognize).then(this.queryRecognizeRes).then(function () { _toast.default.clear(); _this2.$emit('success'); }).catch(function (msg) { _toast.default.clear(); if (msg) (0, _toast.default)(String(msg)); _this2.$emit('fail'); }).finally(function () { _this2.capturing = false; if (_this2.stream && _this2.stream.getTracks) { _this2.stream.getTracks().forEach(function (track) { return track.stop(); }); } }); }, /** * 使用 tracking.js 对视频进行人脸检测 * @param {Element} video 视频元素 * @return {Promise} */ startRecognize: function startRecognize(video) { var _this3 = this; var recognizePromise = new Promise(function (resolve) { var tracker = new window.tracking.ObjectTracker(['face']); _this3.instruction = '请将脸部正对镜头'; tracker.on('track', function (ev) { var data = ev.data; // TODO: 根据 data 数据对人脸的检测进行更严格的控制,比如人脸和蒙层上蓝框的匹配程度 // 检测到人脸 if (data.length !== 0) { _this3.instruction = '点点头'; resolve(); } }); // 内部方法,原生暴露的方法欠缺 webRTC API 兼容处理 _this3.trackTask = window.tracking.trackVideo_(video, tracker); }); return recognizePromise; }, /** * 使用 MediaRecorder 录制15秒的视频 * @return {Promise} */ startRecord: function startRecord() { var _this4 = this; // 停止track识别,防止卡顿 this.trackTask.stop(); this.trackTask = null; var recordPromise = new Promise(function (resolve) { var stream = _this4.stream; var recorder = new MediaRecorder(stream, MediaRecorderOptions); var chunks = []; recorder.ondataavailable = function (e) { chunks.push(e.data); }; recorder.onstop = function () { var blob = new Blob(chunks, { type: recorder.mimeType }); chunks = []; resolve(blob); }; setTimeout(function () { recorder.stop(); }, VIDEO_RECORD_DURATION); recorder.start(); }); return recordPromise; }, uploadFile: function uploadFile(file) { var _this5 = this; this.uploading = true; return (0, _upload.upload)([file], this.tokenUrl).then(function (_ref2) { var url = _ref2[0]; _this5.uploading = false; if (url === '') { return Promise.reject('视频上传失败'); } return Promise.resolve(url); }); }, commitRecognize: function commitRecognize(videoUrl) { var _this6 = this; return this.submitRecognition({ videoUrl: videoUrl, action: this.action }).then(function (_ref3) { var status = _ref3.status, bizNo = _ref3.bizNo; if (status === -1) { _dialog.default.alert({ message: '识别失败,可能是由于您的证件照片不够清晰,请重新上传身份证照片。' }).then(function () { return _this6.$emit('fail-confirm'); }); return Promise.reject(); } return { bizNo: bizNo }; }); }, queryRecognizeRes: function queryRecognizeRes(_ref4) { var _this7 = this; var bizNo = _ref4.bizNo; return this.queryRecognition({ bizNo: bizNo }).then(function (_ref5) { var success = _ref5.success, status = _ref5.status; _this7.loopFailCount = 0; if (success) { return; } if (status === 1) { return (0, _index.delay)(1000).then(function () { return _this7.queryRecognizeRes({ bizNo: bizNo }); }); } return Promise.reject('检测失败,请重试'); }, function (err) { if (err && err.code && err.msg) { return Promise.reject(err.msg); } // 防止因网络超时等导致的前端中断请求,而后端其实执行成功 if (_this7.loopFailCount < MAX_LOOP_FAIL_COUNT) { _this7.loopFailCount += 1; return (0, _index.delay)(1000).then(function () { return _this7.queryRecognizeRes({ bizNo: bizNo }); }); } return Promise.reject('检测失败,请重试'); }); } } }; exports.default = _default2;