<template>
  <div class="import-container">
    <el-button
      type="text"
      size="mini"
      class="import-btn"
      @click="dialogVisible = true"
    >
      <ht-icon name="import" />
      子表导入
    </el-button>
    <el-button
      type="text"
      size="mini"
      class="download-btn"
      @click="exportFormSub"
    >
      <ht-icon name="download" />
      下载模板
    </el-button>
    <el-dialog
      :visible.sync="dialogVisible"
      width="600px"
      title="导入子表数据"
      append-to-body
      :close-on-click-modal="false"
      lock-scroll
    >
      <el-form
        v-form="{ inputsDisplay: 'block' }"
        label-width="100px"
        label-position="left"
      >
        <el-form-item label="导入文件：">
          <input
            ref="selectFile"
            type="file"
            accept="application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
            @change="fileChange"
            :disabled="importLoading"
          />
        </el-form-item>
        <el-form-item label="导入模式：">
          <ht-radio
            v-model="mode"
            :options="modeOptions"
            :props="{ key: 'mode', value: 'desc' }"
          ></ht-radio>
        </el-form-item>
        <el-tag
          v-if="importRows && importRows.length > 0"
          type="warning"
          class="read-success__label"
        >
          已经读取到
          <b>{{ importRows.length }}</b>
          条数据，
          <a @click="showRowData = !showRowData">点击查看详情</a>
          。
        </el-tag>
        <pre v-if="showRowData" class="import-rows__pre">{{ importRows }}</pre>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button
          size="small"
          type="primary"
          :loading="importLoading"
          @click="dialogConfirm"
          class="loading-btn"
        >
          {{ importLoading ? '正在处理...' : '确定' }}
        </el-button>
        <el-button
          size="small"
          :disabled="importLoading"
          @click="dialogVisible = false"
        >
          取消
        </el-button>
      </span>
    </el-dialog>
  </div>
