1. 文件上传(图片、word,ppt,pdf,excel,txt等文件流)

总结一下上传组件的思路

  • input标签的@change事件

  • 通过input标签的@change事件的绑定,进行文件的选择上传,获取到文件const uploadFile = file.target.files[0],然后通过文件流转为base64,然后可以在前端进行预览。

  • 预览只有图片和PDF

  • 预览的文件不多,只有img,和pdf的可以预览,这和浏览器可以打开的文件流有关,前端能做到的预览只有图片和PDF,像word、和ppt、excel等不可前端预览,需要后端解析,重新返回相应地址方可预览

  • word、和ppt、excel的预览需要后端做出相应的处理,这些文件返回的地址是处理过的,预览地址和下载地址是不一样的

  • 后端给的文件地址必须公网

  • 微软解析地址:https://view.officeapps.live.com/op/view.aspx?src=你的文件地址

  • 上传的子组件

<template>
  <div class="addAttachments">
    <el-dialog title="上传附件" v-model="dialogFormVisible" >
      <div class="upload-wrap">
        <input
          class="input"
          type="file"
          ref="uploadInput"
          @change="handleChange($event,photoName)"
        />
        <el-button type="primary" size="small"  @click="submitClick">选择文件</el-button>
      </div>
      <!-- 上传的内容 -->
      <div class="addAttachments-content">
        <el-table :data="gridData" height="400"  v-loading="loading" element-loading-text="图片上传中"
    element-loading-spinner="el-icon-loading"
    element-loading-background="rgba(0, 0, 0, 0.8)">
        <el-table-column property="name" label="名称" ></el-table-column>
        <el-table-column property="localsize" label="大小" width="200">
          <template #default="scope">
            <span >
              {{formatMoney(scope.row.localsize)}}kb
            </span>
          </template>
        </el-table-column>
        <!-- 由于文件未真正上传,所以无法预览word、ppt文档,所以预览功能暂时先隐藏 -->
        <!-- <el-table-column property="localurl" label="地址" width="200">
          <template #default="scope">
            <el-button @click.prevent="previewClick(scope.row)" size="small">
              预览
            </el-button>
          </template>
        </el-table-column> -->
        <el-table-column property="address" label="操作">
          <template #default="scope">
            <el-button @click.prevent="deletefileClick(scope.$index)"
               size="small">
              删除
            </el-button>
          </template>
        </el-table-column>
      </el-table>
      </div>
      <!-- 底部按钮 -->
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="cancelSubmit">取 消</el-button>
          <el-button type="primary" @click="submitClick" >确认上传</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script>
import { apifileupload } from '@/js/fileUpload/fileUpload.js'
import commFunction from '@/common/js/commFunction.js'

