index.vue 9.41 KB
<template>
  <div>
    <el-upload
      :action="baseUrl ? baseUrl : imageApi"
      :auto-upload="true"
      :data="uploadData"
      :headers="headers"
      :on-success="handleSuccess"
      :on-error="handleError"
      :on-exceed="handleExceed"
      :before-upload="beforeUpload"
      :file-list="fileList"
      :disabled="isDisabled"
      :limit="limit"
      :class="{single:singleImage}"
      list-type="picture-card"
      name="multipartFile"
      accept="image/*"
    >
      <i slot="default" class="el-icon-plus" />
      <div slot="file" slot-scope="{file}">
        <!--        <span-->
        <!--          style="position: absolute; z-index: 999; padding-left: 5px; font-size: 12px;color: #ffffff;-->
        <!--          background-color: rgba(0, 0, 0, 0.5); padding-right: 5px; border-bottom-right-radius: 0.5em"-->
        <!--        >-->
        <!--          {{ file.hasOwnProperty("type") ? file.type : ((file.hasOwnProperty("response") ? file.response.type : -1))-->
        <!--            | dictFilter(dictMap.image_type ? dictMap.image_type : [])-->
        <!--            | dictFilter(dictMap.image_type_show ? dictMap.image_type_show : []) }}-->
        <!--        </span>-->
        <!--      于2020/10/14为了ugc基地址进行修改  file.url-->
        <img
          :src="baseUrl ? baseUrl + file.fileUrl : file.url"
          class="el-upload-list__item-thumbnail"
          alt=""
        >
        <span class="el-upload-list__item-actions">
          <span
            class="el-upload-list__item-preview"
            @click="handlePictureCardPreview(file)"
          >
            <i class="el-icon-zoom-in" />
          </span>
          <!--          <span-->
          <!--            v-if="!readOnlyMode"-->
          <!--            class="el-upload-list__item-delete"-->
          <!--            @click="handleChangeType(file)"-->
          <!--          >-->
          <!--            <i class="el-icon-picture" />-->
          <!--          </span>-->
          <span
            v-if="!readOnlyMode"
            class="el-upload-list__item-delete"
            @click="handleRemove(file)"
          >
            <i class="el-icon-delete" />
          </span>
          <span
            v-if="isArticle"
            class="el-upload-list__item-delete"
            @click="handleAddDesc(file)"
          >
            <i class="el-icon-edit" />
          </span>
        </span>
      </div>
    </el-upload>
    <el-dialog :visible.sync="dialogVisible" :append-to-body="true">
      <img :src="dialogImageUrl" width="100%" alt="">
    </el-dialog>
  </div>
</template>
<script>
import { getAttrByValueFromDict, convertImageArr2Json, evil, deepCopy } from '../../utils/common-util'
import { mapGetters } from 'vuex'
import { getToken } from '@/utils/auth'
import initDict from '@/mixins/initDict'
import { Loading } from 'element-ui'

