<script setup lang="ts">
import { Ref } from 'vue';

interface Props {
  anchorDatas: any[];
  viewType: string;
  viewTag: string;
}
const props = withDefaults(defineProps<Props>(), {});

/**
 * 绘制UI数据
 *
 * @type {any}
 * @memberof AppAnchor
 */
let datas: any[] = props.anchorDatas;

/**
 * 组件ref
 *
 * @type {any}
 * @memberof AppAnchor
 */
let appAnchor: Ref<any> = ref(null);

/**
 * 滚动盒子
 *
 * @type {any}
 * @memberof AppAnchor
 */
let container: any = ref(null);

/**
 * Vue生命周期onBeforeMount
 */
onBeforeMount(() => {
  datas.forEach((item: any) => {
    item.active = false;
  });
});

/**
 * Vue生命周期mounted
 */
onMounted(() => {
  // 需要异步获取，有些编辑器绘制慢，确保高度获取正确
  setTimeout(() => {
    computeAppAnchorLayout();
    // 获取滚动区域
    getScrollContainer();
    // 获取锚点到滚动条盒子顶部的距离
    setSrollHeight();
    // 滚动区域滚动时
    handleScroll();
    // 初始化默认锚点激活状态
    initActiveState();
  }, 0);
});

/**
 * Vue生命周期onUpdated
 */
onUpdated(() => {
  // 获取锚点到滚动条盒子顶部的距离
  setSrollHeight();
});

/**
 * Vue生命周期unmounted
 */
onUnmounted(() => {
  if (container.value) {
    container.value.removeEventListener('scroll', scrollEvent);
  }
});

/**
 * 计算锚点位置
 *
 * @memberof AppAnchor
 */
const computeAppAnchorLayout = () => {
  if (appAnchor.value && appAnchor.value.parentNode) {
    const parent = appAnchor.value.parentNode;
    const top = parent.getBoundingClientRect()?.top;
    const right = document.body.clientWidth - parent.getBoundingClientRect()?.right;
    appAnchor.value.style.top = top + 20 + 'px';
    appAnchor.value.style.right = right + 'px';
  }
}

/**
 * 获取滚动区域
 *
 * @memberof AppAnchor
 */
const getScrollContainer = () => {
  switch (props.viewType) {
    case 'DEEDITVIEW3':
      // TODO
      break;
    case 'DEEDITVIEW':
    default:
      container.value = document.querySelector(`.${props.viewTag?.toLowerCase()} .app-view-layout__body`);
      break;
  }
};

/**
 * 滚动事件
 *
 * @memberof AppAnchor
 */
const scrollEvent = (e: any) => {
  let scrollTop = e.target.scrollTop;
  datas.forEach(item => {
    item.active = false;
  });
  let i = -1;
  while (++i <= datas.length) {
    let currentEle = datas[i];
    let nextEle = datas[i + 1];
    if (scrollTop >= currentEle.scrollTop && scrollTop < ((nextEle && nextEle.scrollTop) || Infinity)) {
      datas[i].active = true;
      break;
    }
  }
};

/**
 * 滚动区域滚动
 *
 * @memberof AppAnchor
 */
const handleScroll = () => {
  if (container.value) {
    container.value.addEventListener('scroll', scrollEvent);
  }
};

/**
 * 获取锚点到滚动条盒子顶部的距离
 *
 * @memberof AppAnchor
 */
const setSrollHeight = () => {
  if (container.value) {
    // 容器实际高度
    const actualHeight: number = container.value.scrollHeight;
    // 容器可视区域高度
    const visualHeight: number = container.value.offsetHeight;
    // 容器滑动条最大高度
    const scrollHeight: number = actualHeight - visualHeight;
    // 系数
    // const coefficient = scrollHeight / actualHeight;
    datas.forEach((item: any) => {
      let dom: any = document.querySelector(`.app-form .${item.codeName}`);
      if (dom) {
        // 获取锚点元素与滚动盒子元素相对于视口的距离
        let domTop: number = dom.getBoundingClientRect().top;
        let containerTop: number = container.value.getBoundingClientRect().top;
        let containerScrollTop: number = container.value.scrollTop;
        // 获取需要滚动的距离
        let total = Math.trunc(domTop - (containerTop - containerScrollTop));
        item.scrollTop = total;
      }
    });
  }
};

/**
 * 设置锚点激活状态
 *
 * @memberof AppAnchor
 */
const initActiveState = () => {
  if (datas?.length > 0) {
    handleClick(datas[0], 0);
  }
};

/**
 * 处理点击事件
 */
const handleClick = (item: any, index: any) => {
  // 设置滚动
  if (container.value) {
    container.value.scrollTop = item.scrollTop;
  }
};
</script>

<template>
  <div
    class="app-anchor"
    ref="appAnchor"
  >
    <div class="line"></div>
    <div
      :class="['anchor-points', item.active ? 'active' : 'inactive']"
      v-for="(item, index) in datas"
      :key="item.codeName"
      @click.stop="handleClick(item, index)"
      :ref="item.codeName"
    >
      <span
        class="dot"
        v-if="item.active"
      ></span>
      {{ item.caption }}
    </div>
  </div>
</template>

<style lang="scss" scoped>
.app-anchor {
  position: fixed;
  top: 20px;
  max-width: 200px;
  z-index: 99;
  border-radius: 4px;
  padding: 10px 10px 10px 20px;
  background: rgb(227, 237, 250);
  .line {
    width: 2px;
    position: absolute;
    height: calc(100% - 20px);
    left: 10px;
    background: #fff;
  }
  .anchor-points {
    padding: 2px 0px;
    cursor: pointer;
    color: #b4bcca;
  }
  .active {
    color: #2196f3;
    position: relative;
    .dot {
      position: absolute;
      display: inline-block;
      top: 0px;
      left: -10px;
      width: 2px;
      height: 25px;
      background-color: #2196f3;
    }
  }
}
</style>