一个vue上传组,不切片,最下方是一个切片上传的代码

vue2

<template>
  <div>
    <div>
      <div class="dropzone" @dragover.prevent @drop="dropFile">
        <span>拖拽文件到此处或<em style="color:blue;" @click="showFileInput">点击上传</em></span>
        <input ref="fileInput" class="file_upload" type="file" @change="onFileChange" multiple style="display:none;">
      </div>

    </div>
    <el-table :data="fileList" max-height="400">
      <el-table-column prop="name" label="文件名"></el-table-column>
      <el-table-column prop="size" label="文件大小"></el-table-column>
      <el-table-column prop="type" label="文件类型"></el-table-column>
      <el-table-column label="上传进度">
        <template slot-scope="scope">
          <el-progress :percentage="scope.row.progress" />
          <div v-if="scope.row.status === 'failed'">
            <span style="color: red;">上传失败</span>
          </div>
          <div v-if="scope.row.status === 'success'">
            <span style="color: #49af2f;">上传成功</span>
          </div>
        </template>
      </el-table-column>
      <el-table-column label="操作">
        <template slot-scope="scope">
          <el-button v-if="scope.row.status === 'failed'" type="primary" size="mini"
            @click="retryUpload(scope.$index)">重新上传</el-button>

          <el-button size="mini" @click="deleteUpload(scope.$index)">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
    <el-button type="primary" @click="upload_async">上传(async方式)</el-button>
    <el-button type="primary" @click="upload_promises">上传(promises方式)</el-button>

  </div>
</template>

<script>
import axios from 'axios'
export default {
  data() {
    return {
    allowedTypes: [ "gif",
        "jpeg",
        "jpg",
        "png",
        "psd",
        "rar",
        "zip",
        "pdf",
        "doc",
        "docx",
        "ppt",
        "pptx",
        "txt",
        "xls",
        "xlsx",
      ],
      fileList: [],
      api: 'http://leju.bufan.cloud/lejuAdmin/material/uploadFileOss',
      token: 'eyJhbGciOiJIUzUxMiIsInppcCI6IkdaSVAifQ.H4sIAAAAAAAAAKtWKi5NUrJSSkzJzcxT0lFKrShQsjI0szAwsDQ1M7CsBQAhz0vSIAAAAA.BoZCaxWqEkJEOIPjWPbd5EU_Fi84upgT_obDgQ3V1--oRLCDMkxVzbD2hkYjNHZOf0Hhvp9KcV4V4kTAkiZo9w'
    }
  },
  methods: {
    addFiles_Push(files) {
       let invalidFilesCount = 0;
                    let invalidFileNames = [];
                    const filesArray = Array.from(files);
                    for (let i = 0; i < filesArray.length; i++) {
                        const file = filesArray[i]
                        const fileType = file.name.split(".").pop().toLowerCase();
                        if (!this.allowedTypes.includes(fileType)) {
                            invalidFilesCount++;
                            invalidFileNames.push(file.name);
                            continue;
                        }
                        //验证文件大小 10MB
                        const maxFileSize = 10 * 1024 * 1024;

                        if (file.size > maxFileSize) {
                            invalidFilesCount++;
                            invalidFileNames.push(file.name);
                            continue;
                        }

                        this.fileList.push({
                            name: file.name,
                            size: file.size,
                            type: file.type,
                            progress: 0,
                            CalibrationSupplier: "",
                            CertificateNumber: "",
                            status: 'pending',
                            file: file,
                        })
                    }
                    if (invalidFilesCount > 0) {
                        let errorMessage = `有 ${invalidFilesCount} 个文件类型或大小不允许上传:`;
                        if (invalidFileNames.length > 0) {
                            errorMessage += `${invalidFileNames.join("、")}`;
                        }
                        this.$notify.error({ title: '错误', message: errorMessage });
                    }
                    console.log('这个是需要上传的文件', this.files)
    },
    dropFile(e) {
      e.preventDefault();
      // e.dataTransfer.files  是获取拖拽文件的
      const files = e.dataTransfer.files
      this.addFiles_Push(files)
    },
    showFileInput() {
      this.$refs.fileInput.click()
    },
    onFileChange(e) {
      // e.target.files  是获取选择文件的

      const files = e.target.files
      this.addFiles_Push(files)

    },
    async upload_async() {
      for (let i = 0; i < this.fileList.length; i++) {
        const fileItem = this.fileList[i]
        if (fileItem.status === 'pending') {
          fileItem.status = 'uploading'
          try {
            const formData = new FormData()
            formData.append('file', fileItem.file)
            console.log('这个是上传时的', formData)
            const response = await axios.post('http://leju.bufan.cloud/lejuAdmin/material/uploadFileOss', formData, {
              headers: {
                token: ` ${this.token}` // 在请求头中添加 token 字段  但是依旧添加错了
              },
              onUploadProgress: (progressEvent) => {
                const progress = Math.round((progressEvent.loaded * 100) / progressEvent.total)
                fileItem.progress = progress
              },
            })
            fileItem.status = 'success'
          } catch (error) {
            fileItem.status = 'failed'
          }
        }
      }
    },

    async upload_promises() {
      const promises = [];
      for (let i = 0; i < this.fileList.length; i++) {
        const fileItem = this.fileList[i];
        if (fileItem.status === "pending") {
          fileItem.status = "uploading";
          const formData = new FormData();
          formData.append("file", fileItem.file);

          const promise = axios
            .post(this.api, formData, {
              headers: {
                token: this.token,
              },
              onUploadProgress: (progressEvent) => {
                const progress = Math.round(
                  (progressEvent.loaded * 100) / progressEvent.total
                );
                fileItem.progress = progress;
              },
            })
            .then(() => {
              fileItem.status = "success";
            })
            .catch(() => {
              fileItem.status = "failed";
            });
          promises.push(promise);
        }
      }

      await Promise.all(promises);
    },

    retryUpload(index) {
      const fileItem = this.fileList[index]
      fileItem.status = 'pending'
      fileItem.progress = 0
      this.upload()
    },
    deleteUpload(index) {
      this.fileList.splice(index, 1)
    }

  },
}
</script>
<style scoped>
.dropzone {
  background-color: #eee;
  border: 1px dashed #ccc;
  margin-bottom: 10px;
  padding: 20px;
}

