<template>
  <el-dialog
    class="modify-mark-group modify-marker-question"
    :visible.sync="modalIsShow"
    append-to-body
    top="10vh"
    width="900px"
    title="分组设置"
    :close-on-click-modal="false"
    :close-on-press-escape="false"
    :show-close="false"
    @opened="visibleChange"
  >
    <!-- <div slot="title"></div> -->
    <el-form ref="rowInfoFormRef" :model="rowInfo" :rules="rowInfoRules" inline>
      <el-form-item label="评卷方式：" label-width="80px">
        <el-radio-group
          v-model="rowInfo.doubleEnable"
          @change="doubleEnableChange"
        >
          <el-radio :label="false">单评</el-radio>
          <el-radio :label="true">双评</el-radio>
        </el-radio-group>
      </el-form-item>
      <br />
      <template v-if="rowInfo.doubleEnable">
        <el-form-item label="仲裁阀值：" prop="arbitrateThreshold">
          <el-input-number
            v-model="rowInfo.arbitrateThreshold"
            class="width-80"
            size="small"
            :min="0"
            :max="999999"
            :step="0.01"
            step-strictly
            :controls="false"
          >
          </el-input-number>
        </el-form-item>
        <el-form-item label="合分策略：" prop="scorePolicy">
          <el-select v-model="rowInfo.scorePolicy">
            <el-option
              v-for="(val, key) in SCORE_POLICY_TYPE"
              :key="key"
              :label="val"
              :value="key"
            ></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="双评比例：" prop="doubleRate">
          <el-input-number
            v-model="rowInfo.doubleRate"
            class="width-80"
            size="small"
            :min="1"
            :max="100"
            :step="1"
            step-strictly
            :controls="false"
          >
          </el-input-number>
          <span style="margin-left: 5px">%</span>
        </el-form-item>
      </template>
    </el-form>

    <el-row type="flex" :gutter="10">
      <el-col :span="12">
        <div class="marker-box">
          <div class="user-title">评卷员</div>
          <div class="user-search">
            <el-input
              v-model="filterLabel"
              placeholder="请输入评卷员名称"
              clearable
              size="mini"
              prefix-icon="el-icon-search"
              @input="labelChange"
            ></el-input>
          </div>
          <div class="user-types">
            <div
              :class="['user-type', { 'is-active': userType === 'org' }]"
              @click="switchUserType('org')"
            >
              组织架构
            </div>
            <div
              :class="['user-type', { 'is-active': userType === 'course' }]"
              @click="switchUserType('course')"
            >
              课程
            </div>
          </div>
          <div class="user-tree">
            <el-tree
              ref="UserTree"
              :data="userTree"
              node-key="id"
              :default-checked-keys="selectedUserIds"
              :props="defaultProps"
              default-expand-all
            >
              <span class="custom-tree-node" slot-scope="{ node, data }">
                <el-checkbox
                  v-if="data.isUser"
                  v-model="node.checked"
                  @change="(val) => userChange(val, data)"
                >
                  {{ node.label }}（{{ data.loginName }}）
                </el-checkbox>
                <span v-else>{{ node.label }}</span>
                <div title="全选" @click.stop>
                  <el-checkbox
                    v-if="!data.isUser && data.children.length"
                    v-model="data.selected"
                    @change="(checked) => selectNodeAll(checked, data)"
                  ></el-checkbox>
                </div>
              </span>
            </el-tree>
          </div>
        </div>
      </el-col>
      <el-col :span="12">
        <div class="marker-box marker-box-uq">
          <el-form
            ref="modalFormRef"
            :rules="rules"
            :model="{}"
            label-width="100px"
            label-position="top"
          >
            <el-form-item prop="users" label="已选评卷员：">
              <el-tag
                v-for="user in selectedUsers"
                :key="user.id"
                closable
                :disable-transitions="false"
                @close="toDeleteUser(user)"
              >
                {{ user.name }}（{{ user.orgName }}）
              </el-tag>
            </el-form-item>
            <el-form-item
              prop="questions"
              :label="canSelectQuestion ? '选择评卷题目：' : '评卷题目：'"
            >
              <div class="marker-paper-struct">
                <div
                  v-for="mainItem in paperStructs"
                  :key="mainItem.mainNumber"
                  class="struct-item"
                >
                  <div class="struct-header box-justify">
                    <h4>{{ mainItem.mainNumber }}、{{ mainItem.mainTitle }}</h4>
                    <el-checkbox
                      v-if="
                        canSelectQuestion &&
                        mainItem.children &&
                        mainItem.children.length
                      "
                      v-model="mainItem.selected"
                      title="全选"
                      @change="
                        (checked) => selectQuestionAll(checked, mainItem)
                      "
                    ></el-checkbox>
                  </div>
                  <div
                    v-if="mainItem.children && mainItem.children.length"
                    class="struct-questions"
                  >
                    <template v-if="canSelectQuestion">
                      <el-checkbox
                        v-for="question in mainItem.children"
                        :key="question.id"
                        v-model="question.selected"
                        :disabled="question.disabled"
                        @change="questionChange"
                      >
                        {{ question.subNumber }}
                      </el-checkbox>
                    </template>
                    <template v-else>
                      <template v-for="question in mainItem.children">
                        <el-tag v-if="question.selected" :key="question.id">{{
                          question.subNumber
                        }}</el-tag>
                      </template>
                    </template>
                  </div>
                </div>
              </div>
            </el-form-item>
          </el-form>
        </div>
      </el-col>
    </el-row>

    <div class="marker-footer">
      <el-button type="primary" @click="confirm">确认</el-button>
      <el-button @click="cancel">取消</el-button>
    </div>

    <div slot="footer"></div>
  </el-dialog>
