index.vue 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. <script lang="ts" setup>
  2. import { computed, ref } from 'vue'
  3. import { useScroll } from '@/hooks/useScroll'
  4. import { useShare } from '@/hooks/useShare'
  5. import { safeAreaInsets } from '@/utils'
  6. import { getCouponByType, getCouponDetail } from '../../api/home'
  7. import SpendAndSaveCoupon from '../../components/SpendAndSaveCoupon_large.vue'
  8. definePage({
  9. style: {
  10. navigationBarTitleText: '',
  11. navigationStyle: 'custom',
  12. // 禁用默认下拉刷新
  13. enablePullDownRefresh: false,
  14. },
  15. })
  16. const params = ref()
  17. // 使用内置的useScroll hooks
  18. const {
  19. list: data, // 响应式的数据列表
  20. loading, // 是否加载中
  21. finished, // 是否已全部加载
  22. error, // 是否加载失败
  23. refresh: onRefresh, // 下拉刷新方法
  24. loadMore: onLoadMore, // 加载更多方法
  25. } = useScroll({
  26. fetchData: async (page, pageSize) => {
  27. const response = await getCouponByType({
  28. pageNo: page,
  29. pageSize,
  30. ...params.value,
  31. })
  32. return response.records || []
  33. },
  34. pageSize: 7,
  35. })
  36. const { getShareConfig: getShareCouponConfig } = useShare({
  37. shareType: 'COUPON',
  38. imageSource: 'REMOTE',
  39. path: '/pages/receiveCoupon/index',
  40. pathParamKey: 'couponShareRecordId',
  41. })
  42. // #ifdef MP-WEIXIN
  43. // 分享功能实现
  44. // 分享生命周期函数
  45. onShareAppMessage(async (options) => {
  46. if (options.from === 'button' && options.target.dataset.shareType === 'coupon') {
  47. const couponId = options.target.dataset.couponId
  48. const couponinfo = await getCouponDetail({ templateId: couponId })
  49. return await getShareCouponConfig({
  50. imageUrl: couponinfo?.imageUrl,
  51. }, {
  52. shareContentId: couponId,
  53. })
  54. }
  55. return null
  56. })
  57. // #endif
  58. // 计算底部安全区高度
  59. const safeBottomHeight = computed(() => {
  60. return safeAreaInsets?.bottom || 0
  61. })
  62. const topSafeAreaHeight = safeAreaInsets?.top || 0
  63. // 页面加载时获取数据
  64. onLoad((options) => {
  65. if (options.type) {
  66. params.value = options
  67. onRefresh()
  68. }
  69. })
  70. </script>
  71. <template>
  72. <view class="page-container">
  73. <up-navbar title="满减券" :auto-back="true" />
  74. <up-status-bar />
  75. <scroll-view :style="{ paddingTop: `${topSafeAreaHeight}px` }" class="discount-coupon-list" scroll-y
  76. refresher-enabled :refresher-triggered="loading" @refresherrefresh="onRefresh" @scrolltolower="onLoadMore">
  77. <view class="list-content">
  78. <view v-for="item in data" :key="item.templateId" class="discount-coupon-item">
  79. <SpendAndSaveCoupon :coupon="item" />
  80. </view>
  81. <!-- 加载状态提示 -->
  82. <view v-if="loading && data.length > 0" class="loadmore-container">
  83. <up-loadmore status="loading" loading-text="努力加载中..." icon-size="18" />
  84. </view>
  85. <view v-else-if="finished && data.length > 0" class="loadmore-container">
  86. <up-loadmore status="nomore" nomore-text="我们是有底线的" icon-size="18" />
  87. </view>
  88. </view>
  89. </scroll-view>
  90. <!-- 安全区底部占位 -->
  91. <view class="safe-bottom" :style="{ height: `${safeBottomHeight}px` }" />
  92. </view>
  93. </template>
  94. <style lang="scss" scoped>
  95. .page-container {
  96. height: 100vh;
  97. display: flex;
  98. flex-direction: column;
  99. }
  100. .discount-coupon-list {
  101. flex: 1;
  102. overflow-y: auto;
  103. .list-content {
  104. padding-top: 20rpx;
  105. padding-left: 24rpx;
  106. padding-right: 24rpx;
  107. display: flex;
  108. flex-direction: column;
  109. gap: 20rpx;
  110. }
  111. .loadmore-container {
  112. padding: 30rpx 0;
  113. text-align: center;
  114. }
  115. }
  116. .safe-bottom {
  117. width: 100%;
  118. background-color: #fff;
  119. }
  120. </style>