export default {
  data () {
    return {
      gridData: [],
      dialogFormVisible: false,
      loading: false
    }
  },
  methods: {
    // 打开上传的控件
    openaddattachments () {
      this.dialogFormVisible = true
    },
    // 选择文件上传
    handleChange (file, wrap) {
      const uploadFile = file.target.files[0]
      const fileSize = uploadFile.size / 1024
      // const fileSize = uploadFile.size / 1024 / 1024
      const fileName = file.target.files[0].name
      this.transferImgToBase64(uploadFile, res => {
        const localobjfile = {
          name: fileName,
          localsize: fileSize,
          localurl: res
        }
        this.gridData.push(localobjfile)
        // this.$refs.uploadInput.value = ''
      })
    },
    // base64转换
    transferImgToBase64 (files, cb) {
    // 先判断浏览器是否支持,一般都支持
      if (typeof FileReader === 'undefined') {
        alert('您的浏览器不支持图片上传,请升级您的浏览器')
        return false
      }
      // 实例化实例化`FileReader`对象
      const reader = new FileReader()
      // 读取内容
      reader.readAsDataURL(files)
      // 通过onload事件拿到文件,并注册一个回调事件cb,这个回调事件就是拿来上传文件、预览文件等等的操作,回调的参数就是处理好的base64格式文件
      reader.onload = e => {
        // eslint-disable-next-line no-unused-expressions
        cb ? cb(e.target.result) : null
      }
    },
    // 文件预览
    previewClick (row) {
      var string = row.localurl
      var iframe = "<iframe width='100%' height='100%' :title='" + row.name + "' src='" + string + "'></iframe>"
      var x = window.open()
      x.document.open()
      x.document.write(iframe)
      x.document.close()
      x.document.title = row.name
    },
    // 删除附件
    deletefileClick (index) {
      this.gridData.splice(index, 1)
    },
    // 取消上传
    cancelSubmit () {
      this.loading = false
      this.dialogFormVisible = false
      this.$refs.uploadInput.value = ''
      this.gridData = []
    },
    // 确认上传
    submitClick () {
      this.loading = true
      const arrfilelist = []
      if (this.gridData && this.gridData.length > 0) {
        this.gridData.forEach((item) => {
          const dataBase64res = item.localurl.substring(item.localurl.indexOf(',') + 1)
          const obj = {
            operatID: 'I',
            context_Str: dataBase64res,
            accessoryName: item.name,
            localFilePath: item.name,
            ADAccessoryID: ''
          }
          arrfilelist.push(obj)
        })
        apifileupload(arrfilelist)
          .then((res) => {
            this.loading = false
            const arrList = res.data.result.resultObj
            if (arrList && arrList.length > 0) {
              const newarr = this.concatarrfileFun(arrfilelist, arrList)
              this.$emit('getattachmentList', newarr)
              this.dialogFormVisible = false
              this.$refs.uploadInput.value = ''
              this.gridData = []
              this.$message.success('附件上传成功!')
            } else {
              this.$message.error('附件上传失败!')
            }
          })
          .catch((err) => {
            this.$message.error('附件上传失败:' + err)
            this.loading = false
          })
      } else {
        this.$message.warning('请上传附件')
      }
    },
    // 重组数据
    concatarrfileFun (oldarr, newarr) {
      const concatarr = []
      oldarr.forEach((olditem) => {
        newarr.forEach((newitem) => {
          if (olditem.localFilePath === newitem.fileName) {
            const obj = {
              operatID: 'I',
              context_Str: olditem.context_Str,
              accessoryName: newitem.accessoryName,
              localFilePath: newitem.fileName,
              ADAccessoryID: newitem.ADAccessoryID,
              url: newitem.url,
              fileName: newitem.fileName,
              downloadUrl: newitem.downloadUrl
            }
            concatarr.push(obj)
          }
        })
      })
      return concatarr
    },
    // 保留两位小数的大小
    formatMoney (size) {
      return commFunction.formatMoney(size)
    }
  }
}
</script>

<style lang="scss" scoped>
.addAttachments{
  /deep/ .el-dialog__header,
  /deep/ .el-dialog__body{
    text-align: left !important;
  }
  .upload-wrap {
  width: 80px;
  position: relative;
  border-radius: 5px;
  overflow: hidden;
  background-color: #fff;
  transition: all 0.5s ease-in-out;
  margin: 0 5px 5px 0;
    .input,
    .uploader-icon {
      position: absolute;
      z-index: 99;
      width: 100%;
      height: 100%;
    }
    .input {
      opacity: 0;
      cursor: pointer;
    }
  }
}
</style>
  • 父组件使用:

  • 引入
    import addAttachments from '@/components/addAttachments/addAttachments.vue' import { apideleteAccessory } from '@/js/fileUpload/fileUpload.js'

  • 注册:components: { addAttachments },

  • 使用:<add-attachments ref="refaddattachments" @getattachmentList="getattachmentList"></add-attachments>

  • 父组件通过refs打开子组件,并且进行数据的获取等