</template>

<script>
import { deepCopy } from "../../../../plugins/utils";
import { organizationList } from "../../../base/api";
import { SCORE_POLICY_TYPE } from "@/constants/enumerate";
import { omit } from "lodash";

export default {
  name: "modify-mark-group",
  props: {
    instance: {
      type: Object,
      default() {
        return {};
      },
    },
    disabledQuestionNos: {
      type: Array,
      default() {
        return [];
      },
    },
    paperStructure: {
      type: Array,
      default() {
        return [];
      },
    },
    courseCode: {
      type: String,
      default: "",
    },
    canSelectQuestion: {
      type: Boolean,
      default: true,
    },
  },
  data() {
    const usersValidator = (rule, value, callback) => {
      if (!this.selectedUserIds.length) {
        callback(new Error("请选择评卷员"));
      } else {
        callback();
      }
    };
    const questionsValidator = (rule, value, callback) => {
      if (!this.selectedQuestionNos.length) {
        callback(new Error("请选择试题"));
      } else {
        callback();
      }
    };

    return {
      modalIsShow: false,
      SCORE_POLICY_TYPE,
      filterLabel: "",
      userType: "course",
      courseUsers: [],
      orgUsers: [],
      userTree: [],
      userList: [],
      selectedUsers: [],
      selectedUserIds: [],
      selectedQuestions: [],
      selectedQuestionNos: [],
      paperStructs: [],
      defaultProps: {
        children: "children",
        label: "label",
      },
      rules: {
        users: [
          {
            required: true,
            validator: usersValidator,
            trigger: "change",
          },
        ],
        questions: [
          {
            required: true,
            validator: questionsValidator,
            trigger: "change",
          },
        ],
      },
      instRow: {},
      rowInfo: {},
      rowInfoRules: {
        doubleRate: [
          {
            required: true,
            message: "双评比例必填",
            trigger: "change",
          },
        ],
        arbitrateThreshold: [
          {
            required: true,
            message: "仲裁阀值必填",
            trigger: "change",
          },
        ],
        scorePolicy: [
          {
            required: true,
            message: "合分策略必选",
            trigger: "change",
          },
        ],
      },
    };
  },
  computed: {
    isEdit() {
      return !this.instance.isNew;
    },
  },
  mounted() {
    this.getOrgData();
  },
  methods: {
    visibleChange() {
      this.parseStructs();
      this.filterLabel = "";
      this.userType = "course";
      this.selectedQuestions = this.instance.questions;
      this.selectedQuestionNos = this.selectedQuestions.map((item) => item.id);
      this.selectedUsers = this.instance.markers.map((item) => {
        return { ...item, id: item.userId };
      });
      this.selectedUserIds = this.instance.markers.map((item) => item.userId);
      this.labelChange();
      this.rowInfo = this.$objAssign(
        {
          doubleEnable: false,
          doubleRate: null,
          arbitrateThreshold: null,
          scorePolicy: "AVG",
        },
        this.instance
      );
      this.rowInfo.doubleRate = this.rowInfo.doubleRate || undefined;
      this.rowInfo.arbitrateThreshold =
        this.rowInfo.arbitrateThreshold || undefined;
      this.instRow = { ...this.rowInfo };
    },
    cancel() {
      this.modalIsShow = false;
      this.$emit("cancel");
    },
    open() {
      this.modalIsShow = true;
    },
    doubleEnableChange() {
      this.rowInfo.arbitrateThreshold = undefined;
      this.rowInfo.doubleRate = undefined;
    },
    // user
    switchUserType(type) {
      this.filterLabel = "";
      this.userType = type;

      this.userTree =
        type === "org" ? deepCopy(this.orgUsers) : deepCopy(this.courseUsers);
      this.$refs.UserTree.setCheckedKeys(this.selectedUserIds);
    },
    async getOrgData() {
      let params = {
        specialPrivilege: "MARKER",
      };
      if (this.courseCode) params.courseCode = this.courseCode;
      const data = await organizationList(params);
      this.parseUserData(data);
      this.getUserList();
    },
    parseUserData(data) {
      const parseUser = (list) => {
        return list.map((item) => {
          // org
          let nitem = {
            id: item.id,
            label: item.name,
            isUser: false,
            selected: false,
            children: [],
          };

          if (item["children"] && item["children"].length) {
            nitem.children = [...nitem.children, ...parseUser(item.children)];
          }
          // user
          if (item["sysUserList"] && item["sysUserList"].length) {
            let sysUserList = item.sysUserList;
            const users = sysUserList.map((user) => {
              const nuser = {
                id: user.id,
                userId: user.id,
                label: user.realName,
                name: user.realName,
                orgName: item.name,
                loginName: user.loginName,
                selected: false,
                isUser: true,
              };
              return nuser;
            });
            nitem.children = [...nitem.children, ...users];
          }

          if (item["courseUserList"] && item["courseUserList"].length) {
            nitem.courseUserList = item.courseUserList.map((user) => {
              return {
                id: user.id,
                userId: user.id,
                label: user.realName,
                name: user.realName,
                orgName: user.orgName,
                loginName: user.loginName,
                selected: false,
                isUser: true,
              };
            });
          }
          return nitem;
        });
      };
      this.orgUsers = parseUser(data);
      this.userTree = deepCopy(this.orgUsers);
      if (this.courseCode && this.orgUsers[0].courseUserList) {
        this.courseUsers = deepCopy(this.orgUsers[0].courseUserList);
      }
      this.getUserList();
    },
    getUserList() {
      let userList = [];
      const fetchUser = (users) => {
        users.forEach((item) => {
          if (item["children"] && item["children"].length) {
            fetchUser(item.children);
          } else {
            if (item.isUser) {
              let nitem = { ...item };
              nitem.label = `${nitem.name}(${nitem.orgName})`;
              userList.push(nitem);
            }
          }
        });
      };
      fetchUser(this.orgUsers);

      this.userList = userList;
    },
    labelChange() {
      if (!this.filterLabel) {
        this.switchUserType(this.userType);
      } else {
        const escapeRegexpString = (value = "") =>
          String(value).replace(/[|\\{}()[\]^$+*?.]/g, "\\$&");
        const reg = new RegExp(escapeRegexpString(this.filterLabel), "i");

        if (this.userType === "org") {
          this.userTree = this.userList.filter((item) => reg.test(item.name));
        } else {
          this.userTree = this.courseUsers.filter((item) =>
            reg.test(item.name)
          );
        }
      }
      this.$refs.UserTree.setCheckedKeys(this.selectedUserIds);
    },
    selectNodeAll(checked, data) {
      let users = [];
      const getUserIds = (list) => {
        list.forEach((item) => {
          item.selected = checked;
          if (item.children && item.children.length) {
            getUserIds(item.children);
          } else {
            if (item.isUser) users.push(item);
          }
        });
      };
      getUserIds(data.children);

      const userIds = users.map((u) => u.id);
      const selectedUserIds = this.selectedUsers.map((item) => item.id);

      let deleteUserIds = [];
      userIds.forEach((userId, uindex) => {
        const userPos = selectedUserIds.indexOf(userId);
        const includeUser = userPos !== -1;
        if (checked) {
          if (!includeUser) this.selectedUsers.push(users[uindex]);
        } else {
          if (includeUser) {
            deleteUserIds.push(userId);
          }
        }
      });
      this.selectedUsers = this.selectedUsers.filter(
        (u) => !deleteUserIds.includes(u.id)
      );
      this.selectedUserIds = this.selectedUsers.map((item) => item.id);
      this.$refs.UserTree.setCheckedKeys(this.selectedUserIds);
      this.$refs.modalFormRef.validateField("users");
    },
    updateSelectedUsersFromUserIds() {
      this.selectedUsers = this.userList.filter((user) =>
        this.selectedUserIds.includes(user.id)
      );
    },
    userChange(checked, user) {
      if (checked) {
        this.selectedUsers.push(user);
      } else {
        this.selectedUsers = this.selectedUsers.filter(
          (item) => item.id !== user.id
        );
      }
      this.selectedUserIds = this.selectedUsers.map((item) => item.id);
      this.$refs.modalFormRef.validateField("users");
    },
    toDeleteUser(user) {
      const pos = this.selectedUsers.findIndex((item) => item.id === user.id);
      this.selectedUsers.splice(pos, 1);
      this.selectedUserIds = this.selectedUsers.map((item) => item.id);
      this.$refs.UserTree.setCheckedKeys(this.selectedUserIds);
      this.$refs.modalFormRef.validateField("users");
    },
    // question
    parseStructs() {
      this.selectedQuestionNos = this.instance.questions.map((q) => q.qno);
      let paperStructs = [];
      let struct = null;
      this.paperStructure.forEach((item) => {
        if (item.mainFirstSub) {
          if (struct) paperStructs.push(struct);
          struct = {
            mainTitle: item.mainTitle,
            mainNumber: item.mainNumber,
            selected: false,
            children: [],
          };
        }
        struct.children.push({
          ...item,
          disabled: this.disabledQuestionNos.includes(item.qno),
          selected: this.selectedQuestionNos.includes(item.qno),
        });
      });
      if (struct) paperStructs.push(struct);
      this.paperStructs = paperStructs;
    },
    selectQuestionAll(checked, mainItem) {
      mainItem.children.forEach((q) => {
        if (!q.disabled) q.selected = checked;
      });
      this.questionChange();
    },
    updateSelectedQuestions() {
      let selectedQuestions = [];
      let selectedQuestionNos = [];
      this.paperStructs.forEach((s) => {
        s.children.forEach((q) => {
          if (q.selected && !q.disabled) {
            selectedQuestions.push(q);
            selectedQuestionNos.push(q.qno);
          }
        });
      });
      this.selectedQuestions = selectedQuestions;
      this.selectedQuestionNos = selectedQuestionNos;
    },
    questionChange() {
      this.updateSelectedQuestions();
      this.$refs.modalFormRef.validateField("questions");
    },
    getQuestionStruct(questions) {
      let structs = questions.map((item) => {
        return {
          mainNumber: item.mainNumber,
          subNumber: item.subNumber,
        };
      });
      structs.sort(
        (a, b) => a.mainNumber - b.mainNumber || a.subNumber - b.subNumber
      );
      return structs
        .map((item) => `${item.mainNumber}_${item.subNumber}`)
        .join();
    },
    equalArr(arr1, arr2) {
      arr1.sort((a, b) => {
        return a > b ? -1 : 1;
      });
      arr2.sort((a, b) => {
        return a > b ? -1 : 1;
      });
      // console.log(arr1, arr2);
      return JSON.stringify(arr1) === JSON.stringify(arr2);
    },
    checkDataChange() {
      const fields = ["doubleEnable", "arbitrateThreshold", "doubleRate"];
      let changed = fields.some(
        (field) => this.rowInfo[field] !== this.instRow[field]
      );
      if (changed) return true;

      const prevQnos = this.instance.questions.map(
        (item) => `${item.mainNumber}-${item.subNumber}`
      );
      const curQnos = this.selectedQuestions.map(
        (item) => `${item.mainNumber}-${item.subNumber}`
      );
      changed = !this.equalArr(prevQnos, curQnos);
      return changed;

      // const prevUserIds = this.instance.markers.map((item) => item.userId);
      // const curUserIds = this.selectedUsers.map((item) => item.id);
      // changed = !this.equalArr(prevUserIds, curUserIds);
      // return changed;
    },
    // confirm
    async confirm() {
      const valid1 = await this.$refs.rowInfoFormRef.validate().catch(() => {});
      const valid2 = await this.$refs.modalFormRef.validate().catch(() => {});
      if (!valid1 || !valid2) return;

      if (this.isEdit) {
        const changed = this.checkDataChange();
        if (changed) {
          const confirm = await this.$confirm(
            `保存后分组关联所有评卷任务都将删除，并生成新的分组任务!`,
            "提示",
            {
              type: "warning",
            }
          ).catch(() => {});
          if (confirm !== "confirm") return;
        }
      }

      let datas = Object.assign({}, this.instance, this.rowInfo);
      datas.markers = this.selectedUsers.map((item) => {
        return {
          id: item.id,
          userId: item.id,
          name: item.name,
          loginName: item.loginName,
          orgName: item.orgName,
        };
      });
      datas.questions = this.selectedQuestions.map((item) => {
        let nitem = { ...item };
        delete nitem.disabled;
        delete nitem.selected;
        return nitem;
      });
      // 评卷题目变动时，清空评卷区
      if (
        this.getQuestionStruct(this.instance.questions) !==
        this.getQuestionStruct(datas.questions)
      ) {
        datas.pictureConfigs = [];
      }
      this.$emit("modified", omit(datas, ["isNew"]));
      this.modalIsShow = false;
    },
  },
};
</script>