p {
  margin: 0;
}
</style>

在这里插入图片描述

// 这个是一个上传按钮的事件,也就是选择完文件,确定上传,切片,这里面有2个接口,一个是上传接口,一个是通知后端上传完了的接口
async uploadFiles() {
      const CHUNK_SIZE = 1024 * 1024; // 定义每个数据块的大小为1MB
      const promises = []; // 创建一个空数组,用于存储各个文件上传过程中返回的 Promise 对象
  
      for (let i = 0; i < this.files.length; i++) { // 遍历待上传的文件列表
          const fileItem = this.files[i]; // 获取当前需要上传的文件对象
  
          if (fileItem.status === "pending") { // 如果该文件状态为 "pending"(即等待上传)
              fileItem.status = "uploading"; // 将文件状态更新为 "uploading"(即正在上传)
  
              const formData = new FormData(); // 创建一个空的 FormData 对象,用于存储要传递给服务器的数据
              formData.append("name", fileItem.name); // 向 FormData 对象中添加文件名
              formData.append("size", fileItem.size); // 向 FormData 对象中添加文件大小
              formData.append("type", fileItem.type); // 向 FormData 对象中添加文件类型
              formData.append("__RequestVerificationToken", $.lrToken); // 向 FormData 对象中添加验证令牌
  
              let startByte = 0; // 定义数据块的起始位置为0
              let endByte = Math.min(CHUNK_SIZE, fileItem.size); // 定义数据块的结束位置为1MB或者文件大小之间较小值
              let chunkIndex = 0; // 定义数据块的索引为0
  
              while (startByte < fileItem.size) { // 循环上传文件直到文件的每个数据块都被上传完成
                  const chunkFormData = new FormData(); // 创建一个空的 FormData 对象,用于存储当前数据块要传递给服务器的数据
                  const chunkBlob = fileItem.file.slice(startByte, endByte); // 从文件对象中提取指定范围内的二进制数据,以构造数据块
                  chunkFormData.append('file', chunkBlob, fileItem.name + '.' + chunkIndex); // 向 FormData 对象中添加当前数据块的二进制数据和文件名
                  chunkFormData.append('chunkIndex', chunkIndex); // 向 FormData 对象中添加当前数据块在整个文件中的索引
  
                  console.log('这个是上传的', chunkFormData); // 在控制台输出当前正在上传的数据块的内容
  
                  const promise = new Promise((resolve, reject) => { // 创建一个 Promise 对象,用于处理 AJAX 请求的响应结果
                      $.ajax({
                          url: top.$.rootUrl + "/LR_SystemModule/Annexes/UploadAnnexesFileChunk", // 设置请求的地址  上传地址
                          type: "POST", // 设置请求方法为 POST
                          data: chunkFormData, // 设置请求参数为 chunkFormData 对象
                          processData: false, // 禁止自动将数据转换为查询字符串
                          contentType: false, // 禁止发送 Content-Type 头部信息
                          xhr: () => {
                              const xhr = new XMLHttpRequest(); // 创建一个新的 XMLHttpRequest 对象
                              xhr.upload.onprogress = (e) => { // 在上传过程中,每当传输了一些数据时,更新文件对象的进度信息
                                  const progress = Math.round(((startByte + e.loaded) * 100) / fileItem.size); // 计算文件上传进度的百分比
                                  fileItem.progress = progress; // 更新文件上传进度为新的百分比值
                              };
                              return xhr;
                          },
                          success: () => { // 当 AJAX 请求成功完成时,执行以下语句
                              chunkIndex++; // 更新数据块的索引值
                              startByte = endByte; // 更新下一个数据块的起始位置
                              endByte = Math.min(endByte + CHUNK_SIZE, fileItem.size); // 更新下一个数据块的结束位置
                              if (startByte >= fileItem.size) { // 如果已经上传完最后一个数据块
                                // 最后一个数据块上传完成,调用合并文件的接口
                                $.ajax({
                                    url: top.$.rootUrl + "/LR_SystemModule/Annexes/MergeAnnexesFileChunks", // 设置请求的地址为文件合并的接口
                                    type: "POST", // 设置请求方法为 POST
                                    data: formData, // 设置请求参数为 formData 对象,该对象存储了文件的基本信息
                                    processData: false, // 禁止自动将数据转换为查询字符串
                                    contentType: false, // 禁止发送 Content-Type 头部信息
                                    success: () => { // 当文件合并成功时,执行以下语句
                                        fileItem.status = "success"; // 将文件状态设置为 "success"
                                        resolve(); // 解决当前 Promise 对象
                                    },
                                    error: () => { // 当文件合并失败时,执行以下语句
                                        fileItem.status = "failed"; // 将文件状态设置为 "failed"
                                        reject(); // 拒绝当前 Promise 对象
                                    }
                                });
                            }
                          },
                          error: () => { // 当文件合并失败时,执行以下语句
                            fileItem.status = "failed"; // 将文件状态设置为 "failed"
                            reject(); // 拒绝当前 Promise 对象
                        }
                      });
                  });
                  promises.push(promise);
              }
          }
      }
      await Promise.all(promises);
  },


