fix(admin): 移除题目标题必填验证并优化诗词理解题目展示

移除题目配置中的标题输入框及相关必填验证,使标题字段变为可选
诗词理解题目类型使用富文本编辑器,其他类型使用普通文本域
优化用户端汉字听写和词语听写题目的米字格展示样式
统一图片展示样式,限制最大宽度为50%并居中显示
This commit is contained in:
2026-02-13 08:34:09 +08:00
parent f3136cd9ad
commit f1ff053b68
5 changed files with 39 additions and 35 deletions

View File

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { NButton, NForm, NFormItem, NInput, NInputNumber, NModal, NSelect, type SelectOption } from 'naive-ui' import { NButton, NForm, NFormItem, NInputNumber, NModal, NSelect, type SelectOption } from 'naive-ui'
import { onMounted, ref, watch } from 'vue' import { onMounted, ref, watch } from 'vue'
import { VueDraggable } from 'vue-draggable-plus' import { VueDraggable } from 'vue-draggable-plus'
import { useDict } from '@/hooks/business/useDict' import { useDict } from '@/hooks/business/useDict'
@ -275,14 +275,14 @@ defineExpose({ validate, reset })
</div> </div>
<!-- 标题 --> <!-- 标题 -->
<div class="flex flex-1 items-center gap-2 rounded-lg bg-gray-50 px-3 py-1.5"> <!-- <div class="flex flex-1 items-center gap-2 rounded-lg bg-gray-50 px-3 py-1.5">
<icon-ic-outline-title class="text-gray-400" /> <icon-ic-outline-title class="text-gray-400" />
<span class="whitespace-nowrap text-sm text-gray-400 font-bold">标题</span> <span class="whitespace-nowrap text-sm text-gray-400 font-bold">标题</span>
<NInput <NInput
v-model:value="item.ActitvityQuestionName" class="flex-1 !bg-transparent" size="small" :bordered="false" v-model:value="item.ActitvityQuestionName" class="flex-1 !bg-transparent" size="small" :bordered="false"
placeholder="请输入题目标题" placeholder="请输入题目标题"
/> />
</div> </div> -->
</div> </div>
<!-- 删除按钮 --> <!-- 删除按钮 -->

View File

