This commit is contained in:
xiaoshan
2023-11-24 10:34:45 +08:00
parent c7f5f3a1d7
commit 16a5e19093
6 changed files with 671 additions and 15 deletions

View File

@@ -16,5 +16,10 @@
"前端组件",
"通用组件"
]
}
},
"dependencies": {
"axios": "^0.27.2",
"base-64": "^1.0.0",
"image-tools": "^1.4.0"
}
}

View File

@@ -146,6 +146,14 @@
"enablePullDownRefresh": false,
"navigationStyle": "custom"
}
},
{
"path" : "pages/mine/faceRecognition/faceRecognition",
"style" :
{
"navigationBarTitleText" : "",
"enablePullDownRefresh" : false
}
}
],
"tabBar": {

View File

@@ -6,6 +6,7 @@
</view>
<button @click="$tab.navigateTo('/pages/live/plug-flow')">推流</button>
<button @click="$tab.navigateTo('/pages/live/pull-flow')">拉流</button>
<button @click="$tab.navigateTo('/pages/mine/faceRecognition/faceRecognition')">人脸识别</button>
<button @click="$tab.navigateTo('/pages/componentsTest')">跳转组件测试页</button>
</view>
</template>

View File

@@ -2,33 +2,91 @@
<div class="page-box" :style="`height: ${livePusherStyle}px;`">
<live-pusher
id='livePusher'
ref="livePusher"
ref="livePusher"
class="livePusher"
:style="`height: ${livePusherStyle}px;`"
:url="`rtmp://121.199.24.205:9116/live/livestream2?secret=0a0b8d0d7dc84232ad8c5d24f3000b00&token=${userToken}`"
mode="SD"
whiteness="2"
aspect="9:16"
:muted="true"
:whiteness="whiteness"
:beauty="beauty"
:orientation="orientation"
:aspect="aspect"
:mode="showMode"
:style="`height: ${livePusherStyle}px;`"
:muted="muted"
:enable-camera="true"
:auto-focus="true"
:beauty="1"
@statechange="statechange"
@netstatus="netstatus"
@error="error"
/>
<div class="camera-box-1" @click="close" v-if="liveState">
<div class="camera-box-left" @click="back">
<u-icon name="close" size="22" color="#fff" />
</div>
<div class="camera-box" @click="openEdit">
<text v-if="edit" class="camera-box-text">···</text>
<u-icon v-else name="arrow-right" color="#fff"></u-icon>
</div>
<div class="camera-box-1" @click="close" v-if="liveState" :style="{width: boxWidth}">
<text class="camera-box-text">直播结束</text>
</div>
<div class="camera-box-1" @click="start" v-else>
<div class="camera-box-1" @click="start" v-else :style="{width: boxWidth}">
<text class="camera-box-text">开始直播</text>
</div>
<div class="camera-box-2" @click="switchCamera">
<div class="camera-box-2" @click="switchCamera" :style="{width: boxWidth}">
<text class="camera-box-text">切换镜头</text>
</div>
<div class="camera-box-3" @click="pause">
<div class="camera-box-3" @click="pause" :style="{width: boxWidth}">
<text class="camera-box-text">暂停直播</text>
</div>
<div class="camera-box-4" @click="openShowMode('mode')" :style="{width: boxWidth}">
<text class="camera-box-text">清晰</text>
<text class="camera-box-text">{{showMode}}</text>
<div class="mode-list-1" :style="{width: showModeWidth}">
<text @click="checkMode(item)" :style="{color: showMode == item ? '#00aaff' : '#fff'}" class="camera-box-text" v-for="(item, index) in showModeList" :key="index">
{{item}}
</text>
</div>
</div>
<div class="camera-box-5" @click="openShowMode('aspect')" :style="{width: boxWidth}">
<text class="camera-box-text">宽高</text>
<text class="camera-box-text">{{aspect}}</text>
<div class="mode-list-2" :style="{width: showAspectWidth}">
<text @click="checkMode(item)" :style="{color: aspect == item ? '#00aaff' : '#fff'}" class="camera-box-text" v-for="(item, index) in aspectList" :key="index">
{{item}}
</text>
</div>
</div>
<div class="camera-box-6" @click="isMute" :style="{width: boxWidth}">
<text class="camera-box-text">{{muted ? '静音' : '不静音'}}</text>
</div>
<div class="camera-box-7" @click="openShowMode('orientation')" :style="{width: boxWidth}">
<text class="camera-box-text">方向</text>
<text class="camera-box-text">{{orientationList.filter(i => i.id == orientation)[0].name}}</text>
<div class="mode-list-3" :style="{width: showOrientationWidth}">
<text @click="checkMode(item)" :style="{color: orientation == item.id ? '#00aaff' : '#fff'}" class="camera-box-text" v-for="(item, index) in orientationList" :key="index">
{{item.name}}
</text>
</div>
</div>
<div class="camera-box-8" @click="openShowMode('beaut')" :style="{width: boxWidth}">
<text class="camera-box-text">美颜</text>
<view class="mode-list-4" :style="{width: beautWidth}">
<u-slider
style="width: 500rpx;margin-top: 28rpx;margin-left: 35rpx;"
v-model="beauty"
min="0"
:max="maxType"></u-slider>
</view>
</div>
<div class="camera-box-9" @click="openShowMode('whiteness')" :style="{width: boxWidth}">
<text class="camera-box-text">美白</text>
<div class="mode-list-5" :style="{width: whitenessWidth}">
<u-slider
style="width: 500rpx;margin-top: 28rpx;margin-left: 35rpx;"
v-model="whiteness"
min="0"
:max="maxType"></u-slider>
</div>
</div>
</div>
</template>
@@ -37,11 +95,33 @@
export default {
data() {
return {
aspect: '16:9',
showMode:'SD',
beauty: 0,
whiteness: 0,
step: 1,
maxType: 10,
orientation: 'vertical',
muted: true,
type: '',
userToken: getToken(),
context: null,
livePusherStyle: 0,
showModeWidth: 0,
showAspectWidth: 0,
showOrientationWidth: 0,
beautWidth: 0,
whitenessWidth: 0,
boxWidth: 0,
liveState: false,
playState: true
playState: true,
edit: true,
showModeList: [ 'SD', 'HD', 'FHD' ],
aspectList: ['3:2', '9:16', '16:9'],
orientationList: [
{id: 'vertical', name: '竖屏'},
{id: 'horizontal', name: '横屏'}
]
};
},
onReady() {
@@ -54,7 +134,103 @@
}
})
},
mounted() {
// this.startPreview()
},
methods: {
startPreview: function() {
this.context.startPreview({
success: (a) => {
console.log("livePusher.startPreview:" + JSON.stringify(a));
}
});
},
back() {
uni.navigateBack()
},
openEdit() {
this.edit = !this.edit
if(this.edit) {
let timer = setTimeout(() => {
this.boxWidth = 0
clearTimeout(timer)
}, 500)
this.resetWidth()
}
else this.boxWidth = '100rpx'
},
// 静音
isMute() {
this.muted = !this.muted
},
// 选中弹出窗内容
checkMode(item) {
if(this.type == 'mode') this.showMode = item
else if( this.type == 'aspect') this.aspect = item
else if( this.type = 'orientation') {
this.orientation = item.id
let mode = this.showMode
let timer = null
this.showMode = ''
timer = setTimeout(() => {
this.showMode = mode
clearTimeout(timer)
})
}
},
// 打开功能选项弹出
openShowMode(item){
this.type = item
if(item == 'mode') {
// 设置清晰度
if(this.showModeWidth) {
this.showModeWidth = 0
} else {
this.resetWidth()
this.showModeWidth = '300rpx'
}
} else if (item == 'aspect') {
// 设置比例
if(this.showAspectWidth) {
this.showAspectWidth = 0
} else {
this.resetWidth()
this.showAspectWidth = '300rpx'
}
} else if (item == 'orientation') {
// 设置视频方向
if(this.showOrientationWidth) {
this.showOrientationWidth = 0
} else {
this.resetWidth()
this.showOrientationWidth = '200rpx'
}
} else if (item == 'beaut') {
// 设置美颜
if(this.beautWidth) {
this.beautWidth = 0
} else {
this.resetWidth()
this.beautWidth = '560rpx'
}
} else if (item == 'whiteness') {
// 设置美白
if(this.whitenessWidth) {
this.whitenessWidth = 0
} else {
this.resetWidth()
this.whitenessWidth = '560rpx'
}
}
},
// 重置弹窗宽度
resetWidth() {
this.showAspectWidth = 0
this.showModeWidth = 0
this.showOrientationWidth = 0
this.beautWidth = 0
this.whitenessWidth = 0
},
statechange(e) {
// console.log("statechange:" + JSON.stringify(e));
},
@@ -109,47 +285,200 @@
width: 750rpx;
background-color: #000;
}
.camera-box-left {
position: fixed;
top: 60rpx;
left: 0rpx;
align-items: center;
justify-content: center;
width: 60rpx;
height: 60rpx;
}
.camera-box {
position: fixed;
top: 60rpx;
right: 0rpx;
align-items: center;
justify-content: center;
width: 60rpx;
height: 60rpx;
border: 1rpx;
border-style: solid;
border-color: #fff;
}
.camera-box-1 {
position: fixed;
top: 60rpx;
right: 60rpx;
align-items: center;
justify-content: center;
width: 100rpx;
height: 100rpx;
border: 1rpx;
border-style: solid;
border-color: #fff;
transition: width .5s;
}
.camera-box-2 {
position: fixed;
top: 160rpx;
right: 60rpx;
align-items: center;
justify-content: center;
width: 100rpx;
height: 100rpx;
border: 1rpx;
border-style: solid;
border-color: #fff;
transition: width .5s;
}
.camera-box-3 {
position: fixed;
top: 260rpx;
right: 60rpx;
align-items: center;
justify-content: center;
width: 100rpx;
height: 100rpx;
border: 1rpx;
border-style: solid;
border-color: #fff;
transition: width .5s;
}
.camera-box-4 {
position: fixed;
top: 260rpx;
top: 360rpx;
right: 60rpx;
align-items: center;
justify-content: center;
width: 100rpx;
height: 100rpx;
border: 1rpx;
border-style: solid;
border-color: #fff;
transition: width .5s;
}
.camera-box-5 {
position: fixed;
top: 460rpx;
right: 60rpx;
align-items: center;
justify-content: center;
width: 100rpx;
height: 100rpx;
border: 1rpx;
border-style: solid;
border-color: #fff;
transition: width .5s;
}
.camera-box-6 {
position: fixed;
top: 560rpx;
right: 60rpx;
align-items: center;
justify-content: center;
width: 100rpx;
height: 100rpx;
border: 1rpx;
border-style: solid;
border-color: #fff;
transition: width .5s;
}
.camera-box-7 {
position: fixed;
top: 660rpx;
right: 60rpx;
align-items: center;
justify-content: center;
width: 100rpx;
height: 100rpx;
border: 1rpx;
border-style: solid;
border-color: #fff;
transition: width .5s;
}
.camera-box-8 {
position: fixed;
top: 760rpx;
right: 60rpx;
align-items: center;
justify-content: center;
width: 100rpx;
height: 100rpx;
border: 1rpx;
border-style: solid;
border-color: #fff;
transition: width .5s;
}
.camera-box-9 {
position: fixed;
top: 860rpx;
right: 60rpx;
align-items: center;
justify-content: center;
width: 100rpx;
height: 100rpx;
border: 1rpx;
border-style: solid;
border-color: #fff;
transition: width .5s;
}
.mode-list-1 {
position: fixed;
top: 360rpx;
right: 160rpx;
flex-direction: row;
justify-content: space-between;
align-items: center;
height: 100rpx;
border-radius: 15rpx 0 0 15rpx;
background-color: rgba(255, 255, 255, .2);
transition: width .5s;
}
.mode-list-2 {
position: fixed;
top: 460rpx;
right: 160rpx;
flex-direction: row;
justify-content: space-between;
align-items: center;
height: 100rpx;
border-radius: 15rpx 0 0 15rpx;
background-color: rgba(255, 255, 255, .2);
transition: width .5s;
}
.mode-list-3 {
position: fixed;
top: 660rpx;
right: 160rpx;
flex-direction: row;
justify-content: space-between;
align-items: center;
height: 100rpx;
border-radius: 15rpx 0 0 15rpx;
background-color: rgba(255, 255, 255, .2);
transition: width .5s;
}
.mode-list-4 {
position: fixed;
top: 760rpx;
right: 160rpx;
height: 100rpx;
border-radius: 15rpx 0 0 15rpx;
background-color: rgba(255, 255, 255, .2);
transition: width .5s;
}
.mode-list-5 {
position: fixed;
top: 860rpx;
right: 160rpx;
height: 100rpx;
border-radius: 15rpx 0 0 15rpx;
background-color: rgba(255, 255, 255, .2);
transition: width .5s;
}
.camera-box-text {
width: 100rpx;
color: #fff;
text-align: center;
}

