AppUploadDialog.vue 7.96 KB
<template>
  <el-dialog
    title="导入应用"
    :visible.sync="dialogVisible"
    width="40%"
    top="30vh"
    :close-on-click-modal="false"
  >
    <el-form v-if="dialogVisible">
      <ht-form-item label="上传">
        <el-upload
          style="display: inline-block; width: 100%"
          :action="uploadUrl"
          :on-success="handleUploadResult"
          :on-error="handleUploadResult"
          :headers="uploadHeaders"
          :on-exceed="onExceed"
          multiple
          :on-change="onChange"
          accept=".zip"
          :limit="10"
          :auto-upload="false"
          :http-request="handleImport"
          :file-list="fileList"
          ref="upload"
        >
          <el-button slot="trigger" size="small" icon="el-icon-upload"
            >选择应用</el-button
          >
          <el-button
            v-if="fileList.length > 0"
            style="margin-left: 5px"
            size="small"
            icon="el-icon-delete"
            @click="clearFileList"
            >清空</el-button
          >
        </el-upload></ht-form-item
      >
      <ht-form-item label="分类">
        <tree-select
          style="max-width: 456px"
          :appendToBody="true"
          v-model="menuId"
          :normalizer="normalizer"
          :multiple="false"
          :options="appTypes"
          noOptionsText=" "
          noChildrenText=" "
          z-index="9999"
          placeholder="请选择父节点"
          :clearable="false"
          @select="handleSelectChange"
          class="tree-select-radio"
        />
      </ht-form-item>
    </el-form>
    <span slot="footer" class="dialog-footer">
      <el-button @click="dialogVisible = false" :loading="fullscreenLoading"
        >取 消</el-button
      >
      <el-button
        type="primary"
        @click="uploadSubmit"
        element-loading-text="导入中..."
        :loading="fullscreenLoading"
        >确 定</el-button
      >
    </span>

    <app-import-check-dialog
      ref="appImportCheckDialog"
      @confirm="handleConfirm"
    />
  </el-dialog>
</template>

