|  | @@ -5,33 +5,38 @@
 | 
	
		
			
				|  |  |        list-type="picture-card"
 | 
	
		
			
				|  |  |        :on-success="handleUploadSuccess"
 | 
	
		
			
				|  |  |        :before-upload="handleBeforeUpload"
 | 
	
		
			
				|  |  | +      :limit="limit"
 | 
	
		
			
				|  |  |        :on-error="handleUploadError"
 | 
	
		
			
				|  |  | +      :on-exceed="handleExceed"
 | 
	
		
			
				|  |  |        name="file"
 | 
	
		
			
				|  |  | -      :show-file-list="false"
 | 
	
		
			
				|  |  | +      :on-remove="handleRemove"
 | 
	
		
			
				|  |  | +      :show-file-list="true"
 | 
	
		
			
				|  |  |        :headers="headers"
 | 
	
		
			
				|  |  | -      style="display: inline-block; vertical-align: top"
 | 
	
		
			
				|  |  | +      :file-list="fileList"
 | 
	
		
			
				|  |  | +      :on-preview="handlePictureCardPreview"
 | 
	
		
			
				|  |  | +      :class="{hide: this.fileList.length >= this.limit}"
 | 
	
		
			
				|  |  |      >
 | 
	
		
			
				|  |  | -      <el-image v-if="!value" :src="value">
 | 
	
		
			
				|  |  | -        <div slot="error" class="image-slot">
 | 
	
		
			
				|  |  | -          <i class="el-icon-plus" />
 | 
	
		
			
				|  |  | -        </div>
 | 
	
		
			
				|  |  | -      </el-image>
 | 
	
		
			
				|  |  | -      <div v-else class="image">
 | 
	
		
			
				|  |  | -        <el-image :src="value" :style="`width:150px;height:150px;`" fit="fill"/>
 | 
	
		
			
				|  |  | -        <div class="mask">
 | 
	
		
			
				|  |  | -          <div class="actions">
 | 
	
		
			
				|  |  | -            <span title="预览" @click.stop="dialogVisible = true">
 | 
	
		
			
				|  |  | -              <i class="el-icon-zoom-in" />
 | 
	
		
			
				|  |  | -            </span>
 | 
	
		
			
				|  |  | -            <span title="移除" @click.stop="removeImage">
 | 
	
		
			
				|  |  | -              <i class="el-icon-delete" />
 | 
	
		
			
				|  |  | -            </span>
 | 
	
		
			
				|  |  | -          </div>
 | 
	
		
			
				|  |  | -        </div>
 | 
	
		
			
				|  |  | -      </div>
 | 
	
		
			
				|  |  | +      <i class="el-icon-plus"></i>
 | 
	
		
			
				|  |  |      </el-upload>
 | 
	
		
			
				|  |  | -    <el-dialog :visible.sync="dialogVisible" title="预览" width="800" append-to-body>
 | 
	
		
			
				|  |  | -      <img :src="value" style="display: block; max-width: 100%; margin: 0 auto;">
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  | +    <!-- 上传提示 -->
 | 
	
		
			
				|  |  | +    <div class="el-upload__tip" slot="tip" v-if="showTip">
 | 
	
		
			
				|  |  | +      请上传
 | 
	
		
			
				|  |  | +      <template v-if="fileSize"> 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b> </template>
 | 
	
		
			
				|  |  | +      <template v-if="fileType"> 格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template>
 | 
	
		
			
				|  |  | +      的文件
 | 
	
		
			
				|  |  | +    </div>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    <el-dialog
 | 
	
		
			
				|  |  | +      :visible.sync="dialogVisible"
 | 
	
		
			
				|  |  | +      title="预览"
 | 
	
		
			
				|  |  | +      width="800"
 | 
	
		
			
				|  |  | +      append-to-body
 | 
	
		
			
				|  |  | +    >
 | 
	
		
			
				|  |  | +      <img
 | 
	
		
			
				|  |  | +        :src="dialogImageUrl"
 | 
	
		
			
				|  |  | +        style="display: block; max-width: 100%; margin: 0 auto"
 | 
	
		
			
				|  |  | +      />
 | 
	
		
			
				|  |  |      </el-dialog>
 | 
	
		
			
				|  |  |    </div>
 | 
	
		
			
				|  |  |  </template>
 | 
	
	
		
			
				|  | @@ -40,36 +45,123 @@
 | 
	
		
			
				|  |  |  import { getToken } from "@/utils/auth";
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  export default {
 | 
	
		
			
				|  |  | +  props: {
 | 
	
		
			
				|  |  | +    value: [String, Object, Array],
 | 
	
		
			
				|  |  | +    // 图片数量限制
 | 
	
		
			
				|  |  | +    limit: {
 | 
	
		
			
				|  |  | +      type: Number,
 | 
	
		
			
				|  |  | +      default: 5,
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +    // 大小限制(MB)
 | 
	
		
			
				|  |  | +    fileSize: {
 | 
	
		
			
				|  |  | +       type: Number,
 | 
	
		
			
				|  |  | +      default: 5,
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +    // 文件类型, 例如['png', 'jpg', 'jpeg']
 | 
	
		
			
				|  |  | +    fileType: {
 | 
	
		
			
				|  |  | +      type: Array,
 | 
	
		
			
				|  |  | +      default: () => ["png", "jpg", "jpeg"],
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +    // 是否显示提示
 | 
	
		
			
				|  |  | +    isShowTip: {
 | 
	
		
			
				|  |  | +      type: Boolean,
 | 
	
		
			
				|  |  | +      default: true
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  },
 | 
	
		
			
				|  |  |    data() {
 | 
	
		
			
				|  |  |      return {
 | 
	
		
			
				|  |  | +      dialogImageUrl: "",
 | 
	
		
			
				|  |  |        dialogVisible: false,
 | 
	
		
			
				|  |  | +      hideUpload: false,
 | 
	
		
			
				|  |  |        uploadImgUrl: process.env.VUE_APP_BASE_API + "/file/upload", // 上传的图片服务器地址
 | 
	
		
			
				|  |  |        headers: {
 | 
	
		
			
				|  |  |          Authorization: "Bearer " + getToken(),
 | 
	
		
			
				|  |  |        },
 | 
	
		
			
				|  |  | +      fileList: []
 | 
	
		
			
				|  |  |      };
 | 
	
		
			
				|  |  |    },
 | 
	
		
			
				|  |  | -  props: {
 | 
	
		
			
				|  |  | +  watch: {
 | 
	
		
			
				|  |  |      value: {
 | 
	
		
			
				|  |  | -      type: String,
 | 
	
		
			
				|  |  | -      default: "",
 | 
	
		
			
				|  |  | +      handler(val) {
 | 
	
		
			
				|  |  | +        if (val) {
 | 
	
		
			
				|  |  | +          // 首先将值转为数组
 | 
	
		
			
				|  |  | +          const list = Array.isArray(val) ? val : this.value.split(',');
 | 
	
		
			
				|  |  | +          // 然后将数组转为对象数组
 | 
	
		
			
				|  |  | +          this.fileList = list.map(item => {
 | 
	
		
			
				|  |  | +            if (typeof item === "string") {
 | 
	
		
			
				|  |  | +              item = { name: item, url: item };
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            return item;
 | 
	
		
			
				|  |  | +          });
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +          this.fileList = [];
 | 
	
		
			
				|  |  | +          return [];
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      },
 | 
	
		
			
				|  |  | +      deep: true,
 | 
	
		
			
				|  |  | +      immediate: true
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  },
 | 
	
		
			
				|  |  | +  computed: {
 | 
	
		
			
				|  |  | +    // 是否显示提示
 | 
	
		
			
				|  |  | +    showTip() {
 | 
	
		
			
				|  |  | +      return this.isShowTip && (this.fileType || this.fileSize);
 | 
	
		
			
				|  |  |      },
 | 
	
		
			
				|  |  |    },
 | 
	
		
			
				|  |  |    methods: {
 | 
	
		
			
				|  |  | -    removeImage() {
 | 
	
		
			
				|  |  | -      this.$emit("input", "");
 | 
	
		
			
				|  |  | +    // 删除图片
 | 
	
		
			
				|  |  | +    handleRemove(file, fileList) {
 | 
	
		
			
				|  |  | +      const findex = this.fileList.indexOf(file.name);
 | 
	
		
			
				|  |  | +      this.fileList.splice(findex, 1);
 | 
	
		
			
				|  |  | +      this.$emit("input", this.listToString(this.fileList));
 | 
	
		
			
				|  |  |      },
 | 
	
		
			
				|  |  | +    // 上传成功回调
 | 
	
		
			
				|  |  |      handleUploadSuccess(res) {
 | 
	
		
			
				|  |  | -      this.$emit("input", res.data.url);
 | 
	
		
			
				|  |  | +      this.fileList.push({ name: res.data.url, url: res.data.url });
 | 
	
		
			
				|  |  | +      this.$emit("input", this.listToString(this.fileList));
 | 
	
		
			
				|  |  |        this.loading.close();
 | 
	
		
			
				|  |  |      },
 | 
	
		
			
				|  |  | -    handleBeforeUpload() {
 | 
	
		
			
				|  |  | +    // 上传前loading加载
 | 
	
		
			
				|  |  | +    handleBeforeUpload(file) {
 | 
	
		
			
				|  |  | +      let isImg = false;
 | 
	
		
			
				|  |  | +      if (this.fileType.length) {
 | 
	
		
			
				|  |  | +        let fileExtension = "";
 | 
	
		
			
				|  |  | +        if (file.name.lastIndexOf(".") > -1) {
 | 
	
		
			
				|  |  | +          fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        isImg = this.fileType.some(type => {
 | 
	
		
			
				|  |  | +          if (file.type.indexOf(type) > -1) return true;
 | 
	
		
			
				|  |  | +          if (fileExtension && fileExtension.indexOf(type) > -1) return true;
 | 
	
		
			
				|  |  | +          return false;
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +      } else {
 | 
	
		
			
				|  |  | +        isImg = file.type.indexOf("image") > -1;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      if (!isImg) {
 | 
	
		
			
				|  |  | +        this.$message.error(
 | 
	
		
			
				|  |  | +          `文件格式不正确, 请上传${this.fileType.join("/")}图片格式文件!`
 | 
	
		
			
				|  |  | +        );
 | 
	
		
			
				|  |  | +        return false;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      if (this.fileSize) {
 | 
	
		
			
				|  |  | +        const isLt = file.size / 1024 / 1024 < this.fileSize;
 | 
	
		
			
				|  |  | +        if (!isLt) {
 | 
	
		
			
				|  |  | +          this.$message.error(`上传头像图片大小不能超过 ${this.fileSize} MB!`);
 | 
	
		
			
				|  |  | +          return false;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  |        this.loading = this.$loading({
 | 
	
		
			
				|  |  |          lock: true,
 | 
	
		
			
				|  |  |          text: "上传中",
 | 
	
		
			
				|  |  |          background: "rgba(0, 0, 0, 0.7)",
 | 
	
		
			
				|  |  |        });
 | 
	
		
			
				|  |  |      },
 | 
	
		
			
				|  |  | +    // 文件个数超出
 | 
	
		
			
				|  |  | +    handleExceed() {
 | 
	
		
			
				|  |  | +      this.$message.error(`上传文件数量不能超过 ${this.limit} 个!`);
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +    // 上传失败
 | 
	
		
			
				|  |  |      handleUploadError() {
 | 
	
		
			
				|  |  |        this.$message({
 | 
	
		
			
				|  |  |          type: "error",
 | 
	
	
		
			
				|  | @@ -77,24 +169,37 @@ export default {
 | 
	
		
			
				|  |  |        });
 | 
	
		
			
				|  |  |        this.loading.close();
 | 
	
		
			
				|  |  |      },
 | 
	
		
			
				|  |  | -  },
 | 
	
		
			
				|  |  | -  watch: {},
 | 
	
		
			
				|  |  | +    // 预览
 | 
	
		
			
				|  |  | +    handlePictureCardPreview(file) {
 | 
	
		
			
				|  |  | +      this.dialogImageUrl = file.url;
 | 
	
		
			
				|  |  | +      this.dialogVisible = true;
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +    // 对象转成指定字符串分隔
 | 
	
		
			
				|  |  | +    listToString(list, separator) {
 | 
	
		
			
				|  |  | +      let strs = "";
 | 
	
		
			
				|  |  | +      separator = separator || ",";
 | 
	
		
			
				|  |  | +      for (let i in list) {
 | 
	
		
			
				|  |  | +        strs += list[i].url + separator;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      return strs != '' ? strs.substr(0, strs.length - 1) : '';
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  </script>
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  <style scoped lang="scss">
 | 
	
		
			
				|  |  | -.image {
 | 
	
		
			
				|  |  | -  position: relative;
 | 
	
		
			
				|  |  | -  .mask {
 | 
	
		
			
				|  |  | +// .el-upload--picture-card 控制加号部分
 | 
	
		
			
				|  |  | +::v-deep.hide .el-upload--picture-card {
 | 
	
		
			
				|  |  | +    display: none;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +// 去掉动画效果
 | 
	
		
			
				|  |  | +::v-deep .el-list-enter-active,
 | 
	
		
			
				|  |  | +::v-deep .el-list-leave-active {
 | 
	
		
			
				|  |  | +    transition: all 0s;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +::v-deep .el-list-enter, .el-list-leave-active {
 | 
	
		
			
				|  |  |      opacity: 0;
 | 
	
		
			
				|  |  | -    position: absolute;
 | 
	
		
			
				|  |  | -    top: 0;
 | 
	
		
			
				|  |  | -    width: 100%;
 | 
	
		
			
				|  |  | -    background-color: rgba(0, 0, 0, 0.5);
 | 
	
		
			
				|  |  | -    transition: all 0.3s;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  &:hover .mask {
 | 
	
		
			
				|  |  | -    opacity: 1;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | +    transform: translateY(0);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | -</style>
 | 
	
		
			
				|  |  | +</style>
 | 
	
		
			
				|  |  | +
 |