| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043 |
- <template>
- <div class="app-container">
- <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
- <el-form-item label="题目ID" prop="id">
- <el-input v-model.number="queryParams.id" type="number" placeholder="请输入题目ID" clearable
- @keyup.enter="handleQuery"/>
- </el-form-item>
- <el-form-item label="题干" prop="title">
- <el-input v-model="queryParams.title" placeholder="请输入题干关键词" clearable
- @keyup.enter="handleQuery"/>
- </el-form-item>
- <el-form-item label="题型" prop="qtpye">
- <!-- <el-input v-model="queryParams.qtpye" placeholder="请输入题型" clearable @keyup.enter="handleQuery" /> -->
- <!-- <dict-tag :options="question_type" :value="queryParams.qtpye"/> -->
- <el-select v-model="queryParams.typeId" clearable @change="handleQuery" style="width: 172px">
- <el-option v-for="q in question_type" :label="q.label" :value="q.value"/>
- </el-select>
- </el-form-item>
- <el-form-item label="科目" prop="subjectId">
- <el-select v-model="queryParams.subjectId" clearable @change="handleSubjectChange" style="width: 172px">
- <el-option v-for="s in subjectList" :label="s.subjectName" :value="s.subjectId"/>
- </el-select>
- </el-form-item>
- <el-form-item label="知识点" prop="knowledgeId">
- <el-tree-select node-key="id" v-model="queryParams.knowledgeId" :data="filteredKnowledgeTreeList" check-strictly
- :render-after-expand="false" style="" :props="{ label: 'name', children: 'children' }"
- placeholder="请选择知识点" class="w-[172px]!" @change="handleQuery"/>
- </el-form-item>
- <!-- <el-form-item label="难度" prop="diff">
- <el-input v-model="queryParams.diff" placeholder="请输入难度" clearable @keyup.enter="handleQuery"/>
- </el-form-item> -->
- <!-- <el-form-item label="相似度" prop="similarity">
- <el-input v-model="queryParams.similarity" placeholder="请输入试题在题库中的相似度" clearable @keyup.enter="handleQuery" />
- </el-form-item> -->
- <!-- <el-form-item label="试题年份" prop="year">
- <el-input v-model="queryParams.year" placeholder="请输入试题年份" clearable @keyup.enter="handleQuery"/>
- </el-form-item> -->
- <!-- <el-form-item label="试题类型" prop="paperTpye">
- <el-select v-model="queryParams.paperTpye" clearable @change="handleQuery" style="width: 172px">
- <el-option v-for="p in paper_type" :label="p.label" :value="p.value" />
- </el-select>
- </el-form-item> -->
- <!-- <el-form-item label="来源" prop="source">
- <el-input v-model="queryParams.source" placeholder="请输入来源" clearable @keyup.enter="handleQuery"/>
- </el-form-item> -->
- <!-- <el-form-item label="试题来源" prop="fromSite">
- <el-input v-model="queryParams.fromSite" placeholder="请输入试题来源" clearable
- @keyup.enter="handleQuery"/>
- </el-form-item> -->
- <el-form-item label="包含子题" prop="isSubType">
- <el-select v-model="queryParams.isSubType" placeholder="请选择包含子题" clearable style="width: 172px">
- <el-option v-for="item in bool_values" :key="item.value" :label="item.label" :value="item.value" />
- </el-select>
- </el-form-item>
- <el-form-item>
- <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
- <el-button icon="Refresh" @click="resetQuery">重置</el-button>
- </el-form-item>
- </el-form>
- <el-row :gutter="10" class="mb8">
- <el-col :span="1.5">
- <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['learn:questions:add']">新增
- </el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate"
- v-hasPermi="['learn:questions:edit']">修改
- </el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button type="info" plain icon="Switch" :disabled="!ids.length" @click="handleChangeType"
- v-hasPermi="['learn:questions:changeType']">修改题型
- </el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete"
- v-hasPermi="['learn:questions:remove']">删除
- </el-button>
- </el-col>
- <el-col :span="1.5">
- <el-button type="warning" plain icon="Download" @click="handleExport"
- v-hasPermi="['learn:questions:export']">导出
- </el-button>
- </el-col>
- <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
- </el-row>
- <el-table v-loading="loading" :data="questionsList" @selection-change="handleSelectionChange">
- <el-table-column type="selection" width="55" align="center" fixed="left"/>
- <el-table-column label="题目ID" align="center" prop="id" fixed="left" />
- <el-table-column label="试题-题干" align="left" prop="title" min-width="350" header-align="center"
- fixed="left">
- <template #default="scope">
- <div class="table-cell-content" v-html="formatContentWithImages(scope.row.title)"></div>
- </template>
- </el-table-column>
- <el-table-column label="题型" align="center" prop="qtpye"/>
- <el-table-column label="学科" align="center" prop="subjectId">
- <template #default="scope">
- <span v-if="scope.row.subjectId">
- {{ getSubjectName(scope.row.subjectId) }}
- </span>
- <span v-else>-</span>
- </template>
- </el-table-column>
- <el-table-column label="知识点" align="center" prop="knowledgeId"/>
- <el-table-column label="选项" align="center" prop="optionA" show-overflow-tooltip>
- <template #default="scope">
- <el-link type="primary" @click="handleShowOptions(scope.row)" :underline="false">
- <span v-if="scope.row.optionA" class="table-cell-content" v-html="formatContentWithImages(scope.row.optionA)"></span>
- <span v-else>-</span>
- </el-link>
- </template>
- </el-table-column>
- <!-- <el-table-column label="选项B" align="center" prop="optionB" show-overflow-tooltip>
- <template #default="scope">
- <el-link type="primary" @click="handleShowOptions(scope.row)" :underline="false">
- {{ scope.row.optionB || '-' }}
- </el-link>
- </template>
- </el-table-column>
- <el-table-column label="选项C" align="center" prop="optionC" show-overflow-tooltip>
- <template #default="scope">
- <el-link type="primary" @click="handleShowOptions(scope.row)" :underline="false">
- {{ scope.row.optionC || '-' }}
- </el-link>
- </template>
- </el-table-column>
- <el-table-column label="选项D" align="center" prop="optionD" show-overflow-tooltip>
- <template #default="scope">
- <el-link type="primary" @click="handleShowOptions(scope.row)" :underline="false">
- {{ scope.row.optionD || '-' }}
- </el-link>
- </template>
- </el-table-column>
- <el-table-column label="选项E" align="center" prop="optionE" show-overflow-tooltip>
- <template #default="scope">
- <el-link type="primary" @click="handleShowOptions(scope.row)" :underline="false">
- {{ scope.row.optionE || '-' }}
- </el-link>
- </template>
- </el-table-column>
- <el-table-column label="选项F" align="center" prop="optionF" show-overflow-tooltip>
- <template #default="scope">
- <el-link type="primary" @click="handleShowOptions(scope.row)" :underline="false">
- {{ scope.row.optionF || '-' }}
- </el-link>
- </template>
- </el-table-column>
- <el-table-column label="选项G" align="center" prop="optionG" show-overflow-tooltip>
- <template #default="scope">
- <el-link type="primary" @click="handleShowOptions(scope.row)" :underline="false">
- {{ scope.row.optionG || '-' }}
- </el-link>
- </template>
- </el-table-column> -->
- <el-table-column label="标准答案" align="center" prop="answer1" show-overflow-tooltip>
- <template #default="scope">
- <div class="table-cell-content" v-html="formatContentWithImages(scope.row.answer1 || '-')"></div>
- </template>
- </el-table-column>
- <el-table-column label="答案2" align="center" prop="answer2" show-overflow-tooltip>
- <template #default="scope">
- <div class="table-cell-content" v-html="formatContentWithImages(scope.row.answer2 || '-')"></div>
- </template>
- </el-table-column>
- <!-- <el-table-column label="试卷Id" align="center" prop="paperId"/> -->
- <!-- <el-table-column label="难易度" align="center" prop="diff"/> -->
- <!-- <el-table-column label="相似度" align="center" prop="similarity"/> -->
- <el-table-column label="试题解析" align="center" prop="parse" min-width="250" show-overflow-tooltip>
- <template #default="scope">
- <div class="table-cell-content" v-html="formatContentWithImages(scope.row.parse || '-')"></div>
- </template>
- </el-table-column>
- <!-- <el-table-column label="knowId" align="center" prop="knowId" /> -->
- <!-- <el-table-column label="年级ID" align="center" prop="gradeId"/> -->
- <!-- <el-table-column label="knowledges" align="center" prop="knowledges" /> -->
- <!-- <el-table-column label="试题区域" align="center" prop="area"/> -->
- <el-table-column label="试题年份" align="center" prop="year"/>
- <!-- <el-table-column label="试题类型" align="center" prop="paperTpye"/> -->
- <el-table-column label="来源" align="center" prop="source"/>
- <!-- <el-table-column label="试题来源" align="center" prop="fromSite"/> -->
- <!-- <el-table-column label="图片水印" align="center" prop="isSub"/> -->
- <!-- <el-table-column label="常规题" align="center" prop="isNormal"/> -->
- <el-table-column label="匹配知识点" align="center" prop="isKonw" min-width="120"/>
- <el-table-column label="tiid" align="center" prop="tiid" min-width="100"/>
- <!-- <el-table-column label="试题题干的md5值" align="center" prop="md5" /> -->
- <!-- <el-table-column label="是否唯一" align="center" prop="isunique"/> -->
- <!-- <el-table-column label="md52" align="center" prop="md52" /> -->
- <el-table-column label="分值" align="center" prop="score"/>
- <!-- <el-table-column label="选项" align="center" prop="options"/> -->
- <!-- <el-table-column label="选项" align="center" prop="options0"/> -->
- <!-- <el-table-column label="number" align="center" prop="number" /> -->
- <!-- <el-table-column label="paperTypeTitle" align="center" prop="paperTypeTitle" /> -->
- <!-- <el-table-column label="试题-材料题题干" align="center" prop="title0" min-width="130" show-overflow-tooltip/> -->
- <!-- <el-table-column label="试题-材料题题干" align="center" prop="title1" min-width="130" show-overflow-tooltip/> -->
- <!-- <el-table-column label="试题解析" align="left" prop="parse0" header-align="center" show-overflow-tooltip/> -->
- <!-- <el-table-column label="answer0" align="center" prop="answer0"/> -->
- <el-table-column label="是否更新" align="center" prop="isUpdate">
- <template #default="scope">
- <dict-tag :options="bool_values" :value="scope.row.isUpdate" />
- </template>
- </el-table-column>
- <el-table-column label="包含子题" align="center" prop="isSubType">
- <template #default="scope">
- <dict-tag :options="bool_values" :value="scope.row.isSubType" />
- </template>
- </el-table-column>
- <el-table-column label="操作" align="center" class-name="small-padding fixed-width" min-width="140"
- fixed="right">
- <template #default="scope">
- <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"
- v-hasPermi="['learn:questions:edit']">修改
- </el-button>
- <el-button link type="primary" icon="" @click="handleTextUpdate(scope.row)"
- v-hasPermi="['learn:questions:edit']">文本修改
- </el-button>
- <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"
- v-hasPermi="['learn:questions:remove']">删除
- </el-button>
- </template>
- </el-table-column>
- </el-table>
- <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
- v-model:limit="queryParams.pageSize" @pagination="getList"/>
- <!-- 添加或修改试题对话框 -->
- <el-dialog :title="title" v-model="open" width="1200px" append-to-body>
- <div class="form-content-wrapper">
- <el-form ref="questionsRef" :model="form" :rules="rules" label-width="140px">
- <!-- 只读显示区域:题目标题和选项(仅在修改时显示) -->
- <div class="readonly-section" v-if="form.id != null">
- <el-form-item label="标题">
- <div class="readonly-content" v-html="formatContentWithImages(form.title) || '-'"></div>
- </el-form-item>
- <el-row :gutter="20" v-if="form.optionA || form.optionB || form.optionC || form.optionD || form.optionE || form.optionF || form.optionG">
- <el-col :span="12" v-if="form.optionA">
- <el-form-item label="选项A">
- <div class="readonly-content" v-html="formatContentWithImages(form.optionA)"></div>
- </el-form-item>
- </el-col>
- <el-col :span="12" v-if="form.optionB">
- <el-form-item label="选项B">
- <div class="readonly-content" v-html="formatContentWithImages(form.optionB)"></div>
- </el-form-item>
- </el-col>
- <el-col :span="12" v-if="form.optionC">
- <el-form-item label="选项C">
- <div class="readonly-content" v-html="formatContentWithImages(form.optionC)"></div>
- </el-form-item>
- </el-col>
- <el-col :span="12" v-if="form.optionD">
- <el-form-item label="选项D">
- <div class="readonly-content" v-html="formatContentWithImages(form.optionD)"></div>
- </el-form-item>
- </el-col>
- <el-col :span="12" v-if="form.optionE">
- <el-form-item label="选项E">
- <div class="readonly-content" v-html="formatContentWithImages(form.optionE)"></div>
- </el-form-item>
- </el-col>
- <el-col :span="12" v-if="form.optionF">
- <el-form-item label="选项F">
- <div class="readonly-content" v-html="formatContentWithImages(form.optionF)"></div>
- </el-form-item>
- </el-col>
- <el-col :span="12" v-if="form.optionG">
- <el-form-item label="选项G">
- <div class="readonly-content" v-html="formatContentWithImages(form.optionG)"></div>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20" v-if="form.answer1 || form.answer2">
- <el-col :span="12" v-if="form.answer1">
- <el-form-item label="答案1">
- <div class="readonly-content" v-html="formatContentWithImages(form.answer1)"></div>
- </el-form-item>
- </el-col>
- <el-col :span="12" v-if="form.answer2">
- <el-form-item label="答案2">
- <div class="readonly-content" v-html="formatContentWithImages(form.answer2)"></div>
- </el-form-item>
- </el-col>
- </el-row>
- </div>
- <!-- 横线分隔(仅在修改时显示) -->
- <el-divider v-if="form.id != null"></el-divider>
- <!-- 可修改内容区域,两列布局 -->
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="科目" prop="subjectId">
- <el-select v-model="form.subjectId" placeholder="请选择科目" style="width: 100%">
- <el-option v-for="s in subjectList" :label="s.subjectName" :value="s.subjectId"/>
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="题型" prop="qtpye">
- <el-input v-model="form.qtpye" type="text" placeholder="请输入内容"/>
- </el-form-item>
- </el-col>
- </el-row>
- <el-form-item label="标题" prop="title">
- <Editor v-if="!isTextMode" v-model="form.title" :min-height="120" />
- <el-input v-else v-model="form.title" type="textarea" :autosize="{ minRows: 3 }" placeholder="请输入标题内容"/>
- </el-form-item>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="选项A" prop="optionA">
- <Editor v-if="!isTextMode" v-model="form.optionA" :min-height="120" />
- <el-input v-else v-model="form.optionA" type="textarea" :autosize="{ minRows: 3 }" placeholder="请输入内容"/>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="选项B" prop="optionB">
- <Editor v-if="!isTextMode" v-model="form.optionB" :min-height="120" />
- <el-input v-else v-model="form.optionB" type="textarea" :autosize="{ minRows: 3 }" placeholder="请输入内容"/>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="选项C" prop="optionC">
- <Editor v-if="!isTextMode" v-model="form.optionC" :min-height="120" />
- <el-input v-else v-model="form.optionC" type="textarea" :autosize="{ minRows: 3 }" placeholder="请输入内容"/>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="选项D" prop="optionD">
- <Editor v-if="!isTextMode" v-model="form.optionD" :min-height="120" />
- <el-input v-else v-model="form.optionD" type="textarea" :autosize="{ minRows: 3 }" placeholder="请输入内容"/>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="选项E" prop="optionE">
- <Editor v-if="!isTextMode" v-model="form.optionE" :min-height="120" />
- <el-input v-else v-model="form.optionE" type="textarea" :autosize="{ minRows: 3 }" placeholder="请输入内容"/>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="选项F" prop="optionF">
- <Editor v-if="!isTextMode" v-model="form.optionF" :min-height="120" />
- <el-input v-else v-model="form.optionF" type="textarea" :autosize="{ minRows: 3 }" placeholder="请输入内容"/>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="选项G" prop="optionG">
- <Editor v-if="!isTextMode" v-model="form.optionG" :min-height="120" />
- <el-input v-else v-model="form.optionG" type="textarea" :autosize="{ minRows: 3 }" placeholder="请输入内容"/>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="答案1" prop="answer1">
- <Editor v-if="!isTextMode" v-model="form.answer1" :min-height="120" />
- <el-input v-else v-model="form.answer1" type="textarea" :autosize="{ minRows: 3 }" placeholder="请输入内容"/>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="答案2" prop="answer2">
- <Editor v-if="!isTextMode" v-model="form.answer2" :min-height="120" />
- <el-input v-else v-model="form.answer2" type="textarea" :autosize="{ minRows: 3 }" placeholder="请输入内容"/>
- </el-form-item>
- </el-col>
- </el-row>
- <!-- <el-form-item label="题型" prop="qtpye">
- <el-select v-model="form.typeId" placeholder="请选择类型">
- <el-option v-for="q in question_type" :label="q.label" :value="q.value"/>
- </el-select>
- </el-form-item> -->
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="知识点" prop="knowledgeId">
- <el-tree-select node-key="id" v-model="form.knowledgeId" :data="knowledgeTreeList" check-strictly
- :render-after-expand="false" style="width: 100%"
- :props="{ label: 'name', children: 'children' }"
- placeholder="请选择知识点"/>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="来源" prop="source">
- <el-input v-model="form.source" placeholder="请输入来源"/>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="源ID" prop="tiid">
- <el-input v-model="form.tiid" placeholder="请输入试题的源ID"/>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="试题解析" prop="parse">
- <Editor v-if="!isTextMode" v-model="form.parse" :min-height="120" />
- <el-input v-else v-model="form.parse" type="textarea" :autosize="{ minRows: 3 }" placeholder="请输入内容"/>
- </el-form-item>
- </el-col>
- </el-row>
- <!-- <el-form-item label="试题题干的md5值" prop="md5">
- <el-input v-model="form.md5" placeholder="请输入试题题干的md5值" />
- </el-form-item> -->
- <!-- <el-form-item label="${comment}" prop="isunique">
- <el-input v-model="form.isunique" placeholder="请输入${comment}" />
- </el-form-item> -->
- <!-- <el-form-item label="${comment}" prop="md52">
- <el-input v-model="form.md52" placeholder="请输入${comment}" />
- </el-form-item> -->
- <!-- <el-form-item label="分值" prop="score">
- <el-input v-model="form.score" placeholder="请输入分值"/>
- </el-form-item>
- <el-form-item label="选项" prop="options">
- <el-input v-model="form.options" type="textarea" placeholder="请输入内容"/>
- </el-form-item> -->
- <!-- <el-form-item label="${comment}" prop="number">
- <el-input v-model="form.number" placeholder="请输入${comment}" />
- </el-form-item> -->
- <!-- <el-form-item label="${comment}" prop="paperTypeTitle">
- <el-input v-model="form.paperTypeTitle" placeholder="请输入${comment}" />
- </el-form-item> -->
- <!-- <el-form-item label="选项" prop="options0">
- <el-input v-model="form.options0" type="textarea" placeholder="请输入内容"/>
- </el-form-item>
- <el-form-item label="试题-材料题题干" prop="title0">
- <el-input v-model="form.title0" type="textarea" placeholder="请输入内容"/>
- </el-form-item>
- <el-form-item label="试题-材料题题干" prop="title1">
- <el-input v-model="form.title1" type="textarea" placeholder="请输入内容"/>
- </el-form-item>
- <el-form-item label="试题解析" prop="parse0">
- <el-input v-model="form.parse0" type="textarea" placeholder="请输入内容"/>
- </el-form-item> -->
- <!-- <el-form-item label="${comment}" prop="answer0">
- <el-input v-model="form.answer0" type="textarea" placeholder="请输入内容" />
- </el-form-item> -->
- <!-- <el-form-item label="是否更新" prop="isUpdate">
- <el-input v-model="form.isUpdate" placeholder="请输入是否更新"/>
- </el-form-item> -->
- </el-form>
- </div>
- <template #footer>
- <div class="dialog-footer">
- <el-button type="primary" @click="submitForm">确 定</el-button>
- <el-button @click="cancel">取 消</el-button>
- </div>
- </template>
- </el-dialog>
- <!-- 选项详情弹窗 -->
- <el-dialog v-model="showOptionsDialog" title="选项详情" width="600px" append-to-body>
- <div class="options-detail">
- <div class="option-item" v-if="currentRow.optionA">
- <div class="option-label">选项A:</div>
- <div class="option-content">{{ currentRow.optionA }}</div>
- </div>
- <div class="option-item" v-if="currentRow.optionB">
- <div class="option-label">选项B:</div>
- <div class="option-content">{{ currentRow.optionB }}</div>
- </div>
- <div class="option-item" v-if="currentRow.optionC">
- <div class="option-label">选项C:</div>
- <div class="option-content">{{ currentRow.optionC }}</div>
- </div>
- <div class="option-item" v-if="currentRow.optionD">
- <div class="option-label">选项D:</div>
- <div class="option-content">{{ currentRow.optionD }}</div>
- </div>
- <div class="option-item" v-if="currentRow.optionE">
- <div class="option-label">选项E:</div>
- <div class="option-content">{{ currentRow.optionE }}</div>
- </div>
- <div class="option-item" v-if="currentRow.optionF">
- <div class="option-label">选项F:</div>
- <div class="option-content">{{ currentRow.optionF }}</div>
- </div>
- <div class="option-item" v-if="currentRow.optionG">
- <div class="option-label">选项G:</div>
- <div class="option-content">{{ currentRow.optionG }}</div>
- </div>
- <div v-if="!currentRow.optionA && !currentRow.optionB && !currentRow.optionC && !currentRow.optionD && !currentRow.optionE && !currentRow.optionF && !currentRow.optionG" class="no-options">
- 暂无选项内容
- </div>
- </div>
- <template #footer>
- <div class="dialog-footer">
- <el-button @click="showOptionsDialog = false">关 闭</el-button>
- </div>
- </template>
- </el-dialog>
- <el-dialog v-model="showTypeDialog" title="修改题型" show-close width="500px" append-to-body>
- <div class="text-content">题号:{{typeForm.ids}}</div>
- <div class="mt-2 mb-2">共<el-text type="primary">{{typeForm.ids.length}}</el-text>项</div>
- <div>
- <el-select v-model="typeForm.type" placeholder="请选择题型或者输入自定义题型"
- filterable allow-create default-first-option>
- <el-option v-for="t in question_type" :label="t.label" :value="t.value" />
- </el-select>
- </div>
- <template #footer>
- <div class="dialog-footer">
- <el-button type="primary" @click="handleUpdateType">确 定</el-button>
- <el-button @click="showTypeDialog=false">取 消</el-button>
- </div>
- </template>
- </el-dialog>
- </div>
- </template>
- <script setup name="Questions">
- import {listQuestions, getQuestions, delQuestions, addQuestions, updateQuestions, changeQuestionType} from "@/api/learn/questions"
- import {listKnowledgeTree} from "@/api/learn/knowledgeTree"
- import {listAllSubject} from "@/api/dz/subject"
- import {ElMessage} from "element-plus";
- import DictTag from '@/components/DictTag/index.vue'
- import Editor from '@/components/Editor/index.vue'
- import { computed } from 'vue'
- const {proxy} = getCurrentInstance()
- const {question_type} = proxy.useDict('question_type')
- const {paper_type} = proxy.useDict('paper_type')
- const {bool_values} = proxy.useDict('bool_values')
- const questionsList = ref([])
- const open = ref(false)
- const loading = ref(true)
- const showSearch = ref(true)
- const ids = ref([])
- const single = ref(true)
- const multiple = ref(true)
- const total = ref(0)
- const title = ref("")
- const typeForm = ref({
- ids: [],
- type: ''
- })
- const showTypeDialog = ref(false)
- const showOptionsDialog = ref(false)
- const currentRow = ref({})
- const isTextMode = ref(false) // 是否为文本模式(false为富文本模式)
- const subjectList = ref([])
- const knowledgeTreeList = ref([])
- /** 根据subjectId过滤知识点树 */
- const filteredKnowledgeTreeList = computed(() => {
- if (!queryParams.value.subjectId) {
- return knowledgeTreeList.value
- }
- return filterKnowledgeTreeBySubjectId(knowledgeTreeList.value, queryParams.value.subjectId)
- })
- /** 递归过滤知识点树 */
- function filterKnowledgeTreeBySubjectId(tree, subjectId) {
- if (!tree || !Array.isArray(tree)) {
- return []
- }
- const result = []
- for (const node of tree) {
- // 如果当前节点的subjectId匹配,或者有子节点匹配,则保留该节点
- const filteredChildren = node.children ? filterKnowledgeTreeBySubjectId(node.children, subjectId) : []
- if (node.subjectId === subjectId || filteredChildren.length > 0) {
- result.push({
- ...node,
- children: filteredChildren.length > 0 ? filteredChildren : (node.children || [])
- })
- }
- }
- return result
- }
- const data = reactive({
- form: {},
- queryParams: {
- pageNum: 1,
- pageSize: 10,
- id: null,
- title: null,
- optionA: null,
- optionB: null,
- optionC: null,
- optionD: null,
- optionE: null,
- optionF: null,
- optionG: null,
- answer1: null,
- answer2: null,
- qtpye: null,
- typeId: null,
- subjectId: null,
- paperId: null,
- knowledgeId: null,
- diff: null,
- similarity: null,
- parse: null,
- knowId: null,
- gradeId: null,
- knowledges: null,
- area: null,
- year: null,
- paperTpye: null,
- source: null,
- fromSite: null,
- isSub: null,
- isNormal: null,
- isKonw: null,
- tiid: null,
- md5: null,
- isunique: null,
- md52: null,
- score: null,
- options: null,
- number: null,
- paperTypeTitle: null,
- options0: null,
- title0: null,
- title1: null,
- parse0: null,
- answer0: null,
- isUpdate: null,
- isSubType: null
- },
- rules: {}
- })
- setTimeout(() => {
- console.log(question_type)
- }, 1000)
- const {queryParams, form, rules} = toRefs(data)
- /** 查询试题列表 */
- function getList() {
- loading.value = true
- // 处理查询参数,确保id是数字类型
- const params = { ...queryParams.value }
- if (params.id) {
- // 将id转换为数字类型
- const idNum = Number(params.id)
- if (!isNaN(idNum)) {
- params.id = idNum
- } else {
- params.id = null
- }
- }
- listQuestions(params).then(response => {
- questionsList.value = response.rows
- total.value = response.total
- loading.value = false
- })
- }
- function getKnowledgeTreeList() {
- listKnowledgeTree({}).then(res => {
- knowledgeTreeList.value = res.data
- })
- }
- function getSubjectList() {
- listAllSubject({}).then(res => {
- subjectList.value = res.data
- })
- }
- /** 根据学科ID获取学科名称 */
- function getSubjectName(subjectId) {
- if (!subjectId || !subjectList.value || subjectList.value.length === 0) {
- return '-'
- }
- const subject = subjectList.value.find(s => s.subjectId === subjectId)
- return subject ? subject.subjectName : '-'
- }
- // 取消按钮
- function cancel() {
- open.value = false
- isTextMode.value = false // 重置模式
- reset()
- }
- // 表单重置
- function reset() {
- form.value = {
- id: null,
- title: null,
- optionA: null,
- optionB: null,
- optionC: null,
- optionD: null,
- optionE: null,
- optionF: null,
- optionG: null,
- answer1: null,
- answer2: null,
- qtpye: null,
- subjectId: null,
- paperId: null,
- knowledgeId: null,
- diff: null,
- similarity: null,
- parse: null,
- knowId: null,
- gradeId: null,
- knowledges: null,
- area: null,
- year: null,
- paperTpye: null,
- source: null,
- fromSite: null,
- isSub: null,
- isNormal: null,
- isKonw: null,
- tiid: null,
- md5: null,
- isunique: null,
- md52: null,
- createTime: null,
- score: null,
- options: null,
- number: null,
- paperTypeTitle: null,
- options0: null,
- title0: null,
- title1: null,
- parse0: null,
- answer0: null,
- isUpdate: null,
- isSubType: null
- }
- // 先重置表单验证状态
- if (proxy.$refs["questionsRef"]) {
- proxy.$refs["questionsRef"].resetFields()
- proxy.$refs["questionsRef"].clearValidate()
- }
- }
- /** 科目变化处理 */
- function handleSubjectChange() {
- // 清空知识点选择,因为科目变化后知识点列表会变化
- queryParams.value.knowledgeId = null
- handleQuery()
- }
- /** 搜索按钮操作 */
- function handleQuery() {
- queryParams.value.pageNum = 1
- getList()
- }
- /** 重置按钮操作 */
- function resetQuery() {
- proxy.resetForm("queryRef")
- // 手动清除 typeId,因为 resetForm 可能无法清除 el-select 的值
- queryParams.value.typeId = null
- handleQuery()
- }
- // 多选框选中数据
- function handleSelectionChange(selection) {
- ids.value = selection.map(item => item.id)
- single.value = selection.length != 1
- multiple.value = !selection.length
- }
- /** 新增按钮操作 */
- function handleAdd() {
- reset()
- isTextMode.value = false // 新增使用富文本模式
- open.value = true
- title.value = "添加试题"
- }
- /** 文本修改按钮操作 */
- function handleTextUpdate(row) {
- reset()
- isTextMode.value = true // 文本修改使用普通文本模式
- const _id = row.id || ids.value
- getQuestions(_id).then(response => {
- form.value = response.data
- open.value = true
- title.value = "文本修改"
- })
- }
- /** 修改按钮操作 */
- function handleUpdate(row) {
- reset()
- isTextMode.value = false // 修改使用富文本模式
- const _id = row.id || ids.value
- getQuestions(_id).then(response => {
- form.value = response.data
- open.value = true
- title.value = "修改试题"
- })
- }
- /** 提交按钮 */
- function submitForm() {
- proxy.$refs["questionsRef"].validate(valid => {
- if (valid) {
- // 提交所有可编辑字段(包括题干和选项)
- if (form.value.id != null) {
- updateQuestions(form.value).then(response => {
- proxy.$modal.msgSuccess("修改成功")
- open.value = false
- isTextMode.value = false // 重置模式
- getList()
- })
- } else {
- addQuestions(form.value).then(response => {
- proxy.$modal.msgSuccess("新增成功")
- open.value = false
- isTextMode.value = false // 重置模式
- getList()
- })
- }
- }
- })
- }
- /** 删除按钮操作 */
- function handleDelete(row) {
- const _ids = row.id || ids.value
- proxy.$modal.confirm('是否确认删除试题编号为"' + _ids + '"的数据项?').then(function () {
- return delQuestions(_ids)
- }).then(() => {
- getList()
- proxy.$modal.msgSuccess("删除成功")
- }).catch(() => {
- })
- }
- /** 导出按钮操作 */
- function handleExport() {
- proxy.download('learn/questions/export', {
- ...queryParams.value
- }, `questions_${new Date().getTime()}.xlsx`)
- }
- function handleChangeType() {
- typeForm.value.ids = ids.value
- typeForm.value.type = ''
- showTypeDialog.value = true
- }
- async function handleUpdateType() {
- const {ids, type} = typeForm.value
- if (!ids.length) return ElMessage.error('请选择试题')
- if (!type) return ElMessage.error('请选择题型')
- await changeQuestionType({ids, type})
- ElMessage.success('保存成功')
- showTypeDialog.value = false
- getList()
- }
- /** 显示选项详情 */
- function handleShowOptions(row) {
- currentRow.value = row || {}
- showOptionsDialog.value = true
- }
- /** 获取图片代理URL(如果需要后端代理,可以在这里实现) */
- function getImageProxyUrl(imageUrl) {
- if (!imageUrl) return ''
- // 如果是相对路径或本地路径,直接返回
- if (!imageUrl.startsWith('http://') && !imageUrl.startsWith('https://') && !imageUrl.startsWith('//')) {
- return imageUrl
- }
- // 如果需要通过后端代理访问第三方图片,可以取消下面的注释
- // 注意:需要后端提供图片代理接口
- // const encodedUrl = encodeURIComponent(imageUrl)
- // return `${import.meta.env.VITE_APP_BASE_API}/common/image/proxy?url=${encodedUrl}`
- // 暂时直接返回原URL,通过添加跨域属性来处理
- return imageUrl
- }
- /** 格式化内容,将图片URL转换为img标签 */
- function formatContentWithImages(content) {
- if (!content) return ''
- // 如果内容已经是HTML格式(包含img标签),需要处理其中的图片URL
- if (content.includes('<img') || content.includes('<IMG')) {
- // 提取所有img标签中的src属性
- const imgSrcRegex = /<img[^>]+src=["']([^"']+)["'][^>]*>/gi
- let formattedContent = content
- formattedContent = formattedContent.replace(imgSrcRegex, (match, src) => {
- // 如果是第三方图片URL,转换为代理URL
- let imageUrl = src
- if (src.startsWith('http://') || src.startsWith('https://') || src.startsWith('//')) {
- // 对于第三方图片,尝试使用代理
- // 如果代理不可用,则使用原URL并添加跨域属性
- imageUrl = getImageProxyUrl(src)
- // 如果代理URL和原URL相同(代理不可用),添加跨域属性
- if (imageUrl === src) {
- return match.replace(src, src).replace('<img', '<img crossorigin="anonymous" referrerpolicy="no-referrer"')
- } else {
- return match.replace(src, imageUrl)
- }
- }
- return match
- })
- return formattedContent
- }
- // 匹配图片URL的正则表达式
- // 支持:https://、http://、//开头的完整URL,以及相对路径
- const imageUrlRegex = /(https?:\/\/[^\s<>"']+\.(jpg|jpeg|png|gif|bmp|webp|svg)(\?[^\s<>"']*)?)|(\/\/[^\s<>"']+\.(jpg|jpeg|png|gif|bmp|webp|svg)(\?[^\s<>"']*)?)|(\/[^\s<>"']+\.(jpg|jpeg|png|gif|bmp|webp|svg)(\?[^\s<>"']*)?)/gi
- // 将纯文本的图片URL转换为img标签
- let formattedContent = content
- const matches = content.match(imageUrlRegex)
- if (matches) {
- matches.forEach(url => {
- // 确保URL是完整的
- let imageUrl = url.trim()
- // 如果是以//开头的,添加https:
- if (imageUrl.startsWith('//')) {
- imageUrl = 'https:' + imageUrl
- }
- // 对于第三方图片,尝试使用代理
- const proxyUrl = getImageProxyUrl(imageUrl)
- // 如果代理不可用,使用原URL并添加跨域属性
- const finalUrl = proxyUrl !== imageUrl ? proxyUrl : imageUrl
- const crossOriginAttr = proxyUrl === imageUrl ? 'crossorigin="anonymous" referrerpolicy="no-referrer"' : ''
- // 将URL替换为img标签
- const imgTag = `<img src="${finalUrl}" ${crossOriginAttr} alt="图片" style="max-width: 100%; height: auto; display: block; margin: 10px 0;" onerror="this.onerror=null; this.src='${imageUrl}'; this.style.border='1px solid #ddd'; this.alt='图片加载失败,点击查看原图'; this.style.cursor='pointer'; this.title='点击查看原图'; this.onclick='window.open(this.src)';" />`
- formattedContent = formattedContent.replace(url, imgTag)
- })
- }
- return formattedContent
- }
- getKnowledgeTreeList()
- getSubjectList()
- getList()
- </script>
- <style scoped>
- .options-detail {
- padding: 10px 0;
- }
- .option-item {
- margin-bottom: 15px;
- display: flex;
- align-items: flex-start;
- }
- .option-label {
- font-weight: bold;
- min-width: 60px;
- color: #606266;
- }
- .option-content {
- flex: 1;
- word-break: break-word;
- white-space: pre-wrap;
- line-height: 1.6;
- }
- .no-options {
- text-align: center;
- color: #909399;
- padding: 20px 0;
- }
- .readonly-section {
- background-color: #f5f7fa;
- padding: 15px;
- border-radius: 4px;
- margin-bottom: 20px;
- }
- .readonly-content {
- color: #606266;
- word-break: break-word;
- white-space: pre-wrap;
- line-height: 1.6;
- min-height: 20px;
- }
- .readonly-content :deep(img) {
- max-width: 100%;
- height: auto;
- display: block;
- margin: 10px 0;
- border-radius: 4px;
- object-fit: contain;
- }
- .readonly-content :deep(img[src=""]) {
- display: none;
- }
- .readonly-content :deep(img:not([src])) {
- display: none;
- }
- .form-content-wrapper {
- max-width: 1100px;
- margin: 0 auto;
- }
- /* 表格单元格内容样式 */
- .table-cell-content {
- word-break: break-word;
- line-height: 1.6;
- }
- .table-cell-content :deep(img) {
- max-width: 100%;
- height: auto;
- display: block;
- margin: 5px 0;
- border-radius: 4px;
- object-fit: contain;
- }
- .table-cell-content :deep(img[src=""]) {
- display: none;
- }
- .table-cell-content :deep(img:not([src])) {
- display: none;
- }
- </style>
|