View File

@@ -0,0 +1,312 @@
<template>
<view class="face_2">
<div class="custom" :style="{height: CustomBar+'px'}">
<view class="navcontent" :style="[{top:statusBar + 'px'}]">
<text style="color: #FFFFFF;font-size: 16px;line-height: 45px;" class="iconfont icon-xiangzuo"
@click="BackPage"></text>
<text style="color: #FFFFFF;font-size: 16px;line-height: 45px;text-align: center;">人脸识别</text>
</view>
</div>
<view class="camera">
<live-pusher
id='livePusher'
ref="livePusher"
class="livePusher"
url=""
mode="SD"
:muted="true"
:enable-camera="true"
:auto-focus="true"
:beauty="1"
whiteness="2"
aspect="9:16"
></live-pusher>
<view class="images">
<text v-if="showStatus==1" class="images-text">如果确认开始人脸识别,请点击下方按钮!</text>
<text v-if="showStatus==2" class="images-text-1">人脸信息不一致!</text>
<text v-if="showStatus==3" class="images-text-1">未采集到人脸!</text>
<!-- <cover-image src="../static/rentouxiang.png"></cover-image> -->
</view>
</view>
<button class="btn" v-if="showStatus==1" @click="faceRecognition()"><text style="color: #FFF;">点击进行人脸识别验证</text></button>
<!-- <button class="btn" v-else @click="faceRecognitionStop()"><text style="color: #FFF;">停止人脸识别验证</text></button> -->
<u-toast ref="uToast" />
</view>
</template>
<script>
// import { faceID, getAnswerTime, } from '@/util/request/api.js';
import { base64ToPath } from "@/node_modules/image-tools/index.js";
// import { baseUrl } from "@/util/request/config.js";
export default {
data() {
return {
showStatus: 1,
context: null,
// 定时器
Timer: null,
// 快照的图片路径
imagUrl: null,
id: "",
titles: "",
flag: false,
CustomBar: 0,
statusBar: 0
}
},
watch: {
'flag': function() {
if (this.flag) {
return uni.redirectTo({
url: "/pagesB/my-AnswerPage/my-AnswerPage?id=" + this.id + "&title=" + this.titles,
success() {
// face.close()
this.flag = false;
}
})
}
},
},
// onLoad(e) {
// console.log(e);
// },
onShow() {
let routes = getCurrentPages();
this.id = routes[routes.length - 1].options.id;
this.titles = routes[routes.length - 1].options.title;
},
onReady() {
// 获取导航栏高度
var that = this
uni.getSystemInfo({
success: function(e) {
// 计算导航栏高度
that.statusBar = e.statusBarHeight
// #ifndef MP
if (e.platform == 'android') {
that.CustomBar = e.statusBarHeight + 50
} else {
that.CustomBar = e.statusBarHeight + 45
}
console.log(that.statusBar)
// #endif
// #ifdef MP-WEIXIN
let custom = wx.getMenuButtonBoundingClientRect()
that.CustomBar = custom.bottom + custom.top - e.statusBarHeight
// #endif
// #ifdef MP-ALIPAY
that.CustomBar = e.statusBarHeight + e.titleBarHeight
// #endif
}
})
// 注意需要在onReady中 或 onLoad 延时
// this.context = uni.createLivePusherContext("livePusher", this);
// console.log(this.context);
// 开启摄像头
// this.startPreview();
},
onHide() {
clearInterval(this.Timer)
},
methods: {
BackPage() {
uni.navigateBack(1);
},
// 点击进行人脸识别
faceRecognition() {
this.context = uni.createLivePusherContext("livePusher", this);
// 开启摄像头
this.startPreview();
this.showStatus = 0;
let that = this;
clearInterval(this.Timer);
that.snapshot();
this.Timer = setInterval(() => {
// 调用快照方法
that.snapshot();
}, 2000)
},
faceRecognitionStop() {
this.content.stop()
clearInterval(this.Timer)
this.context = null
},
// 快照
snapshot() {
this.context.snapshot({
success: (e) => {
// 快照拿到的图片地址存在 this.imagUrl
this.imagUrl = e.message.tempImagePath;
this.getMinImage(this.imagUrl)
},
error: (e) => {
console.log("快照error", e.message)
}
});
},
// 开启摄像头
startPreview() {
this.context.startPreview({
success: (a) => {
console.log("livePusher.startPreview:" + JSON.stringify(a));
}
});
},
// 使用plus.zip.compressImage压缩图片并转换成base64
getMinImage(imgPath) {
let token = uni.getStorageSync('token');
let _this = this;
plus.zip.compressImage({
src: imgPath,
dst: imgPath,
overwrite: true,
quality: 40
},
zipRes => {
setTimeout(() => {
var reader = new plus.io.FileReader();
reader.onloadend = res => {
var e = res.target.result; //base64图片
// console.log(e);
base64ToPath(e).then(path => {
console.log(path);
let p = plus.io.convertLocalFileSystemURL(path);
let url = "";
e = 'file://' + p;
uni.uploadFile({
url: baseUrl + "/app/common/upload",
filePath: e,
name: 'file',
header: {
'Authorization': 'Bearer ' + token,
},
success: (res) => {
url = JSON.parse(res.data).data.url;
let result = faceID(url);
console.log(result, "++++++++++++++");
// let t;
result.then(val => {
// console.log(val);
// console.log(val.data.isMatch)
if (val.code == 200 && val.data.isMatch) {
_this.flag = true;
getAnswerTime(_this.id);
} else if (val.code == 200 && !val.data.isMatch) {
this.showStatus = 2
// _this.num++;
// return _this.$refs.uToast.show({
// message: '人脸信息不一致!',
// type: 'warning',
// duration: 1000,
// })
} else {
this.showStatus = 3
// _this.nums++;
// return _this.$refs.uToast.show({
// message: '未采集到人脸!',
// type: 'danger',
// duration: 1000,
// })
}
}).catch(error => {
console.error(error)
})
}
});
}).catch(error => {
console.error(error)
})
};
//一定要使用plus.io.convertLocalFileSystemURL将target地址转换为本地文件地址否则readAsDataURL会找不到文件
reader.readAsDataURL(plus.io.convertLocalFileSystemURL(zipRes.target));
}, 1000);
},
function(error) {
console.log('Compress error!', error);
}
);
}
}
}
</script>
<style scoped>
.custom {
background-color: #2C65F7;
}
.navcontent {
height: 45px;
color: #FFFFFF;
display: flex;
justify-content: space-around;
flex-direction: row;
position: relative;
}
.iconfont {
width: 26rpx;
height: 26rpx;
border-bottom: 2rpx solid #FFFFFF;
border-left: 2rpx solid #FFFFFF;
transform: rotate(45deg);
position: absolute;
top: 50%;
left: 36rpx;
margin-top: -65rpx;
}
.camera {
width: 750rpx;
height: 750rpx;
margin: 0rpx auto 20rpx;
position: relative;
}
.images {
width: 750rpx;
height: 750rpx;
position: absolute;
top: 0;
left: 0;
}
.images-text {
color: #FFFFFF;
text-align: center;
line-height: 750rpx;
}
.images-text-1 {
color: #FFFFFF;
text-align: center;
line-height: 80rpx;
}
image {
width: 100%;
height: 100%;
}
.livePusher {
width: 750rpx;
height: 750rpx;
}
.btn {
width: 600rpx;
height: 100rpx;
border-radius: 50rpx;
color: #FFFFFF;
background: #2B6FC9;
line-height: 100rpx;
text-align: center;
font-size: 36rpx;
margin: 0 75rpx;
}
</style>

View File

@@ -13,7 +13,8 @@ const whiteList = [
'/pages/login/reset-password',
'/pages/mine/pwd/index',
'/pages/common/webview/index',
'/pages/componentsTest'
'/pages/componentsTest',
'/pages/mine/faceRecognition/faceRecognition'
]
// 检查地址白名单