<template>
  <div class="mark-param-structure">
    <div class="part-box part-box-pad box-justify">
      <el-breadcrumb separator="|">
        <el-breadcrumb-item
          >本试卷大题：{{ paperStat.mainQuestionCount }}道</el-breadcrumb-item
        >
        <el-breadcrumb-item
          >小题：{{ paperStat.questionCount }}道</el-breadcrumb-item
        >
        <el-breadcrumb-item
          >客观题：{{ paperStat.objectiveQuestionCount }}道</el-breadcrumb-item
        >
        <el-breadcrumb-item
          >主观题：{{ paperStat.subjectiveQuestionCount }}道</el-breadcrumb-item
        >
        <el-breadcrumb-item
          >总分：<span class="color-danger mlr-1">{{
            paperStat.paperTotalScore
          }}</span>
          分
        </el-breadcrumb-item>
      </el-breadcrumb>

      <div>
        <el-button type="primary" @click="toNext(1)">下一步</el-button>
      </div>
    </div>

    <div class="part-box part-box-pad structure-body">
      <div class="box-justify mb-2">
        <div>
          <el-button v-if="editOpen" type="primary" @click="toAddMain"
            >新增大题</el-button
          >
        </div>
        <div v-if="checkPrivilege('link', 'EditPaperStruct', 'MarkSetting')">
          <el-switch v-model="editOpen" active-text="开启编辑"></el-switch>
        </div>
      </div>

      <el-table
        ref="TableList"
        :data="tableData"
        border
        :row-class-name="getRowClassName"
        :key="tableKey"
        :height="tableHeight"
      >
        <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="editOpen">
          <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"
                :disabled="checkMainQuestionHasMarker(scope.row.mainId)"
                @visible-change="(val) => qTypeVisibleChange(val, scope.row)"
                @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 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 label="每题分值" width="120">
          <template slot="header">
            <span>每题分值</span>
            <el-tooltip effect="dark" placement="top">
              <div slot="content" class="tooltip-area">
                <p>每题分值，属于批量设置</p>
                <p>
                  输入每题分值后，比如2按回车键或鼠标点击输入框外其他地方，系统会自动设置该大题下每个小题的分值为2。
                </p>
              </div>
              <i class="el-icon-info ml-1 tooltip-info-icon"></i>
            </el-tooltip>
          </template>
          <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"
              :max="500"
              :step="0.1"
              step-strictly
              :controls="false"
              placeholder="每题分值"
              @change="(val) => scorePerTopicChange(val, scope.row)"
            ></el-input-number>
          </template>
        </el-table-column>
        <el-table-column prop="totalScore" label="小题满分" width="120">
          <template slot-scope="scope">
            <el-input-number
              v-model="scope.row.totalScore"
              class="width-full"
              size="small"
              :min="0"
              :max="500"
              :step="0.1"
              step-strictly
              :controls="false"
              placeholder="小题分值"
              @change="totalScoreChange(scope.row)"
            ></el-input-number>
          </template>
        </el-table-column>
        <el-table-column label="每题最小分" width="120">
          <template
            slot-scope="scope"
            v-if="scope.row.mainFirstSub && !scope.row.objective"
          >
            <el-input-number
              v-model="intervalScorePerTopic[scope.row.mainId]"
              class="width-full"
              size="small"
              :min="0.1"
              :max="500"
              :step="0.1"
              step-strictly
              :controls="false"
              placeholder="每题最小分"
              @change="(val) => intervalScorePerTopicChange(val, scope.row)"
            ></el-input-number>
          </template>
        </el-table-column>
        <el-table-column prop="intervalScore" label="最小分" width="120">
          <template slot="header">
            <span>最小分</span>
            <el-tooltip effect="dark" placement="top">
              <div slot="content" class="tooltip-area">
                <p>最小分是评卷中每题最小给分间隔，详见样例。</p>
                <p>
                  如小题总分为5分的题目，最小分设置为1，则可以给0,1,2,3,4,5分。
                </p>
                <p>
                  如最小分设置为0.5分，则可以给0.5,1,1.5,2,2.5,3,3.5,4,4.5,5分。
                </p>
                <p>如果最小分设置为5分，则只能给0分和5分。</p>
                <p>每题最小分是只用设置1次，系统会自动设置每个小题的最小分</p>
              </div>
              <i class="el-icon-info ml-1 tooltip-info-icon"></i>
            </el-tooltip>
          </template>
          <template slot-scope="scope" v-if="!scope.row.objective">
            <el-input-number
              v-model="scope.row.intervalScore"
              class="width-full"
              size="small"
              :min="0.1"
              :max="scope.row.totalScore"
              :step="0.1"
              step-strictly
              :controls="false"
              placeholder="最小分"
            ></el-input-number>
          </template>
        </el-table-column>
        <el-table-column
          v-if="editOpen"
          class-name="action-column"
          label="操作"
          width="140px"
        >
          <template slot-scope="scope">
            <el-button
              class="btn-primary"
              type="text"
              @click="toAddSub(scope.row)"
              >新增小题</el-button
            >
            <el-button
              :disabled="
                tableData.length <= 1 || checkSubQuestionHasMarker(scope.row)
              "
              class="btn-danger"
              type="text"
              @click="toDeleteSub(scope.row)"
              >删除</el-button
            >
          </template>
        </el-table-column>
      </el-table>
      <!-- tips -->
      <div class="mt-2">
        <p class="tips-info">
          1.请确认展示的试卷结构与提交的试卷、答题卡是否一致？
        </p>
        <p class="tips-info">
          2.请补充所有题目的小题分值，并确认试卷总分。主观题设置间隔分，间隔分的具体说明见列表帮助提示。
        </p>
        <p class="tips-info tips-error">
          3.开始阅卷后不允许修改试卷结构，请确认清楚后再提交！
        </p>
      </div>
    </div>
  </div>