// 添加附件
    uploadfileclick () {
      this.$refs.refaddattachments.openaddattachments()
    },
    // 获取数据
    getattachmentList (arrlist) {
      if (arrlist && arrlist.length > 0) {
        this.attachmentList = this.attachmentList.concat(arrlist)
      } else {
        this.attachmentList = []
      }
    },
    // 查看附件
    seefileClick (item) {
      window.open(item.url)
    },
    // 删除附件
    deletefileClick (item, index) {
      this.$confirm('是否确定删除?删除即将从数据库中删除!', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        apideleteAccessory(item.ADAccessoryID)
          .then((res) => {
            const result = res.data.result.resultObj
            if (result && result.length > 0) {
              if (result[0].flag === 'Y') {
                // this.applyBillInfo.ADAccessory.splice(index, 1)
                this.attachmentList.splice(index, 1)
                this.applyBillInfo.ADAccessory = []
                this.$message.success('删除附件成功!')
              } else {
                this.$message.error('删除附件失败!')
              }
            }
          })
          .catch((err) => {
            this.$message.error('删除附件失败:' + err)
          })
      })
    },
    // 下载附件
    downfileClick (item) {
      window.open(item.downloadUrl)
    }
  • 父组件的容器和触发方式
  • <div class="accessory-content">
      <div class="content-title">
        <div class="title-left">
          附件
        </div>
        <div  v-if="isHeaderEditable" class="title-right" ref="upLoadFile"
          :class="isHeaderEditable== false?'isNoEdit':''" @click="uploadfileclick">添加
        </div>
        <div v-else class="title-right"  ref="upLoadFile" :class="isHeaderEditable== false?'isNoEdit':''">添加</div>
      </div>
      <div class="content-main" v-if="attachmentList && attachmentList.length > 0">
        <div class="content-attachment-list" v-for="(item, index) in attachmentList" :key="index + item">
            <div class="attachment-list-name" @click.prevent="seefileClick(item)">{{item.fileName}}</div>
            <div class="attachment-list-right">
              <div class="attachment-list-btn" @click.prevent="downfileClick(item)" >
                <i class="el-icon-download"></i>
              </div>
              <div class="attachment-list-btn" @click.prevent="deletefileClick(item,index)">
                <i class="el-icon-delete"></i>
              </div>
            </div>
          </div>
      </div>
    </div>
    
    • 父组件容器的样式
// 附件
            .accessory-content{
                display: flex;
                flex-direction: column;
                justify-content: flex-start;
                background:#F3F8FC;
                padding: 11px 14px;
                box-sizing: border-box;
                .content-title{
                    display: flex;
                    justify-content: space-between;
                    margin-bottom: 10px;
                    .title-left{
                        color: #303133;
                        font-size: 14px;
                        font-family: PingFangSC-Medium;
                    }
                    .title-right{
                        cursor: pointer;
                        color: rgba(0, 137, 255, 100);
                        font-size: 14px;
                        font-family: PingFangSC-Regular;
                    }
                }
                .content-main{
                    width: 100%;
                    .content-attachment-list{
                        display: flex;
                        justify-content: space-between;
                        align-items: center;
                        height: 30px;
                        line-height: 30px;
                        .attachment-list-name{
                            overflow: hidden;
                            text-overflow: ellipsis;
                            display: -webkit-box;
                            -webkit-line-clamp: 1;
                            -webkit-box-orient: vertical;
                            width: 80%;
                            text-align: left;
                            color: rgba(96, 98, 102, 100);
                            font-size: 14px;
                            font-family: PingFangSC-Regular;
                            cursor: pointer;
                        }
                        .attachment-list-right{
                            display: flex;
                            .attachment-list-btn{
                                cursor: pointer;
                                margin-right: 5px;
                                .el-icon-delete,
                                .el-icon-download{
                                    width: 20px;
                                    text-align: center;
                                    font-size: 16px;
                                    color: #0089FF;
                                }
                            }
                        }
                    }
                }
            }

最后的效果图
在这里插入图片描述

在这里插入图片描述

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