ImportForm.vue 8.92 KB
<template>
  <el-dialog title="批量导入" :close-on-click-modal="false" :visible.sync="visible" class="NCC-dialog NCC-dialog_center"
    lock-scroll width="1000px">
    <el-steps :active="active" align-center>
      <el-step title="上传文件"></el-step>
      <el-step title="数据预览"></el-step>
      <el-step title="导入数据"></el-step>
    </el-steps>
    <div class="import-main" v-show="active==1">
      <div class="upload">
        <div class="up_left">
          <img src="@/assets/images/upload.png">
        </div>
        <div class="up_right">
          <p class="title">上传填好的数据表</p>
          <p class="tip">文件后缀名必须是 xls 或 xlsx,文件大小不超过 500KB,最多支持导入 1000 条数据。
            <br/>关联产品列请填写产品编号(与模板下拉一致)。
            <br/>备件分类:按模板下拉的分类名称填写;备件情况:仅支持“有”或“无”。
          </p>
          <el-upload :action="define.comUrl+'/api/file/Uploader/imp'" :headers="{ Authorization: $store.getters.token}"
            :on-success="handleSuccess" :on-remove="handleRemove" :before-remove="beforeRemove"
            :on-change="handleChange" :file-list="fileList" accept=".xls,.xlsx" :before-upload="beforeUpload"
            class="upload-area">
            <el-button type="text">上传文件</el-button>
          </el-upload>
        </div>
      </div>
      <div class="upload">
        <div class="up_left">
          <img src="@/assets/images/import.png">
        </div>
        <div class="up_right">
          <p class="title">填写导入数据信息</p>
          <p class="tip">请按照数据模板的格式准备导入数据,模板中的表头名称不可更改,表头行不能删除</p>
          <el-button type="text" @click="templateDownload">下载模板</el-button>
        </div>
      </div>
    </div>
    <div class="import-main" v-show="active==2">
      <NCC-table v-loading="listLoading" :data="list">
        <el-table-column v-for="item in fileds" :prop="item.value" :key="item.value" :label="item.key" width="150">
          <template slot-scope="scope">
            <el-input v-model="scope.row[item.value]" />
          </template>
        </el-table-column>
        <el-table-column label="操作" fixed="right" width="50">
          <template slot-scope="scope">
            <el-button size="mini" type="text" class="NCC-table-delBtn" @click="handleDel(scope.$index)">删除</el-button>
          </template>
        </el-table-column>
      </NCC-table>
    </div>
    <div class="import-main" v-show="active==3">
      <div class="success" v-if="!result.resultType">
        <img src="@/assets/images/success.png" alt="">
        <p class="success-title">批量导入成功</p>
        <p class="success-tip">您已成功导入 {{ result.snum }} 条数据</p>
      </div>
      <div class="unsuccess" v-if="result.resultType">
        <el-alert title="错误提醒:导入失败数据展示" type="warning" show-icon :closable="false" />
        <div class="upload error-show">
          <div class="up_left">
            <img class="" src="@/assets/images/tip.png">
          </div>
          <div class="up_right">
            <p class="tip">正常数量条数:<el-link type="success" :underline="false">{{ result.snum }} 条</el-link></p>
            <p class="tip">异常数量条数:<el-link type="danger" :underline="false">{{ result.fnum }} 条</el-link></p>
          </div>
        </div>
        <p class="contips">以下为导入异常数据(含错误字段与错误信息)</p>
        <NCC-table :data="resultList" height="280px">
          <el-table-column v-for="item in fileds" :prop="item.value" :key="item.value" :label="item.key" width="100" />
          <el-table-column prop="_errorField" label="错误字段" width="100" />
          <el-table-column prop="_errorMessage" label="错误信息" min-width="160" show-overflow-tooltip />
        </NCC-table>
      </div>
    </div>
    <span slot="footer" class="dialog-footer">
      <el-button @click="cancle()" v-if="active == 1">取 消</el-button>
      <el-button @click="prev" v-if="active == 2">上一步</el-button>
      <el-button @click="next" type="primary" v-if="active < 3" :loading="btnLoading">下一步</el-button>
      <el-button @click="cancle(true)" type="primary" v-else>关 闭</el-button>
    </span>
  </el-dialog>
</template>

