<template>
  <div class="vue-image-upload">
    <div class="vicp-wrap">
      <div class="vicp-upload">
        <span class="vicp-loading" v-show="loading === 1">{{ lang.loading }}</span>
        <div class="vicp-progress-wrap">
          <span class="vicp-progress" v-show="loading === 1" :style="progressStyle"></span>
        </div>
        <div class="vicp-error" v-show="hasError">
          <i class="vicp-icon2"></i> {{ errorMsg }}
        </div>
        <div class="vicp-success" v-show="loading === 2">
          <i class="vicp-icon3"></i> {{ lang.success }}
        </div>
      </div>
      <div class="vicp-operate">
        <a @click="upStep" @mousedown="ripple">{{ lang.btn.back }}</a>
        <a @click="off" @mousedown="ripple">{{ lang.btn.close }}</a>
      </div>
    </div>
  </div>
</template>
<script>
'use strict';

const mimes = {
    'jpg': 'image/jpeg',
    'png': 'image/png',
    'gif': 'image/gif',
    'svg': 'image/svg+xml',
    'psd': 'image/photoshop'
  },
  // 点击波纹效果
  effectRipple = function(e, arg_opts) {
    let opts = Object.assign({
        ele: e.target, // 波纹作用元素
        type: 'hit', // hit点击位置扩散　center中心点扩展
        bgc: 'rgba(255, 255, 255, 0.15)' // 波纹颜色
      }, arg_opts),
      target = opts.ele;
    if (target) {
      let rect = target.getBoundingClientRect(),
        ripple = target.querySelector('.e-ripple');
      if (!ripple) {
        ripple = document.createElement('span');
        ripple.className = 'e-ripple';
        ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px';
        target.appendChild(ripple);
      } else {
        ripple.className = 'e-ripple';
      }
      switch (opts.type) {
        case 'center':
          ripple.style.top = (rect.height / 2 - ripple.offsetHeight / 2) + 'px';
          ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px';
          break;
        default:
          ripple.style.top = (e.pageY - rect.top - ripple.offsetHeight / 2 - document.body.scrollTop) + 'px';
          ripple.style.left = (e.pageX - rect.left - ripple.offsetWidth / 2 - document.body.scrollLeft) + 'px';
      }
      ripple.style.backgroundColor = opts.bgc;
      ripple.className = 'e-ripple z-active';
      return false;
    }
  },
  // database64文件格式转换为2进制
  data2blob = function(data, mime) {
    // dataURL 的格式为 “data:image/png;base64,****”,逗号之前都是一些说明性的文字，我们只需要逗号之后的就行了
    data = data.split(',')[1];
    data = window.atob(data);
    var ia = new Uint8Array(data.length);
    for (var i = 0; i < data.length; i++) {
      ia[i] = data.charCodeAt(i);
    };
    // canvas.toDataURL 返回的默认格式就是 image/png
    return new Blob([ia], {
      type: mime
    });
  };