vue2第二种方式

<template>
  <div style="width: 100%">
    <el-descriptions class="margin-top" :column="3" size="small" border>
      <el-descriptions-item
        label="上传附件:"
        span="3"
        width="130px"
        :labelStyle="rowRight"
      >
        <div style="display: flex; justify-content: space-between">
          <div style="width: 50%; height: 100%">
            <el-upload
              drag
              action=""
              ref="upload"
              :auto-upload="false"
              :show-file-list="false"
              multiple
              :file-list="fileList"
              :on-change="handleChange"
            >
              <div class="el-upload__text">
                请拖入文件,<em>点击此处选择文件</em>
              </div>
            </el-upload>
          </div>
          <div style="flex: 1">
            <h3 style="color: red">上传说明:</h3>
            <h4>
              1、上传时前几秒可能会卡顿,耐心等待一小会,然后表格里的进度条就会执行的,别着急啊,亲。文件越多时间越长...
            </h4>
            <h4>2、已经上传成功的文件不会重复上传。</h4>
            <h4>
              3、上传前请选择好文件类型,因为上传成功后就不允许修改,要修改的话就只能重选文件进行上传。
            </h4>
            <h4>
              4<span style="color: red"
                >.xls文件和.doc文件不允许上传,如果需要上传excel表格和word文档,就请选择.xlsx文件和.docx文件</span
              ></h4>
          </div>
        </div>

        <div style="display: flex; justify-content: space-around">
          <el-button
            style="color: #36d; background-color: #d1a4a4"
            size="mini"
            @click="upload_dataFileTwoList()"
            >确认上传表格文件</el-button
          >
          <el-button
            style="color: #000; background-color: #258ccb"
            size="mini"
            @click="qingkong()"
            >一键清空表格文件</el-button
          >
        </div>
      </el-descriptions-item>
    </el-descriptions>
    <div style="margin-top: 10px">选择的附件如下:</div>
    <el-table
      ref="FileData"
      :data="fileList"
      size="mini"
      style="width: 100%"
      height="300"
      border
    >
      <el-table-column type="index" width="50" align="center" />
      <el-table-column
        prop="name"
        label="文件名称"
        show-overflow-tooltip
        align="center"
      >
        <template slot-scope="scope">
          <div>
            <el-input size="mini" v-model="scope.row.name"></el-input>
          </div>
        </template>
      </el-table-column>
      <el-table-column
        prop="ACTION_TYPE"
        label="文件类型"
        show-overflow-tooltip
        align="center"
      >
        <template slot-scope="scope">
          <div>
            <el-select
              style="width: 86%"
              :disabled="scope.row.status === 'success' ? true : false"
              @change="(event) => onChange(event, scope.$index)"
              v-model="scope.row['ACTION_TYPE']"
              size="mini"
              filterable
              placeholder="请选择"
            >
              <el-option
                v-for="item in FuJian_Type_List.list"
                :key="item.value"
                :label="item.label"
                :value="item.value"
              >
              </el-option>
            </el-select>
          </div>
        </template>
      </el-table-column>
      <el-table-column
        prop="SizeName"
        label="文件大小"
        show-overflow-tooltip
        align="center"
      >
      </el-table-column>
      <el-table-column label="上传进度">
        <template slot-scope="scope">
          <!-- <el-progress :percentage="scope.row.progress" /> -->
          <div v-if="scope.row.status === 'failed'">
            <span style="color: red" :id="'item-' + scope.$index"
              >上传失败</span
            >
          </div>
          <div v-if="scope.row.status === 'success'">
            <span style="color: #49af2f" :id="'item-' + scope.$index"
              >上传成功</span
            >
          </div>
          <div v-if="scope.row.status === '上传中'">
            <span style="color: #36d" :id="'item-' + scope.$index"
              >正在上传中:{{ scope.row.progress }}%</span
            >
          </div>
        </template>
      </el-table-column>
      <el-table-column
        prop="AxiosUrl"
        label="下载"
        show-overflow-tooltip
        align="center"
      >
        <template slot-scope="scope">
          <div
            style="cursor: pointer"
            v-if="scope.row.status === 'success'"
            @click="downloadEvent(scope.row)"
          >
            文件下载
          </div>
        </template>
      </el-table-column>
      <el-table-column fixed="right" align="center" label="操作" width="180">
        <template slot-scope="scope">
          <el-button
            link
            type="success"
            size="mini"
            v-if="scope.row.status === 'failed'"
            @click.prevent="congxinshangchuan(scope.$index, scope.row)"
          >
            重新上传
          </el-button>
          <el-button
            link
            type="primary"
            size="mini"
            @click.prevent="deleteRow_OK(scope.$index, scope.row)"
          >
            删除
          </el-button>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>
