LiveFixture.vue 10.5 KB
<template>
  <div class="live-fixture-page acce-render">
    <template v-for="(game_list, i) in cacheDate">
      <transition name="slideInRight" v-if="game_list" :key="game_list">
        <PullRefresh v-show="i == fitterIndex" v-model="is_Refresh" @refresh="get_game_list">
          <List id="liveFixture" ref="liveFixture" :loading="is_loading" :finished="is_finished" finished-text="没有更多了"
            :style="{ 'min-height': minHigeht + 'px' }">
            <template v-for="(item, index) in game_list" :key="item">
              <!-- <div v-if="item.status == 8 && (game_list[index - 1] && game_list[index - 1].status != 8 || !game_list[index - 1])" class="separator">
                ———&nbsp;&nbsp;&nbsp;已结束&nbsp;&nbsp;&nbsp;———
              </div> -->
              <Match v-if="matchShow(i, index)" class="match-box" :data="item" :note="matchNote(item.id)" :otherData="matchOtherData(item.id)"
                @domHeight="changeCacheHeight" @showMore="changeShowMore" :isShow="showMore == item.id" :isJz="fitterIndex == 1">
              </Match>
              <div v-else-if="cacheHeight[item.id]" :style="{ height: cacheHeight[item.id] + 'px' }"></div>
              <div v-else></div>
            </template>
          </List>
        </PullRefresh>
      </transition>
    </template>
  </div>
</template>

<script lang="ts">
export default { name: 'LiveFixture' };
</script>

<script lang="ts" setup>
import { ref, toRef, computed, onBeforeMount, onActivated, onDeactivated, defineProps, watch } from 'vue';
import { useStore } from 'vuex';
import { List, PullRefresh } from 'vant';
import * as live_api from '@/api/live_api';
import Match from './component/Match.vue';
import { default as _ } from 'lodash';
import moment from 'moment';

const store: any = useStore();
const is_first = ref(true);
const is_loading = ref(false);
const is_Refresh = ref(false);
const is_finished = ref(false);

// 过滤
const defaultTimeDay = moment(store.state.server_time).add(1, 'days');
const props: any = defineProps({
  fitterIndex: {
    type: Number,
    required: true,
    default: () => { return 0; }
  },
  fitterTimeFixture: {
    type: Object,
    required: false,
    default: () => { return {}; }
  }
});
const fitterIndex: any = toRef(props, 'fitterIndex');
const fitterTime: any = computed(() => {
  let date = props.fitterTimeFixture;
  return JSON.stringify(date) != '{}' ? date : defaultTimeDay;
});
watch(() => fitterTime.value, () => {
  get_game_list();
  window.scrollTo({ top: 0 });
});

// 比赛数据
const get_game_list = async () => {
  try {
    if (is_first.value) is_loading.value = true;
    else is_Refresh.value = true;
    is_finished.value = false;
    let game_list_date: any = await live_api.nm_match_list({ match_date: moment(fitterTime.value).format('YYYY-MM-DD') });
    if (game_list_date?.data?.data?.nm_match_list) {
      store.commit('updateMatchListFixture', game_list_date.data.data.nm_match_list);
      is_loading.value = false;
      is_finished.value = true;
    }
    if (is_first.value) is_loading.value = false;
    else is_Refresh.value = false;
    is_finished.value = true;
    is_first.value = false;
  } catch (error) {
    if (is_first.value) is_loading.value = false;
    else is_Refresh.value = false;
    is_finished.value = true;
    is_first.value = false;
  }
};
const isUnusual = (data: any) => { // 是否异常
  let updateWsTime = store.state.updateWsTime || null;
  let status = data?.status || null;
  let isError = false;
  if (!updateWsTime || !status) return isError;
  // 已到比赛时间但状态未开始 || 进行中的比赛不存在ws数据
  if (updateWsTime > data.match_time && status < 2 || ([2, 3, 4, 5, 6, 7].includes(status) && !store.state.nm_live_message[data.id])) {
    isError = true;
  }
  return isError;
};
const gameSort = (arr: any) => {
  const order_end: any = { 8: 1, 9: 2, 10: 3, 11: 4, 12: 5, 13: 6, 0: 7 };
  return arr.sort((a: any, b: any) => {
    const aSortIndex = order_end[a.status] || 0;
    const bSortIndex = order_end[b.status] || 0;
    return aSortIndex - bSortIndex || a.match_time - b.match_time;
  });
};
const match_list_fixture = computed(() => { return _.clone(store.state.match_list_fixture); });
const cacheDate = computed(() => {
  let arr: any = [[], [], [], [], []];
  for (let i = 0; i < match_list_fixture.value.length; i++) {
    let item = match_list_fixture.value[i];
    if (item && !isUnusual(item)) {
      arr[0].push(item);
      if (item.is_zucai) arr[3].push(item);
      if (item.is_jingcai || item.is_beidan) {
        arr[4].push(item);
        if (item.is_jingcai) arr[1].push(item);
        if (item.is_beidan) arr[2].push(item);
      }
    }
  }
  for (let i = 0; i < arr.length; i++) { arr[i] = gameSort(arr[i]); }
  return arr;
});

