Browse Source

📦 节庆日历功能

imengyu 1 month ago
parent
commit
d13747a1c6
2 changed files with 123 additions and 53 deletions
  1. 38 0
      src/api/fusion/CalendarContent.ts
  2. 85 53
      src/pages/travel/calendar.vue

+ 38 - 0
src/api/fusion/CalendarContent.ts

@@ -0,0 +1,38 @@
+import { CommonContentApi, GetContentListItem, GetContentListParams } from '../CommonContent';
+
+export class CalendarListItem extends GetContentListItem {
+  constructor() {
+    super();
+
+    this._nameMapperServer = {
+      lunar: 'date',
+      lunar_date: 'dateString',
+    }
+    const old = this._afterSolveServer;
+    this._afterSolveServer = (data) => {
+      old?.(data);
+      const date = new Date(this.date);
+      this.dateObj = date;
+      this.dateYear = date.getFullYear();
+      this.dateMonth = date.getMonth() + 1;
+    }
+  }
+  date = '';
+  dateString = '';
+  dateObj = new Date();
+  dateYear = 0;
+  dateMonth = 0;
+}
+
+export class CalendarContentApi extends CommonContentApi {
+
+  constructor() {
+    super(undefined, 18, "闽南节庆日历", 272);
+  }
+
+  getCalendarList(params: GetContentListParams, page: number, pageSize?: number) {
+    return super.getContentList<CalendarListItem>(params, page, pageSize, CalendarListItem);
+  }
+}
+
+export default new CalendarContentApi();

+ 85 - 53
src/pages/travel/calendar.vue

@@ -4,14 +4,18 @@
     <view class="banner">
       <swiper class="swiper right-indicator" circular :indicator-dots="true" :autoplay="true" :interval="2000"
         :duration="1000">
-        <swiper-item v-for="item in bannerData" :key="item.id">
+        <swiper-item 
+          v-for="item in bannerData"
+          :key="item.id"
+          @click="goDetail(item.id)"
+        >
           <view class="item">
             <image class="w-100" :src="item.image" mode="aspectFill"></image>
           </view>
         </swiper-item>
       </swiper>
     </view>
-    <view class="main m-3 radius-l p-3 bg-light">
+    <view class="main radius-l p-3 bg-light">
       <view class="change-year">
         <view class="year">
           <text class="iconfont icon-arrow-left" @click="changeYear(currentYear - 1)"></text>
@@ -22,7 +26,7 @@
         </view>
         <text class="iconfont icon-calendar"></text>
       </view>
-      <u-tabs 
+      <!-- <u-tabs 
         :current="activeTab" 
         :list="tabs" 
         lineWidth="30" 
@@ -38,41 +42,55 @@
         }" 
         class="top-tab" 
         @click="tabClick" 
-      />
+      /> -->
       <view class="activity-wrap mt-3">
         <view class="month-list">
           <view 
             v-for="month in monthList"
             :key="month.value"
-            :class="{ active: month.value === currentMonth }" 
             class="month" 
             @click="goMonth(month.value)"
           >
+          <!-- :class="{ active: month.value === currentMonth }"  -->
             {{ month.label }}
           </view>
         </view>
         <SimplePageContentLoader 
           :loader="listLoader"
           :showEmpty="!listLoader.content.value?.length"
+          class="w-100"
         >
           <view 
             v-if="listLoader.content.value && listLoader.content.value.length" 
             class="activity-list"
           >
             <scroll-view scroll-y :scroll-into-view="'month' + currentMonth" scroll-with-animation>
-              <view class="item" v-for="item in listLoader.content.value" :key="item.id">
-                <view class="head" :id="'month' + item.month">
-                  <view class="year-month">{{ item.year }}年{{ item.month }}月</view>
-                  <view>本月活动 <text>{{ item.data.length }}</text></view>
-                </view>
-                <view class="activity" v-for="act in item.data" :key="act.id">
-                  <view class="title">{{ act.title }}</view>
-                  <view class="dot" :class="{ ing: act.status === 0 }"></view>
-                  <view class="desc ellipsis-2">{{ act.desc }}</view>
-                  <view class="place"><text class="iconfont icon-place"></text>{{ act.place }}</view>
-                  <view class="time"><text class="iconfont icon-time"></text>{{ act.time }}</view>
+              <template v-for="(item, key) in listLoader.content.value" :key="key">
+                <view v-if="item" class="item">
+                  <view class="head" :id="'month' + item.month">
+                    <view class="year-month">{{ item.year }}年{{ item.month }}月</view>
+                    <view>本月活动 <text>{{ item.data.length }}</text></view>
+                  </view>
+                  <view v-if="item.data.length == 0" class="activity">
+                    <view class="title">
+                      <text class="iconfont icon-activity"></text>
+                      本月暂无活动
+                    </view>
+                  </view>
+                  <view 
+                    class="activity" 
+                    v-for="act in item.data"
+                    :key="act.id"
+                    @click="goDetail(act.id)"
+                  >
+                    <view class="title">{{ act.title }}</view>
+                    <view class="dot" :class="{ ing: act.status === 0 }"></view>
+                    <view class="desc ellipsis-2">{{ act.desc }}</view>
+                    <view class="place"><text class="iconfont icon-place"></text>{{ act.place }}</view>
+                    <view class="time"><text class="iconfont icon-time"></text>{{ act.time }}</view>
+                  </view> 
                 </view>
