<template>
  <view class="tn-fab-class tn-fab" @touchmove.stop.prevent>
    <view
      class="tn-fab__box"
      :class="{'tn-fab--right': left === 'auto'}"
      :style="{
        left: $tn.string.getLengthUnitValue(fabLeft || left),
        right: $tn.string.getLengthUnitValue(fabRight || right),
        bottom: $tn.string.getLengthUnitValue(fabBottom || bottom),
        zIndex: elZIndex
      }"
    >
      <view
        v-if="visibleSync"
        class="tn-fab__btns"
        :class="[`tn-fab__btns__animation--${animationType}`, 
          showFab ? `tn-fab__btns--visible--${animationType}` : ''
        ]"
      >
        <view
          v-for="(item, index) in btnList"
          :key="index"
          class="tn-fab__item"
          :class="[
            `tn-fab__item__animation--${animationType}`, 
            {'tn-fab__item--left': right === 'auto'}
          ]"
          :style="[fabItemStyle(index)]"
          @tap.stop="handleClick(index)"
        >
          <!-- 带图标或者图片时显示的文字信息 -->
          <view
            v-if="animationType !== 'around' && (item.imgUrl || item.icon)"
            :class="[left === 'auto' ? 'tn-fab__item__text--right' : 'tn-fab__item__text--left']"
            :style="{
              color: item.textColor || '#FFF',
              fontSize: $tn.string.getLengthUnitValue(item.textSize || 28)
            }"
          >{{ item.text || '' }}</view>
          
          <!-- 带图片或者图标时的图片、图标信息 -->
          <view
            class="tn-fab__item__btn"
            :class="[!item.bgColor ? backgroundColorClass : '']"
            :style="{
              width: $tn.string.getLengthUnitValue(width),
              height: $tn.string.getLengthUnitValue(height),
              lineHeight: $tn.string.getLengthUnitValue(height),
              backgroundColor: item.bgColor || backgroundColorStyle || '#01BEFF',
              borderRadius: $tn.string.getLengthUnitValue(radius)
            }"
          >
            <!-- 无图片和无图标时只显示文字 -->
            <view
              v-if="!item.imgUrl && !item.icon"
              class="tn-fab__item__btn__title"
              :style="{
                color: item.textColor || '#fff',
                fontSize: $tn.string.getLengthUnitValue(item.textSize || 28)
              }"
            >{{ item.text || '' }}</view>
            <!-- 图标 -->
            <view
              v-if="item.icon"
              class="tn-fab__item__btn__icon"
              :class="[`tn-icon-${item.icon}`]"
              :style="{
                color: item.iconColor || '#fff',
                fontSize: $tn.string.getLengthUnitValue(item.iconSize || iconSize || 64)
              }"
            ></view>
            <!-- 图片 -->
            <image
              v-else-if="!item.icon && item.imgUrl"
              class="tn-fab__item__btn__image"
              :style="{
                width: $tn.string.getLengthUnitValue(item.imgWidth || 64),
                height: $tn.string.getLengthUnitValue(item.imgHeight || 64),
              }"
              :src="item.imgUrl"
            ></image>
          </view>
        </view>
      </view>
      
      <view
        class="tn-fab__item__btn tn-fab__item__btn--fab"
        :class="[backgroundColorClass, fontColorClass, {'tn-fab__item__btn--active': showFab}]"
        :style="{
          width: $tn.string.getLengthUnitValue(width),
          height: $tn.string.getLengthUnitValue(height),
          backgroundColor: backgroundColorStyle || !backgroundColorClass ? '#01BEFF' : '',
          color: fontColorStyle || '#fff',
          borderRadius: $tn.string.getLengthUnitValue(radius),
          zIndex: elZIndex - 1
        }"
        @tap.stop="fabClick"
      >
        <slot>
          <view class="tn-fab__item__btn__icon" :class="[`tn-icon-${icon}`]" :style="{fontSize: $tn.string.getLengthUnitValue(iconSize || 64)}"></view>
        </slot>
      </view>
    </view>
    <view v-if="visibleSync && showMask" class="tn-fab__mask" :class="{'tn-fab__mask--visible': showFab}" :style="{zIndex: elZIndex - 3}" @tap="clickMask()"></view>
  </view>
</template>

