el-upload组件使用

2024-09-05 17:18:34 浏览数 (3)

代码语言:html复制
<template>
  <div class="app-container" style="padding: 0;">
    <el-dialog
      class="resource-dialog"
      :title="$t('CMS.Resource.SelectorTitle')"
      :visible.sync="visible"
      width="1010px"
      :close-on-click-modal="false"
      append-to-body>
      <el-tabs v-model="activeName" @tab-click="handleTabClick">
        <el-tab-pane :label="$t('CMS.Resource.LocalUpload')" name="local">
          <el-form
            ref="formUpload"
            :model="form_upload"
            v-loading="upload.isUploading"
            label-width="130px">
            <el-form-item :label="$t('CMS.Resource.Source')" prop="source">
               <el-radio-group v-model="form_upload.source" size="small">
                 <el-radio-button label="local">{{ $t('CMS.Resource.LocalUpload') }}</el-radio-button>
                 <el-radio-button label="net">{{ $t('CMS.Resource.RemoteLink') }}</el-radio-button>
                 <el-radio-button label="large">大文件上传</el-radio-button>

              </el-radio-group>
            </el-form-item>
            <el-form-item v-if="showLocal" :label="$t('CMS.Resource.Upload')" prop="path">
              <el-upload
                ref="upload"
                list-type="picture-card"
                :accept="upload.accept"
                :limit="upload.limit"
                :multiple="upload.limit>1"
                :action="upload.url"
                :headers="upload.headers"
                :data="upload.data"
                :file-list="upload.fileList"
                :before-upload="handleFileBeforeUpload"
                :on-progress="handleFileUploadProgress"
                :on-success="handleFileUploadSuccess"
                :on-error="handleFileUploadError"
                :on-exceed="handleFileUloadExceed"
                :on-change="handleFileChange"
                :auto-upload="false">
                <i slot="default" class="el-icon-plus"></i>
                <div slot="file" slot-scope="{file}">
                  <img v-if="isImageResource(file.name)" class="el-upload-list__item-thumbnail" :src="file.url" />
                  <svg-icon v-else :icon-class="getResourceFileIconClass(file.name)" />
                  <span class="el-upload-list__item-actions">
                    <span class="el-upload-list__item-delete" @click="handleRemoveFile(file)">
                      <i class="el-icon-delete"></i>
                    </span>
                  </span>
                </div>
                <div slot="tip" class="el-upload__tip"></div>
              </el-upload>
            </el-form-item>
            <el-form-item v-if="showNet" :label="$t('CMS.Resource.RemoteLink')" prop="path">
              <el-input v-model="form_upload.path" size="small" placeholder="http(s)://"></el-input>
            </el-form-item>
            <el-form-item v-if="showlarge" :label="$t('CMS.Resource.Upload')">
              <el-upload
              v-loading="largeloading"
               ref="upload"
                :action="largeupload.url"
                 :headers="largeupload.headers"
                :before-upload="handleBeforeUpload"
                :on-success="requestsuccess"
                :on-remove="requestRemove"
                :file-list="largefileList"
              >
                <el-button size="small" type="primary">点击上传</el-button>
              </el-upload>
            </el-form-item>
            <el-form-item :label="$t('CMS.Resource.Tag')" prop="tags">
              <el-tag
                :key="tag"
                v-for="tag in form_upload.tags"
                closable
                :disable-transitions="false"
                @close="handleDeleteTag(tag)">
                {{tag}}
              </el-tag>
              <el-input
                class="input-new-tag"
                v-if="tagInputVisible"
                v-model="tagInputValue"
                ref="tagInput"
                size="small"
                @keyup.enter.native="handleTagInputConfirm"
                @blur="handleTagInputConfirm">
              </el-input>
              <el-button v-else class="button-new-tag" size="small" @click="showTagInput">  New Tag</el-button>
            </el-form-item>
          </el-form>
        </el-tab-pane>
        <el-tab-pane :label="$t('CMS.Resource.MaterialLibrary')" name="resources">
          <el-container style="height: 500px; border: 1px solid #eee">
            <el-aside width="200px">
              <el-row>
                <el-link icon="el-icon-user" @click="loadMyResources">{{ $t('CMS.Resource.MyMaterial') }}</el-link>
              </el-row>
            </el-aside>
            <el-container>
              <el-header height="50px">
                <el-form :model="filterQuery"
                ref="queryForm"
                :inline="true"
                size="small"
                label-width="68px"
                class="el-form-search">
                  <el-form-item :label="$t('CMS.Resource.Name')" prop="name">
                    <el-input v-model="filterQuery.name" style="width: 170px;"></el-input>
                  </el-form-item>
                  <el-form-item :label="$t('Common.CreateTime')" style="margin-top:1px;">
                    <el-date-picker
                      v-model="dateRange"
                      style="width: 240px"
                      value-format="yyyy-MM-dd"
                      type="daterange"
                      range-separator="-"
                      :start-placeholder="$t('Common.BeginDate')"
                      :end-placeholder="$t('Common.EndDate')"></el-date-picker>
                  </el-form-item>
                  <el-form-item>
                    <el-button
                      type="primary"
                      icon="el-icon-search"
                      plain
                      @click="handleQuery">{{ $t("Common.Search") }}</el-button>
                    <el-button
                      plain
                      icon="el-icon-refresh"
                      @click="resetQuery">{{ $t("Common.Reset") }}</el-button>
                    <!-- <el-button
                      plain
                      icon="el-icon-scissors"
                      @click="alert('没空做')">{{ $t('CMS.Resource.Cut') }}{{</el-button> -->
                  </el-form-item>
                </el-form>
              </el-header>
              <el-main v-loading="loadingList" style="overflow-y: scroll;">
                <el-card shadow="never" v-for="(r, index) in resourceList" :key="r.resourceId">
                  <el-image v-if="isImageResource(r.src)" class="item-img" fit="scale-down" :src="r.src" @click="handleResourceChecked(index)"></el-image>
                  <svg-icon v-else :icon-class="getResourceFileIconClass(r.path)" class="item-svg" />
                  <div class="r-name" :title="r.name"><el-checkbox v-model="r.selected">{{ r.name }}</el-checkbox></div>
                </el-card>
              </el-main>
              <el-footer>
                <pagination
                  v-show="resourceTotal>0"
                  :total="resourceTotal"
                  :page.sync="filterQuery.pageNum"
                  :limit.sync="filterQuery.pageSize"
                  @pagination="loadResources" />
              </el-footer>
            </el-container>
          </el-container>
        </el-tab-pane>
      </el-tabs>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" :loading="upload.isUploading" @click="handleOk">{{ $t("Common.Confirm") }}</el-button>
        <el-button @click="handleCancel">{{ $t("Common.Cancel") }}</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { isImage, getFileSvgIconClass } from "@/utils/chestnut";
import fileIcon from '@/assets/icons/svg/file-unknown.svg';
import { getToken } from "@/utils/auth";
import { getResrouceList, getResourceTypes } from "@/api/contentcore/resource";
export default {
  name: "CMSResourceDialog",
  props: {
    open: {
      type: Boolean,
      default: false,
      required: true
    },
    rtype: {
      type: String,
      required: false,
      default: "file"
    },
    uploadLimit: {
      type: Number,
      default: 1,
      required: false
    }
  },
  data () {
    return {
      visible: false,
      activeName: 'local',
      siteId: this.$cache.local.get("CurrentSite"),
      form_upload: {
        source: 'local',
        tags: []
      },
      tagInputVisible: false,
      tagInputValue: '',
      // 上传参数
      upload: {
        isUploading: false, // 上传按钮loading
        // accept: ".jpg,.png,.mp3,.mp4,.flv,.pdf", // 文件类型限制
        acceptSize: 20 * 1024 * 1024,
        limit: this.uploadLimit, // 文件数限制
        headers: { Authorization: "Bearer "   getToken(), CurrentSite: this.$cache.local.get("CurrentSite") },
        url: process.env.VUE_APP_BASE_API   "/cms/resource/upload", // 上传的地址
        fileList: [], // 上传的文件列表
        data : {} // 附带参数
      },
      uploadedCount: 0, // 已上传文件数量
      results: [], // 返回的上传/选择的文件结果

      loadingList: false,
      resourcesLoaded: false,
      resourceList: [],
      resourceTotal: 0,
      filterQuery: {
        pageNum: 1,
        pageSize: 10,
        resourceType: this.rtype,
        owner: false,
        name: undefined
      },
      dateRange: [],
      largeupload:{
        headers: { Authorization: "Bearer "   getToken(), CurrentSite: this.$cache.local.get("CurrentSite") },
        url: process.env.VUE_APP_BASE_API   "/cms/resource/upload/minio", // 上传的地址
      },
      largeloading:false,
      largefileList:[]
    };
  },
  computed: {
    showLocal () {
      return this.form_upload.source=='local';
    },
    showNet () {
      return this.form_upload.source=='net'
    },
    fileSizeName() {
      return this.upload.acceptSize / 1024 / 1024   " MB"
    },
    showlarge(){
      return this.form_upload.source=='large'
    }
  },
  watch: {
    open (newVal) {
      this.visible = newVal;
    },
    visible (newVal) {
      if (!newVal) {
        this.noticeClose();
      } else {
        this.upload.isUploading = false;
        this.uploadedCount = 0;
      }
    },
    rtype (newVal) {
      this.loadResourceTypes();
    }
  },
  methods: {
    isImageResource(src) {
      return isImage(src);
    },
    getResourceFileIconClass(path) {
      return getFileSvgIconClass(path)
    },
    handleTabClick (tab, event) {
      if (this.activeName == "resources" && !this.resourcesLoaded) {
        this.loadResources();
      }
    },
    handleDeleteTag(tag) {
      this.form_upload.tags.splice(this.form_upload.tags.indexOf(tag), 1);
    },
    showTagInput() {
      this.tagInputVisible = true;
      this.$nextTick(_ => {
        this.$refs.tagInput.$refs.input.focus();
      });
    },
    handleTagInputConfirm() {
      let tagValue = this.tagInputValue;
      if (tagValue) {
        this.form_upload.tags.push(tagValue);
      }
      this.tagInputVisible = false;
      this.tagInputValue = '';
    },
    loadResourceTypes() {
      getResourceTypes().then(response => {
        response.data.some((item) => {
          if (item.id == this.rtype) {
            this.upload.accept = "."   item.accepts.replaceAll(",", ",.")
            return true;
          }
          return false;
        })
      });
    },
    loadMyResources () {
      this.filterQuery.owner = true;
      this.loadResources();
    },
    loadResources () {
      this.loadingList = true;
      if (this.dateRange && this.dateRange.length == 2) {
        this.filterQuery.beginTime = this.dateRange[0];
        this.filterQuery.endTime = this.dateRange[1];
      }
      this.filterQuery.resourceType = this.rtype || ''
      getResrouceList(this.filterQuery).then(response => {
        this.resourceList = response.data.rows;
        this.resourceList.forEach(r => this.$set(r,'selected',false));
        this.resourceTotal = parseInt(response.data.total);
        this.loadingList = false;
      });
    },
    handleResourceChecked(index) {
      this.$set(this.resourceList[index],'selected',!this.resourceList[index].selected)
    },
    /** 搜索按钮操作 */
    handleQuery () {
      this.filterQuery.pageNum = 1;
      this.loadResources();
    },
    /** 重置按钮操作 */
    resetQuery () {
      this.resetForm("queryForm");
      this.dateRange = [];
      this.filterQuery.owner = false;
      this.handleQuery();
    },
    handleRemoveFile (file) {
      for (var i = 0; i < this.upload.fileList.length; i  ) {
        if (this.upload.fileList[i].uid == file.uid) {
          this.upload.fileList.splice(i, 1)
          break;
        }
      }
    },
    handleFileChange (file, fileList) {
      this.upload.fileList = fileList
    },
    handleFileBeforeUpload (file) {
      if (this.upload.acceptSize > 0 && file.size > this.upload.acceptSize) {
        this.$message.error(this.$t('CMS.Resource.UploadFileSizeLimit', [ this.fileSizeName ]));
        return false;
      }
      return true;
    },
    handleFileUloadExceed (files, fileList) {
      this.$modal.msgWarning(this.$t('CMS.Resource.UploadLimit', [ this.upload.limit ]));
    },
    handleFileUploadProgress (event, file, fileList) {
      this.upload.isUploading = true;
    },
    handleFileUploadSuccess (response, file, fileList) {
      this.onFileUploaded(response.code == 200, fileList, response.code == 200 ? response.data : response.msg);
    },
    handleFileUploadError (err, file, fileList) {
      this.onFileUploaded(false, fileList, "Upload failed.");
    },
    onFileUploaded(isSuccess, fileList, result) {
      if (isSuccess) {
        this.uploadedCount  ;
        this.results.push({
          path: result.internalUrl,
          name: result.name,
          src: result.src,
          width: result.width,
          height: result.height,
          fileSize: result.fileSize,
          fileSizeName: result.fileSizeName,
          resourceType: result.resourceType
        });
      } else {
        this.$modal.msgError(result);
      }
      if (this.uploadedCount == fileList.length) {
        this.noticeOk();
        this.upload.isUploading = false;
      }
    },
    handleOk () {
      if (this.activeName === "local") {
        if (this.form_upload.source === 'local') {
          Object.keys(this.form_upload).forEach(key => this.upload.data[key] = this.form_upload[key]);
          this.$refs.upload.submit();
        } else if(this.form_upload.source === 'large'){ //大文件上传
          this.largefileList.forEach((ele)=>{
            let result=ele.response.data
            console.log(result,'result')
            this.results.push({
              path: result.internalUrl,
              name: result.name,
              src: result.src,
              width: result.width,
              height: result.height,
              fileSize: result.fileSize,
              fileSizeName: result.fileSizeName,
              resourceType: result.resourceType
            });
          })
          console.log(this.results,'this.results')
          this.noticeOk();

        } else  {
          const url = this.form_upload.path;
          if (!url || (!url.startsWith("http://") && !url.startsWith("https://"))) {
            this.$modal.msgError(this.$t('CMS.Resource.RemoteLinkErr'));
            return;
          }
          const name = url.substring(url.lastIndexOf("/")   1);
          this.results.push({
            path: url,
            name: name,
            src: url,
            width: 0,
            height: 0,
            fileSize: 0,
            fileSizeName: "0",
            resourceType: "unknown",
            net: true
          });
          this.noticeOk();
        }
      }  else {
        this.resourceList.forEach((item)=>{
          if (item.selected) {
            this.results.push({
              path: item.internalUrl,
              name: item.name,
              src: item.src,
              width: item.width,
              height: item.height,
              fileSize: item.fileSize,
              fileSizeName: item.fileSizeName,
              resourceType: item.resourceType
            });
          }
        });
        if (this.results.length == 0) {
          this.$modal.msgError(this.$t('Common.SelectFirst'));
          return;
        }
        this.noticeOk();
      }
    },
    handleCancel () {
      this.visible = false;
    },
    noticeOk () {
      if (this.visible) {
        this.$emit("ok", this.results);
        this.visible = false;
      }
    },
    noticeClose () {
      if (!this.visible) {
        this.$emit('update:open', false);
        this.$emit("close");
        this.reset();
      }
    },
    reset () {
        this.activeName = "local";
        this.form_upload = { source: 'local', tags: [] };
        this.tagInputVisible = false,
        this.tagInputValue = '',
        this.upload.fileList = [];
        this.upload.data = {};
        this.uploadedCount = 0;
        this.results = [];
        this.resourcesLoaded = false;
        this.resourceList = [];
        this.resourceTotal = 0;
        this.filterQuery.pageNum = 1;
        this.filterQuery.owner = false;
        this.filterQuery.name = undefined;
        this.dateRange = [];
        this.largefileList=[]
    },
    requestsuccess(response,file, fileList){
      console.log(response,'上传成功')
      if(response.code==200){
        this.largefileList=fileList
        this.$message.success('上传成功')
        this.largeloading=false
      }else{
        this.largeloading=false
      }
    },
    requestRemove(file,fileList){
      this.largefileList=fileList
      console.log(this.largefileList,'删除')
    },
    handleBeforeUpload(file){
      console.log('beforeload')
      this.largeloading=true;
    },
  }
};
</script>
<style>
.resource-dialog .el-upload-list__item .svg-icon {
  width: 66px;
  height: 66px;
}
.resource-dialog .el-aside {
  height: 500px;
}
.resource-dialog .el-header {
  padding: 5px;
  background-color: #f7f7f7;
}
.resource-dialog .el-main {
  overflow-y: hidden;
  background-color: #fff;
  padding: 0 4px;
}
.resource-dialog .el-card {
  width: 148px;
  text-align: center;
  float: left;
  border: none;
  padding: 0;
}
.resource-dialog .el-card__body {
  padding: 15px;
}
.resource-dialog .el-card .r-name {
  height: 28px;
  line-height: 28px;
  overflow: hidden;
}
.resource-dialog .el-card .item-img {
  width: 120px;
  height: 120px;
  background-color: #f7f7f7;
  cursor: pointer;
}
.resource-dialog .el-card .item-svg {
  width: 120px;
  height: 120px;
  background-color: #f7f7f7;
  cursor: pointer;
  padding: 20px;
}
.resource-dialog .el-tag {
  margin-right: 10px;
}
.resource-dialog .button-new-tag {
  height: 32px;
  line-height: 30px;
  padding-top: 0;
  padding-bottom: 0;
}
.resource-dialog .input-new-tag {
  width: 120px;
  vertical-align: bottom;
}
.resource-dialog .el-upload-list--picture-card .el-upload-list__item {
  width: 68px;
  height: 68px;
}
.resource-dialog .el-upload--picture-card {
  line-height: 78px;
  width: 68px;
  height: 68px;
}
</style>

el-upload属性解析

ref="upload":给这个元素一个引用名,方便在Vue实例中通过this.$refs.upload访问。

list-type="picture-card":设置上传列表的展示样式为图片卡片形式。

:accept="upload.accept":设置接受上传的文件类型,例如.jpg,.png。

:limit="upload.limit":设置上传文件的最大数量。

:multiple="upload.limit>1":是否可以选择多个文件上传。

:action="upload.url":指定上传文件的服务端地址。

:headers="upload.headers":设置请求头信息,比如身份认证信息。

:data="upload.data":上传时附带的额外参数。

:file-list="upload.fileList":绑定已上传文件的列表。

:before-upload="handleFileBeforeUpload":上传前的钩子函数,用于校验等操作。

:on-progress="handleFileUploadProgress":上传进度的回调函数。

:on-success="handleFileUploadSuccess":上传成功的回调函数。

:on-error="handleFileUploadError":上传失败的回调函数。

:on-exceed="handleFileUloadExceed":当文件大小超过限制时的回调。

:on-change="handleFileChange":文件选择发生变化时的回调。

:auto-upload="false":设置为手动上传模式,即不会自动上传文件。

插槽(Slots)解析

slot="default":默认插槽,这里插入了一个i标签作为上传按钮。

slot="file":自定义文件项插槽,可以根据文件类型显示不同的内容。这里根据文件名判断是否为图像资源,如果是则显示图片缩略图,否则显示一个图标。

slot-scope="{file}":作用域插槽,允许父组件访问子组件的数据。这里的file对象包含了关于当前文件的信息。

slot="tip":自定义提示信息的位置,通常用来放置一些上传相关的提示信息。

这个配置使得el-upload组件可以灵活地适应各种上传需求,并且可以通过自定义插槽来美化界面或添加更多交互逻辑。

1 人点赞