提交错题本
This commit is contained in:
@@ -3,20 +3,25 @@
|
||||
<view class="line">
|
||||
<text class="tr">维度评分:</text>
|
||||
<text class="td">{{ dimension_all_score }}</text>
|
||||
|
||||
<view class="td_success_error_img">
|
||||
<image :src="select_status_icon" class="img"></image>
|
||||
</view>
|
||||
</view>
|
||||
<view class="line" v-for="item in evalSettingVos">
|
||||
<text class="tr">{{ item.gradeDimens }}:</text>
|
||||
<text class="td">{{ item.anlyGrade }}</text>
|
||||
<view class="your_answer" v-if="item.dimensCode==='01'">
|
||||
<view class="your_answer" v-if="item.dimensCode === '01'">
|
||||
<rich-text :nodes="highlightedText" class="content" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, nextTick, computed, toRaw, watch } from 'vue';
|
||||
import { optionErrorIcon, optionSuccessIcon } from '@/common/imgSvg';
|
||||
|
||||
const emit = defineEmits(['click_option']);
|
||||
const props = defineProps({
|
||||
value: {
|
||||
@@ -37,27 +42,30 @@
|
||||
});
|
||||
const evalSettingVos = computed(() => props.value.evalSettingVos);
|
||||
const status = computed(() => (props.judgeResult ? 'success' : 'error'));
|
||||
const keywords = computed(() => {
|
||||
if (!props.value.relKeyword) return [];
|
||||
return props.value.relKeyword.split(',').map(key => key.trim());
|
||||
const select_status_icon = computed(() => {
|
||||
if (props.judgeResult) {
|
||||
return optionSuccessIcon('#15B859');
|
||||
} else {
|
||||
return optionErrorIcon();
|
||||
}
|
||||
});
|
||||
|
||||
const keywords = computed(() => {
|
||||
if (!props.value.relKeyword) return [];
|
||||
return props.value.relKeyword.split(',').map((key) => key.trim());
|
||||
});
|
||||
|
||||
const highlightedText = computed(() => {
|
||||
// 如果没有关键词,直接返回原文本
|
||||
if (!keywords.value.length) return props.answerText;
|
||||
// 构建正则表达式,匹配所有关键词(不区分大小写)
|
||||
// 对关键词进行转义,避免特殊字符影响正则
|
||||
const escapedKeywords = keywords.value.map(keyword =>
|
||||
keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
||||
);
|
||||
|
||||
// 创建正则表达式,g表示全局匹配,i表示不区分大小写
|
||||
const regex = new RegExp(`(${escapedKeywords.join('|')})`, 'gi');
|
||||
|
||||
// 替换匹配到的关键词,用span包裹并添加高亮样式
|
||||
return props.answerText.replace(regex, (match) =>
|
||||
`<span class="highlight">${match}</span>`
|
||||
);
|
||||
// 如果没有关键词,直接返回原文本
|
||||
if (!keywords.value.length) return '你的答案:' + props.answerText;
|
||||
// 构建正则表达式,匹配所有关键词(不区分大小写)
|
||||
// 对关键词进行转义,避免特殊字符影响正则
|
||||
const escapedKeywords = keywords.value.map((keyword) => keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
|
||||
|
||||
// 创建正则表达式,g表示全局匹配,i表示不区分大小写
|
||||
const regex = new RegExp(`(${escapedKeywords.join('|')})`, 'gi');
|
||||
|
||||
// 替换匹配到的关键词,用span包裹并添加高亮样式
|
||||
return '你的答案:' + props.answerText.replace(regex, (match) => `<span class="highlight">${match}</span>`);
|
||||
});
|
||||
const dimension_all_score = computed(() => {
|
||||
return (
|
||||
@@ -77,7 +85,6 @@
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
.success {
|
||||
background-color: #e7f8ed;
|
||||
.td {
|
||||
@@ -96,12 +103,12 @@
|
||||
color: #f5212d;
|
||||
}
|
||||
}
|
||||
.your_answer{
|
||||
.your_answer {
|
||||
:deep(.highlight) {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.analysis_div {
|
||||
margin-top: 30rpx;
|
||||
|
||||
@@ -109,6 +116,7 @@
|
||||
padding: 22rpx 15rpx 15rpx 34rpx;
|
||||
.line {
|
||||
margin: 12rpx 0;
|
||||
position: relative;
|
||||
}
|
||||
.tr {
|
||||
font-weight: 600;
|
||||
@@ -119,13 +127,23 @@
|
||||
font-weight: 600;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
.your_answer{
|
||||
.your_answer {
|
||||
font-weight: 500;
|
||||
font-size: 30rpx;
|
||||
color: #333333;
|
||||
line-height: 40rpx;
|
||||
line-height: 46rpx;
|
||||
text-align: left;
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
.td_success_error_img {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
.img {
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
padding-right: 20rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -32,10 +32,18 @@
|
||||
</view>
|
||||
<view class="text-btn" v-if="!textShow" @click.stop="translateVoice()">文</view>
|
||||
<view class="fl1"></view>
|
||||
<view v-show="!props.isPreview && props.button_again_show" class="btns-cont-button-text" @click.stop="buutton_click('again')">
|
||||
<view
|
||||
v-show="!props.isPreview && props.button_again_show"
|
||||
class="btns-cont-button-text"
|
||||
@click.stop="buutton_click('again')"
|
||||
>
|
||||
重答
|
||||
</view>
|
||||
<view v-show="!props.isPreview && props.button_complete_show" class="btns-cont-button-text" @click.stop="buutton_click('complete')">
|
||||
<view
|
||||
v-show="!props.isPreview && props.button_complete_show"
|
||||
class="btns-cont-button-text"
|
||||
@click.stop="buutton_click('complete')"
|
||||
>
|
||||
完成
|
||||
</view>
|
||||
</view>
|
||||
@@ -49,8 +57,16 @@
|
||||
</view>
|
||||
<view class="btns-cont" v-show="!props.isPreview">
|
||||
<view class="fl1"></view>
|
||||
<view v-if="props.button_again_show" class="btns-cont-button-text" @click.stop="buutton_click('again')">重答</view>
|
||||
<view v-if="props.button_complete_show" class="btns-cont-button-text" @click.stop="buutton_click('complete')">完成</view>
|
||||
<view v-if="props.button_again_show" class="btns-cont-button-text" @click.stop="buutton_click('again')">
|
||||
重答
|
||||
</view>
|
||||
<view
|
||||
v-if="props.button_complete_show"
|
||||
class="btns-cont-button-text"
|
||||
@click.stop="buutton_click('complete')"
|
||||
>
|
||||
完成
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="talking-info talking-info-loading" v-else-if="status === '00'">
|
||||
@@ -62,7 +78,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, unref, ref, toRefs, watch, onMounted } from 'vue';
|
||||
import { computed, unref, ref, toRefs, watch, onMounted, nextTick } from 'vue';
|
||||
import { onUnload } from '@dcloudio/uni-app';
|
||||
import { useAudioStore } from '@/store/audioStore';
|
||||
const props = defineProps({
|
||||
@@ -105,9 +121,8 @@
|
||||
// 是否显示重答按钮
|
||||
default: true,
|
||||
type: Boolean
|
||||
},
|
||||
}
|
||||
});
|
||||
console.log('props.isPreview', props.isPreview);
|
||||
const audioStore = useAudioStore();
|
||||
const { dataInfo } = toRefs(props);
|
||||
const status = computed(() => props.status);
|
||||
@@ -126,6 +141,11 @@
|
||||
|
||||
// 按钮点击
|
||||
const buutton_click = (type) => {
|
||||
if (type === 'again') {
|
||||
nextTick(() => {
|
||||
textShow.value = true;
|
||||
});
|
||||
}
|
||||
emit('buutton_click', type, props.dataInfo);
|
||||
};
|
||||
|
||||
|
||||
@@ -16,16 +16,28 @@
|
||||
<image :src="feedbackIcon()" class="img" @click="feedback_click()"></image>
|
||||
</view>
|
||||
<template v-if="['mistake'].includes(props.mode)">
|
||||
<view class="right_text" @click="toggleExpand()">展开</view>
|
||||
<uv-icon class="arrow-icon" name="arrow-right" color="#0066FF"></uv-icon>
|
||||
<view class="expand_button_div" @click="toggleExpand()">
|
||||
<!-- <view class="right_text">{{animationState?'收起':'展开'}}</view> -->
|
||||
|
||||
<view class="toggle-container">
|
||||
<view class="toggle-text" :class="{ active: !animationState }">展开</view>
|
||||
<view class="toggle-text" :class="{ active: animationState }">收起</view>
|
||||
</view>
|
||||
|
||||
<uv-icon
|
||||
class="click_text_icon"
|
||||
name="arrow-right"
|
||||
:class="{ click_text_icon_action: animationState }"
|
||||
color="#0066FF"
|
||||
></uv-icon>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
<view class="question_text">
|
||||
{{ subject_data.qnsContent }}
|
||||
</view>
|
||||
|
||||
<view :style="props.mode === 'mistake' ? animationStyle : {}" class="collapse-wrapper" ref="wrapperRef">
|
||||
<view :style="{ height: animationHeight }" :class="{ collapse_wrapper: props.mode === 'mistake' }" ref="wrapperRef">
|
||||
<view class="collapse-content" ref="contentRef">
|
||||
<view class="option_div">
|
||||
<template v-if="qnsTyp === 'ES'">
|
||||
@@ -95,7 +107,7 @@
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, nextTick, computed, getCurrentInstance } from 'vue';
|
||||
import { ref, reactive, onMounted, nextTick, computed, getCurrentInstance, watch } from 'vue';
|
||||
import radioSubjectItem from './radio-subject-item.vue';
|
||||
import esAnalysis from './es-analysis.vue';
|
||||
import questionVue from './question.vue';
|
||||
@@ -149,11 +161,10 @@
|
||||
const wrapperRef = ref(null);
|
||||
const contentRef = ref(null);
|
||||
const judgeResultStatus = computed(() => props.item.judgeResult === 'P');
|
||||
const animationStyle = ref({
|
||||
height: '0px',
|
||||
overflow: 'hidden',
|
||||
transition: 'height 0.3s ease-in-out'
|
||||
});
|
||||
|
||||
// 不是错题本就默认不折叠,错题本默认折叠
|
||||
const animationState = ref(props.mode !== 'mistake' ? true : false);
|
||||
const animationHeight = ref(props.mode !== 'mistake' ? '' : '0px');
|
||||
|
||||
const modelValue = computed({
|
||||
get: () => props.modelValue,
|
||||
@@ -172,14 +183,21 @@
|
||||
|
||||
// 切换展开/折叠状态(兼容H5和App)
|
||||
const toggleExpand = async () => {
|
||||
console.log('切换展开/折叠状态');
|
||||
const query = uni.createSelectorQuery().in(instance);
|
||||
query
|
||||
.select('.collapse-content')
|
||||
.boundingClientRect((rect) => {
|
||||
console.log('rect', rect);
|
||||
})
|
||||
.exec();
|
||||
console.log('切换展开/折叠状态', animationHeight.value, animationState.value);
|
||||
if (!animationState.value) {
|
||||
animationState.value = true;
|
||||
const query = uni.createSelectorQuery().in(instance);
|
||||
query
|
||||
.select('.collapse-content')
|
||||
.boundingClientRect((rect) => {
|
||||
animationHeight.value = `${rect.height}px`;
|
||||
console.log('rect', rect);
|
||||
})
|
||||
.exec();
|
||||
} else {
|
||||
animationState.value = false;
|
||||
animationHeight.value = '0px';
|
||||
}
|
||||
};
|
||||
const queryRect = () => {
|
||||
// 组件内部一般用this.$uvGetRect,对外的为getRect,二者功能一致,名称不同
|
||||
@@ -204,6 +222,7 @@
|
||||
const anserResultArray = props.item.anserResult.split(',');
|
||||
return subject_data.value.itemVos.filter((res) => anserResultArray.includes(res.itemId)).map((res) => res.itemNo);
|
||||
});
|
||||
|
||||
// 判断选项是否完全正确
|
||||
const right_or_wrong_class = computed(
|
||||
() =>
|
||||
@@ -285,16 +304,54 @@
|
||||
answerItems: subject_data.value.itemVos.filter((t) => item_answer.value.includes(t.itemId))
|
||||
});
|
||||
};
|
||||
|
||||
// 初始化动画
|
||||
onMounted(() => {});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.collapse-wrapper {
|
||||
// overflow: hidden; /* 关键:隐藏超出部分 */
|
||||
.expand_button_div {
|
||||
/* 相对定位,让两个文本重叠 */
|
||||
// display: inline-block;
|
||||
// cursor: pointer;
|
||||
}
|
||||
.toggle-container {
|
||||
position: relative;
|
||||
height: 42rpx;
|
||||
width: 60rpx;
|
||||
font-size: 30rpx;
|
||||
line-height: 42rpx;
|
||||
}
|
||||
.toggle-text {
|
||||
/* 绝对定位使文本重叠 */
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
/* 初始状态:非激活文本透明且轻微下移 */
|
||||
opacity: 0;
|
||||
// transform: translateY(15rpx);
|
||||
/* 添加过渡动画 */
|
||||
transition: all 0.2s ease-out;
|
||||
/* 确保文本占据空间一致 */
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* 激活状态:文本可见且位置正常 */
|
||||
.toggle-text.active {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
z-index: 1; /* 确保激活文本在上方 */
|
||||
}
|
||||
|
||||
.collapse_wrapper {
|
||||
overflow: hidden; /* 关键:隐藏超出部分 */
|
||||
// height: 0; /* 初始高度为0 */
|
||||
// transition: height 0.3s ease-in-out;
|
||||
transition: height 0.3s ease-out;
|
||||
}
|
||||
.click_text_icon_action {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
.click_text_icon {
|
||||
transition: transform 0.3s ease-out;
|
||||
}
|
||||
|
||||
.mark_and_feedback_div {
|
||||
@@ -310,6 +367,13 @@
|
||||
padding: 4rpx;
|
||||
}
|
||||
}
|
||||
.expand_button_div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 90rpx;
|
||||
|
||||
justify-content: space-between;
|
||||
}
|
||||
.option_div {
|
||||
padding-top: 20rpx;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user