<template>
  <div class="mark-param-group">
    <div class="box-justify part-box part-box-pad">
      <div>
        <p class="tips-info">
          1.如果采用整卷批阅，请将全部主观题选上。如果采用分题阅卷，请将需要在一个评阅任务里评阅的题目勾选在一起；
        </p>
        <p class="tips-info">
          2.如果采用分班阅卷，每个班都将按设置的评卷任务进行评卷，请给每个班级选择对应评卷老师；
        </p>
        <p class="tips-info tips-error">3.开始阅卷后不允许删除评卷分组！</p>
      </div>
      <div>
        <el-switch
          v-if="checkPrivilege('button', 'OpenClassReading', 'MarkSetting')"
          v-model="markClassIsOpen"
          active-text="分班阅卷"
          @change="markClassChange"
        ></el-switch>
        <el-button class="ml-2" type="primary" @click="toAdd">新增</el-button>
      </div>
    </div>

    <div class="part-box part-box-pad">
      <el-table :data="groupList" border>
        <el-table-column type="index" width="50"> </el-table-column>
        <el-table-column label="评卷员">
          <template slot-scope="scope">
            <el-tag
              v-for="user in scope.row.markers"
              :key="user.id"
              class="tag-spin tag-wrap"
              size="medium"
            >
              {{ user.name }}（{{ user.loginName }}）
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="评卷方式" width="100">
          <template slot-scope="scope">
            {{ scope.row.doubleEnable ? "双评" : "单评" }}
          </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="评阅题目">
          <template slot-scope="scope">
            {{ scope.row.questions | questionsFilter }}
          </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="toEdit(scope.row)"
              >编辑</el-button
            >
            <el-button
              class="btn-primary"
              type="text"
              :disabled="!paperList.length"
              @click="toSetArea(scope.row)"
              >评卷区</el-button
            >
            <el-button
              class="btn-danger"
              type="text"
              @click="toDelete(scope.row)"
              >删除</el-button
            >
          </template>
        </el-table-column>
      </el-table>
      <p v-if="unsetQuestionNos.length" class="tips-info tips-error">
        未设置试题：{{ unsetQuestionNos.join(",") }}
      </p>
    </div>

    <!-- ModifyMarkGroup -->
    <modify-mark-group
      ref="ModifyMarkGroup"
      :course-id="basicInfo.courseId"
      :instance="curGroupInfo"
      :disabled-question-nos="disabledQuestionNos"
      :paper-structure="subjectiveQuestionList"
      @modified="groupModified"
      @cancel="updateDisableQuestionNos"
    ></modify-mark-group>
    <!-- ModifyMarkArea -->
    <modify-mark-area
      ref="ModifyMarkArea"
      :base-info="basicInfo"
      :group="curGroupInfo"
      :paper-list="paperList"
      @modified="areaModified"
    ></modify-mark-area>
  </div>
</template>

<script>
import { mapState, mapMutations } from "vuex";
import ModifyMarkGroup from "./ModifyMarkGroup.vue";
import ModifyMarkArea from "./ModifyMarkArea.vue";
import {
  examStructureFindJpg,
  markGroupItemSave,
  markGroupItemUpdate,
  markGroupItemDelete,
  markGroupAreaSave,
  markClassStatusUpdate,
} from "../../api";
import { cardDetail } from "../../../card/api";
import { deepCopy, maxNum } from "@/plugins/utils";
import { SCORE_POLICY_TYPE } from "@/constants/enumerate";
import { omit, pick } from "lodash";