-              </view>
+              </template>
             </scroll-view>
           </view>
         </SimplePageContentLoader>
@@ -83,9 +101,10 @@
 
 <script setup lang="ts">
 import { GetContentListParams } from '@/api/CommonContent';
-import NewsIndexContent from '@/api/news/NewsIndexContent';
+import CalendarContent from '@/api/fusion/CalendarContent';
 import SimplePageContentLoader from '@/common/components/SimplePageContentLoader.vue';
 import { useSimplePageContentLoader } from '@/common/composeabe/SimplePageContentLoader';
+import { navTo } from '@/common/utils/PageAction';
 import { onLoad } from '@dcloudio/uni-app';
 import { ref } from 'vue';
 
@@ -116,16 +135,7 @@ const tabs = [
   }
 ];
 const activeTab = ref(0);
-const bannerData = [
-  {
-    id: 1,
-    image: 'https://lucheng.app4lh.cnhttps://mn.wenlvti.net/app_static/minnan/tmphttps://mn.wenlvti.net/app_static/minnan/tmp/banner_act.png',
-  },
-  {
-    id: 2,
-    image: 'https://lucheng.app4lh.cnhttps://mn.wenlvti.net/app_static/minnan/tmphttps://mn.wenlvti.net/app_static/minnan/tmp/banner_act.png',
-  }
-]
+const bannerData = ref<{ id: number, image: string }[]>([])
 
 const currentMonth = ref(1);
 const currentYear = ref(new Date().getFullYear());
@@ -168,8 +178,8 @@ const monthList = [
     value: 12
   }
 ];
- 
-const listLoader = useSimplePageContentLoader<{
+
+interface ListItem {
   id: number;
   month: number,
   year: number,
@@ -181,26 +191,41 @@ const listLoader = useSimplePageContentLoader<{
     time: string,
     status: number,
   }[]
-}[]>(async () => {
-  const res = await NewsIndexContent.getContentList(new GetContentListParams()
-    .setModelId(18)
-    .setMainBodyColumnId(272)
-  , 1, 50);
-  return [
-    {
-      id: 1,
-      month: 1,
-      year: 2025, 
-      data: res.list.map(item => ({
-        id: item.id,
-        title: item.title,
-        desc: item.desc,
-        place: item.district,
-        time: '2025-01-01',
-        status: 1,
-      }))
+}
+ 
+const listLoader = useSimplePageContentLoader<ListItem[]>(async () => {
+  const res = (await CalendarContent.getCalendarList(new GetContentListParams(), 1, 100));
+  const res2 : ListItem[] = [];
+  for (let i = 0; i < 12; i++) {
+    res2[i] = {
+      id: i,
+      month: i + 1,
+      year: currentYear.value,
+      data: []
     }
-  ];
+  }
+  for (const item of res.list) {
+    if (item.dateYear != currentYear.value) 
+      continue;
+    const it = res2[item.dateMonth - 1];
+    it.data.push({
+      id: item.id,
+      title: item.title,
+      desc: item.desc, 
+      place: item.district + (item.regionText || ''),
+      time: item.dateString ?? item.date,
+      status: item.dateObj > new Date() ? 0 : 1,
+    })
+    if (bannerData.value.length < 3)
+      bannerData.value.push({
+        id: item.id,
+        image: item.thumbnail || item.image,  
+      })
+  }
+  const a =  res2.filter(p => p);
+  console.log(a);
+  
+  return a
 });
 
 function tabClick(e: { index: number }) {
@@ -213,6 +238,9 @@ async function changeYear(year: number) {
   currentYear.value = year;
   listLoader.loadData(undefined, true);
 }
+function goDetail(id: number) {
+  navTo('/pages/article/details', { id })
+}
 
 onLoad(() => {
   listLoader.loadData(undefined, true);
@@ -227,6 +255,7 @@ $color-primary: map.get($colors, "primary");
 
 .travel_calendar {
   .banner {
+    height: 400rpx;
     margin-top: 0;
 
     .swiper {
@@ -241,6 +270,10 @@ $color-primary: map.get($colors, "primary");
     }
   }
 
+  .main {
+    margin: 30rpx;
+    height: calc(100vh - 400rpx - 120rpx);
+  }
   .activity-wrap {
     display: flex;
 
@@ -355,8 +388,8 @@ $color-primary: map.get($colors, "primary");
 
       .month {
         border-radius: 10rpx;
-        margin-bottom: 30rpx;
-        padding: 12rpx 20rpx;
+        margin-bottom: 10rpx;
+        padding: 10rpx 20rpx;
 
         &.active {
           border: 1px solid $color-primary;
@@ -367,8 +400,7 @@ $color-primary: map.get($colors, "primary");
   }
 
   scroll-view {
-    height: calc(100vh - 540rpx);
-    padding-bottom: 50rpx;
+    height: calc(100vh - 620rpx);
   }
 
   .change-year {