|
|
@@ -0,0 +1,245 @@
|
|
|
+<template>
|
|
|
+ <view class="question-book-item p-24">
|
|
|
+ <view class="question-title">
|
|
|
+ <mp-html :content="title" />
|
|
|
+ </view>
|
|
|
+ <view class="question-options">
|
|
|
+ <view class="question-option" v-for="(option, index) in data.options" :class="getStyleClass(option)" :key="index">
|
|
|
+ <view>
|
|
|
+ <uv-icon v-if="option.isCorrect" name="checkmark-circle-fill" color="#2CC6A0" size="22" />
|
|
|
+ <uv-icon v-else-if="!option.isCorrect && option.isSelected" name="close-circle-fill" color="#FF5B5C"
|
|
|
+ size="22" />
|
|
|
+ <view v-else class="question-option-index">{{ option.no }}</view>
|
|
|
+ </view>
|
|
|
+ <view class="question-option-content">
|
|
|
+ <mp-html :content="option.name" />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <uv-line margin="15px 0 10px 0" />
|
|
|
+ <view class="question-toolbar">
|
|
|
+ <view class="flex items-center gap-6" @click="handleToggleCollect">
|
|
|
+ <uv-icon :name="data.collect ? 'star-fill' : 'star'" size="20" color="var(--primary-color)" />
|
|
|
+ <text class="text-26 text-primary">{{ data.collect ? '已收藏' : '收藏' }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="flex items-center gap-6" @click="handleCorrect">
|
|
|
+ <uv-icon name="info-circle" size="18" color="var(--primary-color)" />
|
|
|
+ <text class="text-26 text-primary">纠错</text>
|
|
|
+ </view>
|
|
|
+ <view v-if="!showAnswer" class="flex items-center" @click="toggleShowParse">
|
|
|
+ <cover-view class="w-60 h-60 flex items-center justify-center">
|
|
|
+ <cover-image v-show="!showParse" src="@/pagesSystem/static/image/icon/icon-eye.png" mode="widthFix"
|
|
|
+ class="w-38 h-38" />
|
|
|
+ <cover-image v-show="showParse" src="@/pagesSystem/static/image/icon/icon-eye-off.png" mode="widthFix"
|
|
|
+ class="w-38 h-38" />
|
|
|
+ </cover-view>
|
|
|
+ <text class="text-26 text-primary">{{ showParse ? '隐藏解析' : '查看解析' }}</text>
|
|
|
+ </view>
|
|
|
+ <view v-else class="flex items-center" @click="handleDelete">
|
|
|
+ <uv-icon name="trash" size="18" color="var(--danger)" />
|
|
|
+ <text class="text-26 text-danger">删除</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view v-show="showParse" class="question-parse">
|
|
|
+ <view v-if="showAnswer">
|
|
|
+ <view class="text-28 text-fore-title font-bold">知识点</view>
|
|
|
+ <view class="mt-10 text-26 text-primary">
|
|
|
+ <mp-html :content="data.knowledge || '暂无知识点'" />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view>
|
|
|
+ <view class="text-28 text-fore-title font-bold">答案</view>
|
|
|
+ <view class="mt-10 text-28 text-primary">
|
|
|
+ <mp-html :content="data.answer || '略'" />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view>
|
|
|
+ <view class="text-28 text-fore-title font-bold">解析</view>
|
|
|
+ <view class="mt-10 text-26 text-primary">
|
|
|
+ <mp-html :content="data.parse || '暂无解析'" />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+<script lang="ts" setup>
|
|
|
+import { EnumQuestionType } from '@/common/enum';
|
|
|
+import type { Study } from '@/types';
|
|
|
+
|
|
|
+
|
|
|
+const props = defineProps({
|
|
|
+ showKnowledge: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ showAnswer: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ data: {
|
|
|
+ type: Object as PropType<Study.FavoriteQuestionVO>,
|
|
|
+ default: () => ({})
|
|
|
+ }
|
|
|
+});
|
|
|
+const showParse = ref(props.showAnswer);
|
|
|
+const title = computed(() => {
|
|
|
+ return `[${props.data.qtype}] ${props.data.title}`;
|
|
|
+});
|
|
|
+
|
|
|
+const emit = defineEmits<{
|
|
|
+ (e: 'correct', question: Study.FavoriteQuestionVO): void;
|
|
|
+ (e: 'toggleCollect', question: Study.FavoriteQuestionVO): void;
|
|
|
+ (e: 'delete', question: Study.FavoriteQuestionVO): void;
|
|
|
+}>();
|
|
|
+const handleCorrect = () => {
|
|
|
+ emit('correct', props.data);
|
|
|
+}
|
|
|
+const handleToggleCollect = () => {
|
|
|
+ emit('toggleCollect', props.data);
|
|
|
+}
|
|
|
+const handleDelete = () => {
|
|
|
+ emit('delete', props.data);
|
|
|
+}
|
|
|
+const toggleShowParse = () => {
|
|
|
+ showParse.value = !showParse.value;
|
|
|
+}
|
|
|
+const getStyleClass = (option: Study.QuestionOption) => {
|
|
|
+ let customClass = '';
|
|
|
+ let { answers, answer, typeId } = props.data;
|
|
|
+ answers = answers?.filter(item => item !== ' ') || [];
|
|
|
+ answer = answer || ''
|
|
|
+ if ([EnumQuestionType.SINGLE_CHOICE, EnumQuestionType.JUDGMENT].includes(typeId)) {
|
|
|
+ if (option.isCorrect) {
|
|
|
+ customClass = 'question-option-correct';
|
|
|
+ } else if (option.isIncorrect) {
|
|
|
+ customClass = 'question-option-incorrect';
|
|
|
+ }
|
|
|
+ } else if ([EnumQuestionType.MULTIPLE_CHOICE].includes(typeId)) {
|
|
|
+ // 我选择的答案
|
|
|
+ if (option.isSelected) {
|
|
|
+ if (option.isCorrect) {
|
|
|
+ customClass = 'question-option-correct';
|
|
|
+ } else {
|
|
|
+ customClass = 'question-option-incorrect';
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 漏选的答案
|
|
|
+ if (option.isMissed) {
|
|
|
+ customClass = 'question-option-miss';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return customClass;
|
|
|
+};
|
|
|
+</script>
|
|
|
+<style lang="scss" scoped>
|
|
|
+.question-title {
|
|
|
+ @apply text-28 text-fore-title break-words;
|
|
|
+}
|
|
|
+
|
|
|
+.question-options {
|
|
|
+ @apply mt-20;
|
|
|
+}
|
|
|
+
|
|
|
+.question-toolbar {
|
|
|
+ @apply flex items-center justify-between gap-20;
|
|
|
+}
|
|
|
+
|
|
|
+.question-parse {
|
|
|
+ @apply mt-30 flex flex-col gap-20;
|
|
|
+}
|
|
|
+
|
|
|
+.question-option {
|
|
|
+ @apply flex items-center px-30 py-24 bg-back rounded-8 border border-none border-transparent;
|
|
|
+
|
|
|
+ .question-option-index {
|
|
|
+ @apply w-40 h-40 rounded-full bg-transparent text-30 text-fore-light font-bold flex items-center justify-center flex-shrink-0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .question-option-content {
|
|
|
+ @apply text-28 text-fore-title ml-20 flex-1 min-w-0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.question-option-selected {
|
|
|
+ @apply bg-[#b5eaff8e];
|
|
|
+
|
|
|
+ .question-option-index {
|
|
|
+ @apply bg-primary text-white;
|
|
|
+ }
|
|
|
+
|
|
|
+ .question-option-content {
|
|
|
+ @apply text-primary;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.question-option-not-know {
|
|
|
+ @apply bg-[#b5eaff8e];
|
|
|
+
|
|
|
+ .question-option-content {
|
|
|
+ @apply text-primary;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.question-option-correct {
|
|
|
+ @apply bg-[#E7FCF8] border-[#E7FCF8] text-[#2CC6A0];
|
|
|
+
|
|
|
+ .question-option-index {
|
|
|
+ @apply text-[#2CC6A0];
|
|
|
+ }
|
|
|
+
|
|
|
+ .question-option-content {
|
|
|
+ @apply text-[#2CC6A0];
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.question-option-miss {
|
|
|
+ @apply relative overflow-hidden;
|
|
|
+
|
|
|
+ &::before {
|
|
|
+ content: '';
|
|
|
+ position: absolute;
|
|
|
+ right: -56rpx;
|
|
|
+ top: 15rpx;
|
|
|
+ width: 180rpx;
|
|
|
+ height: 36rpx;
|
|
|
+ background: rgba(255, 91, 92, 0.2);
|
|
|
+ transform: rotate(30deg);
|
|
|
+ box-shadow: 0 2rpx 4rpx rgba(255, 91, 92, 0.1);
|
|
|
+ }
|
|
|
+
|
|
|
+ &::after {
|
|
|
+ content: '漏选';
|
|
|
+ position: absolute;
|
|
|
+ right: -8rpx;
|
|
|
+ top: 14rpx;
|
|
|
+ width: 100rpx;
|
|
|
+ height: 32rpx;
|
|
|
+ color: #FF5B5C;
|
|
|
+ font-size: 20rpx;
|
|
|
+ // font-weight: bold;
|
|
|
+ transform: rotate(30deg);
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ line-height: 1;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.question-option-incorrect {
|
|
|
+ @apply bg-[#FEEDE9] border-[#FEEDE9] text-[#FF5B5C];
|
|
|
+
|
|
|
+ .question-option-index {
|
|
|
+ @apply text-[#FF5B5C];
|
|
|
+ }
|
|
|
+
|
|
|
+ .question-option-content {
|
|
|
+ @apply text-[#FF5B5C];
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+.question-option+.question-option {
|
|
|
+ @apply mt-24;
|
|
|
+}
|
|
|
+</style>
|