index.vue 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. <!-- 使用 type="home" 属性设置首页,其他页面不需要设置,默认为page;推荐使用json5,更强大,且允许注释 -->
  2. <route lang="json5" type="home">
  3. {
  4. layout: 'tabbar',
  5. style: {
  6. navigationStyle: 'custom',
  7. navigationBarTitleText: '首页',
  8. },
  9. }
  10. </route>
  11. <script lang="ts" setup>
  12. import Card from '@/components/card.vue'
  13. import HotActivity from '@/components/hot-activity.vue'
  14. import MomentItem from '@/components/moment-item.vue'
  15. import HomeBanner from './components/home-banner.vue'
  16. import useRequest from '../../hooks/useRequest'
  17. import Menus from './components/menus.vue'
  18. import {
  19. getActivities,
  20. getCircles,
  21. getMyStudyTours,
  22. getSetIndexConfigs,
  23. getStudyTours,
  24. shareCircle,
  25. updateSetIndexConfig,
  26. } from '../../core/libs/requests'
  27. import { logo } from '../../core/libs/svgs'
  28. import { ComponentExposed } from 'vue-component-type-helpers'
  29. import { usePermissions } from '../../composables/permissions'
  30. import { storeToRefs } from 'pinia'
  31. import { messages } from '../../core/libs/messages'
  32. import { handleUpvoteClick, handleShareClick } from '../../core/libs/actions'
  33. import { useUserStore } from '../../store'
  34. import ScheduleCard from './components/schedule-card.vue'
  35. import dayjs from 'dayjs'
  36. import { pick, sort } from 'radash'
  37. import { Activity, StudyTour } from '../../core/libs/models'
  38. import PageHelperEvo from '@/components/page-helper-evo.vue'
  39. import { useMessage } from 'wot-design-uni'
  40. import { useHonorDialog } from '../../composables/honor-dialog'
  41. defineOptions({
  42. name: 'Home',
  43. })
  44. useMessage()
  45. const { show } = useHonorDialog()
  46. const userStore = useUserStore()
  47. const { userInfo } = storeToRefs(userStore)
  48. const { features, isLogined } = usePermissions()
  49. const pageHelperRef = ref<ComponentExposed<typeof PageHelperEvo>>()
  50. const { data: indexConfigsData, run: setIndexConfigsData } = useRequest(
  51. () => getSetIndexConfigs(),
  52. { initialData: { list: [] } },
  53. )
  54. const { data: studyTours, run: setStudyTours } = useRequest(() => getMyStudyTours(), {
  55. initialData: [],
  56. })
  57. const swiperData = ref<{ data: any }[]>()
  58. const swiperCurrent = ref(0)
  59. const autoplay = ref(true)
  60. const homeBannerRef = ref<ComponentExposed<typeof HomeBanner>[]>()
  61. const hotActivities =
  62. ref<{ type: 'studyTour' | 'activity'; data: StudyTour & Activity; startAt: string | number }[]>()
  63. const currentStudyTour = computed(() =>
  64. studyTours.value.find(
  65. (it) => dayjs(it.studyStartTime).isBefore(dayjs()) && dayjs(it.studyEndTime).isAfter(dayjs()),
  66. ),
  67. )
  68. const toAbout = () => {
  69. uni.navigateTo({ url: '/pages/home/about/index' })
  70. }
  71. const handleSwiperChange = ({ detail: { current, source } }) => {
  72. // console.log('current', current)
  73. console.log(current, source, swiperCurrent.value)
  74. homeBannerRef.value?.[swiperCurrent.value]?.videoContext.pause()
  75. swiperCurrent.value = current
  76. }
  77. const handleLike = async (options) => {
  78. await handleUpvoteClick({
  79. ...options,
  80. userId: userInfo.value.userId,
  81. userName: userInfo.value.nickname,
  82. })
  83. await pageHelperRef.value?.refresh()
  84. }
  85. const setHotActivities = async () => {
  86. const res = await Promise.all([
  87. getStudyTours({ headRecommend: 1 }).then((res) =>
  88. res.data.list.map((it) => ({ type: 'studyTour', data: it, startAt: it.applyStartTime })),
  89. ),
  90. getActivities({ headRecommend: 1 }).then((res) =>
  91. res.data.list.map((it) => ({ type: 'activity', data: it, startAt: it.applyStartTime })),
  92. ),
  93. ])
  94. console.log(sort(res.flat(), (it) => it.startAt))
  95. hotActivities.value = sort(res.flat(), (it) => it.startAt) as any
  96. }
  97. const handlePlay = async (id) => {
  98. const body = pick(swiperData.value?.find((it) => it.data.id === id).data, ['id', 'status'])
  99. autoplay.value = false
  100. await updateSetIndexConfig(body)
  101. }
  102. onShow(async () => {
  103. await pageHelperRef.value?.reload()
  104. const reqs = [setHotActivities()]
  105. if (isLogined.value) {
  106. reqs.push(setStudyTours())
  107. }
  108. await Promise.all(reqs)
  109. })
  110. onLoad(async () => {
  111. await Promise.all([setIndexConfigsData()])
  112. swiperData.value = indexConfigsData.value.list.map((it) => ({
  113. data: it,
  114. }))
  115. show.value({ title: '看不见', content: '看不见', path: '', image: '' })
  116. })
  117. onHide(() => {
  118. // autoplay.value = true
  119. homeBannerRef.value?.[swiperCurrent.value]?.videoContext.pause()
  120. })
  121. onShareAppMessage(async ({ from, target }) => {
  122. console.log('from', from)
  123. console.log('target', target)
  124. const res: Page.CustomShareContent = {}
  125. if (from === 'button') {
  126. await shareCircle(target.dataset.options.id)
  127. res.path = `/pages/home/moment/index?id=${target.dataset.options.id}&isShared=true`
  128. res.imageUrl = target.dataset.options.bannerUrls[0]
  129. res.title = `${target.dataset.options.stylistName}: ${target.dataset.options.circleDesc}`
  130. }
  131. if (from === 'menu') {
  132. res.title = messages.home.shareTitle
  133. }
  134. return res
  135. })
  136. </script>
  137. <template>
  138. <view class="">
  139. <view class="bg-black w-full relative aspect-[1.26/1]">
  140. <swiper :autoplay="autoplay" @change="handleSwiperChange">
  141. <template
  142. v-for="{ data: { id, coverVideoImage, indexPromotionalVideoImage } } of swiperData"
  143. :key="id"
  144. >
  145. <swiper-item>
  146. <HomeBanner
  147. ref="homeBannerRef"
  148. :id="id"
  149. :url="indexPromotionalVideoImage"
  150. :cover="coverVideoImage"
  151. @play="handlePlay"
  152. @ended="autoplay = true"
  153. />
  154. </swiper-item>
  155. </template>
  156. </swiper>
  157. </view>
  158. <view class="bg-[#f6f6f6] relative bottom-4 rounded-t-2xl py-1">
  159. <template v-if="currentStudyTour">
  160. <ScheduleCard
  161. custom-class="my-6 mx-3.5"
  162. :items="currentStudyTour.studyTravelDOList"
  163. ></ScheduleCard>
  164. </template>
  165. <!-- <SectionHeading title="按钮调试"></SectionHeading> -->
  166. <!-- <div class="flex">
  167. <TiltedButton size="large" custom-class="w-30"></TiltedButton>
  168. <ButtonEvo>神奇按钮</ButtonEvo>
  169. <ImgBtnEvo></ImgBtnEvo>
  170. </div> -->
  171. <!-- <div class="flex flex-col gap-1">
  172. <button>咲</button>
  173. <ButtonEvo custom-class="w-auto!">咲</ButtonEvo>
  174. <ButtonEvo custom-class="">遥星</ButtonEvo>
  175. <ButtonEvo custom-class="">血不染</ButtonEvo>
  176. <ButtonEvo custom-class="">天地不容</ButtonEvo>
  177. <ButtonEvo custom-class="">飒沓如流星</ButtonEvo>
  178. <ButtonEvo custom-class="">君有才能纵捭阖</ButtonEvo>
  179. <div class="w-full">
  180. <ButtonEvo custom-class="" block>诗仙纵横,刀剑茫茫去不还</ButtonEvo>
  181. </div>
  182. <ButtonEvo color="red" size="lg">敌无命</ButtonEvo>
  183. </div> -->
  184. <menus></menus>
  185. <view v-if="hotActivities?.length" class="my-6 mx-3.5">
  186. <HotActivity :items="hotActivities"></HotActivity>
  187. </view>
  188. <view v-if="features.about" class="my-6 mx-3.5" @click="toAbout()">
  189. <Card>
  190. <div class="flex items-center gap-2">
  191. <wd-img width="28" height="28" :src="logo"></wd-img>
  192. <div class="text-black/90 text-base font-normal font-['PingFang_SC'] leading-[10.18px]">
  193. 1分钟快速了解筑巢荟
  194. </div>
  195. <div class="flex-1"></div>
  196. <wd-icon name="help-circle" size="22px" custom-class="text-black/60"></wd-icon>
  197. </div>
  198. </Card>
  199. </view>
  200. <view class="mx-3.5 text-5 font-400">设计圈</view>
  201. <view class="mx-3.5">
  202. <PageHelperEvo ref="pageHelperRef" :request="getCircles" class="">
  203. <template #default="{ source }">
  204. <template v-for="it of source.list" :key="it.id">
  205. <view class="my-3">
  206. <MomentItem :options="it" @like="handleLike"></MomentItem>
  207. </view>
  208. </template>
  209. </template>
  210. </PageHelperEvo>
  211. </view>
  212. </view>
  213. </view>
  214. </template>
  215. <style></style>