123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468 |
- <template>
- <div class="mark-param-structure">
- <div class="part-box part-box-pad">
- <p class="tips-info">
- 1.请确认展示的试卷结构与提交的试卷、答题卡是否一致?
- </p>
- <p class="tips-info">2.请补充所有题目的小题分值,并确认试卷总分!</p>
- <p class="tips-info tips-error">
- 3.开始阅卷后不允许修改试卷结构,请确认清楚后再提交!
- </p>
- </div>
- <div class="part-box part-box-pad mb-0">
- <el-table
- ref="TableList"
- :data="tableData"
- border
- :row-class-name="getRowClassName"
- >
- <el-table-column width="50" align="center">
- <template slot-scope="scope" v-if="scope.row.mainFirstSub">
- <div
- :class="[
- 'expand-btn',
- { 'expand-btn-unexpand': !scope.row.expandSub },
- ]"
- @click="switchExpandSub(scope.row)"
- >
- <i
- :class="scope.row.expandSub ? 'el-icon-minus' : 'el-icon-plus'"
- ></i>
- </div>
- </template>
- </el-table-column>
- <template v-if="structureCanEdit">
- <el-table-column prop="mainTitle" label="大题名称">
- <span slot-scope="scope" v-if="scope.row.mainFirstSub">
- <el-input
- v-model.trim="scope.row.mainTitle"
- size="small"
- :maxlength="32"
- clearable
- @change="mainTitleChange(scope.row)"
- ></el-input>
- </span>
- </el-table-column>
- <el-table-column prop="questionType" label="题型" width="120">
- <template slot-scope="scope" v-if="scope.row.mainFirstSub">
- <el-select
- v-model="scope.row.questionType"
- placeholder="请选择"
- class="width-full"
- @change="qTypeChange(scope.row)"
- >
- <el-option
- v-for="item in QUESTION_TYPE_LIST"
- :key="item.code"
- :value="item.code"
- :label="item.name"
- >
- </el-option>
- </el-select>
- </template>
- </el-table-column>
- <el-table-column label="选项个数" width="100">
- <template
- slot-scope="scope"
- v-if="scope.row.questionType <= 2 && scope.row.mainFirstSub"
- >
- <el-input-number
- v-model="scope.row.optionCount"
- class="width-full"
- size="small"
- :min="2"
- :max="26"
- :step="1"
- step-strictly
- :controls="false"
- @change="optionCountChange(scope.row)"
- ></el-input-number>
- </template>
- </el-table-column>
- </template>
- <template v-else>
- <el-table-column prop="mainTitle" label="大题名称">
- <span slot-scope="scope" v-if="scope.row.mainFirstSub">
- {{ scope.row.mainTitle }}
- </span>
- </el-table-column>
- <el-table-column label="题型" width="120">
- <template slot-scope="scope" v-if="scope.row.mainFirstSub">
- {{ questionTypeDict[scope.row.questionType] }}
- </template>
- </el-table-column>
- </template>
- <el-table-column label="每题分值" width="100">
- <template slot-scope="scope" v-if="scope.row.mainFirstSub">
- <el-input-number
- v-model="scoresPerTopic[scope.row.mainId]"
- class="width-full"
- size="small"
- :min="0.5"
- :max="500"
- :step="0.5"
- step-strictly
- :controls="false"
- @change="(val) => scorePerTopicChange(val, scope.row)"
- ></el-input-number>
- </template>
- </el-table-column>
- <el-table-column prop="mainNumber" label="大题号" width="80">
- <template slot-scope="scope" v-if="scope.row.mainFirstSub">
- <span>{{ scope.row.mainNumber }}</span>
- </template>
- </el-table-column>
- <el-table-column
- prop="subNumber"
- label="小题号"
- width="80"
- ></el-table-column>
- <el-table-column prop="totalScore" label="小题满分" width="105">
- <template slot-scope="scope">
- <el-input-number
- v-model="scope.row.totalScore"
- class="width-80"
- size="small"
- :min="0.5"
- :max="500"
- :step="0.5"
- step-strictly
- :controls="false"
- ></el-input-number>
- </template>
- </el-table-column>
- <el-table-column
- v-if="structureCanEdit"
- class-name="action-column"
- label="操作"
- width="200px"
- >
- <template slot-scope="scope">
- <el-button
- class="btn-primary"
- type="text"
- @click="toAddMain(scope.row)"
- >新增大题</el-button
- >
- <el-button
- class="btn-primary"
- type="text"
- @click="toAddSub(scope.row)"
- >新增小题</el-button
- >
- <el-button
- :disabled="tableData.length <= 1"
- class="btn-danger"
- type="text"
- @click="toDeleteSub(scope.row)"
- >删除</el-button
- >
- </template>
- </el-table-column>
- </el-table>
- </div>
- <div class="total-info">
- 试卷总分:<span>{{ paperTotalScore }}</span
- >分
- </div>
- <div class="mark-footer">
- <el-button type="primary" :disabled="loading" @click="submit"
- >提交</el-button
- >
- <el-button @click="cancel">取消</el-button>
- </div>
- </div>
- </template>
- <script>
- import { calcSum } from "@/plugins/utils";
- import { QUESTION_TYPE_LIST } from "@/constants/enumerate";
- import { mapState, mapMutations } from "vuex";
- import { markStructureSave } from "../../api";
- import { omit } from "lodash";
- export default {
- name: "mark-paper-structure",
- data() {
- return {
- tableData: [],
- QUESTION_TYPE_LIST,
- questionTypeDict: {},
- scoresPerTopic: {},
- loading: false,
- };
- },
- computed: {
- ...mapState("markParam", [
- "basicInfo",
- "structureCanEdit",
- "paperStructureInfo",
- ]),
- paperTotalScore() {
- return calcSum(this.tableData.map((item) => item.totalScore || 0));
- },
- },
- mounted() {
- this.initData();
- },
- methods: {
- ...mapMutations("markParam", ["setPaperStructureInfo"]),
- initData() {
- let questionTypeDict = {};
- QUESTION_TYPE_LIST.forEach((item) => {
- questionTypeDict[item.code] = item.name;
- });
- this.questionTypeDict = questionTypeDict;
- let curMainNumber = null;
- let curMainId = null;
- let scoresPerTopic = {};
- this.tableData = this.paperStructureInfo.map((item) => {
- let nitem = {
- ...item,
- key: this.$randomCode(),
- mainFirstSub: false,
- expandSub: true,
- };
- if (curMainNumber !== item.mainNumber) {
- curMainNumber = item.mainNumber;
- curMainId = this.$randomCode();
- scoresPerTopic[curMainNumber] = undefined;
- nitem.mainFirstSub = true;
- }
- nitem.mainId = curMainId;
- return nitem;
- });
- this.scoresPerTopic = scoresPerTopic;
- if (!this.tableData.length && this.structureCanEdit) {
- this.createMain();
- }
- },
- getNewRow(val) {
- return this.$objAssign(
- {
- id: null,
- key: this.$randomCode(),
- mainId: null,
- isObjective: true,
- mainNumber: 1,
- subNumber: 1,
- mainTitle: "",
- answer: "",
- totalScore: undefined,
- intervalScore: undefined,
- objectivePolicy: null,
- questionType: null,
- optionCount: undefined,
- mainFirstSub: true,
- expandSub: true,
- },
- val
- );
- },
- createMain() {
- this.tableData.push(this.getNewRow({}));
- },
- getRowClassName({ row }) {
- let classNames = [];
- if (row.mainFirstSub) {
- classNames.push("row-main-first-sub");
- }
- if (!row.mainFirstSub && !row.expandSub) {
- classNames.push("row-unexpand-sub");
- }
- return classNames.join(" ");
- },
- getNextMainStartPos(startPos, curMainId) {
- let nextMainStartPos = null;
- for (let i = startPos, len = this.tableData.length; i < len; i++) {
- const element = this.tableData[i];
- if (element.mainId !== curMainId) {
- nextMainStartPos = i;
- return nextMainStartPos;
- }
- }
- if (nextMainStartPos === null) return this.tableData.length;
- },
- toAddMain(row) {
- const startPos = this.tableData.findIndex((item) => item.id === row.id);
- let nextMainStartPos = this.getNextMainStartPos(startPos, row.mainId);
- this.tableData.splice(
- nextMainStartPos,
- 0,
- this.getNewRow({
- mainId: this.$randomCode(),
- mainNumber: row.mainNumber + 1,
- totalScore: row.totalScore,
- questionType: row.questionType,
- })
- );
- this.updateMainData();
- },
- updateMainData() {
- let curMainNumber = 0,
- curMainId = null;
- this.tableData.forEach((item) => {
- if (item.mainId !== curMainId) {
- curMainId = item.mainId;
- curMainNumber++;
- }
- item.mainNumber = curMainNumber;
- });
- },
- toAddSub(row) {
- const subPos = this.tableData.findIndex((item) => item.id === row.id);
- this.tableData.splice(
- subPos + 1,
- 0,
- this.getNewRow({
- ...row,
- mainFirstSub: false,
- answer: "",
- key: this.$randomCode(),
- })
- );
- this.updateSubData(row.mainId);
- },
- updateSubData(mainId) {
- this.tableData
- .filter((item) => item.mainId === mainId)
- .forEach((item, index) => {
- item.subNumber = index + 1;
- });
- },
- toDeleteSub(row) {
- const subPos = this.tableData.findIndex((item) => item.id === row.id);
- this.tableData.splice(subPos, 1);
- this.tableData
- .filter((item) => item.mainId === row.mainId)
- .forEach((item, index) => {
- item.mainFirstSub = !index;
- });
- this.updateSubData(row.mainId);
- this.updateMainData();
- },
- switchExpandSub(row) {
- row.expandSub = !row.expandSub;
- this.tableData
- .filter((item) => item.mainId === row.mainId && !item.mainFirstSub)
- .forEach((item) => (item.expandSub = row.expandSub));
- },
- mainTitleChange(row) {
- this.tableData
- .filter((item) => item.mainId === row.mainId && !item.mainFirstSub)
- .forEach((item) => (item.mainTitle = row.mainTitle));
- },
- qTypeChange(row) {
- const curQt = this.QUESTION_TYPE_LIST.find(
- (item) => item.code === row.type
- );
- if (!curQt) return;
- this.tableData
- .filter((item) => item.mainId === row.mainId)
- .forEach((item) => {
- item.questionType = curQt.code;
- item.isObjective = curQt.qType === "objective";
- item.optionCount = curQt.optionCount;
- });
- },
- optionCountChange(row) {
- if (!row.optionCount) return;
- this.tableData
- .filter((item) => item.mainId === row.mainId && !item.mainFirstSub)
- .forEach((item) => {
- item.optionCount = row.optionCount;
- });
- },
- scorePerTopicChange(val, row) {
- if (!val) return;
- this.tableData
- .filter((item) => item.mainId === row.mainId)
- .forEach((item) => {
- item.totalScore = val;
- });
- },
- checkData() {
- let errorMessages = [];
- this.tableData.forEach((item) => {
- let errorMsg = ``;
- if (item.mainFirstSub) {
- let errorFields = [];
- if (!item.mainTitle) {
- errorFields.push("大题名称");
- }
- if (!item.mainNumber) {
- errorFields.push("大题号");
- }
- if (!item.optionCount && item.questionType <= 2) {
- errorFields.push("选项个数");
- }
- if (errorFields.length) {
- errorMsg += `${errorFields.join("、")}不能为空,`;
- }
- }
- let errorFields = [];
- if (!item.subNumber) {
- errorFields.push("小题号");
- }
- if (!item.totalScore) {
- errorFields.push("小题满分");
- }
- if (!item.intervalScore) {
- errorFields.push("评卷间隔分");
- }
- if (errorFields.length) {
- errorMsg += `第${item.subNumber}小题,${errorFields.join(
- "、"
- )}不能为空,`;
- }
- if (errorMsg) {
- errorMsg = `第${item.mainNumber}大题,${errorMsg}`;
- errorMessages.push(errorMsg);
- }
- });
- if (errorMessages.length) {
- this.$message.error(errorMessages.join("。"));
- return;
- }
- return true;
- },
- getData() {
- return this.tableData.map((item) => {
- return omit(item, ["key", "mainId", "expandSub"]);
- });
- },
- async submit() {
- if (this.loading) return;
- if (!this.checkData()) return;
- this.loading = true;
- const questions = this.getData();
- const res = await markStructureSave({
- examId: this.basicInfo.examId,
- paperNumber: this.basicInfo.paperNumber,
- questions,
- }).catch(() => {});
- this.loading = false;
- if (!res) return;
- this.$message.success("保存成功!");
- this.setPaperStructureInfo(questions);
- this.$emit("confirm");
- },
- cancel() {
- this.$emit("cancel");
- },
- },
- };
- </script>
|