【vue2+avue】实现文件上传 技术栈用的是kkfileview

前言:avue实现原文件上传是有格式限制的,且预览展示效果稍微差点,我使用kkfileview去写,这样不会限制文件上传格式

1、kkfileview使用参考我另一篇文章【kkFileView】文件文档在线预览解决方案,基本支持主流办公文档的在线预览,如doc,docx,xls,xlsx,ppt,pptx,pdf,txt,zip,rar,图片,视频,音频等等_^草莓牛乳茶^的博客-CSDN博客

2、全部代码展示

javascript 复制代码
<template>
  <basic-container>
    <avue-crud ref="crud" 
               v-model="form" 
               :before-open="beforeOpen"
               :data="data" 
               :option="option"
               :page.sync="page"
               :permission="permissionList"
               :table-loading="loading"  
               :upload-after="uploadAfter"
               :upload-before="uploadBefore"
               :upload-delete="uploadDelete" 
               :upload-preview="uploadPreview"
               @row-update="rowUpdate"
               @row-save="rowSave"
               @row-del="rowDel" 
               @search-change="searchChange" 
               @search-reset="searchReset" 
               @selection-change="selectionChange"
               @current-change="currentChange"
               @size-change="sizeChange"
               @on-load="onLoad">
      <template slot="fileName" slot-scope="{ type, size, row }">
        <div class="download">
          <div v-for="(item, index) in row.fileLocation" :key="index">
            <el-tooltip :content="item.name" class="item" effect="dark 
                         placement="bottom">
              <div @click="downloadAnnex(row.fileLocation[index], item)">
                {{ item.name }}
              </div>
            </el-tooltip>
          </div>
        </div>
    </avue-crud>
    <showFile ref="showFileList" :fileLocationName="fileLocationName" 
             :fileUpdata="fileUpdata"></showFile>
  </basic-container>
</template>


<script>
import { add, getDetail, getList, remove, update, upspecialdata } from "@/api/safety/administration/safetylicense";
import { mapGetters } from "vuex";
import showFile from "../../safety/showFile.vue";
import safetydivicecloseopenshrecord from "@/views/public/safetydivicecloseopenshrecord.vue";
import { updateFileLocation } from "@/mixins/update-file-location"