// 即时数据
const nm_live_message = computed(() => {
  return store.state.nm_live_message;
});

// 优化
const current = ref([0, 25]);
const c_m_h: any = ref({
  header: 0,
  top: 0,
  center: 0,
  bottom: 0,
  more: 0,
  note: 0,
  paddingBottom: 0,
  finishedText: 0
});
const item_h: any = computed(() => {
  return c_m_h.value.top + c_m_h.value.center + c_m_h.value.bottom + c_m_h.value.paddingBottom;
});
const oldScrollTop: any = ref(0);
const leaveScrollTop: any = ref(0);
const cacheHeight: any = ref({});
const changeCacheHeight: any = (id: any, domHeight: any) => {
  if (cacheHeight.value[id] === domHeight || domHeight < 1) return;
  cacheHeight.value[id] = domHeight;
};
const get_c_m_h = async () => {
  if (c_m_h.value.header < 1) {
    let header: any = document.getElementsByClassName('reserve-box')[0];
    if (header?.offsetHeight > 0) c_m_h.value.header = header?.offsetHeight;
  }
  if (c_m_h.value.top < 1) {
    let top: any = document.getElementsByClassName('match-top')[0];
    if (top?.offsetHeight > 0) c_m_h.value.top = top?.offsetHeight;
  }
  if (c_m_h.value.top < 1) {
    let top: any = document.getElementsByClassName('match-top')[0];
    if (top?.offsetHeight > 0) c_m_h.value.top = top?.offsetHeight;
  }
  if (c_m_h.value.center < 1) {
    let center: any = document.getElementsByClassName('match-center')[0];
    if (center?.offsetHeight > 0) c_m_h.value.center = center?.offsetHeight;
  }
  if (c_m_h.value.bottom < 1) {
    let bottom: any = document.getElementsByClassName('match-bottom')[0];
    if (bottom?.offsetHeight > 0) c_m_h.value.bottom = bottom?.offsetHeight;
  }
  if (c_m_h.value.more < 1) {
    let more: any = document.getElementsByClassName('match-more')[0];
    if (more?.offsetHeight > 0) c_m_h.value.more = more?.offsetHeight;
  }
  if (c_m_h.value.note < 1) {
    let note: any = document.getElementsByClassName('match-note')[0];
    if (note?.offsetHeight > 0) c_m_h.value.note = note?.offsetHeight;
  }
  if (c_m_h.value.finishedText < 1) {
    let finishedText: any = document.getElementsByClassName('van-list__finished-text')[0];
    if (finishedText?.offsetHeight > 0) c_m_h.value.finishedText = finishedText?.offsetHeight;
  }
  if (c_m_h.value.paddingBottom < 1) {
    let item_dom: any = document.getElementsByClassName('match-box')[0];
    if (item_dom && (window as any)?.getComputedStyle(item_dom)?.paddingBottom) {
      c_m_h.value.paddingBottom = Number(window.getComputedStyle(item_dom).paddingBottom.split('px')[0]);
    }
  }
};
const getCurrentIndex = (scrollTop: any) => {
  let list = _.clone(cacheDate.value[fitterIndex.value]);
  let scrollBottom = scrollTop + window.innerHeight;
  if (scrollTop + 200 < window.innerHeight) return [0, 25];
  if (scrollBottom + 200 >= document.body.clientHeight) return [list.length - 25, list.length];
  let top = c_m_h.value.header, topIndex = { isEnd: false, index: current.value[0] };
  let bottom = c_m_h.value.header, bottomIndex = { isEnd: false, index: current.value[1] };
  list.forEach((item: any, index: any) => {
    if (top < scrollTop) {
      top += cacheHeight[item.id] || item_h.value;
    } else if (!topIndex.isEnd) {
      topIndex.index = (index - 10) < 0 ? 0 : index - 10;
      topIndex.isEnd = true;
    }
    if (bottom < scrollBottom) {
      bottom += cacheHeight[item.id] || item_h.value;
    } else if (!bottomIndex.isEnd) {
      bottomIndex.index = (index + 10) > list.length ? list.length : index + 10;
      bottomIndex.isEnd = true;
    }
    if (topIndex.isEnd && bottomIndex.isEnd) return;
  });
  let indexTop = topIndex.index > (list.length - 25) ? list.length - 25 : topIndex.index;
  let indexBottom = bottomIndex.index < 25 ? 25 : bottomIndex.index;
  return [indexTop, indexBottom];
};
const fixtureScrollEvent = () => {
  let scrollTop: any = document.documentElement.scrollTop;
  if (oldScrollTop.value > 0 && Math.abs(oldScrollTop.value - scrollTop) < 80) return;
  oldScrollTop.value = scrollTop;
  get_c_m_h();
  current.value = getCurrentIndex(scrollTop);
};
const fixtureScrollInit = async () => { // 重置
  c_m_h.value = {
    header: 0,
    top: 0,
    center: 0,
    bottom: 0,
    more: 0,
    note: 0,
    paddingBottom: 0,
    finishedText: 0
  };
  cacheHeight.value = {};
  oldScrollTop.value = 0;
};