<script>
  import request from '@/utils/request'
  export default {
    data() {
      return {
        apiPrex: '/api/Extend/Bjxx',
        visible: false,
        btnLoading: false,
        listLoading: false,
        fileName: '',
        fileList: [],
        active: 1,
        fileds: [],
        list: [],
        resultList: [],
        result: { resultType: 0, snum: 0, fnum: 0 }
      }
    },
    methods: {
      prev() {
        if (this.active === 1) return
        this.active--
      },
      next() {
        if (this.active === 2) {
          if (!this.list.length) return this.$message({ message: '导入数据为空', type: 'warning' })
          this.btnLoading = true
          request({
            url: this.apiPrex + '/ImportData',
            method: 'post',
            data: { list: this.list }
          }).then(res => {
            this.result = res.data
            this.resultList = res.data.failResult || []
            this.btnLoading = false
            this.active++
          }).catch(() => { this.btnLoading = false })
        }
        if (this.active === 1) {
          if (!this.fileList.length || !this.fileName) return this.$message({ message: '请先上传文件', type: 'warning' })
          this.btnLoading = true
          request({
            url: this.apiPrex + '/ImportPreview',
            method: 'get',
            data: { fileName: this.fileName }
          }).then(res => {
            const lst = []
            const fileds = res.data.fileds || {}
            for (const item in fileds) lst.push({ key: item, value: fileds[item] })
            this.fileds = lst
            this.list = res.data.dataRow || []
            this.btnLoading = false
            this.active++
          }).catch(() => { this.btnLoading = false })
        }
      },
      cancle(isRefresh) {
        this.visible = false
        if (isRefresh) this.$emit('refresh')
      },
      init() {
        this.active = 1
        this.fileList = []
        this.fileName = ''
        this.visible = true
      },
      handleDel(index) {
        this.list.splice(index, 1)
      },
      templateDownload() {
        request({
          url: this.apiPrex + '/TemplateDownload',
          method: 'get'
        }).then(res => {
          if (!res.data || !res.data.url) return
          window.location.href = this.define.comUrl + res.data.url
        })
      },
      beforeUpload(file) {
        const isRightSize = file.size / 1024 < 500
        if (!isRightSize) this.$message.error('文件大小不能超过 500KB')
        return isRightSize
      },
      handleRemove() {
        this.fileList = []
      },
      beforeRemove(file) {
        return this.$confirm(`确定移除 ${file.name}?`).catch(() => {})
      },
      handleChange(file, fileList) {
        this.fileList = fileList.slice(-1)
      },
      handleSuccess(res, file, fileList) {
        if (res.code === 200) {
          this.fileList = fileList.slice(-1)
          this.fileName = res.data.name
        } else {
          this.fileList = fileList.filter(o => o.uid !== file.uid)
          this.$message({ message: res.msg, type: 'error', duration: 1000 })
        }
      }
    }
  }
</script>
<style lang="scss" scoped>
  ::v-deep .el-dialog__body { padding: 20px 40px 2px !important; }
  .import-main {
    height: 500px;
    margin-top: 20px;
    overflow: hidden;
    .upload {
      display: flex;
      border: 1px solid #dcdfe6;
      margin-bottom: 25px;
      &.error-show {
        margin-top: 10px;
        margin-bottom: 15px;
        .up_left { height: 120px; }
        .up_right { padding-top: 20px; font-size: 16px; ::v-deep .el-link { font-size: 16px; } }
      }
      .up_left {
        width: 126px;
        height: 140px;
        background: #f9f9f9;
        text-align: center;
        padding-top: 20px;
        flex-shrink: 0;
        img { width: 80px; height: 80px; }
      }
      .up_right {
        color: #333;
        margin-left: 30px;
        font-size: 14px;
        padding-top: 30px;
        flex: 1;
        .title { font-size: 18px; font-weight: bold; }
        .tip { margin: 15px 0; }
      }
      .upload-area {
        display: flex;
        padding-right: 200px;
        ::v-deep .el-upload { margin-right: 50px; flex-shrink: 0; }
        ::v-deep .el-upload-list { flex: 1; }
        ::v-deep .el-upload-list__item:first-child { margin-top: 5px; }
      }
    }
    .success {
      display: flex;
      flex-direction: column;
      align-items: center;
      margin-top: 110px;
      .success-title { margin: 20px 0; font-size: 18px; font-weight: bold; }
    }
    .contips { margin-bottom: 15px; }
  }
</style>