Compare commits

..

2 Commits

Author SHA1 Message Date
lwj
4e711d774c style:调整样式 2025-12-18 16:46:18 +08:00
lwj
2f403efa9a fix:试题管理操作不便 2025-12-12 16:29:00 +08:00
10 changed files with 34 additions and 80 deletions

View File

@@ -167,7 +167,7 @@
import simplePaper from "@/components/Course/simpleTestPaper.vue"; import simplePaper from "@/components/Course/simpleTestPaper.vue";
import apiCourse from '../../api/modules/course.js'; import apiCourse from '../../api/modules/course.js';
import apiExamPaper from '../../api/modules/paper.js'; import apiExamPaper from '../../api/modules/paper.js';
import { deepClone, safeJsonParse } from "../../utils"; import { deepClone } from "../../utils";
export default{ export default{
components:{simplePaper}, components:{simplePaper},
props:{ props:{
@@ -253,7 +253,7 @@
this.examInfo=res.result; this.examInfo=res.result;
if(res.result.paperType==1){ if(res.result.paperType==1){
this.examInfo.paperContent=res.result.paperContent; this.examInfo.paperContent=res.result.paperContent;
this.examPaper = safeJsonParse(res.result.paperContent, { items: [] }); this.examPaper=JSON.parse(res.result.paperContent);
}else{ }else{
apiExamPaper.detail(this.examInfo.paperId).then(rs=>{ apiExamPaper.detail(this.examInfo.paperId).then(rs=>{
if(rs.status==200){ if(rs.status==200){

View File

@@ -1218,7 +1218,7 @@ export default {
}); });
this.teacherValues = tlist; this.teacherValues = tlist;
this.teacherDownList = tlist; this.teacherDownList = tlist;
if (this.courseInfo.tags) { if (this.courseInfo.tags != '') {
this.showTags = this.courseInfo.tags.split(','); this.showTags = this.courseInfo.tags.split(',');
} }
this.$nextTick(function() { this.$nextTick(function() {

View File

@@ -132,7 +132,6 @@ import apiCourse from '@/api/modules/course.js';
import apiExamPaper from '@/api/modules/paper.js'; import apiExamPaper from '@/api/modules/paper.js';
import {formatDate,formatSeconds} from '@/utils/datetime.js'; import {formatDate,formatSeconds} from '@/utils/datetime.js';
import {testType,correctJudgment,numberToLetter} from '@/utils/tools.js'; import {testType,correctJudgment,numberToLetter} from '@/utils/tools.js';
import { safeJsonParse } from '@/utils/index.js';
export default { export default {
props:{ props:{
studyId: { studyId: {
@@ -218,11 +217,7 @@ export default {
if(res.status==200){ if(res.status==200){
this.info=res.result; this.info=res.result;
if(this.showTest) { if(this.showTest) {
let paper = safeJsonParse(this.info.paperContent, { items: [] }); let paper= JSON.parse(this.info.paperContent);
if(!paper.items || paper.items.length === 0){
this.viewTest = [];
return;
}
paper.items.forEach(item=>{ paper.items.forEach(item=>{
//console.log(item); //console.log(item);
if(item.type==101){ if(item.type==101){

View File

@@ -575,7 +575,7 @@
import apiExamPaper from '../../api/modules/paper.js'; import apiExamPaper from '../../api/modules/paper.js';
import audioPlayer from '@/components/AudioPlayer/index.vue'; import audioPlayer from '@/components/AudioPlayer/index.vue';
import {getType} from '../../utils/tools.js'; import {getType} from '../../utils/tools.js';
import { deepClone, safeJsonParse } from "../../utils"; import { deepClone } from "../../utils";
export default{ export default{
components:{WxEditor,simplePaper,FileUpload,pdfPreview,audioPlayer,chooseCourseFile}, components:{WxEditor,simplePaper,FileUpload,pdfPreview,audioPlayer,chooseCourseFile},
props: { props: {
@@ -921,7 +921,7 @@
if(res.status==200){ if(res.status==200){
this.exam.info=res.result; this.exam.info=res.result;
if(res.result.paperType==1){ if(res.result.paperType==1){
this.exam.paperJson = safeJsonParse(res.result.paperContent, { items: [] }); this.exam.paperJson=JSON.parse(res.result.paperContent);
}else{ }else{
apiExamPaper.detail(this.exam.info.paperId).then(rs=>{ apiExamPaper.detail(this.exam.info.paperId).then(rs=>{
if(rs.status==200){ if(rs.status==200){

View File

@@ -109,7 +109,6 @@
import imgupload from '@/components/ImageUpload/single.vue'; import imgupload from '@/components/ImageUpload/single.vue';
import apiExamTask from '@/api/modules/examTask.js'; import apiExamTask from '@/api/modules/examTask.js';
import examQuestionApi from "@/api/modules/question"; import examQuestionApi from "@/api/modules/question";
import { safeJsonParse } from '../../utils';
import {numberToLetter, deepCopy} from '../../utils/tools.js'; import {numberToLetter, deepCopy} from '../../utils/tools.js';
export default { export default {
name: 'comEditPaper', name: 'comEditPaper',
@@ -164,7 +163,7 @@
if(res.status === 200) { if(res.status === 200) {
this.paper=res.result; this.paper=res.result;
//转化试题 //转化试题
this.qitems = safeJsonParse(res.result.paperContent, []); this.qitems=JSON.parse(res.result.paperContent);
//console.log(this.qitems,this.qitems) //console.log(this.qitems,this.qitems)
this.tempItems=this.qitems; this.tempItems=this.qitems;
this.paperCalculation(); this.paperCalculation();

View File

@@ -106,8 +106,7 @@
>贡献者大会</span >贡献者大会</span
> >
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<!-- <el-dropdown-item command="four">2025</el-dropdown-item>--> <el-dropdown-item command="three">2024</el-dropdown-item>
<el-dropdown-item command="three" divided>2024</el-dropdown-item>
<el-dropdown-item command="one" divided>2023</el-dropdown-item> <el-dropdown-item command="one" divided>2023</el-dropdown-item>
<el-dropdown-item command="two" divided>2022</el-dropdown-item> <el-dropdown-item command="two" divided>2022</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
@@ -422,7 +421,6 @@ export default {
one: urlPre + "/web/contributornew/index", one: urlPre + "/web/contributornew/index",
two: urlPre + "/web/contributor/index", two: urlPre + "/web/contributor/index",
three: urlPre + "/web/contributor_2024/index", three: urlPre + "/web/contributor_2024/index",
four: urlPre + "/web/contributor_2025/index",
}; };
window.open(obj[val]); window.open(obj[val]);
}, },

View File

@@ -310,42 +310,6 @@ export function deepClone(source) {
return targetObj return targetObj
} }
import { Message } from 'element-ui';
/**
* 安全解析 JSON 字符串,统一处理错误日志和 UI 提示
* @param {string|object} text 待解析的字符串(或对象)
* @param {*} fallback 解析失败或为空时的回退值,默认为空对象 {}
* @param {string} errorMessage UI 提示信息,默认为试卷格式错误提示
* @returns {*}
*/
export function safeJsonParse(text, fallback = {}, errorMessage = '试卷内容格式有误,请联系管理员检查试卷数据') {
// 1. 如果已经是对象或数组,直接返回
if (typeof text === 'object' && text !== null) {
return text;
}
// 2. 处理空值情况
if (text === null || text === undefined || text === '') {
return fallback;
}
// 3. 尝试解析
try {
return JSON.parse(text);
} catch (error) {
// 4. 统一日志和报错
console.error('JSON 解析失败:', {
input: text,
error: error.message
});
if (errorMessage) {
Message.error(errorMessage);
}
return fallback;
}
}
/** /**
* @param {Array} arr * @param {Array} arr
* @returns {Array} * @returns {Array}

View File

@@ -3,7 +3,7 @@
<el-container> <el-container>
<el-header style="height:70px;padding: 12px 20px 10px 20px;" > <el-header style="height:70px;padding: 12px 20px 10px 20px;" >
<el-row> <el-row>
<!-- <el-col :span="4"> <el-col :span="4">
<el-cascader <el-cascader
:options="resOwnerListMap" :options="resOwnerListMap"
v-model="params.ownership" v-model="params.ownership"
@@ -11,7 +11,7 @@
clearable clearable
:props="resourceProps"> :props="resourceProps">
</el-cascader> </el-cascader>
</el-col> --> </el-col>
<el-col :span="4"> <el-col :span="4">
<el-select v-model="params.type" clearable placeholder="类型" > <el-select v-model="params.type" clearable placeholder="类型" >
<el-option v-for="item in optionsList" :key="item.value" :label="item.label" :value="item.value"> </el-option> <el-option v-for="item in optionsList" :key="item.value" :label="item.label" :value="item.value"> </el-option>
@@ -20,7 +20,7 @@
<el-col :span="3"> <el-col :span="3">
<el-input style="margin-left:10px" v-model="params.title" placeholder="题干" clearable></el-input> <el-input style="margin-left:10px" v-model="params.title" placeholder="题干" clearable></el-input>
</el-col> </el-col>
<el-col :span="17" style="display:flex;justify-content: space-between;"> <el-col :span="8" style="display:flex;justify-content: space-between;">
<div style="flex: 1;"> <div style="flex: 1;">
<el-button type="primary" @click="getsearch(1)" style="margin-left: 20px" icon="el-icon-search" >搜索</el-button> <el-button type="primary" @click="getsearch(1)" style="margin-left: 20px" icon="el-icon-search" >搜索</el-button>
<el-button icon="el-icon-refresh-right" type="primary" @click="reset"> 重置 </el-button> <el-button icon="el-icon-refresh-right" type="primary" @click="reset"> 重置 </el-button>
@@ -47,13 +47,13 @@
<span class="previewStyle" @click="viewTopic(scope.row)">{{ scope.row.title }}</span> <span class="previewStyle" @click="viewTopic(scope.row)">{{ scope.row.title }}</span>
</template> </template>
</el-table-column> </el-table-column>
<!-- <el-table-column prop="resSysId" label="资源归属" width="240px" show-overflow-tooltip> <el-table-column prop="resSysId" label="资源归属" width="240px" show-overflow-tooltip>
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{resOwnerName(scope.row.resOwner1)}}</span> <span>{{resOwnerName(scope.row.resOwner1)}}</span>
<span v-if="scope.row.resOwner2 != ''">/{{resOwnerName(scope.row.resOwner2)}}</span> <span v-if="scope.row.resOwner2 != ''">/{{resOwnerName(scope.row.resOwner2)}}</span>
<span v-if="scope.row.resOwner3 != ''">/{{resOwnerName(scope.row.resOwner3)}}</span> <span v-if="scope.row.resOwner3 != ''">/{{resOwnerName(scope.row.resOwner3)}}</span>
</template> </template>
</el-table-column> --> </el-table-column>
<el-table-column prop="type" label="类型" width="70px"> <el-table-column prop="type" label="类型" width="70px">
<template slot-scope="scope"> <template slot-scope="scope">
{{ scope.row.type == 1 ? "单选" : scope.row.type == 2 ? "多选" : scope.row.type == 3 ? "判断题" : "" }} {{ scope.row.type == 1 ? "单选" : scope.row.type == 2 ? "多选" : scope.row.type == 3 ? "判断题" : "" }}
@@ -92,9 +92,9 @@
<div style="padding-top: 10px; overflow: auto"> <div style="padding-top: 10px; overflow: auto">
<div> <div>
<el-form size="mini" label-width="80px" :model="question" ref="questionForm" :rules="questionRules"> <el-form size="mini" label-width="80px" :model="question" ref="questionForm" :rules="questionRules">
<!-- <el-form-item label="资源归属"> <el-form-item label="资源归属">
<el-cascader v-model="ownership" :options="resOwnerListMap" :props="resourceProps"></el-cascader> <el-cascader v-model="ownership" :options="resOwnerListMap" :props="resourceProps"></el-cascader>
</el-form-item> --> </el-form-item>
<el-form-item label="题干" prop="title"> <el-form-item label="题干" prop="title">
<el-col :span="15"> <el-col :span="15">
<el-input class="inputclass" type="textarea" :rows="5" maxlength="500" show-word-limit v-model="question.title" placeholder="请输入题干"></el-input> <el-input class="inputclass" type="textarea" :rows="5" maxlength="500" show-word-limit v-model="question.title" placeholder="请输入题干"></el-input>
@@ -180,9 +180,9 @@
<div style="padding-top: 10px; overflow: auto"> <div style="padding-top: 10px; overflow: auto">
<div> <div>
<el-form size="mini" label-width="80px" :model="question" ref="questionForm" :rules="questionRules"> <el-form size="mini" label-width="80px" :model="question" ref="questionForm" :rules="questionRules">
<!-- <el-form-item label="资源归属"> <el-form-item label="资源归属">
<el-cascader v-model="ownership" :options="resOwnerListMap" :props="resourceProps" ></el-cascader> <el-cascader v-model="ownership" :options="resOwnerListMap" :props="resourceProps" ></el-cascader>
</el-form-item> --> </el-form-item>
<el-form-item label="题干" prop="title"> <el-form-item label="题干" prop="title">
<el-col :span="15"> <el-col :span="15">
<el-input class="inputclass" type="textarea" :rows="5" maxlength="500" show-word-limit v-model="question.title" placeholder="请输入题干"></el-input> <el-input class="inputclass" type="textarea" :rows="5" maxlength="500" show-word-limit v-model="question.title" placeholder="请输入题干"></el-input>

View File

@@ -296,7 +296,7 @@
import apiPaper from '@/api/modules/paper.js'; import apiPaper from '@/api/modules/paper.js';
import apiExamTask from '@/api/modules/examTask.js'; import apiExamTask from '@/api/modules/examTask.js';
import examQuestionApi from "@/api/modules/question"; import examQuestionApi from "@/api/modules/question";
import { deepClone, safeJsonParse } from '../../utils'; import { deepClone } from '../../utils';
import {numberToLetter, deepCopy} from '../../utils/tools.js'; import {numberToLetter, deepCopy} from '../../utils/tools.js';
import { mapGetters,mapActions} from 'vuex'; import { mapGetters,mapActions} from 'vuex';
import editPaper from "@/components/Exam/EditPaper"; import editPaper from "@/components/Exam/EditPaper";
@@ -689,7 +689,7 @@ export default {
this.viewVolumeShow=true; this.viewVolumeShow=true;
apiPaper.detail(row.id).then(res=>{ apiPaper.detail(row.id).then(res=>{
if(res.status === 200) { if(res.status === 200) {
this.viewShowData = safeJsonParse(res.result.paperContent, { items: [] }); this.viewShowData = JSON.parse(res.result.paperContent);
console.log(this.viewShowData,'lll') console.log(this.viewShowData,'lll')
} else { } else {
this.$message.error(res.message); this.$message.error(res.message);
@@ -720,9 +720,8 @@ export default {
apiPaper.detail(row.id).then(res=>{ apiPaper.detail(row.id).then(res=>{
if(res.status === 200) { if(res.status === 200) {
this.paper = res.result; this.paper = res.result;
const parsedValue = safeJsonParse(res.result.paperContent, []); this.paper.data = JSON.parse(res.result.paperContent);
this.paper.data = parsedValue; this.paperData = JSON.parse(res.result.paperContent);
this.paperData = parsedValue;
this.paper.paperType = Number(res.result.paperType); this.paper.paperType = Number(res.result.paperType);
if(res.result.resOwner3) { if(res.result.resOwner3) {
this.resOwner = [res.result.resOwner1,res.result.resOwner2,res.result.resOwner3]; this.resOwner = [res.result.resOwner1,res.result.resOwner2,res.result.resOwner3];

View File

@@ -357,7 +357,7 @@ import apiCourse from "@/api/modules/course.js";
import apiCourseFile from "@/api/modules/courseFile.js"; import apiCourseFile from "@/api/modules/courseFile.js";
import apiCoursePortal from "@/api/modules/coursePortal.js"; import apiCoursePortal from "@/api/modules/coursePortal.js";
import apiUser from '@/api/system/user.js'; import apiUser from '@/api/system/user.js';
import { import {
formatDate, formatDate,
resListMap, resListMap,
toScore, toScore,
@@ -365,9 +365,8 @@ import apiUser from '@/api/system/user.js';
getType, getType,
numberToLetter, numberToLetter,
correctJudgment correctJudgment
} from "@/utils/tools.js"; } from "@/utils/tools.js";
import { safeJsonParse } from "@/utils"; import apicourseStudy from "@/api/modules/courseStudy.js";
import apicourseStudy from "@/api/modules/courseStudy.js";
import apiCourseGrade from "@/api/modules/courseGrade.js"; import apiCourseGrade from "@/api/modules/courseGrade.js";
import apiPraises from "@/api/modules/praises.js"; import apiPraises from "@/api/modules/praises.js";
import apiTrample from "@/api/modules/trample.js"; import apiTrample from "@/api/modules/trample.js";
@@ -717,7 +716,7 @@ export default {
apiCourse.getExam(this.examInfo.content.id).then(res => { apiCourse.getExam(this.examInfo.content.id).then(res => {
if (res.status == 200) { if (res.status == 200) {
this.examInfo.info = res.result; this.examInfo.info = res.result;
this.examInfo.paper = safeJsonParse(res.result.paperContent, { items: [] }); this.examInfo.paper = JSON.parse(res.result.paperContent);
} else if (res.status == 404) { } else if (res.status == 404) {
//没有找到考试信息 //没有找到考试信息
} else { } else {