export default {
  name: 'ImagesUpload',
  mixins: [initDict],
  props: {
    isDisabled: {
      type: Boolean,
      required: false,
      default() {
        return false
      }
    },
    isSubject: {
      type: Boolean,
      required: false,
      default() {
        return true
      }
    },
    image: {
      type: String,
      default: '[]'
    },
    images: {
      type: String,
      default: '{"list":[],"map":{}}'
    },
    uploadEntity: {
      type: String,
      required: true
    },
    limit: {
      type: Number,
      default: 10
    },
    singleMode: {
      type: Boolean,
      default: false
    },
    readOnlyMode: {
      type: Boolean,
      default: false
    },
    isArticle: {
      type: Boolean,
      default: false
    },
    baseUrl: {
      type: String,
      default() {
        return ''
      }
    }
  },
  data() {
    return {
      headers: {
        'Authorization': 'Bearer ' + getToken()
      },
      fileList: [],
      uploadData: { fileType: 'image' },
      dialogImageUrl: '',
      dialogVisible: false,
      dialogImageTypeVisible: false,
      imageType: '-1',
      imageSelect: {},
      imgDesc: {
        desc: ''
      },
      isUploading: false,
      loading: null,
      imageDesc: false
    }
  },
  computed: {
    ...mapGetters(['imageApi']),
    singleImage: function() {
      return (this.singleMode && (this.fileList.length > 0 || this.isUploading)) || this.readOnlyMode
    }
  },
  watch: {
    image: {
      immediate: true,
      handler(val) {
        if (val === null || val === '') {
          val = '[]'
        }
        const arr = evil(val)
        // 2020/12/31 00:04,为了专题管理覆盖数据的操作,增加了isSubject参数
        if (this.fileList.length === arr.length && this.isSubject) {
          // 当图片数量不变时,filelist不响应image的变更,避免2次刷新
          return
        }
        this.fileList = arr
        this.fileList.forEach(file => {
          if (!file.hasOwnProperty('url') && file.fileUrl.indexOf('http') === -1) {
            file.url = this.imageApi + '/' + file.fileUrl
          } else {
            file.url = file.fileUrl
          }
        })
        this.fileList = deepCopy(this.fileList)
      }
    }
  },
  created() {
    this.$nextTick(() => {
      this.getDictMap('image_type,image_type_show,image_size_limit')
    })
  },
  updated() {
    const images = []
    this.fileList.forEach(file => {
      if (file.response) {
        images.push({
          fileType: file.response[0].fileType,
          fileUrl: file.response[0].fileUrl,
          fileName: file.response[0].fileName
        })
      } else {
        images.push({
          fileType: file.fileType,
          fileUrl: file.fileUrl,
          fileName: file.fileName
        })
      }
    })
    console.log(images)
    this.$emit('update:image', JSON.stringify(images))
  },
  methods: {
    getAttrByValueFromDict,
    deepCopy,
    convertImageArr2Json,
    beforeUpload(file) {
      const isValid = (file.type === 'image/jpeg' || file.type === 'image/gif' || file.type === 'image/png')

      const dict = this.dictMap.image_size_limit.find(item => item.label === this.uploadEntity)
      let maxSize = dict ? parseFloat(dict.value) : 20 * 1024 // 默认2M
      const isLtMaxSize = parseFloat(file.size / 1024) < maxSize

      maxSize = maxSize > 1024 ? (parseFloat(maxSize / 1024).toFixed(2) + 'MB') : (maxSize + 'KB')
      this.isUploading = true
      if (!isValid) {
        this.$message.error('上传图片只能是 JPG/PNG/GIF 格式!')
        this.isUploading = false
      }
      if (!isLtMaxSize) {
        this.$message.error('上传图片大小不能超过' + maxSize + ' !')
        this.isUploading = false
      }
      if (isValid && isLtMaxSize) {
        this.loading = Loading.service({
          lock: true,
          text: '解析中Loading',
          spinner: 'el-icon-loading',
          background: 'rgba(0, 0, 0, 0.7)'
        })
      }
      return isValid && isLtMaxSize
    },
    handleRemove(file) {
      this.fileList.splice(this.fileList.findIndex(
        item => !item.hasOwnProperty('response') ? item.id === file.id : item.response.id === file.response.id), 1)
    },
    handlePictureCardPreview(file) {
      this.dialogImageUrl = file.url
      this.dialogVisible = true
    },
    handleChangeType(file) {
      console.log(file)
      this.imageSelect = file
      // 2020/10/23上午,因为发现此处报错,注释
      // this.imageType = file.hasOwnProperty('type') ? file.type.toString() : file.response.type.toString()
      // 2020/11/10上午,需要标示上传图片类型,所以解锁,并置为-1
      this.imageType = file.hasOwnProperty('type') ? file.type.toString() : file.hasOwnProperty('response') ? file.response.type.toString() : '-1'
      // this.imageType = '-1'
      this.dialogImageTypeVisible = true
    },
    // 增加描述
    handleAddDesc(file) {
      this.imgDesc = file
      this.imageDesc = true
    },
    handleError(err, file) {
      this.isUploading = false
      this.loading.close()
      this.$message.error(`图片上传失败,失败信息 ${err}`)
      console.log(err)
    },
    handleSuccess(res, file, fileList) {
      // console.log(res, file, fileList)
      this.loading.close()
      this.isUploading = false
      this.fileList = fileList
    },
    handleExceed(files, fileList) {
      this.$message.warning('图片数量无法大于' + this.limit + '张')
    },
    generateImageFromFileList(item) {
      const images = []
      this.fileList.forEach(file => {
        if (file.hasOwnProperty('response')) {
          images.push((({ id, type, width, height, fileUrl, size }) =>
            ({ id, type, width, height, fileUrl, size }))(file.response))
        } else {
          images.push((({ id, type, width, height, fileUrl, size }) =>
            ({ id, type, width, height, fileUrl, size }))(file))
        }
      })
      item.image = JSON.stringify(images)
      item.images = this.convertImageArr2Json(item.image, this.dictMap.image_type)
    },
    changeImageType() {
      const index = this.fileList.findIndex(
        item => !item.hasOwnProperty('response') ? item.id === this.imageSelect.id : item.response.id === this.imageSelect.response.id)
      if (this.fileList[index].hasOwnProperty('response')) {
        this.fileList[index].response.type = parseInt(this.imageType)
      } else {
        this.fileList[index].type = parseInt(this.imageType)
      }
      this.dialogImageTypeVisible = false
    }
  }
}
</script>

<style>
.el-upload-list__item {
  transition: none;
}
.single .el-upload--picture-card {
  display: none;
}
</style>