封装学习任务和考试中心列表item组件

This commit is contained in:
田岩
2025-08-25 16:47:35 +08:00
parent 0f52f465c8
commit 1ba8a0c843
18 changed files with 899 additions and 720 deletions
+46 -10
View File
@@ -1,6 +1,6 @@
<template>
<view class="talking-info" v-if="intrctWay === '02'">
<view :class="['talking-gif', (props.activeVoiceId === dataInfo.id) ? 'is-play' : '']">
<view :class="['talking-gif', 'is-play']">
<CommonLoading color="#fff" v-show="voiceLoading" />
</view>
<view class="right-time">{{voiceTime}}</view>
@@ -14,9 +14,9 @@
</view>
<view class="btns-cont">
<view class="play-btn">
<image class="icon" v-show="!(props.activeVoiceId === dataInfo.id)" @click="playVoice"
src="@/static/images/course/play-blue.png" style="width: 100%;height: 100%;"></image>
<image class="icon" v-show="props.activeVoiceId === dataInfo.id"
<!-- <image class="icon" v-show="!(props.activeVoiceId === dataInfo.id)" @click="playVoice"
src="@/static/images/course/play-blue.png" style="width: 100%;height: 100%;"></image> -->
<image class="icon"
@click.stop="pauseVoice" src="@/static/images/course/stop-blue.png"
style="width: 100%;height: 100%;"></image>
<!-- <view class="icon text-btn" v-if="type === 1" @click.stop="translateVoice(dataInfo)"></view> -->
@@ -30,8 +30,18 @@
{{ showContent }}
</text>
</view>
<view class="btns-cont">
<view class="play-btn">
<!-- <image class="icon" v-show="!(props.activeVoiceId === dataInfo.id)" @click="playVoice"
src="@/static/images/course/play-blue.png" style="width: 100%;height: 100%;"></image> -->
<image class="icon"
@click.stop="pauseVoice" src="@/static/images/course/stop-blue.png"
style="width: 100%;height: 100%;"></image>
<view class="icon text-btn" @click.stop="buutton_click(dataInfo)">重答</view>
</view>
</view>
</view>
<view class="talking-info talking-info-loading" v-else>
<view class="talking-info talking-info-loading" v-else-if="intrctWay === '00'">
<view :class="['talking-gif']">
<CommonLoading color="#fff" />
</view>
@@ -52,20 +62,39 @@
} from '@dcloudio/uni-app';
const props = defineProps({
dataInfo: {
default: () => ({}),
default: () => ({
talkingText:'',
talkingVoice:'',
}),
type: Object
},
activeVoiceId: {
text: { // 当前激活的语音
default: '',
type: String
},
voice: { // 当前激活的语音
default: '',
type: String
},
activeVoiceId: { // 当前激活的语音
default: '',
type: String
},
intrctWay: {
default: '',
type: String
},
})
const {
activeVoiceId,
dataInfo
} = toRefs(props)
const intrctWay = ref('02')
const intrctWay = computed(() => {
console.log('props.intrctWay', props.intrctWay);
return props.intrctWay
})
const emit = defineEmits(['changePlay'])
watch(() => props.dataInfo, () => {}, {
deep: true,
@@ -80,8 +109,10 @@
const voiceTime = ref('')
const itemVoice = ref('')
// 中间显示的文字
const showContent = computed(() => {
return dataInfo.value.talkingText || ''
return props.text || ''
})
onMounted(() => {
initVoice()
@@ -97,6 +128,11 @@
deep: true,
immediate: true
})
// 按钮点击
const buutton_click = (type) => {
}
const pauseVoice = () => {
if (!talkVoiceObj.value) return
talkVoiceObj.value.pause()
@@ -86,17 +86,19 @@
.option_item {
width: 100%;
height: 108rpx;
min-height: 108rpx;
border-radius: 15rpx;
margin-top: 32rpx;
font-family: PingFangSC;
font-weight: 500;
font-size: 30rpx;
text-align: left;
font-style: normal;
padding-left: 52rpx;
display: flex;
align-items: center;
margin-top: 32rpx;
padding: 10rpx 10rpx 10rpx 52rpx;
// display: -webkit-box;
@@ -106,21 +108,18 @@
overflow: hidden;
.option_text {
flex: 1;
white-space: nowrap;
// white-space: nowrap;
/* 强制不换行 */
overflow: hidden;
/* 超出部分隐藏 */
text-overflow: ellipsis;
}
.img {
width: 30rpx;
// height: 30rpx;
padding-right: 30rpx;
height: 30rpx;
padding-right: 20rpx;
}
}
</style>
+46 -19
View File
@@ -6,8 +6,9 @@
<view class="fl1"></view>
<view class="right">
<!-- 反馈中心 -->
<view class="mark_and_feedback_div" v-if="['examination'].includes(props.mode)">
<view class="mark_and_feedback_div" v-if="['examination', 'practice'].includes(props.mode)">
<image
v-if="props.mode === 'examination'"
:src="markIcon(props.item.mark ? '#0066FF' : '#ABABAB')"
class="img"
@click="mark_click()"
@@ -25,7 +26,12 @@
</view>
<view class="option_div">
<template v-if="qnsTyp === 'ES'">
<!-- <questionVue @changePlay="changePlay" :dataInfo="talkingInfo" :activeVoiceId="questionValue"></questionVue> -->
<questionVue
:intrctWay="subject_data.es_status"
:dataInfo="{}"
:text="subject_data.anserResult"
:activeVoiceId="subject_data.qnsId"
></questionVue>
</template>
<template v-else>
<radioSubjectItem
@@ -52,7 +58,7 @@
确定
</uv-button>
</view>
<view class="analysis_div" v-if="!clearResult && ['study', 'mistake', 'settlement'].includes(props.mode)">
<view class="analysis_div" v-if="!clearResult && ['study', 'mistake', 'settlement', 'practice'].includes(props.mode)">
<view class="analysis_title">
<view class="success_answer">正确答案{{ correctResultLabel.join('') }}</view>
<view class="your_answer">
@@ -67,6 +73,7 @@
<script setup>
import { ref, reactive, onMounted, nextTick, computed, toRaw } from 'vue';
import radioSubjectItem from './radio-subject-item.vue';
import questionVue from './question.vue';
import { markIcon, feedbackIcon } from '@/common/imgSvg';
import { SUBJECT_TYPE } from '@/enum.js';
const customStyle = {
@@ -110,7 +117,7 @@
set: (val) => emit('update:modelValue', val)
});
// result.anserResult
let answerText = props.item?.my_answer || props.item.anserResult || [];
console.log('answerText', props.item.anserResult);
const item_answer = ref(typeof answerText === 'string' ? answerText.split(',') : []);
@@ -124,13 +131,13 @@
const qnsTyp = computed(() => props.item.qnsTyp);
// 正确答案选项
const correctResultLabel = computed(() =>
subject_data.itemVos.filter((res) => res.correctFlag === 'R').map((res) => res.itemNo)
subject_data.value.itemVos.filter((res) => res.correctFlag === 'R').map((res) => res.itemNo)
);
// 我的答案选项
const myResultLabel = computed(() => {
if (!props.item.anserResult) return ['无'];
const anserResultArray = props.item.anserResult.split(',');
return subject_data.itemVos.filter((res) => anserResultArray.includes(res.itemId)).map((res) => res.itemNo);
return subject_data.value.itemVos.filter((res) => anserResultArray.includes(res.itemId)).map((res) => res.itemNo);
});
// 判断选项是否完全正确
const right_or_wrong_class = computed(
@@ -138,18 +145,36 @@
correctResultLabel.value.length === myResultLabel.value.length &&
myResultLabel.value.every((res) => correctResultLabel.value.includes(res))
);
const subject_data = reactive({
qnsId: props.item.qnsId,
qnsContent: props.item.qnsContent,
qnsTyp: props.item.qnsTyp,
analyContent: props.item.analyContent,
itemVos: (props.item.itemVos ?? []).map((res) => ({
...res,
correctFlag: props.clearResult ? '' : res.correctFlag
}))
const subject_data = computed({
get: () => {
return {
qnsId: props.item.qnsId,
qnsContent: props.item.qnsContent,
qnsTyp: props.item.qnsTyp,
es_status: props.item.es_status,
analyContent: props.item.analyContent,
anserResult: props.item.anserResult,
itemVos: (props.item.itemVos ?? []).map((res) => ({
...res,
correctFlag: props.clearResult ? '' : res.correctFlag
}))
}
},
set: (val) => {}
});
// const subject_data = reactive({
// qnsId: props.item.qnsId,
// qnsContent: props.item.qnsContent,
// qnsTyp: props.item.qnsTyp,
// analyContent: props.item.analyContent,
// itemVos: (props.item.itemVos ?? []).map((res) => ({
// ...res,
// correctFlag: props.clearResult ? '' : res.correctFlag
// }))
// });
// 题类型
const subject_type_text = computed(() => SUBJECT_TYPE.find((res) => qnsTyp.value === res.value)?.label || '');
// 点击答题
@@ -183,7 +208,7 @@
qnsTyp: props.item.qnsTyp,
qnsId: props.item.qnsId,
answer: item_answer.value,
answerItems: subject_data.itemVos.filter((t) => item_answer.value.includes(t.itemId))
answerItems: subject_data.value.itemVos.filter((t) => item_answer.value.includes(t.itemId))
});
};
</script>
@@ -202,7 +227,9 @@
padding: 4rpx;
}
}
.option_div{
padding-top: 20rpx;
}
.option_div_button {
width: 100%;
height: 84rpx;
+2
View File
@@ -122,6 +122,8 @@
// #ifdef APP-PLUS
const recorderManager = uni.getRecorderManager();
// #endif
// const innerAudioContext = uni.createInnerAudioContext();
const startTimer = ref(null); // 延迟启动的定时器ID
const startFlag = ref(1);