<template>
  <div :class="$style.wrap">
    <div :class="$style.lefttree">
      <sd-nav-tree ref="tree" :hiera-info="hieraInfo" :root-data="root" @treeSelect="treeSelect" />
    </div>
    <div v-if="parent !== null" :class="$style.rightcontent">
      <a-card :class="$style['search-result']">
        <sd-data-table
          ref="dataTable"
          :data-url="listDataUrl"
          :actions="actions"
          :columns="columns"
          show-selection
          :search-fields="['text']"
          :max-inline-actions="4"
          :filter-expressions="customFilterExpressions"
          :process-req="processReq"
          :process-res="processRes"
          @rowClick="rowClick"
        >
          <template slot="randerEnabled" slot-scope="text, record">
            {{ record.enabled === true ? '启用' : '禁用' }}
          </template>
        </sd-data-table>
      </a-card>
    </div>
    <a-card v-else :class="$style.rightcontent" />
    <a-modal
      v-model="visible"
      :title="title"
      destroy-on-close
      v-bind="{ width: 800 }"
      :mask-closable="false"
      @ok="save"
      @cancel="$emit('closed')"
    >
      <sd-nav
        ref="detailForm"
        :unid="clickedRow"
        :cur-nav="clickedNav"
        :cur-parent="depParent"
        :hiera-info="hieraInfo"
      ></sd-nav>
    </a-modal>

    <!-- 导入 -->
    <a-modal
      title="导入"
      :visible="visibleImport"
      :width="650"
      destroy-on-close
      :confirm-loading="importConfirmLoading"
      :mask-closable="false"
      @ok="importConfirm"
      @cancel="visibleImport = false"
    >
      <sd-form ref="importForm" :init-values="importFormData">
        <template v-slot="{ model }">
          <sd-form-item name="rootId">
            <template>
              <sd-value-picker
                v-model="model.rootId"
                single
                option-value="key"
                option-label="title"
              >
                <template v-slot="scope">
                  <sd-picker-source-tree :load-tree-data="onLoadTreeData" v-bind="scope" />
                </template>
              </sd-value-picker>
            </template>
          </sd-form-item>
          <sd-form-item name="attachment">
            <a-upload-dragger
              name="file"
              :multiple="false"
              :custom-request="(file) => customRequest(file)"
              :file-list="fileList"
              @change="handleChange"
            >
              <p class="ant-upload-drag-icon">
                <a-icon type="inbox" />
              </p>
              <p class="ant-upload-text">
                点击或将文件拖拽到这里上传
              </p>
            </a-upload-dragger>
          </sd-form-item>
          <sd-form-item name="type"> </sd-form-item>
        </template>
      </sd-form>
    </a-modal>

    <a-modal
      v-model="hieraVisible"
      title="权限设置"
      destroy-on-close
      v-bind="{ width: 800 }"
      :mask-closable="false"
      @ok="
        () => {
          this.$refs.hieraForm.save().then((res) => {
            if (res) hieraVisible = false
          })
        }
      "
      @cancel="$emit('closed')"
    >
      <a-tabs default-active-key="1">
        <a-tab-pane key="1" tab="权限">
          <sd-nav-hiera
            ref="hieraForm"
            :cur-parent="parent"
            :unid="clickedRow"
            :hiera-info="hieraInfo"
            :menu-permission="menuPermission"
          ></sd-nav-hiera>
        </a-tab-pane>
        <a-tab-pane key="2" tab="所有者">
          <sd-nav-owner
            :cur-parent="parent"
            :hiera-info="hieraInfo"
            :unid="clickedRow"
            :menu-permission="menuPermission"
          />
        </a-tab-pane>
        <a-tab-pane key="3" tab="有效权限">
          <sd-nav-permission-query :unid="clickedRow" />
        </a-tab-pane>
      </a-tabs>
    </a-modal>
  </div>
</template>

<script>
import axios from '@/common/services/axios-instance'
import { Modal } from '@/common/one-ui'
import download from '@/common/services/download'
import TableActionTypes from '@/common/services/table-action-types'
import { message } from 'ant-design-vue'

import NavService from './nav-service'
import components from './_import-components/sd-nav-category-import'