</template>
<script>
  import SubPagination from '@/services/SubPagination.js'
  import utils from '@/utils.js'
  import { decode } from '@/util/base64.js'
  const { saveAs } = require('file-saver')

  export default {
    name: 'HtSubImportDialog',
    props: {
      rows: Array,
      subDesc: {
        type: String,
        default: '子表模板',
      },
      dataSubname: {
        type: String,
        required: true,
      },
      maxRow: {
        type: String,
        default: null,
      },
      mergeExpression: {
        type: String,
        default: null,
      },
      dataColumns: {
        type: String,
        required: true,
      },
    },
    data() {
      return {
        dialogVisible: false,
        importRows: null,
        showRowData: false,
        mergeFunc: null,
        mode: 'append',
        modeOptions: [
          { mode: 'append', desc: '追加导入' },
          { mode: 'override', desc: '覆盖导入' },
          { mode: 'merge', desc: '合并导入', disabled: true },
        ],
        importLoading: false,
      }
    },
    computed: {
      columns: function () {
        return eval(decode(this.dataColumns))
      },
    },
    watch: {
      dialogVisible: {
        handler: function (newVal) {
          // 清空附件
          if (!newVal && this.$refs.selectFile) {
            this.$refs.selectFile.value = ''
            this.importRows = null
            this.showRowData = false
            this.importLoading = false
          }
        },
        immediate: true,
      },
      mergeExpression: {
        handler: function (newVal) {
          if (newVal) {
            // 如果有导入合并的代码，则允许选择合并导入模式
            this.$set(this.modeOptions[2], 'disabled', false)
            // 并设置默认为 合并导入
            this.mode = 'merge'
            // 解码合并的代码
            const funcExp = decode(newVal)
            this.mergeFunc = eval(`(${funcExp})`)
          }
        },
        immediate: true,
      },
    },
    created() {
      if (!this.$XLSX) {
        console.warn('要使用子表导入/导出功能需要安装XLSX插件')
      }
    },
    mounted() {
      const pInst = utils.getOnlineFormInstance(this)
      if (!SubPagination._map.has(this.dataSubname)) {
        SubPagination.set(this.dataSubname, {
          rows: this.rows || [],
        })
      }
      const instKey = SubPagination._vueComponentKey(this.dataSubname)
      if (
        (!SubPagination._map.has(instKey) && pInst) ||
        (SubPagination._map.get(instKey) &&
          SubPagination._map.get(instKey).$el &&
          !SubPagination._map.get(instKey).$el.__vue__)
      ) {
        SubPagination._map.set(instKey, pInst)
      }
    },
    destroyed() {
      SubPagination.clear(this.dataSubname)
    },
    methods: {
      exportFormSub() {
        let subDesc = this.subDesc || '子表模板'
        let columns = this.columns.filter((item) => {
          return !(
            item.ctrlType &&
            (item.ctrlType === 'sunDiv' || item.ctrlType === 'suntable')
          )
        })
        this.$requestConfig
          .downloadSubtableTemplate(subDesc, columns)
          .then(({ data }) => {
            const blob = new Blob([data])
            saveAs(blob, `${subDesc}.xls`)
          })
          .catch((err) => {
            this.$message.error(`模板下载失败：${err}`)
          })
      },
      getNameByDesc(desc) {
        var name = ''
        this.columns.forEach((col) => {
          if (col.desc == desc) {
            name = col.name
          }
        })
        return name
      },
      changeRowKey(rows) {
        var importRows = []
        rows.forEach((row) => {
          var importRow = {}
          for (let key in row) {
            importRow[this.getNameByDesc(key)] = row[key]
          }
          importRows.push(importRow)
        })
        return importRows
      },
      dialogConfirm() {
        if (this.importLoading) return
        if (!this.importRows || this.importRows.length === 0) {
          this.$message.error('请选择要导入的文件')
          return
        }
        this.importLoading = true
        setTimeout(async () => {
          try {
            let maxRowInt = 0
            if (this.maxRow) {
              maxRowInt = parseInt(this.maxRow) || 0
              if (this.mode === 'override') {
                let count = this.importRows.length
                if (count > maxRowInt && maxRowInt !== 0) {
                  this.$message.error(`子表数据已超过最大行数【${maxRowInt}】`)
                  this.importLoading = false
                  return
                }
              } else if (this.mode === 'append') {
                const formInstance = utils.getOnlineFormInstance(
                  this.$parent.$parent
                )
                if (!formInstance || !formInstance.data) {
                  this.$message.error('未获取到表单数据，无法完成导入。')
                  this.importLoading = false
                  return
                }
                let boData = formInstance.data
                let pathArr = this.dataSubname.split('.')
                let subInitData = boData[pathArr[1]][pathArr[2]] || []
                let num = this.importRows.length + subInitData.length
                if (num > maxRowInt && maxRowInt !== 0) {
                  this.$message.error(`子表数据已超过最大行数【${maxRowInt}】`)
                  this.importLoading = false
                  return
                }
              } else if (this.mode == 'merge') {
                const formInstance = utils.getOnlineFormInstance(
                  this.$parent.$parent
                )
                if (!formInstance || !formInstance.data) {
                  this.$message.error('未获取到表单数据，无法完成导入。')
                }
                this.importLoading = false
              }
            }
            await SubPagination.importData(
              this.dataSubname,
              this.importRows,
              this.mode,
              this.mergeFunc
            )
            this.$message.success('导入成功！')
            this.dialogVisible = false
          } catch (err) {
            this.$message.error(`数据导入失败：${err}`)
          } finally {
            this.importLoading = false
          }
        }, 20)
      },
      fileChange(m) {
        if (!m || !m.target || !m.target.files || m.target.files.length !== 1) {
          return
        }
        this.importRows = []
        this.readWorkbookFromLocalFile(m.target.files[0], (rows) => {
          this.importRows = this.changeRowKey(rows)
        })
      },
      // 读取本地excel文件
      readWorkbookFromLocalFile(file, callback) {
        const reader = new FileReader()
        reader.onload = (e) => {
          const data = e.target.result
          let workbook = null
          try {
            // 读取Excel内容
            workbook = this.$XLSX.read(data, { type: 'binary' })
          } catch (err) {
            this.$message.error('所选文件不是有效的Excel文件.')
            this.importRows = null
            return
          }
          const sheetNames = workbook.SheetNames,
            // 只读取第一个sheet的数据
            worksheet = workbook.Sheets[sheetNames[0]]

          if (worksheet['!merges'] && worksheet['!merges'].length > 0) {
            const merge = worksheet['!merges'][0],
              rowNum = Number(merge['e']['r'])
            // 合并单元格时会导致转换出来的JSON数据格式错乱
            this.$message.error(
              `Excel中不能有合并的单元格，请检查第${rowNum + 1}行数据。`
            )
            this.importRows = null
            return
          }
          // 放在数字精度问题 以字符串形式读取
          const json = this.$XLSX.utils.sheet_to_json(worksheet, { raw: false })
          if (!json || json.constructor != Array) {
            this.$message.error('读取的数据格式错误。')
            this.importRows = null
            return
          }
          if (callback) callback(json)
        }
        reader.readAsBinaryString(file)
      },
    },
  }
</script>
<style lang="scss" scoped>
  .import-container {
    margin: 0 10px;
    .import-btn,
    .download-btn {
      font-size: 14px;
      padding-right: 14px;
    }
  }
  .read-success__label {
    display: block;
    font-size: 13px;
  }
  .read-success__label a {
    color: $base-color-blue;
    cursor: pointer;
  }
  .read-success__label b {
    color: red;
  }
  .import-rows__pre {
    margin-top: 20px;
    max-height: 270px;
    overflow-y: scroll;
  }
  ::v-deep .loading-btn {
    pointer-events: auto !important;
  }
  ::v-deep .el-button.is-loading {
    color: #fff !important;
    background-color: #409eff !important;
    pointer-events: none !important;
    .el-button__loading {
      display: inline-block !important;
    }
  }
</style>