@ -254,10 +254,10 @@ export function useQuestionConfig(props: any) {
window.$message?.error(`${questionPrefix}未设置分数规则`) window.$message?.error(`${questionPrefix}未设置分数规则`)
return false return false
} }
if (question.ActitvityQuestionName === undefined || question.ActitvityQuestionName === null || question.ActitvityQuestionName === '') { // if (question.ActitvityQuestionName === undefined || question.ActitvityQuestionName === null || question.ActitvityQuestionName === '') {
window.$message?.error(`${questionPrefix}未填写标题`) // window.$message?.error(`${questionPrefix}未填写标题`)
return false // return false
} // }
if (question.Point === null || question.Point === undefined) { if (question.Point === null || question.Point === undefined) {
window.$message?.error(`${questionPrefix}未设置分数`) window.$message?.error(`${questionPrefix}未设置分数`)
return false return false

View File

@ -45,7 +45,6 @@ const { options: timeOptions } = useDict('time_out')
// const { options: uiTypeOptions } = useDict('ui_type', 'string') // const { options: uiTypeOptions } = useDict('ui_type', 'string')
const { options: uiTypeOptions } = useDict('question_category_name', 'string') const { options: uiTypeOptions } = useDict('question_category_name', 'string')
// 我们构造一个包含 modelValue 属性的对象,类似于 props
const hookProps = reactive({ const hookProps = reactive({
modelValue, modelValue,
}) })
@ -344,7 +343,7 @@ defineExpose({ validate, reset, modelValue })
</div> </div>
<!-- 标题 --> <!-- 标题 -->
<div class="flex flex-1 items-center gap-2 rounded-lg bg-gray-50 px-3 py-1.5"> <!-- <div class="flex flex-1 items-center gap-2 rounded-lg bg-gray-50 px-3 py-1.5">
<icon-ic-outline-title class="text-gray-400" /> <icon-ic-outline-title class="text-gray-400" />
<span class="whitespace-nowrap text-sm text-gray-400 font-bold">标题</span> <span class="whitespace-nowrap text-sm text-gray-400 font-bold">标题</span>
<NInput <NInput
@ -352,7 +351,7 @@ defineExpose({ validate, reset, modelValue })
placeholder="请输入题目标题" placeholder="请输入题目标题"
:disabled="!isEdit" :disabled="!isEdit"
/> />
</div> </div> -->
</div> </div>
<!-- 删除按钮 --> <!-- 删除按钮 -->

View File

@ -24,9 +24,8 @@ import { pinyin } from 'pinyin-pro'
import { computed, onUnmounted, ref, watch } from 'vue' import { computed, onUnmounted, ref, watch } from 'vue'
import WangEditor from '@/components/common/wang-editor.vue' import WangEditor from '@/components/common/wang-editor.vue'
import SvgIcon from '@/components/custom/svg-icon.vue' import SvgIcon from '@/components/custom/svg-icon.vue'
import { QuestionType } from '@/enum/business' import { QuestionCategoryEnum, QuestionType } from '@/enum/business'
import { fetchAddQuestionLibrary, fetchDeleteQuestionLibrary, fetchGetQuestionLibraryListAll, fetchUpdateQuestionLibrary } from '@/service/api/question' import { fetchAddQuestionLibrary, fetchDeleteQuestionLibrary, fetchGetQuestionLibraryListAll, fetchUpdateQuestionLibrary } from '@/service/api/question'
/** /**
* 为了user端题目展示的效果以及布局可控指定规则 * 为了user端题目展示的效果以及布局可控指定规则
* 1.普通类型 =》用存文字存 ['汉字加一加','词语听写''汉字听写','成语写一写'] * 1.普通类型 =》用存文字存 ['汉字加一加','词语听写''汉字听写','成语写一写']
@ -532,12 +531,13 @@ async function submitQuestion() {
<NForm ref="questionFormRef" label-placement="top" :rules="rules" :model="questionForm" size="small"> <NForm ref="questionFormRef" label-placement="top" :rules="rules" :model="questionForm" size="small">
<NFormItem label="题目正文内容" path="name"> <NFormItem label="题目正文内容" path="name">
<div class="w-full overflow-hidden border border-gray-200 rounded-lg"> <div v-if="[QuestionCategoryEnum.PoetryComprehension].includes(props.currentCategory?.QuestionType)" class="w-full overflow-hidden border border-gray-200 rounded-lg">
<WangEditor <WangEditor
v-model="questionForm.name" placeholder="请输入题目内容..." height="300px" v-model="questionForm.name" placeholder="请输入题目内容..." height="300px"
:exclude-keys="['header1', 'fontSize', 'fontFamily', 'lineHeight', 'justifyLeft', 'justifyRight', 'justifyCenter', 'justifyJustify', 'group-image', 'group-video', 'insertTable', 'headerSelect']" :exclude-keys="['header1', 'fontSize', 'fontFamily', 'lineHeight', 'justifyLeft', 'justifyRight', 'justifyCenter', 'justifyJustify', 'group-image', 'group-video', 'insertTable', 'headerSelect']"
/> />
</div> </div>
<NInput v-else v-model:value="questionForm.name" type="textarea" placeholder="请输入题目内容" :rows="3" />
</NFormItem> </NFormItem>
<!-- <div class="grid grid-cols-2 gap-4"> <!-- <div class="grid grid-cols-2 gap-4">

View File

@ -3,11 +3,6 @@ import { computed, watch } from 'vue'
import { QuestionCategoryEnum } from '@/enum/business' import { QuestionCategoryEnum } from '@/enum/business'
import { useCompetitionStore } from '@/store/modules/competition' import { useCompetitionStore } from '@/store/modules/competition'
// const props = defineProps<{
// template: QuestionCategoryName
// content: QuestionContent
// }>()
const store = useCompetitionStore() const store = useCompetitionStore()
const currentQuestionMainInfo = computed(() => store.currentQuestionMainInfo) const currentQuestionMainInfo = computed(() => store.currentQuestionMainInfo)
const currentQuestionDetail = computed(() => store.currentQuestionDetail) const currentQuestionDetail = computed(() => store.currentQuestionDetail)
@ -61,7 +56,7 @@ const parsedComponentAddTitle = computed(() => {
/** 获取富文本里面的text */ /** 获取富文本里面的text */
const pinyinChars = computed(() => { const pinyinChars = computed(() => {
if (template.value === QuestionCategoryEnum.WordDictation && content.value) { if (content.value) {
// 创建临时元素提取HTML文本内容 // 创建临时元素提取HTML文本内容
const div = document.createElement('div') const div = document.createElement('div')
div.innerHTML = content.value div.innerHTML = content.value
@ -84,16 +79,35 @@ watch(
</script> </script>
<template> <template>
<div class="w-full flex p-6" style="border: 1px solid red;"> <div class="w-full flex p-6">
<!-- template:{{ template }} --> <!-- template:{{ template }} -->
<!-- 模板A: 汉字听写-提示 (拼音+提示) --> <!-- 模板A: 汉字听写-提示 (拼音+提示) -->
<div v-if="template === QuestionCategoryEnum.ChineseCharacterDictation" class="text-center"> <div v-if="template === QuestionCategoryEnum.ChineseCharacterDictation" class="text-center">
<div class="mb-6 inline-block text-5xl font-bold leading-none"> <div class="mb-6 inline-block text-5xl font-bold leading-none">
<div class="ptions-container1 text-2xl"> <div class="ptions-container1 mb-2 text-center text-2xl">
{{ title }} {{ title }}
</div> </div>
<div class="rich-content1"> <div class="rich-content flex gap-1">
{{ content }} <div
v-for="(char, index) in pinyinChars" :key="index"
class="relative h-38 w-42 flex select-none items-center justify-center border-2 border-red-500 bg-white"
>
<!-- 米字格背景 -->
<div class="pointer-events-none absolute inset-0 z-0 h-full w-full">
<!-- 横虚线 -->
<div class="absolute left-0 top-1/2 h-[1px] w-full border-t border-red-400 border-dashed opacity-60" />
<!-- 竖虚线 -->
<div class="absolute left-1/2 top-0 h-full w-[1px] border-l border-red-400 border-dashed opacity-60" />
<!-- 斜虚线 (SVG) -->
<svg width="100%" height="100%" class="absolute inset-0 opacity-60">
<line x1="0" y1="0" x2="100%" y2="100%" stroke="#f87171" stroke-width="1" stroke-dasharray="4 2" />
<line x1="100%" y1="0" x2="0" y2="100%" stroke="#f87171" stroke-width="1" stroke-dasharray="4 2" />
</svg>
</div>
<!-- 文字 -->
<span class="z-10 text-4xl text-gray-800 font-bold font-sans">{{ char }}</span>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -153,21 +167,11 @@ watch(
<!-- 模板E: 成语-文字要求 --> <!-- 模板E: 成语-文字要求 -->
<div v-else-if="template === QuestionCategoryEnum.IdiomWriting" class="text-center"> <div v-else-if="template === QuestionCategoryEnum.IdiomWriting" class="text-center">
<div class="mb-8 text-4xl text-gray-800 font-bold"> <div class="mb-8 text-4xl text-gray-800 font-bold">
<!-- {{ content.title }} --> <!-- {{ content }} -->
<div class="rich-content" v-html="content" /> <div class="rich-content" v-html="content" />
</div> </div>
<!-- <div class="rounded bg-gray-100 px-4 py-2 text-xl text-gray-500">
示例{{ content.meta?.example }}
</div> -->
</div> </div>
<!-- 模板F: 诗词理解 -->
<!-- <div v-else-if="template === 'TEMPLATE_IDIOM_IMAGE'" class="flex flex-col items-center text-center">
<div class="mb-6 h-60 w-80 flex items-center justify-center">
<img :src="content.titleImage" alt="idiom image" class="h-full w-full object-contain">
</div>
</div> -->
<!-- 模板G: 诗词理解-选择题 (通用选择题模板) --> <!-- 模板G: 诗词理解-选择题 (通用选择题模板) -->
<div v-else-if="template === QuestionCategoryEnum.PoetryComprehension" class="w-full flex flex-col items-center"> <div v-else-if="template === QuestionCategoryEnum.PoetryComprehension" class="w-full flex flex-col items-center">
<div class="options-container text-2xl"> <div class="options-container text-2xl">
@ -376,9 +380,10 @@ watch(
.rich-content { .rich-content {
:deep(img) { :deep(img) {
max-width: 100%; max-width: 50%;
height: auto; height: auto;
object-fit: contain; object-fit: contain;
margin: 0 auto;
vertical-align: middle; vertical-align: middle;
} }
} }