<script>
  import componentsColorMixin from '../../libs/mixin/components_color.js'
  export default {
    name: 'tn-fab',
    mixins: [componentsColorMixin],
    props: {
      // 按钮列表
      // {
      //   // 背景颜色
      //   bgColor: '#fff',
      //   // 图片地址
      //   imgUrl: '',
      //   // 图片宽度
      //   imgWidth: 60,
      //   // 图片高度
      //   imgHeight: 60,
      //   // 图标名称
      //   icon: '',
      //   // 图标尺寸
      //   iconSize: 60,
      //   // 图标颜色
      //   iconColor: '#fff',
      //   // 提示文字
      //   text: '',
      //   // 文字大小
      //   textSize: 30,
      //   // 字体颜色
      //   textColor: '#fff'
      // }
      btnList: {
        type: Array,
        default() {
          return []
        }
      },
      // 自定义悬浮按钮内容
      customBtn: {
        type: Boolean,
        default: false
      },
      // 悬浮按钮的宽度
      width: {
        type: [String, Number],
        default: 88
      },
      // 悬浮按钮的高度
      height: {
        type: [String, Number],
        default: 88
      },
      // 图标大小
      iconSize: {
        type: [String, Number],
        default: 64
      },
      // 图标名称
      icon: {
        type: String,
        default: 'open'
      },
      // 按钮圆角
      radius: {
        type: [String, Number],
        default: '50%'
      },
      // 按钮距离左边的位置
      left: {
        type: [String, Number],
        default: 'auto'
      },
      // 按钮距离右边的位置
      right: {
        type: [String, Number],
        default: 'auto'
      },
      // 按钮距离底部的位置
      bottom: {
        type: [String, Number],
        default: 100
      },
      // 展示动画类型 up 往上展示 around 环绕
      animationType: {
        type: String,
        default: 'up'
      },
      // 当动画为圆环时，每个弹出按钮之间的距离, 单位px
      aroundBtnDistance: {
        type: Number,
        default: 10
      },
      zIndex: {
        type: Number,
        default: 0
      },
      // 显示遮罩
      showMask: {
        type: Boolean,
        default: true
      },
      // 点击遮罩是否可以关闭
      maskCloseable: {
        type: Boolean,
        default: true
      }
    },
    data() {
      return {
        showFab: false,
        visibleSync: false,
        timer: null,
        fabLeft: 0,
        fabRight: 0,
        fabBottom: 0,
        fabBtnInfo: {
          width: 0,
          height: 0,
          left: 0,
          right: 0,
          bottom: 0
        },
        systemInfo: {
          width: 0,
          height: 0
        },
        updateProps: false
      }
    },
    computed: {
      elZIndex() {
        return this.zIndex || this.$tn.zIndex.fab
      },
      propsData() {
        return [this.width, this.height, this.left, this.right, this.bottom]
      },
      fabItemStyle() {
        return (index) => {
          let style = {
            zIndex: this.elZIndex - 2
          }
          if (this.animationType === 'up' || !this.showFab) {
            return style
          }
          let base = 1 
          if (this.left === 'auto') {
            base = 1
          } else if (this.right === 'auto') {
            base = -1
          }
          style.transform = `rotate(${base * index * 60}deg) translateX(${(this.aroundBtnDistance + this.fabBtnInfo.width) * (-(base))}px)`
          return style
        }
      }
    },
    watch: {
      propsData() {
        // 更新按钮信息
        this.updateProps = true
      }
    },
    mounted() {
      this.$nextTick(() => {
        this.getFabBtnRectInfo()
      })
    },
    beforeDestroy() {
      if (this.timer) {
        clearTimeout(this.timer)
      }
    },
    methods: {
      // 按钮点击事件
      handleClick(index) {
        this.close()
        this.$emit('click', {index: index})
      },
      // 点击悬浮按钮
      fabClick() {
        if (this.showFab) {
          this.close()
        } else {
          // console.log(this.visibleSync);
          if (this.visibleSync) {
            this.visibleSync = false
            return
          }
          this.open()
        }
      },
      // 点击遮罩
      clickMask() {
        if (!this.showMask || !this.maskCloseable) return
        this.close()
      },
      
      open() {
        this.change('visibleSync', 'showFab', true)
        this.translateFabPosition()
      },
      close() {
        this.change('showFab', 'visibleSync', false)
        this.fabLeft = 0
        this.fabRight = 0
        this.fabBottom = 0
      },
      // 关闭时先通过动画隐藏弹窗和遮罩，再移除整个组件
      // 打开时，先渲染组件，延时一定时间再让遮罩和弹窗的动画起作用
      change(param1, param2, status) {
        this[param1] = status
        if (status) {
          // #ifdef H5 || MP
          this.timer = setTimeout(() => {
            this[param2] = status
            this.$emit(status ? 'open' : 'close')
            clearTimeout(this.timer)
          }, 10)
          // #endif
          // #ifndef H5 || MP
          this.$nextTick(() => {
            this[param2] = status
            this.$emit(status ? 'open' : 'close')
          })
          // #endif
        } else {
          this.timer = setTimeout(() => {
            this[param2] = status
            this.$emit(status ? 'open' : 'close')
            clearTimeout(this.timer)
          }, 250)
        }
      },
      
      /******************** 旋转动画相关函数 ********************/
      // 获取按钮的信息
      async getFabBtnRectInfo() {
        const systemInfo = uni.getSystemInfoSync()
        const btnRectInfo = await this._tGetRect('.tn-fab__item__btn--fab')
        if (!btnRectInfo) {
          setTimeout(() => {
            this.getFabBtnRectInfo()
          }, 10)
          return
        }
        console.log(btnRectInfo);
        this.systemInfo = {
          width: systemInfo.windowWidth,
          height: systemInfo.windowHeight
        }
        this.fabBtnInfo.width = btnRectInfo.width
        this.fabBtnInfo.height = btnRectInfo.height
        this.fabBtnInfo.left = btnRectInfo.left
        this.fabBtnInfo.right = btnRectInfo.right
        this.fabBtnInfo.bottom = btnRectInfo.bottom
      },
      // 更新悬浮按钮的位置
      translateFabPosition() {
        if (this.updateProps) {
          this.getFabBtnRectInfo()
          this.updateProps = false
        }
        if (this.animationType === 'up') return 
        // 按钮组的宽度
        const btnGroupWidth = this.fabBtnInfo.width + this.aroundBtnDistance + 10
        // 判断当前按钮是在左边还是右边
        if (this.left === 'auto' && btnGroupWidth > this.systemInfo.width - this.fabBtnInfo.right) {
          // 距离不够需要移动
          this.fabRight = btnGroupWidth + 'px'
        } else if (this.right === 'auto' && btnGroupWidth > this.fabBtnInfo.left) {
          this.fabLeft = btnGroupWidth + 'px'
        }
        
        if (btnGroupWidth > this.systemInfo.height - this.fabBtnInfo.bottom) {
          this.fabBottom = btnGroupWidth + 'px'
        }
      }
    }
  }
