vue3中,下载模板并进行上传导入文件 & 父子组件props传函数两种写法-传动态接口

vue3中,下载模板并进行上传导入文件 & 父子组件props传函数两种写法-传动态接口

效果

在这里插入图片描述

接口返回模板

传参

在这里插入图片描述

返回

在这里插入图片描述

代码
1、页面文件

index.vue

<template>
  <div>
    <el-button type="primary" @click="() => (isShowImport = true)">
      导入
    </el-button>
    <!-- 导入 -->
    <importPopup
      v-model:showDialog="isShowImport"
      :download-fun="downLoadPlanEvent"
      :import-fun="planImport"
      @import-success="onLoad"
    />
    <el-pagination
      background
      :current-page="page.currentPage"
      layout="total, sizes, prev, pager, next, jumper"
      :page-size="page.pageSize"
      :page-sizes="[10, 20, 30, 40, 50, 100]"
      :total="page.total"
      @current-change="hanleCurrentChange"
      @size-change="handleSizeChange"
    />
  </div>
</template>
<script setup>
  import {
    downloadPlanList,
    planImport,
    queryByPagePlanList,
  } from "@/api/acceptManage/index";
  import { downLoadxls } from "@src/utils/util";
  import importPopup from "@src/components/importPopup";
  const page = reactive({
    pageSize: 10,
    currentPage: 1,
    total: 0,
  });
  const tableData = ref([]);
  const isShowImport = ref(false);
  const downLoadPlanEvent = () => {
    downloadPlanList({}).then((res) => {
      downLoadxls(res, "结算清单下载");
    });
  };
  const hanleCurrentChange = (val) => {
    page.currentPage = val;
    onLoad();
  };
  const handleSizeChange = (val) => {
    page.pageSize = val;
    onLoad();
  };
  const onLoad = async () => {
    const formData = {
      pageSize: page.pageSize,
      pageNumber: page.currentPage,
      ...formInline.value,
      startDate: prjDate.value ? prjDate.value[0] : "",
      endDate: prjDate.value ? prjDate.value[1] : "",
    };
    await queryByPagePlanList(formData).then((res) => {
      const { code, data, message } = res;
      if (code === "00000") {
        data.data.forEach((item) => {
          item.processState === ""
            ? (item.processState = "无")
            : item.processState;
        });
        tableData.value = data.data;
        page.total = Number(data.total);
      } else {
        ElMessage.error(message);
      }
    });
  };
</script>
2、封装组件文件

两种写法——fun1.value()和fun2.value(param).then(res)

src\components\importPopup.vue

<!-- 
  showDialog       //弹窗是否显示
  downloadFun      //下载模板方法
  importFun        //导入方法
  import-success   //导入成功点击确定回调方法
-->

<template>
  <div class="item-content">
    <el-dialog
      v-model="showDialog"
      :close-on-click-modal="true"
      :destroy-on-close="true"
      :show-close="true"
      title="导入"
      width="35%"
      @close="handleCancel"
    >
      <el-upload
        ref="uploadRef"
        action="#"
        class="upload-demo"
        drag
        :file-list="fileList"
        :http-request="uploadFiles"
        :limit="1"
        :multiple="false"
        :show-file-list="true"
      >
        <!-- :on-change="handleChange"
        :on-remove="handleRemove" -->
        <i class="el-icon-upload"></i>
        <div class="el-upload__text">
          <em>选择文件</em>
          或将文件拖拽至此区域
        </div>
        <div class="el-upload__tip">支持格式:xls、xlsx</div>
      </el-upload>
      <el-button type="text" @click="handleDownLoadTemplate">
        下载导入模板
      </el-button>
      <div class="upload-footer">
        <el-button type="primary" @click="handleSubmit">确 定</el-button>
        <el-button plain type="primary" @click="handleCancel">取 消</el-button>
      </div>
    </el-dialog>

    <!-- 导入失败 -->
    <el-dialog
      v-model="isShowFail"
      class="fail-dialog"
      :close-on-click-modal="true"
      :destroy-on-close="true"
      :show-close="true"
      title="导入失败"
      width="35%"
      @close="handleClose"
    >
      <h4 class="fail-title">
        导入失败,请求改后重新上传,错误数据{{
          errorListData.length
        }}条,失败原因如下:
      </h4>
      <el-table :data="errorListData">
        <el-table-column label="行数" prop="index" />
        <el-table-column label="错误原因" prop="msg" />
      </el-table>
    </el-dialog>
  </div>
</template>

<script setup>
  const props = defineProps({
    showDialog: {
      type: Boolean,
      default: false,
    },
    downloadFun: {
      default: null,
      type: Function,
    },
    importFun: {
      default: null,
      type: Function,
    },
  })
  const { downloadFun, importFun } = toRefs(props)
  const emit = defineEmits(['update:showDialog', 'import-success'])
  const showDialog = computed({
    get: () => props.showDialog,
    set: (val) => emit('update:showDialog', val),
  })

  const fileList = ref([])
  const errorListData = ref([])
  const isShowFail = ref(false)
  const successListData = ref()

  //下载导入模板
  const handleDownLoadTemplate = () => {
    downloadFun.value()  // 传函数写法一
  }

  //提交
  const uploadFiles = (options) => {
    const formData = new FormData()
    formData.append('file', options.file)
    //传函数写法二
    importFun
      .value(formData)
      .then((res) => {
        const { data, code } = res
        if (code === '00000') {
          successListData.value = data
        }
      })
      .catch((res) => {
        const { data, code } = res
        if (code !== '00000') {
          const { errorList } = data
          const errs = errorList.map((item) => {
            return {
              index: `第${item.row}行`,
              msg: item.message,
            }
          })
          errorListData.value = errs
          fileList.value = []
          isShowFail.value = true
        }
      })
  }
  const handleSubmit = () => {
    if (errorListData.value.length > 0) {
      isShowFail.value = true
    } else {
      isShowFail.value = false
      ElMessage.success('导入成功')
      emit('update:showDialog', false)
      emit('import-success', successListData.value)
    }
  }

  // 导入弹窗取消
  const handleCancel = () => {
    emit('update:showDialog', false)
  }

  // 导入失败弹窗关闭
  const handleClose = () => {
    isShowFail.value = false
    errorListData.value = []
  }
</script>
<style lang="scss" scoped>
  .fail-dialog {
    .fail-title {
      margin: 0px 0 10px;
    }
    :deep() {
      .ym-dialog__body {
        padding: 10px 20px 20px;
      }
    }
  }
  .upload-footer {
    display: flex;
    justify-content: center;
  }
</style>
3、接口文件

src\app\science\api\acceptManage\index.js

import request from '@src/utils/request'
import { sciencePostUrl } from '@/config'

//年度验收计划列表
export const queryByPagePlanList = (data) => {
  return request({
    url: `${sciencePostUrl}/checkPlan/getPlanPage`,
    method: 'post',
    data,
  })
}

//年度验收计划-结算清单下载
export const downloadPlanList = (data) => {
  return request({
    url: `${sciencePostUrl}/checkPlan/exportQuery`,
    responseType: 'blob',
    headers: {
      'Content-Type': 'application/json',
    },
    method: 'post',
    data,
  })
}

//年度验收计划导入
export const planImport = (data) => {
  return request({
    url: `${sciencePostUrl}/checkPlan/importPlan`,
    method: 'post',
    data,
  })
}

src\app\science\config\index.js

/**
 * @description 4个子配置,vue/cli配置|通用配置|主题配置|网络配置导出
 *              config中的部分配置由vue.config.js读取,本质是node,故不可使用window等浏览器对象
 */
const cli = require('./cli.config')
const prefixApi = require('./prefixApi.config')
module.exports = {
  ...cli,
  ...prefixApi,
}

src\app\science\config\prefixApi.config.js

module.exports = {
  planPostUrl: '/srbm-prj-plan-front/member',
  sciencePostUrl: '/srbm-prj-techprj-front/member',
}
4、方法文件-本地返回模板

src\utils\util.js

//文件流导出数据处理
export const downLoadxls = (res, fileName) => {
  let name = fileName
  if (res.headers['content-disposition']) {
    const contentDisposition = res.headers['content-disposition'].split('=')
    name = (contentDisposition && decodeURI(contentDisposition[1])) || ''
  }
  const file = new File([res.data], name, res.data)
  const href = URL.createObjectURL(file)
  const aTag = document.createElement('a')
  aTag.download = file.name
  aTag.target = '_blank'
  aTag.href = href
  aTag.click()
  URL.revokeObjectURL(href)
}

//本地文件下载  下载的模板文件放在public下的file文件夹中
export const downFile = (fileName) => {
  const anchor = document.createElement('a')
  anchor.href = `${process.env.BASE_URL}static/file/${fileName}`
  anchor.setAttribute('download', fileName)
  anchor.innerHTML = 'downloading...'
  anchor.style.display = 'none'
  document.body.appendChild(anchor)
  setTimeout(() => {
    anchor.click()
    document.body.removeChild(anchor)
    setTimeout(() => {
      self.URL.revokeObjectURL(anchor.href)
    }, 250)
  }, 66)
}

//本地文件下载-自定义文件名
export const downFileNew = (fileName, name) => {
  const anchor = document.createElement('a')
  anchor.href = `${process.env.BASE_URL}static/file/${fileName}`
  anchor.download = name
  // anchor.setAttribute('download', name)
  anchor.innerHTML = 'downloading...'
  anchor.style.display = 'none'
  console.log('anchor', anchor)
  document.body.appendChild(anchor)
  setTimeout(() => {
    anchor.click()
    document.body.removeChild(anchor)
    setTimeout(() => {
      console.log(123, anchor)
      self.URL.revokeObjectURL(anchor.href)
    }, 250)
  }, 66)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值