美文网首页crudapi-admin-web
「免费开源」基于Vue和Quasar的前端SPA项目crudap

「免费开源」基于Vue和Quasar的前端SPA项目crudap

作者: crudapi | 来源:发表于2021-06-22 10:55 被阅读0次

    基于Vue和Quasar的前端SPA项目实战之文件上传(十)

    回顾

    通过之前一篇文章 基于Vue和Quasar的前端SPA项目实战之数据导入(九)的介绍,实现了业务数据批量导入功能,本文主要介绍文件上传相关内容。

    简介

    crudapi支持附件字段,表字段里面保存的是文件url字符串。附件可以通过其它文件管理系统比如阿里云的OSS进行上传,或者使用系统自带的文件管理API进行上传,包括普通文件上传和大文件切片上传两种方式。

    UI界面

    文件上传

    文件上传

    大文件上传

    大文件上传

    API

    文件上传API

    文件上传API,包括普通文件上传和大文件切片两个功能,具体的通过swagger文档可以查看。通过axios封装api,名称为file

    import { axiosInstance } from "boot/axios";
    
    const HEADERS = {
      "Content-Type": "multipart/form-data"
    };
    
    const file = {
      upload: async function(data, progressCallback) {
        console.log("file->upload")
        return axiosInstance.post(`/api/file` , data,
          {
            headers: HEADERS,
            onUploadProgress:  (progressEvent) => {
              if (progressCallback) {
                progressCallback(progressEvent)
              }
            }
        });
      },
      bigUpload: async function(data, progressCallback) {
        console.log("file->bigUpload")
        return axiosInstance.post(`/api/file/big` , data,
          {
            headers: HEADERS,
            onUploadProgress:  (progressEvent) => {
              if (progressCallback) {
                progressCallback(progressEvent)
              }
            }
        });
      }
    };
    
    export { file };
    

    核心代码

    CFile组件

     <q-toggle v-model="enableBigFile" label="开启大文件上传模式" />
    
      <div v-show="!enableBigFile" class="q-py-md">
        <q-file v-model="normalFile" label="请选择文件(普通上传)">
          <template v-slot:prepend>
            <q-icon name="attach_file" />
          </template>
          <template v-slot:after>
            <q-btn round dense flat icon="send" @click="onSubmitClick" />
          </template>
        </q-file>
      </div>
    
      <div v-show="enableBigFile" class="q-py-md">
        <q-file v-model="bigFile" @input="bigFileAdded" label="请选择文件(大文件上传)">
          <template v-slot:prepend>
            <q-icon name="attach_file" />
          </template>
          <template v-slot:after>
            <q-btn round dense flat icon="flight_land" @click="onBigSubmitClick" />
          </template>
        </q-file>
      </div>
    

    通过toggle切换上传模式,如果是小文件采用普通的方式即可。

    普通上传

    async onSubmitClick() {
      console.info("CFile->onSubmitClick");
    
      if (!this.normalFile) {
        this.$q.notify({
          message: '请选择文件!',
          type: 'warning'
        });
        return;
      }
    
      this.$q.loading.show({
        message: "上传中"
      });
    
      try {
        let form = new FormData()
        form.append('file', this.normalFile);
    
        this.fileInfo = await fileService.upload(form, (e)=> {
          console.info(e);
        });
        this.$q.loading.hide();
        this.$emit("input", this.fileInfo);
      } catch (error) {
        this.$q.loading.hide();
        console.error(error);
      }
    }
    

    大文件切片上传

    bigFileAdded(f) {
      console.info("CFile->fileAdded");
    
      if (!f) {
        console.info("CFile->cancel");
        return;
      }
    
      this.$q.loading.show({
        message: "文件准备中"
      });
    
      FileMd5(f, this.chunkSize, (e, md5) => {
        this.md5 = md5;
        console.info(e);
        console.info(md5);
        this.$q.loading.hide();
      });
    },
    
    async onBigSubmitClick() {
      console.info("CFile->onBigSubmitClick");
    
      if (!this.bigFile) {
        this.$q.notify({
          message: '请选择文件!',
          type: 'warning'
        });
        return;
      }
    
    
      this.$q.loading.show({
        message: "上传中"
      });
    
      try {
        let chunks = this.getChunks();
    
        let reqs = [];
        for (let i = 0; i < chunks; ++i) {
          reqs.push(this.uploadWithBlock(i));
        }
    
        await Promise.all(reqs)
        .then((datas) => {
          console.info(datas);
          this.checkFinished(datas);
        });
      } catch (error) {
        this.$q.loading.hide();
        console.error(error);
      }
    }
    

    大文件如果采用普通的上传方式,可能由于网络的原因速度比较慢,而且不稳定,所以采用切片的方式进行多线程上传。具体原理如下:首先计算文件MD5,后台会根据MD5唯一确定是同一个文件,同一个文件的不同block根据大小和偏移量会写在相同文件对应的位置,当最后一个block上传成功后,表示上传结束。分片大小默认为20MB,可以配置为需要的值,前端通过Promise.all的ajax调用方式可以实现多线程同时上传。

    文件表为例

    文件表
    文件表的“链接”字段设置类型为“附件ATTACHMENT”,添加业务数据页面会自动采用CFile组件。 大文件上传demo
    选择大文件之后,点击上传图标,通过chrome网络请求发现,多线程分片上传模式已经启动,上传结束之后可以查看下载。

    小结

    本文主要介绍了文件上传功能,包括普通上传模式和大文件切片上传模式,大文件切片上传模式通过优化后很容易支持断点续传和秒传,后续会根据需求优化文件上传功能。

    demo演示

    官网地址:https://crudapi.cn
    测试地址:https://demo.crudapi.cn/crudapi/login

    附源码地址

    GitHub地址

    https://github.com/crudapi/crudapi-admin-web

    Gitee地址

    https://gitee.com/crudapi/crudapi-admin-web

    由于网络原因,GitHub可能速度慢,改成访问Gitee即可,代码同步更新。

    相关文章

      网友评论

        本文标题:「免费开源」基于Vue和Quasar的前端SPA项目crudap

        本文链接:https://www.haomeiwen.com/subject/qtbpyltx.html