@ -0,0 +1,421 @@ |
||||
<template> |
||||
<view class="yd-check" :style="{'width': winWidth+'px', 'height': winHeight+'px'}"> |
||||
<view class="check-preview"> |
||||
<view class="check-preview__content"> |
||||
<camera_preview ref="aliveDetect" class="check-preview__camera"></camera_preview> |
||||
<image class="check-preview__mask" :style="{ backgroundColor: maskColor }" |
||||
src="/static/shibie/alive_mask@3x.png" @load="handleImgLoad"></image> |
||||
</view> |
||||
<view class="check-preview__audio" @click="toggleAudioSwitch"> |
||||
<image class="check-preview__switch" |
||||
:src="enableAudio ? '/static/shibie/audio_open@3x.png' : '/static/shibie/audio_close@3x.png'"></image> |
||||
</view> |
||||
<view class="check-preview__timer progress-timer"> |
||||
<text class="txt">{{ restSec }}</text> |
||||
<view class="progress-timer__right"> |
||||
<view ref="rightCircle" class="progress-timer__circle progress-timer__circle--right"></view> |
||||
</view> |
||||
<view class="progress-timer__left"> |
||||
<view ref="leftCircle" class="progress-timer__circle progress-timer__circle--left"></view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="check-process"> |
||||
<view class="check-process__tip">{{ curAction.tip }}</view> |
||||
<image class="check-process__img" :src="`/static/shibie/${curAction.image}`"></image> |
||||
<view class="check-steps"> |
||||
<view v-for="(item,index) in commands" :key="index" |
||||
:class="['check-steps__item', curAction.step === index ? 'check-steps__item--active' : '']"> |
||||
<text v-if="curAction.step === index" class="check-steps__text">{{ index+1 }}</text> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
import api from '@/api/index.js' |
||||
const DETECT_ACTION_TYPES = { |
||||
'1': ['向右转头', 'turn_right.gif', 'turn_right.wav'], |
||||
'2': ['向左转头', 'turn_left.gif', 'turn_left.wav'], |
||||
'3': ['张嘴动作', 'open_mouth.gif', 'open_mouth.wav'], |
||||
'4': ['眨眼动作', 'open_eyes.gif', 'open_eyes.wav'] |
||||
} |
||||
const innerAudioContext = uni.createInnerAudioContext() |
||||
innerAudioContext.onPlay(() => { |
||||
console.log('音频开始播放') |
||||
}) |
||||
innerAudioContext.onError((res) => { |
||||
console.log(res.errMsg) |
||||
console.log(res.errCode) |
||||
}) |
||||
const animation = weex.requireModule('animation') |
||||
|
||||
export default { |
||||
data() { |
||||
return { |
||||
curAction: { |
||||
step: 0, |
||||
tip: '', |
||||
image: 'pic_front.png' |
||||
}, |
||||
restSec: 0, |
||||
enableAudio: true, |
||||
timer: null, |
||||
maskColor: '#fff', |
||||
isTimeout: false, |
||||
commands: [], |
||||
winWidth: 0, |
||||
winHeight: 0, |
||||
idCard: "", |
||||
realName: "" |
||||
}; |
||||
}, |
||||
onLoad(o) { |
||||
this.realName = decodeURIComponent(o.realName); |
||||
this.idCard = o.idCard; |
||||
console.log(o) |
||||
this.winWidth = uni.getSystemInfoSync().windowWidth; |
||||
this.winHeight = uni.getSystemInfoSync().windowHeight; |
||||
}, |
||||
onReady() { |
||||
console.log("页面初次渲染完成"); |
||||
this.initAliveDetect() |
||||
}, |
||||
onBackPress() { |
||||
this.$refs.aliveDetect.stopDetect() |
||||
}, |
||||
onUnload() { |
||||
console.log("页面卸载"); |
||||
if (innerAudioContext != null && !innerAudioContext.paused) { |
||||
innerAudioContext.pause() |
||||
innerAudioContext.stop() |
||||
innerAudioContext.destroy() |
||||
innerAudioContext = null |
||||
} |
||||
this.timer && clearInterval(this.timer) |
||||
}, |
||||
methods: { |
||||
initAliveDetect() { |
||||
this.timer && (clearInterval(this.timer)) |
||||
this.curAction = { |
||||
step: 0, |
||||
tip: '', |
||||
image: 'pic_front.png' |
||||
} |
||||
this.$refs.aliveDetect.init({ |
||||
'businessID': '043948b2576b41dc9d23d14b4e500b7a', |
||||
'timeout': 60, |
||||
'isDebug': true |
||||
}, this.handleCheck) |
||||
this.$refs.aliveDetect.startDetect() |
||||
this.restSec = 60 |
||||
this.timer = setInterval(() => { |
||||
if (this.restSec <= 0) { |
||||
clearInterval(this.timer) |
||||
this.timer = null |
||||
} else { |
||||
this.restSec = this.restSec - 1 |
||||
} |
||||
}, 1000) |
||||
|
||||
// nvue不支持css animatin和uni的animation,所以使用weex内置的动画 |
||||
animation.transition(this.$refs.leftCircle, { |
||||
styles: { |
||||
transform: 'rotate(135deg)' |
||||
}, |
||||
duration: 15000, |
||||
timingFunction: 'linear', |
||||
needLayout: false, |
||||
delay: 15000 |
||||
}) |
||||
animation.transition(this.$refs.rightCircle, { |
||||
styles: { |
||||
transform: 'rotate(225deg)' |
||||
}, |
||||
duration: 15000, |
||||
timingFunction: 'linear', |
||||
needLayout: false, |
||||
delay: 0 |
||||
}) |
||||
}, |
||||
//去登录 |
||||
async toReg(token) { |
||||
const res = await api.realNameAuth({ |
||||
userId: uni.getStorageSync("userInfo").id, |
||||
realName: this.realName, |
||||
idCard: this.idCard, |
||||
token |
||||
}) |
||||
console.log({ |
||||
userId: uni.getStorageSync("userInfo").id, |
||||
realName: this.realName, |
||||
idCard: this.idCard, |
||||
token |
||||
}) |
||||
console.log(res) |
||||
if(res.code == 200){ |
||||
uni.showToast({ |
||||
title: "提交成功" |
||||
}) |
||||
setTimeout(()=>{ |
||||
uni.navigateBack({ |
||||
delta: 2 |
||||
}) |
||||
},2000) |
||||
}else{ |
||||
uni.showToast({ |
||||
icon: "none", |
||||
position: "bottom", |
||||
title: res.msg |
||||
}) |
||||
} |
||||
}, |
||||
handleCheck(ev) { |
||||
// 初始化活体检测引擎成功 |
||||
if (typeof ev !== 'object') { |
||||
return |
||||
} |
||||
|
||||
const method = ev['method'] |
||||
const data = ev['data'] |
||||
|
||||
if (method == "onReady") { |
||||
const result = data['initResult'] |
||||
console.log(result ? "引擎初始化成功" : "引擎初始化失败") |
||||
} else if (method == "onConfig") { |
||||
// 动作序列 |
||||
let commands = []; |
||||
for (let i = 0; i < data['actions'].length; i++) { |
||||
commands.push(parseInt(data['actions'][i])) |
||||
}; |
||||
this.commands = commands; |
||||
} else if (method == "onChecking") { |
||||
// 检测提示 |
||||
const actionType = data['currentStep'] + '' |
||||
if (Object.keys(DETECT_ACTION_TYPES).includes(actionType) && |
||||
actionType !== this.curAction.type) { |
||||
const hit = DETECT_ACTION_TYPES[actionType] |
||||
this.curAction = { |
||||
step: this.curAction.step + 1, |
||||
type: actionType, |
||||
tip: hit[0], |
||||
image: hit[1] |
||||
} |
||||
console.log(this.curAction) |
||||
console.log(data) |
||||
this.playAudioIfEnable(hit[2]) |
||||
} |
||||
} else if (method == "onChecked") { |
||||
// // 检测结果 |
||||
console.log(data) |
||||
this.toReg(data.token) |
||||
clearInterval(this.timer) |
||||
this.timer = null |
||||
return |
||||
} else if (method == "onError") { |
||||
// 检测失败 |
||||
console.log("错误码为:" + data['code']); |
||||
console.log("错误信息为:" + data['message']); |
||||
uni.showToast({ |
||||
icon: 'none', |
||||
title: data['message'] |
||||
}) |
||||
} else if (method == "overTime") { |
||||
// 超时 |
||||
clearInterval(this.timer) |
||||
this.timer = null |
||||
uni.showModal({ |
||||
title: '检测超时', |
||||
content: '请在规定时间内完成动作', |
||||
cancelText: '返回上一页', |
||||
confirmText: '重试', |
||||
success: (res) => { |
||||
if (res.confirm) { |
||||
this.initAliveDetect() |
||||
} else { |
||||
uni.navigateBack() |
||||
} |
||||
}, |
||||
fail: () => { |
||||
uni.navigateBack() |
||||
} |
||||
}) |
||||
} |
||||
}, |
||||
playAudioIfEnable(src) { |
||||
if (!this.enableAudio) return |
||||
innerAudioContext.src = `/static/shibie/audio/${src}` |
||||
innerAudioContext.play() |
||||
}, |
||||
toggleAudioSwitch() { |
||||
this.enableAudio = !this.enableAudio |
||||
}, |
||||
handleImgLoad() { |
||||
setTimeout(() => { |
||||
this.maskColor = 'transparent' |
||||
}, 120) |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss"> |
||||
.yd-check { |
||||
background-color: #ffffff; |
||||
} |
||||
|
||||
.check-preview { |
||||
align-items: center; |
||||
justify-content: center; |
||||
position: relative; |
||||
} |
||||
|
||||
.check-preview__content { |
||||
width: 504rpx; |
||||
height: 672rpx; |
||||
margin-top: 6rpx; |
||||
position: relative; |
||||
} |
||||
|
||||
.check-preview__mask { |
||||
width: 504rpx; |
||||
height: 672rpx; |
||||
position: absolute; |
||||
top: 0; |
||||
left: 0; |
||||
z-index: 9999; |
||||
transition: backgroundColor 0.3s; |
||||
background-color: #ffffff; |
||||
} |
||||
|
||||
.check-preview__camera { |
||||
width: 504rpx; |
||||
height: 672rpx; |
||||
border-radius: 50%; |
||||
} |
||||
|
||||
.check-preview__audio { |
||||
position: absolute; |
||||
top: 0; |
||||
right: 40rpx; |
||||
width: 48rpx; |
||||
height: 48rpx; |
||||
} |
||||
|
||||
.check-preview__switch { |
||||
width: 48rpx; |
||||
height: 48rpx; |
||||
} |
||||
|
||||
.check-preview__timer { |
||||
position: absolute; |
||||
top: 80rpx; |
||||
right: 40rpx; |
||||
width: 60rpx; |
||||
height: 60rpx; |
||||
line-height: 60rpx; |
||||
color: #222; |
||||
font-size: 26rpx; |
||||
justify-content: center; |
||||
align-items: center; |
||||
.txt{ |
||||
font-size: 26rpx; |
||||
color: #000; |
||||
} |
||||
} |
||||
|
||||
.progress-timer__right, |
||||
.progress-timer__left { |
||||
width: 30rpx; |
||||
height: 60rpx; |
||||
position: absolute; |
||||
top: 0; |
||||
overflow: hidden; |
||||
} |
||||
|
||||
.progress-timer__right { |
||||
right: 0; |
||||
} |
||||
|
||||
.progress-timer__left { |
||||
left: 0; |
||||
} |
||||
|
||||
.progress-timer__circle { |
||||
width: 60rpx; |
||||
height: 60rpx; |
||||
border-style: solid; |
||||
border-width: 6rpx; |
||||
border-color: #000000; |
||||
border-radius: 50%; |
||||
position: absolute; |
||||
top: 0; |
||||
} |
||||
|
||||
.progress-timer__circle--right { |
||||
border-right-color: #ccc; |
||||
border-top-color: #ccc; |
||||
right: 0; |
||||
transform: rotate(45deg); |
||||
} |
||||
|
||||
.progress-timer__circle--left { |
||||
border-left-color: #ccc; |
||||
border-top-color: #ccc; |
||||
left: 0; |
||||
transform: rotate(-45deg); |
||||
} |
||||
|
||||
.check-process { |
||||
padding-top: 90rpx; |
||||
justify-content: center; |
||||
align-items: center; |
||||
} |
||||
|
||||
.check-process__tip { |
||||
opacity: 0.85; |
||||
font-size: 40rpx; |
||||
color: #000; |
||||
text-align: center; |
||||
line-height: 56rpx; |
||||
height: 56rpx; |
||||
} |
||||
|
||||
.check-process__img { |
||||
width: 280rpx; |
||||
height: 280rpx; |
||||
margin-top: 8rpx; |
||||
text-align: center; |
||||
} |
||||
|
||||
.check-steps { |
||||
flex-direction: row; |
||||
justify-content: space-around; |
||||
align-items: center; |
||||
width: 240rpx; |
||||
margin-top: 32rpx; |
||||
} |
||||
|
||||
.check-steps__item { |
||||
font-size: 0px; |
||||
width: 20rpx; |
||||
height: 20rpx; |
||||
background-color: #DDE3EF; |
||||
border-radius: 50%; |
||||
} |
||||
|
||||
.check-steps__item--active { |
||||
width: 40rpx; |
||||
height: 40rpx; |
||||
background-color: #000000; |
||||
justify-content: center; |
||||
} |
||||
|
||||
.check-steps__text { |
||||
color: #FFFFFF; |
||||
line-height: 40rpx; |
||||
font-size: 28rpx; |
||||
text-align: center; |
||||
} |
||||
</style> |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 62 KiB |
After Width: | Height: | Size: 647 B |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 9.1 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 80 KiB |
After Width: | Height: | Size: 160 KiB |
After Width: | Height: | Size: 271 KiB |
After Width: | Height: | Size: 258 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 62 KiB |
After Width: | Height: | Size: 647 B |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 9.1 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 80 KiB |
After Width: | Height: | Size: 160 KiB |
After Width: | Height: | Size: 271 KiB |
After Width: | Height: | Size: 258 KiB |
After Width: | Height: | Size: 2.3 KiB |