Browse Source

feat(home): 更新热门活动组件,添加倒计时功能并优化活动展示;引入新组件以增强用户体验

EvilDragon 3 months ago
parent
commit
cbf61ef626

+ 39 - 45
packages/app/src/components/hot-activity-item.vue

@@ -1,5 +1,13 @@
 <script lang="ts" setup>
+import dayjs from 'dayjs'
+import { Activity, StudyTour } from '../core/libs/models'
 import TiltedButton from './tilted-button.vue'
+import ActivityCountDown from '@/pages/home/components/activity-count-down.vue'
+import ButtonEvo from './button-evo.vue'
+import { useRouter } from '../core/utils/router'
+
+withDefaults(defineProps<{ options?: StudyTour | Activity; type?: 'studyTour' | 'activity' }>(), {})
+const router = useRouter()
 </script>
 <template>
   <view class="relative w-full box-border">
@@ -16,30 +24,38 @@ import TiltedButton from './tilted-button.vue'
     </view>
     <view class="absolute left-0 right-0 top-1 bottom-6 z-1 p-3.5">
       <view class="w-full h-full flex flex-col justify-between">
-        <wd-img
-          custom-class="ms-1.5"
-          src="/static/svgs/unnamed.svg"
-          width="105px"
-          mode="widthFix"
-        ></wd-img>
+        <div class="flex justify-between">
+          <wd-img
+            custom-class="ms-1.5"
+            src="/static/svgs/unnamed.svg"
+            width="105px"
+            mode="widthFix"
+          ></wd-img>
+          <div></div>
+        </div>
+
         <!-- <view class="flex"></view> -->
         <div class="w-[321px] h-[88px] relative">
           <div class="w-[94px] h-3 left-[185px] top-[64px] absolute">
             <div
-              class="left-0 top-0 absolute text-black/40 text-sm font-normal font-['PingFang_SC'] leading-[34px]"
+              class="left-0 top-0 absolute text-black/40 text-sm font-normal font-['PingFang_SC'] leading-[34px] flex items-center"
             >
-              07.15 08.10
+              <!-- 07.15 08.10 -->
+              {{ dayjs(options?.studyStartTime || options?.planStudyStartTime).format('MM.DD') }}
+              <wd-icon name="play" size="22px"></wd-icon>
+              {{ dayjs(options?.studyEndTime || options?.planStudyEndTime).format('MM.DD') }}
             </div>
           </div>
           <wd-img
             custom-class="w-[110px] h-[88px] left-0 top-0 absolute rounded-[10px] overflow-hidden vertical-bottom"
-            src="https://via.placeholder.com/110x88"
+            :src="options?.thumbnailUrl"
             mode="scaleToFill"
           />
           <div
             class="w-[202px] left-[119px] top-0 absolute text-black text-base font-normal font-['PingFang_SC'] leading-relaxed"
           >
-            活动预告 | 日本研学·东京艺术大学设计游学
+            <!-- 活动预告 | 日本研学·东京艺术大学设计游学 -->
+            {{ options?.name }}
           </div>
           <div
             class="left-[119px] top-[64px] absolute text-black/40 text-sm font-normal font-['PingFang_SC'] leading-[34px]"
@@ -48,42 +64,20 @@ import TiltedButton from './tilted-button.vue'
           </div>
         </div>
         <view class="flex items-center justify-between mb-1.5">
-          <view
-            class="flex items-center text-black/40 text-sm font-normal font-['PingFang_SC'] leading-[34px]"
-          >
-            距结束还剩
-            <view
-              class="w-4 h-4 bg-black/90 rounded flex-col justify-center items-center gap-2.5 inline-flex mx-1.5"
-            >
-              <view
-                class="text-white text-[10px] font-normal font-['PingFang_SC'] leading-[10.18px]"
-              >
-                05
-              </view>
-            </view>
-            天
-            <div
-              class="w-4 h-4 bg-black/90 rounded flex-col justify-center items-center gap-2.5 inline-flex mx-1.5"
+          <ActivityCountDown
+            :start-at="options?.applyStartTime"
+            :end-at="options?.applyEndTime"
+          ></ActivityCountDown>
+          <div>
+            <ButtonEvo
+              size="md"
+              @click="
+                router.push(`/pages/home/activity/detail/index?id=${options?.id}&type=${type}`)
+              "
             >
-              <div
-                class="text-white text-[10px] font-normal font-['PingFang_SC'] leading-[10.18px]"
-              >
-                05
-              </div>
-            </div>
-            时
-            <div
-              class="w-4 h-4 bg-black/90 rounded flex-col justify-center items-center gap-2.5 inline-flex mx-1.5"
-            >
-              <div
-                class="text-white text-[10px] font-normal font-['PingFang_SC'] leading-[10.18px]"
-              >
-                05
-              </div>
-            </div>
-            分
-          </view>
-          <tilted-button>立即报名</tilted-button>
+              立即报名
+            </ButtonEvo>
+          </div>
         </view>
       </view>
     </view>

