<template>
  <div class="m-upload" :style="{ width }">
    <div
      class="file-item item"
      :style="itemStyle"
      v-for="(item, index) of fileThumbList"
      :key="`file-item-${index}`"
    >
      <div class="item-content" v-show="item.status == 'success'">
        <img class="file-thumb" :src="item.thumb" />
        <m-icon
          class="video-play"
          icon="icon-video-play"
          :size="40"
          v-show="item.type == 'video'"
        />
      </div>
      <div class="status-mask flex-default" v-show="item.status == 'loading'">
        <van-progress
          :percentage="item.progress"
          pivot-text=""
          stroke-width="8"
        />
        <div class="percent-label">{{ item.progress + "%" }}</div>
      </div>
      <div class="status-mask flex-default" v-show="item.status == 'fail'">
        <div class="percent-label">{{ item.err }}</div>
      </div>
      <m-icon
        icon="icon-file-del"
        :size="16"
        class="file-del"
        v-show="item.status != 'loading'"
        @click="handleDel(item)"
      />
    </div>
    <template v-for="(item, index) of uploadList">
      <van-uploader
        :key="`upload-item-${index}`"
        v-show="fileMap[item.type].length < maxNumMap[item.type]"
        :after-read="
          (file) => {
            uploadFile(item, file);
          }
        "
        :accept="fileAcceptMap[item.type]"
        :max-size="maxSizeMap[item.type] * 1024"
        @oversize="onOverSize(item)"
      >
        <div class="upload-item item" :style="itemStyle">
          <div class="item-content">
            <m-icon :icon="item.icon" :size="iconSize" />
            <span class="upload-label">{{ item.label }}</span>
          </div>
        </div>
      </van-uploader>
    </template>
  </div>
</template>

