<template>
  <div :class="$style.wrap">
    <a-row>
      <a-col :span="12">
        <a-space>
          <a-button :disabled="selectedRowKeys.length === 0" @click="deleteParticipant">
            删除
          </a-button>
          <a-button type="primary" @click="addParticipant">
            添加
          </a-button>
        </a-space>

        <sd-table
          ref="dataTable"
          :columns="columns"
          :custom-row="customRow"
          :data-source.sync="resData"
          row-key="id"
          :row-selection="{
            onChange: (keys) => {
              selectedRowKeys = keys
            },

            selectedRowKeys: selectedRowKeys,
          }"
          :row-class-name="rowClassName"
          :pagination="false"
        />
      </a-col>
      <a-col :span="12" :class="$style['rights-data']">
        <span> 设置:{{ curRoleName }} </span>
        <sd-table
          :columns="rightsColumns"
          sortable
          :data-source.sync="rightsData"
          :pagination="false"
          row-key="id"
        >
          <template slot="accessRender" slot-scope="text, record">
            <a-switch
              v-model="record.access"
              @change="
                (val) => {
                  if (val) record.deny = !val
                }
              "
            >
              <a-icon slot="checkedChildren" type="check" />
              <a-icon slot="unCheckedChildren" type="close" />
            </a-switch>
          </template>
          <template slot="denyRender" slot-scope="text, record">
            <a-switch
              v-model="record.deny"
              @change="
                (val) => {
                  if (val) record.access = !val
                }
              "
            >
              <a-icon slot="checkedChildren" type="check" />
              <a-icon slot="unCheckedChildren" type="close" />
            </a-switch>
          </template>
        </sd-table>
      </a-col>
    </a-row>
    <a-row>
      <a-col :span="24">
        <a-checkbox v-model="entriesInheriting">
          包括可从该对象的父项继承的权限
        </a-checkbox>
      </a-col>
    </a-row>
    <a-modal
      v-model="participant.visible"
      title="参与者"
      destroy-on-close
      v-bind="{ width: 800 }"
      :mask-closable="false"
      @ok="addParticipantConfirm"
      @cancel="$emit('closed')"
    >
      <a-tabs default-active-key="1" @change="tabsChange">
        <a-tab-pane key="1" tab="角色">
          <a-input-search
            v-model="participant.role.search"
            placeholder=""
            allow-clear
            @change="searchParticipantRole"
            @search="searchParticipantRole"
          />
          <sd-data-table
            ref="globalRolesTable"
            :data-url="participant.role.globalUrl"
            :columns="participant.role.columns"
            show-selection
            :filter-expressions="participant.role.customFilterExpressions"
            :process-req="processRoleReq"
            :row-key="'code'"
            :process-res="
              (res) => {
                return processRoleRes(res, 'globalPageSize')
              }
            "
            :pagination="{
              pageSize: participant.role.globalPageSize,
            }"
            hide-pagination
          >
          </sd-data-table>

          <sd-data-table
            v-if="hieraInfo.flags === false"
            ref="localRolesTable"
            :data-url="participant.role.localUrl"
            :columns="participant.role.columns"
            show-selection
            :filter-expressions="participant.role.customFilterExpressions"
            :process-req="processLocalRoleReq"
            :process-res="
              (res) => {
                return processRoleRes(res, 'localPageSize')
              }
            "
            :row-key="'code'"
            :pagination="{
              pageSize: participant.role.localPageSize,
            }"
            hide-pagination
          >
          </sd-data-table>
        </a-tab-pane>
        <a-tab-pane key="2" tab="组织机构" force-render>
          <a-input-search
            v-model="participant.dep.search"
            placeholder=""
            allow-clear
            @change="searchParticipantDep"
            @search="searchParticipantDep"
          />

          <a-tree
            v-if="!(participant.dep.search && participant.dep.search !== '')"
            :key="updateKey"
            v-model="participant.depTree.checkedKeys"
            half-checked-keys-add
            checkable
            :block-node="true"
            :tree-data="participant.depTree.treeData"
            :default-expanded-keys="participant.depTree.defaultExpandedKeys"
            :load-data="onLoadTreeData"
            check-strictly
            @check="check"
          >
          </a-tree>

          <sd-data-table
            v-if="participant.dep.search && participant.dep.search !== ''"
            ref="participantDepTable"
            show-selection
            :columns="participant.dep.columns"
            sortable
            :data-url="participant.dep.dataUrl"
            :filter-expressions="participant.dep.customFilterExpressions"
          >
          </sd-data-table>
        </a-tab-pane>
      </a-tabs>
    </a-modal>
  </div>
