<template>
  <a-card>
    <div :class="$style.action">
      <a-input-search @search="onSearch" />
      <span v-if="!module && !appNodeId">
        <a-button type="primary" @click="addNode">新建</a-button>
        <a-button v-if="!appId" @click="importVisible = true">导入</a-button>
        <a-button v-if="!appId" :disabled="!selectedRows.length" @click="exportTree">导出</a-button>
        <a-button :disabled="!selectedRows.length" @click="delNode">删除</a-button>
      </span>
    </div>
    <a-table
      :key="key"
      :columns="columns"
      :data-source="searchData || treeData"
      :expanded-row-keys.sync="expandedRowKeys"
      :replace-fields="replaceFields"
      row-key="id"
      :row-selection="rowSelection"
      :pagination="false"
      @expand="expand"
    >
      <a
        v-if="!module && !appNodeId"
        slot="name"
        slot-scope="text, record"
        @click="editNode(record)"
        >{{ text }}</a
      >
      <span v-else>{{ text }}</span>
    </a-table>
    <a-modal v-model="formVisible" title="数据字典" destroy-on-close @ok="handleOk">
      <sd-form ref="form" :init-values="pageFormData">
        <template>
          <sd-form-item name="appId" hidden :input-props="{ defaultValue: appId }"></sd-form-item>
          <sd-form-item name="id" hidden />
          <sd-form-item name="parentCode" hidden :input-props="{ defaultValue: -1 }">
          </sd-form-item>
          <a-form-item label="上级分类">
            <sd-tree-picker
              v-model="parentCat"
              single
              :load-tree-data="loadTreeData"
              @change="parentCatChange"
            ></sd-tree-picker>
          </a-form-item>
          <sd-form-item name="categoryName" />
          <sd-form-item name="categoryCode" />
          <sd-form-item name="sortNumber" />
        </template>
      </sd-form>
    </a-modal>
    <a-modal v-model="importVisible" title="导入树形字典" :footer="null" :width="700">
      <a-upload-dragger :file-list="[]" :custom-request="(file) => uploadExcel(file)">
        <p class="ant-upload-drag-icon">
          <a-icon type="inbox" />
        </p>
        <p class="ant-upload-text">
          点击或将文件拖拽到这里上传
        </p>
      </a-upload-dragger>
    </a-modal>
  </a-card>
</template>