export default {
  components: {
    showFile,
  },
  mixins: [updateFileLocation],
  data() {
      fileUpdata: "fileName",       // 表格显示时用
      fileLocationName: "fileLocation",   // 附件本字段
      form: {},
      query: {},
      loading: true,
      page: {
        pageSize: 10,
        currentPage: 1,
        total: 0,
      },
      selectionList: [],
      option: {
        height: "auto",
        calcHeight: 210,
        searchShow: true,
        searchMenuSpan: 6,
        tip: false,
        border: true,
        index: true,
        viewBtn: true,
        selection: true,
        labelWidth: 140,
        column: [
          {
            label: "许可证照上传",
            prop: "fileLocation",
            type: "upload",
            dataType: "object",
            showFileList: true,
            showColumn: false,
            multiple: true,
            drag: false,
            loadText: "附件上传中,请稍等",
            previewSrcList: false,
            propsHttp: {
              name: "originalName",
              url: "link",
              res: "data",
              // home: "domain",
            },
            props: {
              label: 'name',
              value: 'link'
            },
            action: "/api/blade-resource/oss/endpoint/put-file-attach",
            span: 24, rules: [{
              required: true,
              message: "请输入附件",
              trigger: "blur"
            }]


          },

          {
            label: "文件预览",
            prop: "fileName",
            display: false,
            showColumn: true,
            rules: [
              {
                required: true,
                message: "请输入文件名称",
                trigger: "blur",
              },
            ],
          },
          },
        ],
      },
      data: [],
    };
  },

  methods: {
    shrecordfun(row, index) {
      this.closeoropenid = row.id;
      this.shrecordVisible = true;
    },

    // 是否点击放大图片
    uploadPreview(file, column, done) {
      this.$nextTick(() => {
        /**
         * e:文件路径
         * k:源文件名字
         */
        this.$refs.showFileList.downloadAnnex(file.url || file.link, file.name);//调用组件方法
      });
    },
    // 预览方法
    downloadAnnex(e, k) {
      this.$nextTick(() => {
        this.$refs.showFileList.downloadAnnex(e.url || e.link, k);//调用组件方法
      });
    },
    // 上传前方法
    uploadBefore(file, done, loading, column) {
      done()
    },
    // 上传后方法
    uploadAfter(res, done, loading, column) {
      this.form[this.fileLocationName] = this.formFileLocation(res, this.fileLocationName)
      done()
    },
    // 删除前的方法
    uploadDelete(file, column) {
      this.$nextTick(() => {
        this.$refs.showFileList.frontUploadDelete(file, column); //调用组件方法
      });
    },

// 新增数据调取接口
    rowSave(row, done, loading) {
      row[this.fileLocationName] = JSON.stringify(row[this.fileLocationName])
      // 结束
      add(row).then(
        () => {
          done();
          this.onLoad(this.page);
          this.$message({
            type: "success",
            message: "操作成功!",
          });
        },
        (error) => {
          window.console.log(error);
          loading();
        }
      );
    },

// 编辑数据调取接口
    rowUpdate(row, index, done, loading) {
      // 修改事件
      // row[this.tableDisplay] = ""; //表格显示的字段
      row[this.fileLocationName] = JSON.stringify(row[this.fileLocationName])
      // 结束
      update(row).then(
        () => {
          done();
          this.onLoad(this.page);
          this.$message({
            type: "success",
            message: "操作成功!",
          });
        },
        (error) => {
          window.console.log(error);
          loading();
        }
      );
    },
// 点击查看/编辑查看数据
    beforeOpen(done, type) {
      this.$nextTick(() => {
        this.$refs.showFileList.add(type);//调用组件方法
      });
      if (["edit", "view"].includes(type)) {

        getDetail(this.form.id).then((res) => {
          this.form = this.formData(res, this.fileLocationName)
        });
      }
      done();
    },
    searchReset() {
      this.query = {};
      this.onLoad(this.page);
    },
    searchChange(params, done) {
      this.query = params;
      this.page.currentPage = 1;
      this.onLoad(this.page, params);
      done();
    },
    selectionChange(list) {
      this.selectionList = list;
    },
    selectionClear() {
      this.selectionList = [];
      this.$refs.crud.toggleSelection();
    },
    currentChange(currentPage) {
      this.page.currentPage = currentPage;
      this.onLoad(this.page);
    },
    sizeChange(pageSize) {
      this.page.pageSize = pageSize;
    },

// 页面初始数据加载
    onLoad(page, params = {}) {
      this.loading = true;
      params.mytype = "3";
      getList(
        page.currentPage,
        page.pageSize,
        Object.assign(params, this.query)
      ).then((res) => {
        const data = res.data.data;
        this.page.total = data.total;
        this.data = this.dataRecords(data, this.fileLocationName)
        this.loading = false;
        this.selectionClear();
      });
    },
  },

注意:

文件上传:

1)、type:'upload'

2)、dataType配置数据的结构stringobject,

dataType配置为object时,可以配置props存储的数据结构

  • label图片的名称
  • value路径地址

3)、propsHttp配置请求接口返回的数据结构

  • name图片的名称
  • url路径地址
  • res返回数据层级结构
  • home相对路径的主路径

意思就是你配置dataType为object,传给后台:json数据格式

eg:****"[{\"name\":\"原平经济技术开发区化工园区禁限控目录.pdf\",\"link\":\"/261267-sksoft/upload/20230828/8855ad3f839c2831c2c07c9f8f645af6.pdf\"}]"

字段回显就会是中文,不需要自己在单独处理数据

4)、action:是上传文件调取的接口

5)、showfile文件是我写的公共的上文件组件 不使用原生的预览样式,自己封装的

6)、rowUpdate - rowSave - beforeopen - onLoad页面中使用的方法是我封装的mixins的方法

7)、fileLocationName定义的是上传文件的给后端传接口的字段名字,因为名字不同所以写了这个来定义

3、showfile文件

javascript 复制代码
<template>
  <div>