</script>

<style lang="scss" scoped>
  
  .tn-fab {
    &__box {
      display: flex;
      justify-content: center;
      align-items: flex-start;
      flex-direction: column;
      position: fixed;
      transition: all 0.25s ease-in-out;
    }
    
    &--right {
      align-items: flex-end;
    }
    
    &__btns {
      transition: all 0.25s cubic-bezier(0,.13,0,1.43);
      transform-origin: 80% bottom;
      
      &__animation--up {
        opacity: 0;
        transform: translateY(100%);
      }
      &__animation--around {
        position: absolute;
        top: 0;
        left: 0;
      }
      
      &--visible--up {
        // visibility: visible;
        opacity: 1;
        transform: translateY(0);
      }
      &--visible--around {
        // visibility: visible;
        // opacity: 1;
      }
    }
    
    &__item {
      display: flex;
      justify-content: flex-end;
      align-items: center;
      padding-bottom: 20rpx;
      
      &__animation--around {
        position: absolute;
        top: 0;
        left: 0;
        transition: transform 0.25s ease-in-out;
        transform-origin: 50% 50%;
        padding-bottom: 0 !important;
      }
      
      &--left {
        flex-flow: row-reverse;
      }
      
      &__text {
        &--left {
          padding-left: 14rpx;
        }
        &--right {
          padding-right: 14rpx;
        }
      }
      
      &__btn {
        display: flex;
        align-items: center;
        justify-content: center;
        box-shadow: 0 0 5rpx 2rpx rgba(0, 0, 0, 0.07);
        transition: all 0.2s linear;
        
        &--active {
          animation-name: fab-button-animation;
          animation-duration: 0.2s;
          animation-timing-function: cubic-bezier(0,.13,0,1.43);
        }
        
        &__title {
          width: 90%;
          text-align: center;
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
        }
        
        &__icon {
          text-align: center;
          font-size: 64rpx;
        }
        
        &__image {
          display: block;
        }
      }
    }
    
    &__mask {
      position: fixed;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background-color: rgba(0, 0, 0, 0.4);
      transition: all 0.2s ease-in-out;
      opacity: 0;
      
      &--visible {
        opacity: 1;
      }
    }
  }
  
  @keyframes fab-button-animation {
    0% {
      transform: scale(0.6);
    }
    // 20% {
    //   transform: scale(1.8);
    // }
    // 40% {
    //   transform: scale(0.4);
    // }
    // 50% {
    //   transform: scale(1.4);
    // }
    // 80% {
    //   transform: scale(0.8);
    // }
    100% {
      transform: scale(1);
    }
  }
</style>