<script>
import axios from "axios";
import { DeleteBaoXianFuJian } from "../api/ExpenseAccount";
import { DeleteFuJian } from "../api/index";
export default {

  props: {
    bxcode: {
      type: String,
      default: null,
    },
    tbxcode: {
      type: String,
      default: null,
    },
  },
  data() {
    return {
      FuJian_Type_List: {
        list: [
          {
            value: "附件",
            label: "附件",
          },
          {
            value: "发票",
            label: "发票",
          },
          {
            value: "合同",
            label: "合同",
          },
          {
            value: "其他",
            label: "其他",
          },
        ],
        type: "附件",
      },
      rowRight: {
        "text-align": "right",
      },
      Cookie_USER: null,
      fileList: [],
      fileList_OK: [],
      NewCode: {
        bxcode: "",
        tbxcode: "",
      },
    };
  },
  mounted() {
    // console.log("删除接口是否改变", this.YM);

    this.$store.dispatch("COOLIE_VALUE_USER");
    this.Cookie_USER = this.$store.state.cookieUser;
    // console.log('账号信息', this.Cookie_USER);
    // console.log('bxcode', this.bxcode);
    // console.log('tbxcode', this.tbxcode);
    this.NewCode.bxcode = this.bxcode;
    this.NewCode.tbxcode = this.tbxcode;
  },
  methods: {
  //选择附件类型
    onChange(e, index) {
      this.$set(this.fileList[index], "ACTION_TYPE", e);
      let list = [];
      for (let i = 0; i < this.fileList.length; i++) {
        list.push({
          ...this.fileList[i],
          raw: this.cloneFile(this.fileList[i].raw),
        });
      }
      this.fileList = list;
    },
    cloneFile(file) {
      return new File([file], file.name, { type: file.type });
    },
    // 点击了上传按钮
    upload_dataFileTwoList() {
      if (this.fileList.length > 0) {
        for (let i = 0; i < this.fileList.length; i++) {
          let list = this.fileList[i];
          if (list.status == "failed" || list.status == "pending") {
            this.upload_FN(i, list);
          }
        }
      } else {
        this.$message({
          message: "老铁,需要先选择文件在点击上传",
          type: "warning",
        });
      }
    },
    handleChange(file, fileList) {
      console.log("上传的文件类型", file);
      if (this.isFileTypeAllowed(file.raw)) {
        file.progress = 0;
        file.status = "pending";
        file.NewName = file.name;
        file.SizeName = this.bytesToMegabytes(file.size);

        file.AxiosUrl = "";
        file.ACTION_TYPE = this.FuJian_Type_List.type;
        file.Del_id = "";
        this.fileList.push(file);
      } else {
        console.log("格式不支持");
        this.$notify.error({
          title: "提示",
          message:
            ".xls和.doc这两种文件不支持,如果需要上传表格和word文档就请选择 .xlsx文件 和 .docx文件",
        });
      }
    },
    bytesToMegabytes(bytes) {
      const megabytes = bytes / (1024 * 1024);
      return megabytes % 1 === 0
        ? `${megabytes.toFixed(0)}M`
        : `${megabytes.toFixed(2)}M`;
    },
    isFileTypeAllowed(file) {
      const forbiddenTypes = [
        "application/vnd.ms-excel", // xls
        "application/msword", // doc
      ];
      // 获取文件的 MIME 类型
      const fileType = file.type;
      // 检查文件类型是否在禁止上传的列表中
      if (forbiddenTypes.includes(fileType)) {
        return false; // 不允许上传
      }
      return true; // 允许上传
    },
    async upload_FN(itemINdex, FileItem, qiepian = 0.3) {
      console.log(this.YM, "aaaaa", FileItem);

      let baseURl_QiePian = "https://jcnh.jiuchang.work:17776/api/JcShare/UploadSlice";

      try {
        //    文件类型  文件名称 修改后的文件名 文件大小 文件file对象
        let { ACTION_TYPE, NewName, name, size, raw: uploadfile } = FileItem;
        let uploadedChunks = 0; // 已上传的分片数量
        let hash = this.generateRandomStringWithTimestamp(6);
        const chunkSize = qiepian * 1024 * 1024;
        const totalChunks = Math.ceil(size / chunkSize);
        const concurrency = 3;
        const promises = [];
        // 循环上传分片
        for (let index = 0; index < totalChunks; index++) {
          // 这个地方想办法修改

          const start = index * chunkSize;
          const end = Math.min(start + chunkSize, size);
          const chunk = uploadfile.slice(start, end);
          const chunkFile = new File([chunk], NewName);
          const formData = new FormData();
          formData.append("file", chunkFile);
          formData.append("sliceIndex", index);
          formData.append("totalSlices", totalChunks);
          formData.append("fileName", hash + NewName);
            formData.append("savefile", "fileList");
            formData.append("newname", name ? name : NewName);
          

          formData.append("tbxcode", this.NewCode.tbxcode);
          formData.append(
            "bxcode",
            this.NewCode.bxcode ? this.NewCode.bxcode : this.NewCode.tbxcode
          );
          formData.append("type", ACTION_TYPE);
          formData.append("fillname", this.Cookie_USER.realname1);

          // 上传分片,并处理上传成功的情况
          const promise = axios
            .post(baseURl_QiePian, formData, {
              headers: { "Content-type": "multipart/form-data" },
            })
            .then((response) => {
              uploadedChunks++;
              let progress = Math.round((uploadedChunks / totalChunks) * 100);
              let uploadCube = document.querySelector(`#item-${itemINdex}`);
              if (response.data.code == 200 && response.data.msg == "成功") {
                FileItem.progress = 100;
                if (uploadCube) {
                  uploadCube.innerText = `上传成功:${FileItem.progress}%`;
                }
                FileItem.status = "success";
                FileItem.AxiosUrl = response.data.data;

                if (this.ActionType == "编辑") {
                  this.$refs.editLOOK.gengxin();
                }
              } else if (
                response.data.code == 200 &&
                response.data.msg == "等待上传中"
              ) {
                FileItem.progress = progress;
                FileItem.status = "上传中";
                FileItem.AxiosUrl = "";
                if (uploadCube) {
                  uploadCube.innerText = `正在上传中:${FileItem.progress}%`;
                }
                this.$nextTick(() => {
                  console.log("这个是不是一直在执行", progress);
                  this.$refs.FileData.doLayout();
                });
              } else {
                FileItem.progress = progress;
                if (uploadCube) {
                  uploadCube.innerText = `上传失败:${FileItem.progress}%`;
                }
                FileItem.status = "failed";
                FileItem.AxiosUrl = "";
              }
            });
          promises.push(promise);
          // 控制并发数量
          if (promises.length >= concurrency || index === totalChunks - 1) {
            await Promise.all(promises);
            promises.length = 0; // 清空数组
          }
        }
        // 所有分片上传成功后将状态更新为 "success"
        // FileItem.status = "success";
        // 所有分片上传成功后触发合并请求
      } catch (error) {
        console.error("上传失败", error);
        // 处理错误
        // FileItem.status = "failed";
      }
    },
    // 生成一个长度为6的随机字符串,带时间戳
    generateRandomStringWithTimestamp(length) {
      const characters =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
      let result = "";
      const charactersLength = characters.length;

      for (let i = 0; i < length; i++) {
        const randomIndex = Math.floor(Math.random() * charactersLength);
        result += characters.charAt(randomIndex);
      }
      const timestamp = Date.now().toString();
      result += timestamp;

      return result;
    },
    congxinshangchuan(index, val) {
      val.progress = 0;
      val.status = "pending";
      val.AxiosUrl = "";

      this.upload_FN(index, val);
    },
    deleteRow_OK(index, val) {
      if (val.status == "success") {
        const loading = this.$loading({
          lock: true,
          text: "文件删除中。。。",
          spinner: "el-icon-loading",
          background: "rgba(0, 0, 0, 0.7)",
        });
        let obj = {
          tbxcode: this.NewCode.tbxcode,
          id: val.AxiosUrl,
        };
        let that = this;
        setTimeout(() => {
          let api = null;
          if (this.YM == "改变") {
            api = DeleteFuJian(obj);
          } else {
            api = DeleteBaoXianFuJian(obj);
          }

          api
            .then((res) => {
              if (res.code == 200) {
                that.fileList.splice(index, 1);
                if (this.ActionType == "编辑") {
                  this.$refs.editLOOK.gengxin();
                }
              } else {
                that.$notify.error({
                  title: "提示",
                  message: res.msg,
                });
              }
            })
            .finally(() => {
              loading.close();
            });
        }, 1500);
      } else {
        this.fileList.splice(index, 1);
      }
    },
    qingkong() {
      this.fileList = [];
    },
    downloadEvent(val) {
      const loading = this.$loading({
        lock: true,
        text: "文件准备中。。。",
        spinner: "el-icon-loading",
        background: "rgba(0, 0, 0, 0.7)",
      });
      let name = "";
      if (val.name.includes(".")) {
        const parts = val.name.split(".");
        name = parts[0];
      } else {
        name = val.name;
      }
      fetch(val.AxiosUrl)
        .then((response) => response.blob())
        .then((blob) => {
          loading.close();
          const blobUrl = URL.createObjectURL(blob);
          const a = document.createElement("a");
          a.href = blobUrl;
          a.download = name;
          a.click();
          URL.revokeObjectURL(blobUrl); // 释放URL对象
        })
        .catch((error) => {
          loading.close();
          this.$notify.error({
            title: "提示",
            message: "文件暂时不能下载",
          });
          console.error("文件下载失败:", error);
        });
    },
  },
};
</script>
<style scoped>
.el-upload {
  width: 100%;
  height: 100%;
}

