feat: 课程学习记录

This commit is contained in:
杨航
2025-08-26 17:28:46 +08:00
parent e8251c26e3
commit f114794c22
6 changed files with 1732 additions and 5 deletions
@@ -0,0 +1,333 @@
<template>
<view class="talking-info-es" v-if="intrctWay === '02'">
<view :class="['talking-gif', 'is-play']">
<CommonLoading color="#fff" v-show="voiceLoading" />
</view>
<view class="right-time">{{ voiceTime }}</view>
<view class="talking-cont">
<text :class="['talking-text translate-text loading']" v-show="!translateLoading">
{{ showContent }}
</text>
<view class="talking-text translate-text" v-if="translateLoading">
<CommonLoading color="#fff" />
</view>
</view>
<view class="btns-cont">
<view class="play-btn">
<image class="icon" @click="playVoice" src="@/static/images/course/play-blue.png"
style="width: 100%; height: 100%"></image>
</view>
<view class="text-btn" @click.stop="translateVoice()"></view>
</view>
</view>
<!-- 01纯文字 -->
<view class="talking-info-es talking-info-text" v-else-if="intrctWay === '01'">
<view class="talking-cont">
<text :class="['talking-text translate-text loading']">
{{ showContent }}
</text>
</view>
</view>
<view class="talking-info talking-info-loading" v-else-if="intrctWay === '00'">
<view :class="['talking-gif']">
<CommonLoading color="#fff" />
</view>
</view>
</template>
<script setup>
import {
computed,
unref,
ref,
toRefs,
watch,
onMounted
} from 'vue';
import {
onUnload
} from '@dcloudio/uni-app';
const props = defineProps({
dataInfo: {
default: () => ({
ossAddr: ''
}),
type: Object
},
text: {
// 当前激活的语音
default: '',
type: String
},
voice: {
// 当前激活的语音
default: '',
type: String
},
activeVoiceId: {
// 当前激活的语音
default: '',
type: String
},
intrctWay: {
default: '',
type: String
}
});
const {
dataInfo
} = toRefs(props);
const intrctWay = computed(() => {
console.log('props.intrctWay', props.intrctWay);
return props.intrctWay;
});
const emit = defineEmits(['changePlay', 'buutton_click']);
watch(
() => props.dataInfo,
() => {}, {
deep: true,
immediate: true
}
);
// 声音播放初始化
const talkVoiceObj = ref(null);
const isPlaying = ref(false);
const voiceLoading = ref(false);
const translateLoading = ref(false);
const voiceTime = ref('');
const itemVoice = ref('');
// 中间显示的文字
const showContent = computed(() => {
return props.text || props.dataInfo.anserResult || '';
});
onMounted(() => {
initVoice();
});
onUnload(() => {
pauseVoice();
});
watch(
() => props.dataInfo.ossAddr,
(val) => {
if (val) {
initVoice();
}
}, {
deep: true,
immediate: true
}
);
// 按钮点击
const buutton_click = (type) => {
emit('buutton_click', type, props.dataInfo);
};
const pauseVoice = () => {
if (!talkVoiceObj.value) return;
talkVoiceObj.value.pause();
isPlaying.value = false;
emit('changePlay', '');
};
const playVoice = () => {
emit('changePlay', unref(dataInfo)?.id);
if (talkVoiceObj.value && talkVoiceObj.value.src) {
talkVoiceObj.value.play();
return;
} else {
talkVoiceObj.value.src = '';
if (unref(dataInfo).ossAddr) {
setTimeout(() => {
talkVoiceObj.value.src = unref(dataInfo).ossAddr;
talkVoiceObj.value.play();
isPlaying.value = true;
}, 100);
}
}
};
const initVoice = () => {
talkVoiceObj.value = uni.createInnerAudioContext();
talkVoiceObj.value.onEnded(() => {
emit('changePlay', '');
talkVoiceObj.value.src = '';
});
talkVoiceObj.value.onError(() => {
talkVoiceObj.value.src = '';
});
if (unref(dataInfo).intrctWay === '02') {
itemVoice.value = unref(dataInfo).ossAddr;
talkVoiceObj.value.src = itemVoice.value;
setTimeout(() => {
setVoiceTime(0);
}, 100);
}
};
const setVoiceTime = (sum) => {
sum += 1;
if (Math.ceil(talkVoiceObj.value.duration) > 0) {
voiceTime.value = (Math.ceil(talkVoiceObj.value.duration) || 1) + 's';
} else {
if (sum === 20) {
voiceTime.value = 0 + 's';
return;
}
setTimeout(() => {
setVoiceTime(sum);
}, 200);
}
};
</script>
<style scoped lang="scss">
.talking-info-es {
padding: 20rpx;
border-radius: 15rpx;
background-color: #06f;
padding-bottom: 30rpx;
position: relative;
color: #fff;
width: 100%;
float: left;
margin-bottom: 20rpx;
.talking-gif {
width: 200rpx;
height: 38rpx;
background: url(@/static/images/course/voice-gray.png) no-repeat;
background-size: contain;
padding-left: 168rpx;
&.is-play {
background: url(@/static/images/course/voice-white.gif) no-repeat;
background-size: contain;
}
}
.right-time {
position: absolute;
right: 20rpx;
top: 20rpx;
font-size: 28rpx;
height: 38rpx;
line-height: 38rpx;
}
&.talking-info-loading {
padding-bottom: 20rpx;
}
&.talking-info-text {
padding-bottom: 20rpx;
width: auto;
min-width: calc(100vw * 0.45);
float: left;
.talking-cont {
margin-top: 0rpx;
}
}
.talking-cont {
margin-top: 16rpx;
overflow: hidden;
.talking-text {
font-size: 28rpx;
line-height: 48rpx;
margin-bottom: 20rpx;
word-break: break-all;
white-space: pre-line;
overflow: hidden;
&.translate-text {
min-height: 48rpx;
}
}
}
.btns-cont {
overflow: hidden;
border-top: 3rpx solid #1f79ff;
display: flex;
justify-content: space-between;
padding-top: 20rpx;
margin-top: 22rpx;
.replay-btn {
float: left;
width: 46rpx;
height: 46rpx;
overflow: hidden;
margin-right: 16rpx;
margin-top: 25rpx;
}
.play-btn {
width: 46rpx;
height: 46rpx;
margin-right: 16rpx;
}
.text-btn {
width: 46rpx;
height: 46rpx;
overflow: hidden;
line-height: 46rpx;
text-align: center;
color: #fff;
margin-right: 16rpx;
background-color: #67a4ff;
font-size: 24rpx;
font-weight: bold;
border-radius: 20rpx;
}
.text-right-btn {
float: right;
padding: 0 10rpx;
height: 46rpx;
overflow: hidden;
line-height: 46rpx;
text-align: center;
margin-left: 16rpx;
margin-top: 25rpx;
}
.next-btn {
float: right;
padding: 0 60rpx 0 20rpx;
height: 62rpx;
line-height: 62rpx;
font-size: 30rpx;
background-color: #06f;
color: #fff;
border-radius: 8rpx;
margin-top: 16rpx;
position: relative;
.icon-iamge {
width: 25rpx;
height: 25rpx;
position: absolute;
right: 20rpx;
top: 50%;
margin-top: -12rpx;
}
}
.btns-cont-button-text {
font-weight: 400;
font-size: 30rpx;
color: #ffffff;
line-height: 30rpx;
text-align: left;
font-style: normal;
margin-left: 10rpx;
}
}
}
</style>