vue + elementUI 视频分片上传

<template>
  <div>
    <el-dialog
      title="上传视频"
      :visible.sync="dialogVisible"
      width="50%"
      :before-close="handleClose">
      <el-upload
        class="upload-demo"
        ref="upload"
        :action="uploadUrl"
        :before-upload="beforeUpload"
        :on-progress="handleProgress"
        :on-success="handleSuccess"
        :on-error="handleError"
        :auto-upload="false"
        :file-list="fileList"
        list-type="text">
        <el-button size="small" type="primary">选取视频</el-button>
        <div slot="tip" class="el-upload__tip">支持 mp4, avi, mov, wmv, flv 格式,最大不超过 2GB</div>
      </el-upload>
      <el-progress :percentage="uploadPercentage" style="margin-top: 15px;"></el-progress>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="startUpload">上 传</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
export default {
  data() {
    return {
      dialogVisible: false,
      fileList: [],
      uploadPercentage: 0,
      chunkSize: 5 * 1024 * 1024, // 5MB
      uploadUrl: 'https://your-backend.com/upload'
    };
  },
  methods: {
    beforeUpload(file) {
      const allowedTypes = ['video/mp4', 'video/avi', 'video/quicktime', 'video/x-ms-wmv', 'video/x-flv'];
      const isAllowedType = allowedTypes.includes(file.type);
      const isLt2G = file.size / 1024 / 1024 / 1024 < 2;

      if (!isAllowedType) {
        this.$message.error('视频格式不支持!');
        return false;
      }
      if (!isLt2G) {
        this.$message.error('视频大小不能超过 2GB!');
        return false;
      }

      // 分片处理逻辑
      this.fileList = this.sliceFile(file);
      return false; // 阻止默认的上传行为
    },
    sliceFile(file) {
      const chunks = [];
      const totalChunks = Math.ceil(file.size / this.chunkSize);
      for (let i = 0; i < totalChunks; i++) {
        const chunk = file.slice(i * this.chunkSize, (i + 1) * this.chunkSize);
        chunks.push({ chunk, index: i, file });
      }
      return chunks;
    },
    async startUpload() {
      for (const { chunk, index, file } of this.fileList) {
        const formData = new FormData();
        formData.append('file', chunk);
        formData.append('index', index);
        formData.append('fileName', file.name);

        await this.uploadChunk(formData);
      }

      // 合并请求
      await this.mergeChunks(this.fileList[0].file.name);
    },
    async uploadChunk(formData) {
      try {
        await this.$axios.post(this.uploadUrl, formData, {
          onUploadProgress: (progressEvent) => {
            this.uploadPercentage = Math.round((progressEvent.loaded / progressEvent.total) * 100);
          }
        });
      } catch (error) {
        console.error('Upload chunk error', error);
      }
    },
    async mergeChunks(fileName) {
      try {
        await this.$axios.post(`${this.uploadUrl}/merge`, { fileName });
        this.$message.success('上传成功');
        this.dialogVisible = false;
        this.fileList = [];
        this.uploadPercentage = 0;
      } catch (error) {
        this.$message.error('合并文件失败');
        console.error('Merge chunks error', error);
      }
    },
    handleProgress(event, file, fileList) {
      this.uploadPercentage = Math.round((event.loaded / event.total) * 100);
    },
    handleSuccess(response, file, fileList) {
      this.$message.success('上传成功');
      this.fileList = [];
      this.uploadPercentage = 0;
      this.dialogVisible = false;
    },
    handleError(err, file, fileList) {
      this.$message.error('上传失败');
      this.uploadPercentage = 0;
    },
    handleClose(done) {
      this.$confirm('确认关闭?')
        .then(_ => {
          done();
        })
        .catch(_ => {});
    },
    openDialog() {
      this.dialogVisible = true;
    }
  }
};
</script>

<style scoped>
.upload-demo {
  margin-top: 10px;
}
</style>

  

posted @ 2024-06-19 17:33  james_liang  阅读(25)  评论(0编辑  收藏  举报