Merge branch 'dev-20250930' of http://25.13.9.101:9000/K17_AITS/tra-app into dev-20250930
This commit is contained in:
+2
-1
@@ -36,4 +36,5 @@ VITE_APP_BASE_H5_API_Url = 'http://25.18.122.65:7001'
|
||||
# VITE_APP_BASE_H5_API_Url_TRAEXAM = 'http://25.64.16.140:9604'
|
||||
# 于嘉文
|
||||
# VITE_APP_BASE_H5_API_Url_TRAEXAM = 'http://25.64.16.143:9604'
|
||||
|
||||
# 孙宇
|
||||
VITE_APP_BASE_H5_API_Url_TRAEXAM = 'http://25.64.16.139:9604'
|
||||
|
||||
@@ -119,8 +119,6 @@
|
||||
// result.anserResult
|
||||
|
||||
let answerText = props.item?.my_answer || props.item.anserResult || [];
|
||||
|
||||
console.log('answerText', props.item.anserResult);
|
||||
// item_answer 是答题结果,可以是对象 数组 字符串类型
|
||||
const item_answer = ref(typeof answerText === 'string' ? answerText.split(',') : answerText);
|
||||
const feedback_click = () => {
|
||||
|
||||
@@ -0,0 +1,368 @@
|
||||
<template>
|
||||
<view class="question-info">
|
||||
<view class="qns-type">问答题</view>
|
||||
<view class="question_text">
|
||||
{{ dataInfo.qnsContent }}
|
||||
</view>
|
||||
<view class="qns-desc">你的答案:</view>
|
||||
<view class="ans-list">
|
||||
<esQuestionAnswer v-for="item in dataInfo.analyContentVos" :dataInfo="item" :intrctWay="item.ossKey?'02':'01'"/>
|
||||
</view>
|
||||
<view class="analysis_div">
|
||||
<view class="analysis_title">
|
||||
<view class="success_answer">正确答案:{{ dataInfo.itemAnswer }}</view>
|
||||
</view>
|
||||
<view class="analysis_note">题目解析:{{ dataInfo?.analyContent }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
computed,
|
||||
unref,
|
||||
ref,
|
||||
toRefs,
|
||||
watch,
|
||||
onMounted
|
||||
} from 'vue';
|
||||
import {
|
||||
onUnload
|
||||
} from '@dcloudio/uni-app';
|
||||
import esQuestionAnswer from './esQuestionAnswer.vue'
|
||||
const props = defineProps({
|
||||
dataInfo: {
|
||||
default: () => ({
|
||||
talkingText: '',
|
||||
talkingVoice: ''
|
||||
}),
|
||||
type: Object
|
||||
}
|
||||
});
|
||||
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 initData = (item) => {
|
||||
return {
|
||||
|
||||
}
|
||||
}
|
||||
// 声音播放初始化
|
||||
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.talkingVoice,
|
||||
(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).talkingVoice) {
|
||||
setTimeout(() => {
|
||||
talkVoiceObj.value.src = unref(dataInfo).talkingVoice;
|
||||
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).talkingVoice;
|
||||
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">
|
||||
.qns-type {
|
||||
width: 108rpx;
|
||||
height: 46rpx;
|
||||
background: #267eff;
|
||||
border-radius: 8rpx;
|
||||
font-family: PingFangSC;
|
||||
font-weight: 500;
|
||||
font-size: 25rpx;
|
||||
color: #ffffff;
|
||||
text-align: center;
|
||||
line-height: 46rpx;
|
||||
}
|
||||
.question_text {
|
||||
font-family: PingFangSC;
|
||||
font-weight: 500;
|
||||
font-size: 30rpx;
|
||||
color: #333333;
|
||||
line-height: 48rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
.qns-desc{
|
||||
font-size: 30rpx;
|
||||
margin-top: 20rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
.talking-info {
|
||||
padding: 20rpx;
|
||||
border-radius: 15rpx;
|
||||
background-color: #06f;
|
||||
padding-bottom: 30rpx;
|
||||
position: relative;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
float: right;
|
||||
|
||||
.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: right;
|
||||
|
||||
.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
.question-info{
|
||||
margin-bottom: 20rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
.ans-list{
|
||||
overflow: hidden;
|
||||
}
|
||||
.analysis_div {
|
||||
width: 100%;
|
||||
.analysis_title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin: 12rpx 0 28rpx 0;
|
||||
|
||||
.success_answer {
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.your_answer {
|
||||
.success {
|
||||
color: #15b859;
|
||||
}
|
||||
.error {
|
||||
color: #f5212d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.analysis_note {
|
||||
font-family: PingFangSC;
|
||||
font-weight: 500;
|
||||
font-size: 30rpx;
|
||||
color: #666666;
|
||||
line-height: 48rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -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>
|
||||
@@ -0,0 +1,862 @@
|
||||
<!-- type:
|
||||
0,纯文本信息不翻译
|
||||
1,语音回答 ,
|
||||
2 文本回答
|
||||
3 段落信息
|
||||
4 问题信息
|
||||
5 统计信息
|
||||
6 发送loading状态
|
||||
7 教师反馈文本不翻译
|
||||
8 问题反馈信息
|
||||
9 已学完当前知识点反馈信息
|
||||
-->
|
||||
<template>
|
||||
<view :class="['ai-answer', props.class]" :id="props.id" v-if="[3,4,5,8,9].indexOf(type) >= 0">
|
||||
<!-- 对话信息 -->
|
||||
<view :class="['talking-info', [4].indexOf(type) >= 0 ? 'talking-info-less':''] ">
|
||||
<!-- 语音加载状态 -->
|
||||
<view :class="['talking-gif', !voiceLoading && (activeVoiceId === dataInfo.id)?'is-play':'']" v-if="!([3, 4, 5, 8, 9].indexOf(type) >= 0)">
|
||||
<CommonLoading color="#06f" v-show="voiceLoading"/>
|
||||
</view>
|
||||
<view class="talking-cont">
|
||||
<!-- 题干/段落内容 -->
|
||||
<view class="talking-num"> {{dataInfo.titleNum||''}} </view>
|
||||
<text class="talking-text" v-if="[3, 5, 6, 9].indexOf(type) >= 0 && !dataInfo.isLoading">
|
||||
{{ showContent }}
|
||||
</text>
|
||||
<text class="talking-text" v-if="[4].indexOf(type) >= 0 && dataInfo.qnsTyp === 'ES'">
|
||||
<!-- 请您思考并作答:<br> -->
|
||||
{{ showContent }}
|
||||
</text>
|
||||
<!-- 试题问题 -->
|
||||
<Subject v-if="[4, 8].indexOf(type) >= 0 && dataInfo.qnsTyp !== 'ES'"
|
||||
:isPreview="!isLast"
|
||||
:item="subjectInfo"
|
||||
:mode="mode"
|
||||
:clearResult="type === 4"
|
||||
@subject_click="subject_click" />
|
||||
<esQuestion
|
||||
v-if="[4, 8].indexOf(type) >= 0 && dataInfo.qnsTyp === 'ES'"
|
||||
:dataInfo="esSubjectInfo"
|
||||
/>
|
||||
<!-- 试题问题反馈 -->
|
||||
<!-- <RadioSubjectRequest v-if="[8].indexOf(type) >= 0 && dataInfo.qnsTyp !== 'ES'" :item="dataInfo" :mode="mode" @subject_click="subject_click" /> -->
|
||||
<!-- 段落图片视频预览 -->
|
||||
<view v-if="type === 3" style="overflow: hidden;">
|
||||
<ImagePreview class="cont-img-box" v-if="(dataInfo.imageAddrs||[]).length>0" :imgId="dataInfo.imageAddrs[0]" :previewDetail="true"></ImagePreview>
|
||||
<VideoPreview class="cont-img-box" v-if="(dataInfo.vidoAddrs||[]).length>0" :fileId="dataInfo.vidoAddrs[0]"></VideoPreview>
|
||||
</view>
|
||||
<!-- 维度信息预览 -->
|
||||
<view v-if="[4, 8].indexOf(type) >= 0 && dataInfo.qnsTyp === 'ES'" style="padding-top: 16rpx;">
|
||||
<ChartFour v-if="esSubjectInfo?.evalSettingVos?.length === 4" :dataList="esSubjectInfo.evalSettingVos" :score="intrctGrade"/>
|
||||
<ChartThree v-if="esSubjectInfo?.evalSettingVos?.length === 3" :dataList="esSubjectInfo.evalSettingVos" :score="intrctGrade"/>
|
||||
<ChartFive v-if="esSubjectInfo?.evalSettingVos?.length === 5" :dataList="esSubjectInfo.evalSettingVos" :score="intrctGrade"/>
|
||||
</view>
|
||||
<!-- 参考答案 -->
|
||||
<view class="talking-text" v-if="type === 5 && !dataInfo.isLoading" style="overflow: hidden;">
|
||||
参考答案:{{ dataInfo.itemAnswer }}
|
||||
</view>
|
||||
<!-- 举例预览 -->
|
||||
<view class="talking-text" v-if="type === 3 && dataInfo.knoExampie " style="overflow: hidden;">
|
||||
举例:{{ dataInfo.knoExampie }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="btns-cont" v-show="!dataInfo.isLoading" v-if="!([3, 8, 4].indexOf(type) >= 0)">
|
||||
<!-- 重新播放 -->
|
||||
<view class="replay-btn" @click.stop="restartPlay" v-if="!([5, 8, 9].indexOf(type) >= 0)">
|
||||
<image class="icon" src="@/static/images/course/replay.png" style="width: 100%;height: 100%;"></image>
|
||||
</view>
|
||||
<!-- 播放/暂停 -->
|
||||
<view class="play-btn" v-if="!([5, 8, 9].indexOf(type) >= 0)">
|
||||
<image
|
||||
class="icon"
|
||||
src="@/static/images/course/play.png"
|
||||
style="width: 100%;height: 100%;"
|
||||
@click.stop="playVoice()"
|
||||
v-show="!isPlaying"
|
||||
></image>
|
||||
<image
|
||||
class="icon"
|
||||
v-show="isPlaying"
|
||||
src="@/static/images/course/pause.png"
|
||||
style="width: 100%;height: 100%;"
|
||||
@click.stop="pauseVoice"
|
||||
></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- ai回答 -->
|
||||
<view :class="['ai-answer', props.class]" :id="props.id" v-if="[7].indexOf(type) >= 0">
|
||||
<view :class="['talking-info', [4,7].indexOf(type) >= 0 ? 'talking-info-less':''] ">
|
||||
<view class="talking-cont">
|
||||
<view class="talking-text">
|
||||
{{ showContent }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 用户对话 -->
|
||||
<view :class="['user-answer', props.class]" :id="props.id" v-else-if="[1, 2].indexOf(type) >= 0">
|
||||
<view class="talking-info">
|
||||
<view class="right-time">{{voiceTime}}</view>
|
||||
<view class="talking-cont">
|
||||
<text :class="['talking-text translate-text loading']" >
|
||||
{{ showContent }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="btns-cont">
|
||||
<!-- <view class="replay-btn">
|
||||
<image class="icon" src="@/static/images/course/replay.png" style="width: 100%;height: 100%;"></image>
|
||||
</view> -->
|
||||
<view class="play-btn">
|
||||
<image class="icon"
|
||||
@click.stop="playQnsVoice('qns', dataInfo)"
|
||||
v-show="!isPlaying"
|
||||
src="@/static/images/course/play-blue.png"
|
||||
style="width: 100%;height: 100%;"
|
||||
></image>
|
||||
<image class="icon"
|
||||
v-show="isPlaying"
|
||||
@click.stop="pauseVoice"
|
||||
src="@/static/images/course/stop-blue.png"
|
||||
style="width: 100%;height: 100%;"
|
||||
></image>
|
||||
</view>
|
||||
<view class="icon text-btn" v-if="type === 1" @click.stop="translateVoice(dataInfo)">文</view>
|
||||
<view class="icon text-right-btn" @click.stop="finishQuestion(dataInfo)" v-show="isLast">完成</view>
|
||||
<view
|
||||
class="icon text-right-btn"
|
||||
@click.stop="withdraw"
|
||||
v-show="showWithdraw"
|
||||
>撤回
|
||||
<!-- v-show="showWithdraw" -->
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view :class="['user-answer', props.class]" :id="props.id" v-else-if="[0, 6].indexOf(type) >= 0">
|
||||
<view class="talking-info-less">
|
||||
<text class="talking-text" v-if="type === 0">
|
||||
{{ showContent }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else></view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { watch, unref, ref, toRefs, computed, nextTick,onMounted } from 'vue'
|
||||
import ImagePreview from '@/components/image-preview/image-preview.vue'
|
||||
import VideoPreview from '@/components/image-preview/video-preview.vue'
|
||||
import { downloadVoiceFile, uploadVoiceFile, getAudioByText } from "@/api/common.js"
|
||||
import { studyParagraphOverApi, getAskAboutRawApi } from "@/api/study.js"
|
||||
import ChartFour from "@/pages/course/components/chartFour.vue"
|
||||
import ChartThree from "@/pages/course/components/chartThree.vue"
|
||||
import ChartFive from '@/pages/course/components/chartFive.vue'
|
||||
import common from '@/common/common';
|
||||
import { useStorageStore } from "@/store/storage.js"
|
||||
import { onUnload } from '@dcloudio/uni-app'
|
||||
import esQuestion from './esQuestion.vue'
|
||||
import Subject from '@/components/examination/subject.vue'
|
||||
// import RadioSubjectRequest from '@/pages/wrong_question_record/components/radio-subject.vue'
|
||||
|
||||
const storageStore = useStorageStore()
|
||||
const audioCacheObj = computed(() => storageStore.audioObj)
|
||||
const props = defineProps({
|
||||
type:{
|
||||
default: 0,// 1: userAnswer 0: AIAnswer
|
||||
type:[Number,String]
|
||||
},
|
||||
dataInfo: {
|
||||
default: () => ({}),
|
||||
type: Object
|
||||
},
|
||||
teacherInfo: {
|
||||
default: () => ({}),
|
||||
type: Object
|
||||
},
|
||||
activeVoiceId:{
|
||||
default:'',
|
||||
type: String
|
||||
},
|
||||
isLast:{
|
||||
default:false,
|
||||
type: Boolean
|
||||
},
|
||||
isPlaying:{
|
||||
default:false,
|
||||
type: Boolean
|
||||
},
|
||||
voiceRate: {
|
||||
default: '1.0',
|
||||
type:[Number,String],
|
||||
},
|
||||
isTransform:{
|
||||
default: false,
|
||||
type: Boolean
|
||||
},
|
||||
lastQuestionInfo: {
|
||||
default: () => ({}),
|
||||
type: Object
|
||||
},
|
||||
class: {
|
||||
default:'',
|
||||
type: String
|
||||
},
|
||||
id: {
|
||||
default:'',
|
||||
type: String
|
||||
}
|
||||
})
|
||||
|
||||
const { type, dataInfo, activeVoiceId, isPlaying, isLast, lastQuestionInfo, teacherInfo} = toRefs(props)
|
||||
const emit = defineEmits(['changePlay', 'nextQuestion', 'withdraw', 'finishQuestion', 'answerQuestion'])
|
||||
// 声音播放初始化
|
||||
const talkVoiceObj = ref(uni.createInnerAudioContext())
|
||||
talkVoiceObj.value.playbackRate = Number(props.voiceRate)
|
||||
const itemVoice = ref('')
|
||||
const subjectInfo = computed(()=>{
|
||||
return {
|
||||
...dataInfo.value,
|
||||
...(dataInfo.value?.traQnsInfoVo||{}),
|
||||
my_answer: dataInfo.value?.traQnsInfoVo?.anserResult||''
|
||||
}
|
||||
})
|
||||
const esSubjectInfo = computed(()=>{
|
||||
return {
|
||||
...dataInfo.value,
|
||||
...(dataInfo.value.itemVos && dataInfo.value.itemVos.length>0
|
||||
?
|
||||
dataInfo.value.itemVos[0]
|
||||
:{})
|
||||
}
|
||||
})
|
||||
const intrctGrade = computed(()=>{
|
||||
let _sum = 0
|
||||
let _arr = esSubjectInfo.value.evalSettingVos||[]
|
||||
_arr.forEach(t=>{
|
||||
_sum += t.anlyGrade
|
||||
})
|
||||
return _sum
|
||||
})
|
||||
const mode = ref('study') // 考试 examination 练习practice 学习study
|
||||
|
||||
const showWithdraw = computed(()=>{
|
||||
let _isMe = unref(lastQuestionInfo).qstLogId === unref(dataInfo).qstLogId
|
||||
let _isQuestion = unref(lastQuestionInfo).isQuestion
|
||||
return _isMe && _isQuestion
|
||||
})
|
||||
|
||||
const voiceLoading = ref(false)
|
||||
watch(() => props.teacherInfo,(val) => {
|
||||
itemVoice.value = ''
|
||||
talkVoiceObj.value.src = ''
|
||||
},{
|
||||
deep: true,
|
||||
immediate: true
|
||||
})
|
||||
watch(() => props.isPlaying,(val) => {
|
||||
if(!val){
|
||||
talkVoiceObj.value?.pause()
|
||||
}
|
||||
},{
|
||||
deep: true,
|
||||
immediate: true
|
||||
})
|
||||
watch(() => props.voiceRate,(val) => {
|
||||
talkVoiceObj.value.playbackRate = Number(val)
|
||||
},{
|
||||
deep: true,
|
||||
immediate: true
|
||||
})
|
||||
watch(()=>props.lastTalkingInfo,()=>{},{
|
||||
deep: true,
|
||||
immediate: true
|
||||
})
|
||||
watch(() => props.dataInfo,()=>{},{
|
||||
deep: true,
|
||||
immediate: true
|
||||
})
|
||||
const showGoOnStudyBtn = computed(()=> {
|
||||
if(!(showNextBtn.value && isLast.value)){
|
||||
return false
|
||||
}
|
||||
if(type.value === 5){
|
||||
return true
|
||||
}
|
||||
if(type.value === 8){
|
||||
return !!dataInfo.value.traQnsInfoVo?.judgeResult
|
||||
}
|
||||
if(type.value === 9){
|
||||
return dataInfo.value.stdyStat === 'Y'
|
||||
}
|
||||
return false
|
||||
})
|
||||
const transformContent = ref('')
|
||||
const showContentBase = computed(() => {
|
||||
if(props.isTransform){
|
||||
return transformContent.value
|
||||
}else{
|
||||
if(props.type === 1) return unref(dataInfo)?.chatContent || unref(dataInfo)?.talkingContent
|
||||
else if(props.type === 2) return unref(dataInfo)?.chatContent || unref(dataInfo)?.talkingContent
|
||||
else if(props.type === 3) return unref(dataInfo)?.chatContent || unref(dataInfo)?.pgrphContent
|
||||
else if(props.type === 4) return unref(dataInfo)?.chatContent || unref(dataInfo)?.qnsContent
|
||||
else if(props.type === 5) return unref(dataInfo)?.chatContent || unref(dataInfo)?.analyContent
|
||||
else if(props.type === 9) return unref(dataInfo)?.chatContent || unref(dataInfo)?.analyContent
|
||||
else if(props.type === 0) return unref(dataInfo)?.chatContent || unref(dataInfo)?.talkingContent
|
||||
else return unref(dataInfo)?.chatContent || unref(dataInfo)?.talkingContent
|
||||
}
|
||||
})
|
||||
const showContent = computed(() => {
|
||||
let _str = showContentBase.value || ''
|
||||
return _str.replace(/\/n/g,"\n")
|
||||
})
|
||||
|
||||
const changeBr = (str = '') => {
|
||||
return str.replace(/\/n/g,"\n")
|
||||
}
|
||||
const voiceTime = ref('')
|
||||
const itemInfo = ref({})
|
||||
onMounted(()=>{
|
||||
initVoice()
|
||||
})
|
||||
onUnload(()=>{
|
||||
pauseVoice()
|
||||
})
|
||||
talkVoiceObj.value.onEnded(()=>{
|
||||
emit('changePlay', '')
|
||||
talkVoiceObj.value.src = ''
|
||||
})
|
||||
talkVoiceObj.value.onError(()=>{
|
||||
talkVoiceObj.value.src = ''
|
||||
})
|
||||
const pauseVoice = () => {
|
||||
if(!talkVoiceObj.value) return
|
||||
talkVoiceObj.value.pause()
|
||||
emit('changePlay', '')
|
||||
}
|
||||
// 重播
|
||||
const restartPlay = () => {
|
||||
if(itemVoice.value){
|
||||
emit('changePlay', '')
|
||||
emit('changePlay', unref(dataInfo)?.id)
|
||||
setTimeout(()=>{
|
||||
talkVoiceObj.value.src = itemVoice.value
|
||||
talkVoiceObj.value.seek(0)
|
||||
talkVoiceObj.value.play()
|
||||
},100)
|
||||
}else{
|
||||
playVoice()
|
||||
}
|
||||
}
|
||||
const playVoice = (readType = 'pgth') =>{
|
||||
let _content = showContent.value
|
||||
if(!_content){
|
||||
common.msg('没有可以播放的文字信息!')
|
||||
return
|
||||
}
|
||||
emit('changePlay', unref(dataInfo)?.id)
|
||||
// readType 阅读内容类型pgrh段落/qns问题
|
||||
if(talkVoiceObj.value.src && talkVoiceObj.value.src === itemVoice.value) {
|
||||
emit('changePlay', unref(dataInfo)?.id)
|
||||
talkVoiceObj.value.play()
|
||||
return
|
||||
}
|
||||
talkVoiceObj.value.src = ''
|
||||
if(itemVoice.value){
|
||||
setTimeout(()=>{
|
||||
talkVoiceObj.value.src = itemVoice.value
|
||||
talkVoiceObj.value.play()
|
||||
},100)
|
||||
}else{
|
||||
voiceLoading.value = true
|
||||
let _type = props.type == 2 ? 'ans' : props.type == 3 ? 'pgrh' : props.type == 4 ? 'qns' : ''
|
||||
let _readId = props.type == 2 ? unref(dataInfo)?.intrctId : props.type == 3 ? unref(dataInfo)?.pgrphId : props.type == 4 ? unref(dataInfo)?.qnsId : ''
|
||||
let _params = {
|
||||
crsId: unref(dataInfo)?.crsId || '',
|
||||
pgrphId: unref(dataInfo)?.pgrphId || '',
|
||||
qnsId: unref(dataInfo)?.qnsId || '',
|
||||
readType: _type,// 2 文本回答 3, 段落信息 4 问题信息
|
||||
teachNo: unref(teacherInfo)?.teacherNo, // 必填
|
||||
readId: _readId
|
||||
// content: _content
|
||||
}
|
||||
|
||||
|
||||
let _url = '/trastudy/traStdyInfo/readContent?' + Object.keys(_params).map(t=>{
|
||||
return encodeURIComponent(t) + '=' + encodeURIComponent(_params[t])
|
||||
}).join('&')
|
||||
|
||||
storageStore.getStorageById('audio', _url + _params.teachNo, (url)=>{
|
||||
if(url){
|
||||
voiceLoading.value = false
|
||||
itemVoice.value = url
|
||||
talkVoiceObj.value.src = url
|
||||
talkVoiceObj.value.play()
|
||||
}else{
|
||||
downloadVoiceFile(_url).then(res=>{
|
||||
if(res?.data){
|
||||
common.msg(res.data.message)
|
||||
return
|
||||
}
|
||||
voiceLoading.value = false
|
||||
itemVoice.value = res.tempFilePath
|
||||
talkVoiceObj.value.src = res.tempFilePath
|
||||
talkVoiceObj.value.play()
|
||||
storageStore.setStorage('audio', _url + _params.teachNo, itemVoice.value)
|
||||
}).catch((err)=>{
|
||||
voiceLoading.value = false
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
const saveFile = (buffer,filePath, cb = ()=>{}) => {
|
||||
let fileManager = uni.getFileSystemManager()
|
||||
fileManager.writeFile({
|
||||
filePath: filePath,
|
||||
data: buffer,
|
||||
encoding: 'binary',
|
||||
success: cb,
|
||||
file: ()=>{
|
||||
voiceLoading.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
const initVoice = (readType = 'qns', item, isplay=false) => {
|
||||
if(unref(dataInfo).talkingVoice){
|
||||
itemVoice.value = unref(dataInfo).talkingVoice
|
||||
talkVoiceObj.value.src = itemVoice.value
|
||||
setTimeout(()=>{
|
||||
setVoiceTime(0)
|
||||
},100)
|
||||
}
|
||||
}
|
||||
const setVoiceTime = (sum) => {
|
||||
sum += 1
|
||||
if(talkVoiceObj.value.duration){
|
||||
voiceTime.value = ( Math.ceil(talkVoiceObj.value.duration) || 0 ) + 's'
|
||||
}else{
|
||||
if(sum === 10) {
|
||||
voiceTime.value = 0 + 's'
|
||||
return
|
||||
}
|
||||
setTimeout(()=>{
|
||||
setVoiceTime(sum)
|
||||
},200)
|
||||
}
|
||||
}
|
||||
const playQnsVoice = (readType = 'qns', item) =>{
|
||||
if(type.value === 2){
|
||||
// 文本转语音
|
||||
playVoice(readType)
|
||||
return
|
||||
}
|
||||
// readType 阅读内容类型pgrh段落/qns问题
|
||||
emit('changePlay', unref(dataInfo)?.id)
|
||||
setTimeout(()=>{
|
||||
itemVoice.value = item.talkingVoice
|
||||
talkVoiceObj.value.src = item.talkingVoice
|
||||
talkVoiceObj.value.play()
|
||||
},100)
|
||||
}
|
||||
const translateLoading = ref(false)
|
||||
// 翻译
|
||||
const translateVoice = (item) =>{
|
||||
if(!item.talkingVoice) return
|
||||
translateLoading.value = true
|
||||
uploadVoiceFile(item.talkingVoice,{}).then(res=>{
|
||||
let _data = JSON.parse(res.data)
|
||||
item.talkingContent = _data.body.text
|
||||
translateLoading.value = false
|
||||
}).catch(()=>{
|
||||
translateLoading.value = false
|
||||
})
|
||||
}
|
||||
const showNextBtn = ref(true)
|
||||
const showGoonBtn = computed(()=>{
|
||||
return showNextBtn.value && [3, 6].indexOf(props.type) >= 0 && isLast.value // && !isPlaying.value
|
||||
})
|
||||
const isClick = ref(false)
|
||||
const goOnGetQues = () => {
|
||||
if(isClick.value) return
|
||||
clickNow()
|
||||
if([5,8].indexOf(props.type) >= 0){
|
||||
// 完成问题
|
||||
emit('nextQuestion', unref(dataInfo))
|
||||
}else if([3].indexOf(props.type) >= 0){
|
||||
// 完成段落
|
||||
emit('nextQuestion', unref(dataInfo), 'overGraph')
|
||||
}else if([9].indexOf(props.type) >= 0){
|
||||
// 下一段落
|
||||
emit('nextQuestion', unref(dataInfo), 'nextGraph')
|
||||
}
|
||||
}
|
||||
const clickNow = () => {
|
||||
isClick.value = true
|
||||
setTimeout(()=>{
|
||||
isClick.value = false
|
||||
},800)
|
||||
}
|
||||
const goOnRestart = () => {
|
||||
if(isClick.value) return
|
||||
clickNow()
|
||||
emit('nextQuestion', unref(dataInfo), 'reStart')
|
||||
}
|
||||
const goOnRestartPrgh = () => {
|
||||
if(isClick.value) return
|
||||
clickNow()
|
||||
emit('nextQuestion', unref(dataInfo), 'reStartPrgh')
|
||||
}
|
||||
// 撤回
|
||||
const withdraw = () => {
|
||||
if(isClick.value) return
|
||||
clickNow()
|
||||
emit('withdraw', unref(dataInfo))
|
||||
}
|
||||
// 完成
|
||||
const finishQuestion = (data) => {
|
||||
if(isClick.value) return
|
||||
clickNow()
|
||||
emit('finishQuestion',data)
|
||||
}
|
||||
// 答题 选择
|
||||
const subject_click = (type, data) => {
|
||||
if(['answer', 'choose'].includes(type)){
|
||||
emit('answerQuestion', {
|
||||
...data,
|
||||
...unref(dataInfo)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.ai-answer{
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
margin-bottom: 20rpx;
|
||||
.user-info{
|
||||
overflow: hidden;
|
||||
.avatar-box{
|
||||
float: left;
|
||||
width: 76rpx;
|
||||
height: 76rpx;
|
||||
border: 3rpx solid #fff;
|
||||
background-color: #f1f1f1;
|
||||
overflow: hidden;
|
||||
border-radius: 10rpx;
|
||||
margin-right: 16rpx;
|
||||
margin-bottom: 16rpx;
|
||||
.img-box{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.ai-name{
|
||||
float: left;
|
||||
color: #666;
|
||||
font-size: 25rpx;
|
||||
line-height: 35rpx;
|
||||
.ai-name-desc{
|
||||
color: #999;
|
||||
margin-left: 16rpx;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
.talking-info{
|
||||
padding: 20rpx;
|
||||
border-radius: 15rpx;
|
||||
background-color: #fff;
|
||||
overflow: hidden;
|
||||
padding-bottom: 30rpx;
|
||||
width: 100%;
|
||||
&.talking-info-less{
|
||||
float: left;
|
||||
min-width: 400rpx;
|
||||
padding-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-gif.gif) no-repeat;
|
||||
background-size: contain;
|
||||
}
|
||||
}
|
||||
.talking-cont{
|
||||
margin: 16rpx 0;
|
||||
overflow: hidden;
|
||||
min-height: 48rpx;
|
||||
&.last-cont{
|
||||
margin-bottom: 0;
|
||||
.talking-text{
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
.talking-num{
|
||||
font-size: 30rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
.talking-text{
|
||||
font-size: 28rpx;
|
||||
line-height: 48rpx;
|
||||
min-height: 48rpx;
|
||||
margin-bottom: 20rpx;
|
||||
word-break: break-all;
|
||||
white-space: pre-line;
|
||||
&.loading{
|
||||
// min-height: 36px;
|
||||
}
|
||||
}
|
||||
.cont-img-box{
|
||||
width: 433rpx;
|
||||
height: 269rpx;
|
||||
border-radius: 15rpx;
|
||||
overflow: hidden;
|
||||
background-color: #fafafa;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
}
|
||||
.btns-cont{
|
||||
overflow: hidden;
|
||||
border-top: 3rpx solid #eee;
|
||||
.replay-btn{
|
||||
float: left;
|
||||
width: 46rpx;
|
||||
height: 46rpx;
|
||||
overflow: hidden;
|
||||
margin-right: 16rpx;
|
||||
margin-top: 25rpx;
|
||||
}
|
||||
.play-btn{
|
||||
float: left;
|
||||
width: 46rpx;
|
||||
height: 46rpx;
|
||||
overflow: hidden;
|
||||
margin-right: 16rpx;
|
||||
margin-top: 25rpx;
|
||||
}
|
||||
.next-learn-btn{
|
||||
float: left;
|
||||
padding: 0 60rpx 0 20rpx;
|
||||
height: 62rpx;
|
||||
line-height: 62rpx;
|
||||
font-size: 30rpx;
|
||||
background-color: #06f;
|
||||
color: #fff;
|
||||
border-radius: 8rpx;
|
||||
margin-top: 16rpx;
|
||||
margin-right: 16rpx;
|
||||
position: relative;
|
||||
&.replay-study-btn{
|
||||
float: right;
|
||||
}
|
||||
&.restart{
|
||||
background-color: #eaf2ff;
|
||||
color: #06f;
|
||||
}
|
||||
.icon-iamge{
|
||||
width: 25rpx;
|
||||
height: 25rpx;
|
||||
position: absolute;
|
||||
right: 20rpx;
|
||||
top: 50%;
|
||||
margin-top: -12rpx;
|
||||
}
|
||||
}
|
||||
.replay-learn-btn{
|
||||
float: left;
|
||||
padding: 0 60rpx 0 20rpx;
|
||||
height: 62rpx;
|
||||
line-height: 62rpx;
|
||||
font-size: 30rpx;
|
||||
color: #06f;
|
||||
background-color: #eaf2ff;
|
||||
border-radius: 8rpx;
|
||||
margin-top: 16rpx;
|
||||
margin-right: 16rpx;
|
||||
position: relative;
|
||||
.icon-iamge{
|
||||
width: 25rpx;
|
||||
height: 25rpx;
|
||||
position: absolute;
|
||||
right: 20rpx;
|
||||
top: 50%;
|
||||
margin-top: -12rpx;
|
||||
}
|
||||
}
|
||||
.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.user-answer{
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
margin-bottom: 20rpx;
|
||||
.user-info{
|
||||
overflow: hidden;
|
||||
.avatar-box{
|
||||
float: right;
|
||||
width: 76rpx;
|
||||
height: 76rpx;
|
||||
border: 3rpx solid #fff;
|
||||
background-color: #f1f1f1;
|
||||
overflow: hidden;
|
||||
border-radius: 10rpx;
|
||||
margin-left: 16rpx;
|
||||
margin-bottom: 16rpx;
|
||||
.img-box{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.ai-name{
|
||||
float: right;
|
||||
color: #666;
|
||||
font-size: 25rpx;
|
||||
line-height: 35rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.talking-info-less{
|
||||
padding: 20rpx;
|
||||
float: right;
|
||||
border-radius: 15rpx;
|
||||
background-color: #06f;
|
||||
color: #fff;
|
||||
}
|
||||
.talking-info{
|
||||
padding: 20rpx;
|
||||
border-radius: 15rpx;
|
||||
background-color: #06f;
|
||||
padding-bottom: 30rpx;
|
||||
position: relative;
|
||||
color: #fff;
|
||||
.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-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 #eee;
|
||||
.replay-btn{
|
||||
float: left;
|
||||
width: 46rpx;
|
||||
height: 46rpx;
|
||||
overflow: hidden;
|
||||
margin-right: 16rpx;
|
||||
margin-top: 25rpx;
|
||||
}
|
||||
.play-btn{
|
||||
float: left;
|
||||
width: 46rpx;
|
||||
height: 46rpx;
|
||||
overflow: hidden;
|
||||
margin-right: 16rpx;
|
||||
margin-top: 25rpx;
|
||||
}
|
||||
.text-btn{
|
||||
float: left;
|
||||
width: 46rpx;
|
||||
height: 46rpx;
|
||||
overflow: hidden;
|
||||
line-height: 46rpx;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
margin-right: 16rpx;
|
||||
margin-top: 25rpx;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,8 +1,173 @@
|
||||
<template>
|
||||
<view class="course-record-page">
|
||||
<view class="top-bg"></view>
|
||||
<view class="bot-bg"></view>
|
||||
<view class="course-study-body">
|
||||
<view class="body-title">
|
||||
<uv-icon class="arrow-icon" name="arrow-left" @click="backRouter()" />
|
||||
课程学习记录
|
||||
</view>
|
||||
<scroll-view class="talking-list" :scroll-y="true" :scroll-top="scrollTop" :show-scrollbar="false"
|
||||
:scroll-with-animation="true">
|
||||
<talkingItem v-for="item in talkingList" :type="item.type"
|
||||
:dataInfo="item" :activeVoiceId="activeVoiceTalkingItemId" :isPlaying="activeVoiceTalkingItemId === item.id"
|
||||
:voiceRate="chooseRate" />
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import {
|
||||
onLoad
|
||||
} from '@dcloudio/uni-app';
|
||||
import {
|
||||
ref,
|
||||
unref,
|
||||
computed,
|
||||
watch
|
||||
} from 'vue'
|
||||
import {
|
||||
queryTraStudyExecuteRecord
|
||||
} from '@/api/courseRecord.js'
|
||||
import common from '@/common/common';
|
||||
import talkingItem from './components/talkingItem.vue'
|
||||
|
||||
const stdyId = ref('')
|
||||
const scrollTop = ref(0)
|
||||
const showOrder = ref(1)
|
||||
const pgrphNum = ref(1)
|
||||
|
||||
const activeVoiceTalkingItemId = ref('')
|
||||
const chooseRate = ref('1.0')
|
||||
|
||||
onLoad((params) => {
|
||||
stdyId.value = params.stdyId
|
||||
getRecordInfo()
|
||||
})
|
||||
const talkingRecord = ref([])
|
||||
const talkingList = computed(()=>{
|
||||
let _arr = []
|
||||
talkingRecord.value.forEach((t,index)=> {
|
||||
_arr.push({
|
||||
...t,
|
||||
id: 'prgh-'+index,
|
||||
chatContent:( t.pgrphContent || ''),
|
||||
titleNum: '知识点'+(index+1)+':',
|
||||
type: 3
|
||||
})
|
||||
if(t.qnsInfoVos && t.qnsInfoVos.length>0){
|
||||
t.qnsInfoVos.forEach((k,indexk)=>{
|
||||
if(k.qnsTyp === 'ES'){
|
||||
_arr.push({
|
||||
...k,
|
||||
chatContent: (k.qnsContent || ''),
|
||||
titleNum: '问题'+(indexk+1)+':',
|
||||
type: 8,
|
||||
id: 'qns-'+index+'-'+indexk,
|
||||
})
|
||||
}else{
|
||||
_arr.push({
|
||||
...k,
|
||||
chatContent:(k.qnsContent || ''),
|
||||
titleNum: '问题'+(indexk+1)+':',
|
||||
type: 8,
|
||||
id: 'qns-'+index+'-'+indexk,
|
||||
isQuestion: true,
|
||||
my_answer: [],
|
||||
backend_answer: [],
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
return _arr
|
||||
})
|
||||
const getRecordInfo = () => {
|
||||
queryTraStudyExecuteRecord({
|
||||
stdyId: stdyId.value
|
||||
}).then(res => {
|
||||
talkingRecord.value = res.body
|
||||
})
|
||||
}
|
||||
const backRouter = () => {
|
||||
common.navigateBack()
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
<style scoped lang="scss">
|
||||
|
||||
.course-record-page {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
padding-top: var(--status-bar-height);
|
||||
.top-bg {
|
||||
background: linear-gradient(16deg, rgba(234, 246, 255, 0) 0%, #e6eafd 100%);
|
||||
height: 480rpx;
|
||||
width: 750rpx;
|
||||
}
|
||||
|
||||
.bot-bg {
|
||||
background: linear-gradient(136deg, rgba(234, 246, 255, 0) 0%, #e6eafd 100%);
|
||||
width: 750rpx;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.course-study-body {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 0 0rpx;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-top: v-bind(pageTopPadding);
|
||||
|
||||
.body-title {
|
||||
height: 90rpx;
|
||||
text-align: center;
|
||||
font-size: 33rpx;
|
||||
padding-top: 10rpx;
|
||||
line-height: 46rpx;
|
||||
box-sizing: border-box;
|
||||
font-weight: 500;
|
||||
color: #000;
|
||||
position: relative;
|
||||
|
||||
.arrow-icon {
|
||||
position: absolute;
|
||||
left: 21rpx;
|
||||
top: 5rpx;
|
||||
color: #000;
|
||||
padding: 15rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.talking-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 10rpx 30rpx;
|
||||
background: url(@/static/images/course/study-bg.png) no-repeat;
|
||||
background-size: cover;
|
||||
background-position: center bottom;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
|
||||
.talking-list-cont {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.talking-item {
|
||||
margin-bottom: 46rpx;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user