+ 13 - 3
packages/app/src/components/hot-activity.vue

@@ -1,9 +1,11 @@
 <script lang="ts" setup>
 import HotActivityItem from './hot-activity-item.vue'
 
+withDefaults(defineProps<{ items?: any[] }>(), { items: () => [] })
 const swiperList = [{}]
 const item = ref()
 
+const current = ref(0)
 onMounted(() => {
   console.log('mounted')
   nextTick(() => {
@@ -13,10 +15,18 @@ onMounted(() => {
 })
 </script>
 <template>
-  <swiper class="h-60">
-    <template v-for="it of swiperList" :key="it.id">
+  <swiper class="h-60" @change="(e) => (current = e.detail.current)">
+    <template v-for="it of items" :key="it.id">
       <swiper-item class="h-60">
-        <HotActivityItem ref="item"></HotActivityItem>
+        <HotActivityItem ref="item" :options="it.data" :type="it.type"></HotActivityItem>
+        <div class="absolute top-5 right-4 flex gap-1">
+          <template v-for="(it, i) in items" :key="i">
+            <div
+              class="w-1 h-1 rounded-full"
+              :class="`${current === i ? 'bg-white' : 'bg-white/40'}`"
+            ></div>
+          </template>
+        </div>
       </swiper-item>
     </template>
   </swiper>

+ 25 - 11
packages/app/src/pages/home/index.vue

@@ -17,9 +17,11 @@ import HomeBanner from './components/home-banner.vue'
 import useRequest from '../../hooks/useRequest'
 import Menus from './components/menus.vue'
 import {
+  getActivities,
   getCircles,
   getMyStudyTours,
   getSetIndexConfigs,
+  getStudyTours,
   shareCircle,
 } from '../../core/libs/requests'
 import { logo } from '../../core/libs/svgs'
@@ -36,6 +38,8 @@ import ButtonEvo from '@/components/button-evo.vue'
 import ImgBtnEvo from '@/components/img-btn-evo.vue'
 import SectionHeading from '@/components/section-heading.vue'
 import dayjs from 'dayjs'
+import { sort } from 'radash'
+import { Activity, StudyTour } from '../../core/libs/models'
 
 defineOptions({
   name: 'Home',
@@ -51,8 +55,11 @@ const { data: indexConfigsData, run: setIndexConfigsData } = useRequest(
 const { data: studyTours, run: setStudyTours } = useRequest(() => getMyStudyTours(), {
   initialData: [],
 })
+// const {} = useRequest(() =>)
 const swiperData = ref<{ data: any }[]>()
 const swiperCurrent = ref(0)
+const hotActivities =
+  ref<{ type: 'studyTour' | 'activity'; data: StudyTour & Activity; startAt: string | number }[]>()
 const currentStudyTour = computed(() =>
   studyTours.value.find(
     (it) => dayjs(it.studyStartTime).isBefore(dayjs()) && dayjs(it.studyEndTime).isAfter(dayjs()),
@@ -73,20 +80,27 @@ const handleLike = async (options) => {
   })
   pageHelperRef.value?.refresh()
 }
+const setHotActivities = async () => {
+  const res = await Promise.all([
+    getStudyTours({ headRecommend: 1 }).then((res) =>
+      res.data.list.map((it) => ({ type: 'studyTour', data: it, startAt: it.applyStartTime })),
+    ),
+    getActivities({ headRecommend: 1 }).then((res) =>
+      res.data.list.map((it) => ({ type: 'activity', data: it, startAt: it.applyStartTime })),
+    ),
+  ])
+  console.log(sort(res.flat(), (it) => it.startAt))
+  hotActivities.value = sort(res.flat(), (it) => it.startAt) as any
+}
 onShow(async () => {
   pageHelperRef.value?.refresh()
   // await setStudyTours()
   // setStudyTours()
 })
 onLoad(async () => {
-  await setIndexConfigsData()
-  await setStudyTours()
-  console.log(
-    studyTours.value.map((it) => [
-      dayjs(it.studyStartTime).format('YYYY-MM-DD HH:mm'),
-      dayjs(it.studyEndTime).format('YYYY-MM-DD HH:mm'),
-    ]),
-  )
+  await Promise.all([setIndexConfigsData(), setStudyTours(), setHotActivities()])
+  // await setIndexConfigsData()
+  // await setStudyTours()
   swiperData.value = indexConfigsData.value.list.map((it) => ({
     data: it,
   }))
@@ -178,9 +192,9 @@ onShareAppMessage(async ({ from, target }) => {
         <ButtonEvo color="red" size="lg">敌无命</ButtonEvo>
       </div> -->
       <menus></menus>
-      <!-- <view class="my-6 mx-3.5">
-        <HotActivity></HotActivity>
-      </view> -->
+      <view class="my-6 mx-3.5">
+        <HotActivity :items="hotActivities"></HotActivity>
+      </view>
       <view v-if="features.about" class="my-6 mx-3.5" @click="toAbout()">
         <Card>
           <div class="flex items-center gap-2">