<template>
  <div class="privilege-set">
    <table class="table">
      <colgroup>
        <col width="120" />
        <col width="120" />
        <col width="140" />
        <col width="60" />
        <col width="210" />
      </colgroup>
      <tbody>
        <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'">
              <t-checkbox
                v-model="row.enable"
                :disabled="row.disabled"
                @change="(enable) => pageSelectChange(row, enable)"
              ></t-checkbox>
            </div>
            <div
              v-else-if="
                row.isPage && col && col.type === 'page-data-permission'
              "
            >
              <t-select
                v-model="row.dataPermissionType"
                class="width-200"
                placeholder="请选择"
                :disabled="row.disabled"
                :options="dictToOptionList(DATA_PRIVILEGE_TYPE)"
              >
              </t-select>
            </div>
            <div v-else-if="col && col.type">
              <div
                class="cell-check-list"
                v-for="item in col.datas"
                :key="item.field"
              >
                <t-checkbox
                  v-model="item.enable"
                  :disabled="item.disabled"
                  @change="(enable) => typeSelectChange(row, enable)"
                  >{{ item.name }}</t-checkbox
                >
              </div>
            </div>
            <div v-else></div>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script setup name="PrivilegeEdit">
import { onMounted, ref } from 'vue';
import { DATA_PRIVILEGE_TYPE } from '@/config/constants';
import { dictToOptionList } from '@/utils/tool';

const props = defineProps({
  menus: Array,
  showPermission: {
    type: Boolean,
    default: false,
  },
  disabledPermissionUrls: {
    type: Array,
    default() {
      return [];
    },
  },
});

const maxDeep = ref(0);
const tableData = ref([]);
const tableHead = ref([]);

onMounted(() => {
  initData();
});

function initData() {
  maxDeep.value = getNavsDeep();
  tableHead.value = buildTableHead();
}

function getNavsDeep() {
  let mDeep = 0;
  const getDeep = (navs, deep) => {
    ++deep;
    navs.forEach((nav) => {
      if (mDeep < deep) mDeep = deep;

      if (nav.children && nav.children.length) getDeep(nav.children, deep);
    });
  };
  getDeep(props.menus, mDeep);

  return mDeep;
}
function buildTableHead() {
  let headers = [];
  let codes = ['一', '二', '三', '四', '五', '六', '七', '八'];
  for (let index = 0; index < maxDeep.value; index++) {
    headers.push(`${codes[index]}级页面`);
  }
  headers = [...headers, '页面'];
  if (props.showPermission) headers.push('数据权限');
  headers = [...headers, '查询条件', '功能按钮', '列表展示', '操作列'];

  return headers;
}
function buildTableData(
  privilegeIds = [],
  dataPermissionInfo = [],
  disabledIds = []
) {
  let dataList = [];
  const privColumnCount = props.showPermission ? 6 : 5;
  let tableColumnCount = maxDeep.value + privColumnCount;
  const pageSetTypes = ['conditions', 'buttons', 'lists', 'links'];

  let datePermissionMap = {};
  dataPermissionInfo.forEach((item) => {
    datePermissionMap[item.privilegeId] = item.dataPermissionType;
  });
  const buildData = (navs, deep) => {
    ++deep;
    navs.forEach((nav) => {
      const isDisabledPermissionUrl = props.disabledPermissionUrls.includes(
        nav.url
      );
      let columns = new Array(tableColumnCount);
      columns[deep - 1] = { type: 'page', name: nav.name };
      columns[maxDeep.value] = {
        type: 'page-checkbox',
      };
      if (props.showPermission && !isDisabledPermissionUrl) {
        columns[maxDeep.value + 1] = {
          type: 'page-data-permission',
        };
      }

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

      dataList.push({
        id: nav.id,
        name: nav.name,
        url: nav.url,
        enable: privilegeIds.includes(nav.id),
        disabled: disabledIds.includes(nav.id),
        dataPermissionType:
          isPage && props.showPermission && !isDisabledPermissionUrl
            ? datePermissionMap[nav.id] || 'SELF'
            : null,
        type: nav.type,
        parentId: nav.parentId,
        isPage,
        columns,
      });

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

  tableData.value = dataList;
}
function resetdataPermissionType(val) {
  tableData.value.forEach((item) => {
    if (
      item.isPage &&
      !item.disabled &&
      props.showPermission &&
      !this.disabledPermissionUrls.includes(item.url)
    )
      item.dataPermissionType = val;
  });
}
function getSelectedPrivileges() {
  let privilegeIds = [];
  let dataPermissionInfo = [];
  tableData.value
    .filter((row) => row.enable)
    .forEach((row) => {
      privilegeIds.push(row.id);
      dataPermissionInfo.push({
        privilegeId: row.id,
        dataPermissionType: row.dataPermissionType,
      });
      row.columns.forEach((column) => {
        if (!column.datas || !column.datas.length) return;

        column.datas.forEach((item) => {
          if (item.enable) privilegeIds.push(item.id);
        });
      });
    });
  return { privilegeIds, dataPermissionInfo };
}
// set change
function pageSelectChange(row, enable) {
  changRowColumnEnable(row, enable);
  changeParentNodeSelected(row.parentId, enable);
  changeChildrenNodeSelected(row.id, enable);
}
function typeSelectChange(row, enable) {
  if (!row.enable && enable) {
    row.enable = enable;
    changeParentNodeSelected(row.parentId, enable);
    changeChildrenNodeSelected(row.id, enable);
  }
}
function changRowColumnEnable(row, enable) {
  if (!row.isPage) return;
  row.columns.forEach((column) => {
    if (!column.datas || !column.datas.length) return;

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

defineExpose({
  buildTableData,
  getSelectedPrivileges,
  resetdataPermissionType,
});
</script>

<style lang="less" scoped>
.privilege-set {
  overflow: auto;
  width: 100%;
  .table {
    td,
    th {
      padding: 8px 10px;
    }

    th:nth-of-type(4),
    td:nth-of-type(4) {
      text-align: center;
    }
  }
  .cell-check-list {
    text-align: left;
  }
}
</style>