// 不使用avue原生的预览样式
    <el-dialog title="预览与下载" :visible.sync="dialogVisible" width="60%" :fullscreen="dialogFull"
      :before-close="handleClose" :append-to-body="true" :modal-append-to-body="false">
      <template slot="title">
        <div class="avue-crud__dialog__header">
          <span class="el-dialog__title">
            <span style="
                display: inline-block;
                background-color: #3478f5;
                width: 3px;
                height: 20px;
                margin-right: 5px;
                float: left;
                margin-top: 2px;
              "></span>
            预览与下载
          </span>
          <div class="avue-crud__dialog__menu" @click="dialogFull ? (dialogFull = false) : (dialogFull = true)">
            <i class="el-icon-full-screen"></i>
          </div>
        </div>
      </template>
      <div class="dialogVisible">
        <div class="dialogVisible_left">
          <!-- <img  class="imgurl" :src="imgurl" /> -->
          <iframe id="frmDialog" frameborder="0" width="100%" height="750rpx" allowfullscreen="true"
            :src="pdfWord"></iframe>
        </div>
      </div>
      <span slot="footer" class="dialog-footer">
        <el-button @click="handleClose">取 消</el-button>
        <el-button type="primary" @click="dialogVisibleDow">下载</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
export default {
  props: {
    tableDisplay: String,
    fileUpdata: String,
    fileLocationName: String
  },
  data() {
    return {
      dialogFull: false,
      dialogVisible: false,
      pdfWord: "",
      imgurl: "",
      flieName: [],
      fileUrl: [],
      dowName: "",
      addName: [],
      annexStrList: [],
      demoDel: [],
      btnAnnexStrList: []
    };
  },
  methods: {
    // 全屏
    handleClose(done) {
      this.dialogVisible = false
      this.dialogFull = false,
        done();
    },
    // 文件预览
    downloadAnnex(e, data) {
      this.dowName = data;
      // let KKFILEIP = "线上地址";
      let KKFILEIP = "http://127.0.0.1";
      // const fileurl =""
      // if(e.indexOf(window.location.origin)>=0){
      //   fileurl =e
      // }else{
      //   fileurl = window.location.origin + e;
      // }
      // const fileurl = window.location.origin + e;
      // const fileurl = '地址' + e;
      const fileurl = '测试地址' + e;
      console.log(fileurl, 'fileurl');
      this.imgurl = fileurl;
      this.pdfWord =
        KKFILEIP +
        // ":10001/preview/onlinePreview?url=" +
        ":8012/onlinePreview?url=" +
        encodeURIComponent(Base64.encode(fileurl));
      this.dialogVisible = true;
    },
    // 下载图片
    dialogVisibleDow() {
      getBlob(this.imgurl).then((blob) => {
        saveAs(blob, this.dowName);
      });
      function getBlob(url) {
        return new Promise((resolve) => {
          const xhr = new XMLHttpRequest();
          xhr.open("GET", url, true);
          xhr.responseType = "blob";
          xhr.onload = () => {
            if (xhr.status === 200) {
              resolve(xhr.response);
            }
          };
          xhr.send();
        });
      }
      function saveAs(blob, filename) {
        const elelink = document.createElement("a");
        elelink.style.display = "none";
        elelink.download = filename;
        elelink.href = window.URL.createObjectURL(blob);
        document.body.appendChild(elelink);
        elelink.click();
        document.body.removeChild(elelink);
      }
    },
    // 上传前方法
    frontUploadBefore(file, done, loading, column) {
      this.flieName.push(file.name);
      done();
    },
    // 上传后方法
    behindUploadAfter(res, done, loading, column) {
      if (this.annexStrList[0] == "" || this.annexStrList[0] == ",") {
        this.annexStrList = []
      }
      let a = { url: res.link, name: res.originalName }
      // // this.addName.push(res.link + "-" + res.originalName)
      this.addName.push(a)
      this.annexStrList.push(a.url)
      done();
    },
    // 删除前的方法
    frontUploadDelete(file, column) {
      this.fileUrl.push(file.url);
      this.demoDel.push(this.annexStrList[file.uid])
      this.annexStrList.splice(file.uid, 1)
    },
    // 
    //打开时候要执行的东西
    add(type) {
      this.addName = [];
      this.demoDel = [];
      if (type == "add") {
        this.flieName = [];
      }
    },
    addRes(res) {
      if (res.data.data[this.tableDisplay]) {
        let filelist = JSON.parse(res.data.data[this.tableDisplay]);
        let alist = [];
        for (let i = 0; i < filelist.length; i++) {
          let b = { name: filelist[i].name, url: filelist[i].url }
          alist.push(b);
        }
        this.annexStrList = alist
        return alist;
      }

    },

    flieNameList() {
      return this.flieName
    },
    fileUrlList() {
      this.fileUrl = []

    },
    demoDelList() {
      return this.demoDel.toString();

    },
    addNameList() {
      return JSON.stringify(this.addName)
    },
    annexStrNameList() {
      return this.annexStrList.toString()
    },
    annexStrNameListView() {
      return this.annexStrList

    },
    //初始加载
    flieOnload(data) {
      for (let i = 0; i < data.records.length; i++) {
        let allName = [];
        if (data.records[i][this.tableDisplay]) {
          data.records[i][this.tableDisplay] = data.records[i][this.tableDisplay].split(",");
          let arr = data.records[i][this.tableDisplay];
          for (let j = 0; j < arr.length; j++) {
            let index = arr[j].indexOf("-");
            let list = arr[j].substring(index + 1, arr[j].length);
            allName.push(list.toString());
          }
          data.records[i][this.fileUpdata] = allName;
          data.records[i][this.fileLocationName] = data.records[i][this.fileLocationName].split(",");
        }
      }
    },
  },
};
</script>