<script>
import {mapState} from 'vuex'
import _ from 'lodash'
import utils from '@/hotent-ui-util'
import request from '@/request'
const TreeSelect = () => import('@riophae/vue-treeselect')
import {mapMutations} from 'vuex'
import AppImportCheckDialog from './AppImportCheckDialog.vue'
export default {
  name: 'AppUploadDialog',
  components: {
    AppImportCheckDialog,
    TreeSelect,
  },
  data() {
    return {
      dialogVisible: false,
      menuId: null,
      menu: {},
      fullscreenLoading: false,
      fileList: [],
      checkFailList: [],
    }
  },

  computed: mapState({
    uploadUrl: function () {
      return window.context.portal + '/portal/sysApp/v1/import'
    },
    importCheckUrl: function () {
      return window.context.portal + '/portal/sysApp/v1/importCheck'
    },
    uploadHeaders: function (mapState) {
      return {Authorization: 'Bearer ' + mapState.login.currentUser.token}
    },
    appTypes: function (state) {
      let stateAppTypes = _.cloneDeep(state.menu.appTypes)
      utils.nestForEach(stateAppTypes, 'children', (item) => {
        if (!item.children || item.children.length === 0) {
          delete item.children
        }
      })
      return stateAppTypes || []
    },
  }),
  mounted() {
    this.$store.dispatch('menu/getAppTypes')
  },
  methods: {
    ...mapMutations({
      setDialogVisible: 'user/setDialogVisible',
      setFileList: 'user/setFileList',
      addFiles: 'user/addFiles',
    }),
    open() {
      this.dialogVisible = true
      this.fileList = []
    },
    handleUploadResult(data) {
      if (data.state) {
        if (data.message.includes('已存在故跳过')) {
          this.$message({
            type: 'warning',
            message: data.message,
            showClose: true,
            duration: 5000,
            dangerouslyUseHTMLString: true,
          })
        } else {
          this.$message({type: 'success', message: '导入成功'})
        }
      }
      this.dialogVisible = false
      this.fullscreenLoading = false
      this.$emit('refresh')
    },
    onChange(file, fileList) {
      if (!file.name.endsWith('.zip')) {
        this.debounceMessage()
        for (let i = 0; i < fileList.length; i++) {
          if (fileList[i].name === file.name) {
            this.fileList.splice(i, 1)
          }
        }
        return false
      }
      this.fileList = fileList
    },
    debounceMessage: _.debounce(function () {
      this.$message.warning('只能导入zip文件!')
    }, 500),
    onExceed(file) {
      this.$message.warning('最多只能选择10个zip文件!')
    },
    normalizer(node) {
      return {
        id: node.id,
        label: node.name,
        children: node.children,
        isDefaultExpanded: false,
      }
    },
    async uploadSubmit() {
      if (
        !this.$refs.upload.uploadFiles ||
        this.$refs.upload.uploadFiles.length === 0
      ) {
        this.$message.warning('请选择要导入的应用!')
        return false
      }
      if (!this.menuId) {
        this.$message.warning('请选择分类!')
        return
      }
      this.fullscreenLoading = true
      this.fileList.forEach((item) => {
        if (item.size) {
          item.sizeChange = this.filterSize(item.size)
        }
      })
      let list = []
      let error = false

      for (let i = 0; i < this.fileList.length; i++) {
        let item = this.fileList[i]
        let formData = new FormData()
        formData.append('file', item.raw)
        formData.append('menu', JSON.stringify(this.menu))
        try {
          let response = await request.post(this.importCheckUrl, formData)
          if (!response.data.message || response.data.message === '验证成功') {
            list.push({
              file: item,
              menu: this.menu,
            })
          } else {
            this.checkFailList.push({
              file: item,
              menu: this.menu,
              response: response.data,
            })
          }
        } catch (e) {
          error = true
        } finally {
          this.fullscreenLoading = false
        }
      }
      if (error) {
        return
      }
      this.showCheckFailConfirm()
      this.addFiles(list)
      this.dialogVisible = false
    },
    showCheckFailConfirm() {
      if (this.checkFailList.length > 0) {
        let fail = this.checkFailList.pop()
        this.$refs.appImportCheckDialog.open(fail.response.message, fail)
      }
    },
    handleConfirm(type, fail) {
      if (type === 'cover') {
        fail.isCover = true
        this.addFiles([fail])
      } else {
        this.addFiles([fail])
      }
      this.showCheckFailConfirm()
    },
    pow1024(num) {
      return Math.pow(1024, num)
    },
    filterSize(size) {
      if (!size) return '0KB'
      return size < 1024
        ? size + ' B'
        : size < this.pow1024(2)
        ? (size / 1024).toFixed(2) + ' KB'
        : size < this.pow1024(3)
        ? (size / this.pow1024(2)).toFixed(2) + ' MB'
        : size < this.pow1024(4)
        ? (size / this.pow1024(3)).toFixed(2) + ' GB'
        : (size / this.pow1024(4)).toFixed(2) + ' TB'
    },
    handleImport(param) {
      let formData = new FormData()
      formData.append('file', param.file)
      formData.append('menu', JSON.stringify(this.menu))

      request
        .post(param.action, formData)
        .then((resp) => {
          if (resp.data.state) {
            param.onSuccess(resp.data)
          } else {
            param.onError(resp.data)
          }
        })
        .catch((error) => {
          param.onError(error)
        })
    },
    handleSelectChange(node) {
      this.menu = {
        menuId: node.id,
        menuAlias: node.alias,
        menuName: node.name,
      }
    },
    clearFileList() {
      this.fileList = []
    },
  },
}
</script>

<style lang="scss" scoped>
::v-deep .tree-select-radio .vue-treeselect__control {
  border-radius: 2px;
  height: 32px;
}
::v-deep .el-upload-list__item {
  max-width: 456px;
}
</style>