export default {
  name: "mark-param-group",
  components: {
    ModifyMarkGroup,
    ModifyMarkArea,
  },
  data() {
    return {
      markClassIsOpen: false,
      SCORE_POLICY_TYPE,
      questionCount: 0,
      groupQuestionCount: 0,
      groupList: [],
      fullDisabledQuestionNos: [],
      disabledQuestionNos: [],
      unsetQuestionNos: [],
      curGroupInfo: {},
      subjectiveQuestionList: [],
      subjectiveQuestionCount: 0,
      objectiveQuestionCount: 0,
      MARK_TYPE: {
        0: "单评",
        1: "双评",
      },
      paperList: [],
      cardPages: [],
      dataReady: false,
      deleting: false,
    };
  },
  computed: {
    ...mapState("markParam", [
      "basicInfo",
      "paperStructureInfo",
      "openMarkClass",
      "groupInfo",
    ]),
  },
  filters: {
    questionsFilter(val) {
      return val
        .map((item) => `${item.mainNumber}-${item.subNumber}`)
        .join(",");
    },
  },
  mounted() {
    this.initData();
    this.getPaperList();
    this.getCardPages();
  },
  methods: {
    ...mapMutations("markParam", ["setGroupInfo", "setOpenMarkClass"]),
    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;
    },
    initData() {
      this.markClassIsOpen = this.openMarkClass;
      this.groupList = this.groupInfo.map((item) => {
        return { ...deepCopy(item), id: this.$randomCode() };
      });
      this.questionCount = this.paperStructureInfo.length;
      this.subjectiveQuestionList = this.paperStructureInfo
        .filter((item) => !item.objective)
        .map((item) => {
          return {
            ...item,
            qno: `${item.mainNumber}-${item.subNumber}`,
          };
        });
      this.subjectiveQuestionCount = this.subjectiveQuestionList.length;
      this.objectiveQuestionCount =
        this.questionCount - this.subjectiveQuestionCount;
      this.updateDisableQuestionNos();

      this.dataReady = true;
    },
    updateDisableQuestionNos(filterId) {
      let groupList = this.groupList;
      if (filterId)
        groupList = groupList.filter((item) => item.id !== filterId);
      let disabledQuestionNos = [];
      groupList.forEach((item) => {
        disabledQuestionNos = [
          ...disabledQuestionNos,
          ...item.questions.map(
            (item) => `${item.mainNumber}-${item.subNumber}`
          ),
        ];
      });
      this.disabledQuestionNos = disabledQuestionNos;
      if (!filterId) {
        this.groupQuestionCount = disabledQuestionNos.length;
        this.fullDisabledQuestionNos = [...disabledQuestionNos];
      }
      this.updateUnsetQuestionNos();
    },
    updateUnsetQuestionNos() {
      this.unsetQuestionNos = this.subjectiveQuestionList
        .filter((q) => !this.fullDisabledQuestionNos.includes(q.qno))
        .map((q) => q.qno);
    },
    toAdd() {
      this.updateDisableQuestionNos();
      if (this.groupQuestionCount === this.subjectiveQuestionCount) {
        this.$message.error("当前已经没有主观题目可供设置！");
        return;
      }

      this.curGroupInfo = {
        id: this.$randomCode(),
        groupNumber: maxNum(this.groupList.map((item) => item.groupNumber)) + 1,
        doubleEnable: false,
        doubleRate: 100,
        arbitrateThreshold: 1,
        scorePolicy: "AVG",
        markers: [],
        pictureConfigs: [],
        questions: [],
        isNew: true,
      };
      this.$refs.ModifyMarkGroup.open();
    },
    toEdit(row) {
      this.curGroupInfo = row;
      this.updateDisableQuestionNos(row.id);
      this.$refs.ModifyMarkGroup.open();
    },
    toSetArea(row) {
      this.curGroupInfo = row;
      this.$refs.ModifyMarkArea.open();
    },
    async toDelete(row) {
      if (this.deleting) return;

      const confirm = await this.$confirm(
        `删除分组会清理评卷任务，确定要删除当前分组吗?`,
        "提示",
        {
          type: "warning",
        }
      ).catch(() => {});
      if (confirm !== "confirm") return;

      this.deleting = true;
      const res = await markGroupItemDelete({
        examId: this.basicInfo.examId,
        paperNumber: this.basicInfo.paperNumber,
        groupNumber: row.groupNumber,
      }).catch(() => {});
      this.deleting = false;
      if (!res) return;

      const pos = this.groupList.findIndex((item) => item.id === row.id);
      this.groupList.splice(pos, 1);
      this.updateDisableQuestionNos();
      this.updateData();
    },
    async groupModified(row) {
      const pos = this.groupList.findIndex((item) => item.id === row.id);
      if (!row.pictureConfigs.length) {
        row.pictureConfigs = this.autoParsePictureConfigList(row.questions);
      }

      const data = await this.updateMarkGroup(row, pos === -1);
      row.pictureConfigs = data.pictureConfigList;
      if (pos === -1) {
        this.groupList.push(row);
      } else {
        this.groupList.splice(pos, 1, row);
      }
      this.updateDisableQuestionNos();
      this.updateData();
    },
    async updateMarkGroup(row, isAdd) {
      const data = {
        examId: this.basicInfo.examId,
        paperNumber: this.basicInfo.paperNumber,
        groupInfo: omit(row, ["id"]),
      };
      const updateApi = isAdd ? markGroupItemSave : markGroupItemUpdate;
      return await updateApi(data);
    },
    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;
    },
    async areaModified(row) {
      const pos = this.groupList.findIndex((item) => item.id === row.id);
      if (pos === -1) return;

      await markGroupAreaSave({
        examId: this.basicInfo.examId,
        paperNumber: this.basicInfo.paperNumber,
        groupNumber: row.groupNumber,
        pictureConfigs: row.pictureConfigs,
      });
      this.groupList.splice(pos, 1, row);
      this.updateData();
    },
    async markClassChange() {
      const name = this.markClassIsOpen ? "开启" : "取消";
      const confirm = await this.$confirm(`确定要${name}分班阅卷吗?`, "提示", {
        type: "warning",
      }).catch(() => {});
      if (confirm !== "confirm") {
        this.markClassIsOpen = !this.markClassIsOpen;
        return;
      }

      const res = await markClassStatusUpdate({
        examId: this.basicInfo.examId,
        paperNumber: this.basicInfo.paperNumber,
        openMarkClass: this.markClassIsOpen,
      }).catch(() => {
        this.markClassIsOpen = !this.markClassIsOpen;
      });
      if (!res) return;
      this.setOpenMarkClass(this.markClassIsOpen);
    },
    checkData() {
      let errorMessages = [];

      if (this.subjectiveQuestionCount > this.groupQuestionCount) {
        errorMessages.push("当前还有题目未设置分组");
      }

      this.groupList.forEach((item, index) => {
        if (item.doubleRate === 1 && !item.arbitrateThreshold) {
          errorMessages.push(`序号${index + 1}设置中，仲裁阀值不能为空`);
        }
      });

      if (errorMessages.length) {
        this.$message.error(errorMessages.join("。"));
        return;
      }
    },
    getData() {
      return this.groupList.map((item) => {
        const group = omit(item, ["id"]);
        group.questions = group.questions.map((item) =>
          pick(item, [
            "id",
            "mainNumber",
            "mainTitle",
            "subNumber",
            "questionType",
            "qno",
          ])
        );
        return group;
      });
    },
    updateData() {
      this.setGroupInfo(this.getData());
    },
  },
};
</script>
