page-helper-evo.vue 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. <script setup lang="ts" generic="T extends Object, R extends { list: T[] }, Q extends T">
  2. import { ResPageData } from '@designer-hub/app/src/core/libs/models'
  3. import { NetImages } from '../core/libs/net-images'
  4. import { getRect, addUnit } from 'wot-design-uni/components/common/util'
  5. const props = withDefaults(
  6. defineProps<{
  7. request: (query: any) => Promise<IResData<R>>
  8. query?: Partial<Q> & { [key: symbol]: any }
  9. automatic?: boolean
  10. }>(),
  11. { automatic: true, query: () => ({}) },
  12. )
  13. const slot = defineSlots<{
  14. default(props: { data?: R['list']; items?: T[]; source?: R }): any
  15. top: () => any
  16. }>()
  17. const { proxy } = getCurrentInstance() as any
  18. const pageNo = ref(1)
  19. const pageSize = ref(10)
  20. const nomore = ref(false)
  21. const topRef = ref()
  22. const height = ref(0)
  23. const windowInfo = ref<UniNamespace.GetWindowInfoResult>()
  24. const { data, run: setData } = useRequest(
  25. () => props.request({ pageNo: pageNo.value, pageSize: pageSize.value, ...props.query }),
  26. { immediate: false },
  27. )
  28. const items = ref<T[]>([])
  29. const setPlaceholderHeight = () => {
  30. getRect('.bottom-app-bar', false, proxy).then((res) => {
  31. height.value = res.height as number
  32. })
  33. }
  34. onMounted(async () => {
  35. nextTick(() => {
  36. setPlaceholderHeight()
  37. })
  38. windowInfo.value = await uni.getWindowInfo()
  39. if (props.automatic) {
  40. console.log('Page Helper Automatic')
  41. await setData()
  42. items.value = data.value?.list || data.value || []
  43. }
  44. })
  45. watch(
  46. () => props.query,
  47. async () => {
  48. console.log('Page Helper Query Change')
  49. pageNo.value = 1
  50. pageSize.value = 10
  51. await setData()
  52. items.value = data.value?.list || []
  53. },
  54. )
  55. onReachBottom(async () => {
  56. if (nomore.value) return
  57. console.log('Page Helper Reach Bottom')
  58. if (data.value?.list?.length < pageSize.value) {
  59. return (nomore.value = true)
  60. }
  61. pageNo.value++
  62. await setData()
  63. items.value = items.value.concat(data.value?.list || [])
  64. })
  65. defineExpose({
  66. reload: async () => {
  67. console.log('Page Helper Reload')
  68. pageNo.value = 1
  69. pageSize.value = 10
  70. await setData()
  71. items.value = data.value?.list || data.value || []
  72. },
  73. refresh: async () => {
  74. console.log('Page Helper Refresh')
  75. console.log(items.value.length)
  76. await setData()
  77. // 之前页的数据
  78. const prevItems = items.value.slice(0, pageSize.value * (pageNo.value - 1))
  79. console.log(prevItems.length)
  80. // 之后页的数据
  81. const nextItems = items.value.slice(pageSize.value * pageNo.value, items.value.length)
  82. console.log(nextItems.length)
  83. items.value = prevItems.concat(data.value?.list || [], nextItems)
  84. console.log(items.value.length)
  85. // console.log(items.value)
  86. },
  87. })
  88. </script>
  89. <script lang="ts">
  90. export default {
  91. options: {
  92. virtualHost: true,
  93. styleIsolation: 'shared',
  94. },
  95. }
  96. </script>
  97. <template>
  98. <div
  99. class="flex-grow flex flex-col"
  100. :style="{ paddingBottom: addUnit(windowInfo?.safeAreaInsets.bottom || 0) }"
  101. >
  102. <div class="relative" :style="{ height: addUnit(height) }">
  103. <div
  104. ref="topRef"
  105. class="bottom-app-bar fixed absolute left-0 right-0 z-1"
  106. :style="{ top: addUnit(windowInfo?.windowTop || 0) }"
  107. >
  108. <!-- {{ topRef.offsetHeight }} -->
  109. <slot name="top"></slot>
  110. </div>
  111. </div>
  112. <div class="flex-grow flex flex-col">
  113. <template v-if="!items?.length">
  114. <div class="flex-grow flex flex-col justify-center">
  115. <wd-status-tip :image="NetImages.NotContent" tip="暂无内容"></wd-status-tip>
  116. </div>
  117. </template>
  118. <div v-if="items.length" class="flex-grow flex flex-col">
  119. <slot :source="{ list: items }"></slot>
  120. </div>
  121. <template v-if="nomore">
  122. <div class="my-4"><wd-divider>没有更多了</wd-divider></div>
  123. </template>
  124. </div>
  125. </div>
  126. </template>