export default {
  name: 'SdNavCategory',
  metaInfo: {
    title: '导航管理',
  },
  components,
  data() {
    return {
      title: '',
      hieraVisible: false,
      visibleImport: false,
      loadingMsg: null,
      importConfirmLoading: false,
      importFormData: [
        {
          name: 'rootId',
          dataType: 'String',
          caption: '上级菜单',
          readonly: false,
          required: true,
        },
        {
          name: 'type',
          dataType: 'selectlist',
          caption: '导入策略',
          readonly: false,
          required: false,
          attr: {
            defaultValue: '0',
            multiple: 'false',
            selectListItem: [
              {
                label: '跳过已存在的菜单',
                value: '0',
              },
              {
                label: '覆盖已存在的菜单',
                value: '1',
              },
              {
                label: '停止导入',
                value: '2',
              },
            ],
          },
        },
        {
          name: 'attachment',
          dataType: 'attachment',
          caption: '数据文件',
          readonly: false,
          required: true,
        },
      ],
      fileList: [],
      customFilterExpressions: this.parent
        ? [
            {
              dataType: 'str',
              name: 'parentId',
              op: 'eq',
              stringValue: this.parent.id,
            },
          ]
        : [],
      columns: [
        {
          title: 'ID',
          dataIndex: 'id',
          sdCandidate: true,
        },
        {
          title: '显示文字',
          dataIndex: 'text',
          sdClickable: true,
        },
        {
          title: '链接',
          dataIndex: 'url',
        },
        {
          title: '目标框架',
          dataIndex: 'target',
          sdCandidate: true,
        },
        {
          title: '序号',
          dataIndex: 'index',
          defaultSortOrder: 'asc',
        },
        {
          title: '状态',
          dataIndex: 'enabled',
          scopedSlots: {
            customRender: 'randerEnabled',
          },
        },
        {
          title: '图标',
          dataIndex: 'icon',
          sdCandidate: true,
        },
        {
          title: '提示文字',
          dataIndex: 'tooltip',
          sdCandidate: true,
        },
        {
          title: '徽标服务ID',
          dataIndex: 'appId',
          sdCandidate: true,
        },
      ],
      clickedNav: null,

      actions: [
        {
          label: '删除',
          id: 'delete',
          permission: null,
          type: TableActionTypes.batch,
          callback: () => {
            return this.delete(this.$refs.dataTable.getSelectedRowKeys())
          },
        },
        {
          label: '导出',
          id: 'export',
          permission: null,
          type: TableActionTypes.batch,
          callback: () => {
            return this.exportData(
              this.$refs.dataTable.getSelectedRowKeys(),
              this.$refs.dataTable.getSelectedRows()
            )
          },
        },
        {
          label: '导入',
          id: 'importData',
          permission: null,

          callback: () => {
            this.visibleImport = true
            this.importType = 'zip'

            this.importFormData[0].value = JSON.stringify([
              { key: this.parent.id, title: this.parent.text },
            ])

            this.fileList = []
          },
        },
        {
          label: '授权',
          id: 'setHiera',
          permission: null,
          type: TableActionTypes.inline,
          callback: (record) => {
            this.clickedRow = record.id
            NavService.getPermission({
              params: {
                id: this.clickedRow,
              },
            }).then((res) => {
              this.menuPermission = res.data
              this.hieraVisible = true
            })
          },
        },
        {
          label: '上移',
          id: 'moveUp',
          permission: null,
          type: TableActionTypes.inline,
          hidden: (record, rowIndex) => {
            return rowIndex === 0
          },
          callback: (record) => {
            this.moveUp(record.id)
          },
        },
        {
          label: '下移',
          id: 'moveDown',
          permission: null,
          type: TableActionTypes.inline,
          hidden: (record, rowIndex) => {
            const data = this.listData.datas ?? this.listData.data
            return rowIndex === data.length - 1
          },
          callback: (record) => {
            this.moveDown(record.id)
          },
        },
        {
          label: '复制',
          id: 'copy',
          permission: null,
          type: TableActionTypes.inline,
          callback: (record) => {
            this.sourceId = record.id
            this.operationType = 'copy'
          },
        },
        {
          label: '剪切',
          id: 'move',
          permission: null,
          type: TableActionTypes.inline,
          callback: (record) => {
            this.sourceId = record.id
            this.operationType = 'move'
          },
        },
        {
          label: '粘贴',
          id: 'paste',
          permission: null,
          type: TableActionTypes.inline,
          hidden: (record) => {
            // 不能粘贴到本身
            return this.sourceId === record.id
          },
          callback: (record) => {
            this.pasteNav(record)
          },
        },
        {
          label: '重新编号',
          id: 'reSort',
          permission: null,
          callback: () => {
            this.reSort()
          },
        },
        {
          label: '保存',
          id: 'saveSort',

          permission: null,
          callback: () => {
            this.saveSort()
          },
        },
        {
          label: '清缓存',
          id: 'clearCache',
          permission: null,
          callback: () => {
            this.clearCache()
          },
        },
        {
          label: '新建',
          id: 'new',
          permission: null,
          type: 'primary',
          callback: () => {
            this.title = '新建菜单'
            this.visible = true
            this.clickedRow = null
            this.depParent = this.parent
          },
        },
      ],
      searchFields: [
        {
          fieldId: 'name',
          fieldName: '名称',
          fieldType: 'string',
          dataType: 'string',
          search: true,
        },
        {
          fieldId: 'account',
          fieldName: '账号',
          fieldType: 'string',
          dataType: 'string',
          search: true,
        },
        {
          fieldId: 'status',
          fieldName: '账号状态',
          fieldType: 'number',
          dataType: 'number',
          attr: {
            selectListItem: [
              {
                value: '0',
                label: '未激活',
              },
              {
                value: '1',
                label: '正常',
              },
              { value: '2', label: '注销' },
              { value: '4', label: '账户已过期' },
              { value: '8', label: '密码已过期' },
              { value: '16', label: '已锁定' },
              { value: '32', label: '停用' },
              { value: '64', label: '禁止登录' },
            ],
          },
          search: true,
        },
      ],
      parent: null,
      depParent: null,
      root: null,
      searchValue: '',
      listDataUrl: `api/framework/v1/menu/list/submenu-items`,
      listData: {},
      rootReady: false,
      clickedRow: null,
      visible: false,
      hieraInfo: {},
      sourceId: null,
      operationType: '',
      menuPermission: null,
    }
  },
  computed: {
    expressions() {
      return this.parent
        ? [
            {
              dataType: 'str',
              name: 'parentId',
              op: 'eq',
              stringValue: this.parent.id,
            },
          ]
        : []
    },
  },
  created() {
    this.init()
  },
  methods: {
    customRequest(files, item) {
      if (files.file.size === 0) {
        message.warn(`不能上传大小为0的文件`)
        return
      }

      const formData = new FormData()
      formData.append('file', files.file)
      const url = 'api/framework/v1/tmp-file/upload'

      axios
        .post(url, formData, {
          headers: {
            'Content-Type': 'multipart/form-data',
          },
        })
        .then((res) => {
          if (res.status === 200) {
            // files.file.status = 'done'
            files.onSuccess(res.data, files)
          } else {
            message.warn(`上传失败`)
          }
        })
        .catch((e) => {
          throw e
        })
    },
    handleChange(info) {
      let fileList = [...info.fileList]

      // 1. Limit the number of uploaded files
      //    Only to show two recent uploaded files, and old ones will be replaced by the new
      fileList = fileList.slice(-1)

      // 2. read from response and show file link
      fileList = fileList.map((file) => {
        if (file.response) {
          // Component will show file.url as link
          file.url = file.response.url
          file.id = parseInt(file.response.id, 10)
        }
        return file
      })

      this.$refs.importForm.setFieldValue('attachment', fileList)
      this.fileList = fileList
    },
    importConfirm() {
      return new Promise((resolve) => {
        this.$refs.importForm.validateFields().then((success) => {
          if (success) {
            const values = this.$refs.importForm.getFieldsValue()
            let xhrReq = null

            xhrReq = NavService.importData({
              params: {
                parentId: values.rootId[0].key,
                conflictStrategy: values.type,
              },
              data: values.attachment[0].response,
            })
            this.loadingMsg = message.loading({
              key: this.msgKey,
              content: '导入中...',
              duration: 0,
            })
            xhrReq
              .then((res) => {
                if (res.status === 200) {
                  if (values.type === '2') {
                    if (res.data === '') {
                      message.success('导入成功')
                    } else {
                      message.error(res.data + ',停止导入')
                    }
                  } else {
                    if (res.data === '') {
                      message.success('导入成功')
                    } else {
                      message.success(res.data + ',导入成功')
                    }
                  }

                  this.$refs.dataTable.clearSelection(true)
                  this.$refs.dataTable.refresh()
                  this.$refs.tree.refresh()
                  this.visibleImport = false
                } else {
                  message.error(res.data?.message || '导入失败')
                }
              })
              .catch(() => message.error('导入失败'))
              .finally(() => {
                this.loadingMsg?.()
              })
          }
        })
      })
    },
    exportData(ids) {
      this.loadingMsg = message.loading({
        key: this.msgKey,
        content: '处理中...',
        duration: 0,
      })
      NavService.exportData({ ids: ids.join(',') })
        .then((res) => {
          if (res.status === 200) {
            return download(
              `api/framework/v1/tmp-file/download/${res.data.id}`,
              `${res.data.name}`,
              true
            )
          } else {
            message.error(res.data?.message || '处理失败')
          }
        })
        .catch(() => message.error('导入失败'))
        .finally(() => {
          this.loadingMsg?.()
        })
    },
    clearCache() {
      this.loadingMsg = message.loading({
        key: this.msgKey,
        content: '处理中...',
        duration: 0,
      })

      NavService.clearCache()
        .then((res) => {
          if (res.status === 200) {
            message.success('处理成功')
          } else {
            message.error(res.data?.message || '处理失败')
          }
        })
        .catch(() => message.error('处理失败'))
        .finally(() => {
          this.loadingMsg?.()
        })
    },
    moveUp(id) {
      const data = this.listData.datas ?? this.listData.data
      let curIndex = 0
      data.some((item, index) => {
        if (item.id === id) {
          curIndex = index
          return true
        }
      })
      if (curIndex !== 0) {
        const curRow = {
          ...data[curIndex],
          index: data[curIndex - 1].index,
        }
        data[curIndex] = {
          ...data[curIndex - 1],
          index: data[curIndex].index,
        }
        data[curIndex - 1] = curRow
      }
    },
    moveDown(id) {
      const data = this.listData.datas ?? this.listData.data
      let curIndex = data.length - 1
      data.some((item, index) => {
        if (item.id === id) {
          curIndex = index
          return true
        }
      })
      if (curIndex !== data.length - 1) {
        const curRow = {
          ...data[curIndex],
          index: data[curIndex + 1].index,
        }
        data[curIndex] = {
          ...data[curIndex + 1],
          index: data[curIndex].index,
        }
        data[curIndex + 1] = curRow
      }
    },
    reSort() {
      const data = this.listData.datas ?? this.listData.data
      data.forEach((item, index) => {
        item.index = index + 1
      })
    },
    saveSort() {
      this.loadingMsg = message.loading({
        key: this.msgKey,
        content: '处理中...',
        duration: 0,
      })
      const data = this.listData.datas ?? this.listData.data
      data.forEach((item, index) => {
        item.index = index + 1
      })
      NavService.reSort({ data })
        .then((res) => {
          if (res.status === 200) {
            message.success('处理成功')
            this.$refs.tree.refresh()
          } else {
            message.error(res.data?.message || '处理失败')
          }
        })
        .catch(() => message.error('处理失败'))
        .finally(() => {
          this.loadingMsg?.()
        })
    },
    processRes(resData) {
      this.listData = resData
      return resData
    },
    processReq(req) {
      if (req.data.expressions.length === 0) {
        if (this.parent) {
          req.data.parentId = this.parent.id
        }
      } else {
        if (req.data.expressions[0].name !== 'parentId') {
          // 搜索时传递该参数显示用户部门全路径
          req.data.searchAction = true
        }
        const exps = req.data.expressions.find((e) => e.dataType === 'exps')
        exps?.expressionsValue?.forEach((exp) => {
          req.data[exp.name] = exp.stringValue?.replace(/^%/, '').replace(/%$/, '')
        })
        if (this.parent) {
          req.data.parentId = this.parent.id
        }
      }

      req.data.productMode = false
      req.data.orderBy = 'index asc,id desc'
      delete req.data.expressions
      delete req.data.columns
      req.params = req.data
      req.method = 'get'

      return req
    },
    // 点击树
    treeSelect(info) {
      if (info.id === '-1') {
        return
      }
      this.parent = info
      this.customFilterExpressions = this.parent
        ? [
            {
              dataType: 'str',
              name: 'parentId',
              op: 'eq',
              stringValue: this.parent.id,
            },
          ]
        : []
      if (this.$refs.dataTable) this.$refs.dataTable.clearSelection(true)
    },
    rowClick(record) {
      this.title = '编辑菜单'
      this.clickedNav = record
      this.clickedRow = record.id.toString()
      this.visible = true
    },
    delete(keys) {
      return new Promise((resolve) => {
        Modal.confirm({
          title: '您确定删除这项内容吗？',
          content: '删除这条数据后，就无法恢复初始的状态。',
          okText: '删除',
          okType: 'danger',
          onOk: () => {
            NavService.deleteNav(keys).then((res) => {
              this.$refs.tree.refresh()
              this.$refs.dataTable.clearSelection(true)
              this.$refs.dataTable.refresh()
              resolve()
            })
          },
          onCancel: () => {
            resolve()
          },
        })
      })
    },
    search(value) {
      this.customFilterExpressions = value
    },

    save() {
      this.$refs.detailForm.save().then((success) => {
        if (success) {
          this.$refs.tree.refresh()
          this.$refs.dataTable.clearSelection(true)
          this.$refs.dataTable.refresh()
          this.visible = false
        }
      })
    },
    init() {
      NavService.getMenuHiera().then((res) => {
        this.hieraInfo = res.data
      })
    },
    onLoadTreeData(parentCatId) {
      return new Promise((resolve) => {
        if (parentCatId) {
          return NavService.getTreeChild({
            parentId: parentCatId,
          }).then((deps) => {
            resolve(this.parseTreeData(deps.data))
          })
        } else {
          const oNodes = [
            {
              key: '-1',
              title: '可管理机构菜单',
              isLeaf: false,
              backendAttr: {},
              showAction: false,
              scopedSlots: {
                title: 'root',
              },
            },
          ]
          return this.loadExpand(oNodes, 1).then((ids) => {
            this.treeData = oNodes
            this.defaultExpandedKeys = ids
            this.spinning = false
            resolve(oNodes)
          })
        }
      })
    },
    loadExpand(oNodes, level) {
      // 默认加载并展开对应层的树
      return new Promise((resolve) => {
        let ids = []
        Promise.all(
          oNodes.map((oNode) => {
            return NavService.getTreeChild({
              parentId: oNode.key,
            })
          })
        ).then((resAll) => {
          let childNodes = []
          resAll.forEach((res, index) => {
            oNodes[index].children = this.parseTreeData(res.data)
            ids = ids.concat(
              res.data.map((item) => {
                return item.id
              })
            )
            childNodes = childNodes.concat(oNodes[index].children)
          })
          if (level > 0) {
            this.loadExpand(childNodes, level - 1).then((childIds) => {
              resolve(ids.concat(childIds))
            })
          } else {
            resolve(ids)
          }
        })
      })
    },
    parseTreeData(deps) {
      return deps.map((dep) => {
        return {
          key: dep.id,
          title: dep.text,
          name: dep.text,
          isLeaf: dep.leaf,
          scopedSlots: {
            title: 'title',
          },
        }
      })
    },
    pasteNav(record) {
      if (this.sourceId === null) {
        message.warn('未选择粘贴菜单！')
        return
      }
      const sourceId = this.sourceId
      const targetId = record.id
      NavService.isChildNode(targetId, sourceId).then((isChildNode) => {
        if (isChildNode) {
          message.warn('不能粘贴到子集节点！')
          return
        }
        NavService.pasteNav(sourceId, targetId, this.operationType)
          .then((res) => {
            message.success('粘贴成功')
            this.$refs.tree.refresh()
            this.$refs.dataTable.clearSelection(true)
            this.$refs.dataTable.refresh()
          })
          .catch(() => {
            message.error('粘贴失败')
          })
      })
    },
  },
}
</script>

<style module lang="scss">
@use '@/common/design' as *;
.wrap {
  display: flex;
  height: 100%;

  .lefttree {
    width: 20%;
    min-width: 150px;
    // min-height: 100%;
    height: 100%;
    margin-right: $padding-lg;
    // overflow: auto;
    :global(.ant-card) {
      min-height: 100%;
    }
  }
  .rightcontent {
    width: calc(80% - #{$padding-lg});
    height: 100%;
    overflow-y: auto;
    // :global(.ant-card) {
    //   min-height: 100%;
    // }
  }
}
.no-action {
  :global(.ant-modal-footer) {
    display: none;
  }
}
</style>