// match组件传参
const matchShow = (i: any, index: any) => {
  return i == fitterIndex.value && index >= current.value[0] && index < current.value[1];
};
const matchOtherData = (id: any) => {
  return nm_live_message.value[id]?.stats;
};
const matchNote = (id: any) => {
  return nm_live_message.value[id]?.score[5];
};
const showMore: any = ref(null);
const changeShowMore: any = (id: any, is: any) => {
  if (!showMore.value || showMore.value != id) {
    showMore.value = id;
  } else {
    showMore.value = null;
  }
};

// 列表最小高度(下拉刷新优化)
const minHigeht = computed(() => {
  return window.innerHeight - c_m_h.value.header;
});

// 页面创建前
onBeforeMount(async () => {
  await get_game_list();
});
// 页面显示
onActivated(() => {
  oldScrollTop.value = 0;
  window.addEventListener('scroll', fixtureScrollEvent);
  window.addEventListener('resize', fixtureScrollInit);
  // 滚动条复位:设置延迟,避免动画效果影响
  let timer: any = setTimeout(() => {
    window.scrollTo({ top: leaveScrollTop.value });
    clearTimeout(timer);
    timer = null;
  }, 300);
});
// 页面隐藏
onDeactivated(() => {
  window.removeEventListener('scroll', fixtureScrollEvent);
  window.removeEventListener('resize', fixtureScrollInit);
  leaveScrollTop.value = document.documentElement.scrollTop;
});
</script>

<style lang="scss" scoped>
#liveFixture {
  padding: 5px 2px 0 2px;

  >div {
    padding-bottom: 5px;
    min-height: 103px;
  }

  .separator {
    color: #969799;
    font-size: 14px;
    height: 35px;
    min-height: 35px;
    line-height: 35px;
    padding-bottom: 5px;
  }
}
</style>