vue+element plus+ts 解决视频上传分片问题

需要和后端对接好:我的是拿到数据之后判断是否大于分片大小(不展示进度条),大于就进入分片模式(并展示进度条),小于直接上传。并且我的是只负责分片,提交数据给后端,后端自己合并就行。

1、template部分

 <!-- 上传学员视频文件 -->
    <el-dialog
      v-model="dialogVisible"
      title="上传学员视频文件"
      width="30%"
      :before-close="closeDialog"
    >
      <el-form
        ref="ruleFormRef"
        :inline="true"
        :rules="rules"
        :model="formData"
      >
        <el-form-item label="视频文件:" prop="subjectId">
          <el-upload
             ref="upload"
              :key="uploadKey"
            :limit="1"
            action="#"
            :http-request="uploadChange"
            accept=".mp4"
          >
            <!--   :http-request="uploadChange"上传前的回调,显示文件类型  
                action="#"上传的地址 -->
            <template #trigger>
              <el-button type="primary">上传视频文件</el-button>
            </template>
          </el-upload>
        </el-form-item>
        <div
          class="demo-progress"
          v-show="formData.file.size > formData.chunkSize"
        >
          <el-progress :stroke-width="10" :percentage="uploadProgress" />
        </div>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="syncMsg()">提交</el-button>
        </span>
      </template>
    </el-dialog>

2、script部分

流程:必须有的【分片大小、当前上传的分片、上传的文件、总片数】、我的代码又后端要求每次需要唯一的文件名,这样它可以根据是否是同一个文件名对视频文件进行合并

const upUrl = settings.REST + "/api/stu-photos-mgt/xxx/"+route.query.id;
 // 格式化进度,使用百分比进行展示
const uploadProgress = ref(0); // 进度条进度
const formData = reactive({
  file: "", // 保存上传的文件
  chunkSize: 10 * 1024 * 1024, // 分片大小,10MB 
  filename: "", // 文件名
});
const uploadChange = async (options) => {
  console.log(options);
   // 保存上传的文件
   formData.file = options.file;
  if(formData.file.size>=1024*1024*200){
    ElMessage({message: "请上传小于200M的文件",type: "error"});
    return options.onError("请上传小于200M的文件")
  }  
}
const ruleFormRef = ref();
const uploadKey = ref(Date.now());

const clearFormData = () => {
  uploadKey.value = Date.now(); // 强制重新渲染 ElUpload
  formData.file = {}; // 清空文件对象
  formData.filename = ""; // 清空文件名
  uploadProgress.value = 0; // 重置进度条
};

const closeDialog = () => {
  dialogVisible.value = false;
  clearFormData(); // 调用清空数据的方法
};


const generateUniqueFileName = () => {
  // 生成唯一文件名,使用当前时间戳加上随机数
  const timestamp = Date.now(); // 获取当前时间戳
  const randomNum = Math.floor(Math.random() * 10000); // 生成一个随机数
  return `file_${timestamp}_${randomNum}`; // 拼接生成文件名
};
// 先上传、再分片、再提交
const syncMsg = async () => {
  if (!formData.file) {
    ElMessage.error("请先上传文件");
    return;
  }
  // 如果文件在分片大小以内,就直接上传
  if (formData.file.size <= formData.chunkSize) {
    try {
      const formDataChunk = new FormData();
      formDataChunk.append("uploadFile", formData.file);

      let res = await axios({
        url: `/api/stu-photos-mgt/xxxxxxx/${route.query.id}`,
        method: "POST",
        data: formDataChunk,
      });
      res.code == 200
        ? (ElMessage.success("上传成功"), (dialogVisible.value = false))
        : ElMessage.error(res.message);
      getData();
      setTimeout(closeDialog, 500); // 延时清空数据,确保进度条到达 100%
    } catch (error) {
      ElMessage.error(error);
    }
    return;
  } else {
    // 如果文件超过分片大小,就分片上传
    const file = formData.file; // 上传的文件
    const totalChunks = Math.ceil(file.size / formData.chunkSize); // 计算总分片数
    let currentChunk = 0; // 当前上传的分片
    const uniqueFileName = generateUniqueFileName(); // 生成唯一文件名

    // 分片上传逻辑
    while (currentChunk < totalChunks) {
      const start = currentChunk * formData.chunkSize;
      const end = Math.min(file.size, start + formData.chunkSize);
      const chunk = file.slice(start, end); // 切割文件

      const formDataChunk = new FormData();
      formDataChunk.append("uploadFile", chunk);
      formDataChunk.append("filename", uniqueFileName); // 使用生成的唯一文件名--文件名
      formDataChunk.append("index", currentChunk); // 分片序号,从 0 开始
      formDataChunk.append("chunkSize", totalChunks); // 总分片数--分割文件数

      try {
        // 上传分片接口
        let res = await axios({
          url: `/api/stu-photos-mgt/xxxxxxx/${route.query.id}`,
          method: "POST",
          data: formDataChunk,
        });
        currentChunk++;
         // 更新进度条
         uploadProgress.value = Math.round((currentChunk / totalChunks) * 100);
        if (uploadProgress.value < 100) {
          // 稍微延迟增加进度条的数值,模拟平滑过渡
          await new Promise(resolve => setTimeout(resolve, 50));
        }
        if (
          (res.code == 200 || res.data.code == 1) &&
          currentChunk === totalChunks - 1
        ) {
          // 最后的进度条平滑到 100%
          uploadProgress.value = 100;
          await new Promise(resolve => setTimeout(resolve, 200)); // 延时显示100%的效果
          ElMessage.success("上传成功");
          dialogVisible.value = false;
          getData();
          closeDialog(); // 调用清空数据的方法
        }
      } catch (error) {
        ElMessage.error("上传分片失败,请重试");
        return;
      }
    }
  }
};

3、css代码

.demo-progress .el-progress--line {
  margin-bottom: 15px;
  max-width: 600px;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值