<script>
import { deepCopy } from "@/utils/common";
export default {
  props: {
    value: {
      type: [Object, Array],
    },
    type: {
      type: [String, Array],
      default: () => ["image", "video"],
    },
    maxNum: {
      type: [Number, String, Array],
      default: () => [5, 1],
    },
    // 文件大小限制，单位KB
    maxSize: {
      type: [Number, String, Array],
      default: () => [5 * 1024, 20 * 1024],
    },
    width: {
      type: String,
      default: "100%",
    },
    size: {
      type: String,
      default: "100px",
    },
    iconSize: {
      type: Number,
      default: 40,
    },
    margin: {
      type: String,
      default: "10rpx",
    },
  },
  computed: {
    itemStyle() {
      return {
        height: this.size,
        width: this.size,
        marginRight: this.margin,
      };
    },

    uploadList() {
      let arr = [];
      let genItem = (type) => {
        let label = "";
        let icon = "icon-upload-img";
        if (type == "image") {
          label = "上传照片";
        } else if (type == "video") {
          label = "上传视频";
          icon = "icon-upload-video";
        }
        return { type, label, icon };
      };

      if (this.type_type == "str") {
        arr.push(genItem(this.type));
      } else if (this.type_type == "arr-str") {
        this.type.forEach((item) => {
          arr.push(genItem(item));
        });
      } else if (this.type_type == "arr-obj") {
        this.type.forEach((item) => {
          arr.push(Object.assign(genItem(item.type), item));
        });
      }
      return arr;
    },
    maxNumMap() {
      return this.genMap(this.maxNum);
    },
    maxSizeMap() {
      return this.genMap(this.maxSize);
    },
    type_type() {
      if (typeof this.type == "string") {
        return "str";
      } else if (this.type instanceof Array) {
        if (typeof this.type[0] == "string") {
          return "arr-str";
        } else if (this.type[0] instanceof Object) {
          return "arr-obj";
        }
      }
      return "";
    },
    fileThumbList() {
      let arr = [];
      for (let type in this.fileMap) {
        this.fileMap[type].forEach((file) => {
          let thumb = "";
          if (file.type == "image") {
            thumb = file.url;
          } else if (file.type == "video") {
            thumb = `${file.url}?x-oss-process=video/snapshot,t_0,f_jpg,w_0,h_0,m_fast`;
          }
          arr.push({ ...file, thumb });
        });
      }
      return arr;
    },
  },
  watch: {
    fileMap: {
      handler(val) {
        this.$emit("input", deepCopy(val));
      },
      deep: true,
    },
    value: {
      handler(val) {
        console.log(val);
      },
      deep: true,
    },
  },
  data() {
    return {
      uploadApiMap: {
        image: "uploadImg",
        video: "uploadVideo",
      },
      fileAcceptMap: {
        // image: [".png", ".jpg", ".jpeg", ".gif"],
        // video: [".mkv", ".mp4", ".mov"],
        image: "image/*",
        video: "video/*",
      },
      fileMap: {},
      percent: 0,
    };
  },
  created() {
    this.fileMap = this.genMap([]);
  },
  methods: {
    genMap(data) {
      if (this.type_type == "str") {
        return { [this.type]: data };
      } else if (this.type_type == "arr-str") {
        let map = {};
        for (let i = 0; i < this.type.length; i++) {
          map[this.type[i]] = data[i] || deepCopy(data);
        }
        return map;
      } else if (this.type_type == "arr-obj") {
        let map = {};
        for (let i = 0; i < this.type.length; i++) {
          map[this.type[i].type] = data[i] || deepCopy(data);
        }
        return map;
      }
    },
    uploadFile(item, file) {
      let fileItem = {
        type: item.type,
        url: "",
        status: "loading",
        progress: 0,
        err: "",
      };
      this.fileMap[item.type].push(fileItem);

      this.$api({
        apiName: this.uploadApiMap[item.type],
        postData: file.file,
        onUploadProgress: (e) => {
          let per = ((e.loaded / e.total) * 100) | 0;
          this.uploadOnProgress(fileItem, per);
        },
        success: (res) => {
          this.uploadSuccess(fileItem, res);
        },
        fail: (err) => {
          this.uploadFail(fileItem, err);
        },
        error: (err) => {
          this.uploadFail(fileItem, err);
        },
      });
    },

    uploadOnProgress(item, progress) {
      item.progress = progress;
      this.$emit("on-progress", progress);
    },
    uploadSuccess(item, res) {
      item.status = "success";
      item.url = res;
    },
    uploadFail(item, err) {
      item.status = "fail";
      item.err = "上传失败！";
    },

    onOverSize(item) {
      let maxSize = this.maxSizeMap[item.type];
      let label = "";
      if (maxSize < 1024) {
        label = `${maxSize}KB`;
      } else if (maxSize < 1024 * 1024) {
        label = `${(maxSize / 1024).toFixed(1)}MB`;
      } else {
        label = `${(maxSize / 1024 / 1024).toFixed(1)}MB`;
      }

      this.$toast(`文件大小不得超过${label}！`);
    },

    handleDel(item) {
      let index = this.fileMap[item.type].findIndex(
        (file) => file.url == item.url
      );
      this.fileMap[item.type].splice(index, 1);
    },
  },
};
</script>

<style lang="less" scoped>
.m-upload {
  white-space: nowrap;
  overflow-x: auto;
  .item {
    display: inline-block;
    vertical-align: bottom;
    position: relative;
    padding: 8px 8px 0 0;
  }
  .item .item-content {
    height: 100%;
    width: 100%;
    background-color: #f7f7f7;
    border-radius: 10px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    position: relative;
    .video-play {
      position: absolute;
    }
  }
  .item .upload-label {
    font-size: 12px;
    line-height: 14px;
    color: #aeaeae;
    margin-top: 5px;
  }
  .file-item > .file-del {
    position: absolute;
    top: 0;
    right: 0;
  }
  .file-item > .status-mask {
    position: absolute;
    bottom: 0;
    left: 0;
    width: ~"calc(100% - 8px)";
    height: ~"calc(100% - 8px)";
    border-radius: 10px;
    background: rgba(50, 50, 51, 0.88);
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 0 5px;
    > .van-progress {
      margin-top: 12px;
      width: 100%;
    }
    > .percent-label {
      margin-top: 5px;
      font-size: 12px;
      line-height: 14px;
      color: #ffffff;
    }
  }
  .item .file-thumb {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 10px;
  }
}
</style>