<script>
import qs from 'qs'
import axios from '@/common/services/axios-instance'
import { Modal, Message } from 'ant-design-vue'
import download from '@/common/services/download'
import components from './_import-components/sd-treedata-dictionary-import'
const columns = [
  {
    title: '名称',
    dataIndex: 'name',
    key: 'name',
    scopedSlots: { customRender: 'name' },
  },
  {
    title: '编码',
    dataIndex: 'code',
    key: 'code',
  },
]
const handleTreeData = (arr, picker) => {
  return arr.map((item) => {
    item.isLeaf = item.leaf
    if (!item.leaf && !picker) item.children = []
    return item
  })
}
const searchParentNode = (arr, parentCode) => {
  let node = {}
  arr.forEach((a) => {
    if (a.id === parentCode) {
      node = a
    } else if (a.children) node = { ...searchParentNode(a.children, parentCode), ...node }
  })
  return node
}
export default {
  name: 'SdTreedataDictionary',
  metaInfo: {
    title: '树形字典',
  },
  components,
  props: {
    appId: {
      type: String,
      default: '',
    },
    module: {
      type: Boolean,
      default: false,
    },
    appNodeId: {
      type: String,
      default: undefined,
    },
  },
  data() {
    return {
      columns,
      treeData: [],
      expandedRowKeys: [],
      searchData: null,
      pageFlowId: '',
      importVisible: false,
      pageFormData: [],
      selectedRows: [],
      formVisible: false,
      disabledKeys: [],
      exporting: false,
      replaceFields: {
        key: 'id',
        title: 'name',
      },
      key: 0,
      parentCat: [],
      searchVal: '',
    }
  },
  computed: {
    rowSelection() {
      return {
        selectedRowKeys: this.selectedRows?.map((row) => row.id) || [],
        onChange: (selectedRowKeys, selectedRows) => {
          this.selectChange(selectedRowKeys, selectedRows)
        },
      }
    },
  },
  created() {
    this.getTreeData()
  },
  methods: {
    uploadExcel(file) {
      const formData = new FormData()
      formData.append('file', file.file)
      axios
        .post('api/framework/v1/onl-treemodule/excel-import', formData, {
          headers: {
            'Content-Type': 'multipart/form-data',
          },
        })
        .then((res) => {
          Message.success('导入成功')
        })
        .catch((err) => {
          Message.error(err.response?.data?.errors || '导入失败')
        })
        .finally(() => {
          this.importVisible = false
          this.getTreeData()
        })
    },
    exportTree() {
      if (this.selectedRows.find((row) => row.parentCode !== -1)) {
        Message.warn('导出时只能选择根节点节点，请重新选择！')
        return
      }
      const ids = this.selectedRows.map((row) => row.props?.beanId).join()
      const url = `api/framework/v1/onl-treemodule/excel-export?ids=${ids}`
      const fname = '树形字典.xls'
      download(url, fname)
      this.selectedRows = []
    },
    onSearch(value) {
      this.searchVal = value
      const expressions = [
        {
          dataType: 'str',
          name: 'categoryName',
          op: 'like',
          stringValue: `%${this.searchVal}%`,
        },
      ]
      if (this.appId) {
        expressions.push({
          dataType: 'str',
          name: 'appId',
          op: 'eq',
          stringValue: this.appId,
        })
      } else {
        expressions.push({
          dataType: 'str',
          name: 'appId',
          op: 'is_null',
        })
      }
      if (value) {
        const params = {
          columns: 'categoryName,categoryCode,parentCode',
          expressions,
          formId: 'weOnlTreeModule',
          maxResults: -1,
          startPosition: 0,
        }
        axios.post('api/framework/v1/page/businessList', params).then((res) => {
          if (res.data.data) {
            this.searchData = res.data.data.map((item) => {
              return {
                id: item.id,
                code: item.categoryCode,
                name: item.categoryName,
                parentCode: item.parentCode,
                props: {
                  beanId: item.id,
                },
              }
            })
          }
        })
      } else this.searchData = null
    },
    parentCatChange(parentCat) {
      this.$refs.form.setFieldValue('parentCode', parentCat.length ? parentCat[0].id : -1)
    },
    loadTreeData(parentCatId) {
      const fun = parentCatId ? this.getChildrenNode(parentCatId, true) : this.getRootNode(true)
      return fun.then((res) => {
        return res.filter((r) => !this.disabledKeys.includes(r.id))
      })
    },
    getRootNode(picker) {
      let params = { appId: this.appId, appNodeId: this.appNodeId }
      params = qs.stringify(params, { filter: (prefix, value) => value || undefined })
      return axios
        .get(
          `api/framework/v1/onl-treemodule/categories/topCategoryList${params ? '?' + params : ''}`
        )
        .then((res) => {
          return handleTreeData(res.data, picker)
        })
    },
    getTreeData() {
      this.searchData = null
      this.searchVal = ''
      this.getRootNode().then((res) => {
        if (res)
          this.treeData = res.map((r) => {
            r.parentCode = -1
            return r
          })
      })
    },
    expand(expanded, record) {
      if (expanded) {
        this.refreshNode(record)
      } else {
        this.expandedRowKeys = this.expandedRowKeys.filter((key) => key !== record.id)
      }
    },
    getChildrenNode(id, picker) {
      return axios
        .get(
          `api/framework/v1/onl-treemodule/categories/categoryTree?parentCode=${id}${
            this.appNodeId ? '&appNodeId=' + this.appNodeId : ''
          }`
        )
        .then((res) => {
          return handleTreeData(res.data, picker)
        })
    },
    refreshNode(record) {
      this.getChildrenNode(record.id).then((res) => {
        if (res.length) {
          record.children = res.map((r) => {
            r.parentCode = record.id
            return r
          })
          record.isLeaf = false
          this.expandedRowKeys.push(record.id)
          this.expandedRowKeys = this.expandedRowKeys.filter(
            (key) => res.findIndex((r) => r.id === key) === -1
          )
        } else {
          record.children = null
          res.isLeaf = true
          this.expandedRowKeys = this.expandedRowKeys.filter((key) => key !== record.id)
        }
        const replaceNode = (arr) => {
          arr.forEach((item, index) => {
            if (item.id === record.id) {
              arr[index] = record
            }
            if (item.children) replaceNode(item.children)
          })
        }
        replaceNode(this.treeData)
        this.key++
      })
    },
    addNode() {
      this.disabledKeys = []
      this.parentCat = []
      this.getDetail()
    },
    getDetail(id) {
      axios
        .get(
          `api/xcoa-mobile/v1/page/wp/base/onltreemodule/weOnlTreeModule${id ? '?id=' + id : ''}`
        )
        .then((res) => {
          this.pageFlowId = res.data.attrs?.pageflowId
          this.pageFormData = res.data.pageFormData.pageFieldInfos
          this.formVisible = true
          this.$nextTick(() => {
            this.parentCatChange(this.parentCat)
          })
        })
    },
    editNode(record) {
      this.disabledKeys = [record.id]
      const parentCat = searchParentNode(this.treeData, record.parentCode)
      this.parentCat = parentCat.id ? [parentCat] : []
      this.getDetail(record.props?.beanId)
    },
    handleOk() {
      const parentCode = this.$refs.form.getFieldValue('parentCode')
      const nodeId = this.$refs.form.getFieldValue('id')
      const params = {
        eventId: 'save',
        inputs: this.$refs.form.getBackendValues(),
        pageFlowId: this.pageFlowId,
        pagePath: '/base/onltreemodule/weOnlTreeModule',
      }
      axios
        .post('api/framework/v1/page/handleData', params)
        .then((res) => {
          if (res.data) {
            if (this.searchData) {
              this.onSearch(this.searchVal)
            } else {
              const record = searchParentNode(this.treeData, parentCode)
              this.delOldNode(this.treeData, nodeId)
              if (parentCode !== -1 && record.id) {
                this.refreshNode(record)
              } else {
                this.getTreeData()
                this.expandedRowKeys = []
              }
            }

            this.formVisible = false
          }
        })
        .catch((err) => {
          Message.error(err.response?.data?.message || '保存失败')
        })
    },
    delOldNode(treeData, targetId) {
      for (let i = 0; i < treeData.length; i++) {
        const node = treeData[i]
        if (node.id === targetId) treeData.splice(i, 1)
        else if (node.children) this.delOldNode(node.children, targetId)
      }
    },
    selectChange(selectedRowKeys, selectedRows) {
      this.selectedRows = selectedRows
    },
    delNode() {
      const ids = this.selectedRows.map((row) => row.props?.beanId).toString()
      Modal.confirm({
        content: '确认删除该项及其所有子项吗?',
        onOk: () => {
          axios.delete(`api/framework/v1/page/weOnlTreeModule?ids=${ids}`).then((res) => {
            if (this.searchData) this.onSearch(this.searchVal)
            else {
              this.selectedRows.forEach((row) => {
                const parentCode = row.parentCode
                if (parentCode === -1) {
                  this.treeData = this.treeData.filter((t) => t.id !== row.id)
                } else {
                  const parentNode = searchParentNode(this.treeData, row.parentCode)
                  this.refreshNode(parentNode)
                }
              })
            }
          })
        },
      })
    },
  },
}
</script>

<style module lang="scss">
@use '@/common/design' as *;
.action {
  position: relative;
  z-index: 100;
  float: right;
  :global .ant-btn {
    margin: 0 0 10px 10px;
  }
  :global .ant-input-search {
    width: auto;
  }
}
</style>
