123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463 |
- <template>
- <div class="mark-param-group">
- <div class="box-justify part-box part-box-pad">
- <div>
- <p v-if="unsetQuestionNos" class="tips-info tips-error">
- 试题{{
- unsetQuestionNos
- }}未设置评卷员,请点击列表里设置评卷员选择评卷员
- </p>
- </div>
- <div>
- <el-button type="primary" @click="toPrev(1)">上一步</el-button>
- <el-button type="primary" @click="toNext(1)">下一步</el-button>
- </div>
- </div>
- <div class="part-box part-box-pad">
- <el-table
- :data="subjectiveTaskList"
- border
- :span-method="openMergeMarker ? objectSpanMethod : undefined"
- >
- <el-table-column label="大题名称" prop="mainTitle"> </el-table-column>
- <el-table-column label="大题号" prop="mainNumber" width="80">
- </el-table-column>
- <el-table-column label="小题号" prop="subNumber" width="80">
- </el-table-column>
- <el-table-column label="评卷员" min-width="200">
- <template slot-scope="scope">
- <el-tag
- v-for="user in scope.row.markers"
- :key="user.markUserQuestionId"
- class="tag-spin tag-wrap"
- size="medium"
- effect="dark"
- closable
- @close="toDeleteMarker(scope.row, user)"
- >
- {{ user.name }}({{ user.loginName }})
- </el-tag>
- <el-button
- type="text"
- class="btn-primary"
- @click="toSetMarker(scope.row)"
- >
- 设置评卷员
- </el-button>
- </template>
- </el-table-column>
- <el-table-column label="评卷方式" width="100">
- <template slot-scope="scope">
- {{ scope.row.doubleRate > 0 ? "双评" : "单评" }}
- </template>
- </el-table-column>
- <el-table-column label="仲裁阈值" width="100">
- <template v-if="scope.row.doubleEnable" slot-scope="scope">
- {{ scope.row.arbitrateThreshold }}
- </template>
- </el-table-column>
- <el-table-column label="合分策略" width="100">
- <template v-if="scope.row.doubleEnable" slot-scope="scope">
- {{ SCORE_POLICY_TYPE[scope.row.scorePolicy] }}
- </template>
- </el-table-column>
- <el-table-column label="双评比例" width="100">
- <template v-if="scope.row.doubleEnable" slot-scope="scope">
- {{ scope.row.doubleRate }}%
- </template>
- </el-table-column>
- <el-table-column label="评卷区" width="80" align="center">
- <template slot-scope="scope">
- <i
- v-if="scope.row.pictureConfigs?.length"
- class="el-icon-success color-success"
- ></i>
- </template>
- </el-table-column>
- <el-table-column class-name="action-column" label="操作" width="160px">
- <template slot-scope="scope">
- <el-button
- class="btn-primary"
- type="text"
- @click="toSetMarkType(scope.row)"
- >评卷方式设置</el-button
- >
- <el-button
- class="btn-primary"
- type="text"
- :disabled="!paperList.length"
- @click="toSetArea(scope.row)"
- >评卷区</el-button
- >
- </template>
- </el-table-column>
- </el-table>
- <!-- subjective answer -->
- <el-form class="mt-2" label-width="150px">
- <el-form-item label="请上传标答PDF文档:">
- <mark-param-subjective-answer></mark-param-subjective-answer>
- </el-form-item>
- </el-form>
- </div>
- <!-- ModifyMarkType -->
- <modify-mark-type
- ref="ModifyMarkType"
- :instance="curRow"
- @modified="markTypeModified"
- ></modify-mark-type>
- <!-- ModifyMarkMarker -->
- <modify-mark-marker
- ref="ModifyMarkMarker"
- :instance="curRow"
- :course-id="basicInfo.courseId"
- :question-list="curRowQuestions"
- @modified="markMarkerModified"
- ></modify-mark-marker>
- <!-- ModifyMarkArea -->
- <modify-mark-area
- ref="ModifyMarkArea"
- :base-info="basicInfo"
- :group="curRow"
- :paper-list="paperList"
- @modified="areaModified"
- ></modify-mark-area>
- </div>
- </template>
- <script>
- import { mapState, mapMutations } from "vuex";
- import ModifyMarkType from "./ModifyMarkType.vue";
- import ModifyMarkArea from "./ModifyMarkArea.vue";
- import ModifyMarkMarker from "./ModifyMarkMarker.vue";
- import MarkParamSubjectiveAnswer from "./MarkParamSubjectiveAnswer.vue";
- import {
- examStructureFindJpg,
- markSubjectiveBindMarker,
- markSubjectiveUpdateMarkType,
- markSubjectiveUpdateMarkArea,
- markSubjectiveUnbindMarker,
- } from "../../api";
- import { cardDetail } from "../../../card/api";
- import { SCORE_POLICY_TYPE } from "@/constants/enumerate";
- export default {
- name: "mark-param-group",
- components: {
- ModifyMarkType,
- ModifyMarkArea,
- ModifyMarkMarker,
- MarkParamSubjectiveAnswer,
- },
- data() {
- return {
- SCORE_POLICY_TYPE,
- questionCount: 0,
- curRow: {},
- curRowQuestions: [],
- MARK_TYPE: {
- 0: "单评",
- 1: "双评",
- },
- paperList: [],
- cardPages: [],
- fillQuestionRanges: [],
- };
- },
- computed: {
- ...mapState("markParam", [
- "basicInfo",
- "paperStructureInfo",
- "openMergeMarker",
- "subjectiveTaskList",
- ]),
- unsetQuestionNos() {
- return this.subjectiveTaskList
- .filter((item) => !item.markers.length)
- .map((item) => `${item.mainNumber}-${item.subNumber}`)
- .join(",");
- },
- },
- mounted() {
- this.initFillQuestionRanges();
- this.getPaperList();
- this.getCardPages();
- },
- methods: {
- ...mapMutations("markParam", [
- "setSubjectiveTaskList",
- "updateSubjectiveTaskItem",
- ]),
- async getPaperList() {
- this.paperList = [];
- const data = await examStructureFindJpg({
- examId: this.basicInfo.examId,
- courseId: this.basicInfo.courseId,
- paperNumber: this.basicInfo.paperNumber,
- serialNumber: this.basicInfo.serialNumber,
- });
- const papers = data || [];
- papers.sort((a, b) => a.index - b.index);
- this.paperList = papers.map((paper) => {
- return {
- imgUrl: paper.path,
- areas: [],
- };
- });
- },
- async getCardPages() {
- const detData = await cardDetail(this.basicInfo.cardId);
- const cardContent = JSON.parse(detData.content);
- this.cardPages = cardContent.pages;
- },
- initFillQuestionRanges() {
- if (!this.openMergeMarker) return;
- const qRangeDict = {};
- this.fillQuestionRanges = this.subjectiveTaskList.map((item, index) => {
- if (item.questionType !== 4) return;
- if (qRangeDict[item.mainNumber]) {
- qRangeDict[item.mainNumber].push(index);
- } else {
- qRangeDict[item.mainNumber] = [index];
- }
- });
- this.fillQuestionRanges = Object.values(qRangeDict);
- },
- objectSpanMethod({ rowIndex, columnIndex }) {
- // 第四列为评卷员
- if (columnIndex === 3 || columnIndex === 8) {
- const pos = this.fillQuestionRanges.findIndex((item) =>
- item.includes(rowIndex)
- );
- if (pos === -1) return;
- const range = this.fillQuestionRanges[pos];
- if (range[0] === rowIndex) {
- return {
- rowspan: range.length,
- colspan: 1,
- };
- } else {
- return {
- rowspan: 0,
- colspan: 0,
- };
- }
- }
- },
- getCurrentQuestions(row) {
- let curRowQuestions = [];
- if (this.openMergeMarker && row.questionType === 4) {
- // 填空题按大题批量处理
- const pos = this.subjectiveTaskList.findIndex(
- (item) => item.id === row.id
- );
- if (pos === -1) return;
- const range = this.fillQuestionRanges.find((item) =>
- item.includes(pos)
- );
- if (!range) return;
- curRowQuestions = range.map((index) => {
- const item = this.subjectiveTaskList[index];
- return {
- id: item.id,
- mainNumber: item.mainNumber,
- subNumber: item.subNumber,
- };
- });
- } else {
- // 非填空题按单题处理
- curRowQuestions = [
- {
- id: row.id,
- mainNumber: row.mainNumber,
- subNumber: row.subNumber,
- },
- ];
- }
- return curRowQuestions;
- },
- toSetMarker(row) {
- this.curRow = row;
- this.curRowQuestions = this.getCurrentQuestions(row);
- this.$refs.ModifyMarkMarker.open();
- },
- async markMarkerModified(row) {
- await markSubjectiveBindMarker({
- examId: this.basicInfo.examId,
- paperNumber: this.basicInfo.paperNumber,
- questionIds: this.curRowQuestions.map((item) => item.id),
- markers: row.markers,
- });
- this.curRowQuestions.forEach((item) => {
- this.updateSubjectiveTaskItem({
- id: item.id,
- markers: row.markers,
- });
- });
- },
- toSetArea(row) {
- this.curRow = row;
- this.curRowQuestions = this.getCurrentQuestions(row);
- this.$refs.ModifyMarkArea.open();
- },
- async areaModified(row) {
- await markSubjectiveUpdateMarkArea({
- examId: this.basicInfo.examId,
- paperNumber: this.basicInfo.paperNumber,
- questionIds: this.curRowQuestions.map((item) => item.id),
- pictureConfigs: row.pictureConfigs,
- });
- this.curRowQuestions.forEach((item) => {
- this.updateSubjectiveTaskItem({
- id: item.id,
- pictureConfigs: row.pictureConfigs,
- });
- });
- },
- async toDeleteMarker(row, marker) {
- const confirm = await this.$confirm(`确定要删除当前评卷员吗?`, "提示", {
- type: "warning",
- }).catch(() => {});
- if (confirm !== "confirm") return;
- const markers = row.markers.filter(
- (item) => item.markUserQuestionId !== marker.markUserQuestionId
- );
- await markSubjectiveUnbindMarker(marker.markUserQuestionId);
- this.updateSubjectiveTaskItem({
- id: row.id,
- markers,
- });
- },
- toSetMarkType(row) {
- this.curRow = row;
- this.$refs.ModifyMarkType.open();
- },
- async markTypeModified(row) {
- const pos = this.subjectiveTaskList.findIndex(
- (item) => item.id === row.id
- );
- if (pos === -1) return;
- const datas = {
- questionId: row.id,
- doubleEnable: row.doubleEnable,
- doubleRate: row.doubleRate,
- arbitrateThreshold: row.arbitrateThreshold,
- scorePolicy: row.scorePolicy,
- };
- await markSubjectiveUpdateMarkType(datas);
- this.updateSubjectiveTaskItem({
- ...datas,
- id: row.id,
- });
- },
- autoParsePictureConfigList(questions) {
- if (!questions.length) return [];
- let pictureConfigs = [];
- const structs = questions.map(
- (item) => `${item.mainNumber}_${item.subNumber}`
- );
- this.cardPages.forEach((page, pindex) => {
- page.exchange.answer_area.forEach((area) => {
- const [x, y, w, h] = area.area;
- const qStruct = `${area.main_number}_${area.sub_number}`;
- const pConfig = {
- i: pindex + 1,
- x,
- y,
- w,
- h,
- qStruct,
- };
- if (typeof area.sub_number === "number") {
- if (!structs.includes(qStruct)) return;
- pictureConfigs.push(pConfig);
- return;
- }
- // 复合区域处理,比如填空题,多个小题合并为一个区域
- if (typeof area.sub_number === "string") {
- const areaStructs = area.sub_number
- .split(",")
- .map((subNumber) => `${area.main_number}_${subNumber}`);
- if (
- structs.some((struct) => areaStructs.includes(struct)) &&
- !pictureConfigs.find((item) => item.qStruct === qStruct)
- ) {
- pictureConfigs.push(pConfig);
- }
- }
- });
- });
- pictureConfigs.forEach((item) => {
- delete item.qStruct;
- });
- // console.log(pictureConfigs);
- // 合并相邻区域
- pictureConfigs.sort((a, b) => {
- return a.i - b.i || a.x - b.x || a.y - b.y;
- });
- let combinePictureConfigList = [];
- let prevConfig = null;
- pictureConfigs.forEach((item, index) => {
- if (!index) {
- prevConfig = { ...item };
- combinePictureConfigList.push(prevConfig);
- return;
- }
- const elasticRate = 0.01;
- if (
- prevConfig.i === item.i &&
- prevConfig.y + prevConfig.h + elasticRate >= item.y &&
- prevConfig.w === item.w &&
- prevConfig.x === item.x
- ) {
- prevConfig.h = item.y + item.h - prevConfig.y;
- } else {
- prevConfig = { ...item };
- combinePictureConfigList.push(prevConfig);
- }
- });
- // console.log(combinePictureConfigList);
- return combinePictureConfigList;
- },
- checkData() {
- const errorList = [];
- this.subjectiveTaskList.forEach((item) => {
- const errors = [];
- if (!item.markers?.length) {
- errors.push("评卷员未设置");
- }
- if (!item.pictureConfigs?.length) {
- errors.push("评卷区未设置");
- }
- if (errors.length) {
- errorList.push(
- `${item.mainNumber}-${item.subNumber}:${errors.join("、")}。`
- );
- }
- });
- if (errorList.length) {
- this.$message.error(errorList.join("\n"));
- return false;
- }
- return true;
- },
- toPrev(step = 1) {
- this.$emit("prev", step);
- },
- toNext(step = 1) {
- if (!this.checkData()) return;
- this.$emit("next", step);
- },
- },
- };
- </script>
|