目前只封装了图片与视频,后续会加入excel的导入导出

<template>
  <div class="img-upload">
    <div class="img-upload-box">
      <div v-for="file in value" :key="file.fileId" class="img-upload-item el-upload-list--picture-card">
        <!-- 1图片 2视频 -->
        <template>
          <video v-if="file.type === 2" :src="file.url" :controls="false" controlslist="nodownload" style="width: 100%">
            您的浏览器不支持 video 标签
          </video>
          <el-image
            v-else
            class="el-upload-list__item-thumbnail"
            :src="file.url"
            :alt="file.fileName"
          />
          <span class="el-upload-list__item-actions">
            <span
              class="el-upload-list__item-preview"
              @click="handlePreview(file)"
            >
              <i class="el-icon-circle-plus-outline"></i>
            </span>
            <span
              v-if="!disabled"
              class="el-upload-list__item-delete"
              @click="handleRemove(file)"
            >
              <i class="el-icon-delete"></i>
            </span>
          </span>
        </template>
      </div>
    </div>
    <el-upload
      v-if="value.length < maxCount && !disabled"
      v-loading="uploadLoading"
      element-loading-text="上传速度跟附件大小有关,一般在1分钟之内"
      element-loading-spinner="el-icon-loading"
      element-loading-background="rgba(0, 0, 0, 0.8)"
      class="upload-wrapper"
      ref="upload"
      action="/vue_admin/omp/exceptioncodeFlow/business/upload"
      :show-file-list="false"
      :before-upload="beforeUpload"
      :on-success="uploadSuccess"
      :on-error="uploadFail"
      :multiple="true"
    >
      <div class="plus-btn">
        <i class="el-icon-plus"></i>
      </div>
    </el-upload>
    <div v-if="!disabled" class="el-upload__tip">
      <div class="text" v-for="t in tips" :key="t">· {{ t }}</div>
    </div>
    <el-dialog custom-class="img-preview-dialog" :append-to-body="true" :visible.sync="dialogVisible" title="预览">
      <el-image v-if="dialogType === 1" :src="dialogImageUrl" alt="" />
      <video v-else :src="dialogImageUrl" controls="controls" controlslist="nodownload" style="width: 100%"></video>

      <template #footer>
        <el-button @click="dialogVisible = false;">取消</el-button>
      </template>
    </el-dialog>
  </div>
</template>
<script>
export default {
  name: 'FileUpload',
  props: {
    disabled: Boolean,
    // 图片属性数组
    value: Array,
    // 最大上传图片数量
    maxCount: {
      type: Number,
      default: 1,
    },
    tips: {
      type: Array,
      default() {
        return ['图片大小: 不超过5M; 支持图片格式:jpg/jpeg/png', '视频大小: 不超过100M; 支持视频格式: mp4/mov/rmvb'];
      },
    },
  },
  data() {
    return {
      uploadLoading: false,
      dialogImageUrl: '',
      dialogType: '',
      dialogVisible: false,
    };
  },
  methods: {
    // 文件上传
    beforeUpload(file) {
      let fileName = file.name
      let fileend = fileName.substring(fileName.lastIndexOf("."))
      // 视频
      const isVideo = ['.mp4', '.mov', '.rmvb'].includes(fileend);
      // 图片
      const isJPG = ['.jpg', '.jpeg', '.png'].includes(fileend);
      if (!isVideo && !isJPG) {
        this.$notify({
          title: '提示',
          message: '只能上传图片和视频,图片支持jpg/jpeg/png格式,视频支持mp4/mov/rmvb格式',
          type: 'warning'
        });
        return false;
      }
      if (isVideo) {
        const isLt100M = file.size / 1024 / 1024 < 100;
        if (!isLt100M) {
          this.$message.error('上传视频大小不能超过 100MB!');
          return false;
        }
      }
      if (isJPG) {
        const isLt5M = file.size / 1024 / 1024 < 5;
        if (!isLt5M) {
          this.$message.error('上传图片大小不能超过 5MB!');
          return false;
        }
      }
      this.uploadLoading = true;
      return true;
    },

    // 文件上传成功
    uploadSuccess(res) {
      this.uploadLoading = false;
      if (res.code == 0) {
        if (res.data) {
          const file = {
            ...res.data,
            url: res.data.url.replace('home/file', process.env.NODE_ENV === 'development' ? 'http://172.31.47.193:9070/image/' : '/image'),
          }
          const files = file ? this.value.concat([file]) : this.value;
          this.emitInput(files);
        }
      } else {
        this.$message.error(res.message);
      }
    },
    handleRemove(file) {
      this.$confirm('确认删除?', '提示', {
        type: 'warning',
      }).then(() => {
        const index = this.value.findIndex(ff => ff.fileId === file.fileId);
        const list = [...this.value];
        list.splice(index, 1);
        this.emitInput(list);
      })
    },
    handlePreview(file) {
      this.dialogVisible = true;
      this.dialogType = file.type;
      this.dialogImageUrl = file.url;
    },
    emitInput(files) {
      this.$emit('input', files);
    },

    uploadFail(err) {
      this.uploadLoading = false;
      this.$message.error(err.message || '上传失败');
    },
  },
};
</script>
<style lang="scss" scoped>
.img-upload {
  .img-upload-box {
    display: flex;
    justify-content: flex-start;
    flex-wrap: wrap;
    .img-upload-item {
      width: 80px;
      height: 80px;
      display: flex;
      justify-content: center;
      align-items: center;
      position: relative;
      overflow: hidden;
      border-radius: 8px;
      border: 1px dashed #c0ccda;
      margin: 10px 10px 10px 0;
      padding: 10px;
    }
  }
}
.upload-wrapper {
  width: 300px;
}
.plus-btn {
  height: 80px;
  width: 80px;
  line-height: 80px;
  display: flex;
  justify-content: center;
  align-items: center;
  border: 1px dashed #c0ccda;
  border-radius: 8px;
  i {
    margin-top: inherit;
    font-size: 24px;
  }
}
.img-preview-dialog {
  /deep/ .el-dialog__body {
    text-align: center;
    img {
      max-width: 100%;
    }
  }
}
</style>

使用示例
2022-08-08T07:15:04.png

图片回显示例
2022-08-08T07:15:58.png

发表评论