.el-upload-dragger {
  width: 100%;
  height: 100%;
}
</style>

在这里插入图片描述

vue3

<template>
  <el-upload
    class="upload-demo"
    drag
    ref="upload"
    :auto-upload="false"
    :show-file-list="false"
    multiple
    :file-list="fileList"
    @change="handleChange"
  >
    <el-icon class="el-icon--upload"><upload-filled /></el-icon>
    <div class="el-upload__text">请拖入文件,<em>点击此处选择文件</em></div>
  </el-upload>
  <div
    style="width: 100%; margin: 10px 0; display: flex; justify-content: center"
  >
    <el-button color="#626aef" size="small" @click="upload_promises"
      >确认上传()</el-button
    >
    <el-button color="#626aef" size="small" @click="upload_promisesTwo"
      >确认上传()</el-button
    >
    <el-button color="#626aef" size="small" @click="onClick_UP_List"
      >确认上传{{ fileList.length }}个选择的附件</el-button
    >
  </div>
  <el-table :data="fileList" style="width: 100%" max-height="250" border>
    <el-table-column type="index" width="50" align="center" />
    <el-table-column
      prop="name"
      label="选项"
      show-overflow-tooltip
      align="center"
    />
    <el-table-column label="上传进度">
      <template #default="scope">
        <el-progress :percentage="scope.row.progress" />
        <div v-if="scope.row.status === 'failed'">
          <span style="color: red">上传失败</span>
        </div>
        <div v-if="scope.row.status === 'success'">
          <span style="color: #49af2f">上传成功</span>
        </div>
      </template>
    </el-table-column>
    <el-table-column fixed="right" label="操作" width="120">
      <template #default="scope">
        <el-button
          link
          type="primary"
          size="small"
          @click.prevent="deleteRow(scope.$index)"
        >
          删除
        </el-button>
      </template>
    </el-table-column>
  </el-table>
