vue3 下拉刷新

<script setup lang="ts">
import { Empty } from 'ant-design-vue';

const props = withDefaults(defineProps<{
  modelValue: any[] // 重要: 外部在使用这个的时候,不要修改,要通过endSuccess这些方法来修改
  defaultPageSize: number
  defaultPage: number
}>(), {
  modelValue: () => [],
  defaultPageSize: 10,
  defaultPage: 1,
});

const emit = defineEmits<{
  (e: 'update:modelValue', val: any[]): void
  (e: 'load', val: { page: number, pageSize: number }): void
}>();

const simpleImage = Empty.PRESENTED_IMAGE_SIMPLE;

const dataSource = ref<any[]>([]);
const page = ref(props.defaultPage);
const pageSize = ref(props.defaultPageSize);
const noMoreData = ref(false); // 是否有更多数据
const loading = ref(false); // 是否正在加载中

let lockFlag = false; // 锁,用于保证一次加载只能调用一次回调方法

watch(() => props.modelValue, () => {
  dataSource.value = props.modelValue || [];
}, { immediate: true });

onMounted(() => {
  // dataSource.value = [];
  // page.value = props.defaultPage;
  // pageSize.value = props.defaultPageSize;
  // noMoreData.value = false;
  // loading.value = false;
  nextTick(() => {
    lockFlag = false;
    emit('load', { page: page.value, pageSize: pageSize.value });
  });
});

/**
 * 加载更多
 */
function loadMore() {
  if (noMoreData.value) {
    return;
  }
  if (loading.value) {
    return;
  }
  loading.value = true;
  lockFlag = false;
  emit('load', { page: page.value, pageSize: pageSize.value });
}

function endSuccess(data: any[]) {
  if (lockFlag) {
    return;
  }
  lockFlag = true;
  if (page.value === 1) {
    dataSource.value = data;
  }
  else {
    dataSource.value = [...dataSource.value, ...data];
  }

  if (data.length < pageSize.value) {
    noMoreData.value = true;
  }
  else {
    noMoreData.value = false;
    page.value += 1;
  }
  emit('update:modelValue', [...dataSource.value]);
  loading.value = false;
}

function endError() {
  if (lockFlag) {
    return;
  }
  lockFlag = true;
  loading.value = false;
}

function reload() {
  if (loading.value && page.value === props.defaultPage) {
    return;
  }
  dataSource.value = [];
  page.value = props.defaultPage;
  pageSize.value = props.defaultPageSize;
  noMoreData.value = false;
  loading.value = false;
  emit('update:modelValue', []);
  lockFlag = false;
  emit('load', { page: page.value, pageSize: pageSize.value });
}

defineExpose({
  endSuccess,
  endError,
  reload,
});
</script>

<template>
  <div class="loadmore-list">
    <ScrollLoad class="loadmore-list-body" @load-more="loadMore">
      <div v-if="!dataSource.length">
        <a-empty :image="simpleImage" />
      </div>
      <template v-else>
        <slot />
      </template>
    </ScrollLoad>
  </div>
</template>

<style lang="less" scoped>
.loadmore-list {
  width: 100%;
  height: 100%;
  overflow: hidden;
  .loadmore-list-body {
    width: 100%;
    height: 100%;
    // overflow: auto;
    overflow-x:hidden;
    overflow-y:auto;
  }
}
</style>
<script setup lang="ts">
import loadMoreList from '@/views/components/loadMoreList.vue';
import eventsave from "./eventsave.vue";
import { TYPE, LEVEL, STATUS, levleText, imgUrl } from './enums.ts'
const props = defineProps({
  isupdata: {
    type: Boolean,
    default: false
  }
});
watch(() => props.isupdata, () => {
  if (props.isupdata) {
    _getEventPageQuery()
  }
}, {
  deep: true
});
const list: any = ref([
])
const formpramas = ref({
  pageQueryDTO: {
    currentPage: 1,
    pageSize: 3,
    districtCode: '',
    typ: '',
    level: ''
  }
})
const loadMoreListRef = ref()
const emit = defineEmits(['detail', 'listfirst', 'leftupdata']);
function _getEventPageQuery() {
  getEventPageQuery(formpramas.value).then(res => {
    if (res.success) {
      let d = res.data?.records || [];
      if (d && d.length > 0) {
        (window as any).cMap.glowWayline.addRiskBillboard(d);
      }

      if (d && d.length) {
        d.forEach((item) => {
          item.title = levleText(item.level)
          item.imgUrl = imgUrl(item.type)
        })
        // list.value = d;
        loadMoreListRef.value.endSuccess(d);
        emit('listfirst', list.value[0])
      }
    } else {
      loadMoreListRef.value.endError();
    }
  })
}


