index.vue 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. <template>
  2. <FlexCol :gap="20" :padding="30">
  3. <HomeLargeTitle title="发现" />
  4. <ImageSwiper
  5. :images="appConfiguration?.banners.discover"
  6. width="100%"
  7. :height="400"
  8. radius="radius.md"
  9. :innerStyle="{
  10. border: '1px solid #fff',
  11. overflow: 'hidden',
  12. }"
  13. />
  14. <HomeTitle title="乡村排名" showMore @moreClicked="navTo('/pages/home/village/rank/village')" />
  15. <FlexCol gap="gap.lg">
  16. <Touchable
  17. v-for="item in villageRankListLoader.content.value" :key="item.id"
  18. backgroundColor="background.tertiary"
  19. radius="radius.md"
  20. :padding="[20, 30]"
  21. gap="gap.lg"
  22. align="center"
  23. @click="handleGoVillageDetails(item as any)"
  24. >
  25. <Image
  26. :src="item.image"
  27. defaultImage="https://xy.wenlvti.net/app_static/images/village/PlaceholderVillage.jpg"
  28. :width="280"
  29. :height="80"
  30. :round="false"
  31. :radius="10"
  32. />
  33. <Text :text="item.title" fontConfig="contentText" :innerStyle="{ flex: 1 }" />
  34. </Touchable>
  35. </FlexCol>
  36. <HomeTitle title="志愿者排名" showMore :lightCount="3" @moreClicked="navTo('/pages/home/village/rank/volunteer')" />
  37. <FlexCol gap="gap.lg">
  38. <Touchable
  39. v-for="item in villageRankListLoader.content.value" :key="item.id"
  40. backgroundColor="background.tertiary"
  41. radius="radius.md"
  42. :padding="[20, 30]"
  43. gap="gap.lg"
  44. align="center"
  45. @click="navTo('/pages/home/village/volunteer/detail', { id: $event.id })"
  46. >
  47. <Image
  48. :src="item.image"
  49. defaultImage="https://xy.wenlvti.net/app_static/images/village/PlaceholderVolunteer.jpg"
  50. :width="80"
  51. :height="80"
  52. :round="true"
  53. />
  54. <Text :text="item.title" fontConfig="contentText" :innerStyle="{ flex: 1 }" />
  55. </Touchable>
  56. </FlexCol>
  57. <HomeTitle title="乡源好物" showMore @moreClicked="navTo('/pages/home/village/rank/village')" />
  58. <HomeTitle title="最新推荐" />
  59. <SimplePageListLoader :loader="discoverLoader">
  60. <MasonryGrid>
  61. <MasonryGridItem
  62. v-for="(item, i) in discoverLoader.list.value"
  63. :key="i"
  64. :width="340"
  65. >
  66. <IndexCommonImageItem
  67. :image="item.image"
  68. :title="item.title"
  69. :desc="item.content ?? ''"
  70. :userName="item.villageVolunteerName ?? ''"
  71. :likes="0"
  72. :isLike="false"
  73. @click="handleGoRecommendDetails(item)"
  74. />
  75. </MasonryGridItem>
  76. </MasonryGrid>
  77. </SimplePageListLoader>
  78. <Loadmore status="nomore" />
  79. <Height :height="150" />
  80. </FlexCol>
  81. </template>
  82. <script setup lang="ts">
  83. import { navTo } from '@/components/utils/PageAction';
  84. import { useSimplePageListLoader } from '@/components/composeabe/loader/SimplePageListLoader';
  85. import { useSimpleDataLoader } from '@/components/composeabe/loader/SimpleDataLoader';
  86. import { useVillageStore } from '@/store/village';
  87. import { injectAppConfiguration } from '@/api/system/useAppConfiguration';
  88. import Loadmore from '@/components/display/loading/Loadmore.vue';
  89. import FlexCol from '@/components/layout/FlexCol.vue';
  90. import Height from '@/components/layout/space/Height.vue';
  91. import HomeLargeTitle from '@/common/components/parts/HomeLargeTitle.vue';
  92. import HomeTitle from '@/common/components/parts/HomeTitle.vue';
  93. import ImageSwiper from '@/common/components/parts/ImageSwiper.vue';
  94. import SimplePageListLoader from '@/components/loader/SimplePageListLoader.vue';
  95. import MasonryGrid from '@/components/layout/masonry/MasonryGrid.vue';
  96. import MasonryGridItem from '@/components/layout/masonry/MasonryGridItem.vue';
  97. import VillageInfoApi, { type CommonInfoModel } from '@/api/inhert/VillageInfoApi';
  98. import IndexCommonImageItem from '@/common/components/parts/IndexCommonImageItem.vue';
  99. import LightVillageApi, { type VillageListItem } from '@/api/light/LightVillageApi';
  100. import Avatar from '@/components/display/Avatar.vue';
  101. import Touchable from '@/components/feedback/Touchable.vue';
  102. import Text from '@/components/basic/Text.vue';
  103. import Image from '@/components/basic/Image.vue';
  104. import { waitTimeOut } from '@imengyu/imengyu-utils';
  105. const emit = defineEmits([ 'goVillage' ]);
  106. const villageStore = useVillageStore();
  107. const appConfiguration = injectAppConfiguration();
  108. const discoverLoader = useSimplePageListLoader(15, async (page, pageSize) => {
  109. return await VillageInfoApi.getListForDiscover(page, pageSize);
  110. });
  111. const villageRankListLoader = useSimpleDataLoader(async () => {
  112. const res = await LightVillageApi.getVillageRankList({ num: 10 });
  113. return res.map((item, i) => ({
  114. image: item.image ?? '',
  115. title: item.name,
  116. rank: i + 1,
  117. id: item.id,
  118. }));
  119. });
  120. const villageUserRankListLoader = useSimpleDataLoader(async () => {
  121. const res = (await LightVillageApi.getVolunteerRankList({ num: 10 }))
  122. .map((item, i) => ({
  123. id: item.id,
  124. image: item.image ?? '',
  125. title: item.name,
  126. rank: i + 1,
  127. score: item.points,
  128. }));
  129. return res
  130. });
  131. function handleGoRecommendDetails(item: CommonInfoModel) {
  132. navTo(`/pages/home/discover/details`, { id: item.id });
  133. }
  134. async function handleGoVillageDetails(item: VillageListItem) {
  135. const details = await LightVillageApi.getVillageDetails(item.id);
  136. villageStore.setCurrentVillage(details);
  137. await waitTimeOut(100);
  138. emit('goVillage')
  139. }
  140. </script>