|
@@ -0,0 +1,822 @@
|
|
|
+<template>
|
|
|
+ <div class="df-container">
|
|
|
+ <Loading :top="200" v-show="isLoading" hideMask type="1"></Loading>
|
|
|
+ <Poptip padding="0px 0px" offset="10" placement="top-end" width="300" trigger="hover" :class="shoppingCarClass">
|
|
|
+ <Badge type="primary" :count="selectedArr.length" show-zero :offset="[-3,-3]" @mouseenter.native="changeActive($event)" @mouseleave.native="removeActive($event)">
|
|
|
+ <Icon custom="iconfont icon-sp-car" color="#05C19C" size="50" />
|
|
|
+ </Badge>
|
|
|
+ <div slot="content">
|
|
|
+ <div class="shopping-car-detail">
|
|
|
+ <p class="shopping-car-detail-title">{{$t('evaluation.createPaper.total')}}<span style="margin:0px 5px;">{{selectedArr.length}}</span>{{$t('evaluation.createPaper.nums')}}</p>
|
|
|
+ <div class="shopping-car-detail-item">
|
|
|
+ <span class="question-type">{{$t('evaluation.single')}}:</span>
|
|
|
+ <Progress stroke-color="#6bdfc3" :percent="getPercent('single')" :stroke-width="15" style="width:165px;vertical-align:top;padding-top:2px;" hide-info />
|
|
|
+ <span class="question-num">{{quesTypeList.single}}{{$t('evaluation.createPaper.spc')}}</span>
|
|
|
+ </div>
|
|
|
+ <div class="shopping-car-detail-item">
|
|
|
+ <span class="question-type">{{$t('evaluation.multiple')}}:</span>
|
|
|
+ <Progress stroke-color="#6bdfc3" :percent="getPercent('multiple')" :stroke-width="15" style="width:165px;vertical-align:top;padding-top:2px;" hide-info />
|
|
|
+ <span class="question-num">{{quesTypeList.multiple}}{{$t('evaluation.createPaper.spc')}}</span>
|
|
|
+ </div>
|
|
|
+ <!-- <div class="shopping-car-detail-item">
|
|
|
+ <span class="question-type">{{$t('evaluation.judge')}}:</span>
|
|
|
+ <Progress stroke-color="#6bdfc3" :percent="getPercent('judge')" :stroke-width="15" style="width:165px;vertical-align:top;padding-top:2px;" hide-info />
|
|
|
+ <span class="question-num">{{quesTypeList.judge}}{{$t('evaluation.createPaper.spc')}}</span>
|
|
|
+ </div> -->
|
|
|
+ <div class="shopping-car-detail-item">
|
|
|
+ <span class="question-type">{{$t('evaluation.complete')}}:</span>
|
|
|
+ <Progress stroke-color="#6bdfc3" :percent="getPercent('complete')" :stroke-width="15" style="width:165px;vertical-align:top;padding-top:2px;" hide-info />
|
|
|
+ <span class="question-num">{{quesTypeList.complete}}{{$t('evaluation.createPaper.spc')}}</span>
|
|
|
+ </div>
|
|
|
+ <div class="shopping-car-detail-item">
|
|
|
+ <span class="question-type">{{$t('evaluation.subjective')}}:</span>
|
|
|
+ <Progress stroke-color="#6bdfc3" :percent="getPercent('subjective')" :stroke-width="15" style="width:165px;vertical-align:top;padding-top:2px;" hide-info />
|
|
|
+ <span class="question-num">{{quesTypeList.subjective}}{{$t('evaluation.createPaper.spc')}}</span>
|
|
|
+ </div>
|
|
|
+ <div class="shopping-car-detail-item">
|
|
|
+ <span class="question-type">{{$t('evaluation.compose')}}:</span>
|
|
|
+ <Progress stroke-color="#6bdfc3" :percent="getPercent('compose')" :stroke-width="15" style="width:165px;vertical-align:top;padding-top:2px;" hide-info />
|
|
|
+ <span class="question-num">{{quesTypeList.compose}}{{$t('evaluation.createPaper.spc')}}</span>
|
|
|
+ </div>
|
|
|
+ <p class="shopping-car-detail-bottom" @click="goToPreview">{{$t('evaluation.createPaper.goDetails')}}</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </Poptip>
|
|
|
+ <div class="new-exercise-header">
|
|
|
+ <span class="ev-title">
|
|
|
+ 多分题库
|
|
|
+ </span>
|
|
|
+ <div>
|
|
|
+ <Button @click="backToBank" class="btn-back-to-bank" icon="md-arrow-round-back" style="margin-left: 10px">{{ $t('evaluation.newExercise.backToBank')}}</Button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="create-body">
|
|
|
+ <div class="filter-wrap">
|
|
|
+ <div class="filter-item">
|
|
|
+ <span class="filter-title">{{$t('evaluation.filter.grade')}}:</span>
|
|
|
+ <RadioGroup v-model="filterGrade" type="button" @on-change="getDfList()">
|
|
|
+ <Radio v-for="(item, index) in gradeList" :key="index" :label="index + 1" style="margin-bottom: 5px;">{{ item }}</Radio>
|
|
|
+ </RadioGroup>
|
|
|
+ </div>
|
|
|
+ <div class="filter-item">
|
|
|
+ <span class="filter-title">{{$t('evaluation.filter.subject')}}:</span>
|
|
|
+ <RadioGroup v-model="filterSubject" type="button" @on-change="getDfList()">
|
|
|
+ <Radio v-for="(item, index) in subjectList" :key="index" :label="item.id" style="margin-bottom: 5px;">{{ item.name }}</Radio>
|
|
|
+ </RadioGroup>
|
|
|
+ </div>
|
|
|
+ <div class="filter-item">
|
|
|
+ <span class="filter-title">{{$t('evaluation.filter.type')}}:</span>
|
|
|
+ <RadioGroup v-model="filterType" type="button" @on-change="getDfList()">
|
|
|
+ <Radio label="all" style="margin-bottom: 5px;">全部</Radio>
|
|
|
+ <Radio v-for="(item, index) in typeList" :key="index" :label="item.id" style="margin-bottom: 5px;">{{ item.name }}</Radio>
|
|
|
+ </RadioGroup>
|
|
|
+ </div>
|
|
|
+ <div class="filter-item">
|
|
|
+ <span class="filter-title">{{$t('evaluation.filter.diff')}}:</span>
|
|
|
+ <RadioGroup v-model="filterDiff" type="button" @on-change="getDfList()">
|
|
|
+ <Radio label="all" style="margin-bottom: 5px;">全部</Radio>
|
|
|
+ <Radio v-for="(item, index) in exersicesDiff" :key="index" :label="index + 1" style="margin-bottom: 5px;">{{ item }}</Radio>
|
|
|
+ </RadioGroup>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="bank-action-bar">
|
|
|
+ <div class="action-tools">
|
|
|
+ <div class="action-tool">
|
|
|
+ <Input v-model="searchVal" placeholder="输入关键词搜索试题..." style="width: 300px;" clearable search @on-search="getDfList()"></Input>
|
|
|
+ </div>
|
|
|
+ <div class="action-tool">
|
|
|
+ <Checkbox v-model="isAllOpen" @on-change="onHandleToggle">{{ $t('evaluation.exerciseList.showAllAnswer') }}</Checkbox>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="action-tools" style="display:flex;align-items: center;">
|
|
|
+ <Checkbox v-model="isSelectAll" @on-change="onSelectAll" v-if="($access.can('admin.*||exercise-upd'))">{{ $t('evaluation.choosePageItems') }}</Checkbox>
|
|
|
+ <span style="margin-left:20px">
|
|
|
+ {{ $t('evaluation.exerciseList.totalTip1') }}
|
|
|
+ <span style="font-size: 18px;color: #ff0206;margin: 0 10px;font-weight: bold;">{{ totalNum }}</span>
|
|
|
+ {{ $t('evaluation.exerciseList.unit') }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-if="!exerciseList.length" class="no-data-text">
|
|
|
+ <img src="@/assets/icon/no_data_evaluation.png" width="120" />
|
|
|
+ <span style="margin-top: 15px; color: #808080">{{$t('evaluation.noData')}}</span>
|
|
|
+ </div>
|
|
|
+ <div v-else class="content-wrap" ref="mathJaxContainer">
|
|
|
+ <div class="exercise-item" v-for="(item, index) of exerciseList" :key="index" @click="onQuestionToggle(index, item.id, $event)">
|
|
|
+ <!-- 题干部分 -->
|
|
|
+ <div class="item-question">
|
|
|
+ <div>
|
|
|
+ <div class="item-question-order">{{ pageSize * (pageNum - 1) + index + 1 }} :</div>
|
|
|
+ <div class="item-question-text" v-html="item.question"></div>
|
|
|
+ </div>
|
|
|
+ <span class="item-btn-toggle" style="justify-content: flex-end;">
|
|
|
+ <Icon v-if="item.type !== 'compose'" :type="collapseList.indexOf(index) > -1 ? 'ios-arrow-dropup' : 'ios-arrow-dropdown'" />
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <div class="exercise-item-children" v-if="item.children.length">
|
|
|
+ <BaseChild ref="childRef" :children="item.children" inBank></BaseChild>
|
|
|
+ </div>
|
|
|
+ <!-- 选项部分 -->
|
|
|
+ <div v-for="(option, optionIndex) in item.option" :key="optionIndex" class="item-options">
|
|
|
+ <div class="item-option-content">
|
|
|
+ <div class="item-option-order">
|
|
|
+ {{ String.fromCharCode(64 + parseInt(optionIndex + 1)) }} :
|
|
|
+ </div>
|
|
|
+ <div class="item-option-text" v-html="option.value"></div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <transition name="slide" v-if="item.type !== 'compose'">
|
|
|
+ <div v-show="collapseList.indexOf(exerciseList.indexOf(item)) > -1" class="toggle-area">
|
|
|
+ <div>
|
|
|
+ <!-- 答案展示部分 -->
|
|
|
+ <div class="item-explain">
|
|
|
+ <span class="explain-title">【{{$t('evaluation.answer')}}】</span>
|
|
|
+ <div class="item-explain-details">
|
|
|
+ <!-- 问答题答案 -->
|
|
|
+ <div v-if="item.type === 'subjective' || item.type === 'complete' || item.type === 'connector' || item.type === 'correct' ">
|
|
|
+ <span v-for="(answer, index) in item.answer" :key="index" v-html="item.answer.length ? answer : $t('evaluation.noAnswer')"></span>
|
|
|
+ </div>
|
|
|
+ <!-- 判断题答案 -->
|
|
|
+ <div v-else-if="item.type === 'judge'">
|
|
|
+ <span>{{ item.answer.length ? (item.answer[0] === 'A' ? $t('evaluation.isTrue') : $t('evaluation.isFalse')) : $t('utils.noData') }}</span>
|
|
|
+ </div>
|
|
|
+ <!-- 其余题型答案 -->
|
|
|
+ <div v-else>
|
|
|
+ <span :class="[ item.type === 'complete' ? 'item-answer-item' : '']" v-for="(answer, index) in item.answer" :key="index">{{ answer }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 解析部分 -->
|
|
|
+ <div class="item-explain">
|
|
|
+ <span class="explain-title">【{{$t('evaluation.explain')}}】</span>
|
|
|
+ <div class="item-explain-details">
|
|
|
+ <span v-html="item.explain ||$t('utils.noData')"></span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 知识点部分 -->
|
|
|
+ <div class="item-explain">
|
|
|
+ <span class="explain-title">【{{$t('evaluation.knowledgePoints')}}】</span>
|
|
|
+ <div class="item-explain-details">
|
|
|
+ <span v-if="!item.knowledge || !item.knowledge.length">{{ $t('utils.noData') }}</span>
|
|
|
+ <div v-else>
|
|
|
+ <span v-for="(point, index) in item.knowledge" class="item-point-tag" :key="index">
|
|
|
+ {{ point }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 补救资源部分 -->
|
|
|
+ <div class="item-explain" v-show="isShowAnswer">
|
|
|
+ <span class="explain-title">【{{ $t('evaluation.newExercise.repair') }}】</span>
|
|
|
+ <div class="item-explain-details">
|
|
|
+ <div v-if="item.repair && item.repair.length" style="display: flex; flex-wrap: wrap;">
|
|
|
+ <div class="repair-item" v-for="(link, index) in item.repair" :key="index">
|
|
|
+ <img :src="$tools.getFileThum(link.type, link.name)" width="20" />
|
|
|
+ <span class="repair-item-link" @click.stop="onRepairLinkClick(link)">{{ link.name }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <span v-else>{{ $t('utils.noData') }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </transition>
|
|
|
+ <!-- 底部题目操作栏 -->
|
|
|
+ <div class="item-tools">
|
|
|
+ <span class="item-tools-info">{{$t('evaluation.filter.grade')}}:{{ gradeList[parseInt(item.grade) - 1] }}</span>
|
|
|
+ <span class="item-tools-info">{{$t('evaluation.filter.subject')}}:{{ item.subject }}</span>
|
|
|
+ <span class="item-tools-info">{{$t('evaluation.filter.type')}}:{{ exersicesType[item.type] }}</span>
|
|
|
+ <span class="item-tools-info">{{$t('evaluation.filter.diff')}}:{{ exersicesDiff[item.level - 1] }}</span>
|
|
|
+
|
|
|
+ <div class="buttons" style="float:right;display:flex;flex-direction:row-reverse;align-items:center">
|
|
|
+ <Button type="info" :style="{backgroundColor: selectedArr.map((i) => i.id).indexOf(item.id) > -1 ? '#bbbbbb' : '#2db7f5'}" @click.stop="handleChoose(item)">
|
|
|
+ {{ids.indexOf(item.id) > -1 ? $t('evaluation.removeItem') : $t('evaluation.selectItem')}}
|
|
|
+ </Button>
|
|
|
+ <!-- <Button type="text" @click.stop="handleDelete(item)" v-if="($access.can('admin.*||exercise-upd') || (filterOrigin !== schoolCode)) && !isComponent" icon="md-trash">{{$t('evaluation.deleteItem')}}</Button> -->
|
|
|
+ <!-- <Button type="text" @click.stop="handleEdit(item)" v-if="($access.can('admin.*||exercise-upd') || (filterOrigin !== schoolCode)) && !isComponent" icon="md-create">{{$t('evaluation.editItem')}}</Button> -->
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 底部分页区域 -->
|
|
|
+ <Page :total="totalNum" show-sizer show-total :page-size="pageSize" :current="pageNum" @on-page-size-change="pageSizeChange" @on-change="pageChange" :page-size-opts="[10, 20, 30]" />
|
|
|
+ </div>
|
|
|
+ <Drawer title="已选择题目" width="40" :mask-closable="false" v-model="showQues" class="select-ques">
|
|
|
+ <RadioGroup v-model="saveType" @on-change="saveTypeChange">
|
|
|
+ <Radio label="quesBank">题库</Radio>
|
|
|
+ <Radio label="paper">试卷</Radio>
|
|
|
+ </RadioGroup>
|
|
|
+ <div v-if="!selShowList.length">未选择题目</div>
|
|
|
+ <div v-else class="content-wrap" style="height: 95%;">
|
|
|
+ <vuescroll>
|
|
|
+ <div class="list-view" v-for="(quesItem, quesIndex) in selShowList" :key="quesIndex">
|
|
|
+ <p v-show="saveType === 'paper' && quesItem.list.length" class="type-name">
|
|
|
+ {{ $tools.getChineseByNum(getLatestTypeIndex(quesItem.type) + 1) }} : {{ exersicesType[quesItem.type] }}
|
|
|
+ <span style="font-size: 14px;font-weight: 600;">
|
|
|
+ ({{ `${$t('answerSheet.tip9')} ${quesItem.list.length}${$t('answerSheet.tip17')}${quesItem.score || 0}${$t('evaluation.paperList.score')}` }})
|
|
|
+ </span>
|
|
|
+ </p>
|
|
|
+ <div class="exercise-item" v-for="(item, index) in quesItem.list" :key="index" @click="onQuestionToggle(index, item.id, $event)">
|
|
|
+ <!-- 工具栏部分 -->
|
|
|
+ <div class="item-tools-wrap" v-show="saveType === 'paper'">
|
|
|
+ <div class="item-tools-t flex-row-center" @click.stop="handleDelete(quesItem.list,item,index)">
|
|
|
+ <Icon type="ios-archive-outline" />{{$t('evaluation.deleteItem')}}
|
|
|
+ </div>
|
|
|
+ <div class="item-tools-t flex-row-center" v-show="index != 0" @click.stop="handleMoveUp(quesItem.list,index)">
|
|
|
+ <Icon type="md-arrow-up" />{{$t('evaluation.exerciseList.moveUp')}}
|
|
|
+ </div>
|
|
|
+ <div class="item-tools-t flex-row-center" v-show="index != (quesItem.list.length - 1)" @click.stop="handleMoveDown(quesItem.list,index)">
|
|
|
+ <Icon type="md-arrow-down" />{{$t('evaluation.exerciseList.moveDown')}}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="item-question">
|
|
|
+ <div>
|
|
|
+ <div class="item-question-order">{{ index + 1 }} :</div>
|
|
|
+ <div class="item-question-text" v-html="item.question"></div>
|
|
|
+ </div>
|
|
|
+ <span class="item-btn-toggle" style="justify-content: flex-end;">
|
|
|
+ <Icon v-if="item.type !== 'compose'" :type="selcollaList.indexOf(index) > -1 ? 'ios-arrow-dropup' : 'ios-arrow-dropdown'" />
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <div class="exercise-item-children" v-if="item.children.length">
|
|
|
+ <BaseChild ref="childRef" :children="item.children" inBank></BaseChild>
|
|
|
+ </div>
|
|
|
+ <div v-for="(option, optionIndex) in item.option" :key="optionIndex" class="item-options">
|
|
|
+ <div class="item-option-content">
|
|
|
+ <div class="item-option-order">
|
|
|
+ {{ String.fromCharCode(64 + parseInt(optionIndex + 1)) }} :
|
|
|
+ </div>
|
|
|
+ <div class="item-option-text" v-html="option.value"></div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="item-btn-toggle" v-show="saveType === 'paper'">
|
|
|
+ <!-- 可调整分数 -->
|
|
|
+ <InputNumber v-if="item.type !== 'compose'" :max="item.score + surPlusScore" :min="scoreStep" :step="scoreStep" v-model="item.score" style="display: inline-block ;width: 60px;margin-right: 10px;height: 30px;" @click.stop>
|
|
|
+ </InputNumber>
|
|
|
+ <span style="margin-right: 10px;" v-if="item.type === 'compose'">{{ getComposeScore(item) }}</span>
|
|
|
+ <span style="margin-right: 10px;">{{$t('evaluation.paperList.score')}}</span>
|
|
|
+ <!-- <span class="item-score" title="设置题目分数" @click.stop="onSetSingleItem(item,index)" v-else>{{ item.score }} 分</span> -->
|
|
|
+ <Icon @click.stop="onQuestionToggle(selectedArr.indexOf(item), item.id, $event, quesItem.list)" :type="selcollaList.indexOf(selectedArr.indexOf(item)) > -1 ? 'ios-arrow-dropup' : 'ios-arrow-dropdown'" v-if="item.type !== 'compose'" />
|
|
|
+ </div>
|
|
|
+ <transition name="slide" v-if="item.type !== 'compose'">
|
|
|
+ <div v-show="selcollaList.indexOf(selectedArr.indexOf(item)) > -1" class="toggle-area">
|
|
|
+ <div>
|
|
|
+ <!-- 答案展示部分 -->
|
|
|
+ <div class="item-explain">
|
|
|
+ <span class="explain-title">【{{$t('evaluation.answer')}}】</span>
|
|
|
+ <div class="item-explain-details">
|
|
|
+ <!-- 问答题答案 -->
|
|
|
+ <div v-if="item.type === 'subjective' || item.type === 'complete' || item.type === 'connector' || item.type === 'correct' ">
|
|
|
+ <span v-for="(answer, index) in item.answer" :key="index" v-html="item.answer.length ? answer : $t('evaluation.noAnswer')"></span>
|
|
|
+ </div>
|
|
|
+ <!-- 判断题答案 -->
|
|
|
+ <div v-else-if="item.type === 'judge'">
|
|
|
+ <span>{{ item.answer.length ? (item.answer[0] === 'A' ? $t('evaluation.isTrue') : $t('evaluation.isFalse')) : $t('utils.noData') }}</span>
|
|
|
+ </div>
|
|
|
+ <!-- 其余题型答案 -->
|
|
|
+ <div v-else>
|
|
|
+ <span :class="[ item.type === 'complete' ? 'item-answer-item' : '']" v-for="(answer, index) in item.answer" :key="index">{{ answer }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 解析部分 -->
|
|
|
+ <div class="item-explain">
|
|
|
+ <span class="explain-title">【{{$t('evaluation.explain')}}】</span>
|
|
|
+ <div class="item-explain-details">
|
|
|
+ <span v-html="item.explain ||$t('utils.noData')"></span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 知识点部分 -->
|
|
|
+ <div class="item-explain">
|
|
|
+ <span class="explain-title">【{{$t('evaluation.knowledgePoints')}}】</span>
|
|
|
+ <div class="item-explain-details">
|
|
|
+ <span v-if="!item.knowledge || !item.knowledge.length">{{ $t('utils.noData') }}</span>
|
|
|
+ <div v-else>
|
|
|
+ <span v-for="(point, index) in item.knowledge" class="item-point-tag" :key="index">
|
|
|
+ {{ point }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 补救资源部分 -->
|
|
|
+ <div class="item-explain" v-show="isShowAnswer">
|
|
|
+ <span class="explain-title">【{{ $t('evaluation.newExercise.repair') }}】</span>
|
|
|
+ <div class="item-explain-details">
|
|
|
+ <div v-if="item.repair && item.repair.length" style="display: flex; flex-wrap: wrap;">
|
|
|
+ <div class="repair-item" v-for="(link, index) in item.repair" :key="index">
|
|
|
+ <img :src="$tools.getFileThum(link.type, link.name)" width="20" />
|
|
|
+ <span class="repair-item-link" @click.stop="onRepairLinkClick(link)">{{ link.name }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <span v-else>{{ $t('utils.noData') }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </transition>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </vuescroll>
|
|
|
+ </div>
|
|
|
+ <div style="display: flex; justify-content: space-between;" v-show="selShowList.length">
|
|
|
+ <Button v-show="saveType === 'paper'" @click="saveDFQues('paper')">保存为试卷</Button>
|
|
|
+ <Button v-show="saveType != 'paper'" @click="saveDFQues('quesBank')">加入题库</Button>
|
|
|
+ </div>
|
|
|
+ </Drawer>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import blobTool from '@/utils/blobTool.js'
|
|
|
+import ExerciseList from '@/components/evaluation/ExerciseList.vue'
|
|
|
+export default {
|
|
|
+ components: {
|
|
|
+ ExerciseList
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ isLoading: false,
|
|
|
+ gradeList: ['一年级', '二年级', '三年级', '四年级', '五年级', '六年级', '七年级', '八年级', '九年级', '十年级', '十一年级', '十二年级'],
|
|
|
+ subjectList: [
|
|
|
+ {id: '语文', name: '语文'},
|
|
|
+ {id: '数学', name: '数学'},
|
|
|
+ {id: '英语', name: '英语'},
|
|
|
+ {id: '物理', name: '物理'},
|
|
|
+ {id: '化学', name: '化学'},
|
|
|
+ {id: '地理', name: '地理'},
|
|
|
+ {id: '历史', name: '历史'},
|
|
|
+ {id: '生物', name: '生物'},
|
|
|
+ {id: '政治', name: '政治'},
|
|
|
+ ],
|
|
|
+ typeList: [
|
|
|
+ {id: 'C', name: '选择'},
|
|
|
+ {id: 'F', name: '填空'},
|
|
|
+ {id: 'Q', name: '问答'},
|
|
|
+ {id: 'W', name: '写作'},
|
|
|
+ {id: 'S', name: '综合'},
|
|
|
+ ],
|
|
|
+ exersicesDiff: this.$GLOBAL.EXERCISE_DIFFS(),
|
|
|
+ exersicesType: this.$GLOBAL.EXERCISE_TYPES(),
|
|
|
+ exersicesField: this.$GLOBAL.EXERCISE_LEVELS(),
|
|
|
+ filterGrade: 10,
|
|
|
+ filterSubject: '物理',
|
|
|
+ filterType: 'all',
|
|
|
+ filterDiff: 'all',
|
|
|
+ searchVal: '',
|
|
|
+ totalNum: 0,
|
|
|
+ pageSize: 5,
|
|
|
+ pageNum: 1,
|
|
|
+ exerciseList: [],
|
|
|
+ collapseList: [],
|
|
|
+ selectedArr: [],
|
|
|
+ selcollaList: [],
|
|
|
+ orderList: [],
|
|
|
+ groupList: [],
|
|
|
+ selShowList: [],
|
|
|
+ isSelectAll: false,
|
|
|
+ isShowAnswer: true,
|
|
|
+ isAllOpen: false,
|
|
|
+ showQues: false,
|
|
|
+ saveType: 'quesBank',
|
|
|
+ shoppingCarClass: 'question-shopping-car',
|
|
|
+ quesTypeList: {
|
|
|
+ single: 0,
|
|
|
+ multiple: 0,
|
|
|
+ judge: 0,
|
|
|
+ complete: 0,
|
|
|
+ subjective: 0,
|
|
|
+ compose: 0
|
|
|
+ },
|
|
|
+ scoreStep: 0.5,
|
|
|
+ surPlusScore: 0,
|
|
|
+ needSaveCosmosArr: [],
|
|
|
+ }
|
|
|
+ },
|
|
|
+ created() {
|
|
|
+ this.getDfList()
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ ids() {
|
|
|
+ return this.selectedArr.map(i => i.id)
|
|
|
+ },
|
|
|
+ getPercent(type) {
|
|
|
+ return type => {
|
|
|
+ return this.selectedArr.length ? ((this.quesTypeList[type] * 100) / this.selectedArr.length) : 0
|
|
|
+ }
|
|
|
+ },
|
|
|
+ isSchool() {
|
|
|
+ return this.$route.name === 'schoolDf'
|
|
|
+ },
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ getDfList() {
|
|
|
+ this.isLoading = true
|
|
|
+ let param = {
|
|
|
+ subject: this.filterSubject,
|
|
|
+ grades: this.filterGrade,
|
|
|
+ // type: this.filterType,
|
|
|
+ // difficulty: this.filterDiff,
|
|
|
+ pageSize: this.pageSize,
|
|
|
+ currentPage: this.pageNum,
|
|
|
+ }
|
|
|
+ if(this.filterDiff != 'all') param.difficulty = this.filterDiff
|
|
|
+ if(this.filterType != 'all') param.type = this.filterType
|
|
|
+ if(this.searchVal) param.search = this.searchVal
|
|
|
+ this.$api.newEvaluation.dfQuesList(param).then(res => {
|
|
|
+ if(res.code === 200) {
|
|
|
+ this.exerciseList = res.items
|
|
|
+ this.totalNum = res.count
|
|
|
+ }
|
|
|
+ }).finally(() => {
|
|
|
+ this.isLoading = false
|
|
|
+ })
|
|
|
+ },
|
|
|
+ async handleChoose(item) {
|
|
|
+ if (this.ids.indexOf(item.id) === -1) {
|
|
|
+ this.selectedArr.push(item) //添加题目
|
|
|
+ } else {
|
|
|
+ for (let i = 0; i < this.selectedArr.length; i++) {
|
|
|
+ if (this.selectedArr[i].id === item.id) {
|
|
|
+ this.selectedArr.splice(i, 1) //移除
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ let groupResult = await this.$jsFn.groupBy(this.selectedArr, 'type')
|
|
|
+ for (let i = 0; i < groupResult.length; i++) {
|
|
|
+ this.quesTypeList[groupResult[i][0].type] = groupResult[i].length
|
|
|
+ }
|
|
|
+ this.isSelectAll = this.selectedArr.length === this.exerciseList.length
|
|
|
+ // this.$emit('chooseQuChange', this.selectedArr)
|
|
|
+ },
|
|
|
+ async pageChange(page) {
|
|
|
+ this.pageNum = page;
|
|
|
+ /* let start = this.pageSize * (page - 1);
|
|
|
+ let end = this.pageSize * page;
|
|
|
+ // 拿到当前页码需要展示的数据
|
|
|
+ let simpleList = this.originData.slice(start, end);
|
|
|
+ try {
|
|
|
+ // 执行试题换取完整JSON数据
|
|
|
+ this.exerciseList = await this.$evTools.getFullItem(simpleList);
|
|
|
+ // this.totalNum = this.exerciseList.length
|
|
|
+ this.pageScrollTo(0);
|
|
|
+ this.onHandleToggle(false)
|
|
|
+ this.$refs.childRef && this.$refs.childRef[0] && (this.$refs.childRef[0].collapseList = [])
|
|
|
+ } catch (e) {
|
|
|
+ this.$Message.error('Blob Error : ' + e)
|
|
|
+ } */
|
|
|
+ this.getDfList()
|
|
|
+ },
|
|
|
+ pageSizeChange(val) {
|
|
|
+ this.pageSize = val;
|
|
|
+ this.pageChange(1);
|
|
|
+ },
|
|
|
+ backToBank() {
|
|
|
+ this.$router.push({
|
|
|
+ name: "schoolBank",
|
|
|
+ params: {
|
|
|
+ tabName: "exercise",
|
|
|
+ },
|
|
|
+ });
|
|
|
+ },
|
|
|
+ onQuestionToggle(index, id, e) {
|
|
|
+ console.log(e)
|
|
|
+ this.shoppingCarClass = 'question-shopping-car animated heartBeat'
|
|
|
+ setTimeout(() => {
|
|
|
+ this.shoppingCarClass = 'question-shopping-car'
|
|
|
+ }, 1000)
|
|
|
+ let curClassName = e.target.className
|
|
|
+ if (
|
|
|
+ curClassName === "item-tools" ||
|
|
|
+ curClassName === "richText-video" ||
|
|
|
+ curClassName === "richText-audio" ||
|
|
|
+ curClassName === "ivu-checkbox-input" ||
|
|
|
+ curClassName === "ivu-checkbox-wrapper ivu-checkbox-default"
|
|
|
+ )
|
|
|
+ return
|
|
|
+ e.stopPropagation()
|
|
|
+ let listIndex = this.collapseList.indexOf(index)
|
|
|
+ if (listIndex > -1) {
|
|
|
+ this.collapseList.splice(listIndex, 1)
|
|
|
+ } else {
|
|
|
+ this.collapseList.push(index)
|
|
|
+ let path = this.$tools.composedPath(e)
|
|
|
+ let exerciseItemDom = path.filter((i) => i.className === "exercise-item")
|
|
|
+ if (exerciseItemDom.length) {
|
|
|
+ this.pageScrollTo(exerciseItemDom[0].offsetTop + 180)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ pageScrollTo(scrollDistance) {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ let parentVm = this.$parent.$parent.$parent
|
|
|
+ if (parentVm.$refs["evScroll"]) {
|
|
|
+ parentVm.$refs["evScroll"].scrollTo({y: scrollDistance}, 500, "easeInQuad")
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ changeActive(e) {
|
|
|
+ this.shoppingCarClass = 'question-shopping-car animated pulse'
|
|
|
+ },
|
|
|
+ removeActive() {
|
|
|
+ this.shoppingCarClass = 'question-shopping-car'
|
|
|
+ },
|
|
|
+ goToPreview() {
|
|
|
+ this.orderList = []
|
|
|
+ this.groupList = []
|
|
|
+ let that = this
|
|
|
+ let typesList = this._.cloneDeep(this.exersicesType)
|
|
|
+ for (const types in typesList) {
|
|
|
+ this._.mapKeys(this._.groupBy(this.selectedArr, 'type'), function (value, key) {
|
|
|
+ if (key === types) { /* 按照题型排序,并且计算每种题型的总分 */
|
|
|
+ that.groupList.push({
|
|
|
+ type: key,
|
|
|
+ list: value,
|
|
|
+ score: 0
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ this.orderList.push({list: this._.cloneDeep(this.selectedArr)})
|
|
|
+ this.selShowList = this._.cloneDeep(this.orderList)
|
|
|
+ // 总分默认100
|
|
|
+ this.surPlusScore = 100 - this.selectedArr.reduce((p, e) => Number(p) + Number(e.score), 0);
|
|
|
+ this.showQues = true
|
|
|
+ // this.$emit('goToPreview')
|
|
|
+ // 使用弹出框展示已选题目,再选择加入题库/组成试卷
|
|
|
+ },
|
|
|
+ async onSelectAll() {
|
|
|
+ this.selectedArr = this.isSelectAll ? this._.cloneDeep(this.exerciseList) : []
|
|
|
+ let groupResult = await this.$jsFn.groupBy(this.selectedArr, 'type')
|
|
|
+ if(groupResult.length) {
|
|
|
+ for (let i = 0; i < groupResult.length; i++) {
|
|
|
+ this.quesTypeList[groupResult[i][0].type] = groupResult[i].length
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ for (const key in this.quesTypeList) {
|
|
|
+ this.quesTypeList[key] = 0
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ /* 全部展开与全部折叠 */
|
|
|
+ onHandleToggle(isAllClose) {
|
|
|
+ if (!isAllClose) {
|
|
|
+ this.collapseList = [];
|
|
|
+ } else {
|
|
|
+ this.collapseList = [...this.exerciseList.keys()];
|
|
|
+ }
|
|
|
+ },
|
|
|
+ saveTypeChange(val) {
|
|
|
+ if(val === 'quesBank') {
|
|
|
+ this.selShowList = this._.cloneDeep(this.orderList)
|
|
|
+ } else {
|
|
|
+ this.selShowList = this._.cloneDeep(this.groupList)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ getLatestTypeIndex(type) {
|
|
|
+ let arr = []
|
|
|
+ this.groupList.forEach(i => {
|
|
|
+ if (i.list.length) {
|
|
|
+ arr.push(i.type)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ return arr.indexOf(type)
|
|
|
+ },
|
|
|
+ getComposeScore() {
|
|
|
+ return item => {
|
|
|
+ return item.children.length ? item.children.reduce((a, b) => a + b.score, 0) : 0
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 子题顺序操作
|
|
|
+ moveItems(arr, index1, index2) {
|
|
|
+ arr[index1] = arr.splice(index2, 1, arr[index1])[0]
|
|
|
+ return arr
|
|
|
+ },
|
|
|
+ // 子题上移操作
|
|
|
+ handleMoveUp(arr, index) {
|
|
|
+ this.moveItems(arr, index, index - 1)
|
|
|
+ },
|
|
|
+ // 子题下移操作
|
|
|
+ handleMoveDown(arr, index) {
|
|
|
+ this.moveItems(arr, index, index + 1)
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 删除试卷中的单个试题
|
|
|
+ * @param index
|
|
|
+ */
|
|
|
+ handleDelete(arr, item, index) {
|
|
|
+ this.$Modal.confirm({
|
|
|
+ title: this.$t('evaluation.newExercise.modalTip'),
|
|
|
+ content: this.$t('evaluation.exerciseList.confirmDelete'),
|
|
|
+ onOk: () => {
|
|
|
+ this.surPlusScore += item.score
|
|
|
+ arr.splice(index, 1)
|
|
|
+ this.selectedArr.splice(this.selectedArr.indexOf(item), 1)
|
|
|
+ this.$Message.success(this.$t('evaluation.deleteSuc'))
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ saveDFQues(type) {
|
|
|
+ if(type === 'paper') {
|
|
|
+
|
|
|
+ } else {
|
|
|
+ this.saveQuesBank(this.selShowList[0].list, true).then(async res => {
|
|
|
+ console.log(res);
|
|
|
+ // 校本组卷情况下 同步知识点数据
|
|
|
+ /* if (this.isSchool && this.isSavePoints && this.evaluationInfo.createType === 'import') {
|
|
|
+ if (this.importKnowledges.length) {
|
|
|
+ let paperItem = {
|
|
|
+ code: this.editPaper ? this.editPaper.code.replace('Paper-', '') : (this.isSchool ? this.$store.state.userInfo.schoolCode : this.$store.state.userInfo.TEAMModelId),
|
|
|
+ subjectId: this.isSchool ? this.subjectList[this.evaluationInfo.paperSubject].id : null,
|
|
|
+ periodId: this.isSchool ? this.schoolInfo.period[this.evaluationInfo.paperPeriod].id : null,
|
|
|
+ }
|
|
|
+ this.importKnowledges.push(...refreshList.map(i => i.knowledge).flat(1))
|
|
|
+ await this.saveImportPoints([...new Set(this.importKnowledges)], paperItem)
|
|
|
+ }
|
|
|
+ } */
|
|
|
+ this.$Spin.hide()
|
|
|
+ this.$Message.success(this.$t('evaluation.paperList.saveSuc'))
|
|
|
+ this.isLoading = false
|
|
|
+ // 清空已选试题
|
|
|
+ this.showQues = false
|
|
|
+ this.selectedArr = []
|
|
|
+ this.groupList = []
|
|
|
+ this.orderList = []
|
|
|
+ this.selShowList = []
|
|
|
+ }).catch(err => {
|
|
|
+ console.log(err);
|
|
|
+ this.$Message.error(this.$t('evaluation.paperList.saveFail'))
|
|
|
+ })
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async saveQuesBank(list, isToItemBank) {
|
|
|
+ // 试题id 使用本身的id
|
|
|
+ let that = this
|
|
|
+ this.isLoading = true
|
|
|
+ // 获取初始化Blob需要的数据
|
|
|
+ let sasData = this.isSchool ? await this.$tools.getSchoolSas() : await this.$tools.getPrivateSas()
|
|
|
+ let itemJsonFiles = []
|
|
|
+ let blobFiles = []
|
|
|
+ //初始化Blob
|
|
|
+ let containerClient = new blobTool(sasData.url, sasData.name, sasData.sas, this.isSchool ? 'school' : 'private')
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ let promiseArr = []
|
|
|
+ list.forEach(item => {
|
|
|
+ if(item.children.length) {
|
|
|
+ // 如果是没有保存Blob的综合题 则需要把题干和小题都进行保存操作
|
|
|
+ let composeArr = [item, ...item.children]
|
|
|
+ composeArr.forEach(composeItem => {
|
|
|
+ promiseArr.push(new Promise(async (r, j) => {
|
|
|
+ /* if (composeItem.children.length && composeItem.children[0].id) {
|
|
|
+ composeItem.children = composeItem.children.map(i => i.id)
|
|
|
+ } */
|
|
|
+ // 将当前的试题数据转化为BLOB内部的试题JSON格式
|
|
|
+ let removeItem = await this.$editorTools.doRemoveMideaHost(composeItem)
|
|
|
+ const itemJsonFile = await this.$evTools.createBlobItem(removeItem)
|
|
|
+ const cosmosItem = await this.$evTools.createCosmosItem(composeItem)
|
|
|
+ // 首先保存新题目的JSON文件到Blob 然后返回URL链接
|
|
|
+ let file = new File([JSON.stringify(itemJsonFile)], composeItem.id + ".json")
|
|
|
+ blobFiles.push(file)
|
|
|
+ if (!isToItemBank) {
|
|
|
+ // 只保存试题
|
|
|
+ itemJsonFiles.push(composeItem)
|
|
|
+ r({
|
|
|
+ cosmosItem: composeItem,
|
|
|
+ blobItem: itemJsonFile
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ // 保存试卷时,需要题目id
|
|
|
+ try {
|
|
|
+ // 等待上传blob的返回结果
|
|
|
+ let blobFile = await containerClient.upload(file, {
|
|
|
+ path: 'item/' + composeItem.id,
|
|
|
+ checkSize: false
|
|
|
+ })
|
|
|
+ if (blobFile.blob) {
|
|
|
+ // 保存试题JSON文件到试卷文件夹需要
|
|
|
+ itemJsonFiles.push(composeItem)
|
|
|
+ // 保存到COSMOS是不含base64图片编码的数据 避免数据量过大
|
|
|
+ cosmosItem.blob = blobFile.blob
|
|
|
+ // 保存当前试题到数据库
|
|
|
+ that.needSaveCosmosArr.push(cosmosItem)
|
|
|
+ r({
|
|
|
+ cosmosItem: cosmosItem,
|
|
|
+ blobItem: blobFile
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ j(500)
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ this.$Message.error(e.spaceError)
|
|
|
+ this.isLoading = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }))
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ // 如果没有blob字段 说明试题还没有保存到item目录下 则需要进行保存item文件夹后再保存到paper文件夹(导入试题情况)
|
|
|
+ promiseArr.push(new Promise(async (r, j) => {
|
|
|
+ // 将当前的试题数据转化为BLOB内部的试题JSON格式
|
|
|
+ let removeItem = await this.$editorTools.doRemoveMideaHost(item)
|
|
|
+ const itemJsonFile = await this.$evTools.createBlobItem(removeItem)
|
|
|
+ const cosmosItem = await this.$evTools.createCosmosItem(item)
|
|
|
+ // 首先保存新题目的JSON文件到Blob 然后返回URL链接
|
|
|
+ let file = new File([JSON.stringify(itemJsonFile)], item.id + ".json")
|
|
|
+ blobFiles.push(file)
|
|
|
+ console.log(isToItemBank);
|
|
|
+ try {
|
|
|
+ if (!isToItemBank) {
|
|
|
+ r({
|
|
|
+ cosmosItem: item,
|
|
|
+ blobItem: itemJsonFile
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ // 等待上传blob的返回结果
|
|
|
+ let blobFile = await containerClient.upload(file, {
|
|
|
+ path: 'item/' + item.id,
|
|
|
+ checkSize: false
|
|
|
+ })
|
|
|
+ if (blobFile.blob) {
|
|
|
+ // 保存试题JSON文件到试卷文件夹需要
|
|
|
+ // 保存到COSMOS是不含base64图片编码的数据 避免数据量过大
|
|
|
+ cosmosItem.blob = blobFile.blob
|
|
|
+ // 保存当前试题到数据库
|
|
|
+ that.needSaveCosmosArr.push(cosmosItem)
|
|
|
+ r({
|
|
|
+ cosmosItem: cosmosItem,
|
|
|
+ blobItem: blobFile
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ j(500)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ itemJsonFiles.push(item)
|
|
|
+ } catch (e) {
|
|
|
+ this.$Message.error(e.spaceError)
|
|
|
+ this.isLoading = false
|
|
|
+ }
|
|
|
+ }))
|
|
|
+ }
|
|
|
+ })
|
|
|
+ Promise.all(promiseArr).then(async result => {
|
|
|
+ // 如果是入库 则批量保存所有试题
|
|
|
+ if (isToItemBank) {
|
|
|
+ try {
|
|
|
+ await this.$api.evaluation.upsertAll({
|
|
|
+ option: 'insert',
|
|
|
+ itemInfos: this.needSaveCosmosArr
|
|
|
+ })
|
|
|
+ } catch (e) {
|
|
|
+ this.isLoading = false
|
|
|
+ console.error(e)
|
|
|
+ this.$Message.error(this.$t('evaluation.paperList.saveItemsFailTip'))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ console.log(result)
|
|
|
+ let slides = []
|
|
|
+ // 主观题的answer为空数组
|
|
|
+ let nullType = ['complete', 'subjective', 'compose', 'correct', 'connector']
|
|
|
+ result.map(i => i.cosmosItem).forEach(item => {
|
|
|
+ console.log(item)
|
|
|
+ let o = {
|
|
|
+ url: item.id + '.json',
|
|
|
+ type: item.type,
|
|
|
+ scoring: {
|
|
|
+ score: item.score || 0,
|
|
|
+ knowledge: item.knowledge || [],
|
|
|
+ field: item.field || 1,
|
|
|
+ ans: nullType.includes(item.type) ? [] : (item.answer || [])
|
|
|
+ }
|
|
|
+ }
|
|
|
+ item.type === 'compose' && delete o.scoring
|
|
|
+ slides.push(o)
|
|
|
+ })
|
|
|
+ // this.isLoading = false
|
|
|
+ resolve({
|
|
|
+ slides: slides,
|
|
|
+ files: itemJsonFiles
|
|
|
+ })
|
|
|
+ }).catch(err => {
|
|
|
+ reject(err)
|
|
|
+ this.isLoading = false
|
|
|
+ this.$Message.error(this.$t('evaluation.paperList.saveItemsFailTip'))
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ async savePaper(list) {
|
|
|
+
|
|
|
+ },
|
|
|
+ },
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="less" scoped>
|
|
|
+@import "./DfPage.less";
|
|
|
+</style>
|
|
|
+<style lang="less">
|
|
|
+.select-ques {
|
|
|
+ background-color: #f6f6f6;
|
|
|
+}
|
|
|
+</style>
|