index.vue 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. <template>
  2. <FlexCol :gap="20" :padding="30" :innerStyle="{
  3. marginTop: '-130px',
  4. backgroundImage: 'url(https://xy.wenlvti.net/app_static/images/home/BannerHome.png)',
  5. backgroundSize: '100% auto',
  6. backgroundRepeat: 'no-repeat',
  7. backgroundPosition: 'top center',
  8. backgroundColor: themeContext.resolveThemeColor('background.primary'),
  9. }">
  10. <FlexCol position="absolute" :left="0" :top="0">
  11. <StatusBarSpace />
  12. <Button
  13. @click="showCityPopup = true"
  14. icon="https://xy.wenlvti.net/app_static/images/home/IconSwitch.png"
  15. :text="currentCity"
  16. type="custom"
  17. color="transparent"
  18. />
  19. </FlexCol>
  20. <Height height="200px" />
  21. <FlexCol :gap="20" align="center">
  22. <SearchBar v-model="searchKeywords" placeholder="搜索" :innerStyle="{
  23. backgroundColor: 'white',
  24. borderRadius: '20rpx',
  25. borderWidth: '1px',
  26. borderStyle: 'solid',
  27. borderColor: themeContext.resolveThemeColor('primary'),
  28. width: '650rpx',
  29. }" />
  30. <Image
  31. src="https://xy.wenlvti.net/app_static/images/home/BannerIndex.png"
  32. width="700rpx"
  33. height="200px"
  34. mode="aspectFill"
  35. :innerStyle="{
  36. borderRadius: '20rpx',
  37. clipPath: 'ellipse(100% 90% at 50% 0%)'
  38. }"
  39. />
  40. </FlexCol>
  41. <LightMap
  42. small
  43. :limitCity="currentCity"
  44. :startLonlat="currentLonlat"
  45. @changedCity="handleChangedCity"
  46. @selectVillage="goDetails"
  47. >
  48. <NoticeBar
  49. v-if="currentNoticeContent"
  50. :content="currentNoticeContent"
  51. :innerStyle="{
  52. position: 'absolute',
  53. top: '20rpx',
  54. left: '20rpx',
  55. right: '20rpx',
  56. zIndex: 100,
  57. borderRadius: '30rpx',
  58. }"
  59. :textStyle="{
  60. fontSize: '26rpx',
  61. }"
  62. icon="https://xy.wenlvti.net/app_static/images/home/IconLightActive.png"
  63. :iconProps="{
  64. size: 34,
  65. }"
  66. textColor="#C9211F"
  67. backgroundColor="#D9492E10"
  68. />
  69. </LightMap>
  70. <FlexRow justify="space-between" :padding="[10, 16]" gap="gap.md">
  71. <Button
  72. icon="https://xy.wenlvti.net/app_static/images/home/IconSwitch.png"
  73. radius="radius.lg"
  74. :padding="[10, 30]"
  75. @click="showCityPopup = true"
  76. >
  77. 切换城市
  78. </Button>
  79. <Button
  80. icon="https://xy.wenlvti.net/app_static/images/home/IconFollow.png"
  81. radius="radius.lg" :padding="[10, 30]"
  82. @click="showMyFollowPopup = true"
  83. >
  84. 我的关注
  85. </Button>
  86. <Button
  87. icon="https://xy.wenlvti.net/app_static/images/home/IconLight.png"
  88. radius="radius.lg" :padding="[10, 30]"
  89. @click="navTo('/pages/home/light/submit-map', { code: currentCityCode })"
  90. >
  91. 点亮村社
  92. </Button>
  93. </FlexRow>
  94. <HomeTitle title="乡村排名" showMore />
  95. <VillageRankList />
  96. <HomeTitle title="志愿者排名" showMore :lightCount="3" />
  97. <VillageUserRankList />
  98. <HomeTitle title="精选记忆" showMore />
  99. <MasonryGrid>
  100. <MasonryGridItem
  101. v-for="(item, i) in recommendLoader.content.value"
  102. :key="i"
  103. :width="340"
  104. >
  105. <IndexCommonImageItem
  106. :image="item.image"
  107. :title="item.title"
  108. :desc="item.desc"
  109. :userName="item.userName"
  110. :likes="item.likes"
  111. :isLike="item.isLike"
  112. />
  113. </MasonryGridItem>
  114. </MasonryGrid>
  115. <Loadmore status="nomore" />
  116. <Height :height="150" />
  117. <Popup
  118. v-model:show="showCityPopup"
  119. closeable
  120. position="top"
  121. size="80vh"
  122. >
  123. <CitySelect @selectCity="handleSelectCity" />
  124. </Popup>
  125. <Popup
  126. v-model:show="showMyFollowPopup"
  127. closeable
  128. position="bottom"
  129. round
  130. size="80vh"
  131. >
  132. <VillageMyFollow @goDetails="goDetails" />
  133. </Popup>
  134. </FlexCol>
  135. </template>
  136. <script setup lang="ts">
  137. import { onMounted, ref, watch } from 'vue';
  138. import { useTheme } from '@/components/theme/ThemeDefine';
  139. import { useSimpleDataLoader } from '@/components/composeabe/loader/SimpleDataLoader';
  140. import { useStorageVar } from '@/components/composeabe/StorageVar';
  141. import { useVillageStore } from '@/store/village';
  142. import { navTo } from '@/components/utils/PageAction';
  143. import Image from '@/components/basic/Image.vue';
  144. import Loadmore from '@/components/display/loading/Loadmore.vue';
  145. import FlexCol from '@/components/layout/FlexCol.vue';
  146. import FlexRow from '@/components/layout/FlexRow.vue';
  147. import Height from '@/components/layout/space/Height.vue';
  148. import SearchBar from '@/components/form/SearchBar.vue';
  149. import Button from '@/components/basic/Button.vue';
  150. import HomeTitle from '@/common/components/parts/HomeTitle.vue';
  151. import VillageRankList from './components/VillageRankList.vue';
  152. import VillageUserRankList from './components/VillageUserRankList.vue';
  153. import VillageInfoApi from '@/api/inhert/VillageInfoApi';
  154. import MasonryGrid from '@/components/layout/masonry/MasonryGrid.vue';
  155. import MasonryGridItem from '@/components/layout/masonry/MasonryGridItem.vue';
  156. import IndexCommonImageItem from '@/common/components/parts/IndexCommonImageItem.vue';
  157. import Popup from '@/components/dialog/Popup.vue';
  158. import CitySelect from './components/CitySelect.vue';
  159. import VillageMyFollow from './components/VillageMyFollow.vue';
  160. import type { CityItem } from '@/api/map/MapApi';
  161. import MapApi from '@/api/map/MapApi';
  162. import LightMap from './components/LightMap.vue';
  163. import NoticeBar from '@/components/display/NoticeBar.vue';
  164. import StatusBarSpace from '@/components/layout/space/StatusBarSpace.vue';
  165. import type { VillageListItem } from '@/api/inhert/VillageApi';
  166. import FollowVillageApi from '@/api/light/FollowVillageApi';
  167. const emit = defineEmits(['goVillage']);
  168. const villageStore = useVillageStore();
  169. const themeContext = useTheme();
  170. const searchKeywords = ref('');
  171. const showCityPopup = ref(false);
  172. const showMyFollowPopup = ref(false);
  173. const currentLonlat = ref<{ longitude: number, latitude: number }>();
  174. const { value: currentCity } = useStorageVar('currentCityName', '厦门市');
  175. const currentCityCode = ref('');
  176. watch(currentCity, async (newVal) => {
  177. currentCityCode.value = await MapApi.simpleGetRegionCode(newVal);
  178. }, { immediate: true });
  179. const currentNoticeContent = ref('目前厦门市已被点亮一个社区,刚刚小亮贡献了10个光源,让湖里区点亮了一个社区');
  180. const recommendLoader = useSimpleDataLoader(async () => {
  181. const res = (await VillageInfoApi.getListForDiscover(
  182. 1, 20,
  183. '',
  184. ));
  185. return res.list.concat(res.list,res.list, res.list, res.list).sort(() => Math.random() - 0.5).map((item) => ({
  186. ...item,
  187. isLike: Math.random() > 0.5,
  188. likes: Math.floor(Math.random() * 1000),
  189. userName: '用户' + Math.floor(Math.random() * 1000000),
  190. badge: item.villageName || '',
  191. }))
  192. });
  193. function goDetails(item: VillageListItem) {
  194. showMyFollowPopup.value = false;
  195. villageStore.setCurrentVillage(item);
  196. emit('goVillage')
  197. }
  198. async function handleChangedCity(city: string) {
  199. currentCity.value = city;
  200. const res = await MapApi.searchPoi(city);
  201. if (res.length > 0) {
  202. currentLonlat.value = {
  203. longitude: res[0].location[0],
  204. latitude: res[0].location[1],
  205. };
  206. }
  207. }
  208. function handleSelectCity(city: CityItem) {
  209. currentCity.value = city.name;
  210. showCityPopup.value = false;
  211. handleChangedCity(city.name);
  212. }
  213. onMounted(async () => {
  214. const res = await FollowVillageApi.getFollowVillageList({ page: 1, pageSize: 200 });
  215. villageStore.setMyFollowVillages(res.list);
  216. if (res.list.length > 0)
  217. villageStore.setCurrentVillage(res.list[0]);
  218. });
  219. </script>