Commit 48118b3e by 修福龙

刷脸开门系统信息提示以及收银台语音通话功能实现

parent 743ae110
import React, {Component} from 'react'; import React, {Component} from 'react';
import {View, Text, Image, Dimensions} from 'react-native'; import {View, Text, Image, Dimensions, Modal} from 'react-native';
import AsyncStorage from '@react-native-community/async-storage'; import AsyncStorage from '@react-native-community/async-storage';
import {connect} from 'react-redux'; import {connect} from 'react-redux';
import RtcEngine from 'react-native-agora'; // import RtcEngine from 'react-native-agora';
import Touch from '../components/Touch'; import Touch from '../components/Touch';
import PhoneModal from '../components/PhoneModal'; import PhoneModal from '../components/PhoneModal';
import VerifyCodeModal from '../components/VerifyCodeModal'; import VerifyCodeModal from '../components/VerifyCodeModal';
...@@ -11,6 +11,7 @@ import delay from '../utils/delay'; ...@@ -11,6 +11,7 @@ import delay from '../utils/delay';
import Speech from '../utils/Speech'; import Speech from '../utils/Speech';
import WxFacepay from '../utils/WxFacepay'; import WxFacepay from '../utils/WxFacepay';
import phone from '../assets/Vertical/phone.png'; import phone from '../assets/Vertical/phone.png';
import {onTalkCall, leaveTalkCall} from '../utils/agora';
const {width} = Dimensions.get('screen'); const {width} = Dimensions.get('screen');
...@@ -20,11 +21,13 @@ class FacePage extends Component { ...@@ -20,11 +21,13 @@ class FacePage extends Component {
verifyCodeModal: false, // 显示输入验证码弹窗 verifyCodeModal: false, // 显示输入验证码弹窗
orderDetailsModal: false, // 显示订单详情弹窗 orderDetailsModal: false, // 显示订单详情弹窗
goodsArr: [], goodsArr: [],
talkCall: 2, // 0请求通话,1通话中,2,已挂断通话 talkCall: 2, // 0请求通话,1通话中,2,已挂断通话,待机状态
contact: '', contact: '',
storeName: '', storeName: '',
customerPhone: '', customerPhone: '',
current: 1, current: 1,
tip: '',
tipsModal: false,
}; };
async componentWillMount() { async componentWillMount() {
...@@ -134,49 +137,11 @@ class FacePage extends Component { ...@@ -134,49 +137,11 @@ class FacePage extends Component {
try { try {
// 加入语音通话 // 加入语音通话
clearInterval(this.noTalkCall); clearInterval(this.noTalkCall);
clearInterval(this.callTimeout);
const {data} = await this.props.dispatch({ const {data} = await this.props.dispatch({
type: 'agora/agora', type: 'agora/agora',
}); });
if (!this.engine) { await onTalkCall(data);
//创建 RtcEngine 实例
this.engine = await RtcEngine.create(data.appid);
}
await this.engine.disableVideo(true); // 关闭视频模块
await this.engine.enableLocalAudio(false); //调用 enableLocalAudio(false) 关闭本地采集后,系统会走媒体音量
await this.engine.muteAllRemoteAudioStreams(false); //停止/恢复接收所有音频流。
await this.engine.setDefaultMuteAllRemoteAudioStreams(false); // 设置是否默认接收音频流
await this.engine.setDefaultMuteAllRemoteVideoStreams(true); // 设置是否默认接收视频流
await this.engine.disableVideo(); //关闭视频模块
await this.engine.setAudioProfile(4, 3); //设置音频编码配置
await this.engine.adjustPlaybackSignalVolume(400); //调节本地播放的所有远端用户音量
await this.engine.adjustAudioMixingPlayoutVolume(100); //调节音乐文件的本地播放音量
await this.engine.setDefaultAudioRoutetoSpeakerphone(true); //默认从外放(扬声器)出声
//监听
// this.engine.addListener('Warning', data => {
// console.log('Warning' + data);
// });
// this.engine.addListener('Error', data => {
// console.log('Error' + data);
// });
// this.engine.addListener('JoinChannelSuccess', data => {
// console.warn('JoinChannelSuccess' + data);
// });
// this.engine.addListener('LeaveChannel', data => {
// console.warn('LeaveChannel' + data);
// });
// this.engine.addListener('UserOffline', data => {
// console.warn('UserOffline' + data);
// });
await this.engine.enableWebSdkInteroperability(true); //打开与webSDK的互通
await this.engine.setChannelProfile(0); //设置频道场景
await this.engine.setClientRole(1); //设置为主播角色
await this.engine.muteLocalAudioStream(true); //停止发送本地音频流
// 加入频道
await this.engine.joinChannel(data.token, data.channel, null, data.uid);
//判断当前是否扬声器
if (!(await this.engine.isSpeakerphoneEnabled())) {
await this.engine.setEnableSpeakerphone(true); //切换到外放
}
this.setState({ this.setState({
talkCall: 1, talkCall: 1,
}); });
...@@ -188,9 +153,11 @@ class FacePage extends Component { ...@@ -188,9 +153,11 @@ class FacePage extends Component {
leaveC = async () => { leaveC = async () => {
try { try {
clearInterval(this.noTalkCall); clearInterval(this.noTalkCall);
if (this.engine) { clearInterval(this.callTimeout);
await this.engine.leaveChannel(); await leaveTalkCall;
} // if (this.engine) {
// await this.engine.leaveChannel();
// }
await this.props.dispatch({ await this.props.dispatch({
type: 'agora/talkLeave', type: 'agora/talkLeave',
}); });
...@@ -203,7 +170,7 @@ class FacePage extends Component { ...@@ -203,7 +170,7 @@ class FacePage extends Component {
}; };
// device 代表当前打开的门 // device 代表当前打开的门
handleScaleChange = ({count}) => { handleScaleChange = async ({count}) => {
if (count === -1) { if (count === -1) {
// 重力感应开始识别 // 重力感应开始识别
this.wechatFace(); this.wechatFace();
...@@ -215,6 +182,7 @@ class FacePage extends Component { ...@@ -215,6 +182,7 @@ class FacePage extends Component {
phoneModal: false, phoneModal: false,
verifyCodeModal: false, verifyCodeModal: false,
current: 1, current: 1,
tipsModal: false,
}); });
} }
}; };
...@@ -226,10 +194,13 @@ class FacePage extends Component { ...@@ -226,10 +194,13 @@ class FacePage extends Component {
let tipText = ret.msg; let tipText = ret.msg;
Speech.speak(tipText); Speech.speak(tipText);
this.userId = ret.userId; this.userId = ret.userId;
this.setState({tip: tipText, tipsModal: true});
if (ret.code === 401) { if (ret.code === 401) {
// 需要验证手机号 // 需要验证手机号
this.setState({phoneModal: true}); this.setState({
} else if (ret.orders) { phoneModal: true,
});
} else if (ret.orders && ret.orders.length > 0) {
let goodsArr = []; let goodsArr = [];
ret.orders.map(v1 => { ret.orders.map(v1 => {
v1.goods.map(v2 => { v1.goods.map(v2 => {
...@@ -246,6 +217,7 @@ class FacePage extends Component { ...@@ -246,6 +217,7 @@ class FacePage extends Component {
} else if (ret.msg) { } else if (ret.msg) {
let tipText = ret.msg.replace(/扫码/g, '人脸识别'); let tipText = ret.msg.replace(/扫码/g, '人脸识别');
Speech.speak(tipText); Speech.speak(tipText);
this.setState({tip: tipText, tipsModal: true});
} }
} else { } else {
Speech.speak('正在重新识别,请靠中间站稳'); Speech.speak('正在重新识别,请靠中间站稳');
...@@ -268,6 +240,7 @@ class FacePage extends Component { ...@@ -268,6 +240,7 @@ class FacePage extends Component {
} // 出现订单弹窗,不做人脸识别 } // 出现订单弹窗,不做人脸识别
const tipText = '正在人脸识别,请看向屏幕,靠中间站稳'; const tipText = '正在人脸识别,请看向屏幕,靠中间站稳';
Speech.speak(tipText); Speech.speak(tipText);
this.setState({tip: tipText, tipsModal: true});
let auth = (await this.authinfo()) || {}; let auth = (await this.authinfo()) || {};
if ( if (
auth.return_code === 'SUCCESS' || auth.return_code === 'SUCCESS' ||
...@@ -306,6 +279,8 @@ class FacePage extends Component { ...@@ -306,6 +279,8 @@ class FacePage extends Component {
// 语音通话请求 // 语音通话请求
onCall = async () => { onCall = async () => {
const {talkCall} = this.state;
if (talkCall === 2) {
Speech.speak('正在接通中请稍候'); Speech.speak('正在接通中请稍候');
this.talkCall(); this.talkCall();
clearInterval(this.noTalkCall); clearInterval(this.noTalkCall);
...@@ -313,6 +288,14 @@ class FacePage extends Component { ...@@ -313,6 +288,14 @@ class FacePage extends Component {
this.setState({ this.setState({
talkCall: 0, talkCall: 0,
}); });
clearInterval(this.callTimeout);
this.callTimeout = setTimeout(() => {
clearInterval(this.noTalkCall);
this.setState({
talkCall: 2,
});
}, 30000);
}
}; };
talkCall = () => { talkCall = () => {
...@@ -350,6 +333,8 @@ class FacePage extends Component { ...@@ -350,6 +333,8 @@ class FacePage extends Component {
contact, contact,
customerPhone, customerPhone,
current, current,
tip,
tipsModal,
} = this.state; } = this.state;
let {dispatch} = this.props; let {dispatch} = this.props;
return ( return (
...@@ -404,15 +389,36 @@ class FacePage extends Component { ...@@ -404,15 +389,36 @@ class FacePage extends Component {
</View> </View>
</View> </View>
<View style={styles.face}> <View style={styles.face}>
<View style={styles.faceRecogn}>
<Touch <Touch
onPress={this.wechatFace}
style={styles.faceGif} style={styles.faceGif}
onPress={this.wechatFace}
feedback={false}> feedback={false}>
<Image <Image
source={require('../assets/Vertical/face.gif')} source={require('../assets/Vertical/face.gif')}
style={{flex: 1, width}} style={{flex: 1, width}}
/> />
</Touch> </Touch>
{tipsModal && tip && (
<View style={styles.modal}>
<View style={styles.tips}>
<Text style={styles.tipText}>{tip}</Text>
</View>
<Touch
onPress={this.onCall}
feedback={false}
style={styles.callTouch}>
<View style={styles.callTips}>
<Text style={styles.callTipsText}>呼叫客服</Text>
<Image
source={require('../assets/up.png')}
style={styles.callTipsImg}
/>
</View>
</Touch>
</View>
)}
</View>
<Touch <Touch
onPress={this.wechatFace} onPress={this.wechatFace}
style={styles.btnCome} style={styles.btnCome}
...@@ -516,9 +522,14 @@ const styles = { ...@@ -516,9 +522,14 @@ const styles = {
alignItems: 'center', alignItems: 'center',
justifyContent: 'space-around', justifyContent: 'space-around',
}, },
faceGif: { faceRecogn: {
flex: 0.7, flex: 0.7,
}, },
faceGif: {
// flex: 0.7,
position: 'relative',
zIndex: 2,
},
btnCome: { btnCome: {
flex: 0.15, flex: 0.15,
// backgroundColor: '#00CD66', // backgroundColor: '#00CD66',
...@@ -590,6 +601,64 @@ const styles = { ...@@ -590,6 +601,64 @@ const styles = {
color: '#fff', color: '#fff',
marginLeft: -70, marginLeft: -70,
}, },
modal: {
// flex: 0.2,
marginTop: '30%',
width: '100%',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
position: 'absolute',
zIndex: 999,
},
tips: {
flexDirection: 'row',
backgroundColor: '#FC4000',
width: '70%',
// height: '18%',
height: 200,
justifyContent: 'center',
alignItems: 'center',
marginRight: 5,
},
tipText: {
fontSize: 40,
color: '#fff',
textAlign: 'center',
paddingTop: 40,
paddingBottom: 40,
paddingLeft: 5,
paddingRight: 5,
},
callTouch: {
width: '30%',
// height: '18%',
height: 200,
marginLeft: 5,
backgroundColor: '#FC4000',
},
callTips: {
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
// backgroundColor: '#FC4000',
// width: '30%',
// height: '18%',
// marginLeft: 5,
},
callTipsText: {
fontSize: 40,
color: '#fff',
textAlign: 'center',
paddingTop: 70,
// paddingBottom: 40,
paddingLeft: 10,
paddingRight: 10,
},
callTipsImg: {
width: 80,
height: 60,
},
}; };
export default connect(({store}) => ({store}))(FacePage); export default connect(({store}) => ({store}))(FacePage);
...@@ -16,6 +16,9 @@ import {login} from '../utils/config'; ...@@ -16,6 +16,9 @@ import {login} from '../utils/config';
import {colors} from '../utils/common'; import {colors} from '../utils/common';
import WxFacepay from '../utils/WxFacepay'; import WxFacepay from '../utils/WxFacepay';
import {width} from '../utils/screen'; import {width} from '../utils/screen';
import Speech from '../utils/Speech';
import delay from '../utils/delay';
import {leaveTalkCall, onTalkCall} from '../utils/agora';
let pageSize = 8; // 分页大小 let pageSize = 8; // 分页大小
window.pageSize = pageSize; window.pageSize = pageSize;
...@@ -28,6 +31,7 @@ class VerticalPage extends Component { ...@@ -28,6 +31,7 @@ class VerticalPage extends Component {
contact: '', contact: '',
maskVisible: true, maskVisible: true,
visibleActive: false, visibleActive: false,
talkCall: 2, // 0请求通话,1通话中,2,已挂断通话,待机状态
}; };
async componentWillMount() { async componentWillMount() {
...@@ -41,6 +45,65 @@ class VerticalPage extends Component { ...@@ -41,6 +45,65 @@ class VerticalPage extends Component {
} }
} }
async componentDidMount() {
this.listen();
}
listen = async () => {
try {
while (!window.socket) {
await delay(1000);
}
if (!window.socket.hasListeners('talkCall')) {
// 语音通话中
window.socket.on('talkCall', this.handleTalkCall);
}
if (!window.socket.hasListeners('talkLeave')) {
// 语音通话中
window.socket.on('talkLeave', this.leaveC);
}
} catch (e) {
console.log(e);
}
};
handleTalkCall = async () => {
try {
// 加入语音通话
clearInterval(this.noTalkCall);
clearInterval(this.callTimeout);
const {data} = await this.props.dispatch({
type: 'agora/agora',
});
await onTalkCall(data);
clearInterval(this.onCallTimeout);
this.onCallTimeout = setTimeout(() => {
this.leaveC();
}, 5 * 60 * 1000);
this.setState({
talkCall: 1,
});
} catch (e) {
console.log(e);
}
};
leaveC = async () => {
try {
clearInterval(this.noTalkCall);
clearInterval(this.callTimeout);
await leaveTalkCall;
await this.props.dispatch({
type: 'agora/talkLeave',
});
this.setState({
talkCall: 2,
});
} catch (e) {
console.log(e);
}
};
authinfo = async () => { authinfo = async () => {
const rawdata = await WxFacepay.rawdata(); const rawdata = await WxFacepay.rawdata();
const {data} = await this.props.dispatch({type: 'goods/faceinfo', rawdata}); const {data} = await this.props.dispatch({type: 'goods/faceinfo', rawdata});
...@@ -140,6 +203,32 @@ class VerticalPage extends Component { ...@@ -140,6 +203,32 @@ class VerticalPage extends Component {
} }
}; };
onCall = async () => {
const {talkCall} = this.state;
if (talkCall === 2) {
Speech.speak('正在接通中请稍候');
this.talkCall();
clearInterval(this.noTalkCall);
this.noTalkCall = setInterval(() => this.talkCall(), 10000);
this.setState({
talkCall: 0,
});
clearInterval(this.callTimeout);
this.callTimeout = setTimeout(() => {
clearInterval(this.noTalkCall);
this.setState({
talkCall: 2,
});
}, 30000);
}
};
talkCall = () => {
this.props.dispatch({
type: 'agora/talkCall',
});
};
renderHeader = () => { renderHeader = () => {
return ( return (
<View style={{flex: 1, flexDirection: 'column'}}> <View style={{flex: 1, flexDirection: 'column'}}>
...@@ -179,10 +268,29 @@ class VerticalPage extends Component { ...@@ -179,10 +268,29 @@ class VerticalPage extends Component {
</View> </View>
<View style={styles.TdStyle}> <View style={styles.TdStyle}>
{item.price ? ( {item.price ? (
<Text style={styles.TdText}> // <Text style={styles.TdText}>
{' '} // {' '}
{NP.round(item.price, 2).toFixed(2)}/{item.unit}{' '} // ¥{NP.round(item.price, 2).toFixed(2)}/{item.unit}{' '}
// </Text>
<View
style={{
justifyContent: 'center',
alignItems: 'center',
flexDirection: 'row',
}}>
<Text
style={{
fontSize: 20,
textDecorationLine: 'line-through',
}}>
{NP.round(item.prePrice, 2).toFixed(2)}/
<Text style={{fontSize: 20}}>{item.unit}</Text>
</Text>
<Text style={{fontSize: 25, color: colors.textXSActive}}>
{NP.round(item.price, 2).toFixed(2)}/
<Text style={styles.TdText}>{item.unit}</Text>
</Text> </Text>
</View>
) : ( ) : (
<Text style={styles.TdText}> <Text style={styles.TdText}>
{' '} {' '}
...@@ -283,10 +391,12 @@ class VerticalPage extends Component { ...@@ -283,10 +391,12 @@ class VerticalPage extends Component {
<Image style={styles.counterText} source={counterText} /> <Image style={styles.counterText} source={counterText} />
<Image source={img24h} /> <Image source={img24h} />
</View> </View>
<Touch onPress={() => this.onCall()}>
<View style={styles.right}> <View style={styles.right}>
<Image style={styles.phone} source={phone} /> <Image style={styles.phone} source={phone} />
<Text style={styles.number}>{contact}</Text> <Text style={styles.number}>{contact}</Text>
</View> </View>
</Touch>
</View> </View>
<View style={styles.container}> <View style={styles.container}>
<View style={{flexDirection: 'row', flex: 1}}> <View style={{flexDirection: 'row', flex: 1}}>
......
import RtcEngine from 'react-native-agora';
export const onTalkCall = async data => {
try {
if (!this.engine) {
//创建 RtcEngine 实例
this.engine = await RtcEngine.create(data.appid);
}
await this.engine.disableVideo(true); // 关闭视频模块
await this.engine.enableLocalAudio(false); //调用 enableLocalAudio(false) 关闭本地采集后,系统会走媒体音量
await this.engine.muteAllRemoteAudioStreams(false); //停止/恢复接收所有音频流。
await this.engine.setDefaultMuteAllRemoteAudioStreams(false); // 设置是否默认接收音频流
await this.engine.setDefaultMuteAllRemoteVideoStreams(true); // 设置是否默认接收视频流
await this.engine.disableVideo(); //关闭视频模块
await this.engine.setAudioProfile(4, 3); //设置音频编码配置
await this.engine.adjustPlaybackSignalVolume(400); //调节本地播放的所有远端用户音量
await this.engine.adjustAudioMixingPlayoutVolume(100); //调节音乐文件的本地播放音量
await this.engine.setDefaultAudioRoutetoSpeakerphone(true); //默认从外放(扬声器)出声
//监听
// this.engine.addListener('Warning', data => {
// console.log('Warning' + data);
// });
// this.engine.addListener('Error', data => {
// console.log('Error' + data);
// });
// this.engine.addListener('JoinChannelSuccess', data => {
// console.warn('JoinChannelSuccess' + data);
// });
// this.engine.addListener('LeaveChannel', data => {
// console.warn('LeaveChannel' + data);
// });
// this.engine.addListener('UserOffline', data => {
// console.warn('UserOffline' + data);
// });
await this.engine.enableWebSdkInteroperability(true); //打开与webSDK的互通
await this.engine.setChannelProfile(0); //设置频道场景
await this.engine.setClientRole(1); //设置为主播角色
await this.engine.muteLocalAudioStream(true); //停止发送本地音频流
// 加入频道
await this.engine.joinChannel(data.token, data.channel, null, data.uid);
//判断当前是否扬声器
if (!(await this.engine.isSpeakerphoneEnabled())) {
await this.engine.setEnableSpeakerphone(true); //切换到外放
}
} catch (e) {
console.log(e);
}
};
export const leaveTalkCall = async () => {
if (this.engine) {
await this.engine.leaveChannel();
}
};
export default {onTalkCall, leaveTalkCall};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment