vue ant文件上传组件二次封装

支持功能:多文件上传,单文件上传,文件类型限制,文件大小限制,文件个数限制(主要针对多文件上传)

<template>
  <div>
    <a-spin :spinning="spinning">
      <a-upload
        method="post"
        :disabled="disabled"
        :list-type="listType"
        :data="paramObj"
        :headers="headers"
        :multiple="multiple"
        :accept="fileFormat"
        :action="action"
        :fileList="imageProfile"
        :remove="removeFile"
        :showUploadList="showUploadList"
        :before-upload="beforeUpload"
        @preview="previewFile"
        :customRequest="handleCustomRequest"
      >
        <a-button :type="uploadBtnType">
          <a-icon type="upload" /> {{ uploadBtnName }}
        </a-button>
      </a-upload>
    </a-spin>
   

    <!-- 文件预览弹框-->
    <Modal
      :visible.sync="visible"
      :isShowBtn="false"
      width="48%"
      :keyboardAndMaskClosable="true"
      :title="dialogImageUrl.name"
      @cancel="handlelose"
    >
      <template #content>
        <img
          :alt="dialogImageUrl.name"
          :src="dialogImageUrl.url"
          :title="dialogImageUrl.name"
          class="modal_img"
        />
      </template>
    </Modal>
  </div>
</template>

<script>
import { getAuthorization } from "@/utils/request";
import { getFileExtension } from "@/utils/file-util";
import { patchUpload } from "./api/fileApi";
import {Spin} from 'ant-design-vue'
export default {
  name: "upload",
  components: {
    Modal: () => import("@/components/Modal"),
  },
  props: {
    //按钮名称
    uploadBtnName: {
      type: String,
      default: "上传文件",
    },
    // 默认按钮类型
    uploadBtnType: {
      type: String,
      default: null,
    },
    //其他额外参数
    params: {
      type: [String, Object],
      default: () => "",
    },
    //显示列表
    listType: {
      type: String,
      default: "picture",
    },
    //用于展示的图片地址
    fileList: {
      type: [Array, String],
      default: function () {
        return [];
      },
    },
    //是否支持多文件上传
    multiple: {
      type: Boolean,
      default: false,
    },
    //允许的上传文件个数, 用于支持多文件上传 0:则表示无限制
    fileNumber: {
      type: Number,
      default: 1,
    },
    //文件格式
    fileFormat: {
      type: String,
      default: ".jpg,.jpeg,.pdf,.png,.doc,.docx,.svg",
    },
    //文件上传地址
    action: {
      type: String,
      default: "/prize/uploadPic",
    },
    // 允许的上传文件类型的大小
    fileSizeLimit: {
      type: Number,
      default: 50,
    },
    //是否禁用
    disabled: {
      type: Boolean,
      default: false,
    },
    showUploadList: {
      type: Boolean,
      default: true,
    },
  },
  data() {
    return {
      token: getAuthorization(),
      imageProfile: [],
      Authorization: "",
      paramObj: {},
      visible: false,
      dialogImageUrl: "",
      imageProfile: [], //文件内容
      spinning: false,
    };
  },
  watch: {
    fileList: {
      handler(val) {
        this.imageProfile = val;
      },
      deep: true,
      immediate: true
    }
  },
  computed: {
    headers() {
      return {
        Authorization: this.token,
      };
    },
  },
  created() {
    // console.log("upload-created");
    this.token = getAuthorization();
  },
  methods: {
    //自定义文件上传
    async handleCustomRequest(data) {
      this.spinning = true;
      const formData = new FormData();
      formData.append("file", data.file);
      let progress = { percent: 1 }; //进度条
      let speed = 100 / (data.file.size / 65000);
      const intervalId = setInterval(() => {
        if (progress.percent < 100) {
          progress.percent += speed;
          data.onProgress(progress);
        } else {
          clearInterval(intervalId);
        }
      }, 100);
      let res = await patchUpload(formData);
      this.spinning = false
      if (res.status === 200) {
        data.onSuccess();
        data.file.status = "done";
        this.handleOnSuccess(res, data.file);
        this.$message.success("文件上传成功!");
      } else {
        data.file.status = "error";
        data.onError();
        this.handleError(res, data.file);
        this.$message.error("上传失败,请重试!");
      }
    },

    //文件上传成功
    handleOnSuccess({ url }, file) {
      if (typeof this.imageProfile === "string") {
        this.imageProfile = [];
      }
      let name = null;
      if (url) name = url.substr(url.lastIndexOf("/") + 1, url.length);
      let uid = name + new Date()
      if(file && file.uid) uid = file.uid
      let obj = {
        uid,
        name,
        status: "done",
        thumbUrl: url,
        url,
      };
      if (this.multiple) {
        //可以上传多张
        this.imageProfile.push(obj);
      } else {
        //不能上传多张
        if (this.imageProfile.length > 0) {
          this.imageProfile.splice(0, this.imageProfile.length);
        }
        this.imageProfile.push(obj);
      }
      let errorList = this.imageProfile.filter(
        (item) => item.status === "error"
      );
      if (errorList.length) {
        this.$message.error("尚有未成功上传的文件,请删除后操作!");
        return;
      }
      this.$emit("upload-success", { fileList: this.imageProfile });
    },

    //文件上传失败
    handleError(err) {
      if (err.status === 403 || err.status === 401) {
        Modal.warning({
          content: "该账号已在其他设备登录,您已被强制下线!",
          closable: false,
          destroyOnClose: true,
          keyboard: false,
          maskClosable: false,
          okText: "重新登录",
          title: "温馨提示",
          onOk: () => {
            store.dispatch("user/resetToken").then(() => {
              location.reload();
            });
          },
        });
      } 
    },

    //上传前校验
    beforeUpload(file) {
      // console.log("beforeUpload:", file);
      //文件上传前额外参数
      this.paramObj = {
        ...this.params,
        FileName: file.name,
      };
      const extension = getFileExtension(file.name); //获取文件后缀名
      const isRight = this.fileFormat.indexOf(extension) > -1;
      const isPass = file.size / 1024 / 1024 < this.fileSizeLimit; //文件大小
      if (!isRight) {
        this.$message.error(
          `文件上传类型不正确,请上传后缀名为 ${this.fileFormat} 的文件 !`
        );
      } else if (!isPass) {
        this.$message.error(
          `请检查上传文件大小是否超过${this.fileSizeLimit}MB`
        );
        return false;
      } else if (this.imageProfile.length >= this.fileNumber && this.multiple && this.fileNumber > 0) {
        //多文件上传,才限制文件个数
        this.$message.error(
          `当前限制选择 ${this.fileNumber} 个文件,请删除后再上传`
        );
        return false;
      }
      return isRight;
    },

    //文件移除
    removeFile(file) {
      // console.log("文件移除", file);
      let index = this.imageProfile.findIndex((item) => item.uid === file.uid);
      if(index >= 0) {
        this.imageProfile.splice(index, 1);
        this.$emit("upload-success", { fileList: this.imageProfile });
      } else {
        this.$message.error("文件移除查找index下标失败!")
      }
    },

    //文件预览
    previewFile(file) {
      this.dialogImageUrl = {
        name: file.name,
        url: file.url || file.thumbUrl,
      };
      this.visible = true;
    },

    //预览弹框关闭
    handlelose() {
      this.visible = false;
    },
  },
};
</script>

<style lang="less" scoped>
.modal_img {
  width: 100%;
  object-fit: cover;
}
</style>
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值