//详情
function detail(item: any) {
  emit('detail', item)
}
//加载更多
function getList(pageConfig: { page: number, pageSize: number }) {
  formpramas.value.pageQueryDTO.currentPage = pageConfig.page;
  formpramas.value.pageQueryDTO.pageSize = pageConfig.pageSize;
  _getEventPageQuery()
}
const eventsaveRef = ref();

//应急救援告警接收
function add() {
  eventsaveRef.value.show();
}
function getsaveupdata() {
  //保存成功了
  emit('leftupdata')
}
</script>
<template>
  <div class="w-full h-full">
    <div class="tt-text" @click="add">
      <span>应急救援告警接收</span>
    </div>
    <div class="list-box h-full">
      <loadMoreList ref="loadMoreListRef" v-model="list" @load="getList" :default-page-size="3" :default-page="1">
        <div class="sub" v-for="item in list" @click="detail(item)">
          <div class="tit">
            <span class="s-text">
              <img :src="item.imgUrl" alt="">
              {{ TYPE[item.type] }}
            </span>
            <span class="s-status" :class="`color${item.level}`">
              {{ LEVEL[item.level] }}
              <a-tooltip placement="right" :title="item.title" v-if="item.level">
                <PubSvgIcon name="wenhao" size="12" class="cursor-pointer ml-0.5" />
              </a-tooltip>
            </span>
          </div>
          <div class="cont">
            <div class="cont-sub mt-[6px] justify-between">
              <div>
                关联飞行计划:
              </div>
              <div>
                <a-tooltip placement="right" :title="item.planName">
                  <span>{{ item.planName }}</span>
                </a-tooltip>
              </div>
              <div>
                <span :class="`color${item.status}`">
                  {{ STATUS[item.status] }}
                </span>
              </div>
            </div>
            <div class="cont-sub">
              <div>
                事故发生时间:
              </div>
              <div>
                {{ item.accidentTime }}
              </div>
            </div>
            <div class="cont-sub">
              <div>
                事故地点:
              </div>
              <div class="hidd-cla">
                <a-tooltip placement="right" :title="item.place">
                  <span>{{ item.place }}</span>
                </a-tooltip>
              </div>
            </div>
            <div class="cont-sub">
              <div>
                管理单位:
              </div>
              <div>
                {{ item.orgName }}
              </div>
            </div>
          </div>
        </div>
      </loadMoreList>
    </div>
    <!-- 保存应急救援告警接收 -->
    <eventsave ref="eventsaveRef" @saveupdata="getsaveupdata"></eventsave>
  </div>
</template>
<style lang="less" scoped>
.tt-text {
  position: absolute;
  right: 0;
  top: -4px;
  background: url(@/assets/images/rescue/left2-titbg.png)no-repeat center center;
  background-size: 100% 100%;
  width: 130px;
  // height: 24px;
  line-height: 24px;
  text-align: center;
  cursor: pointer;

  span {

    font-family: youshe;
    font-size: 14px;
    color: #FFFFFF;
    text-align: center;
    text-shadow: 0 0 8px #46B5FF;
  }
}