</template>
  <script setup>
import { ref, onMounted, nextTick } from "vue";
import { JcUploadFile, TXUploadFile } from "../api/JCNB/index";
import {CSUpload} from '../api/index'
import { ElMessage, ElLoading } from "element-plus";
import axios from "axios";
const emit = defineEmits(["submitOK"]);
const baseURL_JIE = "xxxxxx.com";
const baseURL_YANG='xxx.com'

// https://jc.jiuchang.work/api/server/JchrApi.ashx

const props = defineProps({
  limit: {
    type: Number,
    default: 1, //默认最大上传数量为1
  },
  upType: {
    type: String,
    default: "普通",
  },
});
let queryParams = ref({
  type: "普通",
});

// 唐
const upload_promisesTwo =async () => {
    let list = fileList.value;
  if (list.length > 0) {

    // 定义一个更新进度的回调函数
        // const onProgress = {
        //   headers: {
        //     "Content-Type": "multipart/form-data;charset=UTF-8",
        //   },
        //   onUploadProgress: (progressEvent) => {
        //     const progress = Math.round(
        //       (progressEvent.loaded / progressEvent.total) * 100
        //     ); // 更新上传进度百分比
        //     console.log("进度", progress);
        //     fileItem.progress = progress;
        //   },
        // };


    const promises = [];
    for (let i = 0; i < list.length; i++) {
      const fileItem = list[i];
      console.log("执行了", fileItem);
      if (fileItem.status === "pending") {
        fileItem.status = "uploading";
        const formData = new FormData();
        formData.append("file", fileItem.raw);
        formData.append("testing", "storage");
        formData.append("action", "up/qingjia");
        console.log("执行了??");

        const promise = axios
              .post(baseURL_YANG, formData, {
                onUploadProgress: (progressEvent) => {
                  const progress = Math.round(
                    (progressEvent.loaded * 100) / progressEvent.total
                  );
                  console.log("进度", progress);
                  fileItem.progress = progress;
                },
              })
              .then(() => {
                fileItem.status = "success";
              })
              .catch(() => {
                fileItem.status = "failed";
              });
        promises.push(promise);
      }
    }
    await Promise.all(promises);
  } else {
    ElMessage({
      message: `至少选择一个文件才能点击此按钮`,
      type: "warning",
    });
  }
};

// 张
const upload_promises = async () => {
  let list = fileList.value;
  if (list.length > 0) {
    const promises = [];
    for (let i = 0; i < list.length; i++) {
      const fileItem = list[i];
      console.log("执行了", fileItem);
      if (fileItem.status === "pending") {
        fileItem.status = "uploading";
        const formData = new FormData();
        formData.append("file", fileItem.raw);
        formData.append("testing", "storage");
        formData.append("action", "up/qingjia");
        console.log("执行了??");

        const promise = axios
              .post(baseURL_JIE, formData, {
                onUploadProgress: (progressEvent) => {
                  const progress = Math.round(
                    (progressEvent.loaded * 100) / progressEvent.total
                  );
                  console.log("进度", progress);
                  fileItem.progress = progress;
                },
              })
              .then(() => {
                fileItem.status = "success";
              })
              .catch(() => {
                fileItem.status = "failed";
              });
        promises.push(promise);
      }
    }
    await Promise.all(promises);
  } else {
    ElMessage({
      message: `至少选择一个文件才能点击此按钮`,
      type: "warning",
    });
  }
};