export default {
  name:'Upload',
  props: {
    // 域，上传文件name，触发事件会带上（如果一个页面多个图片上传控件，可以做区分
    field: {
      type: String,
      'default': 'file'
    },
    // 原名key，类似于id，触发事件会带上（如果一个页面多个图片上传控件，可以做区分
    ki: {
      'default': 0
    },
    // 上传地址
    url: {
      type: String,
      'default': ''
    },
    // 其他要上传文件附带的数据，对象格式
    params: {
      type: Object,
      'default': null
    },
    //Add custom headers
    headers: {
      type: Object,
      'default': null
    },
    // 单文件大小限制
    maxSize: {
      type: Number,
      'default': 1024*10
    },
    // 图片上传格式
    imgFormat: {
      type: String,
      'default': 'png'
    },
    source: {
      type: String
    }
  },
  data() {
    let that = this,
      {
        imgFormat,
        langType,
        width,
        height
      } = that,

      allowImgFormat = [
        'jpg',
        'png'
      ],
      tempImgFormat = allowImgFormat.indexOf(imgFormat) === -1 ? 'jpg' : imgFormat,
      lang = {
        loading: '正在上传……',
        success: '上传成功',
        fail: '图片上传失败',
        btn: {
          off: '取消',
          close: '关闭',
          back: '上一步',
          save: '保存'
        },
        error: {
          onlyImg: '仅限图片格式',
          outOfSize: '单文件大小不能超过 ',
          lowestPx: '图片最低像素为（宽*高）：'
        }
      },
      mime = mimes[tempImgFormat];
    // 规范图片格式
    that.imgFormat = tempImgFormat;

    return {
      // 图片的mime
      mime,

      lang,
      // 上传状态及进度
      loading: 0, //0未开始 1正在 2成功 3错误
      progress: 0,

      // 是否有错误及错误信息
      hasError: false,
      errorMsg: '',
    }
  },
  computed: {
    // 进度条样式
    progressStyle() {
      let {
        progress
      } = this;
      return {
        width: progress + '%'
      }
    }
  },
  watch: {
    source(newValue) {
      if (newValue) {
        this.upload(newValue);
      }
    }
  },
  methods: {
    // 点击波纹效果
    ripple(e) {
      effectRipple(e);
    },
    // 关闭控件
    off() {
      let that = this;
      setTimeout(function() {
        that.$emit('off')
      }, 200);
    },
    /* ---------------------------------------------------------------*/

    // 检测选择的文件是否合适
    checkFile(file) {
      let that = this,
        {
          lang,
          maxSize
        } = that;
      // 仅限图片
      if (file.type.indexOf('image') === -1) {
        that.hasError = true;
        that.errorMsg = lang.error.onlyImg;
        return false;
      }

      // 超出大小
      if (file.size / 1024 > maxSize) {
        that.hasError = true;
        that.errorMsg = lang.error.outOfSize + maxSize + 'kb';
        return false;
      }
      return true;
    },
    upStep() {
      let that = this;
      setTimeout(function() {
        that.off()
        that.$emit('up-step');
      }, 200);
    },
    // 上传图片
    upload(source) {
      let that = this,
        {
          lang,
          imgFormat,
          mime,
          url,
          params,
          headers,
          field,
          ki
        } = this,
        fmData = new FormData();

      // 添加其他参数
      if (typeof params == 'object' && params) {
        Object.keys(params).forEach((k) => {
          fmData.append(k, params[k]);
        })
      }

      fmData.append(field, data2blob(source, mime), Math.floor(Math.random() * 100000000) + '.' + imgFormat);

      // 监听进度回调
      const uploadProgress = function(event) {
        if (event.lengthComputable) {
          that.progress = 100 * Math.round(event.loaded) / event.total;
        }
      };
      // 上传文件
      that.loading = 1;
      new Promise(function(resolve, reject) {
        let client = new XMLHttpRequest();
        client.open('POST', url, true);
        client.onreadystatechange = function() {
          if (this.readyState !== 4) {
            return;
          }
          if (this.status === 200) {
            resolve( this.responseText ? JSON.parse(this.responseText) : '');
          } else {
            reject(this.status);
          }
        };
        client.upload.addEventListener("progress", uploadProgress, false); //监听进度
        // 设置header
        if (typeof headers == 'object' && headers) {
          Object.keys(headers).forEach((k) => {
            client.setRequestHeader(k, headers[k]);
          })
        }
        client.send(fmData);
      }).then(
        // 上传成功
        function(resData) {
          that.loading = 2;
          that.$emit('crop-upload-success', resData, field, ki);
        },
        // 上传失败
        function(sts) {
          that.loading = 3;
          that.hasError = true;
          that.errorMsg = lang.fail;
          that.$emit('crop-upload-fail', sts, field, ki);
        }
      );
    }
  }
}
</script>
