fix: 测试bug
This commit is contained in:
@@ -1,6 +1,12 @@
|
||||
<template>
|
||||
<view class="talk-btns" ref="talkBtnRef">
|
||||
<view class="touch-btn" @touchstart="getRecordPermission" @touchend="hideOverlayTalking" @touchmove="handleMove">
|
||||
<view class="touch-btn" v-if="!isGettingPermission" @touchstart="getRecordPermission" @touchend="hideOverlayTalking" @touchmove="handleMove">
|
||||
<view class="center-text">
|
||||
<image class="type-icon" src="@/static/images/sparring/talk-icon.png"></image>
|
||||
{{'语音对话'}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="touch-btn" v-else @click="stopRecord()">
|
||||
<view class="center-text">
|
||||
<image class="type-icon" src="@/static/images/sparring/talk-icon.png"></image>
|
||||
{{'语音对话'}}
|
||||
@@ -152,7 +158,6 @@
|
||||
unref(recordObjCom).onStart(() => {
|
||||
isRecording.value = true
|
||||
recordTime.value = 0
|
||||
setRecordTime()
|
||||
if(isGettingPermission.value){
|
||||
stopRecord();
|
||||
return
|
||||
@@ -161,21 +166,26 @@
|
||||
setTimeout(() => {
|
||||
startFlag.value = 2;
|
||||
}, 1000);
|
||||
let _recordPerm = uni.getAppAuthorizeSetting();
|
||||
let _state = _recordPerm.microphoneAuthorized;
|
||||
if (_state === 'authorized') {
|
||||
if (isStopNum.value === isStartNum.value) {
|
||||
stopRecord();
|
||||
} else {
|
||||
showTalkingModel.value = true;
|
||||
}
|
||||
setRecordTime()
|
||||
if (isStopNum.value === isStartNum.value) {
|
||||
stopRecord();
|
||||
} else {
|
||||
showTalkingModel.value = true;
|
||||
}
|
||||
});
|
||||
unref(recordObjCom).onError(() => {
|
||||
isRecording.value = false
|
||||
if(isGettingPermission.value){
|
||||
isGettingPermission.value = false
|
||||
closeModel();
|
||||
}
|
||||
common.msg('语音输入错误,请重试!')
|
||||
});
|
||||
};
|
||||
const setRecordTime = () => {
|
||||
setTimeout(()=>{
|
||||
recordTime.value += 1
|
||||
if(isRecording.value){
|
||||
recordTime.value += 1
|
||||
setRecordTime()
|
||||
}
|
||||
},1000)
|
||||
@@ -194,10 +204,10 @@
|
||||
isStopNum.value = isStartNum.value;
|
||||
try {
|
||||
if (isRecording.value && unref(recordObjCom).stop) {
|
||||
unref(recordObjCom).stop();
|
||||
setTimeout(()=>{
|
||||
isGettingPermission.value = false
|
||||
}, 500)
|
||||
}, 1000)
|
||||
unref(recordObjCom).stop();
|
||||
} else {
|
||||
isGettingPermission.value = false
|
||||
closeModel();
|
||||
@@ -209,13 +219,13 @@
|
||||
};
|
||||
const closeModel = (cb = () => {}) => {
|
||||
isStopNum.value = isStartNum.value;
|
||||
setTimeout(() => {
|
||||
isTalking.value = false;
|
||||
}, 800);
|
||||
setTimeout(() => {
|
||||
showTalkingModel.value = false;
|
||||
cb && cb();
|
||||
}, 350);
|
||||
setTimeout(() => {
|
||||
isTalking.value = false;
|
||||
}, 800);
|
||||
};
|
||||
// #endif
|
||||
//#ifndef APP-PLUS
|
||||
@@ -409,7 +419,6 @@
|
||||
background-color: #06f;
|
||||
font-weight: 400;
|
||||
position: relative;
|
||||
;
|
||||
color: #fff;
|
||||
font-size: 29rpx;
|
||||
border-radius: 23rpx;
|
||||
|
||||
@@ -0,0 +1,585 @@
|
||||
<template>
|
||||
<view class="talk-btns" ref="talkBtnRef">
|
||||
<view class="touch-btn" v-if="!isGettingPermission" @touchstart="getRecordPermission" @touchend="hideOverlayTalking" @touchmove="handleMove">
|
||||
<view class="center-text">
|
||||
<image class="type-icon" src="@/static/images/sparring/talk-icon.png"></image>
|
||||
{{'语音对话'}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="touch-btn" v-else @click="isGettingPermission = false">
|
||||
<view class="center-text">
|
||||
<image class="type-icon" src="@/static/images/sparring/talk-icon.png"></image>
|
||||
{{'语音对话'}}
|
||||
</view>
|
||||
</view>
|
||||
<uni-popup ref="talkModelRef" type="bottom" @click="hideOverlayTalking"
|
||||
mask-background-color="rgba(0,0,0,0.9)">
|
||||
<view class="overlay-box">
|
||||
<view class="circle-bg-box">
|
||||
<view class="icon-box">
|
||||
<image src="/src/static/images/course/talk-icon.png" mode=""></image>
|
||||
</view>
|
||||
</view>
|
||||
<view class="tips-box">松开发送</view>
|
||||
<view class="btns-box">
|
||||
<view :class="['close-btn', isOut ? 'is-out' : '']">
|
||||
取消
|
||||
<image class="btn-box" v-if="!isOut" src="/src/static/images/course/close.png" mode=""></image>
|
||||
<image class="btn-box" v-else src="/src/static/images/course/close-active.png" mode=""></image>
|
||||
</view>
|
||||
</view>
|
||||
<view :class="['talk-dialog', isOut ? 'is-out' : '']">
|
||||
<image src="@/static/images/course/voice-white.gif" mode="" class="gif-box"></image>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
toRefs,
|
||||
ref,
|
||||
computed,
|
||||
unref,
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
nextTick,
|
||||
watch,
|
||||
getCurrentInstance
|
||||
} from 'vue';
|
||||
import common from '../../../common/common';
|
||||
import permission from '@/common/permission.js';
|
||||
import {
|
||||
getPhoneEnvBool
|
||||
} from '@/common/common.js';
|
||||
import {
|
||||
useStorageStore
|
||||
} from '@/store/storage.js';
|
||||
import {
|
||||
onHide,
|
||||
onShow
|
||||
} from '@dcloudio/uni-app';
|
||||
|
||||
const storageStore = useStorageStore();
|
||||
const proxy = getCurrentInstance();
|
||||
const emit = defineEmits(['uploadVoice', 'startRecord']);
|
||||
const props = defineProps({
|
||||
isDisabled: {
|
||||
default: true,
|
||||
type: Boolean
|
||||
},
|
||||
isLoading: {
|
||||
default: false,
|
||||
type: Boolean
|
||||
},
|
||||
loadingText: {
|
||||
default: '发送回答中,请稍后再试!',
|
||||
type: String
|
||||
},
|
||||
formatType: {
|
||||
default: 'mp3', // 生成语音文件类型
|
||||
type: String
|
||||
},
|
||||
});
|
||||
const {
|
||||
isDisabled,
|
||||
onlyVoice,
|
||||
formatType
|
||||
} = toRefs(props);
|
||||
const isLoadingState = computed(() => props.isLoading);
|
||||
|
||||
const showTalkingModel = ref(false);
|
||||
const keyboardIsShow = ref(false);
|
||||
const talkModelRef = ref();
|
||||
storageStore.setTouchBtnZIndex(12);
|
||||
const btnZindex = computed(() => storageStore.getTouchBtnZIndex);
|
||||
|
||||
watch(
|
||||
() => showTalkingModel.value,
|
||||
(val) => (val ? talkModelRef.value.open() : talkModelRef.value.close())
|
||||
);
|
||||
watch(
|
||||
() => props.isLoading,
|
||||
() => {}, {
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
);
|
||||
watch(
|
||||
() => props.isDisabled,
|
||||
(val) => {
|
||||
if (val) {
|
||||
keyboardIsShow.value = false;
|
||||
}
|
||||
}, {
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
);
|
||||
|
||||
const answerValue = ref('');
|
||||
const talkBtnRef = ref();
|
||||
// 录音
|
||||
const audioPath = ref('');
|
||||
const audioObj = uni.createInnerAudioContext();
|
||||
//#ifdef APP-PLUS
|
||||
// app端
|
||||
const recordObjCom = ref({});
|
||||
const IsAndEnv = getPhoneEnvBool('AND');
|
||||
const isStartNum = ref(0);
|
||||
const isStopNum = ref(0);
|
||||
const isGettingPermission = ref(false)
|
||||
const initRecord = () => {
|
||||
recordObjCom.value = uni.getRecorderManager();
|
||||
unref(recordObjCom)?.onStop((res, duration) => {
|
||||
isRecording.value = false
|
||||
if(isGettingPermission.value){
|
||||
isGettingPermission.value = false
|
||||
closeModel();
|
||||
return
|
||||
}
|
||||
audioPath.value = res.tempFilePath;
|
||||
if (!isOut.value) {
|
||||
if (startFlag.value !== 2) {
|
||||
closeModel(() => {
|
||||
nextTick(() => {
|
||||
common.msg('说话时间太短,没有听清!');
|
||||
});
|
||||
});
|
||||
} else {
|
||||
closeModel();
|
||||
emit('uploadVoice', audioPath.value, recordTime.value);
|
||||
}
|
||||
} else {
|
||||
closeModel();
|
||||
}
|
||||
});
|
||||
unref(recordObjCom).onStart(() => {
|
||||
isRecording.value = true
|
||||
recordTime.value = 0
|
||||
setRecordTime()
|
||||
if(isGettingPermission.value){
|
||||
stopRecord();
|
||||
return
|
||||
}
|
||||
startFlag.value = 1;
|
||||
setTimeout(() => {
|
||||
startFlag.value = 2;
|
||||
}, 1000);
|
||||
let _recordPerm = uni.getAppAuthorizeSetting();
|
||||
let _state = _recordPerm.microphoneAuthorized;
|
||||
if (_state === 'authorized') {
|
||||
if (isStopNum.value === isStartNum.value) {
|
||||
stopRecord();
|
||||
} else {
|
||||
showTalkingModel.value = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
const setRecordTime = () => {
|
||||
setTimeout(()=>{
|
||||
if(isRecording.value){
|
||||
recordTime.value += 1
|
||||
setRecordTime()
|
||||
}
|
||||
},1000)
|
||||
}
|
||||
const isRecording = ref(false)
|
||||
const recordTime = ref(0)
|
||||
const startFlag = ref(1);
|
||||
const startRecord = () => {
|
||||
isStartNum.value += 1;
|
||||
unref(recordObjCom).start({
|
||||
format: formatType.value
|
||||
});
|
||||
};
|
||||
|
||||
const stopRecord = () => {
|
||||
isStopNum.value = isStartNum.value;
|
||||
try {
|
||||
if (isRecording.value && unref(recordObjCom).stop) {
|
||||
setTimeout(()=>{
|
||||
isGettingPermission.value = false
|
||||
}, 1000)
|
||||
unref(recordObjCom).stop();
|
||||
} else {
|
||||
isGettingPermission.value = false
|
||||
closeModel();
|
||||
}
|
||||
} catch {
|
||||
isGettingPermission.value = false
|
||||
closeModel();
|
||||
}
|
||||
};
|
||||
const closeModel = (cb = () => {}) => {
|
||||
isStopNum.value = isStartNum.value;
|
||||
setTimeout(() => {
|
||||
showTalkingModel.value = false;
|
||||
cb && cb();
|
||||
}, 350);
|
||||
setTimeout(() => {
|
||||
isTalking.value = false;
|
||||
}, 800);
|
||||
};
|
||||
// #endif
|
||||
//#ifndef APP-PLUS
|
||||
const recordObjCom = ref({});
|
||||
const initRecord = () => {};
|
||||
// #endif
|
||||
onMounted(async () => {
|
||||
initRecord?.();
|
||||
});
|
||||
// 录音结束
|
||||
|
||||
// 记录 按下移动位置
|
||||
const touchX = ref(0);
|
||||
const touchY = ref(0);
|
||||
const baseY = ref(0);
|
||||
const windowInfo = uni.getWindowInfo();
|
||||
// 计算是否超出按下盒子位置
|
||||
const isOut = computed(() => {
|
||||
let _btnHeight = (windowInfo.screenWidth / 750) * 234;
|
||||
let moveVal = windowInfo.screenHeight - touchY.value > _btnHeight;
|
||||
return moveVal;
|
||||
});
|
||||
const outScreen = computed(() => {
|
||||
windowInfo.screenHeight - touchY.value <= 0;
|
||||
});
|
||||
const recNum = ref(1);
|
||||
const activeNum = ref(1);
|
||||
const hasPermission = ref(false)
|
||||
|
||||
const getRecordPermission = async (obj) => {
|
||||
if (isDisabled.value) return;
|
||||
if (isTalking.value) {
|
||||
common.msg('操作频繁,请稍后重试!');
|
||||
setTimeout(() => {
|
||||
isTalking.value = false;
|
||||
}, 500);
|
||||
return;
|
||||
}
|
||||
// #ifdef APP-PLUS
|
||||
if (!hasPermission.value) {
|
||||
let _res = await getPermission()
|
||||
if (_res) {
|
||||
hasPermission.value = true
|
||||
setTimeout(()=>{
|
||||
if(!isGettingPermission.value){
|
||||
showOverlayTalking(obj);
|
||||
}else{
|
||||
isGettingPermission.value = false
|
||||
}
|
||||
},100)
|
||||
}
|
||||
} else {
|
||||
showOverlayTalking(obj);
|
||||
}
|
||||
// #endif
|
||||
};
|
||||
const getPermission = async () => {
|
||||
// #ifdef APP-PLUS
|
||||
// 安卓端
|
||||
if (IsAndEnv) {
|
||||
let _recordPerm = await permission.requestAndroidPermission('android.permission.RECORD_AUDIO');
|
||||
if (_recordPerm !== 1) {
|
||||
showTalkingModel.value = false;
|
||||
let res = await common.show('提示信息', '当前页面需要使用的录音权限,是否前往开启?', true, '取消', '确定')
|
||||
if (res) {
|
||||
// 去开启权限
|
||||
permission.gotoAppPermissionSetting();
|
||||
} else {
|
||||
// 取消
|
||||
common.navigateBack();
|
||||
}
|
||||
return false
|
||||
} else {
|
||||
// isGettingPermission.value = false
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
let _recordPerm = uni.getAppAuthorizeSetting();
|
||||
let _state = _recordPerm.microphoneAuthorized;
|
||||
if (_state === 'denied') {
|
||||
common.show('提示信息', '当前页面需要使用的录音权限,是否前往开启?', true, '取消', '确定').then((res) => {
|
||||
if (res) {
|
||||
// 去开启权限
|
||||
uni.openAppAuthorizeSetting();
|
||||
} else {
|
||||
// 取消
|
||||
common.navigateBack();
|
||||
}
|
||||
});
|
||||
return false
|
||||
} else if (_state === 'not determined') {
|
||||
// startRecord()
|
||||
return true
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
// //#ifndef APP-PLUS
|
||||
// return true
|
||||
// // #endif
|
||||
}
|
||||
const isMoving = ref(false);
|
||||
const isTalking = ref(false);
|
||||
const showOverlayTalking = (obj) => {
|
||||
if (showTalkingModel.value) return;
|
||||
if (isGettingPermission.value) {
|
||||
if(isRecording.value){
|
||||
stopRecord()
|
||||
}else{
|
||||
isGettingPermission.value = false
|
||||
}
|
||||
return
|
||||
}
|
||||
if (isLoadingState.value) {
|
||||
uni.showToast({
|
||||
title: props.loadingText,
|
||||
icon: 'none',
|
||||
duration: 1000
|
||||
});
|
||||
return;
|
||||
}
|
||||
isMoving.value = true;
|
||||
isTalking.value = true;
|
||||
emit('startRecord');
|
||||
recNum.value += 1;
|
||||
let _recnum = recNum.value
|
||||
if (!isDisabled.value) {
|
||||
touchX.value = obj.changedTouches[0].pageX;
|
||||
touchY.value = obj.changedTouches[0].pageY;
|
||||
baseY.value = obj.currentTarget.offsetTop;
|
||||
//#ifdef APP-PLUS
|
||||
// canStart.value = false
|
||||
startRecord();
|
||||
// #endif
|
||||
setTimeout(() => {
|
||||
if (_recnum === recNum.value) {
|
||||
hideOverlayTalking(recNum.value);
|
||||
}
|
||||
}, 59 * 1010);
|
||||
} else {
|
||||
showTalkingModel.value = false;
|
||||
uni.showToast({
|
||||
title: '暂无问题需要回答!',
|
||||
icon: 'none',
|
||||
duration: 1000
|
||||
});
|
||||
}
|
||||
};
|
||||
const hideOverlayTalking = (obj) => {
|
||||
isMoving.value = false;
|
||||
if (!showTalkingModel.value) return;
|
||||
//#ifdef APP-PLUS
|
||||
stopRecord();
|
||||
// #endif
|
||||
};
|
||||
|
||||
const handleMove = (obj) => {
|
||||
if (isMoving.value) {
|
||||
touchX.value = obj.changedTouches[0].pageX;
|
||||
touchY.value = obj.changedTouches[0].pageY;
|
||||
if (outScreen.value) {
|
||||
hideOverlayTalking(obj);
|
||||
}
|
||||
}
|
||||
};
|
||||
onShow(()=>{
|
||||
// stopRecord()
|
||||
// if(isGettingPermission.value){
|
||||
// hideOverlayTalking()
|
||||
// }
|
||||
})
|
||||
onHide(()=>{
|
||||
isGettingPermission.value = true
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.talk-btns {
|
||||
height: 150rpx;
|
||||
background-color: #fff;
|
||||
padding: 25rpx 30rpx 0;
|
||||
position: relative;
|
||||
z-index: v-bind(btnZindex);
|
||||
|
||||
.touch-btn {
|
||||
height: 92rpx;
|
||||
// box-shadow: 0 8rpx 20rpx 0 rgba(0, 0, 0, 0.06);
|
||||
text-align: center;
|
||||
line-height: 92rpx;
|
||||
background-color: #06f;
|
||||
font-weight: 400;
|
||||
position: relative;
|
||||
;
|
||||
color: #fff;
|
||||
font-size: 29rpx;
|
||||
border-radius: 23rpx;
|
||||
|
||||
.center-text {
|
||||
height: 35rpx;
|
||||
line-height: 35rpx;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.type-icon {
|
||||
width: 35rpx;
|
||||
height: 35rpx;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.overlay-box {
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
// justify-content: flex-end;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.circle-bg-box {
|
||||
height: 234rpx;
|
||||
background: url(@/static/images/course/talking.png) no-repeat;
|
||||
background-size: cover;
|
||||
position: relative;
|
||||
|
||||
.icon-box {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
margin-left: -17rpx;
|
||||
margin-top: -24rpx;
|
||||
width: 34rpx;
|
||||
height: 48rpx;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tips-box {
|
||||
height: 40rpx;
|
||||
line-height: 40rpx;
|
||||
color: #c0c0c0;
|
||||
text-align: center;
|
||||
margin: 12rpx 0 24rpx;
|
||||
}
|
||||
|
||||
.btns-box {
|
||||
height: 270rpx;
|
||||
// padding: 0 120rpx;
|
||||
width: 154rpx;
|
||||
margin: 0 auto 100rpx;
|
||||
overflow: hidden;
|
||||
font-size: 28rpx;
|
||||
text-align: center;
|
||||
line-height: 116rpx;
|
||||
|
||||
.close-btn {
|
||||
float: left;
|
||||
height: 100%;
|
||||
width: 154rpx;
|
||||
overflow: hidden;
|
||||
color: #999;
|
||||
|
||||
&.is-out {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.translate-btn {
|
||||
float: right;
|
||||
height: 100%;
|
||||
width: 154rpx;
|
||||
overflow: hidden;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.btn-box {
|
||||
width: 100%;
|
||||
height: 154rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.talk-dialog {
|
||||
width: 506rpx;
|
||||
height: 234rpx;
|
||||
margin: 0 auto;
|
||||
background-color: #06f;
|
||||
border-radius: 32rpx;
|
||||
position: relative;
|
||||
|
||||
&.is-out {
|
||||
background-color: #ff3e49;
|
||||
|
||||
&::after {
|
||||
background-color: #ff3e49;
|
||||
}
|
||||
}
|
||||
|
||||
.gif-box {
|
||||
position: absolute;
|
||||
width: 200rpx;
|
||||
height: 80rpx;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
|
||||
background-color: #06f;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
bottom: -22rpx;
|
||||
left: 50%;
|
||||
margin-left: -22rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.white-bg-box {
|
||||
height: 365rpx;
|
||||
background-color: #fff;
|
||||
overflow: hidden;
|
||||
border-radius: 32rpx 32rpx 0 0;
|
||||
padding: 58rpx 36rpx;
|
||||
|
||||
.box-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
line-height: 46rpx;
|
||||
margin-bottom: 46rpx;
|
||||
}
|
||||
|
||||
.box-btns {
|
||||
height: 46rpx;
|
||||
line-height: 46rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
color: #999;
|
||||
|
||||
.is-active {
|
||||
color: #06f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .uv-input__content__field-wrapper__field {
|
||||
padding-right: 60rpx;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user