onMounted(() => {
  queryParams.value.type = props.upType;
  console.log(queryParams.value.type);
});
// 删除选择的文件
const deleteRow = (val) => {
  fileList.value.splice(val, 1);
};
const upload = ref(null);
const fileList = ref([]);
const handleChange = (file, e) => {
  // console.log('文件',file)
  let list = e.map((item) => {
    item.progress = 0;
    item.status = "pending";
    return item;
  });
  console.log("文件e", list);
  fileList.value = list;
};
// 点击某个文件移除时
const handleRemove = (e, list) => {
  // console.log("文件e", e);
  // console.log("文件list", list);
  fileList.value = list;
};
// 文件超出
const handleExceed = (uploadFile, uploadFiles) => {
  // console.log("文件e", uploadFile);
  // console.log("文件e", uploadFiles);
  ElMessage({
    message: `文件最大上传个数是:${uploadFiles.length}个文件`,
    type: "warning",
  });
};

const onClick_UP_List = () => {
  let list = fileList.value;
  if (list.length > 0) {
    const loading = ElLoading.service({
      lock: true,
      text: "附件上传操作中。。。",
      background: "rgba(0, 0, 0, 0.7)",
    });
    let promises = list.map((item) => submitUpload(item.raw));
    Promise.all(promises)
      .then((res) => {
        // console.log("res", res);
        emit("submitOK", res);
      })
      .finally(() => {
        loading.close();
      });
  } else {
    ElMessage({
      message: `至少选择一个文件才能点击此按钮`,
      type: "warning",
    });
  }
};

const submitUpload = (file) => {
  return new Promise((resolve, reject) => {
    if (queryParams.value.type == "普通") {
      const formData = new FormData();
      formData.append("file", file);
      // formData.append("testing", "storage"); //测试的时候这个字段放出来,但是发布的时候需要注销
      formData.append("action", "up/qingjia");
      JcUploadFile(formData)
        .then((res) => {
          let obj = {
            name: file.name,
            data: res.data,
          };
          resolve(obj);
        })
        .catch((error) => {
          reject();
        });
    } else {
      // 特殊的
      const formData = new FormData();
      formData.append("file", file);
      // formData.append("testing", "storage"); //测试的时候这个字段放出来,但是发布的时候需要注销
      formData.append("action", "up/permit/file");
      TXUploadFile(formData)
        .then((res) => {
          let obj = {
            name: file.name,
            msg: res.msg,
            code: res.code,
            data: res.data,
          };
          resolve(obj);
        })
        .catch((error) => {
          reject();
        });
    }
  });
};
</script>

在这里插入图片描述

这个是一个批量切片上传文件的demo,切片大小自己选择,有100kb,500kb,1M三种切片规格

<template>
  <el-upload
    drag
    ref="upload"
    :auto-upload="false"
    :show-file-list="false"
    multiple
    :file-list="fileList"
    @change="handleChange"
  >
    <!-- <el-icon class="el-icon--upload"><upload-filled /></el-icon> -->
    <div class="el-upload__text">请拖入文件,<em>点击此处选择文件</em></div>
  </el-upload>
  <div
    style="width: 100%; margin: 10px 0; display: flex; justify-content: center"
  >
    
    <el-button color="#36d" size="small" @click="upload_dataFileTwoList('0.1')"
      >确认上传(0.1)</el-button
    >
    <el-button color="#36d" size="small" @click="upload_dataFileTwoList('0.5')"
      >确认上传(0.5)</el-button
    >
    <el-button color="#36d" size="small" @click="upload_dataFileTwoList('1')"
      >确认上传(1)</el-button
    >
  </div>
  <el-table :data="fileList" style="width: 100%" max-height="250" border>
    <el-table-column type="index" width="50" align="center" />
    <el-table-column
      prop="name"
      label="选项"
      show-overflow-tooltip
      align="center"
    />
    <el-table-column label="上传进度">
      <template #default="scope">
        <el-progress :percentage="scope.row.progress" />
        <div v-if="scope.row.status === 'failed'">
          <span style="color: red">上传失败</span>
        </div>
        <div v-if="scope.row.status === 'success'">
          <span style="color: #49af2f">上传成功</span>
        </div>
      </template>
    </el-table-column>
    <el-table-column fixed="right" label="操作" width="120">
      <template #default="scope">
        <el-button
          link
          type="primary"
          size="small"
          @click.prevent="deleteRow(scope.$index)"
        >
          删除
        </el-button>
      </template>
    </el-table-column>
  </el-table>
</template>
  <script setup>