</template>

<script>
import { message } from 'ant-design-vue'

import TableActionTypes from '@/common/services/table-action-types'
import NavService from './nav-service'
import components from './_import-components/sd-nav-hiera-import'

export default {
  name: 'SdNavHiera',
  metaInfo: {
    title: 'SdNavHiera',
  },
  components,
  props: {
    unid: {
      type: String,
      default: function() {
        return null
      },
    },
    hieraInfo: {
      type: Object,
      default: () => {},
    },
    curParent: {
      type: Object,
      default: () => {},
    },
    menuPermission: {
      type: Object,
      default: () => {},
    },
  },
  data() {
    return {
      updateKey: 0,
      loadingMsg: null,
      listDataUrl: 'api/framework/v1/menu/menu-item-permission',
      resData: [],
      entriesInheriting: false,
      columns: [
        {
          title: '参与者',
          dataIndex: 'name',
          sdClickable: true,
        },
      ],
      curClickRowKey: '',

      listRolesDataUrl:
        'api/framework/v1/hierarchy-switch/resource-type-enabled?groupId=-1&resourceType=ROLE',
      rolesColumns: [
        {
          title: '参与者',
          dataIndex: 'name',
          sdClickable: true,
        },
      ],
      selectedRowKeys: [],

      participant: {
        visible: false,
        curTab: 1,
        dep: {
          search: '',
          dataUrl: `api/framework/v1/group-manager/manager/group/${this.curParent.groupId}/search`,
          columns: [
            {
              title: '代码',
              dataIndex: 'code',
            },
            {
              title: '名称',
              dataIndex: 'name',
            },
            {
              title: '所属单位',
              dataIndex: 'parentName',
            },
          ],
          customFilterExpressions: [],
        },
        depTree: {
          treeData: [],
          checkedKeys: [],
          checkedNodes: [],
          defaultExpandedKeys: [],
        },
        role: {
          search: '',
          globalUrl: `api/framework/v1/role-manager/query/roles`,
          globalPageSize: 10,
          localPageSize: 10,
          localUrl: `api/framework/v1/role-manager/query/local-roles`,
          columns: [
            {
              title: '代码',
              dataIndex: 'code',
            },
            {
              title: '名称',
              dataIndex: 'name',
            },
          ],
          customFilterExpressions: [],
        },
      },
      actions: [
        {
          label: '新建',
          id: 'new',
          permission: null,

          callback: () => {
            this.participant.visible = true
          },
        },
        {
          label: '删除',
          id: 'delete',
          permission: null,
          type: TableActionTypes.batch,
          callback: (ids) => {
            this.listData.data = this.listData.data.filter((item) => {
              return ids.indexOf(item.id) === -1
            })
          },
        },
      ],
      rightsColumns: [
        {
          title: '权限',
          dataIndex: 'name',
        },
        {
          title: '允许',
          dataIndex: 'access',
          scopedSlots: {
            customRender: 'accessRender',
          },
        },
        {
          title: '拒绝',
          dataIndex: 'deny',
          scopedSlots: {
            customRender: 'denyRender',
          },
        },
      ],
      rightsData: [],
      curRoleName: '',
    }
  },
  watch: {
    unid: {
      handler(newVal, oldVal) {
        this.getDefaultValue()
      },
      immediate: true,
    },
  },
  methods: {
    searchParticipantRole() {
      this.participant.role.customFilterExpressions =
        this.participant.role.search && this.participant.role.search !== ''
          ? [
              {
                dataType: 'exps',
                op: 'or',
                expressionsValue: [
                  {
                    dataType: 'str',
                    name: 'code',
                    op: 'like',
                    stringValue: '%' + this.participant.role.search + '%',
                  },
                  {
                    dataType: 'str',
                    name: 'name',
                    op: 'like',
                    stringValue: '%' + this.participant.role.search + '%',
                  },
                ],
              },
            ]
          : []
    },
    searchParticipantDep() {
      this.participant.dep.customFilterExpressions =
        this.participant.dep.search && this.participant.dep.search !== ''
          ? [
              {
                dataType: 'exps',
                op: 'or',
                expressionsValue: [
                  {
                    dataType: 'str',
                    name: 'code',
                    op: 'like',
                    stringValue: '%' + this.participant.dep.search + '%',
                  },
                  {
                    dataType: 'str',
                    name: 'name',
                    op: 'like',
                    stringValue: '%' + this.participant.dep.search + '%',
                  },
                ],
              },
            ]
          : []
    },
    processRoleReq(req) {
      req.data.groupId = parseInt(this.curParent.groupId, 10)
      req.data.maxResults = -1
      req.data.excludeUserRole = false
      return req
    },
    processLocalRoleReq(req) {
      req.data.groupId = parseInt(this.curParent.groupId, 10)
      req.data.excludeUserRole = false
      req.data.maxResults = -1
      return req
    },
    processRoleRes(res, name) {
      this.participant.role[name] = res.total
      return res
    },

    check(keys, evt) {
      // console.log(evt.node)
      this.participant.depTree.checkedNodes = evt.checkedNodes.map((item) => {
        const dataRef = item.data.props.dataRef
        return {
          id: dataRef.key,
          name: dataRef.name,
        }
      })
    },
    customRow(record) {
      return {
        on: {
          click: () => {
            this.rowClick(record)
          },
        },
      }
    },
    deleteParticipant() {
      this.resData = this.resData.filter((item) => {
        return this.selectedRowKeys.indexOf(item.id) === -1
      })
      const curClickRowKey = this.resData.filter((item) => {
        return this.curClickRowKey === item.id
      })
      if (curClickRowKey.length === 0) {
        if (this.resData.length !== 0) {
          this.setRightsData(this.resData[0])
        } else {
          this.curRoleName = ''
          this.rightsData = []
        }
      }
      this.selectedRowKeys = []
    },
    addParticipant() {
      this.participant.role.search = ''
      this.participant.dep.search = ''
      this.participant.role.customFilterExpressions = []
      this.participant.dep.customFilterExpressions = []
      this.participant.depTree.checkedKeys = []
      if (this.$refs.participantDepTable) {
        this.$refs.participantDepTable.clearSelection(true)
        this.$refs.participantDepTable.refresh()
      }
      this.participant.depTree.checkedNodes = []
      if (this.$refs.globalRolesTable) {
        this.$refs.globalRolesTable.clearSelection(true)
        this.$refs.globalRolesTable.refresh()
      }
      if (this.$refs.localRolesTable) {
        this.$refs.localRolesTable.clearSelection(true)
        this.$refs.localRolesTable.refresh()
      }
      this.participant.visible = true
    },
    addParticipantConfirm() {
      if (this.participant.curTab === '2') {
        let addOrgs = []
        if (this.participant.dep.search && this.participant.dep.search !== '') {
          addOrgs = this.$refs.participantDepTable.getSelectedRows()
        } else {
          addOrgs = this.participant.depTree.checkedNodes
        }
        if (addOrgs.length === 0) {
          message.error('请选择部门')
          return
        }
        addOrgs.forEach((dep) => {
          const existOrg = this.resData.filter((item) => {
            return dep.id.replace('G', '') === item.id
          })
          if (existOrg.length === 0) {
            this.resData.splice(0, 0, {
              id: dep.id.replace('G', ''),
              name: dep.name + '(组织)',
              type: 'GROUP',
              access: [1],
              deny: [],
            })
          }
        })
      } else {
        let addRoles = []

        addRoles = this.$refs.globalRolesTable.getSelectedRows()
        if (this.$refs.localRolesTable) {
          addRoles = addRoles.concat(this.$refs.localRolesTable.getSelectedRows())
        }

        if (addRoles.length === 0) {
          message.error('请选择角色')
          return
        }
        addRoles.forEach((dep) => {
          const existOrg = this.resData.filter((item) => {
            return dep.code === item.id
          })
          if (existOrg.length === 0) {
            this.resData.splice(0, 0, {
              id: dep.code,
              name: dep.name + '(角色)',
              type: 'ROLE',
              access: [1],
              deny: [],
            })
          }
        })
      }
      this.participant.visible = false
      const curClickRowKey = this.resData.filter((item) => {
        return this.curClickRowKey === item.id
      })
      if (curClickRowKey.length === 0) {
        if (this.resData.length !== 0) {
          this.setRightsData(this.resData[0])
        } else {
          this.rightsData = []
        }
      }
    },

    tabsChange(key) {
      this.participant.curTab = key
      if (key === '1') {
        // this.$refs.mgrTab.init()
        // this.getHieraManager()
      } else if (key === '2') {
        this.onLoadTreeData().then(() => {
          this.updateKey++
        })
      }
    },
    rowClassName(record) {
      return record.id === this.curClickRowKey ? 'click-row' : ''
    },
    rowClick(record) {
      this.setRightsData(record)
    },
    processRes(resData) {
      let aclEntries = resData.acl.entries
      this.entriesInheriting = resData.acl.entriesInheriting
      const data = Object.keys(resData.roles).map((item) => {
        const access = []
        const deny = []
        let roleType
        aclEntries = aclEntries.filter((entry) => {
          if (entry.operator.identifier === item.toString()) {
            if (entry.granting === true) {
              access.push(entry.mask)
            } else if (entry.granting === false) {
              deny.push(entry.mask)
            }
            roleType = entry.operator.type
          } else {
            return true
          }
        })

        return {
          id: item,
          name: resData.roles[item],
          type: roleType,
          access,
          deny,
        }
      })
      if (data.length > 0) this.setRightsData(data[0])
      this.resData = data
      return {
        totalSize: data.length,
        data: data,
      }
    },
    processReq(req) {
      delete req.data.expressions
      delete req.data.columns
      req.params = { ...req.data, id: this.unid }
      req.method = 'get'
      return req
    },
    setRightsData(data) {
      this.curClickRowKey = data.id
      this.curRoleName = data.name
      if (data.dispRights) {
        this.rightsData = data.dispRights
        return
      }
      this.rightsData = [
        {
          id: '1',
          name: '读取',
          access: false,
          deny: false,
        },
        {
          id: '2',
          name: '写入',
          access: false,
          deny: false,
        },
        {
          id: '3',
          name: '新建',
          access: false,
          deny: false,
        },
        {
          id: '4',
          name: '删除',
          access: false,
          deny: false,
        },
        {
          id: '5',
          name: '管理',
          access: false,
          deny: false,
        },
      ]
      const rowIndex = {
        '1': 0,
        '2': 1,
        '4': 2,
        '8': 3,
        '16': 4,
      }

      data.access.forEach((item) => {
        this.rightsData[rowIndex[item.toString()]].access = true
      })
      data.deny.forEach((item) => {
        this.rightsData[rowIndex[item.toString()]].deny = true
      })
      data.dispRights = this.rightsData
    },
    save() {
      const params = []

      const rowIndex = {
        '0': 1,
        '1': 2,
        '2': 4,
        '3': 8,
        '4': 16,
      }

      this.resData.forEach((user) => {
        if (user.dispRights) {
          user.dispRights.forEach((row, index) => {
            const entry = {
              operator: {
                type: user.type,
                identifier: user.id,
              },
              mask: rowIndex[index.toString()],
            }

            if (row.access) {
              params.push({
                ...entry,
                granting: true,
              })
            }
            if (row.deny) {
              params.push({
                ...entry,
                granting: false,
              })
            }
          })
        } else {
          const entry = {
            operator: {
              type: user.type,
              identifier: user.id,
            },
          }
          user.access.forEach((mask) => {
            params.push({
              ...entry,
              mask,
              granting: true,
            })
          })
          user.deny.forEach((mask) => {
            params.push({
              ...entry,
              mask,
              granting: false,
            })
          })
        }
      })

      this.loadingMsg = message.loading({
        key: this.msgKey,
        content: '处理中...',
        duration: 0,
      })
      return new Promise((resolve) => {
        NavService.savePermission({
          params: {
            ids: this.unid,
            entriesInheriting: this.entriesInheriting,
          },
          data: params,
        })
          .then((res) => {
            if (res.status === 200) {
              message.success('保存成功')
              resolve(true)
            } else {
              message.error(res.data?.message || '保存失败')
            }
          })
          .catch(() => message.error('保存失败'))
          .finally(() => {
            this.loadingMsg?.()
          })
      })
    },
    onSelectChange() {},
    getDefaultValue() {
      const resData = this.menuPermission

      let aclEntries = resData.acl.entries
      this.entriesInheriting = resData.acl.entriesInheriting
      const data = Object.keys(resData.roles).map((item) => {
        const access = []
        const deny = []
        let roleType
        aclEntries = aclEntries.filter((entry) => {
          if (entry.operator.identifier === item.toString()) {
            if (entry.granting === true) {
              access.push(entry.mask)
            } else if (entry.granting === false) {
              deny.push(entry.mask)
            }
            roleType = entry.operator.type
          } else {
            return true
          }
        })

        return {
          id: item,
          name: resData.roles[item],
          type: roleType,
          access,
          deny,
        }
      })
      if (data.length > 0) this.setRightsData(data[0])
      this.resData = data
    },
    onLoadTreeData(treeNode) {
      return new Promise((resolve) => {
        if (treeNode) {
          if (treeNode.dataRef.children) {
            resolve()
            return
          }
          NavService.participant
            .getTreeChild({
              parent: 'G' + treeNode.dataRef.key.substr(treeNode.dataRef.key.indexOf('G') + 1),
            })
            .then((deps) => {
              treeNode.dataRef.children = this.parseTreeData(deps.data)
              this.participant.depTree.treeData = [...this.participant.depTree.treeData]

              resolve()
            })
        } else {
          NavService.participant.getTreeRoot().then((deps) => {
            this.participant.depTree.treeData = this.parseTreeData(deps.data).map((item) => {
              return { ...item }
            })

            this.participant.depTree.defaultExpandedKeys = [
              this.participant.depTree.treeData[0].key,
            ]

            resolve()
          })
        }
      })
    },
    parseTreeData(deps) {
      return deps.map((dep) => {
        return {
          key: dep.id,
          title: dep?.props?.hierarchical === 'true' ? dep.text + '(已开启分级)' : dep.text,
          name: dep.text,
          isLeaf: dep.leaf,
          scopedSlots: {
            title: 'title',
          },
        }
      })
    },
  },
}
</script>

<style module lang="scss">
@use '@/common/design' as *;

.wrap {
  .icon-check-switch {
    display: block;
    width: 100%;
    height: 100%;
  }
  :global(.click-row) {
    background: #e6f7ff;
  }
  .rights-data {
    margin-top: 8px;
  }
}
</style>
