150 lines
3.7 KiB
Vue
150 lines
3.7 KiB
Vue
<template>
|
||
<view class="analysis_div" @click.stop="click_option()" :class="status">
|
||
<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'">
|
||
<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: {
|
||
type: Object,
|
||
default: () => {},
|
||
required: false
|
||
},
|
||
judgeResult: {
|
||
type: Boolean,
|
||
default: false,
|
||
required: false
|
||
},
|
||
answerText: {
|
||
type: String,
|
||
default: '',
|
||
required: false
|
||
}
|
||
});
|
||
const evalSettingVos = computed(() => props.value.evalSettingVos);
|
||
const status = computed(() => (props.judgeResult ? 'success' : 'error'));
|
||
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>`);
|
||
});
|
||
const dimension_all_score = computed(() => {
|
||
return (
|
||
evalSettingVos.value
|
||
// 先通过map提取每个item的anlyGrade,不存在或非数字则取0
|
||
.map((item) => (item?.anlyGrade && typeof item.anlyGrade === 'number' ? item.anlyGrade : 0))
|
||
// 再通过reduce累加所有数值
|
||
.reduce((total, current) => total + current, 0)
|
||
);
|
||
});
|
||
watch(evalSettingVos.value, (newVal) => {
|
||
console.log('newVal2', newVal);
|
||
});
|
||
const click_option = () => {
|
||
emit('click_option', props.analysisVo);
|
||
};
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.success {
|
||
background-color: #e7f8ed;
|
||
.td {
|
||
color: #15b859;
|
||
}
|
||
:deep(.highlight) {
|
||
color: #15b859;
|
||
}
|
||
}
|
||
.error {
|
||
background-color: #fce8e9;
|
||
.td {
|
||
color: #f5212d;
|
||
}
|
||
:deep(.highlight) {
|
||
color: #f5212d;
|
||
}
|
||
}
|
||
.your_answer {
|
||
:deep(.highlight) {
|
||
text-decoration: underline;
|
||
}
|
||
}
|
||
|
||
.analysis_div {
|
||
margin-top: 30rpx;
|
||
|
||
border-radius: 16rpx;
|
||
padding: 22rpx 15rpx 15rpx 34rpx;
|
||
.line {
|
||
margin: 12rpx 0;
|
||
position: relative;
|
||
}
|
||
.tr {
|
||
font-weight: 600;
|
||
font-size: 30rpx;
|
||
color: #333333;
|
||
}
|
||
.td {
|
||
font-weight: 600;
|
||
font-size: 30rpx;
|
||
}
|
||
.your_answer {
|
||
font-weight: 500;
|
||
font-size: 30rpx;
|
||
color: #333333;
|
||
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>
|