import { ref, onMounted, nextTick } from "vue";
// import { JcUploadFile, TXUploadFile } from "../api/JCNB/index";
import { ElMessage, ElLoading } from "element-plus";
import axios from "axios";
const emit = defineEmits(["submitOK"]);
const baseURl_QiePian='xxxxxx.com'
const props = defineProps({
  limit: {
    type: Number,
    default: 1, //默认最大上传数量为1
  },
  upType: {
    type: String,
    default: "普通",
  },
});
let queryParams = ref({
  type: "普通",
});
const upload_dataFile = async () => {
  let fileData = fileList.value[0];
  // name 上传文件的名称  size 上传文件的大小 uploadfile 文件的raw
  let { name, size, raw: uploadfile } = fileData;

  // 第一步:检查分片
  let index = 0; //默认分片数量0
  // const {data}=await axios.post(baseURL_YANG,{'文件名称'})
  // data的结构 : {code:200,data:{index:15},msg:'查询成功'}
  // if(data.code==200){
  //   index=data.data.index;  // 返回 0 表示没有上传过,不需要断点续传
  // }

  // 第二步:分片上传
  //分片大小
  let chunkSize = 0.1 * 1024 * 1024; //100kb  可以自己修改  尽量不要太大,5M已经算很大的了  还要考虑带宽,我这个很垃圾才1M带宽,所以这写1M就很卡
  let startSize = 0; //默认开始尺寸
  startSize = chunkSize * index;
  const promises = [];
  while (startSize < size) {
    // 对上传文件进行拆分
    let box = null;
    if (startSize + chunkSize > size) {
      box = uploadfile.slice(startSize, size);
    } else {
      box = uploadfile.slice(startSize, startSize + chunkSize);
    }
    startSize += chunkSize;
    console.log(box);
    //数据转换
    let boxFile = new File([box], name); //把这一片的切片内容转换成file文件然后传给后台
    let formData = new FormData();
    formData.append("index", index); //分片数量
    formData.append("file", boxFile);
    // //请求
    // let res =await axios.post(baseURL_YANG,formData,{
    //   headers:{'Content-type':'multipart/form-data'}
    // });
    // console.log(res)
    // index+=1;//到这第一片分片已经上传了,接下来上传下一个分片
    const promise = axios.post(baseURL_YANG, formData, {
      headers: { "Content-type": "multipart/form-data" },
    });
    promises.push(promise);
    index += 1;
  }
  try {
    const responses = await Promise.all(promises);
    console.log(responses);
    // 在这里处理所有上传请求的响应
  } catch (error) {
    console.error(error);
    // 处理错误
  }

  // 第三步:合并分片
  // 发送合并请求
};



const upload_dataFileTwoList = async (val) => {
  for (let i = 0; i < fileList.value.length; i++) {
    let list = fileList.value[i];
    let qiepian=0
    if(val=='0.1'){
      qiepian=0.1
    }else if(val=='0.5'){
      qiepian=0.5
    }else{
      qiepian=1
    }
    upload_FN(list,qiepian);
  }
};
const upload_FN = async (FileItem,qiepian) => {
  try {
    let { name, size, raw: uploadfile} = FileItem;
    let uploadedChunks = 0; // 已上传的分片数量

    // 设置分片大小和总分片数量
    // const chunkSize = 0.1 * 1024 * 1024; // 1MB
    const chunkSize = qiepian * 1024 * 1024; // 100kb  500kb 1M  可以自己修改  尽量不要太大,5M已经算很大的了  还要考虑带宽,我这个很垃圾才1M带宽,所以这写1M就很卡

    const totalChunks = Math.ceil(size / chunkSize);

    // 限制并发上传数量,可根据需求调整
    const concurrency = 3; // 同时处理的 Promise 数量
    const promises = [];

    // 循环上传分片
    for (let index = 0; index < totalChunks; index++) {
      const start = index * chunkSize;
      const end = Math.min(start + chunkSize, size);
      const chunk = uploadfile.slice(start, end);
      const chunkFile = new File([chunk], name);
      const formData = new FormData();
      formData.append("sliceIndex", index);//当前上次切片的索引
      formData.append("file", chunkFile); //当前切片的fiel文件
      formData.append("totalSlices", totalChunks);  //总共有多少切片
      formData.append("fileName", name);  //文件的名称
      formData.append("address", '测试');  //上传到服务器哪个文件夹
      // 上传分片,并处理上传成功的情况
      const promise = axios.post(baseURl_QiePian, formData, {
        headers: { "Content-type": "multipart/form-data" },
      }).then((response) => {
        uploadedChunks++;
        FileItem.progress = Math.round((uploadedChunks / totalChunks) * 100);
        if(FileItem.progress==100){
          console.log('文件上传后在这进行文件路径赋值', FileItem.progress,FileItem.name)
        }
      });
      promises.push(promise);
      // 控制并发数量
      if (promises.length >= concurrency || index === totalChunks - 1) {
        await Promise.all(promises)
        promises.length = 0; // 清空数组
      }
    }
/// status 是当前文件的一个状态  值有3种:pending 可以上传  uploading上传中 success上传成功 failed上传失败
    // 所有分片上传成功后将状态更新为 "success"
    FileItem.status = "success";
    // 所有分片上传成功后触发合并请求
  } catch (error) {
    console.error('上传失败', error);
    // 处理错误
    FileItem.status = "failed";
  }
};



onMounted(() => {
  queryParams.value.type = props.upType;
  console.log(queryParams.value.type);
});
// 删除选择的文件
const deleteRow = (val) => {
  fileList.value.splice(val, 1);
};
const upload = ref(null);
const fileList = ref([]);
const handleChange = (file, e) => {
  // console.log('文件',file)
  let list = e.map((item) => {
    item.progress = 0;
    item.status = "pending";
    return item;
  });
  // console.log("文件e", list);
  fileList.value = list;
};
</script>

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

曾不错吖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值