</template>

<script>
import { calcSum, maxNum, toPrecision } from "@/plugins/utils";
import { QUESTION_TYPE_LIST } from "@/constants/enumerate";
import { mapState, mapMutations } from "vuex";
import { markStructureSave } from "../../api";
import { omit } from "lodash";
import { MD5 } from "@/plugins/md5";

export default {
  name: "mark-paper-structure",
  data() {
    return {
      tableData: [],
      curRow: {},
      cacheDataMd5: "",
      QUESTION_TYPE_LIST,
      questionTypeDict: {},
      scoresPerTopic: {},
      intervalScorePerTopic: {},
      loading: false,
      editOpen: false,
      tableKey: "",
      hasMarkerQuestions: [],
      tableHeight: 200,
    };
  },
  computed: {
    ...mapState("markParam", [
      "basicInfo",
      "paperStructureInfo",
      "subjectiveTaskList",
    ]),
    paperStat() {
      const questionCount = this.tableData.length;

      const mainQuestionCount = this.tableData.filter(
        (item) => item.mainFirstSub
      ).length;

      const subjectiveQuestionCount = this.tableData.filter(
        (item) => !item.objective
      ).length;

      const paperTotalScore = toPrecision(
        calcSum(this.tableData.map((item) => item.totalScore || 0)),
        1
      );

      return {
        questionCount,
        mainQuestionCount,
        paperTotalScore,
        subjectiveQuestionCount,
        objectiveQuestionCount: questionCount - subjectiveQuestionCount,
      };
    },
  },
  watch: {
    editOpen() {
      this.tableKey = this.$randomCode();
      this.updateTableHeight();
    },
  },
  mounted() {
    this.initData();
    this.registResize();
  },
  methods: {
    ...mapMutations("markParam", ["setPaperStructureInfo"]),
    initData() {
      this.tableKey = this.$randomCode();
      this.hasMarkerQuestions = this.subjectiveTaskList
        .filter((item) => item.markers.length)
        .map((item) => `${item.mainNumber}-${item.subNumber}`);

      let questionTypeDict = {};
      QUESTION_TYPE_LIST.forEach((item) => {
        questionTypeDict[item.code] = item.name;
      });
      this.questionTypeDict = questionTypeDict;

      let curMainNumber = null;
      let curMainId = null;
      let scoresPerTopic = {},
        intervalScorePerTopic = {};

      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;
          intervalScorePerTopic[curMainNumber] = undefined;
          nitem.mainFirstSub = true;
        }
        nitem.totalScore =
          nitem.totalScore || nitem.totalScore === 0
            ? nitem.totalScore
            : undefined;
        nitem.intervalScore = nitem.intervalScore || undefined;
        nitem.mainId = curMainId;

        return nitem;
      });
      this.scoresPerTopic = scoresPerTopic;
      this.intervalScorePerTopic = intervalScorePerTopic;

      if (!this.tableData.length && this.editOpen) {
        this.createMain();
      }
      this.cacheDataMd5 = this.getSubmitDataMd5();

      this.updateTableHeight();
    },
    getSubmitDataMd5() {
      return MD5(JSON.stringify(this.getData()));
    },
    getNewRow(val) {
      return this.$objAssign(
        {
          id: null,
          key: this.$randomCode(),
          mainId: this.$randomCode(),
          objective: 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;
    },
    getNewMainNumber() {
      return maxNum(this.tableData.map((item) => item.mainNumber)) + 1;
    },
    toAddMain() {
      const newMainData = this.getNewRow({
        mainId: this.$randomCode(),
        mainNumber: this.getNewMainNumber(),
        totalScore: undefined,
        questionType: null,
        objective: true,
      });
      this.tableData.push(newMainData);
      this.$set(this.intervalScorePerTopic, newMainData.mainId, undefined);
    },
    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.key === row.key);
      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;
        });
    },
    async toDeleteSub(row) {
      if (!row.objective && this.checkSubQuestionHasMarker(row)) {
        this.$message.error("当前小题已设置评卷员，不可删除！");
        return;
      }

      const confirm = await this.$confirm(`确定要删除小题吗?`, "提示", {
        type: "warning",
      }).catch(() => {});
      if (confirm !== "confirm") return;

      const subPos = this.tableData.findIndex((item) => item.key === row.key);
      this.tableData.splice(subPos, 1);

      this.tableData
        .filter((item) => item.mainId === row.mainId)
        .forEach((item, index) => {
          item.mainFirstSub = !index;
        });
      this.updateSubData(row.mainId);
    },
    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));
    },
    qTypeVisibleChange(val, row) {
      if (!val) return;
      this.curRow = { ...row };
    },
    checkMainQuestionHasMarker(mainId) {
      return this.tableData
        .filter((item) => item.mainId === mainId)
        .some((item) => this.checkSubQuestionHasMarker(item));
    },
    checkSubQuestionHasMarker(item) {
      return this.hasMarkerQuestions.includes(
        `${item.mainNumber}-${item.subNumber}`
      );
    },
    async qTypeChange(row) {
      if (row.objective) {
        const confirm = await this.$confirm(`确定要更改题型吗?`, "提示", {
          type: "warning",
        }).catch(() => {});
        if (confirm !== "confirm") {
          row.questionType = this.curRow.questionType;
          return;
        }
      } else {
        if (this.checkMainQuestionHasMarker(row.mainId)) {
          row.questionType = this.curRow.questionType;
          this.$message.error("当前大题已设置评卷员，不可更改");
          return;
        }
      }

      const curQt = this.QUESTION_TYPE_LIST.find(
        (item) => item.code === row.questionType
      );
      if (!curQt) return;

      this.tableData
        .filter((item) => item.mainId === row.mainId)
        .forEach((item) => {
          item.questionType = curQt.code;
          item.objective = curQt.qType === "objective";
          item.optionCount = curQt.optionCount;
          if (item.objective) {
            item.intervalScore = undefined;
            this.intervalScorePerTopic[row.mainId] = undefined;
          }
        });
    },
    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 && val !== 0) return;
      this.tableData
        .filter((item) => item.mainId === row.mainId)
        .forEach((item) => {
          item.totalScore = val;
          item.intervalScore = Math.min(item.totalScore, item.intervalScore);
        });
    },
    intervalScorePerTopicChange(val, row) {
      if (!val) return;
      this.tableData
        .filter((item) => item.mainId === row.mainId)
        .forEach((item) => {
          item.intervalScore = Math.min(item.totalScore, val);
        });
    },
    totalScoreChange(row) {
      const isInit = (num) => !(num % 1);
      if (!row.intervalScore) {
        row.intervalScore = isInit(row.totalScore) ? 1 : 0.5;
        return;
      }
      if (
        (isInit(row.totalScore) && !isInit(row.intervalScore)) ||
        (!isInit(row.totalScore) && isInit(row.intervalScore))
      ) {
        row.intervalScore = isInit(row.totalScore) ? 1 : 0.5;
        return;
      }

      row.intervalScore = Math.min(row.totalScore, row.intervalScore);
    },
    checkData() {
      let errorMessages = [];
      this.tableData.forEach((item) => {
        let errorMsg = ``;
        if (item.mainFirstSub) {
          let errorFields = [];
          if (!item.mainTitle) {
            errorFields.push("大题名称");
          }
          if (!item.questionType) {
            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 && item.totalScore !== 0) {
          errorFields.push("小题满分");
        }
        if (!item.intervalScore && !item.objective) {
          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);
      return true;
    },
    async toNext(step = 1) {
      if (!this.checkData()) return;

      // 如果试卷结构有变动，先保存
      if (this.cacheDataMd5 !== this.getSubmitDataMd5()) {
        const res = await this.submit();
        if (!res) return;
      }
      this.$emit("next", step);
    },
    // table height
    updateTableHeight() {
      this.$nextTick(() => {
        if (!this.$refs.TableList) return;
        const tableOffsetTop = this.$refs.TableList.$el.offsetTop;
        this.tableHeight = window.innerHeight - tableOffsetTop - 115;
        // console.log(this.tableHeight);
      });
    },
    registResize() {
      window.addEventListener("resize", this.updateTableHeight);
    },
  },
  beforeDestroy() {
    window.removeEventListener("resize", this.updateTableHeight);
  },
};
</script>
