<template>
  <div class="privilege-set">
    <table class="table">
      <tr>
        <th v-for="(item, index) in tableHead" :key="index">{{ item }}</th>
      </tr>
      <tr v-for="row in tableData" :key="row.id">
        <td v-for="(col, cindex) in row.columns" :key="cindex">
          <div v-if="col && col.type === 'page'">{{ col.name }}</div>
          <div v-else-if="col && col.type === 'page-checkbox'">
            <el-checkbox
              v-model="row.enable"
              @change="enable => pageSelectChange(row, enable)"
            ></el-checkbox>
          </div>
          <div v-else-if="col && col.type">
            <div
              class="cell-check-list"
              v-for="item in col.datas"
              :key="item.field"
            >
              <el-checkbox
                v-model="item.enable"
                @change="enable => typeSelectChange(row, enable)"
                >{{ item.name }}</el-checkbox
              >
            </div>
          </div>
          <div v-else></div>
        </td>
      </tr>
    </table>
  </div>
</template>

<script>
export default {
  name: "privilege-set",
  props: {
    menus: {
      type: Array,
      default() {
        return [];
      }
    }
  },
  data() {
    return {
      maxDeep: 0,
      tableData: [],
      tableHead: []
    };
  },
  created() {
    this.initData();
  },
  methods: {
    initData() {
      this.maxDeep = this.getNavsDeep();
      this.tableHead = this.buildTableHead();
      // this.buildTableData();
    },
    getNavsDeep() {
      let maxDeep = 0;
      const getDeep = (navs, deep) => {
        ++deep;
        navs.forEach(nav => {
          if (maxDeep < deep) maxDeep = deep;

          if (nav.children && nav.children.length) getDeep(nav.children, deep);
        });
      };
      getDeep(this.menus, maxDeep);

      return maxDeep;
    },
    buildTableHead() {
      let headers = [];
      let codes = ["一", "二", "三", "四", "五", "六", "七", "八"];
      for (let index = 0; index < this.maxDeep; index++) {
        headers.push(`${codes[index]}级页面`);
      }
      headers = [
        ...headers,
        "页面",
        "查询条件",
        "功能按钮",
        "列表展示",
        "操作列"
      ];
      return headers;
    },
    buildTableData(privilegeIds = []) {
      let tableData = [];
      let tableColumnCount = this.maxDeep + 5;
      const pageSetTypes = ["conditions", "buttons", "lists", "links"];
      const buildData = (navs, deep) => {
        ++deep;
        navs.forEach(nav => {
          let columns = new Array(tableColumnCount);
          columns[deep - 1] = { type: "page", name: nav.name };
          columns[this.maxDeep] = {
            type: "page-checkbox"
          };

          const isPage = pageSetTypes.some(
            type => nav[type] && nav[type].length
          );
          if (isPage) {
            pageSetTypes.forEach((type, index) => {
              const datas = !nav[type]
                ? []
                : nav[type].map(elem => {
                    let data = { ...elem };
                    data.enable = privilegeIds.includes(elem.id);
                    return data;
                  });
              columns[this.maxDeep + index + 1] = { type, datas };
            });
          }

          tableData.push({
            id: nav.id,
            name: nav.name,
            enable: privilegeIds.includes(nav.id),
            type: nav.type,
            parentId: nav.parentId,
            isPage,
            columns
          });

          if (nav.children && nav.children.length)
            buildData(nav.children, deep);
        });
      };
      buildData(this.menus, 0);

      this.tableData = tableData;
    },
    getSelectedPrivilegeIds() {
      let privilegeIds = [];
      this.tableData
        .filter(row => row.enable)
        .forEach(row => {
          privilegeIds.push(row.id);
          row.columns.forEach(column => {
            if (column.type === "page" || column.type === "page-checkbox")
              return;

            column.datas.forEach(item => {
              if (item.enable) privilegeIds.push(item.id);
            });
          });
        });
      return privilegeIds;
    },
    // set change
    pageSelectChange(row, enable) {
      this.changRowColumnEnable(row, enable);
      this.changeParentNodeSelected(row.parentId, enable);
      this.changeChildrenNodeSelected(row.id, enable);
    },
    typeSelectChange(row, enable) {
      if (!row.enable && enable) {
        row.enable = enable;
        this.changeParentNodeSelected(row.parentId, enable);
        this.changeChildrenNodeSelected(row.id, enable);
      }
    },
    changRowColumnEnable(row, enable) {
      if (!row.isPage) return;
      row.columns.forEach(column => {
        if (column.type === "page" || column.type === "page-checkbox") return;

        column.datas.forEach(item => {
          item.enable = enable;
        });
      });
    },
    changeParentNodeSelected(parentId, enable) {
      if (!parentId) return;
      let curParentId = parentId;
      if (enable) {
        while (curParentId) {
          let curParentNode = this.tableData.find(
            row => row.id === curParentId
          );
          curParentNode.enable = enable;
          curParentId = curParentNode.parentId;
          this.changRowColumnEnable(curParentNode, enable);
        }
      } else {
        while (curParentId) {
          let curParentNode = this.tableData.find(
            row => row.id === curParentId
          );
          let childrenHasOneSelected = this.tableData
            .filter(row => row.parentId === curParentId)
            .some(row => row.enable);
          curParentNode.enable = childrenHasOneSelected;
          curParentId = curParentNode.parentId;
          this.changRowColumnEnable(curParentNode, enable);
        }
      }
    },
    changeChildrenNodeSelected(id, enable) {
      if (!id) return;
      let curIds = [id];
      while (curIds.length) {
        const validNodes = this.tableData.filter(row =>
          curIds.includes(row.parentId)
        );
        validNodes.forEach(row => {
          row.enable = enable;
          this.changRowColumnEnable(row, enable);
        });
        curIds = validNodes.map(row => row.id);
      }
    }
  }
};
</script>
