123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- <template>
- <div class="blank-answer-editor">
- <el-card>
- <div class="blank-header">
- <span style="width: 80px;">填空序号</span>
- <span style="flex: 1;">正确答案</span>
- <span style="width: 120px; text-align: center;">分值</span>
- </div>
- <div
- v-for="(blank, index) in blankAnswers"
- :key="index"
- class="blank-item"
- >
- <span style="width: 80px;">{{ blank.blank_index }}</span>
- <el-input
- v-model="blank.correct_answer"
- placeholder="请输入正确答案"
- :disabled="readonly"
- style="flex: 1; margin: 0 10px;"
- />
- <el-input-number
- v-model="blank.score"
- :min="0"
- :max="100"
- :step="1"
- :precision="0"
- :controls="false"
- :disabled="readonly"
- style="width: 120px;"
- placeholder="分值"
- />
- </div>
- <div class="blank-tip">
- 提示:在题目中使用"___"(三个下划线)表示填空位置,系统会自动识别填空数量
- </div>
- </el-card>
- </div>
- </template>
- <script setup lang="ts">
- import { ref, watch, computed } from 'vue';
- interface BlankAnswer {
- blank_index: number;
- correct_answer: string;
- score: number;
- }
- interface Props {
- modelValue: BlankAnswer[];
- question: string;
- readonly?: boolean;
- }
- interface Emits {
- (e: 'update:modelValue', value: BlankAnswer[]): void;
- }
- const props = withDefaults(defineProps<Props>(), {
- readonly: false
- });
- const emit = defineEmits<Emits>();
- const blankAnswers = ref<BlankAnswer[]>([...props.modelValue]);
- // 计算题目中的填空数量
- const blankCount = computed(() => {
- return (props.question || '').split('___').length - 1;
- });
- // 监听数据变化
- watch(() => blankAnswers.value, (newVal) => {
- if (props.readonly) return;
- if (JSON.stringify(newVal) !== JSON.stringify(props.modelValue)) {
- emit('update:modelValue', newVal);
- }
- }, { deep: true });
- // 监听 props 变化
- watch(() => props.modelValue, (newVal) => {
- if (JSON.stringify(blankAnswers.value) !== JSON.stringify(newVal)) {
- blankAnswers.value = [...newVal];
- }
- }, { deep: true });
- // 监听题目变化,自动调整填空数量
- watch(() => props.question, (newQuestion) => {
- if (props.readonly) return;
- const newBlankCount = (newQuestion || '').split('___').length - 1;
-
- if (newBlankCount > 0 && blankAnswers.value.length !== newBlankCount) {
- const newBlankAnswers = Array.from({ length: newBlankCount }, (_, i) => ({
- blank_index: i + 1,
- correct_answer: blankAnswers.value[i]?.correct_answer || '',
- score: blankAnswers.value[i]?.score || 5
- }));
-
- if (JSON.stringify(newBlankAnswers) !== JSON.stringify(blankAnswers.value)) {
- blankAnswers.value = newBlankAnswers;
- }
- }
- });
- // 初始化填空模板
- if (!props.readonly && blankAnswers.value.length === 0) {
- blankAnswers.value = [{ blank_index: 1, correct_answer: '', score: 5 }];
- }
- </script>
- <style scoped>
- .blank-answer-editor {
- width: 100%;
- }
- .blank-header {
- display: flex;
- margin-bottom: 10px;
- font-weight: bold;
- background-color: #f5f7fa;
- padding: 8px;
- border-radius: 4px;
- }
- .blank-item {
- display: flex;
- align-items: center;
- margin-bottom: 10px;
- border: 1px solid #e4e7ed;
- border-radius: 4px;
- padding: 8px;
- }
- .blank-tip {
- color: #666;
- font-size: 12px;
- margin-top: 10px;
- padding: 8px;
- background-color: #f0f9ff;
- border-radius: 4px;
- border-left: 4px solid #3b82f6;
- }
- </style>
|