<style scoped lang="scss">
/*  dialog*/
.el-dialog__header {
  padding: 15px 20px 15px;
}

.el-dialog__headerbtn {
  top: 15px;
}

/*dialog header*/
/deep/.el-dialog__header {
  background: #e3eaed;
}

/deep/.avue-crud__dialog__header {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-align: center;
  -ms-flex-align: center;
  align-items: center;
  -webkit-box-pack: justify;
  -ms-flex-pack: justify;
  justify-content: space-between;
}

/deep/.el-dialog__title {
  color: rgba(0, 0, 0, 0.85);
  font-weight: 500;
  word-wrap: break-word;
}

/deep/.avue-crud__dialog__menu {
  padding-right: 20px;
  float: left;
}

/deep/.avue-crud__dialog__menu i {
  color: #909399;
  font-size: 15px;
}

/deep/.el-icon-full-screen {
  cursor: pointer;
}

/deep/.el-icon-full-screen:before {
  content: "\e719";
}

.download {
  color: rgb(50, 185, 226);
}

.dialogVisible {
  display: flex;
}

.dialogVisible_right {
  width: 50%;
}

.dialogVisible_left {
  width: 100%;
}

.imgurl {
  height: 100%;
  width: 100%;
}
</style>

注意:这一块代码可能会有点乱,vue页面 有上传前,上传后方法就不会使用shoefile文件的方法,showfile页面的方法是针对图片上传的方法

4、updateFileLocation文件

javascript 复制代码
export const updateFileLocation = {
  methods: {
    formFileLocation(res, fileLocationName) {
      let a = [
        ...this.form[fileLocationName],
        {
          name: res.originalName,
          link: res.link,
        },
      ]
      return a
    },
    isJSON(data) {
      try {
        JSON.parse(data)
        return true
      } catch (error) {
        return false
      }
    },
    formData(res, fileLocationName) {
      let b = this.isJSON(res.data.data[fileLocationName])
        ? JSON.parse(res.data.data[fileLocationName])
        : ''
      return b
    },
    dataRecords(data, fileLocationName) {
      return data.records.map((i) => {
        const obj = this.isJSON(i[fileLocationName])
          ? JSON.parse(i[fileLocationName])
          : ''
        i[fileLocationName] = obj || null
        return i
      })
    },
  },
}
相关推荐
魏大帅。2 分钟前
Axios 的 responseType 属性详解及 Blob 与 ArrayBuffer 解析
前端·javascript·ajax
花花鱼9 分钟前
vue3 基于element-plus进行的一个可拖动改变导航与内容区域大小的简单方法
前端·javascript·elementui
k093312 分钟前
sourceTree回滚版本到某次提交
开发语言·前端·javascript
EricWang135834 分钟前
[OS] 项目三-2-proc.c: exit(int status)
服务器·c语言·前端
September_ning34 分钟前
React.lazy() 懒加载
前端·react.js·前端框架
web行路人44 分钟前
React中类组件和函数组件的理解和区别
前端·javascript·react.js·前端框架
番茄小酱0011 小时前
Expo|ReactNative 中实现扫描二维码功能
javascript·react native·react.js
子非鱼9211 小时前
【Ajax】跨域
javascript·ajax·cors·jsonp
超雄代码狂1 小时前
ajax关于axios库的运用小案例
前端·javascript·ajax
长弓三石1 小时前
鸿蒙网络编程系列44-仓颉版HttpRequest上传文件示例
前端·网络·华为·harmonyos·鸿蒙