.list-box {
  overflow-y: auto;
  overflow-x: hidden;
  // overflow: hidden;

  .sub {
    padding: 10px 10px 12px 16px;
    background: url(@/assets/images/rescue/left2-listsub-bg.png)no-repeat center center;
    background-size: 100% 100%;
    width: 344px;
    height: 158px;
    margin-bottom: 9px;
    cursor: pointer;

    .tit {
      display: flex;
      justify-content: space-between;
      height: 21px;

      .s-text {
        display: flex;
        align-items: center;

        img {
          width: 15px;
          height: 15px;
          margin-right: 5px;
        }

        font-family: youshe;
        font-size: 16px;
        color: #FFFFFF;
        text-shadow: 0 2px 4px #21538480;
      }

      .s-status {
        font-family: PingFangSC-Regular;
        font-weight: 400;
        font-size: 12px;
        color: #FFFFFF;
        text-align: center;
        display: flex;
        width: 50px;
        height: 20px;
        border-radius: 4px;
        align-items: center;
        justify-content: center;

        &.color1 {
          background-image: radial-gradient(circle at 13% 20%, #93ffec99 0%, #39f1ff00 38%), linear-gradient(248deg, #4decff1a 0%, #00efffcc 100%);
          box-shadow: inset 6px -6px 8px 0 #40fff652;
        }

        &.color2 {
          background-image: radial-gradient(circle at 13% 20%, #FFD293 0%, #ffa83900 38%), linear-gradient(248deg, #ff9b4d1a 0%, #FF9600 100%);
          box-shadow: inset 6px -6px 8px 0 #ff404052;
        }

        &.color3 {

          background-image: radial-gradient(circle at 13% 20%, #FF9393 0%, #ff393900 38%), linear-gradient(248deg, #ff4d4d1a 0%, #D70000 100%);
          box-shadow: inset 6px -6px 8px 0 #ff404052;
        }
      }
    }

    .cont {
      height: 112px;

      .cont-sub {
        display: flex;
        font-family: PingFangSC-Regular;
        font-weight: 400;
        font-size: 14px;
        margin-bottom: 4px;
        // height: 20px;
        line-height: 20px;
        // justify-content: space-between;

        div:nth-of-type(1) {
          // width: 98px;
          color: #F7F7F7;
        }

        div:nth-of-type(2) {
          width: 160px;
          color: #ffffffb3;
          display: -webkit-box;
          -webkit-box-orient: vertical;
          -webkit-line-clamp: 2;
          overflow: hidden;
          text-overflow: ellipsis;
        }

        div:nth-of-type(3) {
          span {
            font-family: PingFangSC-Regular;
            font-weight: 400;
            font-size: 12px;
            color: #FFFFFF;
            text-align: center;
            display: flex;
            width: 50px;
            height: 20px;
            border-radius: 4px;
            align-items: center;
            justify-content: center;

            &.color1 {

              background-image: radial-gradient(circle at 13% 20%, #FF9393 0%, #ff393900 38%), linear-gradient(248deg, #ff4d4d1a 0%, #D70000 100%);
              box-shadow: inset 6px -6px 8px 0 #ff404052;
            }

            &.color2 {
              background-image: radial-gradient(circle at 13% 20%, #FFD293 0%, #ffa83900 38%), linear-gradient(248deg, #ff9b4d1a 0%, #FF9600 100%);
              box-shadow: inset 6px -6px 8px 0 #ff404052;
            }

            &.color3 {

              background-image: radial-gradient(circle at 13% 20%, #93ffec99 0%, #39f1ff00 38%), linear-gradient(248deg, #4decff1a 0%, #00efffcc 100%);
              box-shadow: inset 6px -6px 8px 0 #40fff652;
            }
          }
        }

        .hidd-cla {
          width: 180px !important;
          -webkit-line-clamp: 1 !important;
        }
      }
    }
  }
}
</style>

 

posted @ 2024-12-27 12:24  abcByme  阅读(14)  评论(0编辑  收藏  举报